@dialpad/dialtone-vue 2.200.0-beta.1 → 2.200.0

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,2 +1,2 @@
1
- "use strict";Object.defineProperties(exports,{__esModule:{value:!0},[Symbol.toStringTag]:{value:"Module"}});const n=require("@dialpad/dialtone-icons/vue2"),r=require("../../common/mixins/modal.cjs"),a=require("./modal-constants.cjs"),l=require("../../common/utils/index.cjs"),o=require("../../common/constants/index.cjs"),d=require("../../shared/sr_only_close_button.cjs"),c=require("../../localization/index.cjs"),u=require("../../_plugin-vue2_normalizer-e_CkxkSV.cjs"),_=require("../button/button.cjs"),m=require("../lazy-show/lazy-show.cjs"),h=require("../notice/notice-constants.cjs"),f={name:"DtModal",components:{DtLazyShow:m.default,DtButton:_.default,DtIconClose:n.DtIconClose,SrOnlyCloseButton:d.default},mixins:[r.default],props:{copy:{type:String,default:""},describedById:{type:String,default:""},labelledById:{type:String,default:function(){return l.getUniqueString()}},show:{type:Boolean,default:!1},title:{type:String,default:""},bannerTitle:{type:String,default:""},kind:{type:String,default:"default",validator:e=>Object.keys(a.MODAL_KIND_MODIFIERS).includes(e)},size:{type:String,default:"default",validator:e=>Object.keys(a.MODAL_SIZE_MODIFIERS).includes(e)},modalClass:{type:[String,Object,Array],default:""},dialogClass:{type:[String,Object,Array],default:""},contentClass:{type:[String,Object,Array],default:""},bannerKind:{type:String,default:"warning",validate(e){return h.NOTICE_KINDS.includes(e)}},bannerClass:{type:[String,Object,Array],default:""},hideClose:{type:Boolean,default:!1},closeOnClick:{type:Boolean,default:!0},fixedHeaderFooter:{type:Boolean,default:!0},initialFocusElement:{type:[String,HTMLElement],default:"first",validator:e=>e==="first"||e instanceof HTMLElement||e.startsWith("#")}},emits:["update:show"],data(){return{MODAL_KIND_MODIFIERS:a.MODAL_KIND_MODIFIERS,MODAL_SIZE_MODIFIERS:a.MODAL_SIZE_MODIFIERS,MODAL_BANNER_KINDS:a.MODAL_BANNER_KINDS,EVENT_KEYNAMES:o.EVENT_KEYNAMES,i18n:new c.DialtoneLocalization}},computed:{modalListeners(){return{...this.$listeners,click:e=>{this.closeOnClick&&e.target===e.currentTarget?this.close():this.show&&e.target!==e.currentTarget&&this.handleModalClick(e),this.$emit("click",e)},keydown:e=>{switch(e.code){case o.EVENT_KEYNAMES.esc:case o.EVENT_KEYNAMES.escape:this.close();break;case o.EVENT_KEYNAMES.tab:this.trapFocus(e);break}this.$emit("keydown",e)},"after-enter":async()=>{this.$emit("update:show",!0),await this.setFocusAfterTransition()}}},open(){return`${!this.show}`},hasFooterSlot(){return!!this.$slots.footer},bannerKindClass(){return a.MODAL_BANNER_KINDS[this.bannerKind]},closeButtonTitle(){return this.i18n.$t("DIALTONE_CLOSE_BUTTON")}},watch:{show:{handler(e){var t;e?(this.previousActiveElement=document.activeElement,l.disableRootScrolling(this.$el.getRootNode().host)):(l.enableRootScrolling(this.$el.getRootNode().host),(t=this.previousActiveElement)==null||t.focus(),this.previousActiveElement=null)}}},methods:{close(){this.$emit("update:show",!1)},async setFocusAfterTransition(){this.initialFocusElement==="first"?await this.focusFirstElement():this.initialFocusElement.startsWith("#")?await this.focusElementById(this.initialFocusElement):this.initialFocusElement instanceof HTMLElement&&this.initialFocusElement.focus()},trapFocus(e){this.show&&this.focusTrappedTabPress(e)},handleModalClick(e){const t=e.target,s=this._getFocusableElements();s.length&&!s.includes(t)&&(s.includes(document.activeElement)||this.focusFirstElement())}}};var E=function(){var t=this,s=t._self._c;return s("dt-lazy-show",t._g({class:["d-modal",t.MODAL_KIND_MODIFIERS[t.kind],t.MODAL_SIZE_MODIFIERS[t.size],t.modalClass],attrs:{transition:"d-zoom",show:t.show,"data-qa":"dt-modal","aria-hidden":t.open}},t.modalListeners),[t.show&&(t.$slots.banner||t.bannerTitle)?s("div",{class:["d-modal__banner",t.bannerClass,t.bannerKindClass],attrs:{"data-qa":"dt-modal-banner"}},[t._t("banner",function(){return[t._v(" "+t._s(t.bannerTitle)+" ")]})],2):t._e(),s("transition",{attrs:{appear:"",name:"d-modal__dialog"}},[s("div",{directives:[{name:"show",rawName:"v-show",value:t.show,expression:"show"}],class:["d-modal__dialog",{"d-modal__dialog--scrollable":t.fixedHeaderFooter},t.dialogClass],attrs:{role:"dialog","aria-modal":"true","aria-describedby":t.describedById,"aria-labelledby":t.labelledById}},[t.$slots.header?s("div",{staticClass:"d-modal__header",attrs:{id:t.labelledById,"data-qa":"dt-modal-title"}},[t._t("header")],2):s("h2",{staticClass:"d-modal__header",attrs:{id:t.labelledById,"data-qa":"dt-modal-title"}},[t._v(" "+t._s(t.title)+" ")]),t.$slots.default?s("div",{class:["d-modal__content",t.contentClass],attrs:{"data-qa":"dt-modal-copy"}},[t._t("default")],2):s("p",{class:["d-modal__content",t.contentClass],attrs:{"data-qa":"dt-modal-copy"}},[t._v(" "+t._s(t.copy)+" ")]),t.hasFooterSlot?s("footer",{staticClass:"d-modal__footer"},[t._t("footer")],2):t._e(),t.hideClose?s("sr-only-close-button",{on:{close:t.close}}):s("dt-button",{staticClass:"d-modal__close",attrs:{"data-qa":"dt-modal-close-button",size:"md",kind:"muted",importance:"clear","aria-label":t.closeButtonTitle,title:t.closeButtonTitle},on:{click:t.close},scopedSlots:t._u([{key:"icon",fn:function({iconSize:i}){return[s("dt-icon-close",{attrs:{size:i}})]}}])})],1)])],1)},b=[],y=u.n(f,E,b);const p=y.exports;exports.default=p;
1
+ "use strict";Object.defineProperties(exports,{__esModule:{value:!0},[Symbol.toStringTag]:{value:"Module"}});const r=require("@dialpad/dialtone-icons/vue2"),d=require("../../common/mixins/modal.cjs"),l=require("./modal-constants.cjs"),n=require("../../common/utils/index.cjs"),i=require("../../common/constants/index.cjs"),c=require("../../shared/sr_only_close_button.cjs"),u=require("../../localization/index.cjs"),_=require("../../node_modules/@linusborg/vue-simple-portal.cjs"),m=require("../../_plugin-vue2_normalizer-e_CkxkSV.cjs"),h=require("../button/button.cjs"),f=require("../lazy-show/lazy-show.cjs"),E=require("../notice/notice-constants.cjs"),p={name:"DtModal",components:{DtLazyShow:f.default,DtButton:h.default,DtIconClose:r.DtIconClose,SrOnlyCloseButton:c.default,Portal:_.Portal},mixins:[d.default],props:{copy:{type:String,default:""},describedById:{type:String,default:""},labelledById:{type:String,default:function(){return n.getUniqueString()}},show:{type:Boolean,default:!1},title:{type:String,default:""},bannerTitle:{type:String,default:""},kind:{type:String,default:"default",validator:e=>Object.keys(l.MODAL_KIND_MODIFIERS).includes(e)},size:{type:String,default:"default",validator:e=>Object.keys(l.MODAL_SIZE_MODIFIERS).includes(e)},modalClass:{type:[String,Object,Array],default:""},dialogClass:{type:[String,Object,Array],default:""},contentClass:{type:[String,Object,Array],default:""},bannerKind:{type:String,default:"warning",validate(e){return E.NOTICE_KINDS.includes(e)}},bannerClass:{type:[String,Object,Array],default:""},hideClose:{type:Boolean,default:!1},closeOnClick:{type:Boolean,default:!0},fixedHeaderFooter:{type:Boolean,default:!0},initialFocusElement:{type:[String,HTMLElement],default:"first",validator:e=>e==="first"||e instanceof HTMLElement||e.startsWith("#")},appendTo:{type:String,default:void 0}},emits:["update:show"],data(){return{MODAL_KIND_MODIFIERS:l.MODAL_KIND_MODIFIERS,MODAL_SIZE_MODIFIERS:l.MODAL_SIZE_MODIFIERS,MODAL_BANNER_KINDS:l.MODAL_BANNER_KINDS,EVENT_KEYNAMES:i.EVENT_KEYNAMES,i18n:new u.DialtoneLocalization}},computed:{modalListeners(){return{...this.$listeners,click:e=>{this.closeOnClick&&e.target===e.currentTarget?this.close():this.show&&e.target!==e.currentTarget&&this.handleModalClick(e),this.$emit("click",e)},keydown:e=>{switch(e.code){case i.EVENT_KEYNAMES.esc:case i.EVENT_KEYNAMES.escape:this.close();break;case i.EVENT_KEYNAMES.tab:this.trapFocus(e);break}this.$emit("keydown",e)},"after-enter":async()=>{this.$emit("update:show",!0),await this.setFocusAfterTransition()}}},open(){return`${!this.show}`},hasFooterSlot(){return!!this.$slots.footer},bannerKindClass(){return l.MODAL_BANNER_KINDS[this.bannerKind]},closeButtonTitle(){return this.i18n.$t("DIALTONE_CLOSE_BUTTON")}},watch:{show:{handler(e){var t,s,a;if(e){this.previousActiveElement=document.activeElement;const o=((t=this.$refs.modalRoot)==null?void 0:t.$el)||this.$el;n.disableRootScrolling(o.getRootNode().host)}else{const o=((s=this.$refs.modalRoot)==null?void 0:s.$el)||this.$el;n.enableRootScrolling(o.getRootNode().host),(a=this.previousActiveElement)==null||a.focus(),this.previousActiveElement=null}}}},methods:{close(){this.$emit("update:show",!1)},async setFocusAfterTransition(){var t;const e=((t=this.$refs.modalRoot)==null?void 0:t.$el)||this.$el;this.initialFocusElement==="first"?await this.focusFirstElement(e):this.initialFocusElement.startsWith("#")?await this.focusElementById(this.initialFocusElement):this.initialFocusElement instanceof HTMLElement&&this.initialFocusElement.focus()},trapFocus(e){var t;if(this.show){const s=((t=this.$refs.modalRoot)==null?void 0:t.$el)||this.$el;this.focusTrappedTabPress(e,s)}},handleModalClick(e){var o;const t=e.target,s=((o=this.$refs.modalRoot)==null?void 0:o.$el)||this.$el,a=this._getFocusableElements(s);a.length&&!a.includes(t)&&(a.includes(document.activeElement)||this.focusFirstElement(s))}}};var b=function(){var t=this,s=t._self._c;return s("portal",{attrs:{disabled:!t.appendTo,selector:t.appendTo}},[s("dt-lazy-show",t._g({ref:"modalRoot",class:["d-modal",t.MODAL_KIND_MODIFIERS[t.kind],t.MODAL_SIZE_MODIFIERS[t.size],t.modalClass],attrs:{transition:"d-zoom",show:t.show,"data-qa":"dt-modal","aria-hidden":t.open}},t.modalListeners),[t.show&&(t.$slots.banner||t.bannerTitle)?s("div",{class:["d-modal__banner",t.bannerClass,t.bannerKindClass],attrs:{"data-qa":"dt-modal-banner"}},[t._t("banner",function(){return[t._v(" "+t._s(t.bannerTitle)+" ")]})],2):t._e(),s("transition",{attrs:{appear:"",name:"d-modal__dialog"}},[s("div",{directives:[{name:"show",rawName:"v-show",value:t.show,expression:"show"}],class:["d-modal__dialog",{"d-modal__dialog--scrollable":t.fixedHeaderFooter},t.dialogClass],attrs:{role:"dialog","aria-modal":"true","aria-describedby":t.describedById,"aria-labelledby":t.labelledById}},[t.$slots.header?s("div",{staticClass:"d-modal__header",attrs:{id:t.labelledById,"data-qa":"dt-modal-title"}},[t._t("header")],2):s("h2",{staticClass:"d-modal__header",attrs:{id:t.labelledById,"data-qa":"dt-modal-title"}},[t._v(" "+t._s(t.title)+" ")]),t.$slots.default?s("div",{class:["d-modal__content",t.contentClass],attrs:{"data-qa":"dt-modal-copy"}},[t._t("default")],2):s("p",{class:["d-modal__content",t.contentClass],attrs:{"data-qa":"dt-modal-copy"}},[t._v(" "+t._s(t.copy)+" ")]),t.hasFooterSlot?s("footer",{staticClass:"d-modal__footer"},[t._t("footer")],2):t._e(),t.hideClose?s("sr-only-close-button",{on:{close:t.close}}):s("dt-button",{staticClass:"d-modal__close",attrs:{"data-qa":"dt-modal-close-button",size:"md",kind:"muted",importance:"clear","aria-label":t.closeButtonTitle,title:t.closeButtonTitle},on:{click:t.close},scopedSlots:t._u([{key:"icon",fn:function({iconSize:a}){return[s("dt-icon-close",{attrs:{size:a}})]}}])})],1)])],1)],1)},y=[],S=m.n(p,b,y);const g=S.exports;exports.default=g;
2
2
  //# sourceMappingURL=modal.cjs.map
@@ -1 +1 @@
1
- {"version":3,"file":"modal.cjs","sources":["../../../components/modal/modal.vue"],"sourcesContent":["<template>\n <dt-lazy-show\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 && ($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=\"$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=\"$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</template>\n\n<script>\n/* eslint-disable max-lines */\nimport { DtButton } from '@/components/button';\nimport { DtIconClose } from '@dialpad/dialtone-icons/vue2';\nimport Modal from '@/common/mixins/modal';\nimport {\n MODAL_BANNER_KINDS,\n MODAL_KIND_MODIFIERS,\n MODAL_SIZE_MODIFIERS,\n} from './modal_constants';\nimport { getUniqueString, 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 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 emits: [\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 i18n: new DialtoneLocalization(),\n };\n },\n\n computed: {\n modalListeners () {\n return {\n ...this.$listeners,\n\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 },\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 disableRootScrolling(this.$el.getRootNode().host);\n } else {\n enableRootScrolling(this.$el.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 if (this.initialFocusElement === 'first') {\n await this.focusFirstElement();\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 this.focusTrappedTabPress(e);\n }\n },\n\n handleModalClick (event) {\n // Ensure focus stays within modal when clicking inside it\n const clickedElement = event.target;\n const focusableElements = this._getFocusableElements();\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();\n }\n }\n },\n },\n};\n</script>\n"],"names":["_sfc_main","DtLazyShow","DtButton","DtIconClose","SrOnlyCloseButton","Modal","getUniqueString","k","MODAL_KIND_MODIFIERS","s","MODAL_SIZE_MODIFIERS","kind","NOTICE_KINDS","initialFocusElement","MODAL_BANNER_KINDS","EVENT_KEYNAMES","DialtoneLocalization","event","isShowing","disableRootScrolling","enableRootScrolling","_a","clickedElement","focusableElements"],"mappings":"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"}
1
+ {"version":3,"file":"modal.cjs","sources":["../../../components/modal/modal.vue"],"sourcesContent":["<template>\n <portal\n :disabled=\"!appendTo\"\n :selector=\"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 && ($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=\"$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=\"$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 </portal>\n</template>\n\n<script>\n/* eslint-disable max-lines */\nimport { DtButton } from '@/components/button';\nimport { DtIconClose } from '@dialpad/dialtone-icons/vue2';\nimport Modal from '@/common/mixins/modal';\nimport {\n MODAL_BANNER_KINDS,\n MODAL_KIND_MODIFIERS,\n MODAL_SIZE_MODIFIERS,\n} from './modal_constants';\nimport { getUniqueString, 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';\nimport { Portal } from '@linusborg/vue-simple-portal';\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 name: 'DtModal',\n\n components: {\n DtLazyShow,\n DtButton,\n DtIconClose,\n SrOnlyCloseButton,\n Portal,\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 * 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 i18n: new DialtoneLocalization(),\n };\n },\n\n computed: {\n modalListeners () {\n return {\n ...this.$listeners,\n\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 },\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(modalEl.getRootNode().host);\n } else {\n const modalEl = this.$refs.modalRoot?.$el || this.$el;\n enableRootScrolling(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"],"names":["_sfc_main","DtLazyShow","DtButton","DtIconClose","SrOnlyCloseButton","Portal","Modal","getUniqueString","k","MODAL_KIND_MODIFIERS","s","MODAL_SIZE_MODIFIERS","kind","NOTICE_KINDS","initialFocusElement","MODAL_BANNER_KINDS","EVENT_KEYNAMES","DialtoneLocalization","event","isShowing","modalEl","_a","disableRootScrolling","_b","enableRootScrolling","_c","clickedElement","focusableElements"],"mappings":"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"}
@@ -1,23 +1,25 @@
1
- import { DtIconClose as r } from "@dialpad/dialtone-icons/vue2";
2
- import d from "../../common/mixins/modal.js";
3
- import { MODAL_BANNER_KINDS as o, MODAL_SIZE_MODIFIERS as l, MODAL_KIND_MODIFIERS as i } from "./modal-constants.js";
4
- import { disableRootScrolling as c, enableRootScrolling as m, getUniqueString as u } from "../../common/utils/index.js";
5
- import { EVENT_KEYNAMES as s } from "../../common/constants/index.js";
6
- import f from "../../shared/sr_only_close_button.js";
7
- import { DialtoneLocalization as h } from "../../localization/index.js";
8
- import { n as _ } from "../../_plugin-vue2_normalizer-DSLOjnn3.js";
9
- import p from "../button/button.js";
10
- import y from "../lazy-show/lazy-show.js";
11
- import { NOTICE_KINDS as b } from "../notice/notice-constants.js";
12
- const g = {
1
+ import { DtIconClose as d } from "@dialpad/dialtone-icons/vue2";
2
+ import c from "../../common/mixins/modal.js";
3
+ import { MODAL_BANNER_KINDS as i, MODAL_SIZE_MODIFIERS as n, MODAL_KIND_MODIFIERS as r } from "./modal-constants.js";
4
+ import { disableRootScrolling as m, enableRootScrolling as u, getUniqueString as f } from "../../common/utils/index.js";
5
+ import { EVENT_KEYNAMES as l } from "../../common/constants/index.js";
6
+ import h from "../../shared/sr_only_close_button.js";
7
+ import { DialtoneLocalization as p } from "../../localization/index.js";
8
+ import { Portal as _ } from "../../node_modules/@linusborg/vue-simple-portal.js";
9
+ import { n as y } from "../../_plugin-vue2_normalizer-DSLOjnn3.js";
10
+ import b from "../button/button.js";
11
+ import E from "../lazy-show/lazy-show.js";
12
+ import { NOTICE_KINDS as g } from "../notice/notice-constants.js";
13
+ const S = {
13
14
  name: "DtModal",
14
15
  components: {
15
- DtLazyShow: y,
16
- DtButton: p,
17
- DtIconClose: r,
18
- SrOnlyCloseButton: f
16
+ DtLazyShow: E,
17
+ DtButton: b,
18
+ DtIconClose: d,
19
+ SrOnlyCloseButton: h,
20
+ Portal: _
19
21
  },
20
- mixins: [d],
22
+ mixins: [c],
21
23
  props: {
22
24
  /**
23
25
  * Body text to display as the modal's main content.
@@ -41,7 +43,7 @@ const g = {
41
43
  labelledById: {
42
44
  type: String,
43
45
  default: function() {
44
- return u();
46
+ return f();
45
47
  }
46
48
  },
47
49
  /**
@@ -74,7 +76,7 @@ const g = {
74
76
  kind: {
75
77
  type: String,
76
78
  default: "default",
77
- validator: (e) => Object.keys(i).includes(e)
79
+ validator: (e) => Object.keys(r).includes(e)
78
80
  },
79
81
  /**
80
82
  * The size of the modal. size - default or full,
@@ -83,7 +85,7 @@ const g = {
83
85
  size: {
84
86
  type: String,
85
87
  default: "default",
86
- validator: (e) => Object.keys(l).includes(e)
88
+ validator: (e) => Object.keys(n).includes(e)
87
89
  },
88
90
  /**
89
91
  * Additional class name for the root modal element.
@@ -120,7 +122,7 @@ const g = {
120
122
  type: String,
121
123
  default: "warning",
122
124
  validate(e) {
123
- return b.includes(e);
125
+ return g.includes(e);
124
126
  }
125
127
  },
126
128
  /**
@@ -167,6 +169,13 @@ const g = {
167
169
  type: [String, HTMLElement],
168
170
  default: "first",
169
171
  validator: (e) => e === "first" || e instanceof HTMLElement || e.startsWith("#")
172
+ },
173
+ /**
174
+ * A CSS selector string for the element to portal the modal to. If not provided, the modal will be rendered in its default location.
175
+ */
176
+ appendTo: {
177
+ type: String,
178
+ default: void 0
170
179
  }
171
180
  },
172
181
  emits: [
@@ -181,11 +190,11 @@ const g = {
181
190
  ],
182
191
  data() {
183
192
  return {
184
- MODAL_KIND_MODIFIERS: i,
185
- MODAL_SIZE_MODIFIERS: l,
186
- MODAL_BANNER_KINDS: o,
187
- EVENT_KEYNAMES: s,
188
- i18n: new h()
193
+ MODAL_KIND_MODIFIERS: r,
194
+ MODAL_SIZE_MODIFIERS: n,
195
+ MODAL_BANNER_KINDS: i,
196
+ EVENT_KEYNAMES: l,
197
+ i18n: new p()
189
198
  };
190
199
  },
191
200
  computed: {
@@ -197,11 +206,11 @@ const g = {
197
206
  },
198
207
  keydown: (e) => {
199
208
  switch (e.code) {
200
- case s.esc:
201
- case s.escape:
209
+ case l.esc:
210
+ case l.escape:
202
211
  this.close();
203
212
  break;
204
- case s.tab:
213
+ case l.tab:
205
214
  this.trapFocus(e);
206
215
  break;
207
216
  }
@@ -219,7 +228,7 @@ const g = {
219
228
  return !!this.$slots.footer;
220
229
  },
221
230
  bannerKindClass() {
222
- return o[this.bannerKind];
231
+ return i[this.bannerKind];
223
232
  },
224
233
  closeButtonTitle() {
225
234
  return this.i18n.$t("DIALTONE_CLOSE_BUTTON");
@@ -228,8 +237,15 @@ const g = {
228
237
  watch: {
229
238
  show: {
230
239
  handler(e) {
231
- var t;
232
- e ? (this.previousActiveElement = document.activeElement, c(this.$el.getRootNode().host)) : (m(this.$el.getRootNode().host), (t = this.previousActiveElement) == null || t.focus(), this.previousActiveElement = null);
240
+ var t, a, o;
241
+ if (e) {
242
+ this.previousActiveElement = document.activeElement;
243
+ const s = ((t = this.$refs.modalRoot) == null ? void 0 : t.$el) || this.$el;
244
+ m(s.getRootNode().host);
245
+ } else {
246
+ const s = ((a = this.$refs.modalRoot) == null ? void 0 : a.$el) || this.$el;
247
+ u(s.getRootNode().host), (o = this.previousActiveElement) == null || o.focus(), this.previousActiveElement = null;
248
+ }
233
249
  }
234
250
  }
235
251
  },
@@ -238,20 +254,27 @@ const g = {
238
254
  this.$emit("update:show", !1);
239
255
  },
240
256
  async setFocusAfterTransition() {
241
- this.initialFocusElement === "first" ? await this.focusFirstElement() : this.initialFocusElement.startsWith("#") ? await this.focusElementById(this.initialFocusElement) : this.initialFocusElement instanceof HTMLElement && this.initialFocusElement.focus();
257
+ var t;
258
+ const e = ((t = this.$refs.modalRoot) == null ? void 0 : t.$el) || this.$el;
259
+ this.initialFocusElement === "first" ? await this.focusFirstElement(e) : this.initialFocusElement.startsWith("#") ? await this.focusElementById(this.initialFocusElement) : this.initialFocusElement instanceof HTMLElement && this.initialFocusElement.focus();
242
260
  },
243
261
  trapFocus(e) {
244
- this.show && this.focusTrappedTabPress(e);
262
+ var t;
263
+ if (this.show) {
264
+ const a = ((t = this.$refs.modalRoot) == null ? void 0 : t.$el) || this.$el;
265
+ this.focusTrappedTabPress(e, a);
266
+ }
245
267
  },
246
268
  handleModalClick(e) {
247
- const t = e.target, a = this._getFocusableElements();
248
- a.length && !a.includes(t) && (a.includes(document.activeElement) || this.focusFirstElement());
269
+ var s;
270
+ const t = e.target, a = ((s = this.$refs.modalRoot) == null ? void 0 : s.$el) || this.$el, o = this._getFocusableElements(a);
271
+ o.length && !o.includes(t) && (o.includes(document.activeElement) || this.focusFirstElement(a));
249
272
  }
250
273
  }
251
274
  };
252
- var E = function() {
275
+ var w = function() {
253
276
  var t = this, a = t._self._c;
254
- return a("dt-lazy-show", t._g({ class: [
277
+ return a("portal", { attrs: { disabled: !t.appendTo, selector: t.appendTo } }, [a("dt-lazy-show", t._g({ ref: "modalRoot", class: [
255
278
  "d-modal",
256
279
  t.MODAL_KIND_MODIFIERS[t.kind],
257
280
  t.MODAL_SIZE_MODIFIERS[t.size],
@@ -272,16 +295,16 @@ var E = function() {
272
295
  ], attrs: { "data-qa": "dt-modal-copy" } }, [t._t("default")], 2) : a("p", { class: [
273
296
  "d-modal__content",
274
297
  t.contentClass
275
- ], attrs: { "data-qa": "dt-modal-copy" } }, [t._v(" " + t._s(t.copy) + " ")]), t.hasFooterSlot ? a("footer", { staticClass: "d-modal__footer" }, [t._t("footer")], 2) : t._e(), t.hideClose ? a("sr-only-close-button", { on: { close: t.close } }) : a("dt-button", { staticClass: "d-modal__close", attrs: { "data-qa": "dt-modal-close-button", size: "md", kind: "muted", importance: "clear", "aria-label": t.closeButtonTitle, title: t.closeButtonTitle }, on: { click: t.close }, scopedSlots: t._u([{ key: "icon", fn: function({ iconSize: n }) {
276
- return [a("dt-icon-close", { attrs: { size: n } })];
277
- } }]) })], 1)])], 1);
278
- }, S = [], w = /* @__PURE__ */ _(
279
- g,
280
- E,
281
- S
298
+ ], attrs: { "data-qa": "dt-modal-copy" } }, [t._v(" " + t._s(t.copy) + " ")]), t.hasFooterSlot ? a("footer", { staticClass: "d-modal__footer" }, [t._t("footer")], 2) : t._e(), t.hideClose ? a("sr-only-close-button", { on: { close: t.close } }) : a("dt-button", { staticClass: "d-modal__close", attrs: { "data-qa": "dt-modal-close-button", size: "md", kind: "muted", importance: "clear", "aria-label": t.closeButtonTitle, title: t.closeButtonTitle }, on: { click: t.close }, scopedSlots: t._u([{ key: "icon", fn: function({ iconSize: o }) {
299
+ return [a("dt-icon-close", { attrs: { size: o } })];
300
+ } }]) })], 1)])], 1)], 1);
301
+ }, C = [], $ = /* @__PURE__ */ y(
302
+ S,
303
+ w,
304
+ C
282
305
  );
283
- const L = w.exports;
306
+ const N = $.exports;
284
307
  export {
285
- L as default
308
+ N as default
286
309
  };
287
310
  //# sourceMappingURL=modal.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"modal.js","sources":["../../../components/modal/modal.vue"],"sourcesContent":["<template>\n <dt-lazy-show\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 && ($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=\"$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=\"$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</template>\n\n<script>\n/* eslint-disable max-lines */\nimport { DtButton } from '@/components/button';\nimport { DtIconClose } from '@dialpad/dialtone-icons/vue2';\nimport Modal from '@/common/mixins/modal';\nimport {\n MODAL_BANNER_KINDS,\n MODAL_KIND_MODIFIERS,\n MODAL_SIZE_MODIFIERS,\n} from './modal_constants';\nimport { getUniqueString, 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 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 emits: [\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 i18n: new DialtoneLocalization(),\n };\n },\n\n computed: {\n modalListeners () {\n return {\n ...this.$listeners,\n\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 },\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 disableRootScrolling(this.$el.getRootNode().host);\n } else {\n enableRootScrolling(this.$el.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 if (this.initialFocusElement === 'first') {\n await this.focusFirstElement();\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 this.focusTrappedTabPress(e);\n }\n },\n\n handleModalClick (event) {\n // Ensure focus stays within modal when clicking inside it\n const clickedElement = event.target;\n const focusableElements = this._getFocusableElements();\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();\n }\n }\n },\n },\n};\n</script>\n"],"names":["_sfc_main","DtLazyShow","DtButton","DtIconClose","SrOnlyCloseButton","Modal","getUniqueString","k","MODAL_KIND_MODIFIERS","s","MODAL_SIZE_MODIFIERS","kind","NOTICE_KINDS","initialFocusElement","MODAL_BANNER_KINDS","EVENT_KEYNAMES","DialtoneLocalization","event","isShowing","disableRootScrolling","enableRootScrolling","_a","clickedElement","focusableElements"],"mappings":"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"}
1
+ {"version":3,"file":"modal.js","sources":["../../../components/modal/modal.vue"],"sourcesContent":["<template>\n <portal\n :disabled=\"!appendTo\"\n :selector=\"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 && ($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=\"$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=\"$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 </portal>\n</template>\n\n<script>\n/* eslint-disable max-lines */\nimport { DtButton } from '@/components/button';\nimport { DtIconClose } from '@dialpad/dialtone-icons/vue2';\nimport Modal from '@/common/mixins/modal';\nimport {\n MODAL_BANNER_KINDS,\n MODAL_KIND_MODIFIERS,\n MODAL_SIZE_MODIFIERS,\n} from './modal_constants';\nimport { getUniqueString, 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';\nimport { Portal } from '@linusborg/vue-simple-portal';\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 name: 'DtModal',\n\n components: {\n DtLazyShow,\n DtButton,\n DtIconClose,\n SrOnlyCloseButton,\n Portal,\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 * 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 i18n: new DialtoneLocalization(),\n };\n },\n\n computed: {\n modalListeners () {\n return {\n ...this.$listeners,\n\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 },\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(modalEl.getRootNode().host);\n } else {\n const modalEl = this.$refs.modalRoot?.$el || this.$el;\n enableRootScrolling(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"],"names":["_sfc_main","DtLazyShow","DtButton","DtIconClose","SrOnlyCloseButton","Portal","Modal","getUniqueString","k","MODAL_KIND_MODIFIERS","s","MODAL_SIZE_MODIFIERS","kind","NOTICE_KINDS","initialFocusElement","MODAL_BANNER_KINDS","EVENT_KEYNAMES","DialtoneLocalization","event","isShowing","modalEl","_a","disableRootScrolling","_b","enableRootScrolling","_c","clickedElement","focusableElements"],"mappings":"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"}
@@ -1,2 +1,2 @@
1
- "use strict";Object.defineProperty(exports,Symbol.toStringTag,{value:"Module"});const a=require("@dialpad/i18n-vue2"),s=require("./en-US.cjs"),u=require("./zh-CN.cjs"),d=require("./nl-NL.cjs"),f=require("./fr-FR.cjs"),g=require("./de-DE.cjs"),S=require("./it-IT.cjs"),N=require("./ja-JP.cjs"),w=require("./pt-BR.cjs"),L=require("./ru-RU.cjs"),R=require("./es-LA.cjs"),e="dialtone",o={ENGLISH:"en-US",CHINESE:"zh-CN",DUTCH:"nl-NL",FRENCH:"fr-FR",GERMAN:"de-DE",ITALIAN:"it-IT",JAPANESE:"ja-JP",PORTUGUESE:"pt-BR",RUSSIAN:"ru-RU",SPANISH:"es-LA"},n="en-US";class l{constructor(t=null){if(typeof l.instance=="object")return l.instance;this._locale=t||l.getPreferredLocale();const r=new a.RawBundleSource({resources:a.RawBundleSource.builtResources([["en-US",e,s.default],["zh-CN",e,u.default],["nl-NL",e,d.default],["fr-FR",e,f.default],["de-DE",e,g.default],["it-IT",e,S.default],["ja-JP",e,N.default],["pt-BR",e,w.default],["ru-RU",e,L.default],["es-LA",e,R.default]])});return new a.LocaleManager({bundleSource:r,allowedLocales:Object.values(o),fallbackLocale:n,preferredLocale:this._locale,namespaces:[e]}).install(e),l.instance=this,typeof window<"u"&&(window.onstorage=i=>{i.key==="user-locale"&&(this.currentLocale=i.newValue)}),this}static getPreferredLocale(){if(typeof window>"u"||!window.localStorage)return n;const t=window.localStorage.getItem("user-locale"),r=Object.values(o).find(c=>c.startsWith(navigator.language.slice(0,2)));return t||r||n}static getAllowedLocales(){return o}$t(...t){return a.useI18N(e).$t(...t)}$ta(...t){return a.useI18N(e).$ta(...t)}get currentLocale(){return this._locale}set currentLocale(t){if(t!==this._locale){if(!Object.values(o).includes(t))throw new Error(`Locale ${t} is not allowed, please use one of the following: ${Object.values(o).join(", ")}`);this._locale=t,a.useI18N(e).setI18N({preferredLocale:t},e)}}}exports.DialtoneLocalization=l;
1
+ "use strict";Object.defineProperty(exports,Symbol.toStringTag,{value:"Module"});const a=require("@dialpad/i18n-vue2"),u=require("./en-US.cjs"),d=require("./zh-CN.cjs"),f=require("./nl-NL.cjs"),g=require("./fr-FR.cjs"),S=require("./de-DE.cjs"),N=require("./it-IT.cjs"),w=require("./ja-JP.cjs"),L=require("./pt-BR.cjs"),R=require("./ru-RU.cjs"),h=require("./es-LA.cjs"),e="dialtone",o={ENGLISH:"en-US",CHINESE:"zh-CN",DUTCH:"nl-NL",FRENCH:"fr-FR",GERMAN:"de-DE",ITALIAN:"it-IT",JAPANESE:"ja-JP",PORTUGUESE:"pt-BR",RUSSIAN:"ru-RU",SPANISH:"es-LA"},n="en-US",s="user-locale";class l{constructor(t=null){if(typeof l.instance=="object")return l.instance;this._locale=t||l.getPreferredLocale();const r=new a.RawBundleSource({resources:a.RawBundleSource.builtResources([["en-US",e,u.default],["zh-CN",e,d.default],["nl-NL",e,f.default],["fr-FR",e,g.default],["de-DE",e,S.default],["it-IT",e,N.default],["ja-JP",e,w.default],["pt-BR",e,L.default],["ru-RU",e,R.default],["es-LA",e,h.default]])});return new a.LocaleManager({bundleSource:r,allowedLocales:Object.values(o),fallbackLocale:n,preferredLocale:this._locale,namespaces:[e]}).install(e),l.instance=this,typeof window<"u"&&(window.onstorage=i=>{i.key===s&&(this.currentLocale=i.newValue)}),this}static getPreferredLocale(){if(typeof window>"u"||!window.localStorage)return n;const t=window.localStorage.getItem(s),r=Object.values(o).find(c=>c.startsWith(navigator.language.slice(0,2)));return t||r||n}static getAllowedLocales(){return o}$t(...t){return a.useI18N(e).$t(...t)}$ta(...t){return a.useI18N(e).$ta(...t)}get currentLocale(){return this._locale}set currentLocale(t){if(t!==this._locale){if(!Object.values(o).includes(t))throw new Error(`Locale ${t} is not allowed, please use one of the following: ${Object.values(o).join(", ")}`);this._locale=t,a.useI18N(e).setI18N({preferredLocale:t},e)}}}exports.DialtoneLocalization=l;
2
2
  //# sourceMappingURL=index.cjs.map
@@ -1 +1 @@
1
- {"version":3,"file":"index.cjs","sources":["../../localization/index.js"],"sourcesContent":["import { LocaleManager, RawBundleSource, useI18N } from '@dialpad/i18n-vue2';\n\nimport enUS from './en-US.ftl?raw';\nimport zhCN from './zh-CN.ftl?raw';\nimport nlNL from './nl-NL.ftl?raw';\nimport frFR from './fr-FR.ftl?raw';\nimport deDE from './de-DE.ftl?raw';\nimport itIT from './it-IT.ftl?raw';\nimport jaJP from './ja-JP.ftl?raw';\nimport ptBR from './pt-BR.ftl?raw';\nimport ruRU from './ru-RU.ftl?raw';\nimport esLA from './es-LA.ftl?raw';\n\nconst dialtoneNamespace = 'dialtone';\nconst allowedLocales = {\n ENGLISH: 'en-US',\n CHINESE: 'zh-CN',\n DUTCH: 'nl-NL',\n FRENCH: 'fr-FR',\n GERMAN: 'de-DE',\n ITALIAN: 'it-IT',\n JAPANESE: 'ja-JP',\n PORTUGUESE: 'pt-BR',\n RUSSIAN: 'ru-RU',\n SPANISH: 'es-LA',\n};\nconst fallbackLocale = 'en-US';\n\nexport class DialtoneLocalization {\n constructor (locale = null) {\n if (typeof DialtoneLocalization.instance === 'object') {\n return DialtoneLocalization.instance;\n }\n\n this._locale = locale || DialtoneLocalization.getPreferredLocale();\n\n const bundleSource = new RawBundleSource({\n resources: RawBundleSource.builtResources([\n ['en-US', dialtoneNamespace, enUS],\n ['zh-CN', dialtoneNamespace, zhCN],\n ['nl-NL', dialtoneNamespace, nlNL],\n ['fr-FR', dialtoneNamespace, frFR],\n ['de-DE', dialtoneNamespace, deDE],\n ['it-IT', dialtoneNamespace, itIT],\n ['ja-JP', dialtoneNamespace, jaJP],\n ['pt-BR', dialtoneNamespace, ptBR],\n ['ru-RU', dialtoneNamespace, ruRU],\n ['es-LA', dialtoneNamespace, esLA],\n ]),\n });\n\n const localeManager = new LocaleManager({\n bundleSource,\n allowedLocales: Object.values(allowedLocales),\n fallbackLocale,\n preferredLocale: this._locale,\n namespaces: [dialtoneNamespace],\n });\n\n localeManager.install(dialtoneNamespace);\n\n DialtoneLocalization.instance = this;\n\n if (typeof window !== 'undefined') {\n /**\n * @description\n * When the browser storage changes, update the current locale\n * @param event\n */\n window.onstorage = (event) => {\n if (event.key === 'user-locale') {\n this.currentLocale = event.newValue;\n }\n };\n }\n\n return this;\n }\n\n static getPreferredLocale () {\n if (typeof window === 'undefined' || !window.localStorage) {\n return fallbackLocale;\n }\n\n const localStorageLanguage = window.localStorage.getItem('user-locale');\n\n // Get the first two letters of the navigator language and check if it's in the allowed locales\n const navigatorLanguage = Object.values(allowedLocales)\n .find(locale => locale.startsWith(navigator.language.slice(0, 2)));\n\n return localStorageLanguage || navigatorLanguage || fallbackLocale;\n }\n\n static getAllowedLocales () {\n return allowedLocales;\n }\n\n $t (...args) {\n return useI18N(dialtoneNamespace).$t(...args);\n }\n\n $ta (...args) {\n return useI18N(dialtoneNamespace).$ta(...args);\n }\n\n get currentLocale () {\n return this._locale;\n }\n\n set currentLocale (newLocale) {\n if (newLocale === this._locale) return;\n if (!Object.values(allowedLocales).includes(newLocale)) {\n throw new Error(`Locale ${newLocale} is not allowed, please use one of the following: ${Object.values(allowedLocales).join(', ')}`);\n }\n\n this._locale = newLocale;\n useI18N(dialtoneNamespace).setI18N({ preferredLocale: newLocale }, dialtoneNamespace);\n }\n}\n"],"names":["dialtoneNamespace","allowedLocales","fallbackLocale","DialtoneLocalization","locale","bundleSource","RawBundleSource","enUS","zhCN","nlNL","frFR","deDE","itIT","jaJP","ptBR","ruRU","esLA","LocaleManager","event","localStorageLanguage","navigatorLanguage","args","useI18N","newLocale"],"mappings":"gXAaMA,EAAoB,WACpBC,EAAiB,CACrB,QAAS,QACT,QAAS,QACT,MAAO,QACP,OAAQ,QACR,OAAQ,QACR,QAAS,QACT,SAAU,QACV,WAAY,QACZ,QAAS,QACT,QAAS,OACX,EACMC,EAAiB,QAEhB,MAAMC,CAAqB,CAChC,YAAaC,EAAS,KAAM,CAC1B,GAAI,OAAOD,EAAqB,UAAa,SAC3C,OAAOA,EAAqB,SAG9B,KAAK,QAAUC,GAAUD,EAAqB,mBAAkB,EAEhE,MAAME,EAAe,IAAIC,kBAAgB,CACvC,UAAWA,EAAAA,gBAAgB,eAAe,CACxC,CAAC,QAASN,EAAmBO,SAAI,EACjC,CAAC,QAASP,EAAmBQ,SAAI,EACjC,CAAC,QAASR,EAAmBS,SAAI,EACjC,CAAC,QAAST,EAAmBU,SAAI,EACjC,CAAC,QAASV,EAAmBW,SAAI,EACjC,CAAC,QAASX,EAAmBY,SAAI,EACjC,CAAC,QAASZ,EAAmBa,SAAI,EACjC,CAAC,QAASb,EAAmBc,SAAI,EACjC,CAAC,QAASd,EAAmBe,SAAI,EACjC,CAAC,QAASf,EAAmBgB,SAAI,CACzC,CAAO,CACP,CAAK,EAUD,OARsB,IAAIC,gBAAc,CACtC,aAAAZ,EACA,eAAgB,OAAO,OAAOJ,CAAc,EAC5C,eAAAC,EACA,gBAAiB,KAAK,QACtB,WAAY,CAACF,CAAiB,CACpC,CAAK,EAEa,QAAQA,CAAiB,EAEvCG,EAAqB,SAAW,KAE5B,OAAO,OAAW,MAMpB,OAAO,UAAae,GAAU,CACxBA,EAAM,MAAQ,gBAChB,KAAK,cAAgBA,EAAM,SAE/B,GAGK,IACT,CAEA,OAAO,oBAAsB,CAC3B,GAAI,OAAO,OAAW,KAAe,CAAC,OAAO,aAC3C,OAAOhB,EAGT,MAAMiB,EAAuB,OAAO,aAAa,QAAQ,aAAa,EAGhEC,EAAoB,OAAO,OAAOnB,CAAc,EACnD,KAAKG,GAAUA,EAAO,WAAW,UAAU,SAAS,MAAM,EAAG,CAAC,CAAC,CAAC,EAEnE,OAAOe,GAAwBC,GAAqBlB,CACtD,CAEA,OAAO,mBAAqB,CAC1B,OAAOD,CACT,CAEA,MAAOoB,EAAM,CACX,OAAOC,EAAAA,QAAQtB,CAAiB,EAAE,GAAG,GAAGqB,CAAI,CAC9C,CAEA,OAAQA,EAAM,CACZ,OAAOC,EAAAA,QAAQtB,CAAiB,EAAE,IAAI,GAAGqB,CAAI,CAC/C,CAEA,IAAI,eAAiB,CACnB,OAAO,KAAK,OACd,CAEA,IAAI,cAAeE,EAAW,CAC5B,GAAIA,IAAc,KAAK,QACvB,IAAI,CAAC,OAAO,OAAOtB,CAAc,EAAE,SAASsB,CAAS,EACnD,MAAM,IAAI,MAAM,UAAUA,CAAS,qDAAqD,OAAO,OAAOtB,CAAc,EAAE,KAAK,IAAI,CAAC,EAAE,EAGpI,KAAK,QAAUsB,EACfD,EAAAA,QAAQtB,CAAiB,EAAE,QAAQ,CAAE,gBAAiBuB,CAAS,EAAIvB,CAAiB,EACtF,CACF"}
1
+ {"version":3,"file":"index.cjs","sources":["../../localization/index.js"],"sourcesContent":["import { LocaleManager, RawBundleSource, useI18N } from '@dialpad/i18n-vue2';\n\nimport enUS from './en-US.ftl?raw';\nimport zhCN from './zh-CN.ftl?raw';\nimport nlNL from './nl-NL.ftl?raw';\nimport frFR from './fr-FR.ftl?raw';\nimport deDE from './de-DE.ftl?raw';\nimport itIT from './it-IT.ftl?raw';\nimport jaJP from './ja-JP.ftl?raw';\nimport ptBR from './pt-BR.ftl?raw';\nimport ruRU from './ru-RU.ftl?raw';\nimport esLA from './es-LA.ftl?raw';\n\nconst dialtoneNamespace = 'dialtone';\nconst allowedLocales = {\n ENGLISH: 'en-US',\n CHINESE: 'zh-CN',\n DUTCH: 'nl-NL',\n FRENCH: 'fr-FR',\n GERMAN: 'de-DE',\n ITALIAN: 'it-IT',\n JAPANESE: 'ja-JP',\n PORTUGUESE: 'pt-BR',\n RUSSIAN: 'ru-RU',\n SPANISH: 'es-LA',\n};\nconst fallbackLocale = 'en-US';\n/**\n * Default key name used by the LocaleManager to store the user's preferred locale in localStorage\n */\nconst localeManagerStorageKey = 'user-locale';\n\n/**\n * Dialtone localization class, follows the singleton pattern to make sure only one instance of the class is created.\n * Initializes the localeManager and looks for changes on the browser storage to update the current locale.\n * https://github.com/dialpad/goblin-client-tools/tree/main/packages/i18n#i18n-vue-3-compatible\n */\nexport class DialtoneLocalization {\n constructor (locale = null) {\n if (typeof DialtoneLocalization.instance === 'object') {\n return DialtoneLocalization.instance;\n }\n\n this._locale = locale || DialtoneLocalization.getPreferredLocale();\n\n const bundleSource = new RawBundleSource({\n resources: RawBundleSource.builtResources([\n ['en-US', dialtoneNamespace, enUS],\n ['zh-CN', dialtoneNamespace, zhCN],\n ['nl-NL', dialtoneNamespace, nlNL],\n ['fr-FR', dialtoneNamespace, frFR],\n ['de-DE', dialtoneNamespace, deDE],\n ['it-IT', dialtoneNamespace, itIT],\n ['ja-JP', dialtoneNamespace, jaJP],\n ['pt-BR', dialtoneNamespace, ptBR],\n ['ru-RU', dialtoneNamespace, ruRU],\n ['es-LA', dialtoneNamespace, esLA],\n ]),\n });\n\n const localeManager = new LocaleManager({\n bundleSource,\n allowedLocales: Object.values(allowedLocales),\n fallbackLocale,\n preferredLocale: this._locale,\n namespaces: [dialtoneNamespace],\n });\n\n localeManager.install(dialtoneNamespace);\n\n DialtoneLocalization.instance = this;\n\n if (typeof window !== 'undefined') {\n /**\n * @description\n * When the browser storage changes, update the current locale\n * @param event\n */\n window.onstorage = (event) => {\n if (event.key === localeManagerStorageKey) {\n this.currentLocale = event.newValue;\n }\n };\n }\n\n return this;\n }\n\n /**\n * Gets the preferred locale from user's locale stored in localStorage or the browser language\n * @returns { string }\n */\n static getPreferredLocale () {\n /**\n * Early return if we're not in the browser or if localStorage is not available\n */\n if (typeof window === 'undefined' || !window.localStorage) {\n return fallbackLocale;\n }\n\n const localStorageLanguage = window.localStorage.getItem(localeManagerStorageKey);\n\n // Get the first two letters of the navigator language and check if it's in the allowed locales\n const navigatorLanguage = Object.values(allowedLocales)\n .find(locale => locale.startsWith(navigator.language.slice(0, 2)));\n\n return localStorageLanguage || navigatorLanguage || fallbackLocale;\n }\n\n static getAllowedLocales () {\n return allowedLocales;\n }\n\n /**\n * Passthrough function to the i18n $t function including the dialtone namespace\n * Returns a translated string based on a key and optional variables.\n * It’s used for simple text translations.\n * https://github.com/dialpad/goblin-client-tools/tree/main/packages/i18n#t\n */\n $t (...args) {\n return useI18N(dialtoneNamespace).$t(...args);\n }\n\n /**\n * Passthrough function to the i18n $ta function including the dialtone namespace\n * Returns an object containing translated attributes to pass directly as props to components, it can contain\n * aria-label, title, etc, rather than just a plain text. It’s useful for handling element attributes in the UI.\n * https://github.com/dialpad/goblin-client-tools/tree/main/packages/i18n#ta\n */\n $ta (...args) {\n return useI18N(dialtoneNamespace).$ta(...args);\n }\n\n get currentLocale () {\n return this._locale;\n }\n\n set currentLocale (newLocale) {\n if (newLocale === this._locale) return;\n if (!Object.values(allowedLocales).includes(newLocale)) {\n throw new Error(`Locale ${newLocale} is not allowed, please use one of the following: ${Object.values(allowedLocales).join(', ')}`);\n }\n\n this._locale = newLocale;\n useI18N(dialtoneNamespace).setI18N({ preferredLocale: newLocale }, dialtoneNamespace);\n }\n}\n"],"names":["dialtoneNamespace","allowedLocales","fallbackLocale","localeManagerStorageKey","DialtoneLocalization","locale","bundleSource","RawBundleSource","enUS","zhCN","nlNL","frFR","deDE","itIT","jaJP","ptBR","ruRU","esLA","LocaleManager","event","localStorageLanguage","navigatorLanguage","args","useI18N","newLocale"],"mappings":"gXAaMA,EAAoB,WACpBC,EAAiB,CACrB,QAAS,QACT,QAAS,QACT,MAAO,QACP,OAAQ,QACR,OAAQ,QACR,QAAS,QACT,SAAU,QACV,WAAY,QACZ,QAAS,QACT,QAAS,OACX,EACMC,EAAiB,QAIjBC,EAA0B,cAOzB,MAAMC,CAAqB,CAChC,YAAaC,EAAS,KAAM,CAC1B,GAAI,OAAOD,EAAqB,UAAa,SAC3C,OAAOA,EAAqB,SAG9B,KAAK,QAAUC,GAAUD,EAAqB,mBAAkB,EAEhE,MAAME,EAAe,IAAIC,kBAAgB,CACvC,UAAWA,EAAAA,gBAAgB,eAAe,CACxC,CAAC,QAASP,EAAmBQ,SAAI,EACjC,CAAC,QAASR,EAAmBS,SAAI,EACjC,CAAC,QAAST,EAAmBU,SAAI,EACjC,CAAC,QAASV,EAAmBW,SAAI,EACjC,CAAC,QAASX,EAAmBY,SAAI,EACjC,CAAC,QAASZ,EAAmBa,SAAI,EACjC,CAAC,QAASb,EAAmBc,SAAI,EACjC,CAAC,QAASd,EAAmBe,SAAI,EACjC,CAAC,QAASf,EAAmBgB,SAAI,EACjC,CAAC,QAAShB,EAAmBiB,SAAI,CACzC,CAAO,CACP,CAAK,EAUD,OARsB,IAAIC,gBAAc,CACtC,aAAAZ,EACA,eAAgB,OAAO,OAAOL,CAAc,EAC5C,eAAAC,EACA,gBAAiB,KAAK,QACtB,WAAY,CAACF,CAAiB,CACpC,CAAK,EAEa,QAAQA,CAAiB,EAEvCI,EAAqB,SAAW,KAE5B,OAAO,OAAW,MAMpB,OAAO,UAAae,GAAU,CACxBA,EAAM,MAAQhB,IAChB,KAAK,cAAgBgB,EAAM,SAE/B,GAGK,IACT,CAMA,OAAO,oBAAsB,CAI3B,GAAI,OAAO,OAAW,KAAe,CAAC,OAAO,aAC3C,OAAOjB,EAGT,MAAMkB,EAAuB,OAAO,aAAa,QAAQjB,CAAuB,EAG1EkB,EAAoB,OAAO,OAAOpB,CAAc,EACnD,KAAKI,GAAUA,EAAO,WAAW,UAAU,SAAS,MAAM,EAAG,CAAC,CAAC,CAAC,EAEnE,OAAOe,GAAwBC,GAAqBnB,CACtD,CAEA,OAAO,mBAAqB,CAC1B,OAAOD,CACT,CAQA,MAAOqB,EAAM,CACX,OAAOC,EAAAA,QAAQvB,CAAiB,EAAE,GAAG,GAAGsB,CAAI,CAC9C,CAQA,OAAQA,EAAM,CACZ,OAAOC,EAAAA,QAAQvB,CAAiB,EAAE,IAAI,GAAGsB,CAAI,CAC/C,CAEA,IAAI,eAAiB,CACnB,OAAO,KAAK,OACd,CAEA,IAAI,cAAeE,EAAW,CAC5B,GAAIA,IAAc,KAAK,QACvB,IAAI,CAAC,OAAO,OAAOvB,CAAc,EAAE,SAASuB,CAAS,EACnD,MAAM,IAAI,MAAM,UAAUA,CAAS,qDAAqD,OAAO,OAAOvB,CAAc,EAAE,KAAK,IAAI,CAAC,EAAE,EAGpI,KAAK,QAAUuB,EACfD,EAAAA,QAAQvB,CAAiB,EAAE,QAAQ,CAAE,gBAAiBwB,CAAS,EAAIxB,CAAiB,EACtF,CACF"}
@@ -1,14 +1,14 @@
1
- import { RawBundleSource as i, LocaleManager as u, useI18N as l } from "@dialpad/i18n-vue2";
2
- import f from "./en-US.js";
3
- import d from "./zh-CN.js";
4
- import m from "./nl-NL.js";
1
+ import { RawBundleSource as i, LocaleManager as f, useI18N as l } from "@dialpad/i18n-vue2";
2
+ import d from "./en-US.js";
3
+ import m from "./zh-CN.js";
4
+ import g from "./nl-NL.js";
5
5
  import p from "./fr-FR.js";
6
- import g from "./de-DE.js";
6
+ import S from "./de-DE.js";
7
7
  import w from "./it-IT.js";
8
8
  import N from "./ja-JP.js";
9
- import S from "./pt-BR.js";
10
- import L from "./ru-RU.js";
11
- import R from "./es-LA.js";
9
+ import L from "./pt-BR.js";
10
+ import R from "./ru-RU.js";
11
+ import h from "./es-LA.js";
12
12
  const e = "dialtone", t = {
13
13
  ENGLISH: "en-US",
14
14
  CHINESE: "zh-CN",
@@ -20,7 +20,7 @@ const e = "dialtone", t = {
20
20
  PORTUGUESE: "pt-BR",
21
21
  RUSSIAN: "ru-RU",
22
22
  SPANISH: "es-LA"
23
- }, n = "en-US";
23
+ }, n = "en-US", u = "user-locale";
24
24
  class o {
25
25
  constructor(r = null) {
26
26
  if (typeof o.instance == "object")
@@ -28,40 +28,56 @@ class o {
28
28
  this._locale = r || o.getPreferredLocale();
29
29
  const a = new i({
30
30
  resources: i.builtResources([
31
- ["en-US", e, f],
32
- ["zh-CN", e, d],
33
- ["nl-NL", e, m],
31
+ ["en-US", e, d],
32
+ ["zh-CN", e, m],
33
+ ["nl-NL", e, g],
34
34
  ["fr-FR", e, p],
35
- ["de-DE", e, g],
35
+ ["de-DE", e, S],
36
36
  ["it-IT", e, w],
37
37
  ["ja-JP", e, N],
38
- ["pt-BR", e, S],
39
- ["ru-RU", e, L],
40
- ["es-LA", e, R]
38
+ ["pt-BR", e, L],
39
+ ["ru-RU", e, R],
40
+ ["es-LA", e, h]
41
41
  ])
42
42
  });
43
- return new u({
43
+ return new f({
44
44
  bundleSource: a,
45
45
  allowedLocales: Object.values(t),
46
46
  fallbackLocale: n,
47
47
  preferredLocale: this._locale,
48
48
  namespaces: [e]
49
49
  }).install(e), o.instance = this, typeof window < "u" && (window.onstorage = (c) => {
50
- c.key === "user-locale" && (this.currentLocale = c.newValue);
50
+ c.key === u && (this.currentLocale = c.newValue);
51
51
  }), this;
52
52
  }
53
+ /**
54
+ * Gets the preferred locale from user's locale stored in localStorage or the browser language
55
+ * @returns { string }
56
+ */
53
57
  static getPreferredLocale() {
54
58
  if (typeof window > "u" || !window.localStorage)
55
59
  return n;
56
- const r = window.localStorage.getItem("user-locale"), a = Object.values(t).find((s) => s.startsWith(navigator.language.slice(0, 2)));
60
+ const r = window.localStorage.getItem(u), a = Object.values(t).find((s) => s.startsWith(navigator.language.slice(0, 2)));
57
61
  return r || a || n;
58
62
  }
59
63
  static getAllowedLocales() {
60
64
  return t;
61
65
  }
66
+ /**
67
+ * Passthrough function to the i18n $t function including the dialtone namespace
68
+ * Returns a translated string based on a key and optional variables.
69
+ * It’s used for simple text translations.
70
+ * https://github.com/dialpad/goblin-client-tools/tree/main/packages/i18n#t
71
+ */
62
72
  $t(...r) {
63
73
  return l(e).$t(...r);
64
74
  }
75
+ /**
76
+ * Passthrough function to the i18n $ta function including the dialtone namespace
77
+ * Returns an object containing translated attributes to pass directly as props to components, it can contain
78
+ * aria-label, title, etc, rather than just a plain text. It’s useful for handling element attributes in the UI.
79
+ * https://github.com/dialpad/goblin-client-tools/tree/main/packages/i18n#ta
80
+ */
65
81
  $ta(...r) {
66
82
  return l(e).$ta(...r);
67
83
  }
@@ -1 +1 @@
1
- {"version":3,"file":"index.js","sources":["../../localization/index.js"],"sourcesContent":["import { LocaleManager, RawBundleSource, useI18N } from '@dialpad/i18n-vue2';\n\nimport enUS from './en-US.ftl?raw';\nimport zhCN from './zh-CN.ftl?raw';\nimport nlNL from './nl-NL.ftl?raw';\nimport frFR from './fr-FR.ftl?raw';\nimport deDE from './de-DE.ftl?raw';\nimport itIT from './it-IT.ftl?raw';\nimport jaJP from './ja-JP.ftl?raw';\nimport ptBR from './pt-BR.ftl?raw';\nimport ruRU from './ru-RU.ftl?raw';\nimport esLA from './es-LA.ftl?raw';\n\nconst dialtoneNamespace = 'dialtone';\nconst allowedLocales = {\n ENGLISH: 'en-US',\n CHINESE: 'zh-CN',\n DUTCH: 'nl-NL',\n FRENCH: 'fr-FR',\n GERMAN: 'de-DE',\n ITALIAN: 'it-IT',\n JAPANESE: 'ja-JP',\n PORTUGUESE: 'pt-BR',\n RUSSIAN: 'ru-RU',\n SPANISH: 'es-LA',\n};\nconst fallbackLocale = 'en-US';\n\nexport class DialtoneLocalization {\n constructor (locale = null) {\n if (typeof DialtoneLocalization.instance === 'object') {\n return DialtoneLocalization.instance;\n }\n\n this._locale = locale || DialtoneLocalization.getPreferredLocale();\n\n const bundleSource = new RawBundleSource({\n resources: RawBundleSource.builtResources([\n ['en-US', dialtoneNamespace, enUS],\n ['zh-CN', dialtoneNamespace, zhCN],\n ['nl-NL', dialtoneNamespace, nlNL],\n ['fr-FR', dialtoneNamespace, frFR],\n ['de-DE', dialtoneNamespace, deDE],\n ['it-IT', dialtoneNamespace, itIT],\n ['ja-JP', dialtoneNamespace, jaJP],\n ['pt-BR', dialtoneNamespace, ptBR],\n ['ru-RU', dialtoneNamespace, ruRU],\n ['es-LA', dialtoneNamespace, esLA],\n ]),\n });\n\n const localeManager = new LocaleManager({\n bundleSource,\n allowedLocales: Object.values(allowedLocales),\n fallbackLocale,\n preferredLocale: this._locale,\n namespaces: [dialtoneNamespace],\n });\n\n localeManager.install(dialtoneNamespace);\n\n DialtoneLocalization.instance = this;\n\n if (typeof window !== 'undefined') {\n /**\n * @description\n * When the browser storage changes, update the current locale\n * @param event\n */\n window.onstorage = (event) => {\n if (event.key === 'user-locale') {\n this.currentLocale = event.newValue;\n }\n };\n }\n\n return this;\n }\n\n static getPreferredLocale () {\n if (typeof window === 'undefined' || !window.localStorage) {\n return fallbackLocale;\n }\n\n const localStorageLanguage = window.localStorage.getItem('user-locale');\n\n // Get the first two letters of the navigator language and check if it's in the allowed locales\n const navigatorLanguage = Object.values(allowedLocales)\n .find(locale => locale.startsWith(navigator.language.slice(0, 2)));\n\n return localStorageLanguage || navigatorLanguage || fallbackLocale;\n }\n\n static getAllowedLocales () {\n return allowedLocales;\n }\n\n $t (...args) {\n return useI18N(dialtoneNamespace).$t(...args);\n }\n\n $ta (...args) {\n return useI18N(dialtoneNamespace).$ta(...args);\n }\n\n get currentLocale () {\n return this._locale;\n }\n\n set currentLocale (newLocale) {\n if (newLocale === this._locale) return;\n if (!Object.values(allowedLocales).includes(newLocale)) {\n throw new Error(`Locale ${newLocale} is not allowed, please use one of the following: ${Object.values(allowedLocales).join(', ')}`);\n }\n\n this._locale = newLocale;\n useI18N(dialtoneNamespace).setI18N({ preferredLocale: newLocale }, dialtoneNamespace);\n }\n}\n"],"names":["dialtoneNamespace","allowedLocales","fallbackLocale","DialtoneLocalization","locale","bundleSource","RawBundleSource","enUS","zhCN","nlNL","frFR","deDE","itIT","jaJP","ptBR","ruRU","esLA","LocaleManager","event","localStorageLanguage","navigatorLanguage","args","useI18N","newLocale"],"mappings":";;;;;;;;;;;AAaA,MAAMA,IAAoB,YACpBC,IAAiB;AAAA,EACrB,SAAS;AAAA,EACT,SAAS;AAAA,EACT,OAAO;AAAA,EACP,QAAQ;AAAA,EACR,QAAQ;AAAA,EACR,SAAS;AAAA,EACT,UAAU;AAAA,EACV,YAAY;AAAA,EACZ,SAAS;AAAA,EACT,SAAS;AACX,GACMC,IAAiB;AAEhB,MAAMC,EAAqB;AAAA,EAChC,YAAaC,IAAS,MAAM;AAC1B,QAAI,OAAOD,EAAqB,YAAa;AAC3C,aAAOA,EAAqB;AAG9B,SAAK,UAAUC,KAAUD,EAAqB,mBAAkB;AAEhE,UAAME,IAAe,IAAIC,EAAgB;AAAA,MACvC,WAAWA,EAAgB,eAAe;AAAA,QACxC,CAAC,SAASN,GAAmBO,CAAI;AAAA,QACjC,CAAC,SAASP,GAAmBQ,CAAI;AAAA,QACjC,CAAC,SAASR,GAAmBS,CAAI;AAAA,QACjC,CAAC,SAAST,GAAmBU,CAAI;AAAA,QACjC,CAAC,SAASV,GAAmBW,CAAI;AAAA,QACjC,CAAC,SAASX,GAAmBY,CAAI;AAAA,QACjC,CAAC,SAASZ,GAAmBa,CAAI;AAAA,QACjC,CAAC,SAASb,GAAmBc,CAAI;AAAA,QACjC,CAAC,SAASd,GAAmBe,CAAI;AAAA,QACjC,CAAC,SAASf,GAAmBgB,CAAI;AAAA,MACzC,CAAO;AAAA,IACP,CAAK;AAUD,WARsB,IAAIC,EAAc;AAAA,MACtC,cAAAZ;AAAA,MACA,gBAAgB,OAAO,OAAOJ,CAAc;AAAA,MAC5C,gBAAAC;AAAA,MACA,iBAAiB,KAAK;AAAA,MACtB,YAAY,CAACF,CAAiB;AAAA,IACpC,CAAK,EAEa,QAAQA,CAAiB,GAEvCG,EAAqB,WAAW,MAE5B,OAAO,SAAW,QAMpB,OAAO,YAAY,CAACe,MAAU;AAC5B,MAAIA,EAAM,QAAQ,kBAChB,KAAK,gBAAgBA,EAAM;AAAA,IAE/B,IAGK;AAAA,EACT;AAAA,EAEA,OAAO,qBAAsB;AAC3B,QAAI,OAAO,SAAW,OAAe,CAAC,OAAO;AAC3C,aAAOhB;AAGT,UAAMiB,IAAuB,OAAO,aAAa,QAAQ,aAAa,GAGhEC,IAAoB,OAAO,OAAOnB,CAAc,EACnD,KAAK,CAAAG,MAAUA,EAAO,WAAW,UAAU,SAAS,MAAM,GAAG,CAAC,CAAC,CAAC;AAEnE,WAAOe,KAAwBC,KAAqBlB;AAAA,EACtD;AAAA,EAEA,OAAO,oBAAqB;AAC1B,WAAOD;AAAA,EACT;AAAA,EAEA,MAAOoB,GAAM;AACX,WAAOC,EAAQtB,CAAiB,EAAE,GAAG,GAAGqB,CAAI;AAAA,EAC9C;AAAA,EAEA,OAAQA,GAAM;AACZ,WAAOC,EAAQtB,CAAiB,EAAE,IAAI,GAAGqB,CAAI;AAAA,EAC/C;AAAA,EAEA,IAAI,gBAAiB;AACnB,WAAO,KAAK;AAAA,EACd;AAAA,EAEA,IAAI,cAAeE,GAAW;AAC5B,QAAIA,MAAc,KAAK,SACvB;AAAA,UAAI,CAAC,OAAO,OAAOtB,CAAc,EAAE,SAASsB,CAAS;AACnD,cAAM,IAAI,MAAM,UAAUA,CAAS,qDAAqD,OAAO,OAAOtB,CAAc,EAAE,KAAK,IAAI,CAAC,EAAE;AAGpI,WAAK,UAAUsB,GACfD,EAAQtB,CAAiB,EAAE,QAAQ,EAAE,iBAAiBuB,EAAS,GAAIvB,CAAiB;AAAA;AAAA,EACtF;AACF;"}
1
+ {"version":3,"file":"index.js","sources":["../../localization/index.js"],"sourcesContent":["import { LocaleManager, RawBundleSource, useI18N } from '@dialpad/i18n-vue2';\n\nimport enUS from './en-US.ftl?raw';\nimport zhCN from './zh-CN.ftl?raw';\nimport nlNL from './nl-NL.ftl?raw';\nimport frFR from './fr-FR.ftl?raw';\nimport deDE from './de-DE.ftl?raw';\nimport itIT from './it-IT.ftl?raw';\nimport jaJP from './ja-JP.ftl?raw';\nimport ptBR from './pt-BR.ftl?raw';\nimport ruRU from './ru-RU.ftl?raw';\nimport esLA from './es-LA.ftl?raw';\n\nconst dialtoneNamespace = 'dialtone';\nconst allowedLocales = {\n ENGLISH: 'en-US',\n CHINESE: 'zh-CN',\n DUTCH: 'nl-NL',\n FRENCH: 'fr-FR',\n GERMAN: 'de-DE',\n ITALIAN: 'it-IT',\n JAPANESE: 'ja-JP',\n PORTUGUESE: 'pt-BR',\n RUSSIAN: 'ru-RU',\n SPANISH: 'es-LA',\n};\nconst fallbackLocale = 'en-US';\n/**\n * Default key name used by the LocaleManager to store the user's preferred locale in localStorage\n */\nconst localeManagerStorageKey = 'user-locale';\n\n/**\n * Dialtone localization class, follows the singleton pattern to make sure only one instance of the class is created.\n * Initializes the localeManager and looks for changes on the browser storage to update the current locale.\n * https://github.com/dialpad/goblin-client-tools/tree/main/packages/i18n#i18n-vue-3-compatible\n */\nexport class DialtoneLocalization {\n constructor (locale = null) {\n if (typeof DialtoneLocalization.instance === 'object') {\n return DialtoneLocalization.instance;\n }\n\n this._locale = locale || DialtoneLocalization.getPreferredLocale();\n\n const bundleSource = new RawBundleSource({\n resources: RawBundleSource.builtResources([\n ['en-US', dialtoneNamespace, enUS],\n ['zh-CN', dialtoneNamespace, zhCN],\n ['nl-NL', dialtoneNamespace, nlNL],\n ['fr-FR', dialtoneNamespace, frFR],\n ['de-DE', dialtoneNamespace, deDE],\n ['it-IT', dialtoneNamespace, itIT],\n ['ja-JP', dialtoneNamespace, jaJP],\n ['pt-BR', dialtoneNamespace, ptBR],\n ['ru-RU', dialtoneNamespace, ruRU],\n ['es-LA', dialtoneNamespace, esLA],\n ]),\n });\n\n const localeManager = new LocaleManager({\n bundleSource,\n allowedLocales: Object.values(allowedLocales),\n fallbackLocale,\n preferredLocale: this._locale,\n namespaces: [dialtoneNamespace],\n });\n\n localeManager.install(dialtoneNamespace);\n\n DialtoneLocalization.instance = this;\n\n if (typeof window !== 'undefined') {\n /**\n * @description\n * When the browser storage changes, update the current locale\n * @param event\n */\n window.onstorage = (event) => {\n if (event.key === localeManagerStorageKey) {\n this.currentLocale = event.newValue;\n }\n };\n }\n\n return this;\n }\n\n /**\n * Gets the preferred locale from user's locale stored in localStorage or the browser language\n * @returns { string }\n */\n static getPreferredLocale () {\n /**\n * Early return if we're not in the browser or if localStorage is not available\n */\n if (typeof window === 'undefined' || !window.localStorage) {\n return fallbackLocale;\n }\n\n const localStorageLanguage = window.localStorage.getItem(localeManagerStorageKey);\n\n // Get the first two letters of the navigator language and check if it's in the allowed locales\n const navigatorLanguage = Object.values(allowedLocales)\n .find(locale => locale.startsWith(navigator.language.slice(0, 2)));\n\n return localStorageLanguage || navigatorLanguage || fallbackLocale;\n }\n\n static getAllowedLocales () {\n return allowedLocales;\n }\n\n /**\n * Passthrough function to the i18n $t function including the dialtone namespace\n * Returns a translated string based on a key and optional variables.\n * It’s used for simple text translations.\n * https://github.com/dialpad/goblin-client-tools/tree/main/packages/i18n#t\n */\n $t (...args) {\n return useI18N(dialtoneNamespace).$t(...args);\n }\n\n /**\n * Passthrough function to the i18n $ta function including the dialtone namespace\n * Returns an object containing translated attributes to pass directly as props to components, it can contain\n * aria-label, title, etc, rather than just a plain text. It’s useful for handling element attributes in the UI.\n * https://github.com/dialpad/goblin-client-tools/tree/main/packages/i18n#ta\n */\n $ta (...args) {\n return useI18N(dialtoneNamespace).$ta(...args);\n }\n\n get currentLocale () {\n return this._locale;\n }\n\n set currentLocale (newLocale) {\n if (newLocale === this._locale) return;\n if (!Object.values(allowedLocales).includes(newLocale)) {\n throw new Error(`Locale ${newLocale} is not allowed, please use one of the following: ${Object.values(allowedLocales).join(', ')}`);\n }\n\n this._locale = newLocale;\n useI18N(dialtoneNamespace).setI18N({ preferredLocale: newLocale }, dialtoneNamespace);\n }\n}\n"],"names":["dialtoneNamespace","allowedLocales","fallbackLocale","localeManagerStorageKey","DialtoneLocalization","locale","bundleSource","RawBundleSource","enUS","zhCN","nlNL","frFR","deDE","itIT","jaJP","ptBR","ruRU","esLA","LocaleManager","event","localStorageLanguage","navigatorLanguage","args","useI18N","newLocale"],"mappings":";;;;;;;;;;;AAaA,MAAMA,IAAoB,YACpBC,IAAiB;AAAA,EACrB,SAAS;AAAA,EACT,SAAS;AAAA,EACT,OAAO;AAAA,EACP,QAAQ;AAAA,EACR,QAAQ;AAAA,EACR,SAAS;AAAA,EACT,UAAU;AAAA,EACV,YAAY;AAAA,EACZ,SAAS;AAAA,EACT,SAAS;AACX,GACMC,IAAiB,SAIjBC,IAA0B;AAOzB,MAAMC,EAAqB;AAAA,EAChC,YAAaC,IAAS,MAAM;AAC1B,QAAI,OAAOD,EAAqB,YAAa;AAC3C,aAAOA,EAAqB;AAG9B,SAAK,UAAUC,KAAUD,EAAqB,mBAAkB;AAEhE,UAAME,IAAe,IAAIC,EAAgB;AAAA,MACvC,WAAWA,EAAgB,eAAe;AAAA,QACxC,CAAC,SAASP,GAAmBQ,CAAI;AAAA,QACjC,CAAC,SAASR,GAAmBS,CAAI;AAAA,QACjC,CAAC,SAAST,GAAmBU,CAAI;AAAA,QACjC,CAAC,SAASV,GAAmBW,CAAI;AAAA,QACjC,CAAC,SAASX,GAAmBY,CAAI;AAAA,QACjC,CAAC,SAASZ,GAAmBa,CAAI;AAAA,QACjC,CAAC,SAASb,GAAmBc,CAAI;AAAA,QACjC,CAAC,SAASd,GAAmBe,CAAI;AAAA,QACjC,CAAC,SAASf,GAAmBgB,CAAI;AAAA,QACjC,CAAC,SAAShB,GAAmBiB,CAAI;AAAA,MACzC,CAAO;AAAA,IACP,CAAK;AAUD,WARsB,IAAIC,EAAc;AAAA,MACtC,cAAAZ;AAAA,MACA,gBAAgB,OAAO,OAAOL,CAAc;AAAA,MAC5C,gBAAAC;AAAA,MACA,iBAAiB,KAAK;AAAA,MACtB,YAAY,CAACF,CAAiB;AAAA,IACpC,CAAK,EAEa,QAAQA,CAAiB,GAEvCI,EAAqB,WAAW,MAE5B,OAAO,SAAW,QAMpB,OAAO,YAAY,CAACe,MAAU;AAC5B,MAAIA,EAAM,QAAQhB,MAChB,KAAK,gBAAgBgB,EAAM;AAAA,IAE/B,IAGK;AAAA,EACT;AAAA;AAAA;AAAA;AAAA;AAAA,EAMA,OAAO,qBAAsB;AAI3B,QAAI,OAAO,SAAW,OAAe,CAAC,OAAO;AAC3C,aAAOjB;AAGT,UAAMkB,IAAuB,OAAO,aAAa,QAAQjB,CAAuB,GAG1EkB,IAAoB,OAAO,OAAOpB,CAAc,EACnD,KAAK,CAAAI,MAAUA,EAAO,WAAW,UAAU,SAAS,MAAM,GAAG,CAAC,CAAC,CAAC;AAEnE,WAAOe,KAAwBC,KAAqBnB;AAAA,EACtD;AAAA,EAEA,OAAO,oBAAqB;AAC1B,WAAOD;AAAA,EACT;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAQA,MAAOqB,GAAM;AACX,WAAOC,EAAQvB,CAAiB,EAAE,GAAG,GAAGsB,CAAI;AAAA,EAC9C;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAQA,OAAQA,GAAM;AACZ,WAAOC,EAAQvB,CAAiB,EAAE,IAAI,GAAGsB,CAAI;AAAA,EAC/C;AAAA,EAEA,IAAI,gBAAiB;AACnB,WAAO,KAAK;AAAA,EACd;AAAA,EAEA,IAAI,cAAeE,GAAW;AAC5B,QAAIA,MAAc,KAAK,SACvB;AAAA,UAAI,CAAC,OAAO,OAAOvB,CAAc,EAAE,SAASuB,CAAS;AACnD,cAAM,IAAI,MAAM,UAAUA,CAAS,qDAAqD,OAAO,OAAOvB,CAAc,EAAE,KAAK,IAAI,CAAC,EAAE;AAGpI,WAAK,UAAUuB,GACfD,EAAQvB,CAAiB,EAAE,QAAQ,EAAE,iBAAiBwB,EAAS,GAAIxB,CAAiB;AAAA;AAAA,EACtF;AACF;"}