@empathyco/x-components 6.0.0-alpha.27 → 6.0.0-alpha.28

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -1 +1 @@
1
- {"version":3,"file":"base-modal.vue.js","sources":["../../../../src/components/modals/base-modal.vue"],"sourcesContent":["<template>\n <div v-show=\"isWaitingForLeave || open\" ref=\"modalRef\" class=\"x-modal\" data-test=\"modal\">\n <component\n :is=\"animation\"\n @before-leave=\"isWaitingForLeave = true\"\n @after-leave=\"isWaitingForLeave = false\"\n >\n <div\n v-if=\"open\"\n ref=\"modalContentRef\"\n class=\"x-modal__content\"\n data-test=\"modal-content\"\n role=\"dialog\"\n :class=\"contentClass\"\n >\n <!-- @slot (Required) Modal container content -->\n <slot />\n </div>\n </component>\n <component :is=\"overlayAnimation\">\n <div\n v-if=\"open\"\n @click=\"emitOverlayClicked\"\n @keydown=\"emitOverlayClicked\"\n class=\"x-modal__overlay\"\n :class=\"overlayClass\"\n data-test=\"modal-overlay\"\n />\n </component>\n </div>\n</template>\n\n<script lang=\"ts\">\n import { defineComponent, nextTick, onBeforeUnmount, onMounted, ref, watch } from 'vue';\n import { useDebounce } from '../../composables';\n import { AnimationProp } from '../../types';\n import { getTargetElement, FOCUSABLE_SELECTORS } from '../../utils';\n import { Fade, NoAnimation } from '../animations';\n\n /**\n * Base component with no XPlugin dependencies that serves as a utility for constructing more\n * complex modals.\n *\n * @public\n */\n export default defineComponent({\n name: 'BaseModal',\n props: {\n /** Determines if the modal is open or not. */\n open: {\n type: Boolean,\n required: true\n },\n /**\n * Determines if the focused element changes to one inside the modal when it opens. Either the\n * first element with a positive tabindex or just the first focusable element.\n */\n focusOnOpen: {\n type: Boolean,\n default: true\n },\n /**\n * The reference selector of a DOM element to use as reference to position the modal.\n * This selector can be an ID or a class, if it is a class, it will use the first\n * element that matches.\n */\n referenceSelector: String,\n /** Animation to use for opening/closing the modal.This animation only affects the content. */\n animation: {\n type: AnimationProp,\n default: () => NoAnimation\n },\n /**\n * Animation to use for the overlay (backdrop) part of the modal. By default, it uses\n * a fade transition.\n */\n overlayAnimation: {\n type: AnimationProp,\n default: () => Fade\n },\n /** Class inherited by content element. */\n contentClass: String,\n /** Class inherited by overlay element. */\n overlayClass: String\n },\n emits: ['click:overlay', 'focusin:body'],\n setup(props, { emit }) {\n /** Reference to the modal element in the DOM. */\n const modalRef = ref<HTMLDivElement>();\n /** Reference to the modal content element in the DOM. */\n const modalContentRef = ref<HTMLDivElement>();\n\n /** The previous value of the body overflow style. */\n const previousBodyOverflow = ref('');\n /** The previous value of the HTML element overflow style. */\n const previousHTMLOverflow = ref('');\n /** Boolean to delay the leave animation until it has completed. */\n const isWaitingForLeave = ref(false);\n /** The reference element to use to find the modal's position. */\n let referenceElement: HTMLElement;\n\n /** Disables the scroll of both the body and the window. */\n function disableScroll() {\n previousBodyOverflow.value = document.body.style.overflow;\n previousHTMLOverflow.value = document.documentElement.style.overflow;\n document.body.style.overflow = document.documentElement.style.overflow = 'hidden';\n }\n\n /** Restores the scroll of both the body and the window. */\n function enableScroll() {\n document.body.style.overflow = previousBodyOverflow.value;\n document.documentElement.style.overflow = previousHTMLOverflow.value;\n }\n\n /**\n * Emits the `click:overlay` event if the click has been triggered in the overlay layer.\n *\n * @param event - The click event.\n */\n function emitOverlayClicked(event: Event) {\n emit('click:overlay', event);\n }\n\n /**\n * Emits the `focusin:body` event if a focus event has been triggered outside the modal.\n *\n * @param event - The focusin event.\n */\n function emitFocusInBody(event: FocusEvent) {\n if (!modalContentRef.value?.contains(getTargetElement(event))) {\n emit('focusin:body', event);\n }\n }\n\n /**\n * Adds listeners to the body element ot detect if the modal should be closed.\n *\n * @remarks TODO find a better solution and remove the timeout\n * To avoid emit the focusin on opening X that provokes closing it immediately.\n * This is because this event was emitted after the open of main modal when the user clicks\n * on the customer website search box (focus event). This way we avoid add the listener before\n * the open and the avoid the event that provokes the close.\n */\n function addBodyListeners() {\n setTimeout(() => {\n document.body.addEventListener('focusin', emitFocusInBody);\n });\n }\n\n /** Removes the body listeners. */\n function removeBodyListeners() {\n document.body.removeEventListener('focusin', emitFocusInBody);\n }\n\n /**\n * Sets the focused element to the first element either the first element with a positive\n * tabindex or, if there isn't any, the first focusable element inside the modal.\n */\n function setFocus() {\n const candidates: HTMLElement[] = Array.from(\n modalContentRef.value?.querySelectorAll(FOCUSABLE_SELECTORS) ?? []\n );\n const element = candidates.find(element => element.tabIndex) ?? candidates[0];\n element?.focus();\n }\n\n /**\n * Syncs the body to the open state of the modal, adding or removing styles and listeners.\n *\n * @remarks nextTick() to wait for `modalContentRef` to be updated to look for focusable\n * candidates inside.\n *\n * @param isOpen - True when the modal is opened.\n */\n async function syncBody(isOpen: boolean) {\n if (isOpen) {\n disableScroll();\n addBodyListeners();\n if (props.focusOnOpen) {\n await nextTick();\n setFocus();\n }\n } else {\n enableScroll();\n removeBodyListeners();\n }\n }\n\n /**\n * Updates the position of the modal setting the top of the element depending\n * on the selector. The modal will be placed under this selector.\n */\n const debouncedUpdatePosition = useDebounce(\n () => {\n const { height, y } = referenceElement?.getBoundingClientRect() ?? { height: 0, y: 0 };\n modalRef.value!.style.top = `${height + y}px`;\n modalRef.value!.style.bottom = '0';\n modalRef.value!.style.height = 'auto';\n },\n 100,\n { leading: true }\n );\n\n let resizeObserver: ResizeObserver;\n\n onMounted(() => {\n watch(() => props.open, syncBody);\n if (props.open) {\n syncBody(true);\n }\n\n resizeObserver = new ResizeObserver(debouncedUpdatePosition);\n\n if (props.referenceSelector) {\n const element = document.querySelector(props.referenceSelector) as HTMLElement;\n if (element) {\n referenceElement = element;\n resizeObserver.observe(element);\n }\n }\n });\n\n onBeforeUnmount(() => {\n if (props.open) {\n removeBodyListeners();\n enableScroll();\n }\n resizeObserver.disconnect();\n });\n\n return {\n emitOverlayClicked,\n isWaitingForLeave,\n modalContentRef,\n modalRef\n };\n }\n });\n</script>\n\n<style lang=\"css\" scoped>\n .x-modal {\n position: fixed;\n top: 0;\n left: 0;\n display: flex;\n align-items: flex-start;\n justify-content: flex-start;\n width: 100%;\n height: 100%;\n z-index: 1;\n }\n\n .x-modal__content {\n display: flex;\n flex-flow: column nowrap;\n z-index: 1;\n }\n\n .x-modal__overlay {\n width: 100%;\n height: 100%;\n position: absolute;\n background-color: rgb(0, 0, 0);\n opacity: 0.3;\n }\n</style>\n\n<docs lang=\"mdx\">\n## Examples\n\nThe `BaseModal` is a simple component that serves to create complex modals. Its open state has to be\npassed via prop. There is a prop, `referenceSelector`, used to place the modal under some element\ninstead of set the top of the element directly. It also accepts an animation to use for opening &\nclosing.\n\nIt emits a `click:overlay` event when any part out of the content is clicked, but only if the modal\nis open.\n\n```vue\n<template>\n <div>\n <button @click=\"open = true\">Open modal</button>\n <BaseModal\n :animation=\"fadeAndSlide\"\n :open=\"open\"\n @click:overlay=\"open = false\"\n referenceSelector=\".header\"\n >\n <h1>Hello</h1>\n <p>The modal is working</p>\n <button @click=\"open = false\">Close modal</button>\n </BaseModal>\n </div>\n</template>\n\n<script>\n import { BaseModal, FadeAndSlide } from '@empathyco/x-components';\n import Vue from 'vue';\n\n Vue.component('fadeAndSlide', FadeAndSlide);\n\n export default {\n components: {\n BaseModal\n },\n data() {\n return {\n open: false\n };\n }\n };\n</script>\n```\n\n### Customized usage\n\n#### Customizing the content with classes\n\nThe `contentClass` prop can be used to add classes to the modal content.\n\n```vue\n<template>\n <div>\n <button @click=\"open = true\">Open modal</button>\n <BaseModal\n :animation=\"fadeAndSlide\"\n :open=\"open\"\n @click:overlay=\"open = false\"\n referenceSelector=\".header\"\n contentClass=\"x-bg-neutral-75\"\n >\n <h1>Hello</h1>\n <p>The modal is working</p>\n <button @click=\"open = false\">Close modal</button>\n </BaseModal>\n </div>\n</template>\n\n<script>\n import { BaseModal, FadeAndSlide } from '@empathyco/x-components';\n import Vue from 'vue';\n\n Vue.component('fadeAndSlide', FadeAndSlide);\n\n export default {\n components: {\n BaseModal\n },\n data() {\n return {\n open: false\n };\n }\n };\n</script>\n```\n\n#### Customizing the overlay with classes\n\nThe `overlayClass` prop can be used to add classes to the modal overlay.\n\n```vue\n<template>\n <div>\n <button @click=\"open = true\">Open modal</button>\n <BaseModal\n :animation=\"fadeAndSlide\"\n :open=\"open\"\n @click:overlay=\"open = false\"\n referenceSelector=\".header\"\n overlayClass=\"x-bg-neutral-75\"\n >\n <h1>Hello</h1>\n <p>The modal is working</p>\n <button @click=\"open = false\">Close modal</button>\n </BaseModal>\n </div>\n</template>\n\n<script>\n import { BaseModal, FadeAndSlide } from '@empathyco/x-components';\n import Vue from 'vue';\n\n Vue.component('fadeAndSlide', FadeAndSlide);\n\n export default {\n components: {\n BaseModal\n },\n data() {\n return {\n open: false\n };\n }\n };\n</script>\n```\n\n## Vue Events\n\nA list of events that the component will emit:\n\n- `click:overlay`: the event is emitted after the user clicks any part out of the content but only\n if the modal is open. The event payload is the mouse event that triggers it.\n- `focusin:body`: the event is emitted after the user focus in any part out of the content but only\n if the modal is open. The event payload is the focus event that triggers it.\n</docs>\n"],"names":["animation","_withDirectives","_openBlock","_createElementBlock","isWaitingForLeave","_createBlock","_withCtx","_normalizeClass","_renderSlot","_createCommentVNode","_resolveDynamicComponent","overlayClass"],"mappings":";;;;;MACyD,UAAe,GAAA;AAAA,EAAC,GAAA,EAAA,UAAA;AAAA,EAAA,KAAA,EAAA,SAAA;;;AACrE,SAAA,WAAA,CAAA,IAAA,EAAA,MAAA,EAFJ,MAGWA,EAAAA,MAAAA,EAAAA,KAAAA,EAAAA,QAAAA,EAAAA;SACJC,cAAY,EAAAC,SAAA,EAAA,EAAAC,kBAAA;AAAA,IAAEC,KAAAA;AAAAA,IAAAA,UAAAA;AAAAA,IAAAA;AAAAA,OAAAA,SAAAA,EACH,EAAAC,WAAA;AAAA,QAAED,uBAAAA,CAAAA,IAAAA,CAAAA,SAAAA,CAAAA;AAAAA,QAAAA;AAAAA,UAAAA,aAAAA,EAAAA,MAAAA,CAAAA,CAAAA,CAAAA,KAAAA,MAAAA,CAAAA,CAAAA,CAAAA,GAAAA,CAAAA,MAAAA,KAAAA,IAAAA,CAAAA,iBAAAA,GAAAA,IAAAA,CAAAA;UALpB,YAiBY,EAAA,MAAA,CAAA,CAAA,CAAA,KAAA,MAAA,CAAA,CAAA,CAAA,GAAA,CAAA,MAAA,KAAA,IAAA,CAAA,iBAAA,GAAA,KAAA,CAAA;AAAA,SAAA;;AAVN,UAAA,OAAA,EAAAE,OAAA,CAAA,MAAA;AAAA,YAAA,IAAA,CAPN,IASY,IAAAJ,SAAA,EAAA,EAAAC,kBAAA;AAAA,cAAiB,KAAA;AAAA,cAAA;AAAA,gBACrB,GAAK,EAAA,CAAA;AAAA,gBACL,GAAA,EAAA,iBAAA;AAAA,gBACA,OAAKI,cAAQ,CAAA,CAAA,kBAAA,EAAA,IAAA,CAAA,YAAA,CAAA,CAAA;AAAA,gBAAA,WAAA,EAAA,eAAA;AAIb,gBAAA,IAAA,EAAA,QAAA;AAAA,eAAA;;AAhBR,gBAAAC,UAAA,CAAA,IAAA,CAAA,MAAA,EAAA,SAAA,EAAA,EAAA,EAAA,KAAA,CAAA,EAAA,IAAA,CAAA;AAAA,eAAA;;;AAAA,aAAA,IAAAC,kBAAA,CAAA,MAAA,EAAA,IAAA,CAAA;AAAA,WAAA,CAAA;;;;AAAA,QAAA,EAAA;AAAA;AAAA,OA2BQ;AAAA,OAAAP,SAAA,EANU,EAAAG,WAAA,CAAAK,uBAAA,CAAA,IAAA,CAAA,gBAAA,CAAA,EAAA,IAAA,EAAA;AAAA,QADZ,OAAA,EAAAJ,OAAA,CAAA,MAAA;AAAA,UAAA,IAAA,CApBN,IAsBc,IAAAJ,SAAA,EAAA,EAAAC,kBAAA;AAAA,YAAA,KAAA;AAAA,YAAA;AAAA,cACL,GAAA,EAAA,CAAA;AAAA,cACD,OAAA,EAxBR,MAwBc,CAAA,CAAA,CAAA,KAAA,MAAA,CAAA,CAAA,CAAA,GAAA,CAAA,GAAA,IAAA,KACEQ,IAAY,CAAA,kBAAA,IAAA,IAAA,CAAA,kBAAA,CAAA,GAAA,IAAA,CAAA,CAAA;AAAA,cACpB,SAAA,EAAS,OAAC,CAAe,CAAA,KAAA,MAAA,CAAA,CAAA,CAAA,GAAA,CAAA,GAAA,IAAA,KAAA,IAAA,CAAA,kBAAA,IAAA,IAAA,CAAA,kBAAA,CAAA,GAAA,IAAA,CAAA,CAAA;AAAA,cAAA,KAAA,EAAAJ,cAAA,CAAA,CAAA,kBAAA,EAAA,IAAA,CAAA,YAAA,CAAA,CAAA;AA1BjC,cAAA,WAAA,EAAA,eAAA;AAAA,aAAA;;;;AAAA,WAAA,IAAAE,kBAAA,CAAA,MAAA,EAAA,IAAA,CAAA;AAAA,SAAA,CAAA;;;;;;;;;;;;;;;"}
1
+ {"version":3,"file":"base-modal.vue.js","sources":["../../../../src/components/modals/base-modal.vue"],"sourcesContent":["<template>\n <div v-show=\"isWaitingForLeave || open\" ref=\"modalRef\" class=\"x-modal\" data-test=\"modal\">\n <component\n :is=\"animation\"\n @before-leave=\"isWaitingForLeave = true\"\n @after-leave=\"isWaitingForLeave = false\"\n >\n <div\n v-if=\"open\"\n ref=\"modalContentRef\"\n class=\"x-modal__content\"\n data-test=\"modal-content\"\n role=\"dialog\"\n :class=\"contentClass\"\n >\n <!-- @slot (Required) Modal container content -->\n <slot />\n </div>\n </component>\n <component :is=\"overlayAnimation\">\n <div\n v-if=\"open\"\n @click=\"emitOverlayClicked\"\n @keydown=\"emitOverlayClicked\"\n class=\"x-modal__overlay\"\n :class=\"overlayClass\"\n data-test=\"modal-overlay\"\n />\n </component>\n </div>\n</template>\n\n<script lang=\"ts\">\n import { defineComponent, nextTick, onBeforeUnmount, onMounted, ref, watch } from 'vue';\n import { useDebounce } from '../../composables';\n import { AnimationProp } from '../../types';\n import { getTargetElement, FOCUSABLE_SELECTORS } from '../../utils';\n import { Fade, NoAnimation } from '../animations';\n\n /**\n * Base component with no XPlugin dependencies that serves as a utility for constructing more\n * complex modals.\n *\n * @public\n */\n export default defineComponent({\n name: 'BaseModal',\n props: {\n /** Determines if the modal is open or not. */\n open: {\n type: Boolean,\n required: true\n },\n /**\n * Determines if the focused element changes to one inside the modal when it opens. Either the\n * first element with a positive tabindex or just the first focusable element.\n */\n focusOnOpen: {\n type: Boolean,\n default: true\n },\n /**\n * The reference selector of a DOM element to use as reference to position the modal.\n * This selector can be an ID or a class, if it is a class, it will use the first\n * element that matches.\n */\n referenceSelector: String,\n /** Animation to use for opening/closing the modal.This animation only affects the content. */\n animation: {\n type: AnimationProp,\n default: () => NoAnimation\n },\n /**\n * Animation to use for the overlay (backdrop) part of the modal. By default, it uses\n * a fade transition.\n */\n overlayAnimation: {\n type: AnimationProp,\n default: () => Fade\n },\n /** Class inherited by content element. */\n contentClass: String,\n /** Class inherited by overlay element. */\n overlayClass: String\n },\n emits: ['click:overlay', 'focusin:body'],\n setup(props, { emit }) {\n /** Reference to the modal element in the DOM. */\n const modalRef = ref<HTMLDivElement>();\n /** Reference to the modal content element in the DOM. */\n const modalContentRef = ref<HTMLDivElement>();\n\n /** The previous value of the body overflow style. */\n const previousBodyOverflow = ref('');\n /** The previous value of the HTML element overflow style. */\n const previousHTMLOverflow = ref('');\n /** Boolean to delay the leave animation until it has completed. */\n const isWaitingForLeave = ref(false);\n /** The reference element to use to find the modal's position. */\n let referenceElement: HTMLElement | undefined;\n\n /** Disables the scroll of both the body and the window. */\n function disableScroll() {\n previousBodyOverflow.value = document.body.style.overflow;\n previousHTMLOverflow.value = document.documentElement.style.overflow;\n document.body.style.overflow = document.documentElement.style.overflow = 'hidden';\n }\n\n /** Restores the scroll of both the body and the window. */\n function enableScroll() {\n document.body.style.overflow = previousBodyOverflow.value;\n document.documentElement.style.overflow = previousHTMLOverflow.value;\n }\n\n /**\n * Emits the `click:overlay` event if the click has been triggered in the overlay layer.\n *\n * @param event - The click event.\n */\n function emitOverlayClicked(event: Event) {\n emit('click:overlay', event);\n }\n\n /**\n * Emits the `focusin:body` event if a focus event has been triggered outside the modal.\n *\n * @param event - The focusin event.\n */\n function emitFocusInBody(event: FocusEvent) {\n if (!modalContentRef.value?.contains(getTargetElement(event))) {\n emit('focusin:body', event);\n }\n }\n\n /**\n * Adds listeners to the body element ot detect if the modal should be closed.\n *\n * @remarks TODO find a better solution and remove the timeout\n * To avoid emit the focusin on opening X that provokes closing it immediately.\n * This is because this event was emitted after the open of main modal when the user clicks\n * on the customer website search box (focus event). This way we avoid add the listener before\n * the open and the avoid the event that provokes the close.\n */\n function addBodyListeners() {\n setTimeout(() => {\n document.body.addEventListener('focusin', emitFocusInBody);\n });\n }\n\n /** Removes the body listeners. */\n function removeBodyListeners() {\n document.body.removeEventListener('focusin', emitFocusInBody);\n }\n\n /**\n * Sets the focused element to the first element either the first element with a positive\n * tabindex or, if there isn't any, the first focusable element inside the modal.\n */\n function setFocus() {\n const candidates: HTMLElement[] = Array.from(\n modalContentRef.value?.querySelectorAll(FOCUSABLE_SELECTORS) ?? []\n );\n const element = candidates.find(element => element.tabIndex) ?? candidates[0];\n element?.focus();\n }\n\n /**\n * Syncs the body to the open state of the modal, adding or removing styles and listeners.\n *\n * @remarks nextTick() to wait for `modalContentRef` to be updated to look for focusable\n * candidates inside.\n *\n * @param isOpen - True when the modal is opened.\n */\n async function syncBody(isOpen: boolean) {\n if (isOpen) {\n disableScroll();\n addBodyListeners();\n if (props.focusOnOpen) {\n await nextTick();\n setFocus();\n }\n } else {\n enableScroll();\n removeBodyListeners();\n }\n }\n\n /**\n * Updates the position of the modal setting the top of the element depending\n * on the selector. The modal will be placed under this selector.\n */\n const debouncedUpdatePosition = useDebounce(\n () => {\n const { height, y } = referenceElement?.getBoundingClientRect() ?? { height: 0, y: 0 };\n modalRef.value!.style.top = `${height + y}px`;\n modalRef.value!.style.bottom = '0';\n modalRef.value!.style.height = 'auto';\n },\n 100,\n { leading: true }\n );\n\n let resizeObserver: ResizeObserver;\n\n onMounted(() => {\n watch(() => props.open, syncBody);\n if (props.open) {\n syncBody(true);\n }\n\n resizeObserver = new ResizeObserver(debouncedUpdatePosition);\n\n watch(\n () => props.referenceSelector,\n () => {\n resizeObserver.disconnect();\n\n if (props.referenceSelector) {\n const element = document.querySelector(props.referenceSelector) as HTMLElement;\n if (element) {\n referenceElement = element;\n resizeObserver.observe(element);\n }\n } else {\n referenceElement = undefined;\n debouncedUpdatePosition();\n }\n },\n { immediate: true }\n );\n });\n\n onBeforeUnmount(() => {\n if (props.open) {\n removeBodyListeners();\n enableScroll();\n }\n resizeObserver.disconnect();\n });\n\n return {\n emitOverlayClicked,\n isWaitingForLeave,\n modalContentRef,\n modalRef\n };\n }\n });\n</script>\n\n<style lang=\"css\" scoped>\n .x-modal {\n position: fixed;\n top: 0;\n left: 0;\n display: flex;\n align-items: flex-start;\n justify-content: flex-start;\n width: 100%;\n height: 100%;\n z-index: 1;\n }\n\n .x-modal__content {\n display: flex;\n flex-flow: column nowrap;\n z-index: 1;\n }\n\n .x-modal__overlay {\n width: 100%;\n height: 100%;\n position: absolute;\n background-color: rgb(0, 0, 0);\n opacity: 0.3;\n }\n</style>\n\n<docs lang=\"mdx\">\n## Examples\n\nThe `BaseModal` is a simple component that serves to create complex modals. Its open state has to be\npassed via prop. There is a prop, `referenceSelector`, used to place the modal under some element\ninstead of set the top of the element directly. It also accepts an animation to use for opening &\nclosing.\n\nIt emits a `click:overlay` event when any part out of the content is clicked, but only if the modal\nis open.\n\n```vue\n<template>\n <div>\n <button @click=\"open = true\">Open modal</button>\n <BaseModal\n :animation=\"fadeAndSlide\"\n :open=\"open\"\n @click:overlay=\"open = false\"\n referenceSelector=\".header\"\n >\n <h1>Hello</h1>\n <p>The modal is working</p>\n <button @click=\"open = false\">Close modal</button>\n </BaseModal>\n </div>\n</template>\n\n<script>\n import { BaseModal, FadeAndSlide } from '@empathyco/x-components';\n import Vue from 'vue';\n\n Vue.component('fadeAndSlide', FadeAndSlide);\n\n export default {\n components: {\n BaseModal\n },\n data() {\n return {\n open: false\n };\n }\n };\n</script>\n```\n\n### Customized usage\n\n#### Customizing the content with classes\n\nThe `contentClass` prop can be used to add classes to the modal content.\n\n```vue\n<template>\n <div>\n <button @click=\"open = true\">Open modal</button>\n <BaseModal\n :animation=\"fadeAndSlide\"\n :open=\"open\"\n @click:overlay=\"open = false\"\n referenceSelector=\".header\"\n contentClass=\"x-bg-neutral-75\"\n >\n <h1>Hello</h1>\n <p>The modal is working</p>\n <button @click=\"open = false\">Close modal</button>\n </BaseModal>\n </div>\n</template>\n\n<script>\n import { BaseModal, FadeAndSlide } from '@empathyco/x-components';\n import Vue from 'vue';\n\n Vue.component('fadeAndSlide', FadeAndSlide);\n\n export default {\n components: {\n BaseModal\n },\n data() {\n return {\n open: false\n };\n }\n };\n</script>\n```\n\n#### Customizing the overlay with classes\n\nThe `overlayClass` prop can be used to add classes to the modal overlay.\n\n```vue\n<template>\n <div>\n <button @click=\"open = true\">Open modal</button>\n <BaseModal\n :animation=\"fadeAndSlide\"\n :open=\"open\"\n @click:overlay=\"open = false\"\n referenceSelector=\".header\"\n overlayClass=\"x-bg-neutral-75\"\n >\n <h1>Hello</h1>\n <p>The modal is working</p>\n <button @click=\"open = false\">Close modal</button>\n </BaseModal>\n </div>\n</template>\n\n<script>\n import { BaseModal, FadeAndSlide } from '@empathyco/x-components';\n import Vue from 'vue';\n\n Vue.component('fadeAndSlide', FadeAndSlide);\n\n export default {\n components: {\n BaseModal\n },\n data() {\n return {\n open: false\n };\n }\n };\n</script>\n```\n\n## Vue Events\n\nA list of events that the component will emit:\n\n- `click:overlay`: the event is emitted after the user clicks any part out of the content but only\n if the modal is open. The event payload is the mouse event that triggers it.\n- `focusin:body`: the event is emitted after the user focus in any part out of the content but only\n if the modal is open. The event payload is the focus event that triggers it.\n</docs>\n"],"names":["animation","_withDirectives","_openBlock","_createElementBlock","isWaitingForLeave","_createBlock","_withCtx","_normalizeClass","_renderSlot","_createCommentVNode","_resolveDynamicComponent","overlayClass"],"mappings":";;;;;MACyD,UAAe,GAAA;AAAA,EAAC,GAAA,EAAA,UAAA;AAAA,EAAA,KAAA,EAAA,SAAA;;;AACrE,SAAA,WAAA,CAAA,IAAA,EAAA,MAAA,EAFJ,MAGWA,EAAAA,MAAAA,EAAAA,KAAAA,EAAAA,QAAAA,EAAAA;SACJC,cAAY,EAAAC,SAAA,EAAA,EAAAC,kBAAA;AAAA,IAAEC,KAAAA;AAAAA,IAAAA,UAAAA;AAAAA,IAAAA;AAAAA,OAAAA,SAAAA,EACH,EAAAC,WAAA;AAAA,QAAED,uBAAAA,CAAAA,IAAAA,CAAAA,SAAAA,CAAAA;AAAAA,QAAAA;AAAAA,UAAAA,aAAAA,EAAAA,MAAAA,CAAAA,CAAAA,CAAAA,KAAAA,MAAAA,CAAAA,CAAAA,CAAAA,GAAAA,CAAAA,MAAAA,KAAAA,IAAAA,CAAAA,iBAAAA,GAAAA,IAAAA,CAAAA;UALpB,YAiBY,EAAA,MAAA,CAAA,CAAA,CAAA,KAAA,MAAA,CAAA,CAAA,CAAA,GAAA,CAAA,MAAA,KAAA,IAAA,CAAA,iBAAA,GAAA,KAAA,CAAA;AAAA,SAAA;;AAVN,UAAA,OAAA,EAAAE,OAAA,CAAA,MAAA;AAAA,YAAA,IAAA,CAPN,IASY,IAAAJ,SAAA,EAAA,EAAAC,kBAAA;AAAA,cAAiB,KAAA;AAAA,cAAA;AAAA,gBACrB,GAAK,EAAA,CAAA;AAAA,gBACL,GAAA,EAAA,iBAAA;AAAA,gBACA,OAAKI,cAAQ,CAAA,CAAA,kBAAA,EAAA,IAAA,CAAA,YAAA,CAAA,CAAA;AAAA,gBAAA,WAAA,EAAA,eAAA;AAIb,gBAAA,IAAA,EAAA,QAAA;AAAA,eAAA;;AAhBR,gBAAAC,UAAA,CAAA,IAAA,CAAA,MAAA,EAAA,SAAA,EAAA,EAAA,EAAA,KAAA,CAAA,EAAA,IAAA,CAAA;AAAA,eAAA;;;AAAA,aAAA,IAAAC,kBAAA,CAAA,MAAA,EAAA,IAAA,CAAA;AAAA,WAAA,CAAA;;;;AAAA,QAAA,EAAA;AAAA;AAAA,OA2BQ;AAAA,OAAAP,SAAA,EANU,EAAAG,WAAA,CAAAK,uBAAA,CAAA,IAAA,CAAA,gBAAA,CAAA,EAAA,IAAA,EAAA;AAAA,QADZ,OAAA,EAAAJ,OAAA,CAAA,MAAA;AAAA,UAAA,IAAA,CApBN,IAsBc,IAAAJ,SAAA,EAAA,EAAAC,kBAAA;AAAA,YAAA,KAAA;AAAA,YAAA;AAAA,cACL,GAAA,EAAA,CAAA;AAAA,cACD,OAAA,EAxBR,MAwBc,CAAA,CAAA,CAAA,KAAA,MAAA,CAAA,CAAA,CAAA,GAAA,CAAA,GAAA,IAAA,KACEQ,IAAY,CAAA,kBAAA,IAAA,IAAA,CAAA,kBAAA,CAAA,GAAA,IAAA,CAAA,CAAA;AAAA,cACpB,SAAA,EAAS,OAAC,CAAe,CAAA,KAAA,MAAA,CAAA,CAAA,CAAA,GAAA,CAAA,GAAA,IAAA,KAAA,IAAA,CAAA,kBAAA,IAAA,IAAA,CAAA,kBAAA,CAAA,GAAA,IAAA,CAAA,CAAA;AAAA,cAAA,KAAA,EAAAJ,cAAA,CAAA,CAAA,kBAAA,EAAA,IAAA,CAAA,YAAA,CAAA,CAAA;AA1BjC,cAAA,WAAA,EAAA,eAAA;AAAA,aAAA;;;;AAAA,WAAA,IAAAE,kBAAA,CAAA,MAAA,EAAA,IAAA,CAAA;AAAA,SAAA,CAAA;;;;;;;;;;;;;;;"}
@@ -188,13 +188,20 @@ var _sfc_main = defineComponent({
188
188
  syncBody(true);
189
189
  }
190
190
  resizeObserver = new ResizeObserver(debouncedUpdatePosition);
191
- if (props.referenceSelector) {
192
- const element = document.querySelector(props.referenceSelector);
193
- if (element) {
194
- referenceElement = element;
195
- resizeObserver.observe(element);
191
+ watch(() => props.referenceSelector, () => {
192
+ resizeObserver.disconnect();
193
+ if (props.referenceSelector) {
194
+ const element = document.querySelector(props.referenceSelector);
195
+ if (element) {
196
+ referenceElement = element;
197
+ resizeObserver.observe(element);
198
+ }
196
199
  }
197
- }
200
+ else {
201
+ referenceElement = undefined;
202
+ debouncedUpdatePosition();
203
+ }
204
+ }, { immediate: true });
198
205
  });
199
206
  onBeforeUnmount(() => {
200
207
  if (props.open) {
@@ -1 +1 @@
1
- {"version":3,"file":"base-modal.vue2.js","sources":["../../../../src/components/modals/base-modal.vue"],"sourcesContent":["<template>\n <div v-show=\"isWaitingForLeave || open\" ref=\"modalRef\" class=\"x-modal\" data-test=\"modal\">\n <component\n :is=\"animation\"\n @before-leave=\"isWaitingForLeave = true\"\n @after-leave=\"isWaitingForLeave = false\"\n >\n <div\n v-if=\"open\"\n ref=\"modalContentRef\"\n class=\"x-modal__content\"\n data-test=\"modal-content\"\n role=\"dialog\"\n :class=\"contentClass\"\n >\n <!-- @slot (Required) Modal container content -->\n <slot />\n </div>\n </component>\n <component :is=\"overlayAnimation\">\n <div\n v-if=\"open\"\n @click=\"emitOverlayClicked\"\n @keydown=\"emitOverlayClicked\"\n class=\"x-modal__overlay\"\n :class=\"overlayClass\"\n data-test=\"modal-overlay\"\n />\n </component>\n </div>\n</template>\n\n<script lang=\"ts\">\n import { defineComponent, nextTick, onBeforeUnmount, onMounted, ref, watch } from 'vue';\n import { useDebounce } from '../../composables';\n import { AnimationProp } from '../../types';\n import { getTargetElement, FOCUSABLE_SELECTORS } from '../../utils';\n import { Fade, NoAnimation } from '../animations';\n\n /**\n * Base component with no XPlugin dependencies that serves as a utility for constructing more\n * complex modals.\n *\n * @public\n */\n export default defineComponent({\n name: 'BaseModal',\n props: {\n /** Determines if the modal is open or not. */\n open: {\n type: Boolean,\n required: true\n },\n /**\n * Determines if the focused element changes to one inside the modal when it opens. Either the\n * first element with a positive tabindex or just the first focusable element.\n */\n focusOnOpen: {\n type: Boolean,\n default: true\n },\n /**\n * The reference selector of a DOM element to use as reference to position the modal.\n * This selector can be an ID or a class, if it is a class, it will use the first\n * element that matches.\n */\n referenceSelector: String,\n /** Animation to use for opening/closing the modal.This animation only affects the content. */\n animation: {\n type: AnimationProp,\n default: () => NoAnimation\n },\n /**\n * Animation to use for the overlay (backdrop) part of the modal. By default, it uses\n * a fade transition.\n */\n overlayAnimation: {\n type: AnimationProp,\n default: () => Fade\n },\n /** Class inherited by content element. */\n contentClass: String,\n /** Class inherited by overlay element. */\n overlayClass: String\n },\n emits: ['click:overlay', 'focusin:body'],\n setup(props, { emit }) {\n /** Reference to the modal element in the DOM. */\n const modalRef = ref<HTMLDivElement>();\n /** Reference to the modal content element in the DOM. */\n const modalContentRef = ref<HTMLDivElement>();\n\n /** The previous value of the body overflow style. */\n const previousBodyOverflow = ref('');\n /** The previous value of the HTML element overflow style. */\n const previousHTMLOverflow = ref('');\n /** Boolean to delay the leave animation until it has completed. */\n const isWaitingForLeave = ref(false);\n /** The reference element to use to find the modal's position. */\n let referenceElement: HTMLElement;\n\n /** Disables the scroll of both the body and the window. */\n function disableScroll() {\n previousBodyOverflow.value = document.body.style.overflow;\n previousHTMLOverflow.value = document.documentElement.style.overflow;\n document.body.style.overflow = document.documentElement.style.overflow = 'hidden';\n }\n\n /** Restores the scroll of both the body and the window. */\n function enableScroll() {\n document.body.style.overflow = previousBodyOverflow.value;\n document.documentElement.style.overflow = previousHTMLOverflow.value;\n }\n\n /**\n * Emits the `click:overlay` event if the click has been triggered in the overlay layer.\n *\n * @param event - The click event.\n */\n function emitOverlayClicked(event: Event) {\n emit('click:overlay', event);\n }\n\n /**\n * Emits the `focusin:body` event if a focus event has been triggered outside the modal.\n *\n * @param event - The focusin event.\n */\n function emitFocusInBody(event: FocusEvent) {\n if (!modalContentRef.value?.contains(getTargetElement(event))) {\n emit('focusin:body', event);\n }\n }\n\n /**\n * Adds listeners to the body element ot detect if the modal should be closed.\n *\n * @remarks TODO find a better solution and remove the timeout\n * To avoid emit the focusin on opening X that provokes closing it immediately.\n * This is because this event was emitted after the open of main modal when the user clicks\n * on the customer website search box (focus event). This way we avoid add the listener before\n * the open and the avoid the event that provokes the close.\n */\n function addBodyListeners() {\n setTimeout(() => {\n document.body.addEventListener('focusin', emitFocusInBody);\n });\n }\n\n /** Removes the body listeners. */\n function removeBodyListeners() {\n document.body.removeEventListener('focusin', emitFocusInBody);\n }\n\n /**\n * Sets the focused element to the first element either the first element with a positive\n * tabindex or, if there isn't any, the first focusable element inside the modal.\n */\n function setFocus() {\n const candidates: HTMLElement[] = Array.from(\n modalContentRef.value?.querySelectorAll(FOCUSABLE_SELECTORS) ?? []\n );\n const element = candidates.find(element => element.tabIndex) ?? candidates[0];\n element?.focus();\n }\n\n /**\n * Syncs the body to the open state of the modal, adding or removing styles and listeners.\n *\n * @remarks nextTick() to wait for `modalContentRef` to be updated to look for focusable\n * candidates inside.\n *\n * @param isOpen - True when the modal is opened.\n */\n async function syncBody(isOpen: boolean) {\n if (isOpen) {\n disableScroll();\n addBodyListeners();\n if (props.focusOnOpen) {\n await nextTick();\n setFocus();\n }\n } else {\n enableScroll();\n removeBodyListeners();\n }\n }\n\n /**\n * Updates the position of the modal setting the top of the element depending\n * on the selector. The modal will be placed under this selector.\n */\n const debouncedUpdatePosition = useDebounce(\n () => {\n const { height, y } = referenceElement?.getBoundingClientRect() ?? { height: 0, y: 0 };\n modalRef.value!.style.top = `${height + y}px`;\n modalRef.value!.style.bottom = '0';\n modalRef.value!.style.height = 'auto';\n },\n 100,\n { leading: true }\n );\n\n let resizeObserver: ResizeObserver;\n\n onMounted(() => {\n watch(() => props.open, syncBody);\n if (props.open) {\n syncBody(true);\n }\n\n resizeObserver = new ResizeObserver(debouncedUpdatePosition);\n\n if (props.referenceSelector) {\n const element = document.querySelector(props.referenceSelector) as HTMLElement;\n if (element) {\n referenceElement = element;\n resizeObserver.observe(element);\n }\n }\n });\n\n onBeforeUnmount(() => {\n if (props.open) {\n removeBodyListeners();\n enableScroll();\n }\n resizeObserver.disconnect();\n });\n\n return {\n emitOverlayClicked,\n isWaitingForLeave,\n modalContentRef,\n modalRef\n };\n }\n });\n</script>\n\n<style lang=\"css\" scoped>\n .x-modal {\n position: fixed;\n top: 0;\n left: 0;\n display: flex;\n align-items: flex-start;\n justify-content: flex-start;\n width: 100%;\n height: 100%;\n z-index: 1;\n }\n\n .x-modal__content {\n display: flex;\n flex-flow: column nowrap;\n z-index: 1;\n }\n\n .x-modal__overlay {\n width: 100%;\n height: 100%;\n position: absolute;\n background-color: rgb(0, 0, 0);\n opacity: 0.3;\n }\n</style>\n\n<docs lang=\"mdx\">\n## Examples\n\nThe `BaseModal` is a simple component that serves to create complex modals. Its open state has to be\npassed via prop. There is a prop, `referenceSelector`, used to place the modal under some element\ninstead of set the top of the element directly. It also accepts an animation to use for opening &\nclosing.\n\nIt emits a `click:overlay` event when any part out of the content is clicked, but only if the modal\nis open.\n\n```vue\n<template>\n <div>\n <button @click=\"open = true\">Open modal</button>\n <BaseModal\n :animation=\"fadeAndSlide\"\n :open=\"open\"\n @click:overlay=\"open = false\"\n referenceSelector=\".header\"\n >\n <h1>Hello</h1>\n <p>The modal is working</p>\n <button @click=\"open = false\">Close modal</button>\n </BaseModal>\n </div>\n</template>\n\n<script>\n import { BaseModal, FadeAndSlide } from '@empathyco/x-components';\n import Vue from 'vue';\n\n Vue.component('fadeAndSlide', FadeAndSlide);\n\n export default {\n components: {\n BaseModal\n },\n data() {\n return {\n open: false\n };\n }\n };\n</script>\n```\n\n### Customized usage\n\n#### Customizing the content with classes\n\nThe `contentClass` prop can be used to add classes to the modal content.\n\n```vue\n<template>\n <div>\n <button @click=\"open = true\">Open modal</button>\n <BaseModal\n :animation=\"fadeAndSlide\"\n :open=\"open\"\n @click:overlay=\"open = false\"\n referenceSelector=\".header\"\n contentClass=\"x-bg-neutral-75\"\n >\n <h1>Hello</h1>\n <p>The modal is working</p>\n <button @click=\"open = false\">Close modal</button>\n </BaseModal>\n </div>\n</template>\n\n<script>\n import { BaseModal, FadeAndSlide } from '@empathyco/x-components';\n import Vue from 'vue';\n\n Vue.component('fadeAndSlide', FadeAndSlide);\n\n export default {\n components: {\n BaseModal\n },\n data() {\n return {\n open: false\n };\n }\n };\n</script>\n```\n\n#### Customizing the overlay with classes\n\nThe `overlayClass` prop can be used to add classes to the modal overlay.\n\n```vue\n<template>\n <div>\n <button @click=\"open = true\">Open modal</button>\n <BaseModal\n :animation=\"fadeAndSlide\"\n :open=\"open\"\n @click:overlay=\"open = false\"\n referenceSelector=\".header\"\n overlayClass=\"x-bg-neutral-75\"\n >\n <h1>Hello</h1>\n <p>The modal is working</p>\n <button @click=\"open = false\">Close modal</button>\n </BaseModal>\n </div>\n</template>\n\n<script>\n import { BaseModal, FadeAndSlide } from '@empathyco/x-components';\n import Vue from 'vue';\n\n Vue.component('fadeAndSlide', FadeAndSlide);\n\n export default {\n components: {\n BaseModal\n },\n data() {\n return {\n open: false\n };\n }\n };\n</script>\n```\n\n## Vue Events\n\nA list of events that the component will emit:\n\n- `click:overlay`: the event is emitted after the user clicks any part out of the content but only\n if the modal is open. The event payload is the mouse event that triggers it.\n- `focusin:body`: the event is emitted after the user focus in any part out of the content but only\n if the modal is open. The event payload is the focus event that triggers it.\n</docs>\n"],"names":["NoAnimation"],"mappings":"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"}
1
+ {"version":3,"file":"base-modal.vue2.js","sources":["../../../../src/components/modals/base-modal.vue"],"sourcesContent":["<template>\n <div v-show=\"isWaitingForLeave || open\" ref=\"modalRef\" class=\"x-modal\" data-test=\"modal\">\n <component\n :is=\"animation\"\n @before-leave=\"isWaitingForLeave = true\"\n @after-leave=\"isWaitingForLeave = false\"\n >\n <div\n v-if=\"open\"\n ref=\"modalContentRef\"\n class=\"x-modal__content\"\n data-test=\"modal-content\"\n role=\"dialog\"\n :class=\"contentClass\"\n >\n <!-- @slot (Required) Modal container content -->\n <slot />\n </div>\n </component>\n <component :is=\"overlayAnimation\">\n <div\n v-if=\"open\"\n @click=\"emitOverlayClicked\"\n @keydown=\"emitOverlayClicked\"\n class=\"x-modal__overlay\"\n :class=\"overlayClass\"\n data-test=\"modal-overlay\"\n />\n </component>\n </div>\n</template>\n\n<script lang=\"ts\">\n import { defineComponent, nextTick, onBeforeUnmount, onMounted, ref, watch } from 'vue';\n import { useDebounce } from '../../composables';\n import { AnimationProp } from '../../types';\n import { getTargetElement, FOCUSABLE_SELECTORS } from '../../utils';\n import { Fade, NoAnimation } from '../animations';\n\n /**\n * Base component with no XPlugin dependencies that serves as a utility for constructing more\n * complex modals.\n *\n * @public\n */\n export default defineComponent({\n name: 'BaseModal',\n props: {\n /** Determines if the modal is open or not. */\n open: {\n type: Boolean,\n required: true\n },\n /**\n * Determines if the focused element changes to one inside the modal when it opens. Either the\n * first element with a positive tabindex or just the first focusable element.\n */\n focusOnOpen: {\n type: Boolean,\n default: true\n },\n /**\n * The reference selector of a DOM element to use as reference to position the modal.\n * This selector can be an ID or a class, if it is a class, it will use the first\n * element that matches.\n */\n referenceSelector: String,\n /** Animation to use for opening/closing the modal.This animation only affects the content. */\n animation: {\n type: AnimationProp,\n default: () => NoAnimation\n },\n /**\n * Animation to use for the overlay (backdrop) part of the modal. By default, it uses\n * a fade transition.\n */\n overlayAnimation: {\n type: AnimationProp,\n default: () => Fade\n },\n /** Class inherited by content element. */\n contentClass: String,\n /** Class inherited by overlay element. */\n overlayClass: String\n },\n emits: ['click:overlay', 'focusin:body'],\n setup(props, { emit }) {\n /** Reference to the modal element in the DOM. */\n const modalRef = ref<HTMLDivElement>();\n /** Reference to the modal content element in the DOM. */\n const modalContentRef = ref<HTMLDivElement>();\n\n /** The previous value of the body overflow style. */\n const previousBodyOverflow = ref('');\n /** The previous value of the HTML element overflow style. */\n const previousHTMLOverflow = ref('');\n /** Boolean to delay the leave animation until it has completed. */\n const isWaitingForLeave = ref(false);\n /** The reference element to use to find the modal's position. */\n let referenceElement: HTMLElement | undefined;\n\n /** Disables the scroll of both the body and the window. */\n function disableScroll() {\n previousBodyOverflow.value = document.body.style.overflow;\n previousHTMLOverflow.value = document.documentElement.style.overflow;\n document.body.style.overflow = document.documentElement.style.overflow = 'hidden';\n }\n\n /** Restores the scroll of both the body and the window. */\n function enableScroll() {\n document.body.style.overflow = previousBodyOverflow.value;\n document.documentElement.style.overflow = previousHTMLOverflow.value;\n }\n\n /**\n * Emits the `click:overlay` event if the click has been triggered in the overlay layer.\n *\n * @param event - The click event.\n */\n function emitOverlayClicked(event: Event) {\n emit('click:overlay', event);\n }\n\n /**\n * Emits the `focusin:body` event if a focus event has been triggered outside the modal.\n *\n * @param event - The focusin event.\n */\n function emitFocusInBody(event: FocusEvent) {\n if (!modalContentRef.value?.contains(getTargetElement(event))) {\n emit('focusin:body', event);\n }\n }\n\n /**\n * Adds listeners to the body element ot detect if the modal should be closed.\n *\n * @remarks TODO find a better solution and remove the timeout\n * To avoid emit the focusin on opening X that provokes closing it immediately.\n * This is because this event was emitted after the open of main modal when the user clicks\n * on the customer website search box (focus event). This way we avoid add the listener before\n * the open and the avoid the event that provokes the close.\n */\n function addBodyListeners() {\n setTimeout(() => {\n document.body.addEventListener('focusin', emitFocusInBody);\n });\n }\n\n /** Removes the body listeners. */\n function removeBodyListeners() {\n document.body.removeEventListener('focusin', emitFocusInBody);\n }\n\n /**\n * Sets the focused element to the first element either the first element with a positive\n * tabindex or, if there isn't any, the first focusable element inside the modal.\n */\n function setFocus() {\n const candidates: HTMLElement[] = Array.from(\n modalContentRef.value?.querySelectorAll(FOCUSABLE_SELECTORS) ?? []\n );\n const element = candidates.find(element => element.tabIndex) ?? candidates[0];\n element?.focus();\n }\n\n /**\n * Syncs the body to the open state of the modal, adding or removing styles and listeners.\n *\n * @remarks nextTick() to wait for `modalContentRef` to be updated to look for focusable\n * candidates inside.\n *\n * @param isOpen - True when the modal is opened.\n */\n async function syncBody(isOpen: boolean) {\n if (isOpen) {\n disableScroll();\n addBodyListeners();\n if (props.focusOnOpen) {\n await nextTick();\n setFocus();\n }\n } else {\n enableScroll();\n removeBodyListeners();\n }\n }\n\n /**\n * Updates the position of the modal setting the top of the element depending\n * on the selector. The modal will be placed under this selector.\n */\n const debouncedUpdatePosition = useDebounce(\n () => {\n const { height, y } = referenceElement?.getBoundingClientRect() ?? { height: 0, y: 0 };\n modalRef.value!.style.top = `${height + y}px`;\n modalRef.value!.style.bottom = '0';\n modalRef.value!.style.height = 'auto';\n },\n 100,\n { leading: true }\n );\n\n let resizeObserver: ResizeObserver;\n\n onMounted(() => {\n watch(() => props.open, syncBody);\n if (props.open) {\n syncBody(true);\n }\n\n resizeObserver = new ResizeObserver(debouncedUpdatePosition);\n\n watch(\n () => props.referenceSelector,\n () => {\n resizeObserver.disconnect();\n\n if (props.referenceSelector) {\n const element = document.querySelector(props.referenceSelector) as HTMLElement;\n if (element) {\n referenceElement = element;\n resizeObserver.observe(element);\n }\n } else {\n referenceElement = undefined;\n debouncedUpdatePosition();\n }\n },\n { immediate: true }\n );\n });\n\n onBeforeUnmount(() => {\n if (props.open) {\n removeBodyListeners();\n enableScroll();\n }\n resizeObserver.disconnect();\n });\n\n return {\n emitOverlayClicked,\n isWaitingForLeave,\n modalContentRef,\n modalRef\n };\n }\n });\n</script>\n\n<style lang=\"css\" scoped>\n .x-modal {\n position: fixed;\n top: 0;\n left: 0;\n display: flex;\n align-items: flex-start;\n justify-content: flex-start;\n width: 100%;\n height: 100%;\n z-index: 1;\n }\n\n .x-modal__content {\n display: flex;\n flex-flow: column nowrap;\n z-index: 1;\n }\n\n .x-modal__overlay {\n width: 100%;\n height: 100%;\n position: absolute;\n background-color: rgb(0, 0, 0);\n opacity: 0.3;\n }\n</style>\n\n<docs lang=\"mdx\">\n## Examples\n\nThe `BaseModal` is a simple component that serves to create complex modals. Its open state has to be\npassed via prop. There is a prop, `referenceSelector`, used to place the modal under some element\ninstead of set the top of the element directly. It also accepts an animation to use for opening &\nclosing.\n\nIt emits a `click:overlay` event when any part out of the content is clicked, but only if the modal\nis open.\n\n```vue\n<template>\n <div>\n <button @click=\"open = true\">Open modal</button>\n <BaseModal\n :animation=\"fadeAndSlide\"\n :open=\"open\"\n @click:overlay=\"open = false\"\n referenceSelector=\".header\"\n >\n <h1>Hello</h1>\n <p>The modal is working</p>\n <button @click=\"open = false\">Close modal</button>\n </BaseModal>\n </div>\n</template>\n\n<script>\n import { BaseModal, FadeAndSlide } from '@empathyco/x-components';\n import Vue from 'vue';\n\n Vue.component('fadeAndSlide', FadeAndSlide);\n\n export default {\n components: {\n BaseModal\n },\n data() {\n return {\n open: false\n };\n }\n };\n</script>\n```\n\n### Customized usage\n\n#### Customizing the content with classes\n\nThe `contentClass` prop can be used to add classes to the modal content.\n\n```vue\n<template>\n <div>\n <button @click=\"open = true\">Open modal</button>\n <BaseModal\n :animation=\"fadeAndSlide\"\n :open=\"open\"\n @click:overlay=\"open = false\"\n referenceSelector=\".header\"\n contentClass=\"x-bg-neutral-75\"\n >\n <h1>Hello</h1>\n <p>The modal is working</p>\n <button @click=\"open = false\">Close modal</button>\n </BaseModal>\n </div>\n</template>\n\n<script>\n import { BaseModal, FadeAndSlide } from '@empathyco/x-components';\n import Vue from 'vue';\n\n Vue.component('fadeAndSlide', FadeAndSlide);\n\n export default {\n components: {\n BaseModal\n },\n data() {\n return {\n open: false\n };\n }\n };\n</script>\n```\n\n#### Customizing the overlay with classes\n\nThe `overlayClass` prop can be used to add classes to the modal overlay.\n\n```vue\n<template>\n <div>\n <button @click=\"open = true\">Open modal</button>\n <BaseModal\n :animation=\"fadeAndSlide\"\n :open=\"open\"\n @click:overlay=\"open = false\"\n referenceSelector=\".header\"\n overlayClass=\"x-bg-neutral-75\"\n >\n <h1>Hello</h1>\n <p>The modal is working</p>\n <button @click=\"open = false\">Close modal</button>\n </BaseModal>\n </div>\n</template>\n\n<script>\n import { BaseModal, FadeAndSlide } from '@empathyco/x-components';\n import Vue from 'vue';\n\n Vue.component('fadeAndSlide', FadeAndSlide);\n\n export default {\n components: {\n BaseModal\n },\n data() {\n return {\n open: false\n };\n }\n };\n</script>\n```\n\n## Vue Events\n\nA list of events that the component will emit:\n\n- `click:overlay`: the event is emitted after the user clicks any part out of the content but only\n if the modal is open. The event payload is the mouse event that triggers it.\n- `focusin:body`: the event is emitted after the user focus in any part out of the content but only\n if the modal is open. The event payload is the focus event that triggers it.\n</docs>\n"],"names":["NoAnimation"],"mappings":"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"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@empathyco/x-components",
3
- "version": "6.0.0-alpha.27",
3
+ "version": "6.0.0-alpha.28",
4
4
  "description": "Empathy X Components",
5
5
  "author": "Empathy Systems Corporation S.L.",
6
6
  "license": "Apache-2.0",
@@ -138,5 +138,5 @@
138
138
  "access": "public",
139
139
  "directory": "dist"
140
140
  },
141
- "gitHead": "cc91c55beed9cd1c4e056ba61b19801e279a6eac"
141
+ "gitHead": "66f60255a67fe290db89301b390ef6b4d65d0baf"
142
142
  }
@@ -1 +1 @@
1
- {"version":3,"file":"base-modal.vue?vue&type=script&lang.d.ts","sourceRoot":"","sources":["../../../../src/components/modals/base-modal.vue?vue&type=script&lang.ts"],"names":[],"mappings":"AAOE;;;;;GAKG;;IAIC,8CAA8C;;;;;IAK9C;;;OAGG;;;;;IAKH;;;;OAIG;;IAEH,8FAA8F;;;;;IAK9F;;;OAGG;;;;;IAKH,0CAA0C;;IAE1C,0CAA0C;;;gCAqCP,KAAK;;;;;IAvExC,8CAA8C;;;;;IAK9C;;;OAGG;;;;;IAKH;;;;OAIG;;IAEH,8FAA8F;;;;;IAK9F;;;OAGG;;;;;IAKH,0CAA0C;;IAE1C,0CAA0C;;;;;;;;;;AArC9C,wBAgMG"}
1
+ {"version":3,"file":"base-modal.vue?vue&type=script&lang.d.ts","sourceRoot":"","sources":["../../../../src/components/modals/base-modal.vue?vue&type=script&lang.ts"],"names":[],"mappings":"AAOE;;;;;GAKG;;IAIC,8CAA8C;;;;;IAK9C;;;OAGG;;;;;IAKH;;;;OAIG;;IAEH,8FAA8F;;;;;IAK9F;;;OAGG;;;;;IAKH,0CAA0C;;IAE1C,0CAA0C;;;gCAqCP,KAAK;;;;;IAvExC,8CAA8C;;;;;IAK9C;;;OAGG;;;;;IAKH;;;;OAIG;;IAEH,8FAA8F;;;;;IAK9F;;;OAGG;;;;;IAKH,0CAA0C;;IAE1C,0CAA0C;;;;;;;;;;AArC9C,wBA2MG"}