diff --git a/packages/default/scss/toolbar/_layout.scss b/packages/default/scss/toolbar/_layout.scss index 1b3c371235b..5eac2cc0bab 100644 --- a/packages/default/scss/toolbar/_layout.scss +++ b/packages/default/scss/toolbar/_layout.scss @@ -39,6 +39,44 @@ flex-wrap: nowrap; } + &.k-toolbar-scrollable { + flex-wrap: nowrap; + position: relative; + + &::before { + content: ''; + height: 100%; + width: 46px; + position: absolute; + inset-inline-start: 0; + z-index: 3; + } + + &::after { + content: ''; + height: 100%; + width: 46px; + position: absolute; + inset-inline-end: 0; + z-index: 3; + } + + &.k-toolbar-scrollable-start::before { + display: none; + } + + &.k-toolbar-scrollable-end::after { + display: none; + } + } + + &.k-toolbar-scrollable-buttons { + &::before, + &::after { + display: none; + } + } + > * { flex-shrink: 0; display: inline-flex; @@ -77,12 +115,6 @@ width: min-content; } - // Overflow anchor - .k-toolbar-overflow-button { - margin-inline-start: auto; - } - - // Separator .k-separator, .k-toolbar-separator { @@ -93,6 +125,10 @@ align-self: center; } + // Overflow separator + .k-toolbar-overflow-separator { + margin-inline-start: auto; + } // Spacer .k-toolbar-spacer { @@ -109,6 +145,30 @@ } } + .k-toolbar-items { + display: flex; + flex-flow: row nowrap; + gap: $kendo-toolbar-spacing; + align-items: center; + justify-content: flex-start; + flex: 1 1 auto; + overflow: hidden; + } + + .k-toolbar-scrollable .k-toolbar-items { + overflow-x: auto; + scrollbar-width: none; + + &::-webkit-scrollbar { + display: none; + } + } + + .k-toolbar-popup .k-toolbar-items { + flex-wrap: wrap; + } + + // Outline Toolbar .k-toolbar-outline { border-width: $kendo-toolbar-outline-border-width; @@ -148,9 +208,23 @@ margin-inline-start: calc( #{$_spacing} * -1 ); } + &.k-toolbar-scrollable::before { + inset-inline-start: $_spacing; + } + > * > label { margin-inline-end: $_spacing; } + + .k-toolbar-items { + gap: $_spacing; + } + } + + .k-toolbar-popup-#{$size} .k-toolbar-items { + padding-block: $_padding-y; + padding-inline: $_padding-x; + gap: $_spacing; } } // Remove once we decide to not size empty containers diff --git a/packages/default/scss/toolbar/_theme.scss b/packages/default/scss/toolbar/_theme.scss index ba62aff9c82..1b4d62f6b9c 100644 --- a/packages/default/scss/toolbar/_theme.scss +++ b/packages/default/scss/toolbar/_theme.scss @@ -34,6 +34,16 @@ $kendo-toolbar-gradient ); @include box-shadow( $kendo-toolbar-shadow ); + + &.k-toolbar-scrollable { + &::before { + background: linear-gradient(90deg, $kendo-toolbar-bg, rgba(255, 255, 255, 0)); + } + + &::after { + background: linear-gradient(270deg, $kendo-toolbar-bg, rgba(255, 255, 255, 0)); + } + } } // Outline Toolbar @@ -58,6 +68,19 @@ } } + .k-toolbar-outline, + .k-toolbar-flat { + &.k-toolbar-scrollable { + &::before { + background: linear-gradient(90deg, $kendo-toolbar-bg, rgba(255, 255, 255, 0)); + } + + &::after { + background: linear-gradient(270deg, $kendo-toolbar-bg, rgba(255, 255, 255, 0)); + } + } + } + .k-floating-toolbar, .editorToolbarWindow.k-window-content { // stylelint-disable-line @include fill( diff --git a/packages/html/src/toolbar/index.ts b/packages/html/src/toolbar/index.ts index 19e2110cb4c..fe405dc1378 100644 --- a/packages/html/src/toolbar/index.ts +++ b/packages/html/src/toolbar/index.ts @@ -4,3 +4,5 @@ export * from './toolbar-item.spec'; export * from './toolbar-popup.spec'; export * from './templates/toolbar-normal'; export * from './templates/toolbar-resizable'; +export * from './templates/toolbar-scrollable'; +export * from './templates/toolbar-section'; diff --git a/packages/html/src/toolbar/templates/toolbar-resizable.tsx b/packages/html/src/toolbar/templates/toolbar-resizable.tsx index adeb48de47c..ce060c740ea 100644 --- a/packages/html/src/toolbar/templates/toolbar-resizable.tsx +++ b/packages/html/src/toolbar/templates/toolbar-resizable.tsx @@ -3,6 +3,7 @@ import { Button } from '../../button'; import { ButtonGroup } from '../../button-group'; import { MenuButton } from '../../menu-button'; import { SplitButton } from '../../split-button'; +import { ToolbarSeparator } from "../toolbar-separator"; export const ToolbarResizable = (props) => ( ( , + , ]} {...props}> diff --git a/packages/html/src/toolbar/templates/toolbar-scrollable.tsx b/packages/html/src/toolbar/templates/toolbar-scrollable.tsx new file mode 100644 index 00000000000..1034a4765ad --- /dev/null +++ b/packages/html/src/toolbar/templates/toolbar-scrollable.tsx @@ -0,0 +1,28 @@ +import { Toolbar } from "../toolbar.spec"; +import { Button } from '../../button'; +import { ButtonGroup } from '../../button-group'; +import { MenuButton } from '../../menu-button'; +import { SplitButton } from '../../split-button'; + +export const ToolbarScrollable = (props) => ( + Button, + , + Split button, + + + + + , + , + , + Split button, + + + + + + ]} + {...props}> + +); diff --git a/packages/html/src/toolbar/templates/toolbar-section.tsx b/packages/html/src/toolbar/templates/toolbar-section.tsx new file mode 100644 index 00000000000..65acb7f10d3 --- /dev/null +++ b/packages/html/src/toolbar/templates/toolbar-section.tsx @@ -0,0 +1,35 @@ +import { Toolbar } from "../toolbar.spec"; +import { Button } from '../../button'; +import { ButtonGroup } from '../../button-group'; +import { MenuButton } from '../../menu-button'; +import { SplitButton } from '../../split-button'; +import { ToolbarSeparator } from "../toolbar-separator"; +import ToolbarPopup from "../toolbar-popup.spec"; + +export const ToolbarSection = ({ fillMode, size, ...other }: any) => ( + <> + Button, + , + + + + + , + , + + ]} + {...other}> + + + Split button + + + + + + + + + +); diff --git a/packages/html/src/toolbar/tests/toolbar-adaptive.tsx b/packages/html/src/toolbar/tests/toolbar-adaptive.tsx index 58aba48c14f..7c8734b4e82 100644 --- a/packages/html/src/toolbar/tests/toolbar-adaptive.tsx +++ b/packages/html/src/toolbar/tests/toolbar-adaptive.tsx @@ -2,7 +2,7 @@ import { Button } from '../../button'; import { ButtonGroup } from '../../button-group'; import { ActionSheet, ActionSheetHeader } from '../../action-sheet'; import { MenuItem, MenuSeparator, MenuList } from '../../menu'; -import { ToolbarResizable } from '..'; +import { ToolbarResizable, ToolbarSeparator } from '..'; const styles = ` #test-area { @@ -32,6 +32,7 @@ export default () =>( + diff --git a/packages/html/src/toolbar/tests/toolbar-scrollable.tsx b/packages/html/src/toolbar/tests/toolbar-scrollable.tsx new file mode 100644 index 00000000000..5397f09f56e --- /dev/null +++ b/packages/html/src/toolbar/tests/toolbar-scrollable.tsx @@ -0,0 +1,40 @@ +import { ToolbarScrollable } from '..'; + + +export default () =>( + <> +
+ + Toolbar Buttons Around +
+ +
+ + Toolbar Buttons Start +
+ +
+ + Toolbar Buttons End +
+ +
+ + Toolbar No Buttons Scroll Start +
+ +
+ + Toolbar No Buttons Scroll End +
+ +
+ + RTL +
+ +
+ +
+ +); diff --git a/packages/html/src/toolbar/tests/toolbar-section.tsx b/packages/html/src/toolbar/tests/toolbar-section.tsx new file mode 100644 index 00000000000..9f85e7f25c9 --- /dev/null +++ b/packages/html/src/toolbar/tests/toolbar-section.tsx @@ -0,0 +1,37 @@ +import { ToolbarSection } from '../templates/toolbar-section'; + + +const styles = ` + .k-animation-container { + width: 100%; + } + + .toolbar-popup-section { + position: relative; + height: 200px; + } +`; + +export default () =>( + <> + +
+ + Toolbar Popup Section +
+ +
+ + Toolbar Popup Section Flat +
+ +
+ + Toolbar Popup Section +
+ +
+ +
+ +); diff --git a/packages/html/src/toolbar/tests/toolbar-sizes.tsx b/packages/html/src/toolbar/tests/toolbar-sizes.tsx index 9cf1d455460..677b4fcbd26 100644 --- a/packages/html/src/toolbar/tests/toolbar-sizes.tsx +++ b/packages/html/src/toolbar/tests/toolbar-sizes.tsx @@ -30,6 +30,7 @@ export default () =>( + diff --git a/packages/html/src/toolbar/tests/toolbar.tsx b/packages/html/src/toolbar/tests/toolbar.tsx index dbc0cafe81b..9d57608fdc1 100644 --- a/packages/html/src/toolbar/tests/toolbar.tsx +++ b/packages/html/src/toolbar/tests/toolbar.tsx @@ -31,6 +31,7 @@ export default () =>( + @@ -55,6 +56,7 @@ export default () =>( + @@ -76,6 +78,7 @@ export default () =>( + @@ -87,6 +90,7 @@ export default () =>( + @@ -98,6 +102,7 @@ export default () =>( + @@ -112,6 +117,7 @@ export default () =>( + diff --git a/packages/html/src/toolbar/toolbar-popup.spec.tsx b/packages/html/src/toolbar/toolbar-popup.spec.tsx index ff6e4c96e8b..1cb456924c1 100644 --- a/packages/html/src/toolbar/toolbar-popup.spec.tsx +++ b/packages/html/src/toolbar/toolbar-popup.spec.tsx @@ -1,19 +1,33 @@ -import { classNames } from '../misc'; +import { classNames, optionClassNames, Size } from '../misc'; import { Popup } from '../popup'; export const TOOLBARPOPUP_CLASSNAME = `k-toolbar-popup`; const states = []; -const options = {}; +const options = { + size: [Size.small, Size.medium, Size.large], +}; -const defaultOptions = {}; +export type KendoToolbarPopupProps = { + size?: (typeof options.size)[number] | null; + section?: boolean; +}; + +const defaultOptions = { + size: Size.medium, +}; export const ToolbarPopup = ( - props: React.HTMLAttributes + props: KendoToolbarPopupProps & + React.HTMLAttributes ) => { - const { ...other } = props; + const { + size=defaultOptions.size, + section, + ...other + } = props; return ( - {props.children} + {section + ? {props.children} + : props.children + } + ); }; diff --git a/packages/html/src/toolbar/toolbar.spec.tsx b/packages/html/src/toolbar/toolbar.spec.tsx index 08e034931f2..539a2fd7d8f 100644 --- a/packages/html/src/toolbar/toolbar.spec.tsx +++ b/packages/html/src/toolbar/toolbar.spec.tsx @@ -6,6 +6,7 @@ import { DropdownList } from '../dropdownlist'; import { MenuButton } from '../menu-button'; import SplitButton from '../split-button/split-button.spec'; import { classNames, optionClassNames, stateClassNames, States, Size, FillMode } from '../misc'; +import { ToolbarSeparator } from './toolbar-separator'; export const TOOLBAR_CLASSNAME = `k-toolbar`; @@ -25,6 +26,10 @@ export type KendoToolbarOptions = { export type KendoToolbarProps = KendoToolbarOptions & { resizable?: boolean; + scrollable?: boolean; + scrollButtons?: 'hidden' | 'start' | 'end' | 'around'; + scrollingPosition?: 'start' | 'end'; + section?: boolean; }; export type KendoToolbarState = { [K in (typeof states)[number]]?: boolean }; @@ -44,6 +49,10 @@ export const Toolbar = ( fillMode = defaultOptions.fillMode, focus, resizable, + scrollable, + scrollButtons, + scrollingPosition, + section, ...other } = props; @@ -179,10 +188,51 @@ export const Toolbar = ( }), { [`${TOOLBAR_CLASSNAME}-resizable`]: resizable, + [`${TOOLBAR_CLASSNAME}-scrollable`]: scrollable, + [`${TOOLBAR_CLASSNAME}-scrollable-buttons`]: (scrollButtons && scrollButtons !== 'hidden'), + [`${TOOLBAR_CLASSNAME}-scrollable-${scrollingPosition}`]: scrollingPosition, + [`${TOOLBAR_CLASSNAME}-section`]: section, } )} > - {toolbarChildren} + {!scrollable && toolbarChildren} + + {scrollable && (scrollButtons === 'hidden' || !scrollButtons) && + {toolbarChildren} + } + + {scrollable && scrollButtons === 'start' && + <> + + + + + +
{toolbarChildren}
+ + } + + {scrollable && scrollButtons === 'end' && + <> +
{toolbarChildren}
+ + + + + + + } + + {scrollable && scrollButtons === 'around' && + <> + + +
{toolbarChildren}
+ + + + } + ); };