UNPKG

@dialpad/dialtone

Version:

Dialpad's Dialtone design system monorepo

402 lines (401 loc) 12.1 kB
import K from "../../common/mixins/keyboard-list-navigation.js"; import { DROPDOWN_PADDING_CLASSES as a } from "./dropdown-constants.js"; import { getUniqueString as w } from "../../common/utils/index.js"; import { EVENT_KEYNAMES as n } from "../../common/constants/index.js"; import O from "../../common/mixins/sr-only-close-button.js"; import b from "../../shared/sr_only_close_button.js"; import { resolveComponent as p, openBlock as u, createBlock as g, mergeProps as m, toHandlers as E, withCtx as l, renderSlot as d, createElementVNode as I, normalizeClass as x, createCommentVNode as S } from "vue"; import { _ as H } from "../../_plugin-vue_export-helper-CHgC5LLL.js"; import P from "../popover/popover.js"; import { LIST_ITEM_NAVIGATION_TYPES as h } from "../list-item/list-item-constants.js"; import { POPOVER_APPEND_TO_VALUES as C } from "../popover/popover-constants.js"; const _ = { compatConfig: { MODE: 3 }, name: "DtDropdown", components: { DtPopover: P, SrOnlyCloseButton: b }, mixins: [ K({ indexKey: "highlightIndex", idKey: "highlightId", listElementKey: "getListElement", listItemRole: "menuitem", afterHighlightMethod: "afterHighlight", beginningOfListMethod: "beginningOfListMethod", endOfListMethod: "endOfListMethod", activeItemKey: "activeItemEl", focusOnKeyboardNavigation: !0 }), O ], inheritAttrs: !1, 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 v-model */ 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: !1 }, /** * Vertical padding size around the list element. * @values none, small, large */ padding: { type: String, default: "small", validator: (e) => Object.keys(a).some((t) => t === e) }, /** * Determines modal state, dropdown has a modal overlay preventing interaction with elements * below it, but it is invisible. */ modal: { type: Boolean, default: !0 }, /** * 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 w(); } }, /** * 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: h.ARROW_KEYS, validator: (e) => Object.values(h).includes(e) }, /** * 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: () => ["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: (e) => C.includes(e) || e 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: !0 }, /** * Named transition when the content display is toggled. * @see DtLazyShow */ transition: { type: String, default: "fade" } }, emits: [ /** * Native keydown event * * @event keydown * @type {KeyboardEvent} */ "keydown", /** * Event fired when the highlight changes * * @event highlight * @type {Number} */ "highlight", /** * Event fired to sync the open prop with the parent component * @event update:open */ "update:open", /** * 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: h, DROPDOWN_PADDING_CLASSES: a, EVENT_KEYNAMES: n, openedWithKeyboard: !1, isOpen: null }; }, computed: { dropdownListeners() { return { opened: (e) => { this.updateInitialHighlightIndex(e); }, keydown: (e) => { switch (e.code) { case n.up: case n.arrowup: this.onUpKeyPress(e), e.stopPropagation(), e.preventDefault(); break; case n.down: case n.arrowdown: this.onDownKeyPress(e), e.stopPropagation(), e.preventDefault(); break; case n.space: case n.spacebar: this.onSpaceKey(); break; case n.enter: this.onEnterKey(); break; case n.home: this.onHomeKeyPress(e), e.stopPropagation(), e.preventDefault(); break; case n.end: this.onEndKeyPress(e), e.stopPropagation(), e.preventDefault(); break; default: this.onKeyPress(e); break; } this.$emit("keydown", e); } }; }, 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", a[this.padding], this.listClass, { "d-context-menu-list": this.openOnContext } ]; }, shouldOpenWithArrowKeys() { return !this.openOnContext; } }, methods: { onMouseHighlight(e) { const t = e.target.closest("li"); t && t.role && this.highlightId !== t.id && (this.setHighlightId(t.id), t.focus()); }, getListElement() { return this.$refs.listWrapper; }, clearHighlightIndex() { this.setHighlightIndex(-1); }, afterHighlight() { this.visuallyHiddenClose && this.highlightIndex === this._itemsLength() - 1 || this.$emit("highlight", this.highlightIndex); }, updateInitialHighlightIndex(e) { this.isOpen = e, e ? (this.openedWithKeyboard && this.isArrowKeyNav && this.setHighlightIndex(0), this.$emit("opened", !0)) : (this.clearHighlightIndex(), this.openedWithKeyboard = !1, this.$emit("opened", !1)); }, onSpaceKey() { this.open || (this.openedWithKeyboard = !0); }, onEnterKey() { this.open || (this.openedWithKeyboard = !0); }, onUpKeyPress() { if (!this.isOpen) { this.openedWithKeyboard = !0; return; } if (this.isArrowKeyNav) return this.onUpKey(); }, onDownKeyPress() { if (!this.isOpen) { this.openedWithKeyboard = !0; return; } if (this.isArrowKeyNav) return this.onDownKey(); }, onHomeKeyPress() { if (!(!this.isOpen || !this.isArrowKeyNav)) return this.onHomeKey(); }, onEndKeyPress() { if (!(!this.isOpen || !this.isArrowKeyNav)) return this.onEndKey(); }, onKeyPress(e) { if (!(!this.isOpen || !this.isArrowKeyNav || !this.isValidLetter(e.key))) return e.stopPropagation(), e.preventDefault(), this.onNavigationKey(e.key); } } }, A = ["id"]; function L(e, t, i, v, f, o) { const y = p("sr-only-close-button"), c = p("dt-popover"); return u(), g(c, m({ ref: "popover", "content-width": i.contentWidth, open: i.open, placement: i.placement, "initial-focus-element": f.openedWithKeyboard ? "first" : "dialog", "fallback-placements": i.fallbackPlacements, padding: "none", role: "menu", "append-to": i.appendTo, modal: i.modal, "max-height": i.maxHeight, "max-width": i.maxWidth, "open-with-arrow-keys": o.shouldOpenWithArrowKeys, "open-on-context": i.openOnContext }, e.$attrs, { tether: i.tether, transition: i.transition }, E(o.dropdownListeners)), { anchor: l(({ attrs: s }) => [ d(e.$slots, "anchor", m({ ref: "anchor" }, s)) ]), content: l(({ close: s }) => [ I("ul", { id: i.listId, ref: "listWrapper", class: x(o.listClasses), "data-qa": "dt-dropdown-list-wrapper", onMouseleave: t[0] || (t[0] = (...r) => o.clearHighlightIndex && o.clearHighlightIndex(...r)), onMousemoveCapture: t[1] || (t[1] = (...r) => o.onMouseHighlight && o.onMouseHighlight(...r)) }, [ d(e.$slots, "list", { close: s }), e.showVisuallyHiddenClose ? (u(), g(y, { key: 0, "visually-hidden-close-label": e.visuallyHiddenCloseLabel, tabindex: o.isArrowKeyNav ? -1 : 0, onClose: s }, null, 8, ["visually-hidden-close-label", "tabindex", "onClose"])) : S("", !0) ], 42, A) ]), footerContent: l(({ close: s }) => [ d(e.$slots, "footer", { close: s }) ]), _: 3 }, 16, ["content-width", "open", "placement", "initial-focus-element", "fallback-placements", "append-to", "modal", "max-height", "max-width", "open-with-arrow-keys", "open-on-context", "tether", "transition"]); } const Y = /* @__PURE__ */ H(_, [["render", L]]); export { Y as default }; //# sourceMappingURL=dropdown.js.map