UNPKG

@dialpad/dialtone

Version:

Dialpad's Dialtone design system monorepo

572 lines (571 loc) 17.6 kB
import { disableRootScrolling as e, enableRootScrolling as t, getUniqueString as n, hasSlotContent as r, isOutOfViewPort as i, returnFirstEl as a, warnIfUnmounted as o } from "../../common/utils/index.js"; import { t as s } from "../../_plugin-vue_export-helper-BTgDAbhb.js"; import c from "../../common/mixins/modal.js"; import l from "../../shared/sr_only_close_button.js"; import u from "../lazy-show/lazy-show.js"; import { createTippyPopover as d, getPopperOptions as f } from "./tippy-utils.js"; import { POPOVER_APPEND_TO_VALUES as p, POPOVER_CONTENT_WIDTHS as m, POPOVER_HEADER_FOOTER_PADDING_CLASSES as h, POPOVER_INITIAL_FOCUS_STRINGS as g, POPOVER_PADDING_CLASSES as _, POPOVER_ROLES as v, POPOVER_STICKY_VALUES as y } from "./popover-constants.js"; import b from "./popover-header-footer.js"; import { Teleport as x, createBlock as S, createCommentVNode as C, createElementBlock as w, createElementVNode as T, createVNode as E, mergeProps as D, normalizeClass as O, openBlock as k, renderSlot as A, resolveComponent as j, resolveDynamicComponent as M, toHandlers as N, withCtx as P, withKeys as F, withModifiers as I } from "vue"; //#region components/popover/popover.vue var L = { compatConfig: { MODE: 3 }, name: "DtPopover", components: { SrOnlyCloseButton: l, DtLazyShow: u, PopoverHeaderFooter: b }, mixins: [c], props: { open: { type: Boolean, default: null }, openOnContext: { type: Boolean, default: !1 }, elementType: { type: String, default: "div" }, transition: { type: String, default: "fade" }, role: { type: String, default: "dialog", validator: (e) => v.includes(e) }, ariaLabelledby: { type: String, default: null }, ariaLabel: { type: String, default: null }, padding: { type: String, default: "large", validator: (e) => Object.keys(_).some((t) => t === e) }, contentClass: { type: [ String, Array, Object ], default: "" }, contentWidth: { type: String, default: "", validator: (e) => m.includes(e) }, contentAppear: { type: Boolean, default: null }, contentTabindex: { type: Number || null, default: -1 }, externalAnchor: { type: String, default: "" }, externalAnchorElement: { type: HTMLElement, default: null }, id: { type: String, default() { return n(); } }, offset: { type: Array, default: () => [0, 4] }, hideOnClick: { type: Boolean, default: !0 }, modal: { type: Boolean, default: !0 }, fallbackPlacements: { type: Array, default: () => ["auto"] }, placement: { type: String, default: "bottom-end" }, tether: { type: Boolean, default: !0 }, sticky: { type: [Boolean, String], default: !1, validator: (e) => y.includes(e) }, maxHeight: { type: String, default: "" }, maxWidth: { type: String, default: "" }, showCloseButton: { type: Boolean, default: !1 }, headerClass: { type: [ String, Array, Object ], default: "" }, footerClass: { type: [ String, Array, Object ], default: "" }, dialogClass: { type: [ String, Array, Object ], default: "" }, initialFocusElement: { type: [String, HTMLElement], default: "first", validator: (e) => g.includes(e) || e instanceof HTMLElement || e.startsWith("#") }, openWithArrowKeys: { type: Boolean, default: !1 }, appendTo: { type: [HTMLElement, String], default: "body", validator: (e) => p.includes(e) || e instanceof HTMLElement } }, emits: [ "keydown", "update:open", "opened", "mouseenter-popover", "mouseleave-popover", "mouseenter-popover-anchor", "mouseleave-popover-anchor" ], data() { return { POPOVER_PADDING_CLASSES: _, POPOVER_HEADER_FOOTER_PADDING_CLASSES: h, intersectionObserver: null, mutationObserver: null, isOutsideViewport: !1, isOpen: !1, toAppear: !1, anchorEl: null, popoverContentEl: null, hasSlotContent: r }; }, computed: { popoverListeners() { return { keydown: (e) => { this.onKeydown(e); }, "after-leave": () => { this.onLeaveTransitionComplete(); }, "after-enter": () => { this.onEnterTransitionComplete(); } }; }, calculatedMaxHeight() { return this.isOutsideViewport && this.modal ? "calc(100vh - var(--dt-space-300))" : this.maxHeight; }, labelledBy() { return this.ariaLabelledby || !this.ariaLabel && n("DtPopover__anchor"); } }, watch: { $props: { immediate: !0, deep: !0, handler() { this.validateProps(); } }, modal(e) { this.tip?.setProps({ zIndex: e ? 650 : this.calculateAnchorZindex() }); }, offset(e) { this.tip?.setProps({ offset: e }); }, sticky(e) { this.tip?.setProps({ sticky: e }); }, fallbackPlacements() { this.tip?.setProps({ popperOptions: this.popperOptions() }); }, tether() { this.tip?.setProps({ popperOptions: this.popperOptions() }); }, externalAnchorElement() { this.updateAnchorEl(); }, placement(e) { this.tip?.setProps({ placement: e }); }, open: { handler: function(e) { e !== null && (this.isOpen = e), e === !0 && (this.toAppear = !0); }, immediate: !0 }, contentAppear: { handler: function(e) { e !== null && (this.toAppear = e); } }, isOpen(e, t) { e ? (this.initTippyInstance(), this.tip?.show()) : !e && t !== e && (this.removeEventListeners(), this.tip?.hide()); } }, mounted() { o(a(this.$el), this.$options.name), this.popoverContentEl = a(this.$refs.content?.$el), this.updateAnchorEl(), this.mutationObserver = new MutationObserver(this.updateAnchorEl), this.mutationObserver.observe(this.$refs.anchor, { childList: !0 }), this.intersectionObserver = new IntersectionObserver(this.hasIntersectedViewport), this.intersectionObserver.observe(this.popoverContentEl); }, beforeUnmount() { this._isUnmounting = !0, this.popoverContentEl && (this.popoverContentEl.style.transition = "none"), this.tip?.destroy(), this.intersectionObserver?.disconnect(), this.mutationObserver?.disconnect(), this.removeReferences(), this.removeEventListeners(); }, methods: { hasIntersectedViewport(e) { let t = e?.[0]?.target; if (!t) return; let n = i(t); this.isOutsideViewport = n.bottom || n.top; }, updateAnchorEl() { let e = (this.externalAnchorElement || (this.externalAnchor ? this.$refs.anchor.getRootNode().querySelector(`#${this.externalAnchor}`) : null)) ?? this.$refs.anchor.children[0]; if (e !== this.anchorEl) { if (this.anchorEl = e, this.tip?.destroy(), delete this.tip, !this.anchorEl) { console.warn("No anchor found for popover"); return; } this.isOpen && (this.initTippyInstance(), this.tip?.show()); } }, popperOptions() { return f({ fallbackPlacements: this.fallbackPlacements, tether: this.tether, hasHideModifierEnabled: !0 }); }, validateProps() { this.modal && this.initialFocusElement === "none" && console.error("If the popover is modal you must set the initialFocusElement prop. Possible values: \"dialog\", \"first\", HTMLElement"); }, calculateAnchorZindex() { return a(this.$el).getRootNode().querySelector(".d-modal[aria-hidden=\"false\"], .d-modal--transparent[aria-hidden=\"false\"]") || this.anchorEl?.closest(".d-zi-drawer") ? 650 : 300; }, defaultToggleOpen(e) { if (!this.openOnContext && (this.open === null || this.open === void 0)) { if (!this.anchorEl?.contains(e.target) && !this.anchorEl?.isEqualNode(e.target) || this.anchorEl?.disabled) return; this.toggleOpen(); } }, async onContext(e) { this.openOnContext && (e.preventDefault(), this.isOpen = !0, await this.$nextTick(), this.tip?.setProps({ placement: "right-start", getReferenceClientRect: () => ({ width: 0, height: 0, top: e.clientY, bottom: e.clientY, left: e.clientX, right: e.clientX }) })); }, toggleOpen() { this.isOpen = !this.isOpen; }, onArrowKeyPress(e) { this.open === null && (this.openWithArrowKeys && this.anchorEl?.contains(e.target) && (this.isOpen || (this.isOpen = !0)), this.$emit("keydown", e)); }, addEventListeners() { window.addEventListener("dt-popover-close", this.closePopover), this.contentWidth === "anchor" && window.addEventListener("resize", this.onResize); }, removeEventListeners() { window.removeEventListener("dt-popover-close", this.closePopover), this.contentWidth === "anchor" && window.removeEventListener("resize", this.onResize); }, closePopover() { this.isOpen = !1; }, preventScrolling() { if (this.modal) { let t = this.anchorEl?.closest("body, .tippy-box"); if (!t) return; t.tagName?.toLowerCase() === "body" ? (e(this.anchorEl.getRootNode().host), this.tip?.setProps({ offset: this.offset })) : t.classList.add("d-zi-popover"); } }, enableScrolling() { let e = this.anchorEl?.closest("body, .tippy-box"); e && (e.tagName?.toLowerCase() === "body" ? (t(this.anchorEl.getRootNode().host), this.tip?.setProps({ offset: this.offset })) : e.classList.remove("d-zi-popover")); }, removeReferences() { this.anchorEl = null, this.popoverContentEl = null, this.tip = null; }, async onShow() { this.contentWidth === "anchor" && await this.setPopoverContentAnchorWidth(), this.contentWidth === null && (this.popoverContentEl.style.width = "auto"), this.addEventListeners(); }, async onLeaveTransitionComplete() { if (!this._isUnmounting) { if (this.modal) { if (await this.focusFirstElement(this.$refs.anchor), this._isUnmounting || (await this.$nextTick(), this._isUnmounting)) return; this.enableScrolling(); } this._isUnmounting || (this.tip?.unmount(), this.$emit("opened", !1), this.open !== null && this.$emit("update:open", !1)); } }, async onEnterTransitionComplete() { this._isUnmounting || (this.focusInitialElement(), await this.$nextTick(), !this._isUnmounting && (this.preventScrolling(), this.$emit("opened", !0, this.$refs.popover__content), this.open !== null && this.$emit("update:open", !0))); }, focusInitialElement() { this.initialFocusElement === "dialog" && a(this.$refs.content?.$el)?.focus(), this.initialFocusElement.startsWith("#") && this.focusInitialElementById(), this.initialFocusElement === "first" && this.focusFirstElementIfNeeded(this.$refs.popover__content), this.initialFocusElement instanceof HTMLElement && this.initialFocusElement.focus(); }, focusInitialElementById() { let e = a(this.$refs.content?.$el)?.querySelector(this.initialFocusElement); e ? e.focus() : (console.warn("Could not find the element specified in dt-popover prop \"initialFocusElement\". Defaulting to focusing the dialog."), a(this.$refs.content?.$el)?.focus()); }, onResize() { this.closePopover(); }, onClickOutside() { this.hideOnClick && (this.popoverContentEl?.querySelector(".d-popover__anchor--opened") || this.closePopover()); }, onKeydown(e) { e.key === "Tab" && this.modal && this.focusTrappedTabPress(e, this.popoverContentEl), e.key === "Escape" && this.closePopover(), this.$emit("keydown", e); }, async setPopoverContentAnchorWidth() { await this.$nextTick(), this.popoverContentEl.style.width = `${this.anchorEl?.clientWidth}px`; }, focusFirstElementIfNeeded(e) { this._getFocusableElements(e, !0).length === 0 ? this.showCloseButton ? this.$refs.popover__header?.focusCloseButton() : a(this.$refs.content?.$el).focus() : this.focusFirstElement(e); }, getReferenceClientRect(e) { let t = this.anchorEl?.getBoundingClientRect(); if (this.appendTo !== "root" || e) return t; let n = this.anchorEl?.ownerDocument, r = (n?.defaultView || n?.parentWindow)?.frameElement; if (!r) return t; let i = r.getBoundingClientRect(); return { width: t?.width, height: t?.height, top: i?.top + t?.top, left: i?.left + t?.left, right: i?.right + t?.right, bottom: i?.bottom + t?.bottom }; }, initTippyInstance() { let e = null, t = !1; switch (this.appendTo) { case "body": e = this.anchorEl?.getRootNode()?.querySelector("body"); break; case "root": try { e = window.parent.document.body; } catch (n) { console.error("Could not attach the popover to iframe parent window: ", n), e = "parent", t = !0; } break; default: e = this.appendTo; break; } this.tip?.destroy(), this.tip = d(this.anchorEl, { popperOptions: this.popperOptions(), contentElement: this.popoverContentEl, placement: this.placement, offset: this.offset, sticky: this.sticky, appendTo: e, interactive: !0, trigger: "manual", getReferenceClientRect: () => this.getReferenceClientRect(t), hideOnClick: !1, zIndex: this.modal ? 650 : this.calculateAnchorZindex(), onClickOutside: this.onClickOutside, onShow: this.onShow }); }, onMouseEnter() { this.$emit("mouseenter-popover"); }, onMouseLeave() { this.$emit("mouseleave-popover"); }, onMouseEnterAnchor() { this.$emit("mouseenter-popover-anchor"); }, onMouseLeaveAnchor() { this.$emit("mouseleave-popover-anchor"); } } }, R = [ "id", "data-qa", "tabindex" ], z = ["data-qa"]; function B(e, t, n, r, i, a) { let o = j("popover-header-footer"), s = j("sr-only-close-button"), c = j("dt-lazy-show"); return k(), w("div", null, [n.modal && i.isOpen ? (k(), S(x, { key: 0, to: "body" }, [T("div", { class: "d-modal--transparent", "aria-hidden": "false", onClick: t[0] || (t[0] = I(() => {}, ["prevent", "stop"])) })])) : C("", !0), (k(), S(M(n.elementType), { ref: "popover", class: O(["d-popover", { "d-popover__anchor--opened": i.isOpen }]), "data-qa": "dt-popover-container" }, { default: P(() => [T("div", { id: !n.ariaLabelledby && a.labelledBy, ref: "anchor", "data-qa": e.$attrs["data-qa"] ? `${e.$attrs["data-qa"]}-anchor` : "dt-popover-anchor", tabindex: n.openOnContext ? 0 : void 0, onClickCapture: t[1] || (t[1] = (...e) => a.defaultToggleOpen && a.defaultToggleOpen(...e)), onContextmenu: t[2] || (t[2] = (...e) => a.onContext && a.onContext(...e)), onKeydown: [ t[3] || (t[3] = F(I((...e) => a.onArrowKeyPress && a.onArrowKeyPress(...e), ["prevent"]), ["up"])), t[4] || (t[4] = F(I((...e) => a.onArrowKeyPress && a.onArrowKeyPress(...e), ["prevent"]), ["down"])), t[6] || (t[6] = F((t) => e.$emit("keydown", t), ["enter"])), t[7] || (t[7] = F((t) => e.$emit("keydown", t), ["space"])) ], onKeydownCapture: t[5] || (t[5] = F((...e) => a.closePopover && a.closePopover(...e), ["escape"])), onMouseenter: t[8] || (t[8] = (...e) => a.onMouseEnter && a.onMouseEnter(...e)), onMouseleave: t[9] || (t[9] = (...e) => a.onMouseLeave && a.onMouseLeave(...e)) }, [A(e.$slots, "anchor", { attrs: { "aria-expanded": i.isOpen.toString(), "aria-controls": n.id, "aria-haspopup": n.role } })], 40, R), E(c, D({ id: n.id, ref: "content", role: n.role, "data-qa": e.$attrs["data-qa"] ? `${e.$attrs["data-qa"]}__dialog` : "dt-popover", "aria-hidden": `${!i.isOpen}`, "aria-labelledby": a.labelledBy, "aria-label": n.ariaLabel, "aria-modal": `${!n.modal}`, transition: n.transition, show: i.isOpen, appear: i.toAppear, class: [ "d-popover__dialog", { "d-popover__dialog--modal": n.modal }, n.dialogClass ], style: { "max-height": a.calculatedMaxHeight, "max-width": n.maxWidth }, css: e.$attrs.css, tabindex: n.contentTabindex }, N(a.popoverListeners), { onMouseenter: a.onMouseEnterAnchor, onMouseleave: a.onMouseLeaveAnchor }), { default: P(() => [ i.hasSlotContent(e.$slots.headerContent) || n.showCloseButton ? (k(), S(o, { key: 0, ref: "popover__header", class: O(i.POPOVER_HEADER_FOOTER_PADDING_CLASSES[n.padding]), "content-class": n.headerClass, type: "header", "show-close-button": n.showCloseButton, onClose: a.closePopover }, { content: P(() => [A(e.$slots, "headerContent", { close: a.closePopover })]), _: 3 }, 8, [ "class", "content-class", "show-close-button", "onClose" ])) : C("", !0), T("div", { ref: "popover__content", "data-qa": e.$attrs["data-qa"] ? `${e.$attrs["data-qa"]}-content` : "dt-popover-content", class: O([ "d-popover__content", i.POPOVER_PADDING_CLASSES[n.padding], n.contentClass ]) }, [A(e.$slots, "content", { close: a.closePopover })], 10, z), i.hasSlotContent(e.$slots.footerContent) ? (k(), S(o, { key: 1, ref: "popover__footer", type: "footer", class: O(i.POPOVER_HEADER_FOOTER_PADDING_CLASSES[n.padding]), "content-class": n.footerClass }, { content: P(() => [A(e.$slots, "footerContent", { close: a.closePopover })]), _: 3 }, 8, ["class", "content-class"])) : C("", !0), n.showCloseButton ? C("", !0) : (k(), S(s, { key: 2, onClose: a.closePopover }, null, 8, ["onClose"])) ]), _: 3 }, 16, [ "id", "role", "data-qa", "aria-hidden", "aria-labelledby", "aria-label", "aria-modal", "transition", "show", "appear", "class", "style", "css", "tabindex", "onMouseenter", "onMouseleave" ])]), _: 3 }, 8, ["class"]))]); } var V = /* @__PURE__ */ s(L, [["render", B]]); //#endregion export { V as default }; //# sourceMappingURL=popover.js.map