primevue
Version:
[](https://opensource.org/licenses/MIT) [](https://badge.fury.io/js/primevue) [ • 25.1 kB
JavaScript
import { ObjectUtils, DomHandler, ZIndexUtils, ConnectedOverlayScrollHandler } from 'primevue/utils';
import OverlayEventBus from 'primevue/overlayeventbus';
import Ripple from 'primevue/ripple';
import { resolveComponent, resolveDirective, openBlock, createBlock, Fragment, renderList, withDirectives, createVNode, resolveDynamicComponent, toDisplayString, createCommentVNode, renderSlot, createTextVNode, Teleport, Transition, withCtx } from 'vue';
var script = {
name: 'CascadeSelectSub',
emits: ['option-select','optiongroup-select'],
props: {
selectionPath: Array,
level: Number,
options: Array,
optionLabel: String,
optionValue: String,
optionGroupLabel: String,
optionGroupChildren: Array,
parentActive: Boolean,
dirty: Boolean,
templates: null,
root: Boolean
},
data() {
return {
activeOption: null
}
},
mounted() {
if (this.selectionPath && this.options && !this.dirty) {
for (let option of this.options) {
if (this.selectionPath.includes(option)) {
this.activeOption = option;
break;
}
}
}
if (!this.root) {
this.position();
}
},
watch: {
parentActive(newValue) {
if (!newValue) {
this.activeOption = null;
}
}
},
methods: {
onOptionClick(event, option) {
if (this.isOptionGroup(option)) {
this.activeOption = (this.activeOption === option) ? null : option;
this.$emit('optiongroup-select', {
originalEvent: event,
value: option
});
}
else {
this.$emit('option-select', {
originalEvent: event,
value: this.getOptionValue(option)
});
}
},
onOptionSelect(event) {
this.$emit('option-select', event);
},
onOptionGroupSelect(event) {
this.$emit('optiongroup-select', event);
},
getOptionLabel(option) {
return this.optionLabel ? ObjectUtils.resolveFieldData(option, this.optionLabel) : option;
},
getOptionValue(option) {
return this.optionValue ? ObjectUtils.resolveFieldData(option, this.optionValue) : option;
},
getOptionGroupLabel(optionGroup) {
return this.optionGroupLabel ? ObjectUtils.resolveFieldData(optionGroup, this.optionGroupLabel) : null;
},
getOptionGroupChildren(optionGroup) {
return ObjectUtils.resolveFieldData(optionGroup, this.optionGroupChildren[this.level]);
},
isOptionGroup(option) {
return Object.prototype.hasOwnProperty.call(option, this.optionGroupChildren[this.level]);
},
getOptionLabelToRender(option) {
return this.isOptionGroup(option) ? this.getOptionGroupLabel(option) : this.getOptionLabel(option);
},
getItemClass(option) {
return [
'p-cascadeselect-item', {
'p-cascadeselect-item-group': this.isOptionGroup(option),
'p-cascadeselect-item-active p-highlight': this.isOptionActive(option)
}
]
},
isOptionActive(option) {
return this.activeOption === option;
},
onKeyDown(event, option, index) {
switch (event.key) {
case 'Down':
case 'ArrowDown':
var nextItem = this.$el.children[index + 1];
if (nextItem) {
nextItem.children[0].focus();
}
break;
case 'Up':
case 'ArrowUp':
var prevItem = this.$el.children[index - 1];
if (prevItem) {
prevItem.children[0].focus();
}
break;
case 'Right':
case 'ArrowRight':
if (this.isOptionGroup(option)) {
if (this.isOptionActive(option)) {
event.currentTarget.nextElementSibling.children[0].children[0].focus();
}
else {
this.activeOption = option;
}
}
break;
case 'Left':
case 'ArrowLeft':
this.activeOption = null;
var parentList = event.currentTarget.parentElement.parentElement.previousElementSibling;
if (parentList) {
parentList.focus();
}
break;
case 'Enter':
this.onOptionClick(event, option);
break;
}
event.preventDefault();
},
position() {
const parentItem = this.$el.parentElement;
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: {
'ripple': Ripple
}
};
const _hoisted_1 = {
class: "p-cascadeselect-panel p-cascadeselect-items",
role: "listbox",
"aria-orientation": "horizontal"
};
const _hoisted_2 = {
key: 1,
class: "p-cascadeselect-item-text"
};
const _hoisted_3 = {
key: 2,
class: "p-cascadeselect-group-icon pi pi-angle-right"
};
function render(_ctx, _cache, $props, $setup, $data, $options) {
const _component_CascadeSelectSub = resolveComponent("CascadeSelectSub", true);
const _directive_ripple = resolveDirective("ripple");
return (openBlock(), createBlock("ul", _hoisted_1, [
(openBlock(true), createBlock(Fragment, null, renderList($props.options, (option, i) => {
return (openBlock(), createBlock("li", {
key: $options.getOptionLabelToRender(option),
class: $options.getItemClass(option),
role: "none"
}, [
withDirectives(createVNode("div", {
class: "p-cascadeselect-item-content",
onClick: $event => ($options.onOptionClick($event, option)),
tabindex: "0",
onKeydown: $event => ($options.onKeyDown($event, option, i))
}, [
($props.templates['option'])
? (openBlock(), createBlock(resolveDynamicComponent($props.templates['option']), {
key: 0,
option: option
}, null, 8, ["option"]))
: (openBlock(), createBlock("span", _hoisted_2, toDisplayString($options.getOptionLabelToRender(option)), 1)),
($options.isOptionGroup(option))
? (openBlock(), createBlock("span", _hoisted_3))
: createCommentVNode("", true)
], 40, ["onClick", "onKeydown"]), [
[_directive_ripple]
]),
($options.isOptionGroup(option) && $options.isOptionActive(option))
? (openBlock(), createBlock(_component_CascadeSelectSub, {
key: 0,
class: "p-cascadeselect-sublist",
selectionPath: $props.selectionPath,
options: $options.getOptionGroupChildren(option),
optionLabel: $props.optionLabel,
optionValue: $props.optionValue,
level: $props.level + 1,
onOptionSelect: $options.onOptionSelect,
onOptiongroupSelect: $options.onOptionGroupSelect,
optionGroupLabel: $props.optionGroupLabel,
optionGroupChildren: $props.optionGroupChildren,
parentActive: $options.isOptionActive(option),
dirty: $props.dirty,
templates: $props.templates
}, null, 8, ["selectionPath", "options", "optionLabel", "optionValue", "level", "onOptionSelect", "onOptiongroupSelect", "optionGroupLabel", "optionGroupChildren", "parentActive", "dirty", "templates"]))
: createCommentVNode("", true)
], 2))
}), 128))
]))
}
script.render = render;
var script$1 = {
name: 'CascadeSelect',
emits: ['update:modelValue','change','group-change', 'before-show','before-hide','hide','show'],
data() {
return {
selectionPath: null,
focused: false,
overlayVisible: false,
dirty: false
};
},
props: {
modelValue: null,
options: Array,
optionLabel: String,
optionValue: String,
optionGroupLabel: String,
optionGroupChildren: Array,
placeholder: String,
disabled: Boolean,
dataKey: null,
inputId: String,
tabindex: String,
ariaLabelledBy: null,
appendTo: {
type: String,
default: 'body'
},
panelClass: null,
loading: {
type: Boolean,
default: false
},
loadingIcon: {
type: String,
default: 'pi pi-spinner pi-spin'
}
},
outsideClickListener: null,
scrollHandler: null,
resizeListener: null,
overlay: null,
beforeUnmount() {
this.unbindOutsideClickListener();
this.unbindResizeListener();
if (this.scrollHandler) {
this.scrollHandler.destroy();
this.scrollHandler = null;
}
if (this.overlay) {
ZIndexUtils.clear(this.overlay);
this.overlay = null;
}
},
mounted() {
this.updateSelectionPath();
},
watch: {
modelValue() {
this.updateSelectionPath();
}
},
methods: {
onOptionSelect(event) {
this.$emit('update:modelValue', event.value);
this.$emit('change', event);
this.hide();
this.$refs.focusInput.focus();
},
onOptionGroupSelect(event) {
this.dirty = true;
this.$emit('group-change', event);
},
getOptionLabel(option) {
return this.optionLabel ? ObjectUtils.resolveFieldData(option, this.optionLabel) : option;
},
getOptionValue(option) {
return this.optionValue ? ObjectUtils.resolveFieldData(option, this.optionValue) : option;
},
getOptionGroupChildren(optionGroup, level) {
return ObjectUtils.resolveFieldData(optionGroup, this.optionGroupChildren[level]);
},
isOptionGroup(option, level) {
return Object.prototype.hasOwnProperty.call(option, this.optionGroupChildren[level]);
},
updateSelectionPath() {
let path;
if (this.modelValue != null && this.options) {
for (let option of this.options) {
path = this.findModelOptionInGroup(option, 0);
if (path) {
break;
}
}
}
this.selectionPath = path;
},
findModelOptionInGroup(option, level) {
if (this.isOptionGroup(option, level)) {
let selectedOption;
for (let childOption of this.getOptionGroupChildren(option, level)) {
selectedOption = this.findModelOptionInGroup(childOption, level + 1);
if (selectedOption) {
selectedOption.unshift(option);
return selectedOption;
}
}
}
else if ((ObjectUtils.equals(this.modelValue, this.getOptionValue(option), this.dataKey))) {
return [option];
}
return null;
},
show() {
this.$emit('before-show');
this.overlayVisible = true;
},
hide() {
this.$emit('before-hide');
this.overlayVisible = false;
},
onFocus() {
this.focused = true;
},
onBlur() {
this.focused = false;
},
onClick(event) {
if (this.disabled || this.loading) {
return;
}
if (!this.overlay || !this.overlay.contains(event.target)) {
if (this.overlayVisible)
this.hide();
else
this.show();
this.$refs.focusInput.focus();
}
},
onOverlayEnter(el) {
ZIndexUtils.set('overlay', el, this.$primevue.config.zIndex.overlay);
this.alignOverlay();
this.bindOutsideClickListener();
this.bindScrollListener();
this.bindResizeListener();
this.$emit('show');
},
onOverlayLeave() {
this.unbindOutsideClickListener();
this.unbindScrollListener();
this.unbindResizeListener();
this.$emit('hide');
this.overlay = null;
this.dirty = false;
},
onOverlayAfterLeave(el) {
ZIndexUtils.clear(el);
},
alignOverlay() {
if (this.appendDisabled) {
DomHandler.relativePosition(this.overlay, this.$el);
}
else {
this.overlay.style.minWidth = DomHandler.getOuterWidth(this.$el) + 'px';
DomHandler.absolutePosition(this.overlay, this.$el);
}
},
bindOutsideClickListener() {
if (!this.outsideClickListener) {
this.outsideClickListener = (event) => {
if (this.overlayVisible && this.overlay && !this.$el.contains(event.target) && !this.overlay.contains(event.target)) {
this.hide();
}
};
document.addEventListener('click', this.outsideClickListener);
}
},
unbindOutsideClickListener() {
if (this.outsideClickListener) {
document.removeEventListener('click', this.outsideClickListener);
this.outsideClickListener = null;
}
},
bindScrollListener() {
if (!this.scrollHandler) {
this.scrollHandler = new ConnectedOverlayScrollHandler(this.$refs.container, () => {
if (this.overlayVisible) {
this.hide();
}
});
}
this.scrollHandler.bindScrollListener();
},
unbindScrollListener() {
if (this.scrollHandler) {
this.scrollHandler.unbindScrollListener();
}
},
bindResizeListener() {
if (!this.resizeListener) {
this.resizeListener = () => {
if (this.overlayVisible) {
this.hide();
}
};
window.addEventListener('resize', this.resizeListener);
}
},
unbindResizeListener() {
if (this.resizeListener) {
window.removeEventListener('resize', this.resizeListener);
this.resizeListener = null;
}
},
overlayRef(el) {
this.overlay = el;
},
onKeyDown(event) {
switch(event.key) {
case 'Down':
case 'ArrowDown':
if (this.overlayVisible) {
DomHandler.findSingle(this.overlay, '.p-cascadeselect-item').children[0].focus();
}
else if (event.altKey && this.options && this.options.length) {
this.show();
}
event.preventDefault();
break;
case 'Escape':
if (this.overlayVisible) {
this.hide();
event.preventDefault();
}
break;
case 'Tab':
this.hide();
break;
}
},
onOverlayClick(event) {
OverlayEventBus.emit('overlay-click', {
originalEvent: event,
target: this.$el
});
}
},
computed: {
containerClass() {
return [
'p-cascadeselect p-component p-inputwrapper',
{
'p-disabled': this.disabled,
'p-focus': this.focused,
'p-inputwrapper-filled': this.modelValue,
'p-inputwrapper-focus': this.focused || this.overlayVisible
}
];
},
labelClass() {
return [
'p-cascadeselect-label',
{
'p-placeholder': this.label === this.placeholder,
'p-cascadeselect-label-empty': !this.$slots['value'] && (this.label === 'p-emptylabel' || this.label.length === 0)
}
];
},
label() {
if (this.selectionPath)
return this.getOptionLabel(this.selectionPath[this.selectionPath.length - 1]);
else
return this.placeholder||'p-emptylabel';
},
panelStyleClass() {
return ['p-cascadeselect-panel p-component', this.panelClass, {
'p-input-filled': this.$primevue.config.inputStyle === 'filled',
'p-ripple-disabled': this.$primevue.config.ripple === false
}];
},
appendDisabled() {
return this.appendTo === 'self';
},
appendTarget() {
return this.appendDisabled ? null : this.appendTo;
},
dropdownIconClass() {
return ['p-cascadeselect-trigger-icon', this.loading ? this.loadingIcon : 'pi pi-chevron-down'];
}
},
components: {
'CascadeSelectSub': script
}
};
const _hoisted_1$1 = { class: "p-hidden-accessible" };
const _hoisted_2$1 = { class: "p-cascadeselect-items-wrapper" };
function render$1(_ctx, _cache, $props, $setup, $data, $options) {
const _component_CascadeSelectSub = resolveComponent("CascadeSelectSub");
return (openBlock(), createBlock("div", {
ref: "container",
class: $options.containerClass,
onClick: _cache[5] || (_cache[5] = $event => ($options.onClick($event)))
}, [
createVNode("div", _hoisted_1$1, [
createVNode("input", {
ref: "focusInput",
type: "text",
id: $props.inputId,
readonly: "",
disabled: $props.disabled,
onFocus: _cache[1] || (_cache[1] = (...args) => ($options.onFocus && $options.onFocus(...args))),
onBlur: _cache[2] || (_cache[2] = (...args) => ($options.onBlur && $options.onBlur(...args))),
onKeydown: _cache[3] || (_cache[3] = (...args) => ($options.onKeyDown && $options.onKeyDown(...args))),
tabindex: $props.tabindex,
"aria-haspopup": "listbox",
"aria-expanded": $data.overlayVisible,
"aria-labelledby": $props.ariaLabelledBy
}, null, 40, ["id", "disabled", "tabindex", "aria-expanded", "aria-labelledby"])
]),
createVNode("span", { class: $options.labelClass }, [
renderSlot(_ctx.$slots, "value", {
value: $props.modelValue,
placeholder: $props.placeholder
}, () => [
createTextVNode(toDisplayString($options.label), 1)
])
], 2),
createVNode("div", {
class: "p-cascadeselect-trigger",
role: "button",
"aria-haspopup": "listbox",
"aria-expanded": $data.overlayVisible
}, [
createVNode("span", { class: $options.dropdownIconClass }, null, 2)
], 8, ["aria-expanded"]),
(openBlock(), createBlock(Teleport, {
to: $options.appendTarget,
disabled: $options.appendDisabled
}, [
createVNode(Transition, {
name: "p-connected-overlay",
onEnter: $options.onOverlayEnter,
onLeave: $options.onOverlayLeave,
onAfterLeave: $options.onOverlayAfterLeave
}, {
default: withCtx(() => [
($data.overlayVisible)
? (openBlock(), createBlock("div", {
key: 0,
ref: $options.overlayRef,
class: $options.panelStyleClass,
onClick: _cache[4] || (_cache[4] = (...args) => ($options.onOverlayClick && $options.onOverlayClick(...args)))
}, [
createVNode("div", _hoisted_2$1, [
createVNode(_component_CascadeSelectSub, {
options: $props.options,
selectionPath: $data.selectionPath,
optionLabel: $props.optionLabel,
optionValue: $props.optionValue,
level: 0,
templates: _ctx.$slots,
optionGroupLabel: $props.optionGroupLabel,
optionGroupChildren: $props.optionGroupChildren,
onOptionSelect: $options.onOptionSelect,
onOptiongroupSelect: $options.onOptionGroupSelect,
dirty: $data.dirty,
root: true
}, null, 8, ["options", "selectionPath", "optionLabel", "optionValue", "templates", "optionGroupLabel", "optionGroupChildren", "onOptionSelect", "onOptiongroupSelect", "dirty"])
])
], 2))
: createCommentVNode("", true)
]),
_: 1
}, 8, ["onEnter", "onLeave", "onAfterLeave"])
], 8, ["to", "disabled"]))
], 2))
}
function styleInject(css, ref) {
if ( ref === void 0 ) ref = {};
var insertAt = ref.insertAt;
if (!css || typeof document === 'undefined') { return; }
var head = document.head || document.getElementsByTagName('head')[0];
var style = document.createElement('style');
style.type = 'text/css';
if (insertAt === 'top') {
if (head.firstChild) {
head.insertBefore(style, head.firstChild);
} else {
head.appendChild(style);
}
} else {
head.appendChild(style);
}
if (style.styleSheet) {
style.styleSheet.cssText = css;
} else {
style.appendChild(document.createTextNode(css));
}
}
var css_248z = "\n.p-cascadeselect {\n display: -webkit-inline-box;\n display: -ms-inline-flexbox;\n display: inline-flex;\n cursor: pointer;\n position: relative;\n -webkit-user-select: none;\n -moz-user-select: none;\n -ms-user-select: none;\n user-select: none;\n}\n.p-cascadeselect-trigger {\n display: -webkit-box;\n display: -ms-flexbox;\n display: flex;\n -webkit-box-align: center;\n -ms-flex-align: center;\n align-items: center;\n -webkit-box-pack: center;\n -ms-flex-pack: center;\n justify-content: center;\n -ms-flex-negative: 0;\n flex-shrink: 0;\n}\n.p-cascadeselect-label {\n display: block;\n white-space: nowrap;\n overflow: hidden;\n -webkit-box-flex: 1;\n -ms-flex: 1 1 auto;\n flex: 1 1 auto;\n width: 1%;\n text-overflow: ellipsis;\n cursor: pointer;\n}\n.p-cascadeselect-label-empty {\n overflow: hidden;\n visibility: hidden;\n}\n.p-cascadeselect .p-cascadeselect-panel {\n min-width: 100%;\n}\n.p-cascadeselect-panel {\n position: absolute;\n}\n.p-cascadeselect-item {\n cursor: pointer;\n font-weight: normal;\n white-space: nowrap;\n}\n.p-cascadeselect-item-content {\n display: -webkit-box;\n display: -ms-flexbox;\n display: flex;\n -webkit-box-align: center;\n -ms-flex-align: center;\n align-items: center;\n overflow: hidden;\n position: relative;\n}\n.p-cascadeselect-group-icon {\n margin-left: auto;\n}\n.p-cascadeselect-items {\n margin: 0;\n padding: 0;\n list-style-type: none;\n min-width: 100%;\n}\n.p-fluid .p-cascadeselect {\n display: -webkit-box;\n display: -ms-flexbox;\n display: flex;\n}\n.p-fluid .p-cascadeselect .p-cascadeselect-label {\n width: 1%;\n}\n.p-cascadeselect-sublist {\n position: absolute;\n min-width: 100%;\n z-index: 1;\n display: none;\n}\n.p-cascadeselect-item-active {\n overflow: visible !important;\n}\n.p-cascadeselect-item-active > .p-cascadeselect-sublist {\n display: block;\n left: 100%;\n top: 0;\n}\n";
styleInject(css_248z);
script$1.render = render$1;
export default script$1;