UNPKG

@dialpad/dialtone

Version:

Dialpad's Dialtone design system monorepo

392 lines (391 loc) 13.1 kB
import { TOOLTIP_DELAY_MS as s, TOOLTIP_KIND_MODIFIERS as c, TOOLTIP_STICKY_VALUES as p, TOOLTIP_DIRECTIONS as f } from "./tooltip-constants.js"; import { POPOVER_APPEND_TO_VALUES as m } from "../popover/popover-constants.js"; import { returnFirstEl as r, flushPromises as w, warnIfUnmounted as y, hasSlotContent as E, getUniqueString as S } from "../../common/utils/index.js"; import { getPopperOptions as a, createTippy as v, getAnchor as g } from "../popover/tippy-utils.js"; import { createElementBlock as h, openBlock as l, createCommentVNode as A, createElementVNode as T, withKeys as L, renderSlot as d, normalizeClass as P, createTextVNode as O, toDisplayString as b } from "vue"; import { _ as x } from "../../_plugin-vue_export-helper-CHgC5LLL.js"; const I = { compatConfig: { MODE: 3 }, name: "DtTooltip", props: { /** * The id of the tooltip */ id: { type: String, default() { return S(); } }, /** * If the popover does not fit in the direction described by "placement", * it will attempt to change its direction to the "fallbackPlacements" * if defined, otherwise it will automatically position to a new location * as it sees best fit. See * <a * class="d-link" * href="https://popper.js.org/docs/v2/modifiers/flip/#fallbackplacements" * target="_blank" * > * Popper.js docs * </a> * */ fallbackPlacements: { type: Array, default: () => ["auto"] }, /** * If true, applies inverted styles to the tooltip * @values true, false */ inverted: { type: Boolean, default: !1 }, /** * Displaces the tooltip from its reference element * by the specified number of pixels. See * <a * class="d-link" * href="https://atomiks.github.io/tippyjs/v6/all-props/#offset" * target="_blank" * > * Tippy.js docs * </a> */ offset: { type: Array, default: () => [0, 12] }, /** * The direction the popover displays relative to the anchor. See * <a * class="d-link" * href="https://atomiks.github.io/tippyjs/v6/all-props/#placement" * target="_blank" * > * Tippy.js docs * </a> * @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 */ placement: { type: String, default: "top", validator(e) { return f.includes(e); } }, /** * If the tooltip sticks to the anchor. This is usually not needed, but can be needed * if the reference element's position is animating, or to automatically update the popover * position in those cases the DOM layout changes the reference element's position. * `true` enables it, `reference` only checks the "reference" rect for changes and `popper` only * checks the "popper" rect for changes. See * <a * class="d-link" * href="https://atomiks.github.io/tippyjs/v6/all-props/#sticky" * target="_blank" * > * Tippy.js docs * </a> * @values true, false, reference, popper */ sticky: { type: [Boolean, String], default: !0, validator: (e) => p.includes(e) }, /** * Sets the element to which the tooltip is going to append to. * 'body' will append to the nearest body (supports shadow DOM). * This prop is not reactive, must be set on initial render. * @values 'body', 'parent', HTMLElement, */ appendTo: { type: [HTMLElement, String], default: "body", validator: (e) => m.includes(e) || e instanceof HTMLElement }, /** * Additional css classes for the tooltip content element. * Can accept all of String, Object, and Array, i.e. has the * same api as Vue's built-in handling of the class attribute. */ contentClass: { type: [String, Object, Array], default: "" }, /** * A provided message for the tooltip content */ message: { type: String, default: "" }, /** * Controls whether hover/focus causes the tooltip to appear. * Cannot be combined with the show prop. show value will be ignored. * by default this is true, if you override with false, the tooltip will never show up. */ enabled: { type: Boolean, default: !0 }, /** * Controls whether the tooltip is shown. Leaving this null will have the tooltip trigger on mouseover by default. * If you set this value, the default mouseover behavior will be disabled and you can control it as you need. * Supports .sync modifier * @values null, true, false */ show: { type: Boolean, default: null }, /** * Whether the tooltip should have a transition effect (fade). */ transition: { type: Boolean, default: !0 }, /** * Whether the tooltip will have a delay when being focused or moused over. * @values true, false */ delay: { type: Boolean, default: !0 }, /** * Set a custom theme on the tooltip. See https://atomiks.github.io/tippyjs/v6/themes/ */ theme: { type: String, default: null }, /** * External anchor id to use in those cases the anchor can't be provided via the slot. * For instance, using the combobox's input as the anchor for the popover. */ externalAnchor: { type: String, default: null } }, emits: [ /** * Emitted when tooltip is shown or hidden * * @event shown * @type {Boolean} */ "shown", /** * Sync show value * * @event update:show */ "update:show" ], data() { return { TOOLTIP_KIND_MODIFIERS: c, hasSlotContent: E, tip: null, inTimer: null, // Internal state for whether the tooltip is shown. Changing the prop // will update this. internalShow: !1, // this is where the placement currently is, this can be different than // the placement prop when there is not enough available room for the tip // to display and it uses a fallback placement. currentPlacement: this.placement }; }, computed: { tippyProps() { return { offset: this.offset, delay: this.delay ? s : !1, placement: this.placement, sticky: this.sticky, theme: this.inverted ? "inverted" : this.theme, animation: this.transition ? "fade" : !1, // onShown only triggers when transition is truthy onShown: (e) => this.onShow(e, "onShown"), // onShown will always be called, but it will be called before the animation is complete onShow: (e) => this.onShow(e, "onShow"), onHidden: this.onHide, popperOptions: a({ fallbackPlacements: this.fallbackPlacements, hasHideModifierEnabled: !0 }) }; }, anchor() { return this.externalAnchor ? document.body.querySelector(this.externalAnchor) : g(this.$refs.anchor); } }, watch: { tippyProps: { handler: "setProps", deep: !0 }, show: { handler: function(e) { e !== null && this.enabled && (this.internalShow = e); }, immediate: !0 }, internalShow(e) { e ? (this.setProps(), this.tip.show()) : this.tip.hide(); }, sticky(e) { this.tip.setProps({ sticky: e }); } }, async mounted() { !this.enabled && this.show != null && (console.warn("Tooltip: You cannot use both the enabled and show props at the same time."), console.warn("The show prop will be ignored.")), this.tip = v(this.anchor, this.initOptions()), this.externalAnchor && (await w(), this.addExternalAnchorEventListeners()), y(r(this.$el), this.$options.name); }, beforeUnmount() { var e, t; this.externalAnchor && this.removeExternalAnchorEventListeners(), (e = this.anchor) != null && e._tippy && ((t = this.tip) == null || t.destroy()); }, methods: { calculateAnchorZindex() { return r(this.$el).getRootNode().querySelector( `.d-modal[aria-hidden="false"], .d-modal--transparent[aria-hidden="false"], .d-modal:not([aria-hidden]), .d-modal--transparent:not([aria-hidden])` ) || // Special case because we don't have any dialtone drawer component yet. Render at 651 when // anchor of popover is within a drawer. r(this.$el).closest(".d-zi-drawer") ? 651 : 400; }, hasVisibleFocus() { return this.anchor.matches(":focus-visible"); }, onEnterAnchor(e) { this.enabled && (this.delay && this.inTimer === null ? this.inTimer = setTimeout(() => { this.triggerShow(e); }, s) : this.triggerShow(e)); }, triggerShow(e) { e.type === "focusin" ? this.show === null && this.hasVisibleFocus() && (this.internalShow = !0) : this.show === null && (this.internalShow = !0); }, onLeaveAnchor(e) { e.type === "keydown" && e.code !== "Escape" || (clearTimeout(this.inTimer), this.inTimer = null, this.triggerHide()); }, triggerHide() { this.show === null && (this.internalShow = !1); }, onChangePlacement(e) { this.currentPlacement = e; }, onHide() { var e; (e = this.tip) == null || e.unmount(), this.$emit("shown", !1), this.show !== null && this.$emit("update:show", !1); }, onShow(e, t) { if (!this.tooltipHasContent(e)) return !1; this.transition && t === "onShow" || (this.$emit("shown", !0), this.show !== null && this.$emit("update:show", !0)); }, setProps() { var e, t; this.tip && this.tip.setProps && this.tip.setProps({ ...this.tippyProps, // these need to be set here rather than in tippyProps because they are non-reactive appendTo: this.appendTo === "body" ? (t = (e = this.anchor) == null ? void 0 : e.getRootNode()) == null ? void 0 : t.querySelector("body") : this.appendTo, zIndex: this.calculateAnchorZindex() }); }, onMount() { this.setProps(); }, tooltipHasContent(e) { return e.props.content.textContent.trim().length !== 0; }, // set initial options here. If any of the options need to dynamically change, they should be put in // tippyProps instead. initOptions() { return { content: this.$refs.content, arrow: '<svg xmlns="http://www.w3.org/2000/svg" width="16" height="7"><path d="M 14.5,7 8,0 1.5,7 Z"/></svg>', // transition duration - same as our custom fade delay in dialtone-globals.less duration: 180, interactive: !1, trigger: "manual", hideOnClick: !1, // disable tooltip from displaying on touch devices touch: !1, onMount: this.onMount, showOnCreate: this.internalShow, popperOptions: a({ hasHideModifierEnabled: !0 }) }; }, addExternalAnchorEventListeners() { ["focusin", "mouseenter"].forEach((e) => { var t; (t = this.anchor) == null || t.addEventListener(e, (n) => this.onEnterAnchor(n)); }), ["focusout", "mouseleave", "keydown"].forEach((e) => { var t; (t = this.anchor) == null || t.addEventListener(e, (n) => this.onLeaveAnchor(n)); }); }, removeExternalAnchorEventListeners() { ["focusin", "mouseenter"].forEach((e) => { var t; (t = this.anchor) == null || t.removeEventListener(e, (n) => this.onEnterAnchor(n)); }), ["focusout", "mouseleave", "keydown"].forEach((e) => { var t; (t = this.anchor) == null || t.removeEventListener(e, (n) => this.onLeaveAnchor(n)); }); } } }, k = { "data-qa": "dt-tooltip-container" }, C = ["id"]; function M(e, t, n, _, u, o) { return l(), h("div", k, [ n.externalAnchor ? A("", !0) : (l(), h("span", { key: 0, ref: "anchor", "data-qa": "dt-tooltip-anchor", onFocusin: t[0] || (t[0] = (...i) => o.onEnterAnchor && o.onEnterAnchor(...i)), onFocusout: t[1] || (t[1] = (...i) => o.onLeaveAnchor && o.onLeaveAnchor(...i)), onMouseenter: t[2] || (t[2] = (...i) => o.onEnterAnchor && o.onEnterAnchor(...i)), onMouseleave: t[3] || (t[3] = (...i) => o.onLeaveAnchor && o.onLeaveAnchor(...i)), onKeydown: t[4] || (t[4] = L((...i) => o.onLeaveAnchor && o.onLeaveAnchor(...i), ["esc"])) }, [ d(e.$slots, "anchor") ], 544)), T("div", { id: n.id, ref: "content", "data-qa": "dt-tooltip", class: P([ "d-tooltip", { [u.TOOLTIP_KIND_MODIFIERS.inverted]: n.inverted }, n.contentClass ]) }, [ d(e.$slots, "default", {}, () => [ O(b(n.message), 1) ]) ], 10, C) ]); } const F = /* @__PURE__ */ x(I, [["render", M]]); export { F as default }; //# sourceMappingURL=tooltip.js.map