Fixed #4784 - Collision Enhancements
parent
a5a0ce75c8
commit
cba43b310b
|
@ -1,5 +1,5 @@
|
||||||
<template>
|
<template>
|
||||||
<ul :class="cx('list')" v-bind="level === 0 ? ptm('list') : ptm('sublist')">
|
<ul :ref="containerRef" :class="cx('list')" v-bind="level === 0 ? ptm('list') : ptm('sublist')">
|
||||||
<template v-for="(processedOption, index) of options" :key="getOptionLabelToRender(processedOption)">
|
<template v-for="(processedOption, index) of options" :key="getOptionLabelToRender(processedOption)">
|
||||||
<li
|
<li
|
||||||
:id="getOptionId(processedOption)"
|
:id="getOptionId(processedOption)"
|
||||||
|
@ -45,6 +45,7 @@
|
||||||
@option-change="onOptionChange"
|
@option-change="onOptionChange"
|
||||||
:pt="pt"
|
:pt="pt"
|
||||||
:unstyled="unstyled"
|
:unstyled="unstyled"
|
||||||
|
:isParentMount="mounted"
|
||||||
/>
|
/>
|
||||||
</li>
|
</li>
|
||||||
</template>
|
</template>
|
||||||
|
@ -62,6 +63,7 @@ export default {
|
||||||
hostName: 'CascadeSelect',
|
hostName: 'CascadeSelect',
|
||||||
extends: BaseComponent,
|
extends: BaseComponent,
|
||||||
emits: ['option-change'],
|
emits: ['option-change'],
|
||||||
|
container: null,
|
||||||
props: {
|
props: {
|
||||||
selectId: String,
|
selectId: String,
|
||||||
focusedOptionId: String,
|
focusedOptionId: String,
|
||||||
|
@ -74,12 +76,25 @@ export default {
|
||||||
optionGroupChildren: Array,
|
optionGroupChildren: Array,
|
||||||
activeOptionPath: Array,
|
activeOptionPath: Array,
|
||||||
level: Number,
|
level: Number,
|
||||||
templates: null
|
templates: null,
|
||||||
|
isParentMount: Boolean
|
||||||
|
},
|
||||||
|
data() {
|
||||||
|
return {
|
||||||
|
mounted: false
|
||||||
|
};
|
||||||
|
},
|
||||||
|
watch: {
|
||||||
|
isParentMount: {
|
||||||
|
handler(newValue) {
|
||||||
|
newValue && DomHandler.nestedPosition(this.container, this.level);
|
||||||
|
}
|
||||||
|
}
|
||||||
},
|
},
|
||||||
mounted() {
|
mounted() {
|
||||||
if (ObjectUtils.isNotEmpty(this.parentKey)) {
|
// entering order correction when an item is selected
|
||||||
this.position();
|
(this.isParentMount || this.level === 0) && DomHandler.nestedPosition(this.container, this.level);
|
||||||
}
|
this.mounted = true;
|
||||||
},
|
},
|
||||||
methods: {
|
methods: {
|
||||||
getOptionId(processedOption) {
|
getOptionId(processedOption) {
|
||||||
|
@ -121,16 +136,8 @@ export default {
|
||||||
onOptionChange(event) {
|
onOptionChange(event) {
|
||||||
this.$emit('option-change', event);
|
this.$emit('option-change', event);
|
||||||
},
|
},
|
||||||
position() {
|
containerRef(el) {
|
||||||
const parentItem = this.$el.parentElement;
|
this.container = el;
|
||||||
const containerOffset = DomHandler.getOffset(parentItem);
|
|
||||||
const viewport = DomHandler.getViewport();
|
|
||||||
const sublistWidth = this.$el.offsetParent ? this.$el.offsetWidth : DomHandler.getHiddenElementOuterWidth(this.$el);
|
|
||||||
const itemOuterWidth = DomHandler.getOuterWidth(parentItem.children[0]);
|
|
||||||
|
|
||||||
if (parseInt(containerOffset.left, 10) + itemOuterWidth + sublistWidth > viewport.width - DomHandler.calculateScrollbarWidth()) {
|
|
||||||
this.$el.style.left = '-100%';
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
directives: {
|
directives: {
|
||||||
|
|
|
@ -82,6 +82,15 @@ const css = `
|
||||||
left: 100%;
|
left: 100%;
|
||||||
top: 0;
|
top: 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.p-cascadeselect-enter-from,
|
||||||
|
.p-cascadeselect-leave-active {
|
||||||
|
opacity: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
.p-cascadeselect-enter-active {
|
||||||
|
transition: opacity 150ms;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
`;
|
`;
|
||||||
|
|
||||||
|
|
|
@ -169,22 +169,7 @@ export default {
|
||||||
return index - this.items.slice(0, index).filter((processedItem) => this.isItemVisible(processedItem) && this.getItemProp(processedItem, 'separator')).length + 1;
|
return index - this.items.slice(0, index).filter((processedItem) => this.isItemVisible(processedItem) && this.getItemProp(processedItem, 'separator')).length + 1;
|
||||||
},
|
},
|
||||||
onEnter() {
|
onEnter() {
|
||||||
this.position();
|
DomHandler.nestedPosition(this.$refs.container, this.level);
|
||||||
},
|
|
||||||
position() {
|
|
||||||
const parentItem = this.$refs.container.parentElement;
|
|
||||||
const containerOffset = DomHandler.getOffset(this.$refs.container.parentElement);
|
|
||||||
const viewport = DomHandler.getViewport();
|
|
||||||
const sublistWidth = this.$refs.container.offsetParent ? this.$refs.container.offsetWidth : DomHandler.getHiddenElementOuterWidth(this.$refs.container);
|
|
||||||
const itemOuterWidth = DomHandler.getOuterWidth(parentItem.children[0]);
|
|
||||||
|
|
||||||
this.$refs.container.style.top = '0px';
|
|
||||||
|
|
||||||
if (parseInt(containerOffset.left, 10) + itemOuterWidth + sublistWidth > viewport.width - DomHandler.calculateScrollbarWidth()) {
|
|
||||||
this.$refs.container.style.left = -1 * sublistWidth + 'px';
|
|
||||||
} else {
|
|
||||||
this.$refs.container.style.left = itemOuterWidth + 'px';
|
|
||||||
}
|
|
||||||
},
|
},
|
||||||
getMenuItemProps(processedItem, index) {
|
getMenuItemProps(processedItem, index) {
|
||||||
return {
|
return {
|
||||||
|
|
|
@ -35,7 +35,8 @@ const css = `
|
||||||
margin-left: auto;
|
margin-left: auto;
|
||||||
}
|
}
|
||||||
|
|
||||||
.p-contextmenu-enter-from {
|
.p-contextmenu-enter-from,
|
||||||
|
.p-contextmenu-leave-active {
|
||||||
opacity: 0;
|
opacity: 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -21,6 +21,7 @@
|
||||||
:templates="$slots"
|
:templates="$slots"
|
||||||
:activeItemPath="activeItemPath"
|
:activeItemPath="activeItemPath"
|
||||||
:level="0"
|
:level="0"
|
||||||
|
:visible="submenuVisible"
|
||||||
:pt="pt"
|
:pt="pt"
|
||||||
:unstyled="unstyled"
|
:unstyled="unstyled"
|
||||||
@focus="onFocus"
|
@focus="onFocus"
|
||||||
|
@ -64,6 +65,7 @@ export default {
|
||||||
focusedItemInfo: { index: -1, level: 0, parentKey: '' },
|
focusedItemInfo: { index: -1, level: 0, parentKey: '' },
|
||||||
activeItemPath: [],
|
activeItemPath: [],
|
||||||
visible: !this.popup,
|
visible: !this.popup,
|
||||||
|
submenuVisible: false,
|
||||||
dirty: false
|
dirty: false
|
||||||
};
|
};
|
||||||
},
|
},
|
||||||
|
@ -240,7 +242,10 @@ export default {
|
||||||
|
|
||||||
const activeItemPath = this.activeItemPath.filter((p) => p.parentKey !== parentKey && p.parentKey !== key);
|
const activeItemPath = this.activeItemPath.filter((p) => p.parentKey !== parentKey && p.parentKey !== key);
|
||||||
|
|
||||||
grouped && activeItemPath.push(processedItem);
|
if (grouped) {
|
||||||
|
activeItemPath.push(processedItem);
|
||||||
|
this.submenuVisible = true;
|
||||||
|
}
|
||||||
|
|
||||||
this.focusedItemInfo = { index, level, parentKey };
|
this.focusedItemInfo = { index, level, parentKey };
|
||||||
this.activeItemPath = activeItemPath;
|
this.activeItemPath = activeItemPath;
|
||||||
|
|
|
@ -1,5 +1,6 @@
|
||||||
<template>
|
<template>
|
||||||
<ul :class="level === 0 ? cx('menu') : cx('submenu')" :tabindex="tabindex" v-bind="level === 0 ? ptm('menu') : ptm('submenu')">
|
<transition name="p-tieredmenu" @enter="onEnter" v-bind="ptm('menu.transition')">
|
||||||
|
<ul v-if="level === 0 ? true : visible" :ref="containerRef" :class="level === 0 ? cx('menu') : cx('submenu')" :tabindex="tabindex" v-bind="level === 0 ? ptm('menu') : ptm('submenu')">
|
||||||
<template v-for="(processedItem, index) of items" :key="getItemKey(processedItem)">
|
<template v-for="(processedItem, index) of items" :key="getItemKey(processedItem)">
|
||||||
<li
|
<li
|
||||||
v-if="isItemVisible(processedItem) && !getItemProp(processedItem, 'separator')"
|
v-if="isItemVisible(processedItem) && !getItemProp(processedItem, 'separator')"
|
||||||
|
@ -44,6 +45,7 @@
|
||||||
:templates="templates"
|
:templates="templates"
|
||||||
:activeItemPath="activeItemPath"
|
:activeItemPath="activeItemPath"
|
||||||
:level="level + 1"
|
:level="level + 1"
|
||||||
|
:visible="isItemActive(processedItem) && isItemGroup(processedItem)"
|
||||||
:pt="pt"
|
:pt="pt"
|
||||||
:unstyled="unstyled"
|
:unstyled="unstyled"
|
||||||
@item-click="$emit('item-click', $event)"
|
@item-click="$emit('item-click', $event)"
|
||||||
|
@ -60,13 +62,14 @@
|
||||||
></li>
|
></li>
|
||||||
</template>
|
</template>
|
||||||
</ul>
|
</ul>
|
||||||
|
</transition>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script>
|
<script>
|
||||||
import BaseComponent from 'primevue/basecomponent';
|
import BaseComponent from 'primevue/basecomponent';
|
||||||
import AngleRightIcon from 'primevue/icons/angleright';
|
import AngleRightIcon from 'primevue/icons/angleright';
|
||||||
import Ripple from 'primevue/ripple';
|
import Ripple from 'primevue/ripple';
|
||||||
import { ObjectUtils } from 'primevue/utils';
|
import { DomHandler, ObjectUtils } from 'primevue/utils';
|
||||||
import { mergeProps } from 'vue';
|
import { mergeProps } from 'vue';
|
||||||
|
|
||||||
export default {
|
export default {
|
||||||
|
@ -74,6 +77,7 @@ export default {
|
||||||
hostName: 'TieredMenu',
|
hostName: 'TieredMenu',
|
||||||
extends: BaseComponent,
|
extends: BaseComponent,
|
||||||
emits: ['item-click', 'item-mouseenter'],
|
emits: ['item-click', 'item-mouseenter'],
|
||||||
|
container: null,
|
||||||
props: {
|
props: {
|
||||||
menuId: {
|
menuId: {
|
||||||
type: String,
|
type: String,
|
||||||
|
@ -87,6 +91,10 @@ export default {
|
||||||
type: Array,
|
type: Array,
|
||||||
default: null
|
default: null
|
||||||
},
|
},
|
||||||
|
visible: {
|
||||||
|
type: Boolean,
|
||||||
|
default: false
|
||||||
|
},
|
||||||
level: {
|
level: {
|
||||||
type: Number,
|
type: Number,
|
||||||
default: 0
|
default: 0
|
||||||
|
@ -143,6 +151,9 @@ export default {
|
||||||
isItemGroup(processedItem) {
|
isItemGroup(processedItem) {
|
||||||
return ObjectUtils.isNotEmpty(processedItem.items);
|
return ObjectUtils.isNotEmpty(processedItem.items);
|
||||||
},
|
},
|
||||||
|
onEnter() {
|
||||||
|
DomHandler.nestedPosition(this.container, this.level);
|
||||||
|
},
|
||||||
onItemClick(event, processedItem) {
|
onItemClick(event, processedItem) {
|
||||||
this.getItemProp(processedItem, 'command', { originalEvent: event, item: processedItem.item });
|
this.getItemProp(processedItem, 'command', { originalEvent: event, item: processedItem.item });
|
||||||
this.$emit('item-click', { originalEvent: event, processedItem, isFocus: true });
|
this.$emit('item-click', { originalEvent: event, processedItem, isFocus: true });
|
||||||
|
@ -185,6 +196,9 @@ export default {
|
||||||
this.getPTOptions(processedItem, index, 'submenuIcon')
|
this.getPTOptions(processedItem, index, 'submenuIcon')
|
||||||
)
|
)
|
||||||
};
|
};
|
||||||
|
},
|
||||||
|
containerRef(el) {
|
||||||
|
this.container = el;
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
components: {
|
components: {
|
||||||
|
|
|
@ -41,6 +41,15 @@ const css = `
|
||||||
left: 100%;
|
left: 100%;
|
||||||
top: 0;
|
top: 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.p-tieredmenu-enter-from,
|
||||||
|
.p-tieredmenu-leave-active {
|
||||||
|
opacity: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
.p-tieredmenu-enter-active {
|
||||||
|
transition: opacity 250ms;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
`;
|
`;
|
||||||
|
|
||||||
|
|
|
@ -363,6 +363,35 @@ export default {
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|
||||||
|
nestedPosition(element, level) {
|
||||||
|
if (element) {
|
||||||
|
const parentItem = element.parentElement;
|
||||||
|
const elementOffset = this.getOffset(parentItem);
|
||||||
|
const viewport = this.getViewport();
|
||||||
|
const sublistWidth = element.offsetParent ? element.offsetWidth : this.getHiddenElementOuterWidth(element);
|
||||||
|
const itemOuterWidth = this.getOuterWidth(parentItem.children[0]);
|
||||||
|
let left;
|
||||||
|
|
||||||
|
if (parseInt(elementOffset.left, 10) + itemOuterWidth + sublistWidth > viewport.width - this.calculateScrollbarWidth()) {
|
||||||
|
if (parseInt(elementOffset.left, 10) < sublistWidth) {
|
||||||
|
// for too small screens
|
||||||
|
if (level % 2 === 1) {
|
||||||
|
left = parseInt(elementOffset.left, 10) ? '-' + parseInt(elementOffset.left, 10) + 'px' : '100%';
|
||||||
|
} else if (level % 2 === 0) {
|
||||||
|
left = viewport.width - sublistWidth - this.calculateScrollbarWidth() + 'px';
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
left = '-100%';
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
left = '100%';
|
||||||
|
}
|
||||||
|
|
||||||
|
element.style.top = '0px';
|
||||||
|
element.style.left = left;
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
getParents(element, parents = []) {
|
getParents(element, parents = []) {
|
||||||
return element['parentNode'] === null ? parents : this.getParents(element.parentNode, parents.concat([element.parentNode]));
|
return element['parentNode'] === null ? parents : this.getParents(element.parentNode, parents.concat([element.parentNode]));
|
||||||
},
|
},
|
||||||
|
|
|
@ -34,6 +34,7 @@ export declare class DomHandler {
|
||||||
static getWidth(el: HTMLElement): number;
|
static getWidth(el: HTMLElement): number;
|
||||||
static absolutePosition(el: HTMLElement, target: HTMLElement): void;
|
static absolutePosition(el: HTMLElement, target: HTMLElement): void;
|
||||||
static relativePosition(el: HTMLElement, target: HTMLElement): void;
|
static relativePosition(el: HTMLElement, target: HTMLElement): void;
|
||||||
|
static nestedPosition(el: HTMLElement, level: number): void;
|
||||||
static getParents(el: HTMLElement, parents?: any[]): any[];
|
static getParents(el: HTMLElement, parents?: any[]): any[];
|
||||||
static getScrollableParents(el: HTMLElement): any[];
|
static getScrollableParents(el: HTMLElement): any[];
|
||||||
static getHiddenElementOuterHeight(el: HTMLElement): number;
|
static getHiddenElementOuterHeight(el: HTMLElement): number;
|
||||||
|
|
Loading…
Reference in New Issue