diff --git a/packages/primevue/src/tieredmenu/BaseTieredMenu.vue b/packages/primevue/src/tieredmenu/BaseTieredMenu.vue index 593965797..4febf5901 100644 --- a/packages/primevue/src/tieredmenu/BaseTieredMenu.vue +++ b/packages/primevue/src/tieredmenu/BaseTieredMenu.vue @@ -18,6 +18,10 @@ export default { type: [String, Object], default: 'body' }, + breakpoint: { + type: String, + default: '960px' + }, autoZIndex: { type: Boolean, default: true diff --git a/packages/primevue/src/tieredmenu/TieredMenu.d.ts b/packages/primevue/src/tieredmenu/TieredMenu.d.ts index f541c87de..efd4c706c 100755 --- a/packages/primevue/src/tieredmenu/TieredMenu.d.ts +++ b/packages/primevue/src/tieredmenu/TieredMenu.d.ts @@ -226,6 +226,11 @@ export interface TieredMenuProps { * @defaultValue false */ popup?: boolean | undefined; + /** + * The breakpoint to define the maximum width boundary. + * @defaultValue 960px + */ + breakpoint?: string | undefined; /** * A valid query selector or an HTMLElement to specify where the overlay gets attached. * @defaultValue body diff --git a/packages/primevue/src/tieredmenu/TieredMenu.vue b/packages/primevue/src/tieredmenu/TieredMenu.vue index 3d9d77e09..8700b3d22 100755 --- a/packages/primevue/src/tieredmenu/TieredMenu.vue +++ b/packages/primevue/src/tieredmenu/TieredMenu.vue @@ -57,6 +57,7 @@ export default { inheritAttrs: false, emits: ['focus', 'blur', 'before-show', 'before-hide', 'hide', 'show'], outsideClickListener: null, + matchMediaListener: null, scrollHandler: null, resizeListener: null, target: null, @@ -72,7 +73,9 @@ export default { activeItemPath: [], visible: !this.popup, submenuVisible: false, - dirty: false + dirty: false, + query: null, + queryMatches: false }; }, watch: { @@ -93,10 +96,12 @@ export default { }, mounted() { this.id = this.id || UniqueComponentId(); + this.bindMatchMediaListener(); }, beforeUnmount() { this.unbindOutsideClickListener(); this.unbindResizeListener(); + this.unbindMatchMediaListener(); if (this.scrollHandler) { this.scrollHandler.destroy(); @@ -498,6 +503,26 @@ export default { this.resizeListener = null; } }, + bindMatchMediaListener() { + if (!this.matchMediaListener) { + const query = matchMedia(`(max-width: ${this.breakpoint})`); + + this.query = query; + this.queryMatches = query.matches; + + this.matchMediaListener = () => { + this.queryMatches = query.matches; + }; + + this.query.addEventListener('change', this.matchMediaListener); + } + }, + unbindMatchMediaListener() { + if (this.matchMediaListener) { + this.query.removeEventListener('change', this.matchMediaListener); + this.matchMediaListener = null; + } + }, isItemMatched(processedItem) { return this.isValidItem(processedItem) && this.getProccessedItemLabel(processedItem)?.toLocaleLowerCase().startsWith(this.searchValue.toLocaleLowerCase()); }, diff --git a/packages/primevue/src/tieredmenu/style/TieredMenuStyle.js b/packages/primevue/src/tieredmenu/style/TieredMenuStyle.js index 06fde8938..75e61c9e7 100644 --- a/packages/primevue/src/tieredmenu/style/TieredMenuStyle.js +++ b/packages/primevue/src/tieredmenu/style/TieredMenuStyle.js @@ -126,6 +126,47 @@ const theme = ({ dt }) => ` .p-tieredmenu-enter-active { transition: opacity 250ms; } + +.p-tieredmenu-mobile { + position: relative; +} + +.p-tieredmenu-mobile .p-tieredmenu-button { + display: flex; +} + +.p-tieredmenu-mobile .p-tieredmenu-root-list > .p-tieredmenu-item > .p-tieredmenu-item-content > .p-tieredmenu-item-link { + padding: ${dt('tieredmenu.item.padding')}; +} + +.p-tieredmenu-mobile .p-tieredmenu-root-list .p-tieredmenu-separator { + border-top: 1px solid ${dt('tieredmenu.separator.border.color')}; +} + +.p-tieredmenu-mobile .p-tieredmenu-root-list > .p-tieredmenu-item > .p-tieredmenu-item-content .p-tieredmenu-submenu-icon { + margin-left: auto; + transition: transform 0.2s; +} + +.p-tieredmenu-mobile .p-tieredmenu-root-list > .p-tieredmenu-item-active > .p-tieredmenu-item-content .p-tieredmenu-submenu-icon { + transform: rotate(-90deg); +} + +.p-tieredmenu-mobile .p-tieredmenu-submenu .p-tieredmenu-submenu-icon { + transition: transform 0.2s; + transform: rotate(90deg); +} + +.p-tieredmenu-mobile .p-tieredmenu-item-active > .p-tieredmenu-item-content .p-tieredmenu-submenu-icon { + transform: rotate(-90deg); +} + +.p-tieredmenu-mobile .p-tieredmenu-submenu { + position: static; + box-shadow: none; + border: 0 none; + padding-left: ${dt('tieredmenu.submenu.mobile.indent')}; +} `; const inlineStyles = { @@ -133,10 +174,12 @@ const inlineStyles = { }; const classes = { - root: ({ instance, props }) => [ + root: ({ props, instance }) => [ 'p-tieredmenu p-component', { - 'p-tieredmenu-overlay': props.popup + 'p-tieredmenu-overlay': props.popup, + 'p-tieredmenu-mobile': instance.queryMatches, + 'p-tieredmenu-mobile-active': instance.mobileActive } ], start: 'p-tieredmenu-start', diff --git a/packages/themes/src/presets/aura/tieredmenu/index.js b/packages/themes/src/presets/aura/tieredmenu/index.js index f157f99a0..f11781b90 100644 --- a/packages/themes/src/presets/aura/tieredmenu/index.js +++ b/packages/themes/src/presets/aura/tieredmenu/index.js @@ -26,6 +26,9 @@ export default { activeColor: '{navigation.item.icon.active.color}' } }, + submenu: { + mobileIndent: '1rem' + }, submenuLabel: { padding: '{navigation.submenu.label.padding}', fontWeight: '{navigation.submenu.label.font.weight}', diff --git a/packages/themes/src/presets/lara/tieredmenu/index.js b/packages/themes/src/presets/lara/tieredmenu/index.js index 0d328e6d3..10b0ec35a 100644 --- a/packages/themes/src/presets/lara/tieredmenu/index.js +++ b/packages/themes/src/presets/lara/tieredmenu/index.js @@ -26,6 +26,9 @@ export default { activeColor: '{navigation.item.icon.active.color}' } }, + submenu: { + mobileIndent: '1.25rem' + }, submenuIcon: { size: '{navigation.submenu.icon.size}', color: '{navigation.submenu.icon.color}', diff --git a/packages/themes/src/presets/material/tieredmenu/index.js b/packages/themes/src/presets/material/tieredmenu/index.js index f157f99a0..f11781b90 100644 --- a/packages/themes/src/presets/material/tieredmenu/index.js +++ b/packages/themes/src/presets/material/tieredmenu/index.js @@ -26,6 +26,9 @@ export default { activeColor: '{navigation.item.icon.active.color}' } }, + submenu: { + mobileIndent: '1rem' + }, submenuLabel: { padding: '{navigation.submenu.label.padding}', fontWeight: '{navigation.submenu.label.font.weight}', diff --git a/packages/themes/src/presets/nora/tieredmenu/index.js b/packages/themes/src/presets/nora/tieredmenu/index.js index f157f99a0..f11781b90 100644 --- a/packages/themes/src/presets/nora/tieredmenu/index.js +++ b/packages/themes/src/presets/nora/tieredmenu/index.js @@ -26,6 +26,9 @@ export default { activeColor: '{navigation.item.icon.active.color}' } }, + submenu: { + mobileIndent: '1rem' + }, submenuLabel: { padding: '{navigation.submenu.label.padding}', fontWeight: '{navigation.submenu.label.font.weight}',