UNPKG

@dialpad/dialtone

Version:

Dialpad's Dialtone design system monorepo

403 lines (402 loc) 13 kB
"use strict"; Object.defineProperties(exports, { __esModule: { value: true }, [Symbol.toStringTag]: { value: "Module" } }); const keyboard_list_navigation = require("../../common/mixins/keyboard_list_navigation.cjs"); const dropdown_constants = require("./dropdown_constants.cjs"); const common_utils = require("../../common/utils.cjs"); const common_constants = require("../../common/constants.cjs"); const sr_only_close_button$1 = require("../../common/mixins/sr_only_close_button.cjs"); const sr_only_close_button = require("../../common/sr_only_close_button.vue.cjs"); const _pluginVue2_normalizer = require("../../_virtual/_plugin-vue2_normalizer.cjs"); const popover = require("../popover/popover.vue.cjs"); const list_item_constants = require("../list_item/list_item_constants.cjs"); const popover_constants = require("../popover/popover_constants.cjs"); const _sfc_main = { name: "DtDropdown", components: { DtPopover: popover.default, SrOnlyCloseButton: sr_only_close_button.default }, mixins: [ keyboard_list_navigation.default({ indexKey: "highlightIndex", idKey: "highlightId", listElementKey: "getListElement", listItemRole: "menuitem", afterHighlightMethod: "afterHighlight", beginningOfListMethod: "beginningOfListMethod", endOfListMethod: "endOfListMethod", activeItemKey: "activeItemEl", focusOnKeyboardNavigation: true }), sr_only_close_button$1.default ], props: { /** * Controls whether the dropdown is shown. Leaving this null will have the dropdown trigger on click by default. * If you set this value, the default trigger behavior will be disabled and you can control it as you need. * Supports .sync modifier */ open: { type: Boolean, default: null }, /** * Opens the dropdown on right click (context menu). If you set this value to `true`, * the default trigger behavior will be disabled. */ openOnContext: { type: Boolean, default: false }, /** * Vertical padding size around the list element. * @values none, small, large */ padding: { type: String, default: "small", validator: (padding) => { return Object.keys(dropdown_constants.DROPDOWN_PADDING_CLASSES).some((item) => item === padding); } }, /** * Determines modal state, dropdown has a modal overlay preventing interaction with elements * below it, but it is invisible. */ modal: { type: Boolean, default: true }, /** * Width configuration for the popover content. When its value is 'anchor', * the popover content will have the same width as the anchor. * @values null, anchor */ contentWidth: { type: String, default: null }, /** * Determines maximum height for the popover before overflow. * Possible units rem|px|em */ maxHeight: { type: String, default: "" }, /** * Determines maximum width for the popover before overflow. * Possible units rem|px|%|em */ maxWidth: { type: String, default: "" }, /** * Sets an ID on the list element of the component. Used by several aria attributes * as well as when deriving the IDs for each item. */ listId: { type: String, default() { return common_utils.getUniqueString(); } }, /** * The type of navigation that this component should support. * - "arrow-keys" for items that are navigated with UP/DOWN keys. * - "tab" for items that are navigated using the TAB key. * - "none" for static items that are not interactive. * @values arrow-keys, tab, none */ navigationType: { type: String, default: list_item_constants.LIST_ITEM_NAVIGATION_TYPES.ARROW_KEYS, validator: (t) => Object.values(list_item_constants.LIST_ITEM_NAVIGATION_TYPES).includes(t) }, /** * If the dropdown does not fit in the direction described by "placement", * it will attempt to change it's direction to the "fallbackPlacements". * * @values top, top-start, top-end, * right, right-start, right-end, * left, left-start, left-end, * bottom, bottom-start, bottom-end, * auto, auto-start, auto-end * */ fallbackPlacements: { type: Array, default: () => { return ["auto"]; } }, /** * The direction the dropdown displays relative to the anchor. */ placement: { type: String, default: "bottom" }, /** * A method that will be called when the selection goes past the beginning of the list. */ onBeginningOfList: { type: Function, default: null }, /** * A method that will be called when the selection goes past the end of the list. */ onEndOfList: { type: Function, default: null }, /** * Additional class for the wrapper list element. */ listClass: { type: [String, Array, Object], default: "" }, /** * Sets the element to which the popover is going to append to. * 'body' will append to the nearest body (supports shadow DOM). * @values 'body', 'parent', HTMLElement, */ appendTo: { type: [HTMLElement, String], default: "body", validator: (appendTo) => { return popover_constants.POPOVER_APPEND_TO_VALUES.includes(appendTo) || appendTo instanceof HTMLElement; } }, /** * If set to false the dialog will display over top of the anchor when there is insufficient space. * If set to true it will never move from its position relative to the anchor and will clip instead. * <a * class="d-link" * href="https://popper.js.org/docs/v2/modifiers/prevent-overflow/#tether" * target="_blank" * > * Popper.js docs * </a> * @values true, false */ tether: { type: Boolean, default: true }, /** * Named transition when the content display is toggled. * @see DtLazyShow */ transition: { type: String, default: "fade" } }, emits: [ /** * Event fired when the highlight changes * * @event highlight * @type {Number} */ "highlight", /** * Event fired when dropdown is shown or hidden * * @event opened * @type {Boolean | Array} */ "opened", /** * Event fired to sync the open prop with the parent component * @event update:open */ "update:open" ], data() { return { LIST_ITEM_NAVIGATION_TYPES: list_item_constants.LIST_ITEM_NAVIGATION_TYPES, DROPDOWN_PADDING_CLASSES: dropdown_constants.DROPDOWN_PADDING_CLASSES, EVENT_KEYNAMES: common_constants.EVENT_KEYNAMES, openedWithKeyboard: false, isOpen: null }; }, computed: { dropdownListeners() { return { ...this.$listeners, opened: (isPopoverOpen) => { this.updateInitialHighlightIndex(isPopoverOpen); }, keydown: (event) => { const eventCode = event.code; switch (eventCode) { case common_constants.EVENT_KEYNAMES.up: case common_constants.EVENT_KEYNAMES.arrowup: this.onUpKeyPress(event); event.stopPropagation(); event.preventDefault(); break; case common_constants.EVENT_KEYNAMES.down: case common_constants.EVENT_KEYNAMES.arrowdown: this.onDownKeyPress(event); event.stopPropagation(); event.preventDefault(); break; case common_constants.EVENT_KEYNAMES.space: case common_constants.EVENT_KEYNAMES.spacebar: this.onSpaceKey(); break; case common_constants.EVENT_KEYNAMES.enter: this.onEnterKey(); break; case common_constants.EVENT_KEYNAMES.home: this.onHomeKeyPress(event); event.stopPropagation(); event.preventDefault(); break; case common_constants.EVENT_KEYNAMES.end: this.onEndKeyPress(event); event.stopPropagation(); event.preventDefault(); break; default: this.onKeyPress(event); break; } this.$emit("keydown", event); } }; }, beginningOfListMethod() { return this.onBeginningOfList || this.jumpToEnd; }, endOfListMethod() { return this.onEndOfList || this.jumpToBeginning; }, activeItemEl() { return this.getListElement().querySelector("#" + this.highlightId); }, isArrowKeyNav() { return this.navigationType === this.LIST_ITEM_NAVIGATION_TYPES.ARROW_KEYS; }, listClasses() { return [ "d-dropdown-list", dropdown_constants.DROPDOWN_PADDING_CLASSES[this.padding], this.listClass, { "d-context-menu-list": this.openOnContext } ]; }, shouldOpenWithArrowKeys() { return !this.openOnContext; } }, methods: { onMouseHighlight(e) { const liElement = e.target.closest("li"); if (liElement && liElement.role && this.highlightId !== liElement.id) { this.setHighlightId(liElement.id); liElement.focus(); } }, getListElement() { return this.$refs.listWrapper; }, clearHighlightIndex() { this.setHighlightIndex(-1); }, afterHighlight() { if (this.visuallyHiddenClose && this.highlightIndex === this._itemsLength() - 1) { return; } this.$emit("highlight", this.highlightIndex); }, updateInitialHighlightIndex(isPopoverOpen) { this.isOpen = isPopoverOpen; if (isPopoverOpen) { if (this.openedWithKeyboard && this.isArrowKeyNav) { this.setHighlightIndex(0); } this.$emit("opened", true); } else { this.clearHighlightIndex(); this.openedWithKeyboard = false; this.$emit("opened", false); } }, onSpaceKey() { if (!this.open) { this.openedWithKeyboard = true; } }, onEnterKey() { if (!this.open) { this.openedWithKeyboard = true; } }, onUpKeyPress() { if (!this.isOpen) { this.openedWithKeyboard = true; return; } if (this.isArrowKeyNav) { return this.onUpKey(); } }, onDownKeyPress() { if (!this.isOpen) { this.openedWithKeyboard = true; return; } if (this.isArrowKeyNav) { return this.onDownKey(); } }, onHomeKeyPress() { if (!this.isOpen || !this.isArrowKeyNav) { return; } return this.onHomeKey(); }, onEndKeyPress() { if (!this.isOpen || !this.isArrowKeyNav) { return; } return this.onEndKey(); }, onKeyPress(e) { if (!this.isOpen || !this.isArrowKeyNav || !this.isValidLetter(e.key)) { return; } e.stopPropagation(); e.preventDefault(); return this.onNavigationKey(e.key); } } }; var _sfc_render = function render() { var _vm = this, _c = _vm._self._c; return _c("dt-popover", _vm._g({ ref: "popover", attrs: { "content-width": _vm.contentWidth, "open": _vm.open, "placement": _vm.placement, "initial-focus-element": _vm.openedWithKeyboard ? "first" : "dialog", "fallback-placements": _vm.fallbackPlacements, "padding": "none", "role": "menu", "append-to": _vm.appendTo, "modal": _vm.modal, "max-height": _vm.maxHeight, "max-width": _vm.maxWidth, "open-with-arrow-keys": _vm.shouldOpenWithArrowKeys, "open-on-context": _vm.openOnContext, "tether": _vm.tether, "transition": _vm.transition }, scopedSlots: _vm._u([{ key: "anchor", fn: function({ attrs }) { return [_vm._t("anchor", null, null, attrs)]; } }, { key: "content", fn: function({ close }) { return [_c("ul", { ref: "listWrapper", class: _vm.listClasses, attrs: { "id": _vm.listId, "data-qa": "dt-dropdown-list-wrapper" }, on: { "mouseleave": _vm.clearHighlightIndex, "!mousemove": function($event) { return _vm.onMouseHighlight.apply(null, arguments); } } }, [_vm._t("list", null, { "close": close }), _vm.showVisuallyHiddenClose ? _c("sr-only-close-button", { attrs: { "visually-hidden-close-label": _vm.visuallyHiddenCloseLabel, "tabindex": _vm.isArrowKeyNav ? -1 : 0 }, on: { "close": close } }) : _vm._e()], 2)]; } }, { key: "footerContent", fn: function({ close }) { return [_vm._t("footer", null, { "close": close })]; } }], null, true) }, _vm.dropdownListeners)); }; var _sfc_staticRenderFns = []; var __component__ = /* @__PURE__ */ _pluginVue2_normalizer.default( _sfc_main, _sfc_render, _sfc_staticRenderFns ); const DtDropdown = __component__.exports; exports.default = DtDropdown; //# sourceMappingURL=dropdown.vue.cjs.map