{"version":3,"file":"modal.cjs","names":[],"sources":["../../../components/modal/modal.vue"],"sourcesContent":["<template>\n  <teleport\n    :disabled=\"!appendTo\"\n    :to=\"appendTo\"\n  >\n    <dt-lazy-show\n      ref=\"modalRoot\"\n      transition=\"d-zoom\"\n      :show=\"show\"\n      :class=\"[\n        'd-modal',\n        MODAL_KIND_MODIFIERS[kind],\n        MODAL_SIZE_MODIFIERS[size],\n        modalClass,\n      ]\"\n      data-qa=\"dt-modal\"\n      :aria-hidden=\"open\"\n      v-on=\"modalListeners\"\n    >\n      <div\n        v-if=\"show && (hasSlotContent($slots.banner) || bannerTitle)\"\n        data-qa=\"dt-modal-banner\"\n        :class=\"[\n          'd-modal__banner',\n          bannerClass,\n          bannerKindClass,\n        ]\"\n      >\n        <!-- @slot Slot for the banner, defaults to bannerTitle prop -->\n        <slot name=\"banner\">\n          {{ bannerTitle }}\n        </slot>\n      </div>\n      <transition\n        appear\n        name=\"d-modal__dialog\"\n      >\n        <div\n          v-show=\"show\"\n          :class=\"[\n            'd-modal__dialog',\n            { 'd-modal__dialog--scrollable': fixedHeaderFooter },\n            dialogClass,\n          ]\"\n          role=\"dialog\"\n          aria-modal=\"true\"\n          :aria-describedby=\"describedById\"\n          :aria-labelledby=\"labelledById\"\n        >\n          <div\n            v-if=\"hasSlotContent($slots.header)\"\n            :id=\"labelledById\"\n            class=\"d-modal__header\"\n            data-qa=\"dt-modal-title\"\n          >\n            <!-- @slot Slot for dialog header section, taking the place of any \"title\" text prop -->\n            <slot name=\"header\" />\n          </div>\n          <h2\n            v-else\n            :id=\"labelledById\"\n            class=\"d-modal__header\"\n            data-qa=\"dt-modal-title\"\n          >\n            {{ title }}\n          </h2>\n          <div\n            v-if=\"hasSlotContent($slots.default)\"\n            :class=\"[\n              'd-modal__content',\n              contentClass,\n            ]\"\n            data-qa=\"dt-modal-copy\"\n          >\n            <!-- @slot Default slot for dialog body section, taking the place of any \"copy\" text prop -->\n            <slot />\n          </div>\n          <p\n            v-else\n            :class=\"[\n              'd-modal__content',\n              contentClass,\n            ]\"\n            data-qa=\"dt-modal-copy\"\n          >\n            {{ copy }}\n          </p>\n          <footer\n            v-if=\"hasFooterSlot\"\n            class=\"d-modal__footer\"\n          >\n            <!-- @slot Slot for dialog footer content, often containing cancel and confirm buttons. -->\n            <slot name=\"footer\" />\n          </footer>\n          <sr-only-close-button\n            v-if=\"hideClose\"\n            @close=\"close\"\n          />\n          <dt-button\n            v-else\n            class=\"d-modal__close\"\n            data-qa=\"dt-modal-close-button\"\n            size=\"md\"\n            kind=\"muted\"\n            importance=\"clear\"\n            :aria-label=\"closeButtonTitle\"\n            :title=\"closeButtonTitle\"\n            @click=\"close\"\n          >\n            <template #icon=\"{ iconSize }\">\n              <dt-icon-close\n                :size=\"iconSize\"\n              />\n            </template>\n          </dt-button>\n        </div>\n      </transition>\n    </dt-lazy-show>\n  </teleport>\n</template>\n\n<script>\n/* eslint-disable max-lines */\nimport { DtButton } from '@/components/button';\nimport { DtIconClose } from '@dialpad/dialtone-icons/vue3';\nimport Modal from '@/common/mixins/modal';\nimport {\n  MODAL_BANNER_KINDS,\n  MODAL_KIND_MODIFIERS,\n  MODAL_SIZE_MODIFIERS,\n} from './modal_constants';\nimport { returnFirstEl, getUniqueString, hasSlotContent, disableRootScrolling, enableRootScrolling } from '@/common/utils';\nimport { DtLazyShow } from '@/components/lazy_show';\nimport { EVENT_KEYNAMES } from '@/common/constants';\nimport SrOnlyCloseButton from '@/common/sr_only_close_button.vue';\nimport { NOTICE_KINDS } from '@/components/notice';\nimport { DialtoneLocalization } from '@/localization';\n\n/**\n * Modals focus the user’s attention exclusively on one task or piece of information\n * via a window that sits on top of the page content.\n * @see https://dialtone.dialpad.com/components/modal.html\n */\nexport default {\n  compatConfig: { MODE: 3 },\n  name: 'DtModal',\n\n  components: {\n    DtLazyShow,\n    DtButton,\n    DtIconClose,\n    SrOnlyCloseButton,\n  },\n\n  mixins: [Modal],\n\n  props: {\n    /**\n     * Body text to display as the modal's main content.\n     */\n    copy: {\n      type: String,\n      default: '',\n    },\n\n    /**\n     * Id to use for the dialog's aria-describedby.\n     * Recommended only if the dialog content itself isn't enough to give full context,\n     * as screen readers should recite the dialog contents by default before any aria-description.\n     */\n    describedById: {\n      type: String,\n      default: '',\n    },\n\n    /**\n     * Id to use for the dialog's aria-labelledby.\n     */\n    labelledById: {\n      type: String,\n      default: function () { return getUniqueString(); },\n    },\n\n    /**\n     * Whether the modal should be shown.\n     * Parent component can sync on this value to control the modal's visibility.\n     * @values true, false\n     */\n    show: {\n      type: Boolean,\n      default: false,\n    },\n\n    /**\n     * Title text to display in the modal header.\n     */\n    title: {\n      type: String,\n      default: '',\n    },\n\n    /**\n     * Title text to display in the modal banner.\n     */\n    bannerTitle: {\n      type: String,\n      default: '',\n    },\n\n    /**\n     * The theme of the modal. kind - default or danger,\n     * @values default, danger\n     */\n    kind: {\n      type: String,\n      default: 'default',\n      validator: (k) => Object.keys(MODAL_KIND_MODIFIERS).includes(k),\n    },\n\n    /**\n     * The size of the modal. size - default or full,\n     * @values default, full\n     */\n    size: {\n      type: String,\n      default: 'default',\n      validator: (s) => Object.keys(MODAL_SIZE_MODIFIERS).includes(s),\n    },\n\n    /**\n     * Additional class name for the root modal element.\n     * Can accept String, Object, and Array, i.e. has the\n     * same API as Vue's built-in handling of the class attribute.\n     */\n    modalClass: {\n      type: [String, Object, Array],\n      default: '',\n    },\n\n    /**\n     * Additional class name for the dialog element within the modal.\n     * Can accept String, Object, and Array, i.e. has the\n     * same API as Vue's built-in handling of the class attribute.\n     */\n    dialogClass: {\n      type: [String, Object, Array],\n      default: '',\n    },\n\n    /**\n     * Additional class name for the content element within the modal.\n     * Can accept String, Object, and Array, i.e. has the\n     * same API as Vue's built-in handling of the class attribute.\n     */\n    contentClass: {\n      type: [String, Object, Array],\n      default: '',\n    },\n\n    /**\n     * Sets the color of the banner.\n     * @values base, error, info, success, warning\n     */\n    bannerKind: {\n      type: String,\n      default: 'warning',\n      validate (kind) {\n        return NOTICE_KINDS.includes(kind);\n      },\n    },\n\n    /**\n     * Additional class name for the banner element within the modal.\n     * Can accept String, Object, and Array, i.e. has the\n     * same API as Vue's built-in handling of the class attribute.\n     */\n    bannerClass: {\n      type: [String, Object, Array],\n      default: '',\n    },\n\n    /**\n     * Hides the close button on the modal\n     * @values true, false\n     */\n    hideClose: {\n      type: Boolean,\n      default: false,\n    },\n\n    /**\n     * Whether the modal will close when you click outside of the dialog on the overlay.\n     * @values true, false\n     */\n    closeOnClick: {\n      type: Boolean,\n      default: true,\n    },\n\n    /**\n     * Scrollable modal that allows scroll the modal content keeping the header and footer fixed\n     * @values true, false\n     */\n    fixedHeaderFooter: {\n      type: Boolean,\n      default: true,\n    },\n\n    /**\n     * The element that is focused when the modal is opened. This can be an\n     * HTMLElement within the modal, a string starting with '#' which will\n     * find the element by ID. 'first' which will automatically focus\n     * the first element, or 'dialog' which will focus the dialog window itself.\n     * If the dialog is modal this prop cannot be 'none'.\n     */\n    initialFocusElement: {\n      type: [String, HTMLElement],\n      default: 'first',\n      validator: initialFocusElement => {\n        return initialFocusElement === 'first' ||\n          (initialFocusElement instanceof HTMLElement) ||\n          initialFocusElement.startsWith('#');\n      },\n    },\n\n    /**\n     * A CSS selector string for the element to portal the modal to. If not provided, the modal will be rendered in its default location.\n     */\n    appendTo: {\n      type: String,\n      default: undefined,\n    },\n  },\n\n  emits: [\n    /**\n     * Native button click event\n     *\n     * @event click\n     * @type {PointerEvent | KeyboardEvent}\n     */\n    'click',\n\n    /**\n     * Native keydown event\n     *\n     * @event keydown\n     * @type {KeyboardEvent}\n     */\n    'keydown',\n\n    /**\n     * The modal will emit a \"false\" boolean value for this event when the user performs a modal-closing action.\n     * Parent components can sync on this value to create a 2-way binding to control modal visibility.\n     *\n     * @event update:show\n     * @type {Boolean}\n     */\n    'update:show',\n  ],\n\n  data () {\n    return {\n      MODAL_KIND_MODIFIERS,\n      MODAL_SIZE_MODIFIERS,\n      MODAL_BANNER_KINDS,\n      EVENT_KEYNAMES,\n      hasSlotContent,\n      i18n: new DialtoneLocalization(),\n    };\n  },\n\n  computed: {\n    modalListeners () {\n      return {\n        click: event => {\n          // Handle backdrop clicks for closing modal\n          if (this.closeOnClick && event.target === event.currentTarget) {\n            this.close();\n          } else if (this.show && event.target !== event.currentTarget) {\n            // Ensure focus stays within modal when clicking inside it\n            this.handleModalClick(event);\n          }\n\n          this.$emit('click', event);\n        },\n\n        keydown: event => {\n          switch (event.code) {\n            case EVENT_KEYNAMES.esc:\n            case EVENT_KEYNAMES.escape:\n              this.close();\n              break;\n            case EVENT_KEYNAMES.tab:\n              this.trapFocus(event);\n              break;\n          }\n          this.$emit('keydown', event);\n        },\n\n        'after-enter': async () => {\n          this.$emit('update:show', true);\n          await this.setFocusAfterTransition();\n        },\n\n        focusin: event => {\n          // Ensure focus stays within modal\n          const modalEl = this.$refs.modalRoot?.$el || this.$el;\n          if (this.show && modalEl && !modalEl.contains(event.target)) {\n            event.preventDefault();\n            this.focusFirstElement(modalEl);\n          }\n        },\n      };\n    },\n\n    open () {\n      return `${!this.show}`;\n    },\n\n    hasFooterSlot () {\n      return !!this.$slots.footer;\n    },\n\n    bannerKindClass () {\n      return MODAL_BANNER_KINDS[this.bannerKind];\n    },\n\n    closeButtonTitle () {\n      return this.i18n.$t('DIALTONE_CLOSE_BUTTON');\n    },\n  },\n\n  watch: {\n    show: {\n      handler (isShowing) {\n        if (isShowing) {\n          // Set a reference to the previously-active element, to which we'll return focus on modal close.\n          this.previousActiveElement = document.activeElement;\n          const modalEl = this.$refs.modalRoot?.$el || this.$el;\n          disableRootScrolling(returnFirstEl(modalEl).getRootNode().host);\n        } else {\n          const modalEl = this.$refs.modalRoot?.$el || this.$el;\n          enableRootScrolling(returnFirstEl(modalEl).getRootNode().host);\n          // Modal is being hidden, so return focus to the previously active element before clearing the reference.\n          this.previousActiveElement?.focus();\n          this.previousActiveElement = null;\n        }\n      },\n    },\n  },\n\n  methods: {\n    close () {\n      this.$emit('update:show', false);\n    },\n\n    async setFocusAfterTransition () {\n      const modalEl = this.$refs.modalRoot?.$el || this.$el;\n      if (this.initialFocusElement === 'first') {\n        await this.focusFirstElement(modalEl);\n      } else if (this.initialFocusElement.startsWith('#')) {\n        await this.focusElementById(this.initialFocusElement);\n      } else if (this.initialFocusElement instanceof HTMLElement) {\n        this.initialFocusElement.focus();\n      }\n    },\n\n    trapFocus (e) {\n      if (this.show) {\n        const modalEl = this.$refs.modalRoot?.$el || this.$el;\n        this.focusTrappedTabPress(e, modalEl);\n      }\n    },\n\n    handleModalClick (event) {\n      // Ensure focus stays within modal when clicking inside it\n      const clickedElement = event.target;\n      const modalEl = this.$refs.modalRoot?.$el || this.$el;\n      const focusableElements = this._getFocusableElements(modalEl);\n\n      // If the clicked element is not focusable, ensure focus stays in modal\n      if (focusableElements.length && !focusableElements.includes(clickedElement)) {\n        // Check if current active element is still within the modal\n        if (!focusableElements.includes(document.activeElement)) {\n          this.focusFirstElement(modalEl);\n        }\n      }\n    },\n  },\n};\n</script>\n"],"mappings":"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"}