@dialpad/dialtone 9.81.1 → 9.83.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.
- package/dist/css/dialtone-default-theme.css +32 -0
- package/dist/css/dialtone-default-theme.min.css +1 -1
- package/dist/css/dialtone.css +32 -0
- package/dist/css/dialtone.min.css +1 -1
- package/dist/tokens/doc.json +8553 -8553
- package/dist/vue2/common/emoji.cjs +0 -6
- package/dist/vue2/common/emoji.cjs.map +1 -1
- package/dist/vue2/common/emoji.js +0 -6
- package/dist/vue2/common/emoji.js.map +1 -1
- package/dist/vue2/component-documentation.json +1 -1
- package/dist/vue2/components/emoji_picker/modules/emoji_selector.vue.cjs +7 -8
- package/dist/vue2/components/emoji_picker/modules/emoji_selector.vue.cjs.map +1 -1
- package/dist/vue2/components/emoji_picker/modules/emoji_selector.vue.js +7 -8
- package/dist/vue2/components/emoji_picker/modules/emoji_selector.vue.js.map +1 -1
- package/dist/vue2/components/emoji_text_wrapper/emoji_text_wrapper.vue.cjs +4 -3
- package/dist/vue2/components/emoji_text_wrapper/emoji_text_wrapper.vue.cjs.map +1 -1
- package/dist/vue2/components/emoji_text_wrapper/emoji_text_wrapper.vue.js +5 -4
- package/dist/vue2/components/emoji_text_wrapper/emoji_text_wrapper.vue.js.map +1 -1
- package/dist/vue2/components/input/input.vue.cjs +1 -1
- package/dist/vue2/components/input/input.vue.cjs.map +1 -1
- package/dist/vue2/components/input/input.vue.js +1 -1
- package/dist/vue2/components/input/input.vue.js.map +1 -1
- package/dist/vue2/components/input/input_constants.cjs +2 -1
- package/dist/vue2/components/input/input_constants.cjs.map +1 -1
- package/dist/vue2/components/input/input_constants.js +2 -1
- package/dist/vue2/components/input/input_constants.js.map +1 -1
- package/dist/vue2/dialtone-vue.cjs +0 -1
- package/dist/vue2/dialtone-vue.cjs.map +1 -1
- package/dist/vue2/dialtone-vue.js +1 -2
- package/dist/vue2/types/common/emoji/index.d.ts +0 -1
- package/dist/vue2/types/common/emoji/index.d.ts.map +1 -1
- package/dist/vue2/types/components/emoji_picker/modules/emoji_selector.vue.d.ts +1 -0
- package/dist/vue2/types/components/emoji_text_wrapper/emoji_text_wrapper.vue.d.ts.map +1 -1
- package/dist/vue2/types/components/input/input_constants.d.ts +1 -0
- package/dist/vue3/common/emoji.cjs +0 -6
- package/dist/vue3/common/emoji.cjs.map +1 -1
- package/dist/vue3/common/emoji.js +0 -6
- package/dist/vue3/common/emoji.js.map +1 -1
- package/dist/vue3/component-documentation.json +1 -1
- package/dist/vue3/components/emoji_picker/modules/emoji_selector.vue.cjs +6 -6
- package/dist/vue3/components/emoji_picker/modules/emoji_selector.vue.cjs.map +1 -1
- package/dist/vue3/components/emoji_picker/modules/emoji_selector.vue.js +6 -6
- package/dist/vue3/components/emoji_picker/modules/emoji_selector.vue.js.map +1 -1
- package/dist/vue3/components/emoji_text_wrapper/emoji_text_wrapper.vue.cjs +4 -3
- package/dist/vue3/components/emoji_text_wrapper/emoji_text_wrapper.vue.cjs.map +1 -1
- package/dist/vue3/components/emoji_text_wrapper/emoji_text_wrapper.vue.js +5 -4
- package/dist/vue3/components/emoji_text_wrapper/emoji_text_wrapper.vue.js.map +1 -1
- package/dist/vue3/components/input/input.vue.cjs +1 -1
- package/dist/vue3/components/input/input.vue.cjs.map +1 -1
- package/dist/vue3/components/input/input.vue.js +1 -1
- package/dist/vue3/components/input/input.vue.js.map +1 -1
- package/dist/vue3/components/input/input_constants.cjs +2 -1
- package/dist/vue3/components/input/input_constants.cjs.map +1 -1
- package/dist/vue3/components/input/input_constants.js +2 -1
- package/dist/vue3/components/input/input_constants.js.map +1 -1
- package/dist/vue3/dialtone-vue.cjs +0 -1
- package/dist/vue3/dialtone-vue.cjs.map +1 -1
- package/dist/vue3/dialtone-vue.js +1 -2
- package/dist/vue3/types/common/emoji/index.d.ts +0 -1
- package/dist/vue3/types/common/emoji/index.d.ts.map +1 -1
- package/dist/vue3/types/components/emoji_text_wrapper/emoji_text_wrapper.vue.d.ts.map +1 -1
- package/dist/vue3/types/components/input/input_constants.d.ts +1 -0
- package/package.json +2 -2
|
@@ -258,7 +258,7 @@ const _sfc_main = {
|
|
|
258
258
|
emits("focus-skin-selector");
|
|
259
259
|
break;
|
|
260
260
|
case "Enter":
|
|
261
|
-
selectEmoji(emoji);
|
|
261
|
+
selectEmoji(emoji, event);
|
|
262
262
|
break;
|
|
263
263
|
}
|
|
264
264
|
};
|
|
@@ -286,12 +286,12 @@ const _sfc_main = {
|
|
|
286
286
|
}
|
|
287
287
|
break;
|
|
288
288
|
case "Enter":
|
|
289
|
-
selectEmoji(emoji);
|
|
289
|
+
selectEmoji(emoji, event);
|
|
290
290
|
break;
|
|
291
291
|
}
|
|
292
292
|
};
|
|
293
|
-
function selectEmoji(emoji) {
|
|
294
|
-
emits("selected-emoji", emoji);
|
|
293
|
+
function selectEmoji(emoji, event) {
|
|
294
|
+
emits("selected-emoji", { ...emoji, shift_key: event.shiftKey });
|
|
295
295
|
}
|
|
296
296
|
function highlightEmoji(emoji) {
|
|
297
297
|
emits("highlighted-emoji", emoji);
|
|
@@ -346,7 +346,7 @@ const _sfc_main = {
|
|
|
346
346
|
},
|
|
347
347
|
type: "button",
|
|
348
348
|
"aria-label": emoji.name,
|
|
349
|
-
onClick: (
|
|
349
|
+
onClick: (event) => selectEmoji(emoji, event),
|
|
350
350
|
onFocusin: ($event) => highlightEmoji(emoji),
|
|
351
351
|
onFocusout: _cache[0] || (_cache[0] = ($event) => highlightEmoji(null)),
|
|
352
352
|
onMouseover: ($event) => highlightEmoji(emoji),
|
|
@@ -382,7 +382,7 @@ const _sfc_main = {
|
|
|
382
382
|
class: vue.normalizeClass({
|
|
383
383
|
"hover-emoji": index === 0 && vue.unref(hoverFirstEmoji)
|
|
384
384
|
}),
|
|
385
|
-
onClick: (
|
|
385
|
+
onClick: (event) => selectEmoji(emoji, event),
|
|
386
386
|
onFocusin: ($event) => highlightEmoji(emoji),
|
|
387
387
|
onFocusout: _cache[2] || (_cache[2] = ($event) => highlightEmoji(null)),
|
|
388
388
|
onMouseover: ($event) => hoverEmoji(emoji),
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"emoji_selector.vue.cjs","sources":["../../../../components/emoji_picker/modules/emoji_selector.vue"],"sourcesContent":["<template>\n <div\n class=\"d-emoji-picker__selector\"\n >\n <div\n id=\"d-emoji-picker-list\"\n ref=\"listRef\"\n class=\"d-emoji-picker__list\"\n >\n <p\n v-if=\"emojiFilter\"\n class=\"d-emoji-picker__search-label d-emoji-picker__alignment\"\n >\n {{ filteredEmojis.length > 0 ? searchResultsLabel : searchNoResultsLabel }}\n </p>\n <div\n v-else\n ref=\"tabCategoryRef\"\n class=\"d-emoji-picker__category d-emoji-picker__alignment\"\n >\n <p>\n {{ fixedLabel }}\n </p>\n </div>\n <div\n v-for=\"(tabLabel, indexTab) in tabLabels\"\n v-show=\"!emojiFilter\"\n :key=\"indexTab\"\n :ref=\"tabLabel.ref\"\n class=\"d-emoji-picker__alignment\"\n >\n <p\n v-if=\"indexTab\"\n >\n {{ tabLabel.label }}\n </p>\n <div\n class=\"d-emoji-picker__tab\"\n >\n <button\n v-for=\"(emoji, indexEmoji) in\n (emojis[tabs[indexTab] + skinTone] ? emojis[tabs[indexTab] + skinTone] : emojis[tabs[indexTab]])\"\n :key=\"emoji.shortname\"\n :ref=\"el => { if (el) setEmojiRef(el, indexTab, indexEmoji) }\"\n type=\"button\"\n :aria-label=\"emoji.name\"\n @click=\"selectEmoji(emoji)\"\n @focusin=\"highlightEmoji(emoji)\"\n @focusout=\"highlightEmoji(null)\"\n @mouseover=\"highlightEmoji(emoji)\"\n @mouseleave=\"highlightEmoji(null)\"\n @keydown=\"event => handleKeyDown(event, indexTab, indexEmoji, emoji)\"\n >\n <img\n class=\"d-icon d-icon--size-500\"\n :alt=\"emoji.name\"\n :aria-label=\"emoji.name\"\n :title=\"emoji.name\"\n :src=\"getImgSrc(emoji.unicode_character)\"\n @error=\"handleImageError\"\n >\n </button>\n </div>\n </div>\n <div\n v-if=\"emojiFilter\"\n class=\"d-emoji-picker__alignment\"\n >\n <div\n class=\"d-emoji-picker__tab \"\n data-qa=\"filtered-emojis\"\n >\n <button\n v-for=\"(emoji, index) in filteredEmojis\"\n :key=\"emoji.shortname\"\n :ref=\"el => { if (el) setFilteredRef(el, index) }\"\n type=\"button\"\n :aria-label=\"emoji.name\"\n :class=\"{\n 'hover-emoji': (index === 0 && hoverFirstEmoji),\n }\"\n @click=\"selectEmoji(emoji)\"\n @focusin=\"highlightEmoji(emoji)\"\n @focusout=\"highlightEmoji(null)\"\n @mouseover=\"hoverEmoji(emoji)\"\n @mouseleave=\"hoverEmoji(null)\"\n @keydown=\"event => handleKeyDownFilteredEmojis(event, index, emoji)\"\n >\n <img\n class=\"d-icon d-icon--size-500\"\n :alt=\"emoji.name\"\n :aria-label=\"emoji.name\"\n :title=\"emoji.name\"\n :src=\"`${CDN_URL + emoji.unicode_character}.png`\"\n >\n </button>\n </div>\n </div>\n </div>\n </div>\n</template>\n\n<script setup>\n/* eslint-disable max-len */\n/* eslint-disable max-lines */\nimport { emojisGrouped as emojis } from '@dialpad/dialtone-emojis';\nimport { computed, onMounted, onUnmounted, ref, watch, nextTick } from 'vue';\nimport { CDN_URL, ARROW_KEYS } from '@/components/emoji_picker/emoji_picker_constants';\nimport { useKeyboardNavigation } from '@/components/emoji_picker/composables/useKeyboardNavigation';\n\nconst props = defineProps({\n /**\n * The filter to apply to the emoji list\n * @type {String}\n * @default ''\n */\n emojiFilter: {\n type: String,\n default: '',\n },\n\n /**\n * The skin tone to apply to the emoji list\n * @type {String}\n * @required\n */\n skinTone: {\n type: String,\n required: true,\n },\n\n /**\n * The labels for the tabset\n * @type {Array}\n * @required\n */\n tabsetLabels: {\n type: Array,\n required: true,\n },\n\n selectedTabset: {\n type: Object,\n required: true,\n },\n\n /**\n * The label for the search results tab\n * @type {String}\n * @required\n */\n searchResultsLabel: {\n type: String,\n required: true,\n },\n\n searchNoResultsLabel: {\n type: String,\n required: true,\n },\n\n /**\n * The list of recently used emojis\n * @type {Array}\n */\n recentlyUsedEmojis: {\n type: Array,\n default: () => [],\n },\n});\n\nconst emits = defineEmits([\n /**\n * Emitted when the user hover over an emoji\n * @event highlighted-emoji\n * @param {Object} emoji - The emoji data that was hovered\n */\n 'highlighted-emoji',\n\n /**\n * Emitted when the user select an emoji\n * @event selected-emoji\n * @param {Object} emoji - The emoji data that was selected\n */\n 'selected-emoji',\n\n /**\n * Emitted when the user scroll into an emoji tab\n * @event scroll-into-tab\n * @param {Number} tab-index - The tab that was scrolled into\n */\n 'scroll-into-tab',\n\n /**\n * Emitted when the user reach the end of the emoji list\n * @event focus-skin-selector\n */\n 'focus-skin-selector',\n\n /**\n * Emitted when the user shift tab in first tab of emoji selector\n * @event focus-search-input\n */\n 'focus-search-input',\n]);\n\nconst {\n emojiFilteredRefs,\n isFiltering,\n hoverFirstEmoji,\n setEmojiRef,\n setFilteredRef,\n focusEmoji,\n handleArrowNavigationFiltered,\n handleArrowNavigation,\n} = useKeyboardNavigation();\n\n/**\n * The ref for the tab category\n * This is used to display the fixed label\n */\nconst tabCategoryRef = ref(null);\n\n/**\n * The ref for the list\n * This is used to display the tabs\n */\nconst listRef = ref(null);\n\n/**\n * The ref for the tab label observer\n * This is used to update the fixed label\n */\nconst tabLabelObserver = ref(null);\n\n/**\n * The list of tabs\n * This is used to display the tabs\n */\nconst TABS_DATA = ['Recently used', 'People', 'Nature', 'Food', 'Activity', 'Travel', 'Objects', 'Symbols', 'Flags'];\n\n/**\n * The list of tab labels\n * This is used to display the tabs\n * This is a computed property because it will check if the recently used emojis list is empty\n * If it is empty, it will remove the recently used tab\n */\nconst tabLabels = computed(() => {\n return props.recentlyUsedEmojis.length\n ? props.tabsetLabels.map((label) => ({ label, ref: ref(null) }))\n : props.tabsetLabels.slice(1).map((label) => ({ label, ref: ref(null) }));\n});\n\n/**\n * The label of the fixed tab\n * This is used to display the fixed label\n */\nconst fixedLabel = ref(tabLabels.value[0].label);\n\n/**\n * The list of tabs\n * This is used to display the tabs\n * This is a computed property because it will check if the recently used emojis list is empty\n * If it is empty, it will remove the recently used tab\n * The difference between this and the tab labels is that this one will set the structure of tabs\n * and the tab labels will set the labels\n */\nconst tabs = computed(() => {\n return props.recentlyUsedEmojis.length ? TABS_DATA : TABS_DATA.slice(1);\n});\n\n/**\n * The list of current emojis that match the filter\n * This will be updated when the emojiFilter changes\n * This is used to display the search results\n * The difference between this and the current emojis list is that this one will not have the skin tone applied\n */\nconst filteredEmojis = ref([]);\n\n/**\n * The current emojis list we are displaying\n * This will be updated when the skin tone changes\n * The difference between this and the emojis list is that this one will have only the skin tone applied\n */\nconst currentEmojis = computed(() => {\n return [\n ...emojis[`People${props.skinTone}`],\n ...emojis.Nature,\n ...emojis.Food,\n ...emojis[`Activity${props.skinTone}`],\n ...emojis.Travel,\n ...emojis[`Objects${props.skinTone}`],\n ...emojis.Symbols,\n ...emojis.Flags,\n ];\n});\n\n/**\n * This will trigger the searchByNameAndKeywords function with debounce of 300 milliseconds\n */\nconst debouncedSearch = debounce(() => {\n // We clean the emojiFilteredRefs to have an updated ref list for the search results\n emojiFilteredRefs.value = [];\n searchByNameAndKeywords();\n});\n\n/**\n * Update the current emojis list on skin tone changes\n * Also update the filtered emojis list\n * @listens skinTone\n */\nwatch(currentEmojis, () => {\n searchByNameAndKeywords();\n}, { immediate: true });\n\n/**\n * Update the recently used emojis list on recently used emojis prop changes\n * @listens recentlyUsedEmojis\n */\nwatch(() => props.recentlyUsedEmojis,\n () => {\n emojis['Recently used'] = props.recentlyUsedEmojis;\n }, { immediate: true });\n\n/**\n * Search for emojis by name and keywords\n * Will update the filtered emojis list on emojiFilter update\n * @listens emojiFilter\n */\nwatch(() => props.emojiFilter, () => {\n resetScroll();\n if (props.emojiFilter) {\n isFiltering.value = true;\n } else {\n isFiltering.value = false;\n // If the emoji filter is empty, emit null to remove the highlighted emoji\n // of the previous search\n highlightEmoji(null);\n }\n debouncedSearch();\n});\n\nwatch(\n () => props.selectedTabset,\n (tab) => {\n scrollToTab(tab.tabId);\n },\n { deep: true },\n);\n\nfunction hoverEmoji (emoji, isFirst = false) {\n hoverFirstEmoji.value = isFirst;\n emits('highlighted-emoji', emoji);\n}\n\n/**\n * Filters an array of emoji objects based on a search string that matches both the name and keywords.\n * Will update the filtered emojis list\n */\nfunction searchByNameAndKeywords () {\n const searchStr = props.emojiFilter.toLowerCase();\n filteredEmojis.value = currentEmojis.value.filter(obj => {\n const nameIncludesSearchStr = obj.name.toLowerCase().includes(searchStr);\n const keywordsIncludeSearchStr = obj.keywords.some(keyword => keyword.toLowerCase().includes(searchStr));\n return nameIncludesSearchStr || keywordsIncludeSearchStr;\n });\n nextTick(() => {\n if (searchStr) {\n hoverEmoji(filteredEmojis.value[0], true);\n }\n });\n}\n\nfunction debounce (fn, delay = 300) {\n let timeout;\n\n return (...args) => {\n clearTimeout(timeout);\n timeout = setTimeout(() => fn(...args), delay);\n };\n}\n\nfunction getImgSrc (emoji) {\n return `${CDN_URL + emoji}.png`;\n}\n\n/**\n * Handle image error - We hide the entire button if the image is not found\n */\nfunction handleImageError (event) {\n event.target.parentNode.style.display = 'none';\n}\n\n/**\n * Scroll to the selected tab\n */\nfunction scrollToTab (tabIndex, focusFirstEmoji = true) {\n const tabLabel = tabLabels.value[tabIndex - 1];\n const tabElement = tabLabel.ref.value[0];\n\n nextTick(() => {\n const container = listRef.value;\n const offsetTop = tabIndex === 1 ? 0 : tabElement.offsetTop - 15;\n\n container.scrollTop = offsetTop;\n\n if (focusFirstEmoji) {\n focusEmoji((tabIndex - 1), 0);\n }\n });\n}\n\nfunction resetScroll () {\n const container = listRef.value;\n\n container.scrollTop = 0;\n}\n\n/**\n * This code creates an IntersectionObserver object that monitors the intersection between\n * the root element (tabCategoryRef) and its targets (the child elements of listRef),\n * and updates the value of the fixedLabel variable accordingly.\n */\nfunction setTabLabelObserver () {\n /**\n * The code extracts the target element and its index from the IntersectionObserverEntry object,\n * and checks whether the target intersects with the root and is positioned above or below it.\n */\n tabLabelObserver.value = new IntersectionObserver(async (entries) => {\n // eslint-disable-next-line complexity\n entries.forEach(entry => {\n const { target } = entry;\n const index = parseInt(target.dataset.index);\n\n /**\n * If the target is positioned above the root,\n * the code updates the value of the fixed label to the label of the previous tab,\n * or the first tab if the current tab is the first one. If the target is positioned below the root, the code\n * updates the value of the fixed label to the label of the current tab.\n * If the target stops intersecting with the root and its index is 1 (the second tab),\n * the code updates the value of the fixed label to the label of the first tab.\n * NOTES:\n * This last condition is needed because sometimes it is\n * not detect the intersection between the root and the target.\n * We also provide a 50 pixels offset to the root element in the first condition to always get the\n * first tab if it has fewer emojis, because in some cases if you quickly scroll the observer does not detect it.\n */\n if (entry.isIntersecting && target.offsetTop <= tabCategoryRef.value.offsetTop + 50) {\n fixedLabel.value = tabLabels.value[index - 1]?.label ?? tabLabels.value[0]?.label;\n emits('scroll-into-tab', index - 1);\n } else if (entry.boundingClientRect.bottom <= tabCategoryRef.value?.getBoundingClientRect().bottom) {\n emits('scroll-into-tab', index);\n fixedLabel.value = tabLabels.value[index]?.label;\n } else if (index === 1) {\n emits('scroll-into-tab', index);\n fixedLabel.value = tabLabels.value[0]?.label;\n }\n });\n });\n\n /**\n * The tabLabelObserver is set to observe the root element and all its children elements with\n * the IntersectionObserver object, and sets their data-index attribute to their index.\n */\n tabLabelObserver.value.observe(tabCategoryRef.value);\n\n Array.from(listRef.value.children).forEach((child, index) => {\n tabLabelObserver.value.observe(child);\n child.dataset.index = index;\n });\n}\n\nconst handleKeyDownFilteredEmojis = (event, indexEmoji, emoji) => {\n event.preventDefault();\n\n if (Object.values(ARROW_KEYS).includes(event.key)) {\n handleArrowNavigationFiltered(event.key, indexEmoji);\n return;\n }\n\n switch (event.key) {\n case 'Tab':\n emits('focus-skin-selector');\n break;\n case 'Enter':\n selectEmoji(emoji);\n break;\n default:\n break;\n }\n};\n\n/* eslint-disable-next-line complexity */\nconst handleKeyDown = (event, indexTab, indexEmoji, emoji) => {\n event.preventDefault();\n\n if (Object.values(ARROW_KEYS).includes(event.key)) {\n handleArrowNavigation(event.key, indexTab, indexEmoji);\n return;\n }\n\n switch (event.key) {\n case 'Tab':\n if (event.shiftKey) {\n if (focusEmoji(indexTab, 0) && indexTab > 0) {\n scrollToTab(indexTab, true);\n } else {\n scrollToTab(1, false);\n emits('focus-search-input');\n }\n } else {\n if (focusEmoji(indexTab + 1, 0)) {\n scrollToTab(indexTab + 1 + 1, false);\n } else {\n // We are on the last emoji tabset, jump to the skin selector\n emits('focus-skin-selector');\n }\n }\n break;\n\n case 'Enter':\n selectEmoji(emoji);\n break;\n\n default:\n break;\n }\n};\n\nfunction selectEmoji (emoji) {\n emits('selected-emoji', emoji);\n}\n\nfunction highlightEmoji (emoji) {\n emits('highlighted-emoji', emoji);\n}\n\nfunction focusEmojiSelector () {\n focusEmoji(0, 0);\n}\n\nfunction focusLastEmoji () {\n scrollToTab(tabs.value.length, true);\n}\n\nonMounted(() => {\n setTabLabelObserver();\n});\n\nonUnmounted(() => {\n tabLabelObserver.value.disconnect();\n});\n\ndefineExpose({\n focusEmojiSelector,\n focusLastEmoji,\n});\n</script>\n"],"names":["useKeyboardNavigation","ref","computed","emojis","watch","nextTick","CDN_URL","ARROW_KEYS","onMounted","onUnmounted"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"emoji_selector.vue.cjs","sources":["../../../../components/emoji_picker/modules/emoji_selector.vue"],"sourcesContent":["<template>\n <div\n class=\"d-emoji-picker__selector\"\n >\n <div\n id=\"d-emoji-picker-list\"\n ref=\"listRef\"\n class=\"d-emoji-picker__list\"\n >\n <p\n v-if=\"emojiFilter\"\n class=\"d-emoji-picker__search-label d-emoji-picker__alignment\"\n >\n {{ filteredEmojis.length > 0 ? searchResultsLabel : searchNoResultsLabel }}\n </p>\n <div\n v-else\n ref=\"tabCategoryRef\"\n class=\"d-emoji-picker__category d-emoji-picker__alignment\"\n >\n <p>\n {{ fixedLabel }}\n </p>\n </div>\n <div\n v-for=\"(tabLabel, indexTab) in tabLabels\"\n v-show=\"!emojiFilter\"\n :key=\"indexTab\"\n :ref=\"tabLabel.ref\"\n class=\"d-emoji-picker__alignment\"\n >\n <p\n v-if=\"indexTab\"\n >\n {{ tabLabel.label }}\n </p>\n <div\n class=\"d-emoji-picker__tab\"\n >\n <button\n v-for=\"(emoji, indexEmoji) in\n (emojis[tabs[indexTab] + skinTone] ? emojis[tabs[indexTab] + skinTone] : emojis[tabs[indexTab]])\"\n :key=\"emoji.shortname\"\n :ref=\"el => { if (el) setEmojiRef(el, indexTab, indexEmoji) }\"\n type=\"button\"\n :aria-label=\"emoji.name\"\n @click=\"event => selectEmoji(emoji, event)\"\n @focusin=\"highlightEmoji(emoji)\"\n @focusout=\"highlightEmoji(null)\"\n @mouseover=\"highlightEmoji(emoji)\"\n @mouseleave=\"highlightEmoji(null)\"\n @keydown=\"event => handleKeyDown(event, indexTab, indexEmoji, emoji)\"\n >\n <img\n class=\"d-icon d-icon--size-500\"\n :alt=\"emoji.name\"\n :aria-label=\"emoji.name\"\n :title=\"emoji.name\"\n :src=\"getImgSrc(emoji.unicode_character)\"\n @error=\"handleImageError\"\n >\n </button>\n </div>\n </div>\n <div\n v-if=\"emojiFilter\"\n class=\"d-emoji-picker__alignment\"\n >\n <div\n class=\"d-emoji-picker__tab \"\n data-qa=\"filtered-emojis\"\n >\n <button\n v-for=\"(emoji, index) in filteredEmojis\"\n :key=\"emoji.shortname\"\n :ref=\"el => { if (el) setFilteredRef(el, index) }\"\n type=\"button\"\n :aria-label=\"emoji.name\"\n :class=\"{\n 'hover-emoji': (index === 0 && hoverFirstEmoji),\n }\"\n @click=\"event => selectEmoji(emoji, event)\"\n @focusin=\"highlightEmoji(emoji)\"\n @focusout=\"highlightEmoji(null)\"\n @mouseover=\"hoverEmoji(emoji)\"\n @mouseleave=\"hoverEmoji(null)\"\n @keydown=\"event => handleKeyDownFilteredEmojis(event, index, emoji)\"\n >\n <img\n class=\"d-icon d-icon--size-500\"\n :alt=\"emoji.name\"\n :aria-label=\"emoji.name\"\n :title=\"emoji.name\"\n :src=\"`${CDN_URL + emoji.unicode_character}.png`\"\n >\n </button>\n </div>\n </div>\n </div>\n </div>\n</template>\n\n<script setup>\n/* eslint-disable max-len */\n/* eslint-disable max-lines */\nimport { emojisGrouped as emojis } from '@dialpad/dialtone-emojis';\nimport { computed, onMounted, onUnmounted, ref, watch, nextTick } from 'vue';\nimport { CDN_URL, ARROW_KEYS } from '@/components/emoji_picker/emoji_picker_constants';\nimport { useKeyboardNavigation } from '@/components/emoji_picker/composables/useKeyboardNavigation';\n\nconst props = defineProps({\n /**\n * The filter to apply to the emoji list\n * @type {String}\n * @default ''\n */\n emojiFilter: {\n type: String,\n default: '',\n },\n\n /**\n * The skin tone to apply to the emoji list\n * @type {String}\n * @required\n */\n skinTone: {\n type: String,\n required: true,\n },\n\n /**\n * The labels for the tabset\n * @type {Array}\n * @required\n */\n tabsetLabels: {\n type: Array,\n required: true,\n },\n\n selectedTabset: {\n type: Object,\n required: true,\n },\n\n /**\n * The label for the search results tab\n * @type {String}\n * @required\n */\n searchResultsLabel: {\n type: String,\n required: true,\n },\n\n searchNoResultsLabel: {\n type: String,\n required: true,\n },\n\n /**\n * The list of recently used emojis\n * @type {Array}\n */\n recentlyUsedEmojis: {\n type: Array,\n default: () => [],\n },\n});\n\nconst emits = defineEmits([\n /**\n * Emitted when the user hover over an emoji\n * @event highlighted-emoji\n * @param {Object} emoji - The emoji data that was hovered\n */\n 'highlighted-emoji',\n\n /**\n * Emitted when the user select an emoji\n * @event selected-emoji\n * @param {Object} emoji - The emoji data that was selected\n */\n 'selected-emoji',\n\n /**\n * Emitted when the user scroll into an emoji tab\n * @event scroll-into-tab\n * @param {Number} tab-index - The tab that was scrolled into\n */\n 'scroll-into-tab',\n\n /**\n * Emitted when the user reach the end of the emoji list\n * @event focus-skin-selector\n */\n 'focus-skin-selector',\n\n /**\n * Emitted when the user shift tab in first tab of emoji selector\n * @event focus-search-input\n */\n 'focus-search-input',\n]);\n\nconst {\n emojiFilteredRefs,\n isFiltering,\n hoverFirstEmoji,\n setEmojiRef,\n setFilteredRef,\n focusEmoji,\n handleArrowNavigationFiltered,\n handleArrowNavigation,\n} = useKeyboardNavigation();\n\n/**\n * The ref for the tab category\n * This is used to display the fixed label\n */\nconst tabCategoryRef = ref(null);\n\n/**\n * The ref for the list\n * This is used to display the tabs\n */\nconst listRef = ref(null);\n\n/**\n * The ref for the tab label observer\n * This is used to update the fixed label\n */\nconst tabLabelObserver = ref(null);\n\n/**\n * The list of tabs\n * This is used to display the tabs\n */\nconst TABS_DATA = ['Recently used', 'People', 'Nature', 'Food', 'Activity', 'Travel', 'Objects', 'Symbols', 'Flags'];\n\n/**\n * The list of tab labels\n * This is used to display the tabs\n * This is a computed property because it will check if the recently used emojis list is empty\n * If it is empty, it will remove the recently used tab\n */\nconst tabLabels = computed(() => {\n return props.recentlyUsedEmojis.length\n ? props.tabsetLabels.map((label) => ({ label, ref: ref(null) }))\n : props.tabsetLabels.slice(1).map((label) => ({ label, ref: ref(null) }));\n});\n\n/**\n * The label of the fixed tab\n * This is used to display the fixed label\n */\nconst fixedLabel = ref(tabLabels.value[0].label);\n\n/**\n * The list of tabs\n * This is used to display the tabs\n * This is a computed property because it will check if the recently used emojis list is empty\n * If it is empty, it will remove the recently used tab\n * The difference between this and the tab labels is that this one will set the structure of tabs\n * and the tab labels will set the labels\n */\nconst tabs = computed(() => {\n return props.recentlyUsedEmojis.length ? TABS_DATA : TABS_DATA.slice(1);\n});\n\n/**\n * The list of current emojis that match the filter\n * This will be updated when the emojiFilter changes\n * This is used to display the search results\n * The difference between this and the current emojis list is that this one will not have the skin tone applied\n */\nconst filteredEmojis = ref([]);\n\n/**\n * The current emojis list we are displaying\n * This will be updated when the skin tone changes\n * The difference between this and the emojis list is that this one will have only the skin tone applied\n */\nconst currentEmojis = computed(() => {\n return [\n ...emojis[`People${props.skinTone}`],\n ...emojis.Nature,\n ...emojis.Food,\n ...emojis[`Activity${props.skinTone}`],\n ...emojis.Travel,\n ...emojis[`Objects${props.skinTone}`],\n ...emojis.Symbols,\n ...emojis.Flags,\n ];\n});\n\n/**\n * This will trigger the searchByNameAndKeywords function with debounce of 300 milliseconds\n */\nconst debouncedSearch = debounce(() => {\n // We clean the emojiFilteredRefs to have an updated ref list for the search results\n emojiFilteredRefs.value = [];\n searchByNameAndKeywords();\n});\n\n/**\n * Update the current emojis list on skin tone changes\n * Also update the filtered emojis list\n * @listens skinTone\n */\nwatch(currentEmojis, () => {\n searchByNameAndKeywords();\n}, { immediate: true });\n\n/**\n * Update the recently used emojis list on recently used emojis prop changes\n * @listens recentlyUsedEmojis\n */\nwatch(() => props.recentlyUsedEmojis,\n () => {\n emojis['Recently used'] = props.recentlyUsedEmojis;\n }, { immediate: true });\n\n/**\n * Search for emojis by name and keywords\n * Will update the filtered emojis list on emojiFilter update\n * @listens emojiFilter\n */\nwatch(() => props.emojiFilter, () => {\n resetScroll();\n if (props.emojiFilter) {\n isFiltering.value = true;\n } else {\n isFiltering.value = false;\n // If the emoji filter is empty, emit null to remove the highlighted emoji\n // of the previous search\n highlightEmoji(null);\n }\n debouncedSearch();\n});\n\nwatch(\n () => props.selectedTabset,\n (tab) => {\n scrollToTab(tab.tabId);\n },\n { deep: true },\n);\n\nfunction hoverEmoji (emoji, isFirst = false) {\n hoverFirstEmoji.value = isFirst;\n emits('highlighted-emoji', emoji);\n}\n\n/**\n * Filters an array of emoji objects based on a search string that matches both the name and keywords.\n * Will update the filtered emojis list\n */\nfunction searchByNameAndKeywords () {\n const searchStr = props.emojiFilter.toLowerCase();\n filteredEmojis.value = currentEmojis.value.filter(obj => {\n const nameIncludesSearchStr = obj.name.toLowerCase().includes(searchStr);\n const keywordsIncludeSearchStr = obj.keywords.some(keyword => keyword.toLowerCase().includes(searchStr));\n return nameIncludesSearchStr || keywordsIncludeSearchStr;\n });\n nextTick(() => {\n if (searchStr) {\n hoverEmoji(filteredEmojis.value[0], true);\n }\n });\n}\n\nfunction debounce (fn, delay = 300) {\n let timeout;\n\n return (...args) => {\n clearTimeout(timeout);\n timeout = setTimeout(() => fn(...args), delay);\n };\n}\n\nfunction getImgSrc (emoji) {\n return `${CDN_URL + emoji}.png`;\n}\n\n/**\n * Handle image error - We hide the entire button if the image is not found\n */\nfunction handleImageError (event) {\n event.target.parentNode.style.display = 'none';\n}\n\n/**\n * Scroll to the selected tab\n */\nfunction scrollToTab (tabIndex, focusFirstEmoji = true) {\n const tabLabel = tabLabels.value[tabIndex - 1];\n const tabElement = tabLabel.ref.value[0];\n\n nextTick(() => {\n const container = listRef.value;\n const offsetTop = tabIndex === 1 ? 0 : tabElement.offsetTop - 15;\n\n container.scrollTop = offsetTop;\n\n if (focusFirstEmoji) {\n focusEmoji((tabIndex - 1), 0);\n }\n });\n}\n\nfunction resetScroll () {\n const container = listRef.value;\n\n container.scrollTop = 0;\n}\n\n/**\n * This code creates an IntersectionObserver object that monitors the intersection between\n * the root element (tabCategoryRef) and its targets (the child elements of listRef),\n * and updates the value of the fixedLabel variable accordingly.\n */\nfunction setTabLabelObserver () {\n /**\n * The code extracts the target element and its index from the IntersectionObserverEntry object,\n * and checks whether the target intersects with the root and is positioned above or below it.\n */\n tabLabelObserver.value = new IntersectionObserver(async (entries) => {\n // eslint-disable-next-line complexity\n entries.forEach(entry => {\n const { target } = entry;\n const index = parseInt(target.dataset.index);\n\n /**\n * If the target is positioned above the root,\n * the code updates the value of the fixed label to the label of the previous tab,\n * or the first tab if the current tab is the first one. If the target is positioned below the root, the code\n * updates the value of the fixed label to the label of the current tab.\n * If the target stops intersecting with the root and its index is 1 (the second tab),\n * the code updates the value of the fixed label to the label of the first tab.\n * NOTES:\n * This last condition is needed because sometimes it is\n * not detect the intersection between the root and the target.\n * We also provide a 50 pixels offset to the root element in the first condition to always get the\n * first tab if it has fewer emojis, because in some cases if you quickly scroll the observer does not detect it.\n */\n if (entry.isIntersecting && target.offsetTop <= tabCategoryRef.value.offsetTop + 50) {\n fixedLabel.value = tabLabels.value[index - 1]?.label ?? tabLabels.value[0]?.label;\n emits('scroll-into-tab', index - 1);\n } else if (entry.boundingClientRect.bottom <= tabCategoryRef.value?.getBoundingClientRect().bottom) {\n emits('scroll-into-tab', index);\n fixedLabel.value = tabLabels.value[index]?.label;\n } else if (index === 1) {\n emits('scroll-into-tab', index);\n fixedLabel.value = tabLabels.value[0]?.label;\n }\n });\n });\n\n /**\n * The tabLabelObserver is set to observe the root element and all its children elements with\n * the IntersectionObserver object, and sets their data-index attribute to their index.\n */\n tabLabelObserver.value.observe(tabCategoryRef.value);\n\n Array.from(listRef.value.children).forEach((child, index) => {\n tabLabelObserver.value.observe(child);\n child.dataset.index = index;\n });\n}\n\nconst handleKeyDownFilteredEmojis = (event, indexEmoji, emoji) => {\n event.preventDefault();\n\n if (Object.values(ARROW_KEYS).includes(event.key)) {\n handleArrowNavigationFiltered(event.key, indexEmoji);\n return;\n }\n\n switch (event.key) {\n case 'Tab':\n emits('focus-skin-selector');\n break;\n case 'Enter':\n selectEmoji(emoji, event);\n break;\n default:\n break;\n }\n};\n\n/* eslint-disable-next-line complexity */\nconst handleKeyDown = (event, indexTab, indexEmoji, emoji) => {\n event.preventDefault();\n\n if (Object.values(ARROW_KEYS).includes(event.key)) {\n handleArrowNavigation(event.key, indexTab, indexEmoji);\n return;\n }\n\n switch (event.key) {\n case 'Tab':\n if (event.shiftKey) {\n if (focusEmoji(indexTab, 0) && indexTab > 0) {\n scrollToTab(indexTab, true);\n } else {\n scrollToTab(1, false);\n emits('focus-search-input');\n }\n } else {\n if (focusEmoji(indexTab + 1, 0)) {\n scrollToTab(indexTab + 1 + 1, false);\n } else {\n // We are on the last emoji tabset, jump to the skin selector\n emits('focus-skin-selector');\n }\n }\n break;\n\n case 'Enter':\n selectEmoji(emoji, event);\n break;\n\n default:\n break;\n }\n};\n\nfunction selectEmoji (emoji, event) {\n emits('selected-emoji', { ...emoji, shift_key: event.shiftKey });\n}\n\nfunction highlightEmoji (emoji) {\n emits('highlighted-emoji', emoji);\n}\n\nfunction focusEmojiSelector () {\n focusEmoji(0, 0);\n}\n\nfunction focusLastEmoji () {\n scrollToTab(tabs.value.length, true);\n}\n\nonMounted(() => {\n setTabLabelObserver();\n});\n\nonUnmounted(() => {\n tabLabelObserver.value.disconnect();\n});\n\ndefineExpose({\n focusEmojiSelector,\n focusLastEmoji,\n});\n</script>\n"],"names":["useKeyboardNavigation","ref","computed","emojis","watch","nextTick","CDN_URL","ARROW_KEYS","onMounted","onUnmounted"],"mappings":"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"}
|
|
@@ -256,7 +256,7 @@ const _sfc_main = {
|
|
|
256
256
|
emits("focus-skin-selector");
|
|
257
257
|
break;
|
|
258
258
|
case "Enter":
|
|
259
|
-
selectEmoji(emoji);
|
|
259
|
+
selectEmoji(emoji, event);
|
|
260
260
|
break;
|
|
261
261
|
}
|
|
262
262
|
};
|
|
@@ -284,12 +284,12 @@ const _sfc_main = {
|
|
|
284
284
|
}
|
|
285
285
|
break;
|
|
286
286
|
case "Enter":
|
|
287
|
-
selectEmoji(emoji);
|
|
287
|
+
selectEmoji(emoji, event);
|
|
288
288
|
break;
|
|
289
289
|
}
|
|
290
290
|
};
|
|
291
|
-
function selectEmoji(emoji) {
|
|
292
|
-
emits("selected-emoji", emoji);
|
|
291
|
+
function selectEmoji(emoji, event) {
|
|
292
|
+
emits("selected-emoji", { ...emoji, shift_key: event.shiftKey });
|
|
293
293
|
}
|
|
294
294
|
function highlightEmoji(emoji) {
|
|
295
295
|
emits("highlighted-emoji", emoji);
|
|
@@ -344,7 +344,7 @@ const _sfc_main = {
|
|
|
344
344
|
},
|
|
345
345
|
type: "button",
|
|
346
346
|
"aria-label": emoji.name,
|
|
347
|
-
onClick: (
|
|
347
|
+
onClick: (event) => selectEmoji(emoji, event),
|
|
348
348
|
onFocusin: ($event) => highlightEmoji(emoji),
|
|
349
349
|
onFocusout: _cache[0] || (_cache[0] = ($event) => highlightEmoji(null)),
|
|
350
350
|
onMouseover: ($event) => highlightEmoji(emoji),
|
|
@@ -380,7 +380,7 @@ const _sfc_main = {
|
|
|
380
380
|
class: normalizeClass({
|
|
381
381
|
"hover-emoji": index === 0 && unref(hoverFirstEmoji)
|
|
382
382
|
}),
|
|
383
|
-
onClick: (
|
|
383
|
+
onClick: (event) => selectEmoji(emoji, event),
|
|
384
384
|
onFocusin: ($event) => highlightEmoji(emoji),
|
|
385
385
|
onFocusout: _cache[2] || (_cache[2] = ($event) => highlightEmoji(null)),
|
|
386
386
|
onMouseover: ($event) => hoverEmoji(emoji),
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"emoji_selector.vue.js","sources":["../../../../components/emoji_picker/modules/emoji_selector.vue"],"sourcesContent":["<template>\n <div\n class=\"d-emoji-picker__selector\"\n >\n <div\n id=\"d-emoji-picker-list\"\n ref=\"listRef\"\n class=\"d-emoji-picker__list\"\n >\n <p\n v-if=\"emojiFilter\"\n class=\"d-emoji-picker__search-label d-emoji-picker__alignment\"\n >\n {{ filteredEmojis.length > 0 ? searchResultsLabel : searchNoResultsLabel }}\n </p>\n <div\n v-else\n ref=\"tabCategoryRef\"\n class=\"d-emoji-picker__category d-emoji-picker__alignment\"\n >\n <p>\n {{ fixedLabel }}\n </p>\n </div>\n <div\n v-for=\"(tabLabel, indexTab) in tabLabels\"\n v-show=\"!emojiFilter\"\n :key=\"indexTab\"\n :ref=\"tabLabel.ref\"\n class=\"d-emoji-picker__alignment\"\n >\n <p\n v-if=\"indexTab\"\n >\n {{ tabLabel.label }}\n </p>\n <div\n class=\"d-emoji-picker__tab\"\n >\n <button\n v-for=\"(emoji, indexEmoji) in\n (emojis[tabs[indexTab] + skinTone] ? emojis[tabs[indexTab] + skinTone] : emojis[tabs[indexTab]])\"\n :key=\"emoji.shortname\"\n :ref=\"el => { if (el) setEmojiRef(el, indexTab, indexEmoji) }\"\n type=\"button\"\n :aria-label=\"emoji.name\"\n @click=\"selectEmoji(emoji)\"\n @focusin=\"highlightEmoji(emoji)\"\n @focusout=\"highlightEmoji(null)\"\n @mouseover=\"highlightEmoji(emoji)\"\n @mouseleave=\"highlightEmoji(null)\"\n @keydown=\"event => handleKeyDown(event, indexTab, indexEmoji, emoji)\"\n >\n <img\n class=\"d-icon d-icon--size-500\"\n :alt=\"emoji.name\"\n :aria-label=\"emoji.name\"\n :title=\"emoji.name\"\n :src=\"getImgSrc(emoji.unicode_character)\"\n @error=\"handleImageError\"\n >\n </button>\n </div>\n </div>\n <div\n v-if=\"emojiFilter\"\n class=\"d-emoji-picker__alignment\"\n >\n <div\n class=\"d-emoji-picker__tab \"\n data-qa=\"filtered-emojis\"\n >\n <button\n v-for=\"(emoji, index) in filteredEmojis\"\n :key=\"emoji.shortname\"\n :ref=\"el => { if (el) setFilteredRef(el, index) }\"\n type=\"button\"\n :aria-label=\"emoji.name\"\n :class=\"{\n 'hover-emoji': (index === 0 && hoverFirstEmoji),\n }\"\n @click=\"selectEmoji(emoji)\"\n @focusin=\"highlightEmoji(emoji)\"\n @focusout=\"highlightEmoji(null)\"\n @mouseover=\"hoverEmoji(emoji)\"\n @mouseleave=\"hoverEmoji(null)\"\n @keydown=\"event => handleKeyDownFilteredEmojis(event, index, emoji)\"\n >\n <img\n class=\"d-icon d-icon--size-500\"\n :alt=\"emoji.name\"\n :aria-label=\"emoji.name\"\n :title=\"emoji.name\"\n :src=\"`${CDN_URL + emoji.unicode_character}.png`\"\n >\n </button>\n </div>\n </div>\n </div>\n </div>\n</template>\n\n<script setup>\n/* eslint-disable max-len */\n/* eslint-disable max-lines */\nimport { emojisGrouped as emojis } from '@dialpad/dialtone-emojis';\nimport { computed, onMounted, onUnmounted, ref, watch, nextTick } from 'vue';\nimport { CDN_URL, ARROW_KEYS } from '@/components/emoji_picker/emoji_picker_constants';\nimport { useKeyboardNavigation } from '@/components/emoji_picker/composables/useKeyboardNavigation';\n\nconst props = defineProps({\n /**\n * The filter to apply to the emoji list\n * @type {String}\n * @default ''\n */\n emojiFilter: {\n type: String,\n default: '',\n },\n\n /**\n * The skin tone to apply to the emoji list\n * @type {String}\n * @required\n */\n skinTone: {\n type: String,\n required: true,\n },\n\n /**\n * The labels for the tabset\n * @type {Array}\n * @required\n */\n tabsetLabels: {\n type: Array,\n required: true,\n },\n\n selectedTabset: {\n type: Object,\n required: true,\n },\n\n /**\n * The label for the search results tab\n * @type {String}\n * @required\n */\n searchResultsLabel: {\n type: String,\n required: true,\n },\n\n searchNoResultsLabel: {\n type: String,\n required: true,\n },\n\n /**\n * The list of recently used emojis\n * @type {Array}\n */\n recentlyUsedEmojis: {\n type: Array,\n default: () => [],\n },\n});\n\nconst emits = defineEmits([\n /**\n * Emitted when the user hover over an emoji\n * @event highlighted-emoji\n * @param {Object} emoji - The emoji data that was hovered\n */\n 'highlighted-emoji',\n\n /**\n * Emitted when the user select an emoji\n * @event selected-emoji\n * @param {Object} emoji - The emoji data that was selected\n */\n 'selected-emoji',\n\n /**\n * Emitted when the user scroll into an emoji tab\n * @event scroll-into-tab\n * @param {Number} tab-index - The tab that was scrolled into\n */\n 'scroll-into-tab',\n\n /**\n * Emitted when the user reach the end of the emoji list\n * @event focus-skin-selector\n */\n 'focus-skin-selector',\n\n /**\n * Emitted when the user shift tab in first tab of emoji selector\n * @event focus-search-input\n */\n 'focus-search-input',\n]);\n\nconst {\n emojiFilteredRefs,\n isFiltering,\n hoverFirstEmoji,\n setEmojiRef,\n setFilteredRef,\n focusEmoji,\n handleArrowNavigationFiltered,\n handleArrowNavigation,\n} = useKeyboardNavigation();\n\n/**\n * The ref for the tab category\n * This is used to display the fixed label\n */\nconst tabCategoryRef = ref(null);\n\n/**\n * The ref for the list\n * This is used to display the tabs\n */\nconst listRef = ref(null);\n\n/**\n * The ref for the tab label observer\n * This is used to update the fixed label\n */\nconst tabLabelObserver = ref(null);\n\n/**\n * The list of tabs\n * This is used to display the tabs\n */\nconst TABS_DATA = ['Recently used', 'People', 'Nature', 'Food', 'Activity', 'Travel', 'Objects', 'Symbols', 'Flags'];\n\n/**\n * The list of tab labels\n * This is used to display the tabs\n * This is a computed property because it will check if the recently used emojis list is empty\n * If it is empty, it will remove the recently used tab\n */\nconst tabLabels = computed(() => {\n return props.recentlyUsedEmojis.length\n ? props.tabsetLabels.map((label) => ({ label, ref: ref(null) }))\n : props.tabsetLabels.slice(1).map((label) => ({ label, ref: ref(null) }));\n});\n\n/**\n * The label of the fixed tab\n * This is used to display the fixed label\n */\nconst fixedLabel = ref(tabLabels.value[0].label);\n\n/**\n * The list of tabs\n * This is used to display the tabs\n * This is a computed property because it will check if the recently used emojis list is empty\n * If it is empty, it will remove the recently used tab\n * The difference between this and the tab labels is that this one will set the structure of tabs\n * and the tab labels will set the labels\n */\nconst tabs = computed(() => {\n return props.recentlyUsedEmojis.length ? TABS_DATA : TABS_DATA.slice(1);\n});\n\n/**\n * The list of current emojis that match the filter\n * This will be updated when the emojiFilter changes\n * This is used to display the search results\n * The difference between this and the current emojis list is that this one will not have the skin tone applied\n */\nconst filteredEmojis = ref([]);\n\n/**\n * The current emojis list we are displaying\n * This will be updated when the skin tone changes\n * The difference between this and the emojis list is that this one will have only the skin tone applied\n */\nconst currentEmojis = computed(() => {\n return [\n ...emojis[`People${props.skinTone}`],\n ...emojis.Nature,\n ...emojis.Food,\n ...emojis[`Activity${props.skinTone}`],\n ...emojis.Travel,\n ...emojis[`Objects${props.skinTone}`],\n ...emojis.Symbols,\n ...emojis.Flags,\n ];\n});\n\n/**\n * This will trigger the searchByNameAndKeywords function with debounce of 300 milliseconds\n */\nconst debouncedSearch = debounce(() => {\n // We clean the emojiFilteredRefs to have an updated ref list for the search results\n emojiFilteredRefs.value = [];\n searchByNameAndKeywords();\n});\n\n/**\n * Update the current emojis list on skin tone changes\n * Also update the filtered emojis list\n * @listens skinTone\n */\nwatch(currentEmojis, () => {\n searchByNameAndKeywords();\n}, { immediate: true });\n\n/**\n * Update the recently used emojis list on recently used emojis prop changes\n * @listens recentlyUsedEmojis\n */\nwatch(() => props.recentlyUsedEmojis,\n () => {\n emojis['Recently used'] = props.recentlyUsedEmojis;\n }, { immediate: true });\n\n/**\n * Search for emojis by name and keywords\n * Will update the filtered emojis list on emojiFilter update\n * @listens emojiFilter\n */\nwatch(() => props.emojiFilter, () => {\n resetScroll();\n if (props.emojiFilter) {\n isFiltering.value = true;\n } else {\n isFiltering.value = false;\n // If the emoji filter is empty, emit null to remove the highlighted emoji\n // of the previous search\n highlightEmoji(null);\n }\n debouncedSearch();\n});\n\nwatch(\n () => props.selectedTabset,\n (tab) => {\n scrollToTab(tab.tabId);\n },\n { deep: true },\n);\n\nfunction hoverEmoji (emoji, isFirst = false) {\n hoverFirstEmoji.value = isFirst;\n emits('highlighted-emoji', emoji);\n}\n\n/**\n * Filters an array of emoji objects based on a search string that matches both the name and keywords.\n * Will update the filtered emojis list\n */\nfunction searchByNameAndKeywords () {\n const searchStr = props.emojiFilter.toLowerCase();\n filteredEmojis.value = currentEmojis.value.filter(obj => {\n const nameIncludesSearchStr = obj.name.toLowerCase().includes(searchStr);\n const keywordsIncludeSearchStr = obj.keywords.some(keyword => keyword.toLowerCase().includes(searchStr));\n return nameIncludesSearchStr || keywordsIncludeSearchStr;\n });\n nextTick(() => {\n if (searchStr) {\n hoverEmoji(filteredEmojis.value[0], true);\n }\n });\n}\n\nfunction debounce (fn, delay = 300) {\n let timeout;\n\n return (...args) => {\n clearTimeout(timeout);\n timeout = setTimeout(() => fn(...args), delay);\n };\n}\n\nfunction getImgSrc (emoji) {\n return `${CDN_URL + emoji}.png`;\n}\n\n/**\n * Handle image error - We hide the entire button if the image is not found\n */\nfunction handleImageError (event) {\n event.target.parentNode.style.display = 'none';\n}\n\n/**\n * Scroll to the selected tab\n */\nfunction scrollToTab (tabIndex, focusFirstEmoji = true) {\n const tabLabel = tabLabels.value[tabIndex - 1];\n const tabElement = tabLabel.ref.value[0];\n\n nextTick(() => {\n const container = listRef.value;\n const offsetTop = tabIndex === 1 ? 0 : tabElement.offsetTop - 15;\n\n container.scrollTop = offsetTop;\n\n if (focusFirstEmoji) {\n focusEmoji((tabIndex - 1), 0);\n }\n });\n}\n\nfunction resetScroll () {\n const container = listRef.value;\n\n container.scrollTop = 0;\n}\n\n/**\n * This code creates an IntersectionObserver object that monitors the intersection between\n * the root element (tabCategoryRef) and its targets (the child elements of listRef),\n * and updates the value of the fixedLabel variable accordingly.\n */\nfunction setTabLabelObserver () {\n /**\n * The code extracts the target element and its index from the IntersectionObserverEntry object,\n * and checks whether the target intersects with the root and is positioned above or below it.\n */\n tabLabelObserver.value = new IntersectionObserver(async (entries) => {\n // eslint-disable-next-line complexity\n entries.forEach(entry => {\n const { target } = entry;\n const index = parseInt(target.dataset.index);\n\n /**\n * If the target is positioned above the root,\n * the code updates the value of the fixed label to the label of the previous tab,\n * or the first tab if the current tab is the first one. If the target is positioned below the root, the code\n * updates the value of the fixed label to the label of the current tab.\n * If the target stops intersecting with the root and its index is 1 (the second tab),\n * the code updates the value of the fixed label to the label of the first tab.\n * NOTES:\n * This last condition is needed because sometimes it is\n * not detect the intersection between the root and the target.\n * We also provide a 50 pixels offset to the root element in the first condition to always get the\n * first tab if it has fewer emojis, because in some cases if you quickly scroll the observer does not detect it.\n */\n if (entry.isIntersecting && target.offsetTop <= tabCategoryRef.value.offsetTop + 50) {\n fixedLabel.value = tabLabels.value[index - 1]?.label ?? tabLabels.value[0]?.label;\n emits('scroll-into-tab', index - 1);\n } else if (entry.boundingClientRect.bottom <= tabCategoryRef.value?.getBoundingClientRect().bottom) {\n emits('scroll-into-tab', index);\n fixedLabel.value = tabLabels.value[index]?.label;\n } else if (index === 1) {\n emits('scroll-into-tab', index);\n fixedLabel.value = tabLabels.value[0]?.label;\n }\n });\n });\n\n /**\n * The tabLabelObserver is set to observe the root element and all its children elements with\n * the IntersectionObserver object, and sets their data-index attribute to their index.\n */\n tabLabelObserver.value.observe(tabCategoryRef.value);\n\n Array.from(listRef.value.children).forEach((child, index) => {\n tabLabelObserver.value.observe(child);\n child.dataset.index = index;\n });\n}\n\nconst handleKeyDownFilteredEmojis = (event, indexEmoji, emoji) => {\n event.preventDefault();\n\n if (Object.values(ARROW_KEYS).includes(event.key)) {\n handleArrowNavigationFiltered(event.key, indexEmoji);\n return;\n }\n\n switch (event.key) {\n case 'Tab':\n emits('focus-skin-selector');\n break;\n case 'Enter':\n selectEmoji(emoji);\n break;\n default:\n break;\n }\n};\n\n/* eslint-disable-next-line complexity */\nconst handleKeyDown = (event, indexTab, indexEmoji, emoji) => {\n event.preventDefault();\n\n if (Object.values(ARROW_KEYS).includes(event.key)) {\n handleArrowNavigation(event.key, indexTab, indexEmoji);\n return;\n }\n\n switch (event.key) {\n case 'Tab':\n if (event.shiftKey) {\n if (focusEmoji(indexTab, 0) && indexTab > 0) {\n scrollToTab(indexTab, true);\n } else {\n scrollToTab(1, false);\n emits('focus-search-input');\n }\n } else {\n if (focusEmoji(indexTab + 1, 0)) {\n scrollToTab(indexTab + 1 + 1, false);\n } else {\n // We are on the last emoji tabset, jump to the skin selector\n emits('focus-skin-selector');\n }\n }\n break;\n\n case 'Enter':\n selectEmoji(emoji);\n break;\n\n default:\n break;\n }\n};\n\nfunction selectEmoji (emoji) {\n emits('selected-emoji', emoji);\n}\n\nfunction highlightEmoji (emoji) {\n emits('highlighted-emoji', emoji);\n}\n\nfunction focusEmojiSelector () {\n focusEmoji(0, 0);\n}\n\nfunction focusLastEmoji () {\n scrollToTab(tabs.value.length, true);\n}\n\nonMounted(() => {\n setTabLabelObserver();\n});\n\nonUnmounted(() => {\n tabLabelObserver.value.disconnect();\n});\n\ndefineExpose({\n focusEmojiSelector,\n focusLastEmoji,\n});\n</script>\n"],"names":["emojis"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"emoji_selector.vue.js","sources":["../../../../components/emoji_picker/modules/emoji_selector.vue"],"sourcesContent":["<template>\n <div\n class=\"d-emoji-picker__selector\"\n >\n <div\n id=\"d-emoji-picker-list\"\n ref=\"listRef\"\n class=\"d-emoji-picker__list\"\n >\n <p\n v-if=\"emojiFilter\"\n class=\"d-emoji-picker__search-label d-emoji-picker__alignment\"\n >\n {{ filteredEmojis.length > 0 ? searchResultsLabel : searchNoResultsLabel }}\n </p>\n <div\n v-else\n ref=\"tabCategoryRef\"\n class=\"d-emoji-picker__category d-emoji-picker__alignment\"\n >\n <p>\n {{ fixedLabel }}\n </p>\n </div>\n <div\n v-for=\"(tabLabel, indexTab) in tabLabels\"\n v-show=\"!emojiFilter\"\n :key=\"indexTab\"\n :ref=\"tabLabel.ref\"\n class=\"d-emoji-picker__alignment\"\n >\n <p\n v-if=\"indexTab\"\n >\n {{ tabLabel.label }}\n </p>\n <div\n class=\"d-emoji-picker__tab\"\n >\n <button\n v-for=\"(emoji, indexEmoji) in\n (emojis[tabs[indexTab] + skinTone] ? emojis[tabs[indexTab] + skinTone] : emojis[tabs[indexTab]])\"\n :key=\"emoji.shortname\"\n :ref=\"el => { if (el) setEmojiRef(el, indexTab, indexEmoji) }\"\n type=\"button\"\n :aria-label=\"emoji.name\"\n @click=\"event => selectEmoji(emoji, event)\"\n @focusin=\"highlightEmoji(emoji)\"\n @focusout=\"highlightEmoji(null)\"\n @mouseover=\"highlightEmoji(emoji)\"\n @mouseleave=\"highlightEmoji(null)\"\n @keydown=\"event => handleKeyDown(event, indexTab, indexEmoji, emoji)\"\n >\n <img\n class=\"d-icon d-icon--size-500\"\n :alt=\"emoji.name\"\n :aria-label=\"emoji.name\"\n :title=\"emoji.name\"\n :src=\"getImgSrc(emoji.unicode_character)\"\n @error=\"handleImageError\"\n >\n </button>\n </div>\n </div>\n <div\n v-if=\"emojiFilter\"\n class=\"d-emoji-picker__alignment\"\n >\n <div\n class=\"d-emoji-picker__tab \"\n data-qa=\"filtered-emojis\"\n >\n <button\n v-for=\"(emoji, index) in filteredEmojis\"\n :key=\"emoji.shortname\"\n :ref=\"el => { if (el) setFilteredRef(el, index) }\"\n type=\"button\"\n :aria-label=\"emoji.name\"\n :class=\"{\n 'hover-emoji': (index === 0 && hoverFirstEmoji),\n }\"\n @click=\"event => selectEmoji(emoji, event)\"\n @focusin=\"highlightEmoji(emoji)\"\n @focusout=\"highlightEmoji(null)\"\n @mouseover=\"hoverEmoji(emoji)\"\n @mouseleave=\"hoverEmoji(null)\"\n @keydown=\"event => handleKeyDownFilteredEmojis(event, index, emoji)\"\n >\n <img\n class=\"d-icon d-icon--size-500\"\n :alt=\"emoji.name\"\n :aria-label=\"emoji.name\"\n :title=\"emoji.name\"\n :src=\"`${CDN_URL + emoji.unicode_character}.png`\"\n >\n </button>\n </div>\n </div>\n </div>\n </div>\n</template>\n\n<script setup>\n/* eslint-disable max-len */\n/* eslint-disable max-lines */\nimport { emojisGrouped as emojis } from '@dialpad/dialtone-emojis';\nimport { computed, onMounted, onUnmounted, ref, watch, nextTick } from 'vue';\nimport { CDN_URL, ARROW_KEYS } from '@/components/emoji_picker/emoji_picker_constants';\nimport { useKeyboardNavigation } from '@/components/emoji_picker/composables/useKeyboardNavigation';\n\nconst props = defineProps({\n /**\n * The filter to apply to the emoji list\n * @type {String}\n * @default ''\n */\n emojiFilter: {\n type: String,\n default: '',\n },\n\n /**\n * The skin tone to apply to the emoji list\n * @type {String}\n * @required\n */\n skinTone: {\n type: String,\n required: true,\n },\n\n /**\n * The labels for the tabset\n * @type {Array}\n * @required\n */\n tabsetLabels: {\n type: Array,\n required: true,\n },\n\n selectedTabset: {\n type: Object,\n required: true,\n },\n\n /**\n * The label for the search results tab\n * @type {String}\n * @required\n */\n searchResultsLabel: {\n type: String,\n required: true,\n },\n\n searchNoResultsLabel: {\n type: String,\n required: true,\n },\n\n /**\n * The list of recently used emojis\n * @type {Array}\n */\n recentlyUsedEmojis: {\n type: Array,\n default: () => [],\n },\n});\n\nconst emits = defineEmits([\n /**\n * Emitted when the user hover over an emoji\n * @event highlighted-emoji\n * @param {Object} emoji - The emoji data that was hovered\n */\n 'highlighted-emoji',\n\n /**\n * Emitted when the user select an emoji\n * @event selected-emoji\n * @param {Object} emoji - The emoji data that was selected\n */\n 'selected-emoji',\n\n /**\n * Emitted when the user scroll into an emoji tab\n * @event scroll-into-tab\n * @param {Number} tab-index - The tab that was scrolled into\n */\n 'scroll-into-tab',\n\n /**\n * Emitted when the user reach the end of the emoji list\n * @event focus-skin-selector\n */\n 'focus-skin-selector',\n\n /**\n * Emitted when the user shift tab in first tab of emoji selector\n * @event focus-search-input\n */\n 'focus-search-input',\n]);\n\nconst {\n emojiFilteredRefs,\n isFiltering,\n hoverFirstEmoji,\n setEmojiRef,\n setFilteredRef,\n focusEmoji,\n handleArrowNavigationFiltered,\n handleArrowNavigation,\n} = useKeyboardNavigation();\n\n/**\n * The ref for the tab category\n * This is used to display the fixed label\n */\nconst tabCategoryRef = ref(null);\n\n/**\n * The ref for the list\n * This is used to display the tabs\n */\nconst listRef = ref(null);\n\n/**\n * The ref for the tab label observer\n * This is used to update the fixed label\n */\nconst tabLabelObserver = ref(null);\n\n/**\n * The list of tabs\n * This is used to display the tabs\n */\nconst TABS_DATA = ['Recently used', 'People', 'Nature', 'Food', 'Activity', 'Travel', 'Objects', 'Symbols', 'Flags'];\n\n/**\n * The list of tab labels\n * This is used to display the tabs\n * This is a computed property because it will check if the recently used emojis list is empty\n * If it is empty, it will remove the recently used tab\n */\nconst tabLabels = computed(() => {\n return props.recentlyUsedEmojis.length\n ? props.tabsetLabels.map((label) => ({ label, ref: ref(null) }))\n : props.tabsetLabels.slice(1).map((label) => ({ label, ref: ref(null) }));\n});\n\n/**\n * The label of the fixed tab\n * This is used to display the fixed label\n */\nconst fixedLabel = ref(tabLabels.value[0].label);\n\n/**\n * The list of tabs\n * This is used to display the tabs\n * This is a computed property because it will check if the recently used emojis list is empty\n * If it is empty, it will remove the recently used tab\n * The difference between this and the tab labels is that this one will set the structure of tabs\n * and the tab labels will set the labels\n */\nconst tabs = computed(() => {\n return props.recentlyUsedEmojis.length ? TABS_DATA : TABS_DATA.slice(1);\n});\n\n/**\n * The list of current emojis that match the filter\n * This will be updated when the emojiFilter changes\n * This is used to display the search results\n * The difference between this and the current emojis list is that this one will not have the skin tone applied\n */\nconst filteredEmojis = ref([]);\n\n/**\n * The current emojis list we are displaying\n * This will be updated when the skin tone changes\n * The difference between this and the emojis list is that this one will have only the skin tone applied\n */\nconst currentEmojis = computed(() => {\n return [\n ...emojis[`People${props.skinTone}`],\n ...emojis.Nature,\n ...emojis.Food,\n ...emojis[`Activity${props.skinTone}`],\n ...emojis.Travel,\n ...emojis[`Objects${props.skinTone}`],\n ...emojis.Symbols,\n ...emojis.Flags,\n ];\n});\n\n/**\n * This will trigger the searchByNameAndKeywords function with debounce of 300 milliseconds\n */\nconst debouncedSearch = debounce(() => {\n // We clean the emojiFilteredRefs to have an updated ref list for the search results\n emojiFilteredRefs.value = [];\n searchByNameAndKeywords();\n});\n\n/**\n * Update the current emojis list on skin tone changes\n * Also update the filtered emojis list\n * @listens skinTone\n */\nwatch(currentEmojis, () => {\n searchByNameAndKeywords();\n}, { immediate: true });\n\n/**\n * Update the recently used emojis list on recently used emojis prop changes\n * @listens recentlyUsedEmojis\n */\nwatch(() => props.recentlyUsedEmojis,\n () => {\n emojis['Recently used'] = props.recentlyUsedEmojis;\n }, { immediate: true });\n\n/**\n * Search for emojis by name and keywords\n * Will update the filtered emojis list on emojiFilter update\n * @listens emojiFilter\n */\nwatch(() => props.emojiFilter, () => {\n resetScroll();\n if (props.emojiFilter) {\n isFiltering.value = true;\n } else {\n isFiltering.value = false;\n // If the emoji filter is empty, emit null to remove the highlighted emoji\n // of the previous search\n highlightEmoji(null);\n }\n debouncedSearch();\n});\n\nwatch(\n () => props.selectedTabset,\n (tab) => {\n scrollToTab(tab.tabId);\n },\n { deep: true },\n);\n\nfunction hoverEmoji (emoji, isFirst = false) {\n hoverFirstEmoji.value = isFirst;\n emits('highlighted-emoji', emoji);\n}\n\n/**\n * Filters an array of emoji objects based on a search string that matches both the name and keywords.\n * Will update the filtered emojis list\n */\nfunction searchByNameAndKeywords () {\n const searchStr = props.emojiFilter.toLowerCase();\n filteredEmojis.value = currentEmojis.value.filter(obj => {\n const nameIncludesSearchStr = obj.name.toLowerCase().includes(searchStr);\n const keywordsIncludeSearchStr = obj.keywords.some(keyword => keyword.toLowerCase().includes(searchStr));\n return nameIncludesSearchStr || keywordsIncludeSearchStr;\n });\n nextTick(() => {\n if (searchStr) {\n hoverEmoji(filteredEmojis.value[0], true);\n }\n });\n}\n\nfunction debounce (fn, delay = 300) {\n let timeout;\n\n return (...args) => {\n clearTimeout(timeout);\n timeout = setTimeout(() => fn(...args), delay);\n };\n}\n\nfunction getImgSrc (emoji) {\n return `${CDN_URL + emoji}.png`;\n}\n\n/**\n * Handle image error - We hide the entire button if the image is not found\n */\nfunction handleImageError (event) {\n event.target.parentNode.style.display = 'none';\n}\n\n/**\n * Scroll to the selected tab\n */\nfunction scrollToTab (tabIndex, focusFirstEmoji = true) {\n const tabLabel = tabLabels.value[tabIndex - 1];\n const tabElement = tabLabel.ref.value[0];\n\n nextTick(() => {\n const container = listRef.value;\n const offsetTop = tabIndex === 1 ? 0 : tabElement.offsetTop - 15;\n\n container.scrollTop = offsetTop;\n\n if (focusFirstEmoji) {\n focusEmoji((tabIndex - 1), 0);\n }\n });\n}\n\nfunction resetScroll () {\n const container = listRef.value;\n\n container.scrollTop = 0;\n}\n\n/**\n * This code creates an IntersectionObserver object that monitors the intersection between\n * the root element (tabCategoryRef) and its targets (the child elements of listRef),\n * and updates the value of the fixedLabel variable accordingly.\n */\nfunction setTabLabelObserver () {\n /**\n * The code extracts the target element and its index from the IntersectionObserverEntry object,\n * and checks whether the target intersects with the root and is positioned above or below it.\n */\n tabLabelObserver.value = new IntersectionObserver(async (entries) => {\n // eslint-disable-next-line complexity\n entries.forEach(entry => {\n const { target } = entry;\n const index = parseInt(target.dataset.index);\n\n /**\n * If the target is positioned above the root,\n * the code updates the value of the fixed label to the label of the previous tab,\n * or the first tab if the current tab is the first one. If the target is positioned below the root, the code\n * updates the value of the fixed label to the label of the current tab.\n * If the target stops intersecting with the root and its index is 1 (the second tab),\n * the code updates the value of the fixed label to the label of the first tab.\n * NOTES:\n * This last condition is needed because sometimes it is\n * not detect the intersection between the root and the target.\n * We also provide a 50 pixels offset to the root element in the first condition to always get the\n * first tab if it has fewer emojis, because in some cases if you quickly scroll the observer does not detect it.\n */\n if (entry.isIntersecting && target.offsetTop <= tabCategoryRef.value.offsetTop + 50) {\n fixedLabel.value = tabLabels.value[index - 1]?.label ?? tabLabels.value[0]?.label;\n emits('scroll-into-tab', index - 1);\n } else if (entry.boundingClientRect.bottom <= tabCategoryRef.value?.getBoundingClientRect().bottom) {\n emits('scroll-into-tab', index);\n fixedLabel.value = tabLabels.value[index]?.label;\n } else if (index === 1) {\n emits('scroll-into-tab', index);\n fixedLabel.value = tabLabels.value[0]?.label;\n }\n });\n });\n\n /**\n * The tabLabelObserver is set to observe the root element and all its children elements with\n * the IntersectionObserver object, and sets their data-index attribute to their index.\n */\n tabLabelObserver.value.observe(tabCategoryRef.value);\n\n Array.from(listRef.value.children).forEach((child, index) => {\n tabLabelObserver.value.observe(child);\n child.dataset.index = index;\n });\n}\n\nconst handleKeyDownFilteredEmojis = (event, indexEmoji, emoji) => {\n event.preventDefault();\n\n if (Object.values(ARROW_KEYS).includes(event.key)) {\n handleArrowNavigationFiltered(event.key, indexEmoji);\n return;\n }\n\n switch (event.key) {\n case 'Tab':\n emits('focus-skin-selector');\n break;\n case 'Enter':\n selectEmoji(emoji, event);\n break;\n default:\n break;\n }\n};\n\n/* eslint-disable-next-line complexity */\nconst handleKeyDown = (event, indexTab, indexEmoji, emoji) => {\n event.preventDefault();\n\n if (Object.values(ARROW_KEYS).includes(event.key)) {\n handleArrowNavigation(event.key, indexTab, indexEmoji);\n return;\n }\n\n switch (event.key) {\n case 'Tab':\n if (event.shiftKey) {\n if (focusEmoji(indexTab, 0) && indexTab > 0) {\n scrollToTab(indexTab, true);\n } else {\n scrollToTab(1, false);\n emits('focus-search-input');\n }\n } else {\n if (focusEmoji(indexTab + 1, 0)) {\n scrollToTab(indexTab + 1 + 1, false);\n } else {\n // We are on the last emoji tabset, jump to the skin selector\n emits('focus-skin-selector');\n }\n }\n break;\n\n case 'Enter':\n selectEmoji(emoji, event);\n break;\n\n default:\n break;\n }\n};\n\nfunction selectEmoji (emoji, event) {\n emits('selected-emoji', { ...emoji, shift_key: event.shiftKey });\n}\n\nfunction highlightEmoji (emoji) {\n emits('highlighted-emoji', emoji);\n}\n\nfunction focusEmojiSelector () {\n focusEmoji(0, 0);\n}\n\nfunction focusLastEmoji () {\n scrollToTab(tabs.value.length, true);\n}\n\nonMounted(() => {\n setTabLabelObserver();\n});\n\nonUnmounted(() => {\n tabLabelObserver.value.disconnect();\n});\n\ndefineExpose({\n focusEmojiSelector,\n focusLastEmoji,\n});\n</script>\n"],"names":["emojis"],"mappings":"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"}
|
|
@@ -3,6 +3,7 @@ Object.defineProperties(exports, { __esModule: { value: true }, [Symbol.toString
|
|
|
3
3
|
const common_emoji = require("../../common/emoji.cjs");
|
|
4
4
|
const vue = require("vue");
|
|
5
5
|
const icon_constants = require("../icon/icon_constants.cjs");
|
|
6
|
+
const regexCombinedEmojis = require("regex-combined-emojis");
|
|
6
7
|
const emoji = require("../emoji/emoji.vue.cjs");
|
|
7
8
|
const _sfc_main = {
|
|
8
9
|
name: "DtEmojiTextWrapper",
|
|
@@ -44,7 +45,8 @@ const _sfc_main = {
|
|
|
44
45
|
const regexp = new RegExp(`(${replaceList.join("|")})`, "g");
|
|
45
46
|
const items = textContent.split(regexp);
|
|
46
47
|
return items.filter((item) => item.trim() !== "").map((item) => {
|
|
47
|
-
|
|
48
|
+
regexp.lastIndex = 0;
|
|
49
|
+
if (replaceList.includes(item) || regexp.test(item)) {
|
|
48
50
|
return vue.h(emoji.default, { code: item, size: this.size });
|
|
49
51
|
}
|
|
50
52
|
return vue.h("span", { class: "d-emoji-text-wrapper__text" }, item);
|
|
@@ -73,8 +75,7 @@ const _sfc_main = {
|
|
|
73
75
|
*/
|
|
74
76
|
searchCodes(textContent) {
|
|
75
77
|
const shortcodes = common_emoji.findShortCodes(textContent);
|
|
76
|
-
const
|
|
77
|
-
const replaceList = [...shortcodes, ...emojis];
|
|
78
|
+
const replaceList = [...shortcodes, regexCombinedEmojis.emojiPattern];
|
|
78
79
|
if (replaceList.length === 0) return textContent;
|
|
79
80
|
return this.replaceDtEmojis(replaceList, textContent);
|
|
80
81
|
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"emoji_text_wrapper.vue.cjs","sources":["../../../components/emoji_text_wrapper/emoji_text_wrapper.vue"],"sourcesContent":["<script>\nimport { DtEmoji } from '../emoji';\nimport {
|
|
1
|
+
{"version":3,"file":"emoji_text_wrapper.vue.cjs","sources":["../../../components/emoji_text_wrapper/emoji_text_wrapper.vue"],"sourcesContent":["<script>\nimport { DtEmoji } from '../emoji';\nimport { findShortCodes } from '@/common/emoji';\nimport { h } from 'vue';\nimport { ICON_SIZE_MODIFIERS } from '@/components/icon/icon_constants';\nimport { emojiPattern } from 'regex-combined-emojis';\n\n/**\n * Wrapper to find and replace shortcodes like :smile: or unicode chars such as 😄 with our custom Emojis implementation.\n * @see https://dialtone.dialpad.com/components/emoji_text_wrapper.html\n */\nexport default {\n name: 'DtEmojiTextWrapper',\n\n components: {\n DtEmoji,\n },\n\n props: {\n /**\n * Element type (tag name) to use for the wrapper.\n */\n elementType: {\n type: String,\n default: 'div',\n },\n\n /**\n * The icon size to render the emojis at: 100 to 800\n */\n size: {\n type: String,\n default: '500',\n validator: (t) => Object.keys(ICON_SIZE_MODIFIERS).includes(t),\n },\n },\n\n data () {\n return {\n loadingEmojiJson: true,\n };\n },\n\n async created () {\n this.loadingEmojiJson = false;\n },\n\n methods: {\n /**\n * Replaces the valid codes from the text content with a DtEmoji component.\n * @returns {Array<VNode|string>}\n */\n replaceDtEmojis (replaceList, textContent) {\n if (!replaceList.length) return textContent;\n\n const regexp = new RegExp(`(${replaceList.join('|')})`, 'g');\n const items = textContent.split(regexp);\n\n return items\n .filter(item => item.trim() !== '')\n .map((item) => {\n // Reset the regexp index to 0 to start from the beginning\n // Otherwise, it will start from the last index\n regexp.lastIndex = 0;\n if (replaceList.includes(item) || regexp.test(item)) {\n return h(DtEmoji, { code: item, size: this.size });\n }\n return h('span', { class: 'd-emoji-text-wrapper__text' }, item);\n });\n },\n\n /**\n * Recursively search the Vue virtual DOM to find text\n * @param VNode\n * @returns {VNode|*}\n */\n searchVNodes (VNode) {\n if (typeof VNode === 'string') return this.searchCodes(VNode);\n if (typeof VNode.type === 'symbol') return this.searchCodes(VNode.children);\n if (VNode.props?.innerHTML) return this.searchVNodes(VNode.props.innerHTML);\n\n const children = Array.isArray(VNode.children) ? VNode.children : [VNode.children];\n return h(VNode.type, VNode.props, children.map(VNodeChild => this.searchVNodes(VNodeChild)));\n },\n\n // TODO: Find a way to crawl vue components\n replaceVueComponentVNodeContent (VNode) {\n //\n },\n\n /**\n * Find codes in text.\n * @param textContent string\n * @returns {Array<VNode|string>|string}\n */\n searchCodes (textContent) {\n const shortcodes = findShortCodes(textContent);\n\n const replaceList = [...shortcodes, emojiPattern];\n if (replaceList.length === 0) return textContent;\n return this.replaceDtEmojis(replaceList, textContent);\n },\n },\n\n render () {\n const defaultSlotContent = this.$slots.default ? this.$slots.default() : [];\n return h(\n this.elementType,\n {\n 'data-qa': 'emoji-text-wrapper',\n class: 'd-emoji-text-wrapper',\n },\n this.loadingEmojiJson\n ? defaultSlotContent\n : defaultSlotContent.map(VNode => this.searchVNodes(VNode)),\n );\n },\n};\n</script>\n"],"names":["DtEmoji","ICON_SIZE_MODIFIERS","h","findShortCodes","emojiPattern"],"mappings":";;;;;;;AAWA,MAAK,YAAU;AAAA,EACb,MAAM;AAAA,EAEN,YAAY;AAAA,IACV,SAAAA,MAAO;AAAA,EACR;AAAA,EAED,OAAO;AAAA;AAAA;AAAA;AAAA,IAIL,aAAa;AAAA,MACX,MAAM;AAAA,MACN,SAAS;AAAA,IACV;AAAA;AAAA;AAAA;AAAA,IAKD,MAAM;AAAA,MACJ,MAAM;AAAA,MACN,SAAS;AAAA,MACT,WAAW,CAAC,MAAM,OAAO,KAAKC,kCAAmB,EAAE,SAAS,CAAC;AAAA,IAC9D;AAAA,EACF;AAAA,EAED,OAAQ;AACN,WAAO;AAAA,MACL,kBAAkB;AAAA;EAErB;AAAA,EAED,MAAM,UAAW;AACf,SAAK,mBAAmB;AAAA,EACzB;AAAA,EAED,SAAS;AAAA;AAAA;AAAA;AAAA;AAAA,IAKP,gBAAiB,aAAa,aAAa;AACzC,UAAI,CAAC,YAAY,OAAQ,QAAO;AAEhC,YAAM,SAAS,IAAI,OAAO,IAAI,YAAY,KAAK,GAAG,CAAC,KAAK,GAAG;AAC3D,YAAM,QAAQ,YAAY,MAAM,MAAM;AAEtC,aAAO,MACJ,OAAO,UAAQ,KAAK,KAAI,MAAO,EAAE,EACjC,IAAI,CAAC,SAAS;AAGb,eAAO,YAAY;AACnB,YAAI,YAAY,SAAS,IAAI,KAAK,OAAO,KAAK,IAAI,GAAG;AACnD,iBAAOC,IAAC,EAACF,MAAO,SAAE,EAAE,MAAM,MAAM,MAAM,KAAK,KAAG,CAAG;AAAA,QACnD;AACA,eAAOE,IAAAA,EAAE,QAAQ,EAAE,OAAO,6BAA2B,GAAK,IAAI;AAAA,MAChE,CAAC;AAAA,IACJ;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,IAOD,aAAc,OAAO;;AACnB,UAAI,OAAO,UAAU,SAAU,QAAO,KAAK,YAAY,KAAK;AAC5D,UAAI,OAAO,MAAM,SAAS,SAAU,QAAO,KAAK,YAAY,MAAM,QAAQ;AAC1E,WAAI,WAAM,UAAN,mBAAa,UAAW,QAAO,KAAK,aAAa,MAAM,MAAM,SAAS;AAE1E,YAAM,WAAW,MAAM,QAAQ,MAAM,QAAQ,IAAI,MAAM,WAAW,CAAC,MAAM,QAAQ;AACjF,aAAOA,IAAC,EAAC,MAAM,MAAM,MAAM,OAAO,SAAS,IAAI,gBAAc,KAAK,aAAa,UAAU,CAAC,CAAC;AAAA,IAC5F;AAAA;AAAA,IAGD,gCAAiC,OAAO;AAAA,IAEvC;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,IAOD,YAAa,aAAa;AACxB,YAAM,aAAaC,4BAAe,WAAW;AAE7C,YAAM,cAAc,CAAC,GAAG,YAAYC,oBAAY,YAAA;AAChD,UAAI,YAAY,WAAW,EAAG,QAAO;AACrC,aAAO,KAAK,gBAAgB,aAAa,WAAW;AAAA,IACrD;AAAA,EACF;AAAA,EAED,SAAU;AACR,UAAM,qBAAqB,KAAK,OAAO,UAAU,KAAK,OAAO,QAAU,IAAE;AACzE,WAAOF,IAAC;AAAA,MACN,KAAK;AAAA,MACL;AAAA,QACE,WAAW;AAAA,QACX,OAAO;AAAA,MACR;AAAA,MACD,KAAK,mBACD,qBACA,mBAAmB,IAAI,WAAS,KAAK,aAAa,KAAK,CAAC;AAAA;EAE/D;AACH;;;"}
|
|
@@ -1,6 +1,7 @@
|
|
|
1
|
-
import { findShortCodes
|
|
1
|
+
import { findShortCodes } from "../../common/emoji.js";
|
|
2
2
|
import { h } from "vue";
|
|
3
3
|
import { ICON_SIZE_MODIFIERS } from "../icon/icon_constants.js";
|
|
4
|
+
import { emojiPattern } from "regex-combined-emojis";
|
|
4
5
|
import DtEmoji from "../emoji/emoji.vue.js";
|
|
5
6
|
const _sfc_main = {
|
|
6
7
|
name: "DtEmojiTextWrapper",
|
|
@@ -42,7 +43,8 @@ const _sfc_main = {
|
|
|
42
43
|
const regexp = new RegExp(`(${replaceList.join("|")})`, "g");
|
|
43
44
|
const items = textContent.split(regexp);
|
|
44
45
|
return items.filter((item) => item.trim() !== "").map((item) => {
|
|
45
|
-
|
|
46
|
+
regexp.lastIndex = 0;
|
|
47
|
+
if (replaceList.includes(item) || regexp.test(item)) {
|
|
46
48
|
return h(DtEmoji, { code: item, size: this.size });
|
|
47
49
|
}
|
|
48
50
|
return h("span", { class: "d-emoji-text-wrapper__text" }, item);
|
|
@@ -71,8 +73,7 @@ const _sfc_main = {
|
|
|
71
73
|
*/
|
|
72
74
|
searchCodes(textContent) {
|
|
73
75
|
const shortcodes = findShortCodes(textContent);
|
|
74
|
-
const
|
|
75
|
-
const replaceList = [...shortcodes, ...emojis];
|
|
76
|
+
const replaceList = [...shortcodes, emojiPattern];
|
|
76
77
|
if (replaceList.length === 0) return textContent;
|
|
77
78
|
return this.replaceDtEmojis(replaceList, textContent);
|
|
78
79
|
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"emoji_text_wrapper.vue.js","sources":["../../../components/emoji_text_wrapper/emoji_text_wrapper.vue"],"sourcesContent":["<script>\nimport { DtEmoji } from '../emoji';\nimport {
|
|
1
|
+
{"version":3,"file":"emoji_text_wrapper.vue.js","sources":["../../../components/emoji_text_wrapper/emoji_text_wrapper.vue"],"sourcesContent":["<script>\nimport { DtEmoji } from '../emoji';\nimport { findShortCodes } from '@/common/emoji';\nimport { h } from 'vue';\nimport { ICON_SIZE_MODIFIERS } from '@/components/icon/icon_constants';\nimport { emojiPattern } from 'regex-combined-emojis';\n\n/**\n * Wrapper to find and replace shortcodes like :smile: or unicode chars such as 😄 with our custom Emojis implementation.\n * @see https://dialtone.dialpad.com/components/emoji_text_wrapper.html\n */\nexport default {\n name: 'DtEmojiTextWrapper',\n\n components: {\n DtEmoji,\n },\n\n props: {\n /**\n * Element type (tag name) to use for the wrapper.\n */\n elementType: {\n type: String,\n default: 'div',\n },\n\n /**\n * The icon size to render the emojis at: 100 to 800\n */\n size: {\n type: String,\n default: '500',\n validator: (t) => Object.keys(ICON_SIZE_MODIFIERS).includes(t),\n },\n },\n\n data () {\n return {\n loadingEmojiJson: true,\n };\n },\n\n async created () {\n this.loadingEmojiJson = false;\n },\n\n methods: {\n /**\n * Replaces the valid codes from the text content with a DtEmoji component.\n * @returns {Array<VNode|string>}\n */\n replaceDtEmojis (replaceList, textContent) {\n if (!replaceList.length) return textContent;\n\n const regexp = new RegExp(`(${replaceList.join('|')})`, 'g');\n const items = textContent.split(regexp);\n\n return items\n .filter(item => item.trim() !== '')\n .map((item) => {\n // Reset the regexp index to 0 to start from the beginning\n // Otherwise, it will start from the last index\n regexp.lastIndex = 0;\n if (replaceList.includes(item) || regexp.test(item)) {\n return h(DtEmoji, { code: item, size: this.size });\n }\n return h('span', { class: 'd-emoji-text-wrapper__text' }, item);\n });\n },\n\n /**\n * Recursively search the Vue virtual DOM to find text\n * @param VNode\n * @returns {VNode|*}\n */\n searchVNodes (VNode) {\n if (typeof VNode === 'string') return this.searchCodes(VNode);\n if (typeof VNode.type === 'symbol') return this.searchCodes(VNode.children);\n if (VNode.props?.innerHTML) return this.searchVNodes(VNode.props.innerHTML);\n\n const children = Array.isArray(VNode.children) ? VNode.children : [VNode.children];\n return h(VNode.type, VNode.props, children.map(VNodeChild => this.searchVNodes(VNodeChild)));\n },\n\n // TODO: Find a way to crawl vue components\n replaceVueComponentVNodeContent (VNode) {\n //\n },\n\n /**\n * Find codes in text.\n * @param textContent string\n * @returns {Array<VNode|string>|string}\n */\n searchCodes (textContent) {\n const shortcodes = findShortCodes(textContent);\n\n const replaceList = [...shortcodes, emojiPattern];\n if (replaceList.length === 0) return textContent;\n return this.replaceDtEmojis(replaceList, textContent);\n },\n },\n\n render () {\n const defaultSlotContent = this.$slots.default ? this.$slots.default() : [];\n return h(\n this.elementType,\n {\n 'data-qa': 'emoji-text-wrapper',\n class: 'd-emoji-text-wrapper',\n },\n this.loadingEmojiJson\n ? defaultSlotContent\n : defaultSlotContent.map(VNode => this.searchVNodes(VNode)),\n );\n },\n};\n</script>\n"],"names":[],"mappings":";;;;;AAWA,MAAK,YAAU;AAAA,EACb,MAAM;AAAA,EAEN,YAAY;AAAA,IACV;AAAA,EACD;AAAA,EAED,OAAO;AAAA;AAAA;AAAA;AAAA,IAIL,aAAa;AAAA,MACX,MAAM;AAAA,MACN,SAAS;AAAA,IACV;AAAA;AAAA;AAAA;AAAA,IAKD,MAAM;AAAA,MACJ,MAAM;AAAA,MACN,SAAS;AAAA,MACT,WAAW,CAAC,MAAM,OAAO,KAAK,mBAAmB,EAAE,SAAS,CAAC;AAAA,IAC9D;AAAA,EACF;AAAA,EAED,OAAQ;AACN,WAAO;AAAA,MACL,kBAAkB;AAAA;EAErB;AAAA,EAED,MAAM,UAAW;AACf,SAAK,mBAAmB;AAAA,EACzB;AAAA,EAED,SAAS;AAAA;AAAA;AAAA;AAAA;AAAA,IAKP,gBAAiB,aAAa,aAAa;AACzC,UAAI,CAAC,YAAY,OAAQ,QAAO;AAEhC,YAAM,SAAS,IAAI,OAAO,IAAI,YAAY,KAAK,GAAG,CAAC,KAAK,GAAG;AAC3D,YAAM,QAAQ,YAAY,MAAM,MAAM;AAEtC,aAAO,MACJ,OAAO,UAAQ,KAAK,KAAI,MAAO,EAAE,EACjC,IAAI,CAAC,SAAS;AAGb,eAAO,YAAY;AACnB,YAAI,YAAY,SAAS,IAAI,KAAK,OAAO,KAAK,IAAI,GAAG;AACnD,iBAAO,EAAE,SAAS,EAAE,MAAM,MAAM,MAAM,KAAK,KAAG,CAAG;AAAA,QACnD;AACA,eAAO,EAAE,QAAQ,EAAE,OAAO,6BAA2B,GAAK,IAAI;AAAA,MAChE,CAAC;AAAA,IACJ;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,IAOD,aAAc,OAAO;;AACnB,UAAI,OAAO,UAAU,SAAU,QAAO,KAAK,YAAY,KAAK;AAC5D,UAAI,OAAO,MAAM,SAAS,SAAU,QAAO,KAAK,YAAY,MAAM,QAAQ;AAC1E,WAAI,WAAM,UAAN,mBAAa,UAAW,QAAO,KAAK,aAAa,MAAM,MAAM,SAAS;AAE1E,YAAM,WAAW,MAAM,QAAQ,MAAM,QAAQ,IAAI,MAAM,WAAW,CAAC,MAAM,QAAQ;AACjF,aAAO,EAAE,MAAM,MAAM,MAAM,OAAO,SAAS,IAAI,gBAAc,KAAK,aAAa,UAAU,CAAC,CAAC;AAAA,IAC5F;AAAA;AAAA,IAGD,gCAAiC,OAAO;AAAA,IAEvC;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,IAOD,YAAa,aAAa;AACxB,YAAM,aAAa,eAAe,WAAW;AAE7C,YAAM,cAAc,CAAC,GAAG,YAAY,YAAY;AAChD,UAAI,YAAY,WAAW,EAAG,QAAO;AACrC,aAAO,KAAK,gBAAgB,aAAa,WAAW;AAAA,IACrD;AAAA,EACF;AAAA,EAED,SAAU;AACR,UAAM,qBAAqB,KAAK,OAAO,UAAU,KAAK,OAAO,QAAU,IAAE;AACzE,WAAO;AAAA,MACL,KAAK;AAAA,MACL;AAAA,QACE,WAAW;AAAA,QACX,OAAO;AAAA,MACR;AAAA,MACD,KAAK,mBACD,qBACA,mBAAmB,IAAI,WAAS,KAAK,aAAa,KAAK,CAAC;AAAA;EAE/D;AACH;;"}
|
|
@@ -23,7 +23,7 @@ const _sfc_main = {
|
|
|
23
23
|
/**
|
|
24
24
|
* Type of the input.
|
|
25
25
|
* When `textarea` a `<textarea>` element will be rendered instead of an `<input>` element.
|
|
26
|
-
* @values text, password, email, number, textarea, date, time, file, tel
|
|
26
|
+
* @values text, password, email, number, textarea, date, time, file, tel, search
|
|
27
27
|
* @default 'text'
|
|
28
28
|
*/
|
|
29
29
|
type: {
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"input.vue.cjs","sources":["../../../components/input/input.vue"],"sourcesContent":["<template>\n <div\n ref=\"container\"\n :class=\"['d-input__root', { 'd-input--hidden': hidden }]\"\n data-qa=\"dt-input\"\n >\n <label\n class=\"d-input__label\"\n :aria-details=\"$slots.description || description ? descriptionKey : undefined\"\n data-qa=\"dt-input-label-wrapper\"\n >\n <!-- @slot Slot for label, defaults to label prop -->\n <slot name=\"labelSlot\">\n <div\n v-if=\"labelVisible && label\"\n ref=\"label\"\n data-qa=\"dt-input-label\"\n :class=\"[\n 'd-input__label-text',\n 'd-label',\n labelSizeClasses[size],\n ]\"\n >\n {{ label }}\n </div>\n </slot>\n <div\n v-if=\"hasSlotContent($slots.description) || description || shouldValidateLength\"\n :id=\"descriptionKey\"\n ref=\"description\"\n :class=\"[\n 'd-input__description',\n 'd-description',\n descriptionSizeClasses[size],\n ]\"\n data-qa=\"dt-input-description\"\n >\n <div\n v-if=\"hasSlotContent($slots.description) || description\"\n >\n <!-- @slot Slot for description, defaults to description prop -->\n <slot name=\"description\">{{ description }}</slot>\n </div>\n <div\n v-if=\"shouldValidateLength\"\n data-qa=\"dt-input-length-description\"\n class=\"d-input__length-description\"\n >\n {{ validationProps.length.description }}\n </div>\n </div>\n <div\n :class=\"inputWrapperClasses()\"\n :read-only=\"disabled === true ? true : undefined\"\n >\n <span\n class=\"d-input-icon d-input-icon--left\"\n data-qa=\"dt-input-left-icon-wrapper\"\n @focusout=\"onBlur\"\n >\n <!-- @slot Slot for left icon -->\n <slot\n name=\"leftIcon\"\n :icon-size=\"iconSize\"\n />\n </span>\n <textarea\n v-if=\"isTextarea\"\n ref=\"input\"\n :value=\"modelValue\"\n :name=\"name\"\n :disabled=\"disabled\"\n :autocomplete=\"$attrs.autocomplete ?? 'off'\"\n :class=\"inputClasses()\"\n :maxlength=\"shouldLimitMaxLength ? validationProps.length.max : null\"\n data-qa=\"dt-input-input\"\n v-bind=\"$attrs\"\n v-on=\"inputListeners\"\n />\n <input\n v-else\n ref=\"input\"\n :value=\"modelValue\"\n :name=\"name\"\n :type=\"type\"\n :disabled=\"disabled\"\n :autocomplete=\"$attrs.autocomplete ?? 'off'\"\n :class=\"inputClasses()\"\n :maxlength=\"shouldLimitMaxLength ? validationProps.length.max : null\"\n data-qa=\"dt-input-input\"\n v-bind=\"$attrs\"\n v-on=\"inputListeners\"\n >\n <span\n class=\"d-input-icon d-input-icon--right\"\n data-qa=\"dt-input-right-icon-wrapper\"\n @focusout=\"onBlur\"\n >\n <!-- @slot Slot for right icon -->\n <slot\n name=\"rightIcon\"\n :icon-size=\"iconSize\"\n :clear=\"clearInput\"\n />\n </span>\n </div>\n </label>\n <dt-validation-messages\n :validation-messages=\"validationMessages\"\n :show-messages=\"showMessages\"\n :class=\"messagesClass\"\n v-bind=\"messagesChildProps\"\n data-qa=\"dt-input-messages\"\n />\n </div>\n</template>\n\n<script>\n/* eslint-disable max-lines */\nimport { DESCRIPTION_SIZE_TYPES, VALIDATION_MESSAGE_TYPES } from '@/common/constants';\nimport {\n INPUT_TYPES,\n INPUT_SIZES,\n INPUT_SIZE_CLASSES,\n INPUT_ICON_SIZES,\n INPUT_STATE_CLASSES,\n DESCRIPTION_SIZE_CLASSES,\n LABEL_SIZE_CLASSES,\n} from './input_constants';\nimport {\n getUniqueString,\n getValidationState,\n hasSlotContent,\n} from '@/common/utils';\nimport { DtValidationMessages } from '@/components/validation_messages';\nimport { MessagesMixin } from '@/common/mixins/input';\n\n/**\n * An input field is an input control that allows users to enter alphanumeric information.\n * It can have a range of options and supports single line and multi-line lengths,\n * as well as varying formats, including numbers, masked passwords, etc.\n * @property {Boolean} placeholder attribute\n * @see https://dialtone.dialpad.com/components/input.html\n */\nexport default {\n name: 'DtInput',\n\n components: { DtValidationMessages },\n\n mixins: [MessagesMixin],\n\n inheritAttrs: false,\n\n props: {\n /**\n * Name property of the input element\n */\n name: {\n type: String,\n default: '',\n },\n\n /**\n * Type of the input.\n * When `textarea` a `<textarea>` element will be rendered instead of an `<input>` element.\n * @values text, password, email, number, textarea, date, time, file, tel\n * @default 'text'\n */\n type: {\n type: String,\n default: INPUT_TYPES.TEXT,\n validator: (t) => Object.values(INPUT_TYPES).includes(t),\n },\n\n /**\n * Value of the input\n */\n modelValue: {\n type: [String, Number],\n default: '',\n },\n\n /**\n * Disables the input\n * @values true, false\n */\n disabled: {\n type: Boolean,\n default: false,\n },\n\n /**\n * Label for the input\n */\n label: {\n type: String,\n default: '',\n },\n\n /**\n * Determines visibility of input label.\n * @values true, false\n */\n labelVisible: {\n type: Boolean,\n default: true,\n },\n\n /**\n * Description for the input\n */\n description: {\n type: String,\n default: '',\n },\n\n /**\n * Size of the input, one of `xs`, `sm`, `md`, `lg`, `xl`\n * @values xs, sm, md, lg, xl\n */\n size: {\n type: String,\n default: 'md',\n validator: (t) => Object.values(INPUT_SIZES).includes(t),\n },\n\n /**\n * Additional class name for the input 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 inputClass: {\n type: [String, Object, Array],\n default: '',\n },\n\n /**\n * Additional class name for the input wrapper element.\n * Can accept all of String, Object, and Array, i.e. has the\n * same api as Vue's built-in handling of the class attribute.\n */\n inputWrapperClass: {\n type: [String, Object, Array],\n default: '',\n },\n\n /**\n * The current character length that the user has entered into the input.\n * This will only need to be used if you are using `validate.length` and\n * the string contains abnormal characters.\n * For example, an emoji could take up many characters in the input, but should only count as 1 character.\n * If no number is provided, a built-in length calculation will be used for the length validation.\n */\n currentLength: {\n type: Number,\n default: null,\n },\n\n /**\n * Whether the input will continue to display a warning validation message even if the input has lost focus.\n */\n retainWarning: {\n type: Boolean,\n default: false,\n },\n\n /**\n * Validation for the input. Supports maximum length validation with the structure:\n * `{ \"length\": {\"description\": string, \"max\": number, \"warn\": number, \"message\": string,\n * \"limitMaxLength\": boolean }}`\n */\n validate: {\n type: Object,\n default: null,\n },\n\n /**\n * hidden allows to use input without the element visually present in DOM\n */\n hidden: {\n type: Boolean,\n default: false,\n },\n },\n\n emits: [\n /**\n * Native input event\n *\n * @event input\n * @type {String}\n */\n 'input',\n\n /**\n * Native input blur event\n *\n * @event blur\n * @type {FocusEvent}\n */\n 'blur',\n\n /**\n * Input clear event\n *\n * @event clear\n */\n 'clear',\n\n /**\n * Native input focus event\n *\n * @event focus\n * @type {FocusEvent}\n */\n 'focus',\n\n /**\n * Native input focusin event\n *\n * @event focusin\n * @type {FocusEvent}\n */\n 'focusin',\n\n /**\n * Native input focusout event\n *\n * @event focusout\n * @type {FocusEvent}\n */\n 'focusout',\n\n /**\n * Event fired to sync the modelValue prop with the parent component\n * @event update:modelValue\n */\n 'update:modelValue',\n\n /**\n * Length of the input when currentLength prop is not passed\n *\n * @event update:length\n * @type {Number}\n */\n 'update:length',\n\n /**\n * Result of the input validation\n *\n * @event update:invalid\n * @type {Boolean}\n */\n 'update:invalid',\n ],\n\n data () {\n return {\n isInputFocused: false,\n isInvalid: false,\n defaultLength: 0,\n hasSlotContent,\n };\n },\n\n computed: {\n\n isTextarea () {\n return this.type === INPUT_TYPES.TEXTAREA;\n },\n\n isDefaultSize () {\n return this.size === INPUT_SIZES.DEFAULT;\n },\n\n iconSize () {\n return INPUT_ICON_SIZES[this.size];\n },\n\n isValidSize () {\n return Object.values(INPUT_SIZES).includes(this.size);\n },\n\n isValidDescriptionSize () {\n return Object.values(DESCRIPTION_SIZE_TYPES).includes(this.size);\n },\n\n inputComponent () {\n if (this.isTextarea) {\n return 'textarea';\n }\n\n return 'input';\n },\n\n inputListeners () {\n return {\n input: async event => {\n let val = event.target.value;\n if (this.type === INPUT_TYPES.FILE) {\n const files = Array.from(event.target.files);\n val = files.map(file => file.name);\n }\n this.$emit('input', val);\n this.$emit('update:modelValue', val);\n },\n\n blur: event => {\n this.isInputFocused = false;\n this.onBlur(event);\n },\n\n focus: event => {\n this.isInputFocused = true;\n this.$emit('focus', event);\n },\n\n focusin: event => this.$emit('focusin', event),\n focusout: event => this.$emit('focusout', event),\n };\n },\n\n descriptionKey () {\n return `input-description-${getUniqueString()}`;\n },\n\n inputState () {\n return getValidationState(this.validationMessages);\n },\n\n defaultLengthCalculation () {\n return this.calculateLength(this.modelValue);\n },\n\n validationProps () {\n return {\n length: {\n description: this?.validate?.length?.description,\n max: this?.validate?.length?.max,\n warn: this?.validate?.length?.warn,\n message: this?.validate?.length?.message,\n limitMaxLength: this?.validate?.length?.limitMaxLength ? this.validate.length.limitMaxLength : false,\n },\n };\n },\n\n validationMessages () {\n // Add length validation message if exists\n if (this.showLengthLimitValidation) {\n return this.formattedMessages.concat([this.inputLengthErrorMessage()]);\n }\n\n return this.formattedMessages;\n },\n\n showInputState () {\n return this.showMessages && this.inputState;\n },\n\n inputLength () {\n return this.currentLength ? this.currentLength : this.defaultLengthCalculation;\n },\n\n inputLengthState () {\n if (this.inputLength < this.validationProps.length.warn) {\n return null;\n } else if (this.inputLength <= this.validationProps.length.max) {\n return this.validationProps.length.warn ? VALIDATION_MESSAGE_TYPES.WARNING : null;\n } else {\n return VALIDATION_MESSAGE_TYPES.ERROR;\n }\n },\n\n shouldValidateLength () {\n return !!(\n this.validationProps.length.description &&\n this.validationProps.length.max\n );\n },\n\n shouldLimitMaxLength () {\n return this.shouldValidateLength && this.validationProps.length.limitMaxLength;\n },\n\n // eslint-disable-next-line complexity\n showLengthLimitValidation () {\n return (\n this.shouldValidateLength &&\n this.inputLengthState !== null &&\n this.validationProps.length.message &&\n (this.retainWarning || this.isInputFocused || this.isInvalid)\n );\n },\n\n sizeModifierClass () {\n if (this.isDefaultSize || !this.isValidSize) {\n return '';\n }\n\n return INPUT_SIZE_CLASSES[this.inputComponent][this.size];\n },\n\n stateClass () {\n return [INPUT_STATE_CLASSES[this.inputState]];\n },\n },\n\n watch: {\n isInvalid (val) {\n this.$emit('update:invalid', val);\n },\n\n modelValue: {\n immediate: true,\n handler (newValue) {\n if (this.shouldValidateLength) {\n this.validateLength(this.inputLength);\n }\n\n if (this.currentLength == null) {\n this.$emit('update:length', this.calculateLength(newValue));\n }\n },\n },\n },\n\n beforeMount () {\n this.descriptionSizeClasses = DESCRIPTION_SIZE_CLASSES;\n this.labelSizeClasses = LABEL_SIZE_CLASSES;\n },\n\n methods: {\n inputClasses () {\n return [\n 'd-input__input',\n this.inputComponent === 'input' ? 'd-input' : 'd-textarea',\n {\n [this.stateClass]: this.showInputState,\n 'd-input-icon--left': this.$slots.leftIcon,\n 'd-input-icon--right': this.$slots.rightIcon,\n },\n this.sizeModifierClass,\n this.inputClass,\n ];\n },\n\n inputWrapperClasses () {\n if (this.hidden) {\n return [];\n }\n return [\n 'd-input__wrapper',\n { [this.stateClass]: this.showInputState },\n this.inputWrapperClass,\n ];\n },\n\n calculateLength (value) {\n if (typeof value !== 'string') {\n return 0;\n }\n\n return [...value].length;\n },\n\n inputLengthErrorMessage () {\n return {\n message: this.validationProps.length.message,\n type: this.inputLengthState,\n };\n },\n\n onBlur (e) {\n // Do not emit a blur event if the target element is a child of this component\n if (!this.$refs.container?.contains(e.relatedTarget)) {\n this.$emit('blur', e);\n }\n },\n\n emitClearEvents () {\n this.$emit('input', '');\n this.$emit('clear');\n this.$emit('update:modelValue', '');\n },\n\n blur () {\n this.$refs.input.blur();\n },\n\n focus () {\n this.$refs.input.focus();\n },\n\n select () {\n this.$refs.input.select();\n },\n\n getMessageKey (type, index) {\n return `message-${type}-${index}`;\n },\n\n validateLength (length) {\n this.isInvalid = (length > this.validationProps.length.max);\n },\n\n clearInput () {\n this.$refs.input.value = '';\n this.$refs.input.focus();\n this.emitClearEvents();\n },\n },\n};\n</script>\n"],"names":["DtValidationMessages","MessagesMixin","INPUT_TYPES","INPUT_SIZES","hasSlotContent","INPUT_ICON_SIZES","DESCRIPTION_SIZE_TYPES","getUniqueString","getValidationState","VALIDATION_MESSAGE_TYPES","INPUT_SIZE_CLASSES","INPUT_STATE_CLASSES","DESCRIPTION_SIZE_CLASSES","LABEL_SIZE_CLASSES","_createElementBlock","_normalizeClass","_createElementVNode","_renderSlot","_createCommentVNode","_openBlock","_createTextVNode","_toDisplayString","_mergeProps","_toHandlers","_createVNode"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"input.vue.cjs","sources":["../../../components/input/input.vue"],"sourcesContent":["<template>\n <div\n ref=\"container\"\n :class=\"['d-input__root', { 'd-input--hidden': hidden }]\"\n data-qa=\"dt-input\"\n >\n <label\n class=\"d-input__label\"\n :aria-details=\"$slots.description || description ? descriptionKey : undefined\"\n data-qa=\"dt-input-label-wrapper\"\n >\n <!-- @slot Slot for label, defaults to label prop -->\n <slot name=\"labelSlot\">\n <div\n v-if=\"labelVisible && label\"\n ref=\"label\"\n data-qa=\"dt-input-label\"\n :class=\"[\n 'd-input__label-text',\n 'd-label',\n labelSizeClasses[size],\n ]\"\n >\n {{ label }}\n </div>\n </slot>\n <div\n v-if=\"hasSlotContent($slots.description) || description || shouldValidateLength\"\n :id=\"descriptionKey\"\n ref=\"description\"\n :class=\"[\n 'd-input__description',\n 'd-description',\n descriptionSizeClasses[size],\n ]\"\n data-qa=\"dt-input-description\"\n >\n <div\n v-if=\"hasSlotContent($slots.description) || description\"\n >\n <!-- @slot Slot for description, defaults to description prop -->\n <slot name=\"description\">{{ description }}</slot>\n </div>\n <div\n v-if=\"shouldValidateLength\"\n data-qa=\"dt-input-length-description\"\n class=\"d-input__length-description\"\n >\n {{ validationProps.length.description }}\n </div>\n </div>\n <div\n :class=\"inputWrapperClasses()\"\n :read-only=\"disabled === true ? true : undefined\"\n >\n <span\n class=\"d-input-icon d-input-icon--left\"\n data-qa=\"dt-input-left-icon-wrapper\"\n @focusout=\"onBlur\"\n >\n <!-- @slot Slot for left icon -->\n <slot\n name=\"leftIcon\"\n :icon-size=\"iconSize\"\n />\n </span>\n <textarea\n v-if=\"isTextarea\"\n ref=\"input\"\n :value=\"modelValue\"\n :name=\"name\"\n :disabled=\"disabled\"\n :autocomplete=\"$attrs.autocomplete ?? 'off'\"\n :class=\"inputClasses()\"\n :maxlength=\"shouldLimitMaxLength ? validationProps.length.max : null\"\n data-qa=\"dt-input-input\"\n v-bind=\"$attrs\"\n v-on=\"inputListeners\"\n />\n <input\n v-else\n ref=\"input\"\n :value=\"modelValue\"\n :name=\"name\"\n :type=\"type\"\n :disabled=\"disabled\"\n :autocomplete=\"$attrs.autocomplete ?? 'off'\"\n :class=\"inputClasses()\"\n :maxlength=\"shouldLimitMaxLength ? validationProps.length.max : null\"\n data-qa=\"dt-input-input\"\n v-bind=\"$attrs\"\n v-on=\"inputListeners\"\n >\n <span\n class=\"d-input-icon d-input-icon--right\"\n data-qa=\"dt-input-right-icon-wrapper\"\n @focusout=\"onBlur\"\n >\n <!-- @slot Slot for right icon -->\n <slot\n name=\"rightIcon\"\n :icon-size=\"iconSize\"\n :clear=\"clearInput\"\n />\n </span>\n </div>\n </label>\n <dt-validation-messages\n :validation-messages=\"validationMessages\"\n :show-messages=\"showMessages\"\n :class=\"messagesClass\"\n v-bind=\"messagesChildProps\"\n data-qa=\"dt-input-messages\"\n />\n </div>\n</template>\n\n<script>\n/* eslint-disable max-lines */\nimport { DESCRIPTION_SIZE_TYPES, VALIDATION_MESSAGE_TYPES } from '@/common/constants';\nimport {\n INPUT_TYPES,\n INPUT_SIZES,\n INPUT_SIZE_CLASSES,\n INPUT_ICON_SIZES,\n INPUT_STATE_CLASSES,\n DESCRIPTION_SIZE_CLASSES,\n LABEL_SIZE_CLASSES,\n} from './input_constants';\nimport {\n getUniqueString,\n getValidationState,\n hasSlotContent,\n} from '@/common/utils';\nimport { DtValidationMessages } from '@/components/validation_messages';\nimport { MessagesMixin } from '@/common/mixins/input';\n\n/**\n * An input field is an input control that allows users to enter alphanumeric information.\n * It can have a range of options and supports single line and multi-line lengths,\n * as well as varying formats, including numbers, masked passwords, etc.\n * @property {Boolean} placeholder attribute\n * @see https://dialtone.dialpad.com/components/input.html\n */\nexport default {\n name: 'DtInput',\n\n components: { DtValidationMessages },\n\n mixins: [MessagesMixin],\n\n inheritAttrs: false,\n\n props: {\n /**\n * Name property of the input element\n */\n name: {\n type: String,\n default: '',\n },\n\n /**\n * Type of the input.\n * When `textarea` a `<textarea>` element will be rendered instead of an `<input>` element.\n * @values text, password, email, number, textarea, date, time, file, tel, search\n * @default 'text'\n */\n type: {\n type: String,\n default: INPUT_TYPES.TEXT,\n validator: (t) => Object.values(INPUT_TYPES).includes(t),\n },\n\n /**\n * Value of the input\n */\n modelValue: {\n type: [String, Number],\n default: '',\n },\n\n /**\n * Disables the input\n * @values true, false\n */\n disabled: {\n type: Boolean,\n default: false,\n },\n\n /**\n * Label for the input\n */\n label: {\n type: String,\n default: '',\n },\n\n /**\n * Determines visibility of input label.\n * @values true, false\n */\n labelVisible: {\n type: Boolean,\n default: true,\n },\n\n /**\n * Description for the input\n */\n description: {\n type: String,\n default: '',\n },\n\n /**\n * Size of the input, one of `xs`, `sm`, `md`, `lg`, `xl`\n * @values xs, sm, md, lg, xl\n */\n size: {\n type: String,\n default: 'md',\n validator: (t) => Object.values(INPUT_SIZES).includes(t),\n },\n\n /**\n * Additional class name for the input 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 inputClass: {\n type: [String, Object, Array],\n default: '',\n },\n\n /**\n * Additional class name for the input wrapper element.\n * Can accept all of String, Object, and Array, i.e. has the\n * same api as Vue's built-in handling of the class attribute.\n */\n inputWrapperClass: {\n type: [String, Object, Array],\n default: '',\n },\n\n /**\n * The current character length that the user has entered into the input.\n * This will only need to be used if you are using `validate.length` and\n * the string contains abnormal characters.\n * For example, an emoji could take up many characters in the input, but should only count as 1 character.\n * If no number is provided, a built-in length calculation will be used for the length validation.\n */\n currentLength: {\n type: Number,\n default: null,\n },\n\n /**\n * Whether the input will continue to display a warning validation message even if the input has lost focus.\n */\n retainWarning: {\n type: Boolean,\n default: false,\n },\n\n /**\n * Validation for the input. Supports maximum length validation with the structure:\n * `{ \"length\": {\"description\": string, \"max\": number, \"warn\": number, \"message\": string,\n * \"limitMaxLength\": boolean }}`\n */\n validate: {\n type: Object,\n default: null,\n },\n\n /**\n * hidden allows to use input without the element visually present in DOM\n */\n hidden: {\n type: Boolean,\n default: false,\n },\n },\n\n emits: [\n /**\n * Native input event\n *\n * @event input\n * @type {String}\n */\n 'input',\n\n /**\n * Native input blur event\n *\n * @event blur\n * @type {FocusEvent}\n */\n 'blur',\n\n /**\n * Input clear event\n *\n * @event clear\n */\n 'clear',\n\n /**\n * Native input focus event\n *\n * @event focus\n * @type {FocusEvent}\n */\n 'focus',\n\n /**\n * Native input focusin event\n *\n * @event focusin\n * @type {FocusEvent}\n */\n 'focusin',\n\n /**\n * Native input focusout event\n *\n * @event focusout\n * @type {FocusEvent}\n */\n 'focusout',\n\n /**\n * Event fired to sync the modelValue prop with the parent component\n * @event update:modelValue\n */\n 'update:modelValue',\n\n /**\n * Length of the input when currentLength prop is not passed\n *\n * @event update:length\n * @type {Number}\n */\n 'update:length',\n\n /**\n * Result of the input validation\n *\n * @event update:invalid\n * @type {Boolean}\n */\n 'update:invalid',\n ],\n\n data () {\n return {\n isInputFocused: false,\n isInvalid: false,\n defaultLength: 0,\n hasSlotContent,\n };\n },\n\n computed: {\n\n isTextarea () {\n return this.type === INPUT_TYPES.TEXTAREA;\n },\n\n isDefaultSize () {\n return this.size === INPUT_SIZES.DEFAULT;\n },\n\n iconSize () {\n return INPUT_ICON_SIZES[this.size];\n },\n\n isValidSize () {\n return Object.values(INPUT_SIZES).includes(this.size);\n },\n\n isValidDescriptionSize () {\n return Object.values(DESCRIPTION_SIZE_TYPES).includes(this.size);\n },\n\n inputComponent () {\n if (this.isTextarea) {\n return 'textarea';\n }\n\n return 'input';\n },\n\n inputListeners () {\n return {\n input: async event => {\n let val = event.target.value;\n if (this.type === INPUT_TYPES.FILE) {\n const files = Array.from(event.target.files);\n val = files.map(file => file.name);\n }\n this.$emit('input', val);\n this.$emit('update:modelValue', val);\n },\n\n blur: event => {\n this.isInputFocused = false;\n this.onBlur(event);\n },\n\n focus: event => {\n this.isInputFocused = true;\n this.$emit('focus', event);\n },\n\n focusin: event => this.$emit('focusin', event),\n focusout: event => this.$emit('focusout', event),\n };\n },\n\n descriptionKey () {\n return `input-description-${getUniqueString()}`;\n },\n\n inputState () {\n return getValidationState(this.validationMessages);\n },\n\n defaultLengthCalculation () {\n return this.calculateLength(this.modelValue);\n },\n\n validationProps () {\n return {\n length: {\n description: this?.validate?.length?.description,\n max: this?.validate?.length?.max,\n warn: this?.validate?.length?.warn,\n message: this?.validate?.length?.message,\n limitMaxLength: this?.validate?.length?.limitMaxLength ? this.validate.length.limitMaxLength : false,\n },\n };\n },\n\n validationMessages () {\n // Add length validation message if exists\n if (this.showLengthLimitValidation) {\n return this.formattedMessages.concat([this.inputLengthErrorMessage()]);\n }\n\n return this.formattedMessages;\n },\n\n showInputState () {\n return this.showMessages && this.inputState;\n },\n\n inputLength () {\n return this.currentLength ? this.currentLength : this.defaultLengthCalculation;\n },\n\n inputLengthState () {\n if (this.inputLength < this.validationProps.length.warn) {\n return null;\n } else if (this.inputLength <= this.validationProps.length.max) {\n return this.validationProps.length.warn ? VALIDATION_MESSAGE_TYPES.WARNING : null;\n } else {\n return VALIDATION_MESSAGE_TYPES.ERROR;\n }\n },\n\n shouldValidateLength () {\n return !!(\n this.validationProps.length.description &&\n this.validationProps.length.max\n );\n },\n\n shouldLimitMaxLength () {\n return this.shouldValidateLength && this.validationProps.length.limitMaxLength;\n },\n\n // eslint-disable-next-line complexity\n showLengthLimitValidation () {\n return (\n this.shouldValidateLength &&\n this.inputLengthState !== null &&\n this.validationProps.length.message &&\n (this.retainWarning || this.isInputFocused || this.isInvalid)\n );\n },\n\n sizeModifierClass () {\n if (this.isDefaultSize || !this.isValidSize) {\n return '';\n }\n\n return INPUT_SIZE_CLASSES[this.inputComponent][this.size];\n },\n\n stateClass () {\n return [INPUT_STATE_CLASSES[this.inputState]];\n },\n },\n\n watch: {\n isInvalid (val) {\n this.$emit('update:invalid', val);\n },\n\n modelValue: {\n immediate: true,\n handler (newValue) {\n if (this.shouldValidateLength) {\n this.validateLength(this.inputLength);\n }\n\n if (this.currentLength == null) {\n this.$emit('update:length', this.calculateLength(newValue));\n }\n },\n },\n },\n\n beforeMount () {\n this.descriptionSizeClasses = DESCRIPTION_SIZE_CLASSES;\n this.labelSizeClasses = LABEL_SIZE_CLASSES;\n },\n\n methods: {\n inputClasses () {\n return [\n 'd-input__input',\n this.inputComponent === 'input' ? 'd-input' : 'd-textarea',\n {\n [this.stateClass]: this.showInputState,\n 'd-input-icon--left': this.$slots.leftIcon,\n 'd-input-icon--right': this.$slots.rightIcon,\n },\n this.sizeModifierClass,\n this.inputClass,\n ];\n },\n\n inputWrapperClasses () {\n if (this.hidden) {\n return [];\n }\n return [\n 'd-input__wrapper',\n { [this.stateClass]: this.showInputState },\n this.inputWrapperClass,\n ];\n },\n\n calculateLength (value) {\n if (typeof value !== 'string') {\n return 0;\n }\n\n return [...value].length;\n },\n\n inputLengthErrorMessage () {\n return {\n message: this.validationProps.length.message,\n type: this.inputLengthState,\n };\n },\n\n onBlur (e) {\n // Do not emit a blur event if the target element is a child of this component\n if (!this.$refs.container?.contains(e.relatedTarget)) {\n this.$emit('blur', e);\n }\n },\n\n emitClearEvents () {\n this.$emit('input', '');\n this.$emit('clear');\n this.$emit('update:modelValue', '');\n },\n\n blur () {\n this.$refs.input.blur();\n },\n\n focus () {\n this.$refs.input.focus();\n },\n\n select () {\n this.$refs.input.select();\n },\n\n getMessageKey (type, index) {\n return `message-${type}-${index}`;\n },\n\n validateLength (length) {\n this.isInvalid = (length > this.validationProps.length.max);\n },\n\n clearInput () {\n this.$refs.input.value = '';\n this.$refs.input.focus();\n this.emitClearEvents();\n },\n },\n};\n</script>\n"],"names":["DtValidationMessages","MessagesMixin","INPUT_TYPES","INPUT_SIZES","hasSlotContent","INPUT_ICON_SIZES","DESCRIPTION_SIZE_TYPES","getUniqueString","getValidationState","VALIDATION_MESSAGE_TYPES","INPUT_SIZE_CLASSES","INPUT_STATE_CLASSES","DESCRIPTION_SIZE_CLASSES","LABEL_SIZE_CLASSES","_createElementBlock","_normalizeClass","_createElementVNode","_renderSlot","_createCommentVNode","_openBlock","_createTextVNode","_toDisplayString","_mergeProps","_toHandlers","_createVNode"],"mappings":"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"}
|
|
@@ -21,7 +21,7 @@ const _sfc_main = {
|
|
|
21
21
|
/**
|
|
22
22
|
* Type of the input.
|
|
23
23
|
* When `textarea` a `<textarea>` element will be rendered instead of an `<input>` element.
|
|
24
|
-
* @values text, password, email, number, textarea, date, time, file, tel
|
|
24
|
+
* @values text, password, email, number, textarea, date, time, file, tel, search
|
|
25
25
|
* @default 'text'
|
|
26
26
|
*/
|
|
27
27
|
type: {
|