UNPKG

@dialpad/dialtone-vue

Version:

Vue component library for Dialpad's design system Dialtone

1 lines 10.1 kB
{"version":3,"file":"hovercard.cjs","sources":["../../../components/hovercard/hovercard.vue"],"sourcesContent":["<template>\n <dt-popover\n :id=\"id\"\n ref=\"popover\"\n :open=\"hovercardOpen\"\n :placement=\"placement\"\n :content-class=\"contentClass\"\n :dialog-class=\"dialogClass\"\n :fallback-placements=\"fallbackPlacements\"\n :padding=\"padding\"\n :transition=\"transition ? 'fade' : null\"\n :offset=\"offset\"\n :modal=\"false\"\n initial-focus-element=\"none\"\n :header-class=\"headerClass\"\n :footer-class=\"footerClass\"\n :append-to=\"appendTo\"\n data-qa=\"dt-hovercard\"\n :enter-delay=\"enterDelay\"\n :leave-delay=\"leaveDelay\"\n @opened=\"(e) => ($emit('opened', e))\"\n @mouseenter-popover=\"onMouseEnter\"\n @mouseleave-popover=\"onMouseLeave\"\n @mouseenter-popover-anchor=\"onMouseEnter\"\n @mouseleave-popover-anchor=\"onMouseLeave\"\n >\n <template #anchor=\"{ attrs }\">\n <slot\n name=\"anchor\"\n v-bind=\"attrs\"\n />\n </template>\n <template #content>\n <div\n @focusin=\"onContentFocusIn\"\n @focusout=\"onContentFocusOut\"\n >\n <!-- @slot Slot for the content that is displayed in the hovercard. -->\n <slot name=\"content\" />\n </div>\n </template>\n <template #headerContent>\n <slot name=\"headerContent\" />\n </template>\n\n <template #footerContent>\n <slot name=\"footerContent\" />\n </template>\n </dt-popover>\n</template>\n\n<script>\nimport { POPOVER_APPEND_TO_VALUES, POPOVER_PADDING_CLASSES, DtPopover } from '@/components/popover/index.js';\nimport { TOOLTIP_DIRECTIONS, TOOLTIP_DELAY_MS } from '@/components/tooltip/index.js';\nimport { getUniqueString } from '@/common/utils';\n\nexport default {\n name: 'DtHovercard',\n\n components: {\n DtPopover,\n },\n\n props: {\n /**\n * Controls whether the hovercard is shown. Leaving this null will have the hovercard trigger on hover by default.\n * If you set this value, the default trigger behavior will be disabled, and you can control it as you need.\n * Supports .sync modifier\n * @values null, true, false\n */\n open: {\n type: Boolean,\n default: null,\n },\n\n /**\n * Fade transition when the content display is toggled.\n * @type boolean\n * @values true, false\n */\n transition: {\n type: Boolean,\n default: false,\n },\n\n /**\n * If the popover does not fit in the direction described by \"placement\",\n * it will attempt to change its direction to the \"fallbackPlacements\".\n * @see https://popper.js.org/docs/v2/modifiers/flip/#fallbackplacements\"\n */\n fallbackPlacements: {\n type: Array,\n default: () => {\n return ['auto'];\n },\n },\n\n /**\n * The direction the popover displays relative to the anchor.\n * @see https://atomiks.github.io/tippyjs/v6/all-props/#placement\"\n * @values top, top-start, top-end,\n * right, right-start, right-end,\n * left, left-start, left-end,\n * bottom, bottom-start, bottom-end,\n * auto, auto-start, auto-end\n */\n placement: {\n type: String,\n default: 'top-start',\n validator (placement) {\n return TOOLTIP_DIRECTIONS.includes(placement);\n },\n },\n\n /**\n * Padding size class for the popover content.\n * @values none, small, medium, large\n */\n padding: {\n type: String,\n default: 'large',\n validator: (padding) => {\n return Object.keys(POPOVER_PADDING_CLASSES).some((item) => item === padding);\n },\n },\n\n /**\n * Displaces the content box from its anchor element\n * by the specified number of pixels.\n * @see https://atomiks.github.io/tippyjs/v6/all-props/#offset\"\n */\n offset: {\n type: Array,\n default: () => [0, 16],\n },\n\n /**\n * The id of the tooltip\n */\n id: {\n type: String,\n default () { return getUniqueString(); },\n },\n\n /**\n * Additional class name for the header content wrapper element.\n */\n headerClass: {\n type: [String, Array, Object],\n default: '',\n },\n\n /**\n * Additional class name for the footer content wrapper element.\n */\n footerClass: {\n type: [String, Array, Object],\n default: '',\n },\n\n /**\n * Additional class name for the dialog element.\n */\n dialogClass: {\n type: [String, Array, Object],\n default: '',\n },\n\n /**\n * Additional class name for the content wrapper element.\n */\n contentClass: {\n type: [String, Array, Object],\n default: '',\n },\n\n /**\n * Sets the element to which the popover is going to append to.\n * 'body' will append to the nearest body (supports shadow DOM).\n * @values 'body', 'parent', HTMLElement,\n */\n appendTo: {\n type: [HTMLElement, String],\n default: 'body',\n validator: appendTo => {\n return POPOVER_APPEND_TO_VALUES.includes(appendTo) ||\n (appendTo instanceof HTMLElement);\n },\n },\n\n /**\n * The enter delay in milliseconds before the hovercard is shown.\n * @type number\n */\n enterDelay: {\n type: Number,\n default: TOOLTIP_DELAY_MS,\n },\n\n /**\n * The leave delay in milliseconds before the hovercard is hidden.\n * @type number\n */\n leaveDelay: {\n type: Number,\n default: TOOLTIP_DELAY_MS,\n },\n },\n\n emits: [\n /**\n * Emitted when popover is shown or hidden\n *\n * @event opened\n * @type {Boolean | Array}\n */\n 'opened',\n ],\n\n data () {\n return {\n hovercardOpen: this.open,\n anchorEl: null,\n observer: null,\n inTimer: null,\n outTimer: null,\n contentFocused: false,\n mouseOverHovercard: false,\n };\n },\n\n watch: {\n open: {\n handler: function (open) {\n this.hovercardOpen = open;\n },\n\n immediate: true,\n },\n },\n\n mounted () {\n this.$nextTick(() => {\n this.anchorEl = this.$refs.popover?.$refs?.anchor?.firstElementChild;\n\n this.observer = new MutationObserver(() => {\n if (this.anchorEl && !this.anchorEl.isConnected) {\n // If the anchor element is removed from the DOM, close the hovercard\n this.hovercardOpen = false;\n }\n });\n\n this.observer.observe(document.body, {\n childList: true,\n subtree: true,\n });\n });\n },\n\n beforeDestroy () {\n if (this.observer) {\n this.observer.disconnect();\n }\n\n clearTimeout(this.inTimer);\n clearTimeout(this.outTimer);\n },\n\n methods: {\n setInTimer () {\n if (this.open === null) {\n clearTimeout(this.outTimer);\n this.inTimer = setTimeout(() => {\n this.hovercardOpen = true;\n }, this.enterDelay);\n }\n },\n\n setOutTimer () {\n if (this.open === null) {\n clearTimeout(this.inTimer);\n this.outTimer = setTimeout(() => {\n this.hovercardOpen = false;\n }, this.leaveDelay);\n }\n },\n\n onMouseEnter () {\n this.mouseOverHovercard = true;\n this.setInTimer();\n },\n\n onMouseLeave () {\n this.mouseOverHovercard = false;\n if (this.contentFocused) {\n return;\n }\n if (this.open === null) {\n clearTimeout(this.inTimer);\n this.setOutTimer();\n }\n },\n\n onContentFocusIn () {\n this.contentFocused = true;\n this.setInTimer();\n },\n\n onContentFocusOut () {\n this.contentFocused = false;\n\n // If mouse is not over the hovercard, close it\n if (!this.mouseOverHovercard) {\n this.setOutTimer();\n }\n },\n },\n};\n</script>\n"],"names":["_sfc_main","DtPopover","placement","TOOLTIP_DIRECTIONS","padding","POPOVER_PADDING_CLASSES","item","getUniqueString","appendTo","POPOVER_APPEND_TO_VALUES","TOOLTIP_DELAY_MS","open","_c","_b","_a"],"mappings":"oVAwDAA,EAAA,CACA,KAAA,cAEA,WAAA,CACA,UAAAC,EAAAA,OACA,EAEA,MAAA,CAOA,KAAA,CACA,KAAA,QACA,QAAA,IACA,EAOA,WAAA,CACA,KAAA,QACA,QAAA,EACA,EAOA,mBAAA,CACA,KAAA,MACA,QAAA,IACA,CAAA,MAAA,CAEA,EAWA,UAAA,CACA,KAAA,OACA,QAAA,YACA,UAAAC,EAAA,CACA,OAAAC,EAAAA,mBAAA,SAAAD,CAAA,CACA,CACA,EAMA,QAAA,CACA,KAAA,OACA,QAAA,QACA,UAAAE,GACA,OAAA,KAAAC,yBAAA,EAAA,KAAAC,GAAAA,IAAAF,CAAA,CAEA,EAOA,OAAA,CACA,KAAA,MACA,QAAA,IAAA,CAAA,EAAA,EAAA,CACA,EAKA,GAAA,CACA,KAAA,OACA,SAAA,CAAA,OAAAG,EAAAA,gBAAA,CAAA,CACA,EAKA,YAAA,CACA,KAAA,CAAA,OAAA,MAAA,MAAA,EACA,QAAA,EACA,EAKA,YAAA,CACA,KAAA,CAAA,OAAA,MAAA,MAAA,EACA,QAAA,EACA,EAKA,YAAA,CACA,KAAA,CAAA,OAAA,MAAA,MAAA,EACA,QAAA,EACA,EAKA,aAAA,CACA,KAAA,CAAA,OAAA,MAAA,MAAA,EACA,QAAA,EACA,EAOA,SAAA,CACA,KAAA,CAAA,YAAA,MAAA,EACA,QAAA,OACA,UAAAC,GACAC,EAAAA,yBAAA,SAAAD,CAAA,GACAA,aAAA,WAEA,EAMA,WAAA,CACA,KAAA,OACA,QAAAE,EAAAA,gBACA,EAMA,WAAA,CACA,KAAA,OACA,QAAAA,EAAAA,gBACA,CACA,EAEA,MAAA,CAOA,QACA,EAEA,MAAA,CACA,MAAA,CACA,cAAA,KAAA,KACA,SAAA,KACA,SAAA,KACA,QAAA,KACA,SAAA,KACA,eAAA,GACA,mBAAA,EACA,CACA,EAEA,MAAA,CACA,KAAA,CACA,QAAA,SAAAC,EAAA,CACA,KAAA,cAAAA,CACA,EAEA,UAAA,EACA,CACA,EAEA,SAAA,CACA,KAAA,UAAA,IAAA,WACA,KAAA,UAAAC,GAAAC,GAAAC,EAAA,KAAA,MAAA,UAAA,YAAAA,EAAA,QAAA,YAAAD,EAAA,SAAA,YAAAD,EAAA,kBAEA,KAAA,SAAA,IAAA,iBAAA,IAAA,CACA,KAAA,UAAA,CAAA,KAAA,SAAA,cAEA,KAAA,cAAA,GAEA,CAAA,EAEA,KAAA,SAAA,QAAA,SAAA,KAAA,CACA,UAAA,GACA,QAAA,EACA,CAAA,CACA,CAAA,CACA,EAEA,eAAA,CACA,KAAA,UACA,KAAA,SAAA,WAAA,EAGA,aAAA,KAAA,OAAA,EACA,aAAA,KAAA,QAAA,CACA,EAEA,QAAA,CACA,YAAA,CACA,KAAA,OAAA,OACA,aAAA,KAAA,QAAA,EACA,KAAA,QAAA,WAAA,IAAA,CACA,KAAA,cAAA,EACA,EAAA,KAAA,UAAA,EAEA,EAEA,aAAA,CACA,KAAA,OAAA,OACA,aAAA,KAAA,OAAA,EACA,KAAA,SAAA,WAAA,IAAA,CACA,KAAA,cAAA,EACA,EAAA,KAAA,UAAA,EAEA,EAEA,cAAA,CACA,KAAA,mBAAA,GACA,KAAA,WAAA,CACA,EAEA,cAAA,CACA,KAAA,mBAAA,GACA,MAAA,gBAGA,KAAA,OAAA,OACA,aAAA,KAAA,OAAA,EACA,KAAA,YAAA,EAEA,EAEA,kBAAA,CACA,KAAA,eAAA,GACA,KAAA,WAAA,CACA,EAEA,mBAAA,CACA,KAAA,eAAA,GAGA,KAAA,oBACA,KAAA,YAAA,CAEA,CACA,CACA"}