@dialpad/dialtone 9.140.0 → 9.140.1
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/tokens/doc.json +61544 -61544
- package/dist/vue2/lib/emoji-picker/emoji-picker.cjs +1 -1
- package/dist/vue2/lib/emoji-picker/emoji-picker.cjs.map +1 -1
- package/dist/vue2/lib/emoji-picker/emoji-picker.js +1 -2
- package/dist/vue2/lib/emoji-picker/emoji-picker.js.map +1 -1
- package/dist/vue3/lib/emoji-picker/emoji-picker.cjs +1 -1
- package/dist/vue3/lib/emoji-picker/emoji-picker.cjs.map +1 -1
- package/dist/vue3/lib/emoji-picker/emoji-picker.js +26 -26
- package/dist/vue3/lib/emoji-picker/emoji-picker.js.map +1 -1
- package/package.json +3 -3
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"emoji-picker.cjs","sources":["../../../components/emoji_picker/modules/emoji_search.vue","../../../components/emoji_picker/modules/emoji_tabset.vue","../../../components/emoji_picker/composables/useKeyboardNavigation.js","../../../components/emoji_picker/modules/emoji_selector.vue","../../../components/emoji_picker/modules/emoji_skin_selector.vue","../../../components/emoji_picker/modules/emoji_description.vue","../../../components/emoji_picker/emoji_picker.vue"],"sourcesContent":["<template>\n <div class=\"d-emoji-picker__search d-emoji-picker__alignment\">\n <dt-input\n id=\"searchInput\"\n ref=\"searchInput\"\n :placeholder=\"searchPlaceholderLabel\"\n :model-value=\"modelValue\"\n @update:model-value=\"$emit('update:modelValue', $event)\"\n @keydown.up=\"$emit('focus-tabset')\"\n @keydown.down.prevent=\"$emit('focus-emoji-selector')\"\n @keydown.enter=\"$emit('select-first-emoji')\"\n >\n <template #leftIcon>\n <dt-icon-search\n size=\"200\"\n />\n </template>\n <template\n v-if=\"modelValue.length > 0\"\n #rightIcon\n >\n <dt-button\n importance=\"clear\"\n size=\"xs\"\n class=\"d-emoji-picker__search-x-button\"\n circle\n kind=\"muted\"\n @click=\"clearSearch\"\n >\n <template #icon>\n <dt-icon-close\n size=\"200\"\n />\n </template>\n </dt-button>\n </template>\n </dt-input>\n </div>\n</template>\n\n<script setup>\nimport { DtIconSearch, DtIconClose } from '@dialpad/dialtone-icons/vue3';\nimport { DtInput } from '@/components/input';\nimport { DtButton } from '@/components/button';\nimport { onMounted, ref } from 'vue';\n\ndefineProps({\n searchPlaceholderLabel: {\n type: String,\n required: true,\n },\n modelValue: {\n type: String,\n default: '',\n },\n});\n\nconst emits = defineEmits(['update:modelValue', 'focus-emoji-selector', 'focus-tabset', 'select-first-emoji']);\n\nconst searchInput = ref(null);\n\nfunction clearSearch () {\n emits('update:modelValue', '');\n focusSearchInput();\n}\n\nfunction focusSearchInput () {\n searchInput.value.focus();\n}\nonMounted(() => {\n focusSearchInput();\n});\n\ndefineExpose({\n focusSearchInput,\n});\n</script>\n","<template>\n <div class=\"d-emoji-picker__tabset\">\n <dt-tab-group\n :selected=\"selectedTab\"\n size=\"sm\"\n tab-list-class=\"d-emoji-picker__tabset-list\"\n >\n <template #tabs>\n <dt-tab\n v-for=\"(tab, index) in tabs\"\n :id=\"tab.id\"\n :key=\"tab.id\"\n :ref=\"el => { if (el) setTabsetRef(el) }\"\n :label=\"tab.label\"\n :panel-id=\"tab.panelId\"\n :tabindex=\"index + 1\"\n aria-controls=\"d-emoji-picker-list\"\n @keydown=\"handleKeyDown($event, tab.id)\"\n @click.capture.stop=\"selectTabset(tab.id)\"\n >\n <component\n :is=\"tab.icon\"\n size=\"400\"\n />\n </dt-tab>\n </template>\n </dt-tab-group>\n </div>\n</template>\n\n<script setup>\nimport { computed, ref, watch } from 'vue';\nimport { DtTab, DtTabGroup } from '@/components/tab';\nimport { returnFirstEl } from '@/common/utils';\nimport {\n DtIconClock,\n DtIconSatisfied,\n DtIconLivingThing,\n DtIconFood,\n DtIconObject,\n DtIconTransportation,\n DtIconLightbulb,\n DtIconHeart,\n DtIconFlag,\n DtIconTiktok,\n} from '@dialpad/dialtone-icons/vue3';\n\nconst props = defineProps({\n /**\n * Whether to show the recently used tab or not\n * @type {Boolean}\n * @default false\n */\n showRecentlyUsedTab: {\n type: Boolean,\n default: false,\n },\n\n /**\n * Whether to show the custom emojis tab or not\n * @type {Boolean}\n * @default false\n */\n showCustomEmojisTab: {\n type: Boolean,\n default: false,\n },\n\n scrollIntoTab: {\n type: Number,\n required: true,\n },\n\n emojiFilter: {\n type: String,\n default: '',\n },\n\n /**\n * The labels for the aria-label\n * @type {Array}\n * @required\n */\n tabSetLabels: {\n type: Array,\n required: true,\n },\n});\n\nconst emits = defineEmits([\n /**\n * Emitted when a tab is selected\n * @event selected-tabset\n * @param {String} tabId - The name of the tab that was selected\n */\n 'selected-tabset',\n\n 'focus-search-input',\n 'focus-skin-selector',\n]);\n\nconst TABS_DATA = [\n { label: props.tabSetLabels[0], icon: DtIconClock },\n { label: props.tabSetLabels[1], icon: DtIconSatisfied },\n { label: props.tabSetLabels[2], icon: DtIconLivingThing },\n { label: props.tabSetLabels[3], icon: DtIconFood },\n { label: props.tabSetLabels[4], icon: DtIconObject },\n { label: props.tabSetLabels[5], icon: DtIconTransportation },\n { label: props.tabSetLabels[6], icon: DtIconLightbulb },\n { label: props.tabSetLabels[7], icon: DtIconHeart },\n { label: props.tabSetLabels[8], icon: DtIconFlag },\n { label: props.tabSetLabels[9], icon: DtIconTiktok },\n];\n\nconst tabs = computed(() => {\n const tabsData = props.showRecentlyUsedTab ? TABS_DATA : TABS_DATA.slice(1);\n // if showCustomEmojisTab is false remove last index of TABS_DATA\n if (!props.showCustomEmojisTab) {\n tabsData.pop();\n }\n\n return tabsData.map((tab, index) => ({\n ...tab,\n // IDs on dt-tab component need to be on string\n id: (index + 1).toString(),\n panelId: (index + 1).toString(),\n }));\n});\n\nconst isSearching = computed(() => props.emojiFilter.length > 0);\n\nconst selectedTab = ref('1');\n\nconst tabsetRef = ref([]);\n\nwatch(() => props.scrollIntoTab,\n () => {\n if (!isSearching.value) {\n selectedTab.value = (props.scrollIntoTab + 1).toString();\n }\n });\n\nwatch(isSearching,\n () => {\n if (isSearching.value) {\n selectedTab.value = null;\n }\n });\n\n/**\n * We are using .capture.stop modifiers on the click event\n * because we don't want to trigger the click event of the\n * dt-tab component\n */\nfunction selectTabset (id) {\n // IDs on scrollToTab need to be on number\n const parseId = parseInt(id);\n // IDs on dt-tab component need to be on string\n selectedTab.value = id;\n emits('selected-tabset', parseId);\n}\n\nfunction setTabsetRef (ref) {\n // We push the $el, because $el is the button inside the dt-tab component\n // and we need the button to focus it\n tabsetRef.value.push(returnFirstEl(ref.$el));\n}\n\nfunction focusTabset () {\n tabsetRef.value[0].focus();\n}\n\nfunction handleKeyDown (event, tabId) {\n if (event.key === 'Enter') {\n selectTabset(tabId);\n // We blur because seems like the tab component override the selected prop, and it removes the selected style\n tabsetRef.value[tabId - 1].blur();\n }\n\n if (event.key === 'Tab') {\n event.preventDefault();\n if (event.shiftKey) {\n emits('focus-skin-selector');\n } else {\n emits('focus-search-input');\n }\n }\n\n if (event.key === 'ArrowDown') {\n // Jump to search input\n emits('focus-search-input');\n }\n}\n\ndefineExpose({\n focusTabset,\n});\n</script>\n","import { ref } from 'vue';\nimport { EMOJIS_PER_ROW, ARROW_KEYS } from '@/components/emoji_picker/emoji_picker_constants';\n\nexport function useKeyboardNavigation () {\n const emojiRefs = ref([]);\n const emojiFilteredRefs = ref([]);\n const isFiltering = ref(false);\n const hoverFirstEmoji = ref(true);\n\n function _handleArrowLeft (indexTab, indexEmoji) {\n if (!focusEmoji(indexTab, indexEmoji - 1)) {\n if (emojiRefs.value[indexTab - 1]) {\n focusEmoji(indexTab - 1, emojiRefs.value[indexTab - 1].length - 1);\n } else {\n focusEmoji(emojiRefs.value.length - 1, emojiRefs.value[emojiRefs.value.length - 1].length - 1);\n }\n }\n }\n\n function _handleArrowRight (indexTab, indexEmoji) {\n if (!focusEmoji(indexTab, indexEmoji + 1)) {\n if (!focusEmoji(indexTab + 1, 0)) {\n focusEmoji(0, 0);\n }\n }\n }\n\n function _handleArrowLeftFiltered (indexTab, indexEmoji) {\n if (!focusEmoji(0, indexEmoji - 1)) {\n focusEmoji(0, emojiFilteredRefs.value.length - 1);\n }\n }\n\n function _handleArrowRightFiltered (indexTab, indexEmoji) {\n if (!focusEmoji(0, indexEmoji + 1)) {\n focusEmoji(0, 0);\n }\n }\n\n function _handleHorizontalNavigation (direction, indexTab, indexEmoji) {\n if (isFiltering.value) {\n if (direction === 'left') {\n _handleArrowLeftFiltered(indexTab, indexEmoji);\n } else if (direction === 'right') {\n _handleArrowRightFiltered(indexTab, indexEmoji);\n }\n } else {\n if (direction === 'left') {\n _handleArrowLeft(indexTab, indexEmoji);\n } else if (direction === 'right') {\n _handleArrowRight(indexTab, indexEmoji);\n }\n }\n }\n\n function focusEmoji (indexTab, indexEmoji) {\n const emojiRef = isFiltering.value\n ? emojiFilteredRefs.value?.[indexEmoji]\n : emojiRefs.value?.[indexTab]?.[indexEmoji];\n\n if (emojiRef) {\n emojiRef.focus();\n return true;\n }\n\n return false;\n }\n\n function setEmojiRef (el, indexTab, indexEmoji) {\n if (!emojiRefs.value[indexTab]) {\n emojiRefs.value[indexTab] = [];\n }\n emojiRefs.value[indexTab][indexEmoji] = el;\n }\n\n function setFilteredRef (el, index) {\n emojiFilteredRefs.value[index] = el;\n }\n\n function handleArrowNavigationFiltered (key, indexEmoji) {\n hoverFirstEmoji.value = false;\n\n if (key === ARROW_KEYS.ARROW_UP) {\n const position = indexEmoji % EMOJIS_PER_ROW;\n\n if (!focusEmoji(0, indexEmoji - EMOJIS_PER_ROW)) {\n const lastEmojiPosition =\n emojiFilteredRefs.value.length - (emojiFilteredRefs.value.length % EMOJIS_PER_ROW) + position;\n\n focusEmoji(0, lastEmojiPosition);\n\n if (!focusEmoji(0, lastEmojiPosition)) {\n focusEmoji(0, emojiFilteredRefs.value.length - 1);\n }\n }\n }\n\n if (key === ARROW_KEYS.ARROW_DOWN) {\n if (!focusEmoji(0, indexEmoji + EMOJIS_PER_ROW)) {\n const position = indexEmoji % EMOJIS_PER_ROW;\n\n if (emojiFilteredRefs.value?.[indexEmoji + (EMOJIS_PER_ROW - position)]) {\n focusEmoji(0, emojiFilteredRefs.value.length - 1);\n } else {\n focusEmoji(0, position);\n }\n }\n }\n\n if (key === ARROW_KEYS.ARROW_LEFT) {\n _handleHorizontalNavigation('left', 0, indexEmoji);\n }\n\n if (key === ARROW_KEYS.ARROW_RIGHT) {\n _handleHorizontalNavigation('right', 0, indexEmoji);\n }\n }\n\n function handleArrowNavigation (key, indexTab, indexEmoji) {\n if (key === 'ArrowUp') {\n const position = indexEmoji % EMOJIS_PER_ROW;\n\n if (indexTab === 0) {\n // we are on the first emoji tab, then we should jump to the last row of the last emoji tab\n const numberOfMissingEmojis =\n EMOJIS_PER_ROW - (emojiRefs.value[emojiRefs.value.length - 1].length % EMOJIS_PER_ROW);\n\n const emojiToJump =\n emojiRefs.value[emojiRefs.value.length - 1].length + numberOfMissingEmojis - (EMOJIS_PER_ROW - position);\n\n if (!focusEmoji(emojiRefs.value.length - 1, emojiToJump)) {\n // if there is no emoji in this position, jump to the last emoji of the row\n focusEmoji(emojiRefs.value.length - 1, emojiRefs.value[emojiRefs.value.length - 1].length - 1);\n }\n return;\n }\n\n // if we are not on the first tab, we should jump to the previous row of the current tab\n if (!focusEmoji(indexTab, indexEmoji - EMOJIS_PER_ROW)) {\n // if there is no previous row, we should jump to emoji in the sampe position of the previous tab\n const previousTab = indexTab - 1 < 0 ? 0 : indexTab - 1;\n const emojisInPreviousTab = emojiRefs.value[previousTab].length;\n const lastEmojiPosition = emojisInPreviousTab - (emojisInPreviousTab % EMOJIS_PER_ROW) + position;\n\n if (!focusEmoji(previousTab, lastEmojiPosition)) {\n // if there is no emoji in this position, jump to the last emoji of the row\n focusEmoji(indexTab - 1, emojiRefs.value[indexTab - 1].length - 1);\n }\n }\n }\n\n if (key === 'ArrowDown') {\n if (!focusEmoji(indexTab, indexEmoji + EMOJIS_PER_ROW)) {\n // if cannot go down\n\n // Calculate position from cell 0 to cell 8\n const position = indexEmoji % EMOJIS_PER_ROW;\n\n // check if it exists a next row in the current tab\n if (emojiRefs.value?.[indexTab]?.[indexEmoji + (EMOJIS_PER_ROW - position)]) {\n // if it exists, we should focus the last emoji of the next row in the current tab\n focusEmoji(indexTab, emojiRefs.value[indexTab].length - 1);\n // if we are at the end of the list it will do nothing\n } else {\n // We don't have next row, we are in the last of the tab, then jump\n // to the next tab but in the equal emoji position in row 0.\n\n if (!focusEmoji(indexTab + 1, position)) {\n // We are on the bottom!, should jump to the same position emoji in the first row of the first tabset\n // if it doesn't has, jump to the last\n if (!focusEmoji(0, position)) {\n focusEmoji(0, emojiRefs.value[0].length - 1);\n }\n }\n }\n }\n }\n\n if (key === 'ArrowLeft') {\n _handleHorizontalNavigation('left', indexTab, indexEmoji);\n }\n\n if (key === 'ArrowRight') {\n _handleHorizontalNavigation('right', indexTab, indexEmoji);\n }\n }\n\n return {\n emojiFilteredRefs,\n isFiltering,\n hoverFirstEmoji,\n setEmojiRef,\n setFilteredRef,\n focusEmoji,\n handleArrowNavigationFiltered,\n handleArrowNavigation,\n };\n}\n","<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)\"\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, onBeforeUnmount, 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 /**\n * The list of custom emojis\n * @type {Array}\n */\n customEmojis: {\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 bottom scroll\n * This event is used on handleScroll method\n * @event scroll-bottom-reached\n */\n 'scroll-bottom-reached',\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', 'Custom'];\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 or custom emojis list is empty\n * If it is empty, it will remove it\n */\nconst tabLabels = computed(() => {\n let updateTabLabels = props.tabsetLabels.map((label) => ({ label, ref: ref(null) }));\n\n if (props.recentlyUsedEmojis && !props.recentlyUsedEmojis.length) {\n updateTabLabels = props.tabsetLabels.slice(1).map((label) => ({ label, ref: ref(null) }));\n }\n\n if (props.customEmojis && !props.customEmojis.length) {\n updateTabLabels.pop();\n }\n\n return updateTabLabels;\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 or custom emojis is empty\n * If it is empty, it will remove it\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 const updateTabsOrder = props.recentlyUsedEmojis.length ? TABS_DATA.slice() : TABS_DATA.slice(1);\n\n if (props.customEmojis && !props.customEmojis.length) {\n updateTabsOrder.pop();\n }\n\n return updateTabsOrder;\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 * handleScroll will be defined when user scroll\n */\nconst handleScroll = () => {\n const container = listRef.value;\n // TODO -- this will probably need to be updated if we add more emojis.\n // because the container height will change.\n // maybe with a nextTick similar of scrollToTab.\n if (container.scrollTop + container.clientHeight >= container.scrollHeight) {\n emits('scroll-bottom-reached');\n }\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 * Update the custom emojis list on custom emojis prop changes\n * @listens customEmojis\n */\nwatch(() => props.customEmojis,\n () => {\n emojis.Custom = props.customEmojis;\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 // TODO Update json structure to have a property for custom emojis and avoid using date_added\n if (emoji.date_added) { // if custom emoji\n return emoji.image;\n } else { // if regular emoji\n return CDN_URL + emoji.unicode_character + '.png';\n }\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\nfunction setBottomScrollListener () {\n listRef.value.addEventListener('scroll', handleScroll);\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 setBottomScrollListener();\n});\n\nonBeforeUnmount(() => {\n tabLabelObserver.value.disconnect();\n listRef.value.removeEventListener('scroll', handleScroll);\n});\n\ndefineExpose({\n focusEmojiSelector,\n focusLastEmoji,\n});\n</script>\n","<template>\n <div data-qa=\"skin-selector\">\n <div\n v-show=\"isOpen\"\n class=\"d-emoji-picker__skin-list\"\n >\n <button\n v-for=\"(skin, index) in skinList\"\n :ref=\"el => { if (el) setSkinsRef(el) }\"\n :key=\"skin.name\"\n :class=\"{\n 'selected': skinSelected.skinCode === skin.skinCode,\n }\"\n @keydown=\"event => handleKeyDown(event, skin, index)\"\n @click=\"selectSkin(skin)\"\n >\n <img\n class=\"d-icon d-icon--size-500\"\n :alt=\"skin.name\"\n :aria-label=\"skin.name\"\n :title=\"skin.name\"\n :src=\"`${CDN_URL + skin.unicode_output}.png`\"\n >\n </button>\n </div>\n <div\n v-show=\"!isOpen\"\n class=\"d-emoji-picker__skin-selected\"\n >\n <dt-tooltip placement=\"top-end\">\n {{ skinSelectorButtonTooltipLabel }}\n <template #anchor>\n <button\n ref=\"skinSelectorRef\"\n :aria-label=\"skinSelectorButtonTooltipLabel\"\n tabindex=\"-1\"\n @click=\"toggleSkinList\"\n @keydown=\"event => handleKeyDown(event)\"\n >\n <img\n class=\"d-icon d-icon--size-500\"\n :alt=\"skinSelected.name\"\n :aria-label=\"skinSelected.name\"\n :title=\"skinSelected.name\"\n :src=\"`${CDN_URL + skinSelected.unicode_output}.png`\"\n >\n </button>\n </template>\n </dt-tooltip>\n </div>\n </div>\n</template>\n\n<script setup>\nimport { computed, nextTick, ref, watchEffect } from 'vue';\nimport { CDN_URL, EMOJI_PICKER_SKIN_TONE_MODIFIERS } from '@/components/emoji_picker/emoji_picker_constants.js';\nimport { DtTooltip } from '@/components/tooltip';\n\nconst props = defineProps({\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 isHovering: {\n type: Boolean,\n default: false,\n },\n\n skinSelectorButtonTooltipLabel: {\n type: String,\n required: true,\n },\n});\n\nconst emits = defineEmits([\n /**\n * The skin tone that was selected\n * @event skin-tone\n * @type {Number}\n */\n 'skin-tone',\n 'focus-tabset',\n 'focus-last-emoji',\n]);\n\nconst skinList = [\n {\n name: ':wave_tone1:',\n unicode_output: '1f44b-1f3fb',\n skinTone: EMOJI_PICKER_SKIN_TONE_MODIFIERS.LIGHT,\n skinCode: '_tone1',\n },\n {\n name: ':wave_tone2:',\n unicode_output: '1f44b-1f3fc',\n skinTone: EMOJI_PICKER_SKIN_TONE_MODIFIERS.MEDIUM_LIGHT,\n skinCode: '_tone2',\n },\n {\n name: ':wave_tone3:',\n unicode_output: '1f44b-1f3fd',\n skinTone: EMOJI_PICKER_SKIN_TONE_MODIFIERS.MEDIUM,\n skinCode: '_tone3',\n },\n {\n name: ':wave_tone4:',\n unicode_output: '1f44b-1f3fe',\n skinTone: EMOJI_PICKER_SKIN_TONE_MODIFIERS.MEDIUM_DARK,\n skinCode: '_tone4',\n },\n {\n name: ':wave_tone5:',\n unicode_output: '1f44b-1f3ff',\n skinTone: EMOJI_PICKER_SKIN_TONE_MODIFIERS.DARK,\n skinCode: '_tone5',\n },\n {\n name: ':wave:',\n unicode_output: '1f44b',\n skinTone: EMOJI_PICKER_SKIN_TONE_MODIFIERS.DEFAULT,\n skinCode: '',\n },\n];\n\nconst isOpen = ref(false);\n\nconst skinSelectorRef = ref(null);\n\nconst skinsRef = ref([]);\n\n/**\n * It will close the skin selector if the user is hovering over the emoji list\n */\nwatchEffect(\n () => props.isHovering && (isOpen.value = false),\n);\n\n/**\n * It will initially display props.skinTone. If a new skin tone is selected,\n * it will display that until props.skinTone changes.\n */\nconst skinPassedIn = computed(() => skinList.find((skin) => skin.skinTone === props.skinTone));\nconst skinSelected = ref(skinPassedIn.value);\nwatchEffect(() => skinPassedIn.value && (skinSelected.value = skinPassedIn.value));\n\nfunction setSkinsRef (ref) {\n skinsRef.value.push(ref);\n}\nfunction focusSkinSelector () {\n skinSelectorRef.value.focus();\n}\n\nfunction selectSkin (skin) {\n skinSelected.value = skin;\n isOpen.value = false;\n emits('skin-tone', skin.skinTone);\n nextTick(() => focusSkinSelector());\n}\n\nconst handleKeyDown = (event, skin, index) => {\n event.preventDefault();\n\n if (event.key === 'ArrowLeft') {\n if (index === 0) skinsRef.value[skinsRef.value.length - 1]?.focus();\n skinsRef.value[index - 1]?.focus();\n }\n\n if (event.key === 'ArrowRight') {\n skinsRef.value[index + 1]?.focus();\n }\n\n if (event.key === 'Enter') {\n if (skin) { selectSkin(skin); } else {\n toggleSkinList();\n }\n }\n\n if (event.key === 'Tab') {\n if (event.shiftKey) {\n emits('focus-last-emoji');\n } else {\n emits('focus-tabset');\n }\n }\n};\n\nfunction toggleSkinList () {\n isOpen.value = !isOpen.value;\n nextTick(() => skinsRef.value[0].focus());\n}\n\ndefineExpose({\n focusSkinSelector,\n});\n</script>\n","<template>\n <div class=\"d-emoji-picker__data\">\n <img\n v-if=\"emoji\"\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)\"\n >\n <div>{{ emoji?.name }}</div>\n </div>\n</template>\n\n<script setup>\nimport { CDN_URL } from '@/components/emoji_picker/emoji_picker_constants';\n\ndefineProps({\n /**\n * Emoji data\n * @type {Object}\n * @default null\n */\n emoji: {\n type: Object,\n default: null,\n },\n});\n\nfunction getImgSrc (emoji) {\n if (emoji.date_added) { // if custom emoji\n return emoji.image;\n } else { // if regular emoji\n return `${CDN_URL + emoji.unicode_character}.png`;\n }\n}\n</script>\n","<template>\n <div\n class=\"d-emoji-picker\"\n >\n <div class=\"d-emoji-picker--header\">\n <emoji-tabset\n ref=\"tabsetRef\"\n :emoji-filter=\"internalSearchQuery\"\n :show-custom-emojis-tab=\"showCustomEmojisTab\"\n :show-recently-used-tab=\"showRecentlyUsedTab\"\n :scroll-into-tab=\"scrollIntoTab\"\n :tab-set-labels=\"tabSetLabels\"\n @focus-skin-selector=\"$refs.skinSelectorRef.focusSkinSelector()\"\n @focus-search-input=\"showSearch\n ? $refs.searchInputRef.focusSearchInput()\n : $refs.emojiSelectorRef.focusEmojiSelector()\"\n @selected-tabset=\"scrollToSelectedTabset\"\n @keydown.esc=\"emits('close')\"\n />\n </div>\n <div class=\"d-emoji-picker--body\">\n <emoji-search\n v-if=\"showSearch\"\n ref=\"searchInputRef\"\n v-model=\"internalSearchQuery\"\n :search-placeholder-label=\"searchPlaceholderLabel\"\n @select-first-emoji=\"emits('selected-emoji', highlightedEmoji)\"\n @focus-tabset=\"$refs.tabsetRef.focusTabset()\"\n @focus-emoji-selector=\"$refs.emojiSelectorRef.focusEmojiSelector()\"\n @keydown.esc=\"emits('close')\"\n />\n <emoji-selector\n ref=\"emojiSelectorRef\"\n :emoji-filter=\"internalSearchQuery\"\n :skin-tone=\"skinTone\"\n :tabset-labels=\"tabSetLabels\"\n :search-results-label=\"searchResultsLabel\"\n :search-no-results-label=\"searchNoResultsLabel\"\n :recently-used-emojis=\"recentlyUsedEmojis\"\n :custom-emojis=\"customEmojis\"\n :selected-tabset=\"selectedTabset\"\n @scroll-into-tab=\"updateScrollIntoTab\"\n @highlighted-emoji=\"updateHighlightedEmoji\"\n @selected-emoji=\"emits('selected-emoji', $event)\"\n @focus-skin-selector=\"$refs.skinSelectorRef.focusSkinSelector()\"\n @focus-search-input=\"showSearch ? $refs.searchInputRef.focusSearchInput() : $refs.tabsetRef.focusTabset()\"\n @keydown.esc=\"emits('close')\"\n @scroll-bottom-reached=\"emits('scroll-bottom-reached')\"\n />\n </div>\n <div class=\"d-emoji-picker--footer\">\n <dt-button\n v-if=\"showAddEmojiButton && !highlightedEmoji\"\n importance=\"outlined\"\n :aria-label=\"addEmojiLabel\"\n class=\"d-emoji-picker__add-emoji\"\n @click=\"emits('add-emoji')\"\n >\n {{ addEmojiLabel }}\n </dt-button>\n <emoji-description :emoji=\"highlightedEmoji\" />\n <emoji-skin-selector\n ref=\"skinSelectorRef\"\n :is-hovering=\"!!highlightedEmoji\"\n :skin-selector-button-tooltip-label=\"skinSelectorButtonTooltipLabel\"\n :skin-tone=\"skinTone\"\n @skin-tone=\"emits('skin-tone', $event)\"\n @focus-tabset=\"$refs.tabsetRef.focusTabset()\"\n @focus-last-emoji=\"$refs.emojiSelectorRef.focusLastEmoji()\"\n @keydown.esc=\"emits('close')\"\n />\n </div>\n </div>\n</template>\n\n<script setup>\nimport EmojiSearch from './modules/emoji_search.vue';\nimport EmojiTabset from './modules/emoji_tabset.vue';\nimport EmojiSelector from './modules/emoji_selector.vue';\nimport EmojiSkinSelector from './modules/emoji_skin_selector.vue';\nimport EmojiDescription from './modules/emoji_description.vue';\nimport { DtButton } from '../button';\nimport { computed, ref, watch } from 'vue';\nimport { DialtoneLocalization } from '@/localization';\n\nconst props = defineProps({\n /**\n * The array with recently used emoji object\n * This list is necessary to fill the recently used tab\n * @type {Array}\n * @default []\n * @example\n * <dt-emoji-picker :recentlyUsedEmojis=\"[emojiObject, emojiObject]\" />\n */\n // TODO try to simplify this to achieve an array of unicode characters and not an entire emoji data object\n recentlyUsedEmojis: {\n type: Array,\n default: () => [],\n },\n\n /**\n * The array with custom emojis object\n * This list is necessary to fill the custom tab\n * @type {Array}\n * @default []\n * @example\n * <dt-emoji-picker :customEmojis=\"[emojiObject, emojiObject]\" />\n */\n customEmojis: {\n type: Array,\n },\n\n /**\n * The skin tone to show the emojis\n * This prop gives the possibility to use the skin tone selected by the user previously\n * @type {String}\n * @default 'Default'\n * @values 'Default', 'Light', 'MediumLight', 'Medium', 'MediumDark', 'Dark'\n * @example\n * <dt-emoji-picker :skinTone=\"'Default'\" />\n */\n skinTone: {\n type: String,\n default: 'Default',\n },\n\n /**\n\n * Sets the search query that filters emojis.\n * @type {String}\n * @example\n * <dt-emoji-picker search-query=\"smile\" />\n */\n searchQuery: {\n type: String,\n default: '',\n },\n\n /**\n * Shows the search input\n * @type {Boolean}\n * @example\n * <dt-emoji-picker :show-search=\"false\" />\n */\n showSearch: {\n type: Boolean,\n default: true,\n },\n\n /**\n * Shows the add emoji button in the footer when no emoji is highlighted\n * @type {Boolean}\n * @example\n * <dt-emoji-picker :show-add-emoji-button=\"true\" />\n */\n showAddEmojiButton: {\n type: Boolean,\n default: false,\n },\n});\n\nconst emits = defineEmits(\n [\n /**\n * It will emit the selected emoji\n * @event selected-emoji\n * @param {Object} emoji - The selected emoji from the emoji selector\n */\n 'selected-emoji',\n\n /**\n * Emitted when the user reach bottom scroll\n * This is being handled by handleScroll method\n * @event scroll-bottom-reached\n */\n 'scroll-bottom-reached',\n\n /**\n * It will emit the selected skin tone\n * @event skin-tone\n * @param {String} skin - The selected skin tone from the skin selector\n */\n 'skin-tone',\n\n /**\n * Since the keyboard events are encapsulated, we emit this event to close the picker\n * @event close\n */\n 'close',\n\n /**\n * Emitted when the user clicks on the add emoji button\n * @event add-emoji\n */\n 'add-emoji',\n ],\n);\n\nconst internalSearchQuery = ref(props.searchQuery.value);\nconst highlightedEmoji = ref(null);\nconst selectedTabset = ref({});\n\nconst scrollIntoTab = ref(0);\n\nconst showRecentlyUsedTab = computed(() => props.recentlyUsedEmojis?.length > 0);\nconst showCustomEmojisTab = computed(() => props.customEmojis?.length > 0);\n\nconst i18n = new DialtoneLocalization();\n\nconst tabSetLabels = [\n i18n.$t('DIALTONE_EMOJI_PICKER_TABSET_RECENTLY_USED_LABEL'),\n i18n.$t('DIALTONE_EMOJI_PICKER_TABSET_SMILEYS_AND_PEOPLE_LABEL'),\n i18n.$t('DIALTONE_EMOJI_PICKER_TABSET_NATURE_LABEL'),\n i18n.$t('DIALTONE_EMOJI_PICKER_TABSET_FOOD_LABEL'),\n i18n.$t('DIALTONE_EMOJI_PICKER_TABSET_ACTIVITY_LABEL'),\n i18n.$t('DIALTONE_EMOJI_PICKER_TABSET_TRAVEL_LABEL'),\n i18n.$t('DIALTONE_EMOJI_PICKER_TABSET_OBJECTS_LABEL'),\n i18n.$t('DIALTONE_EMOJI_PICKER_TABSET_SYMBOLS_LABEL'),\n i18n.$t('DIALTONE_EMOJI_PICKER_TABSET_FLAGS_LABEL'),\n i18n.$t('DIALTONE_EMOJI_PICKER_TABSET_CUSTOM_LABEL'),\n];\n\nconst searchPlaceholderLabel = i18n.$t('DIALTONE_EMOJI_PICKER_SEARCH_PLACEHOLDER_LABEL');\nconst searchResultsLabel = i18n.$t('DIALTONE_EMOJI_PICKER_SEARCH_RESULTS_LABEL');\nconst searchNoResultsLabel = i18n.$t('DIALTONE_EMOJI_PICKER_SEARCH_NO_RESULTS_LABEL');\nconst skinSelectorButtonTooltipLabel = i18n.$t('DIALTONE_EMOJI_PICKER_SKIN_SELECTOR_BUTTON_TOOLTIP_LABEL');\nconst addEmojiLabel = i18n.$t('DIALTONE_EMOJI_PICKER_ADD_EMOJI_LABEL');\n\nwatch(\n () => props.searchQuery,\n (newValue) => {\n internalSearchQuery.value = newValue;\n },\n);\n\n/**\n * Handle the selected tabset event\n * We're creating a new object with the same value as selectedTabset and assigning it back to selectedTabset.\n * Vue will see this as a new object and trigger the watcher in the child component.\n * Using this method, we are able to trigger the watcher in the child component even if the value being passed is the\n * same as the previous value.\n * @event selectedTabset\n * @param tabId {String} - The id of the tab that was selected\n */\nfunction scrollToSelectedTabset (tabId) {\n internalSearchQuery.value = '';\n selectedTabset.value = { ...selectedTabset.value, tabId };\n}\n\nfunction updateScrollIntoTab (value) {\n scrollIntoTab.value = value;\n}\n\nfunction updateHighlightedEmoji (emoji) {\n highlightedEmoji.value = emoji;\n}\n</script>\n"],"names":["emits","__emit","searchInput","ref","clearSearch","focusSearchInput","onMounted","__expose","props","__props","TABS_DATA","DtIconClock","DtIconSatisfied","DtIconLivingThing","DtIconFood","DtIconObject","DtIconTransportation","DtIconLightbulb","DtIconHeart","DtIconFlag","DtIconTiktok","tabs","computed","tabsData","tab","index","isSearching","selectedTab","tabsetRef","watch","selectTabset","id","parseId","setTabsetRef","returnFirstEl","focusTabset","handleKeyDown","event","tabId","useKeyboardNavigation","emojiRefs","emojiFilteredRefs","isFiltering","hoverFirstEmoji","_handleArrowLeft","indexTab","indexEmoji","focusEmoji","_handleArrowRight","_handleArrowLeftFiltered","_handleArrowRightFiltered","_handleHorizontalNavigation","direction","emojiRef","_a","_c","_b","setEmojiRef","el","setFilteredRef","handleArrowNavigationFiltered","key","ARROW_KEYS","position","EMOJIS_PER_ROW","lastEmojiPosition","handleArrowNavigation","numberOfMissingEmojis","emojiToJump","previousTab","emojisInPreviousTab","tabCategoryRef","listRef","tabLabelObserver","tabLabels","updateTabLabels","label","fixedLabel","updateTabsOrder","filteredEmojis","currentEmojis","emojis","debouncedSearch","debounce","searchByNameAndKeywords","handleScroll","container","resetScroll","highlightEmoji","scrollToTab","hoverEmoji","emoji","isFirst","searchStr","obj","nameIncludesSearchStr","keywordsIncludeSearchStr","keyword","nextTick","fn","delay","timeout","args","getImgSrc","CDN_URL","handleImageError","tabIndex","focusFirstEmoji","tabElement","offsetTop","setBottomScrollListener","setTabLabelObserver","entries","entry","target","_d","_e","child","handleKeyDownFilteredEmojis","selectEmoji","focusEmojiSelector","focusLastEmoji","onBeforeUnmount","skinList","EMOJI_PICKER_SKIN_TONE_MODIFIERS","isOpen","skinSelectorRef","skinsRef","watchEffect","skinPassedIn","skin","skinSelected","setSkinsRef","focusSkinSelector","selectSkin","toggleSkinList","internalSearchQuery","highlightedEmoji","selectedTabset","scrollIntoTab","showRecentlyUsedTab","showCustomEmojisTab","i18n","DialtoneLocalization","tabSetLabels","searchPlaceholderLabel","searchResultsLabel","searchNoResultsLabel","skinSelectorButtonTooltipLabel","addEmojiLabel","newValue","scrollToSelectedTabset","updateScrollIntoTab","value","updateHighlightedEmoji"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"emoji-picker.cjs","sources":["../../../components/emoji_picker/modules/emoji_search.vue","../../../components/emoji_picker/modules/emoji_tabset.vue","../../../components/emoji_picker/composables/useKeyboardNavigation.js","../../../components/emoji_picker/modules/emoji_selector.vue","../../../components/emoji_picker/modules/emoji_skin_selector.vue","../../../components/emoji_picker/modules/emoji_description.vue","../../../components/emoji_picker/emoji_picker.vue"],"sourcesContent":["<template>\n <div class=\"d-emoji-picker__search d-emoji-picker__alignment\">\n <dt-input\n id=\"searchInput\"\n ref=\"searchInput\"\n :placeholder=\"searchPlaceholderLabel\"\n :model-value=\"modelValue\"\n @update:model-value=\"$emit('update:modelValue', $event)\"\n @keydown.up=\"$emit('focus-tabset')\"\n @keydown.down.prevent=\"$emit('focus-emoji-selector')\"\n @keydown.enter=\"$emit('select-first-emoji')\"\n >\n <template #leftIcon>\n <dt-icon-search\n size=\"200\"\n />\n </template>\n <template\n v-if=\"modelValue.length > 0\"\n #rightIcon\n >\n <dt-button\n importance=\"clear\"\n size=\"xs\"\n class=\"d-emoji-picker__search-x-button\"\n circle\n kind=\"muted\"\n @click=\"clearSearch\"\n >\n <template #icon>\n <dt-icon-close\n size=\"200\"\n />\n </template>\n </dt-button>\n </template>\n </dt-input>\n </div>\n</template>\n\n<script setup>\nimport { DtIconSearch, DtIconClose } from '@dialpad/dialtone-icons/vue3';\nimport { DtInput } from '@/components/input';\nimport { DtButton } from '@/components/button';\nimport { onMounted, ref } from 'vue';\n\ndefineProps({\n searchPlaceholderLabel: {\n type: String,\n required: true,\n },\n modelValue: {\n type: String,\n default: '',\n },\n});\n\nconst emits = defineEmits(['update:modelValue', 'focus-emoji-selector', 'focus-tabset', 'select-first-emoji']);\n\nconst searchInput = ref(null);\n\nfunction clearSearch () {\n emits('update:modelValue', '');\n focusSearchInput();\n}\n\nfunction focusSearchInput () {\n searchInput.value.focus();\n}\nonMounted(() => {\n focusSearchInput();\n});\n\ndefineExpose({\n focusSearchInput,\n});\n</script>\n","<template>\n <div class=\"d-emoji-picker__tabset\">\n <dt-tab-group\n :selected=\"selectedTab\"\n size=\"sm\"\n tab-list-class=\"d-emoji-picker__tabset-list\"\n >\n <template #tabs>\n <dt-tab\n v-for=\"(tab, index) in tabs\"\n :id=\"tab.id\"\n :key=\"tab.id\"\n :ref=\"el => { if (el) setTabsetRef(el) }\"\n :label=\"tab.label\"\n :panel-id=\"tab.panelId\"\n :tabindex=\"index + 1\"\n aria-controls=\"d-emoji-picker-list\"\n @keydown=\"handleKeyDown($event, tab.id)\"\n @click.capture.stop=\"selectTabset(tab.id)\"\n >\n <component\n :is=\"tab.icon\"\n size=\"400\"\n />\n </dt-tab>\n </template>\n </dt-tab-group>\n </div>\n</template>\n\n<script setup>\nimport { computed, ref, watch } from 'vue';\nimport { DtTab, DtTabGroup } from '@/components/tab';\nimport { returnFirstEl } from '@/common/utils';\nimport {\n DtIconClock,\n DtIconSatisfied,\n DtIconLivingThing,\n DtIconFood,\n DtIconObject,\n DtIconTransportation,\n DtIconLightbulb,\n DtIconHeart,\n DtIconFlag,\n DtIconDialpadStar,\n} from '@dialpad/dialtone-icons/vue3';\n\nconst props = defineProps({\n /**\n * Whether to show the recently used tab or not\n * @type {Boolean}\n * @default false\n */\n showRecentlyUsedTab: {\n type: Boolean,\n default: false,\n },\n\n /**\n * Whether to show the custom emojis tab or not\n * @type {Boolean}\n * @default false\n */\n showCustomEmojisTab: {\n type: Boolean,\n default: false,\n },\n\n scrollIntoTab: {\n type: Number,\n required: true,\n },\n\n emojiFilter: {\n type: String,\n default: '',\n },\n\n /**\n * The labels for the aria-label\n * @type {Array}\n * @required\n */\n tabSetLabels: {\n type: Array,\n required: true,\n },\n});\n\nconst emits = defineEmits([\n /**\n * Emitted when a tab is selected\n * @event selected-tabset\n * @param {String} tabId - The name of the tab that was selected\n */\n 'selected-tabset',\n\n 'focus-search-input',\n 'focus-skin-selector',\n]);\n\nconst TABS_DATA = [\n { label: props.tabSetLabels[0], icon: DtIconClock },\n { label: props.tabSetLabels[1], icon: DtIconSatisfied },\n { label: props.tabSetLabels[2], icon: DtIconLivingThing },\n { label: props.tabSetLabels[3], icon: DtIconFood },\n { label: props.tabSetLabels[4], icon: DtIconObject },\n { label: props.tabSetLabels[5], icon: DtIconTransportation },\n { label: props.tabSetLabels[6], icon: DtIconLightbulb },\n { label: props.tabSetLabels[7], icon: DtIconHeart },\n { label: props.tabSetLabels[8], icon: DtIconFlag },\n { label: props.tabSetLabels[9], icon: DtIconDialpadStar },\n];\n\nconst tabs = computed(() => {\n const tabsData = props.showRecentlyUsedTab ? TABS_DATA : TABS_DATA.slice(1);\n // if showCustomEmojisTab is false remove last index of TABS_DATA\n if (!props.showCustomEmojisTab) {\n tabsData.pop();\n }\n\n return tabsData.map((tab, index) => ({\n ...tab,\n // IDs on dt-tab component need to be on string\n id: (index + 1).toString(),\n panelId: (index + 1).toString(),\n }));\n});\n\nconst isSearching = computed(() => props.emojiFilter.length > 0);\n\nconst selectedTab = ref('1');\n\nconst tabsetRef = ref([]);\n\nwatch(() => props.scrollIntoTab,\n () => {\n if (!isSearching.value) {\n selectedTab.value = (props.scrollIntoTab + 1).toString();\n }\n });\n\nwatch(isSearching,\n () => {\n if (isSearching.value) {\n selectedTab.value = null;\n }\n });\n\n/**\n * We are using .capture.stop modifiers on the click event\n * because we don't want to trigger the click event of the\n * dt-tab component\n */\nfunction selectTabset (id) {\n // IDs on scrollToTab need to be on number\n const parseId = parseInt(id);\n // IDs on dt-tab component need to be on string\n selectedTab.value = id;\n emits('selected-tabset', parseId);\n}\n\nfunction setTabsetRef (ref) {\n // We push the $el, because $el is the button inside the dt-tab component\n // and we need the button to focus it\n tabsetRef.value.push(returnFirstEl(ref.$el));\n}\n\nfunction focusTabset () {\n tabsetRef.value[0].focus();\n}\n\nfunction handleKeyDown (event, tabId) {\n if (event.key === 'Enter') {\n selectTabset(tabId);\n // We blur because seems like the tab component override the selected prop, and it removes the selected style\n tabsetRef.value[tabId - 1].blur();\n }\n\n if (event.key === 'Tab') {\n event.preventDefault();\n if (event.shiftKey) {\n emits('focus-skin-selector');\n } else {\n emits('focus-search-input');\n }\n }\n\n if (event.key === 'ArrowDown') {\n // Jump to search input\n emits('focus-search-input');\n }\n}\n\ndefineExpose({\n focusTabset,\n});\n</script>\n","import { ref } from 'vue';\nimport { EMOJIS_PER_ROW, ARROW_KEYS } from '@/components/emoji_picker/emoji_picker_constants';\n\nexport function useKeyboardNavigation () {\n const emojiRefs = ref([]);\n const emojiFilteredRefs = ref([]);\n const isFiltering = ref(false);\n const hoverFirstEmoji = ref(true);\n\n function _handleArrowLeft (indexTab, indexEmoji) {\n if (!focusEmoji(indexTab, indexEmoji - 1)) {\n if (emojiRefs.value[indexTab - 1]) {\n focusEmoji(indexTab - 1, emojiRefs.value[indexTab - 1].length - 1);\n } else {\n focusEmoji(emojiRefs.value.length - 1, emojiRefs.value[emojiRefs.value.length - 1].length - 1);\n }\n }\n }\n\n function _handleArrowRight (indexTab, indexEmoji) {\n if (!focusEmoji(indexTab, indexEmoji + 1)) {\n if (!focusEmoji(indexTab + 1, 0)) {\n focusEmoji(0, 0);\n }\n }\n }\n\n function _handleArrowLeftFiltered (indexTab, indexEmoji) {\n if (!focusEmoji(0, indexEmoji - 1)) {\n focusEmoji(0, emojiFilteredRefs.value.length - 1);\n }\n }\n\n function _handleArrowRightFiltered (indexTab, indexEmoji) {\n if (!focusEmoji(0, indexEmoji + 1)) {\n focusEmoji(0, 0);\n }\n }\n\n function _handleHorizontalNavigation (direction, indexTab, indexEmoji) {\n if (isFiltering.value) {\n if (direction === 'left') {\n _handleArrowLeftFiltered(indexTab, indexEmoji);\n } else if (direction === 'right') {\n _handleArrowRightFiltered(indexTab, indexEmoji);\n }\n } else {\n if (direction === 'left') {\n _handleArrowLeft(indexTab, indexEmoji);\n } else if (direction === 'right') {\n _handleArrowRight(indexTab, indexEmoji);\n }\n }\n }\n\n function focusEmoji (indexTab, indexEmoji) {\n const emojiRef = isFiltering.value\n ? emojiFilteredRefs.value?.[indexEmoji]\n : emojiRefs.value?.[indexTab]?.[indexEmoji];\n\n if (emojiRef) {\n emojiRef.focus();\n return true;\n }\n\n return false;\n }\n\n function setEmojiRef (el, indexTab, indexEmoji) {\n if (!emojiRefs.value[indexTab]) {\n emojiRefs.value[indexTab] = [];\n }\n emojiRefs.value[indexTab][indexEmoji] = el;\n }\n\n function setFilteredRef (el, index) {\n emojiFilteredRefs.value[index] = el;\n }\n\n function handleArrowNavigationFiltered (key, indexEmoji) {\n hoverFirstEmoji.value = false;\n\n if (key === ARROW_KEYS.ARROW_UP) {\n const position = indexEmoji % EMOJIS_PER_ROW;\n\n if (!focusEmoji(0, indexEmoji - EMOJIS_PER_ROW)) {\n const lastEmojiPosition =\n emojiFilteredRefs.value.length - (emojiFilteredRefs.value.length % EMOJIS_PER_ROW) + position;\n\n focusEmoji(0, lastEmojiPosition);\n\n if (!focusEmoji(0, lastEmojiPosition)) {\n focusEmoji(0, emojiFilteredRefs.value.length - 1);\n }\n }\n }\n\n if (key === ARROW_KEYS.ARROW_DOWN) {\n if (!focusEmoji(0, indexEmoji + EMOJIS_PER_ROW)) {\n const position = indexEmoji % EMOJIS_PER_ROW;\n\n if (emojiFilteredRefs.value?.[indexEmoji + (EMOJIS_PER_ROW - position)]) {\n focusEmoji(0, emojiFilteredRefs.value.length - 1);\n } else {\n focusEmoji(0, position);\n }\n }\n }\n\n if (key === ARROW_KEYS.ARROW_LEFT) {\n _handleHorizontalNavigation('left', 0, indexEmoji);\n }\n\n if (key === ARROW_KEYS.ARROW_RIGHT) {\n _handleHorizontalNavigation('right', 0, indexEmoji);\n }\n }\n\n function handleArrowNavigation (key, indexTab, indexEmoji) {\n if (key === 'ArrowUp') {\n const position = indexEmoji % EMOJIS_PER_ROW;\n\n if (indexTab === 0) {\n // we are on the first emoji tab, then we should jump to the last row of the last emoji tab\n const numberOfMissingEmojis =\n EMOJIS_PER_ROW - (emojiRefs.value[emojiRefs.value.length - 1].length % EMOJIS_PER_ROW);\n\n const emojiToJump =\n emojiRefs.value[emojiRefs.value.length - 1].length + numberOfMissingEmojis - (EMOJIS_PER_ROW - position);\n\n if (!focusEmoji(emojiRefs.value.length - 1, emojiToJump)) {\n // if there is no emoji in this position, jump to the last emoji of the row\n focusEmoji(emojiRefs.value.length - 1, emojiRefs.value[emojiRefs.value.length - 1].length - 1);\n }\n return;\n }\n\n // if we are not on the first tab, we should jump to the previous row of the current tab\n if (!focusEmoji(indexTab, indexEmoji - EMOJIS_PER_ROW)) {\n // if there is no previous row, we should jump to emoji in the sampe position of the previous tab\n const previousTab = indexTab - 1 < 0 ? 0 : indexTab - 1;\n const emojisInPreviousTab = emojiRefs.value[previousTab].length;\n const lastEmojiPosition = emojisInPreviousTab - (emojisInPreviousTab % EMOJIS_PER_ROW) + position;\n\n if (!focusEmoji(previousTab, lastEmojiPosition)) {\n // if there is no emoji in this position, jump to the last emoji of the row\n focusEmoji(indexTab - 1, emojiRefs.value[indexTab - 1].length - 1);\n }\n }\n }\n\n if (key === 'ArrowDown') {\n if (!focusEmoji(indexTab, indexEmoji + EMOJIS_PER_ROW)) {\n // if cannot go down\n\n // Calculate position from cell 0 to cell 8\n const position = indexEmoji % EMOJIS_PER_ROW;\n\n // check if it exists a next row in the current tab\n if (emojiRefs.value?.[indexTab]?.[indexEmoji + (EMOJIS_PER_ROW - position)]) {\n // if it exists, we should focus the last emoji of the next row in the current tab\n focusEmoji(indexTab, emojiRefs.value[indexTab].length - 1);\n // if we are at the end of the list it will do nothing\n } else {\n // We don't have next row, we are in the last of the tab, then jump\n // to the next tab but in the equal emoji position in row 0.\n\n if (!focusEmoji(indexTab + 1, position)) {\n // We are on the bottom!, should jump to the same position emoji in the first row of the first tabset\n // if it doesn't has, jump to the last\n if (!focusEmoji(0, position)) {\n focusEmoji(0, emojiRefs.value[0].length - 1);\n }\n }\n }\n }\n }\n\n if (key === 'ArrowLeft') {\n _handleHorizontalNavigation('left', indexTab, indexEmoji);\n }\n\n if (key === 'ArrowRight') {\n _handleHorizontalNavigation('right', indexTab, indexEmoji);\n }\n }\n\n return {\n emojiFilteredRefs,\n isFiltering,\n hoverFirstEmoji,\n setEmojiRef,\n setFilteredRef,\n focusEmoji,\n handleArrowNavigationFiltered,\n handleArrowNavigation,\n };\n}\n","<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)\"\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, onBeforeUnmount, 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 /**\n * The list of custom emojis\n * @type {Array}\n */\n customEmojis: {\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 bottom scroll\n * This event is used on handleScroll method\n * @event scroll-bottom-reached\n */\n 'scroll-bottom-reached',\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', 'Custom'];\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 or custom emojis list is empty\n * If it is empty, it will remove it\n */\nconst tabLabels = computed(() => {\n let updateTabLabels = props.tabsetLabels.map((label) => ({ label, ref: ref(null) }));\n\n if (props.recentlyUsedEmojis && !props.recentlyUsedEmojis.length) {\n updateTabLabels = props.tabsetLabels.slice(1).map((label) => ({ label, ref: ref(null) }));\n }\n\n if (props.customEmojis && !props.customEmojis.length) {\n updateTabLabels.pop();\n }\n\n return updateTabLabels;\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 or custom emojis is empty\n * If it is empty, it will remove it\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 const updateTabsOrder = props.recentlyUsedEmojis.length ? TABS_DATA.slice() : TABS_DATA.slice(1);\n\n if (props.customEmojis && !props.customEmojis.length) {\n updateTabsOrder.pop();\n }\n\n return updateTabsOrder;\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 * handleScroll will be defined when user scroll\n */\nconst handleScroll = () => {\n const container = listRef.value;\n // TODO -- this will probably need to be updated if we add more emojis.\n // because the container height will change.\n // maybe with a nextTick similar of scrollToTab.\n if (container.scrollTop + container.clientHeight >= container.scrollHeight) {\n emits('scroll-bottom-reached');\n }\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 * Update the custom emojis list on custom emojis prop changes\n * @listens customEmojis\n */\nwatch(() => props.customEmojis,\n () => {\n emojis.Custom = props.customEmojis;\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 // TODO Update json structure to have a property for custom emojis and avoid using date_added\n if (emoji.date_added) { // if custom emoji\n return emoji.image;\n } else { // if regular emoji\n return CDN_URL + emoji.unicode_character + '.png';\n }\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\nfunction setBottomScrollListener () {\n listRef.value.addEventListener('scroll', handleScroll);\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 setBottomScrollListener();\n});\n\nonBeforeUnmount(() => {\n tabLabelObserver.value.disconnect();\n listRef.value.removeEventListener('scroll', handleScroll);\n});\n\ndefineExpose({\n focusEmojiSelector,\n focusLastEmoji,\n});\n</script>\n","<template>\n <div data-qa=\"skin-selector\">\n <div\n v-show=\"isOpen\"\n class=\"d-emoji-picker__skin-list\"\n >\n <button\n v-for=\"(skin, index) in skinList\"\n :ref=\"el => { if (el) setSkinsRef(el) }\"\n :key=\"skin.name\"\n :class=\"{\n 'selected': skinSelected.skinCode === skin.skinCode,\n }\"\n @keydown=\"event => handleKeyDown(event, skin, index)\"\n @click=\"selectSkin(skin)\"\n >\n <img\n class=\"d-icon d-icon--size-500\"\n :alt=\"skin.name\"\n :aria-label=\"skin.name\"\n :title=\"skin.name\"\n :src=\"`${CDN_URL + skin.unicode_output}.png`\"\n >\n </button>\n </div>\n <div\n v-show=\"!isOpen\"\n class=\"d-emoji-picker__skin-selected\"\n >\n <dt-tooltip placement=\"top-end\">\n {{ skinSelectorButtonTooltipLabel }}\n <template #anchor>\n <button\n ref=\"skinSelectorRef\"\n :aria-label=\"skinSelectorButtonTooltipLabel\"\n tabindex=\"-1\"\n @click=\"toggleSkinList\"\n @keydown=\"event => handleKeyDown(event)\"\n >\n <img\n class=\"d-icon d-icon--size-500\"\n :alt=\"skinSelected.name\"\n :aria-label=\"skinSelected.name\"\n :title=\"skinSelected.name\"\n :src=\"`${CDN_URL + skinSelected.unicode_output}.png`\"\n >\n </button>\n </template>\n </dt-tooltip>\n </div>\n </div>\n</template>\n\n<script setup>\nimport { computed, nextTick, ref, watchEffect } from 'vue';\nimport { CDN_URL, EMOJI_PICKER_SKIN_TONE_MODIFIERS } from '@/components/emoji_picker/emoji_picker_constants.js';\nimport { DtTooltip } from '@/components/tooltip';\n\nconst props = defineProps({\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 isHovering: {\n type: Boolean,\n default: false,\n },\n\n skinSelectorButtonTooltipLabel: {\n type: String,\n required: true,\n },\n});\n\nconst emits = defineEmits([\n /**\n * The skin tone that was selected\n * @event skin-tone\n * @type {Number}\n */\n 'skin-tone',\n 'focus-tabset',\n 'focus-last-emoji',\n]);\n\nconst skinList = [\n {\n name: ':wave_tone1:',\n unicode_output: '1f44b-1f3fb',\n skinTone: EMOJI_PICKER_SKIN_TONE_MODIFIERS.LIGHT,\n skinCode: '_tone1',\n },\n {\n name: ':wave_tone2:',\n unicode_output: '1f44b-1f3fc',\n skinTone: EMOJI_PICKER_SKIN_TONE_MODIFIERS.MEDIUM_LIGHT,\n skinCode: '_tone2',\n },\n {\n name: ':wave_tone3:',\n unicode_output: '1f44b-1f3fd',\n skinTone: EMOJI_PICKER_SKIN_TONE_MODIFIERS.MEDIUM,\n skinCode: '_tone3',\n },\n {\n name: ':wave_tone4:',\n unicode_output: '1f44b-1f3fe',\n skinTone: EMOJI_PICKER_SKIN_TONE_MODIFIERS.MEDIUM_DARK,\n skinCode: '_tone4',\n },\n {\n name: ':wave_tone5:',\n unicode_output: '1f44b-1f3ff',\n skinTone: EMOJI_PICKER_SKIN_TONE_MODIFIERS.DARK,\n skinCode: '_tone5',\n },\n {\n name: ':wave:',\n unicode_output: '1f44b',\n skinTone: EMOJI_PICKER_SKIN_TONE_MODIFIERS.DEFAULT,\n skinCode: '',\n },\n];\n\nconst isOpen = ref(false);\n\nconst skinSelectorRef = ref(null);\n\nconst skinsRef = ref([]);\n\n/**\n * It will close the skin selector if the user is hovering over the emoji list\n */\nwatchEffect(\n () => props.isHovering && (isOpen.value = false),\n);\n\n/**\n * It will initially display props.skinTone. If a new skin tone is selected,\n * it will display that until props.skinTone changes.\n */\nconst skinPassedIn = computed(() => skinList.find((skin) => skin.skinTone === props.skinTone));\nconst skinSelected = ref(skinPassedIn.value);\nwatchEffect(() => skinPassedIn.value && (skinSelected.value = skinPassedIn.value));\n\nfunction setSkinsRef (ref) {\n skinsRef.value.push(ref);\n}\nfunction focusSkinSelector () {\n skinSelectorRef.value.focus();\n}\n\nfunction selectSkin (skin) {\n skinSelected.value = skin;\n isOpen.value = false;\n emits('skin-tone', skin.skinTone);\n nextTick(() => focusSkinSelector());\n}\n\nconst handleKeyDown = (event, skin, index) => {\n event.preventDefault();\n\n if (event.key === 'ArrowLeft') {\n if (index === 0) skinsRef.value[skinsRef.value.length - 1]?.focus();\n skinsRef.value[index - 1]?.focus();\n }\n\n if (event.key === 'ArrowRight') {\n skinsRef.value[index + 1]?.focus();\n }\n\n if (event.key === 'Enter') {\n if (skin) { selectSkin(skin); } else {\n toggleSkinList();\n }\n }\n\n if (event.key === 'Tab') {\n if (event.shiftKey) {\n emits('focus-last-emoji');\n } else {\n emits('focus-tabset');\n }\n }\n};\n\nfunction toggleSkinList () {\n isOpen.value = !isOpen.value;\n nextTick(() => skinsRef.value[0].focus());\n}\n\ndefineExpose({\n focusSkinSelector,\n});\n</script>\n","<template>\n <div class=\"d-emoji-picker__data\">\n <img\n v-if=\"emoji\"\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)\"\n >\n <div>{{ emoji?.name }}</div>\n </div>\n</template>\n\n<script setup>\nimport { CDN_URL } from '@/components/emoji_picker/emoji_picker_constants';\n\ndefineProps({\n /**\n * Emoji data\n * @type {Object}\n * @default null\n */\n emoji: {\n type: Object,\n default: null,\n },\n});\n\nfunction getImgSrc (emoji) {\n if (emoji.date_added) { // if custom emoji\n return emoji.image;\n } else { // if regular emoji\n return `${CDN_URL + emoji.unicode_character}.png`;\n }\n}\n</script>\n","<template>\n <div\n class=\"d-emoji-picker\"\n >\n <div class=\"d-emoji-picker--header\">\n <emoji-tabset\n ref=\"tabsetRef\"\n :emoji-filter=\"internalSearchQuery\"\n :show-custom-emojis-tab=\"showCustomEmojisTab\"\n :show-recently-used-tab=\"showRecentlyUsedTab\"\n :scroll-into-tab=\"scrollIntoTab\"\n :tab-set-labels=\"tabSetLabels\"\n @focus-skin-selector=\"$refs.skinSelectorRef.focusSkinSelector()\"\n @focus-search-input=\"showSearch\n ? $refs.searchInputRef.focusSearchInput()\n : $refs.emojiSelectorRef.focusEmojiSelector()\"\n @selected-tabset=\"scrollToSelectedTabset\"\n @keydown.esc=\"emits('close')\"\n />\n </div>\n <div class=\"d-emoji-picker--body\">\n <emoji-search\n v-if=\"showSearch\"\n ref=\"searchInputRef\"\n v-model=\"internalSearchQuery\"\n :search-placeholder-label=\"searchPlaceholderLabel\"\n @select-first-emoji=\"emits('selected-emoji', highlightedEmoji)\"\n @focus-tabset=\"$refs.tabsetRef.focusTabset()\"\n @focus-emoji-selector=\"$refs.emojiSelectorRef.focusEmojiSelector()\"\n @keydown.esc=\"emits('close')\"\n />\n <emoji-selector\n ref=\"emojiSelectorRef\"\n :emoji-filter=\"internalSearchQuery\"\n :skin-tone=\"skinTone\"\n :tabset-labels=\"tabSetLabels\"\n :search-results-label=\"searchResultsLabel\"\n :search-no-results-label=\"searchNoResultsLabel\"\n :recently-used-emojis=\"recentlyUsedEmojis\"\n :custom-emojis=\"customEmojis\"\n :selected-tabset=\"selectedTabset\"\n @scroll-into-tab=\"updateScrollIntoTab\"\n @highlighted-emoji=\"updateHighlightedEmoji\"\n @selected-emoji=\"emits('selected-emoji', $event)\"\n @focus-skin-selector=\"$refs.skinSelectorRef.focusSkinSelector()\"\n @focus-search-input=\"showSearch ? $refs.searchInputRef.focusSearchInput() : $refs.tabsetRef.focusTabset()\"\n @keydown.esc=\"emits('close')\"\n @scroll-bottom-reached=\"emits('scroll-bottom-reached')\"\n />\n </div>\n <div class=\"d-emoji-picker--footer\">\n <dt-button\n v-if=\"showAddEmojiButton && !highlightedEmoji\"\n importance=\"outlined\"\n :aria-label=\"addEmojiLabel\"\n class=\"d-emoji-picker__add-emoji\"\n @click=\"emits('add-emoji')\"\n >\n {{ addEmojiLabel }}\n </dt-button>\n <emoji-description :emoji=\"highlightedEmoji\" />\n <emoji-skin-selector\n ref=\"skinSelectorRef\"\n :is-hovering=\"!!highlightedEmoji\"\n :skin-selector-button-tooltip-label=\"skinSelectorButtonTooltipLabel\"\n :skin-tone=\"skinTone\"\n @skin-tone=\"emits('skin-tone', $event)\"\n @focus-tabset=\"$refs.tabsetRef.focusTabset()\"\n @focus-last-emoji=\"$refs.emojiSelectorRef.focusLastEmoji()\"\n @keydown.esc=\"emits('close')\"\n />\n </div>\n </div>\n</template>\n\n<script setup>\nimport EmojiSearch from './modules/emoji_search.vue';\nimport EmojiTabset from './modules/emoji_tabset.vue';\nimport EmojiSelector from './modules/emoji_selector.vue';\nimport EmojiSkinSelector from './modules/emoji_skin_selector.vue';\nimport EmojiDescription from './modules/emoji_description.vue';\nimport { DtButton } from '../button';\nimport { computed, ref, watch } from 'vue';\nimport { DialtoneLocalization } from '@/localization';\n\nconst props = defineProps({\n /**\n * The array with recently used emoji object\n * This list is necessary to fill the recently used tab\n * @type {Array}\n * @default []\n * @example\n * <dt-emoji-picker :recentlyUsedEmojis=\"[emojiObject, emojiObject]\" />\n */\n // TODO try to simplify this to achieve an array of unicode characters and not an entire emoji data object\n recentlyUsedEmojis: {\n type: Array,\n default: () => [],\n },\n\n /**\n * The array with custom emojis object\n * This list is necessary to fill the custom tab\n * @type {Array}\n * @default []\n * @example\n * <dt-emoji-picker :customEmojis=\"[emojiObject, emojiObject]\" />\n */\n customEmojis: {\n type: Array,\n },\n\n /**\n * The skin tone to show the emojis\n * This prop gives the possibility to use the skin tone selected by the user previously\n * @type {String}\n * @default 'Default'\n * @values 'Default', 'Light', 'MediumLight', 'Medium', 'MediumDark', 'Dark'\n * @example\n * <dt-emoji-picker :skinTone=\"'Default'\" />\n */\n skinTone: {\n type: String,\n default: 'Default',\n },\n\n /**\n\n * Sets the search query that filters emojis.\n * @type {String}\n * @example\n * <dt-emoji-picker search-query=\"smile\" />\n */\n searchQuery: {\n type: String,\n default: '',\n },\n\n /**\n * Shows the search input\n * @type {Boolean}\n * @example\n * <dt-emoji-picker :show-search=\"false\" />\n */\n showSearch: {\n type: Boolean,\n default: true,\n },\n\n /**\n * Shows the add emoji button in the footer when no emoji is highlighted\n * @type {Boolean}\n * @example\n * <dt-emoji-picker :show-add-emoji-button=\"true\" />\n */\n showAddEmojiButton: {\n type: Boolean,\n default: false,\n },\n});\n\nconst emits = defineEmits(\n [\n /**\n * It will emit the selected emoji\n * @event selected-emoji\n * @param {Object} emoji - The selected emoji from the emoji selector\n */\n 'selected-emoji',\n\n /**\n * Emitted when the user reach bottom scroll\n * This is being handled by handleScroll method\n * @event scroll-bottom-reached\n */\n 'scroll-bottom-reached',\n\n /**\n * It will emit the selected skin tone\n * @event skin-tone\n * @param {String} skin - The selected skin tone from the skin selector\n */\n 'skin-tone',\n\n /**\n * Since the keyboard events are encapsulated, we emit this event to close the picker\n * @event close\n */\n 'close',\n\n /**\n * Emitted when the user clicks on the add emoji button\n * @event add-emoji\n */\n 'add-emoji',\n ],\n);\n\nconst internalSearchQuery = ref(props.searchQuery.value);\nconst highlightedEmoji = ref(null);\nconst selectedTabset = ref({});\n\nconst scrollIntoTab = ref(0);\n\nconst showRecentlyUsedTab = computed(() => props.recentlyUsedEmojis?.length > 0);\nconst showCustomEmojisTab = computed(() => props.customEmojis?.length > 0);\n\nconst i18n = new DialtoneLocalization();\n\nconst tabSetLabels = [\n i18n.$t('DIALTONE_EMOJI_PICKER_TABSET_RECENTLY_USED_LABEL'),\n i18n.$t('DIALTONE_EMOJI_PICKER_TABSET_SMILEYS_AND_PEOPLE_LABEL'),\n i18n.$t('DIALTONE_EMOJI_PICKER_TABSET_NATURE_LABEL'),\n i18n.$t('DIALTONE_EMOJI_PICKER_TABSET_FOOD_LABEL'),\n i18n.$t('DIALTONE_EMOJI_PICKER_TABSET_ACTIVITY_LABEL'),\n i18n.$t('DIALTONE_EMOJI_PICKER_TABSET_TRAVEL_LABEL'),\n i18n.$t('DIALTONE_EMOJI_PICKER_TABSET_OBJECTS_LABEL'),\n i18n.$t('DIALTONE_EMOJI_PICKER_TABSET_SYMBOLS_LABEL'),\n i18n.$t('DIALTONE_EMOJI_PICKER_TABSET_FLAGS_LABEL'),\n i18n.$t('DIALTONE_EMOJI_PICKER_TABSET_CUSTOM_LABEL'),\n];\n\nconst searchPlaceholderLabel = i18n.$t('DIALTONE_EMOJI_PICKER_SEARCH_PLACEHOLDER_LABEL');\nconst searchResultsLabel = i18n.$t('DIALTONE_EMOJI_PICKER_SEARCH_RESULTS_LABEL');\nconst searchNoResultsLabel = i18n.$t('DIALTONE_EMOJI_PICKER_SEARCH_NO_RESULTS_LABEL');\nconst skinSelectorButtonTooltipLabel = i18n.$t('DIALTONE_EMOJI_PICKER_SKIN_SELECTOR_BUTTON_TOOLTIP_LABEL');\nconst addEmojiLabel = i18n.$t('DIALTONE_EMOJI_PICKER_ADD_EMOJI_LABEL');\n\nwatch(\n () => props.searchQuery,\n (newValue) => {\n internalSearchQuery.value = newValue;\n },\n);\n\n/**\n * Handle the selected tabset event\n * We're creating a new object with the same value as selectedTabset and assigning it back to selectedTabset.\n * Vue will see this as a new object and trigger the watcher in the child component.\n * Using this method, we are able to trigger the watcher in the child component even if the value being passed is the\n * same as the previous value.\n * @event selectedTabset\n * @param tabId {String} - The id of the tab that was selected\n */\nfunction scrollToSelectedTabset (tabId) {\n internalSearchQuery.value = '';\n selectedTabset.value = { ...selectedTabset.value, tabId };\n}\n\nfunction updateScrollIntoTab (value) {\n scrollIntoTab.value = value;\n}\n\nfunction updateHighlightedEmoji (emoji) {\n highlightedEmoji.value = emoji;\n}\n</script>\n"],"names":["emits","__emit","searchInput","ref","clearSearch","focusSearchInput","onMounted","__expose","props","__props","TABS_DATA","DtIconClock","DtIconSatisfied","DtIconLivingThing","DtIconFood","DtIconObject","DtIconTransportation","DtIconLightbulb","DtIconHeart","DtIconFlag","DtIconDialpadStar","tabs","computed","tabsData","tab","index","isSearching","selectedTab","tabsetRef","watch","selectTabset","id","parseId","setTabsetRef","returnFirstEl","focusTabset","handleKeyDown","event","tabId","useKeyboardNavigation","emojiRefs","emojiFilteredRefs","isFiltering","hoverFirstEmoji","_handleArrowLeft","indexTab","indexEmoji","focusEmoji","_handleArrowRight","_handleArrowLeftFiltered","_handleArrowRightFiltered","_handleHorizontalNavigation","direction","emojiRef","_a","_c","_b","setEmojiRef","el","setFilteredRef","handleArrowNavigationFiltered","key","ARROW_KEYS","position","EMOJIS_PER_ROW","lastEmojiPosition","handleArrowNavigation","numberOfMissingEmojis","emojiToJump","previousTab","emojisInPreviousTab","tabCategoryRef","listRef","tabLabelObserver","tabLabels","updateTabLabels","label","fixedLabel","updateTabsOrder","filteredEmojis","currentEmojis","emojis","debouncedSearch","debounce","searchByNameAndKeywords","handleScroll","container","resetScroll","highlightEmoji","scrollToTab","hoverEmoji","emoji","isFirst","searchStr","obj","nameIncludesSearchStr","keywordsIncludeSearchStr","keyword","nextTick","fn","delay","timeout","args","getImgSrc","CDN_URL","handleImageError","tabIndex","focusFirstEmoji","tabElement","offsetTop","setBottomScrollListener","setTabLabelObserver","entries","entry","target","_d","_e","child","handleKeyDownFilteredEmojis","selectEmoji","focusEmojiSelector","focusLastEmoji","onBeforeUnmount","skinList","EMOJI_PICKER_SKIN_TONE_MODIFIERS","isOpen","skinSelectorRef","skinsRef","watchEffect","skinPassedIn","skin","skinSelected","setSkinsRef","focusSkinSelector","selectSkin","toggleSkinList","internalSearchQuery","highlightedEmoji","selectedTabset","scrollIntoTab","showRecentlyUsedTab","showCustomEmojisTab","i18n","DialtoneLocalization","tabSetLabels","searchPlaceholderLabel","searchResultsLabel","searchNoResultsLabel","skinSelectorButtonTooltipLabel","addEmojiLabel","newValue","scrollToSelectedTabset","updateScrollIntoTab","value","updateHighlightedEmoji"],"mappings":"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"}
|
|
@@ -1,11 +1,11 @@
|
|
|
1
1
|
import { ref as S, onMounted as re, createElementBlock as I, openBlock as E, createVNode as F, unref as k, withKeys as J, withModifiers as ue, createSlots as ye, withCtx as N, computed as M, watch as K, Fragment as W, renderList as G, createBlock as Z, resolveDynamicComponent as Le, nextTick as x, onBeforeUnmount as Te, createElementVNode as A, createCommentVNode as Y, toDisplayString as z, withDirectives as te, vShow as oe, normalizeClass as ce, watchEffect as ae, createTextVNode as fe } from "vue";
|
|
2
|
-
import { DtIconSearch as je, DtIconClose as Ie, DtIconClock as Re, DtIconSatisfied as Ae, DtIconLivingThing as $e, DtIconFood as we, DtIconObject as Oe, DtIconTransportation as
|
|
2
|
+
import { DtIconSearch as je, DtIconClose as Ie, DtIconClock as Re, DtIconSatisfied as Ae, DtIconLivingThing as $e, DtIconFood as we, DtIconObject as Oe, DtIconTransportation as De, DtIconLightbulb as Ce, DtIconHeart as Be, DtIconFlag as Fe, DtIconDialpadStar as Ke } from "@dialpad/dialtone-icons/vue3";
|
|
3
3
|
import Ne from "../input/input.js";
|
|
4
4
|
import de from "../button/button.js";
|
|
5
5
|
import { returnFirstEl as Me } from "../../common/utils/index.js";
|
|
6
6
|
import Pe from "../tab/tab-group.js";
|
|
7
7
|
import Ue from "../tab/tab.js";
|
|
8
|
-
import { emojisGrouped as
|
|
8
|
+
import { emojisGrouped as D } from "@dialpad/dialtone-emojis";
|
|
9
9
|
import { EMOJIS_PER_ROW as $, ARROW_KEYS as H, CDN_URL as Q, EMOJI_PICKER_SKIN_TONE_MODIFIERS as V } from "./emoji-picker-constants.js";
|
|
10
10
|
import Je from "../tooltip/tooltip.js";
|
|
11
11
|
import { DialtoneLocalization as Ve } from "../../localization/index.js";
|
|
@@ -131,8 +131,8 @@ const He = { class: "d-emoji-picker__search d-emoji-picker__alignment" }, ze = {
|
|
|
131
131
|
{ label: l.tabSetLabels[2], icon: $e },
|
|
132
132
|
{ label: l.tabSetLabels[3], icon: we },
|
|
133
133
|
{ label: l.tabSetLabels[4], icon: Oe },
|
|
134
|
-
{ label: l.tabSetLabels[5], icon:
|
|
135
|
-
{ label: l.tabSetLabels[6], icon:
|
|
134
|
+
{ label: l.tabSetLabels[5], icon: De },
|
|
135
|
+
{ label: l.tabSetLabels[6], icon: Ce },
|
|
136
136
|
{ label: l.tabSetLabels[7], icon: Be },
|
|
137
137
|
{ label: l.tabSetLabels[8], icon: Fe },
|
|
138
138
|
{ label: l.tabSetLabels[9], icon: Ke }
|
|
@@ -160,7 +160,7 @@ const He = { class: "d-emoji-picker__search d-emoji-picker__alignment" }, ze = {
|
|
|
160
160
|
const e = parseInt(o);
|
|
161
161
|
m.value = o, f("selected-tabset", e);
|
|
162
162
|
}
|
|
163
|
-
function
|
|
163
|
+
function C(o) {
|
|
164
164
|
a.value.push(Me(o.$el));
|
|
165
165
|
}
|
|
166
166
|
function B() {
|
|
@@ -183,7 +183,7 @@ const He = { class: "d-emoji-picker__search d-emoji-picker__alignment" }, ze = {
|
|
|
183
183
|
key: n.id,
|
|
184
184
|
ref_for: !0,
|
|
185
185
|
ref: (c) => {
|
|
186
|
-
c &&
|
|
186
|
+
c && C(c);
|
|
187
187
|
},
|
|
188
188
|
label: n.label,
|
|
189
189
|
"panel-id": n.panelId,
|
|
@@ -228,7 +228,7 @@ function Ge() {
|
|
|
228
228
|
function d(o, e, n) {
|
|
229
229
|
t.value[e] || (t.value[e] = []), t.value[e][n] = o;
|
|
230
230
|
}
|
|
231
|
-
function
|
|
231
|
+
function C(o, e) {
|
|
232
232
|
g.value[e] = o;
|
|
233
233
|
}
|
|
234
234
|
function B(o, e) {
|
|
@@ -271,7 +271,7 @@ function Ge() {
|
|
|
271
271
|
isFiltering: y,
|
|
272
272
|
hoverFirstEmoji: l,
|
|
273
273
|
setEmojiRef: d,
|
|
274
|
-
setFilteredRef:
|
|
274
|
+
setFilteredRef: C,
|
|
275
275
|
focusEmoji: a,
|
|
276
276
|
handleArrowNavigationFiltered: B,
|
|
277
277
|
handleArrowNavigation: w
|
|
@@ -394,7 +394,7 @@ const Ye = { class: "d-emoji-picker__selector" }, Qe = {
|
|
|
394
394
|
setEmojiRef: m,
|
|
395
395
|
setFilteredRef: a,
|
|
396
396
|
focusEmoji: d,
|
|
397
|
-
handleArrowNavigationFiltered:
|
|
397
|
+
handleArrowNavigationFiltered: C,
|
|
398
398
|
handleArrowNavigation: B
|
|
399
399
|
} = Ge(), w = S(null), o = S(null), e = S(null), n = ["Recently used", "People", "Nature", "Food", "Activity", "Travel", "Objects", "Symbols", "Flags", "Custom"], v = M(() => {
|
|
400
400
|
let s = l.tabsetLabels.map((u) => ({ label: u, ref: S(null) }));
|
|
@@ -403,14 +403,14 @@ const Ye = { class: "d-emoji-picker__selector" }, Qe = {
|
|
|
403
403
|
const s = l.recentlyUsedEmojis.length ? n.slice() : n.slice(1);
|
|
404
404
|
return l.customEmojis && !l.customEmojis.length && s.pop(), s;
|
|
405
405
|
}), r = S([]), i = M(() => [
|
|
406
|
-
...
|
|
407
|
-
...
|
|
408
|
-
...
|
|
409
|
-
...
|
|
410
|
-
...
|
|
411
|
-
...
|
|
412
|
-
...
|
|
413
|
-
...
|
|
406
|
+
...D[`People${l.skinTone}`],
|
|
407
|
+
...D.Nature,
|
|
408
|
+
...D.Food,
|
|
409
|
+
...D[`Activity${l.skinTone}`],
|
|
410
|
+
...D.Travel,
|
|
411
|
+
...D[`Objects${l.skinTone}`],
|
|
412
|
+
...D.Symbols,
|
|
413
|
+
...D.Flags
|
|
414
414
|
]), _ = me(() => {
|
|
415
415
|
R.value = [], se();
|
|
416
416
|
}), le = () => {
|
|
@@ -422,13 +422,13 @@ const Ye = { class: "d-emoji-picker__selector" }, Qe = {
|
|
|
422
422
|
}, { immediate: !0 }), K(
|
|
423
423
|
() => l.recentlyUsedEmojis,
|
|
424
424
|
() => {
|
|
425
|
-
|
|
425
|
+
D["Recently used"] = l.recentlyUsedEmojis;
|
|
426
426
|
},
|
|
427
427
|
{ immediate: !0 }
|
|
428
428
|
), K(
|
|
429
429
|
() => l.customEmojis,
|
|
430
430
|
() => {
|
|
431
|
-
|
|
431
|
+
D.Custom = l.customEmojis;
|
|
432
432
|
},
|
|
433
433
|
{ immediate: !0 }
|
|
434
434
|
), K(() => l.emojiFilter, () => {
|
|
@@ -491,7 +491,7 @@ const Ye = { class: "d-emoji-picker__selector" }, Qe = {
|
|
|
491
491
|
}
|
|
492
492
|
const Ee = (s, u, h) => {
|
|
493
493
|
if (s.preventDefault(), Object.values(H).includes(s.key)) {
|
|
494
|
-
|
|
494
|
+
C(s.key, u);
|
|
495
495
|
return;
|
|
496
496
|
}
|
|
497
497
|
switch (s.key) {
|
|
@@ -558,7 +558,7 @@ const Ye = { class: "d-emoji-picker__selector" }, Qe = {
|
|
|
558
558
|
}, [
|
|
559
559
|
p ? (E(), I("p", Xe, z(h.label), 1)) : Y("", !0),
|
|
560
560
|
A("div", Ze, [
|
|
561
|
-
(E(!0), I(W, null, G(k(
|
|
561
|
+
(E(!0), I(W, null, G(k(D)[T.value[p] + t.skinTone] ? k(D)[T.value[p] + t.skinTone] : k(D)[T.value[p]], (b, U) => (E(), I("button", {
|
|
562
562
|
key: b.shortname,
|
|
563
563
|
ref_for: !0,
|
|
564
564
|
ref: (O) => {
|
|
@@ -694,7 +694,7 @@ const Ye = { class: "d-emoji-picker__selector" }, Qe = {
|
|
|
694
694
|
);
|
|
695
695
|
const a = M(() => R.find((n) => n.skinTone === l.skinTone)), d = S(a.value);
|
|
696
696
|
ae(() => a.value && (d.value = a.value));
|
|
697
|
-
function
|
|
697
|
+
function C(n) {
|
|
698
698
|
m.value.push(n);
|
|
699
699
|
}
|
|
700
700
|
function B() {
|
|
@@ -717,7 +717,7 @@ const Ye = { class: "d-emoji-picker__selector" }, Qe = {
|
|
|
717
717
|
(E(), I(W, null, G(R, (c, T) => A("button", {
|
|
718
718
|
ref_for: !0,
|
|
719
719
|
ref: (r) => {
|
|
720
|
-
r &&
|
|
720
|
+
r && C(r);
|
|
721
721
|
},
|
|
722
722
|
key: c.name,
|
|
723
723
|
class: ce({
|
|
@@ -908,7 +908,7 @@ const Ye = { class: "d-emoji-picker__selector" }, Qe = {
|
|
|
908
908
|
}), a = M(() => {
|
|
909
909
|
var r;
|
|
910
910
|
return ((r = y.customEmojis) == null ? void 0 : r.length) > 0;
|
|
911
|
-
}), d = new Ve(),
|
|
911
|
+
}), d = new Ve(), C = [
|
|
912
912
|
d.$t("DIALTONE_EMOJI_PICKER_TABSET_RECENTLY_USED_LABEL"),
|
|
913
913
|
d.$t("DIALTONE_EMOJI_PICKER_TABSET_SMILEYS_AND_PEOPLE_LABEL"),
|
|
914
914
|
d.$t("DIALTONE_EMOJI_PICKER_TABSET_NATURE_LABEL"),
|
|
@@ -943,7 +943,7 @@ const Ye = { class: "d-emoji-picker__selector" }, Qe = {
|
|
|
943
943
|
"show-custom-emojis-tab": a.value,
|
|
944
944
|
"show-recently-used-tab": m.value,
|
|
945
945
|
"scroll-into-tab": j.value,
|
|
946
|
-
"tab-set-labels":
|
|
946
|
+
"tab-set-labels": C,
|
|
947
947
|
onFocusSkinSelector: i[0] || (i[0] = (_) => r.$refs.skinSelectorRef.focusSkinSelector()),
|
|
948
948
|
onFocusSearchInput: i[1] || (i[1] = (_) => t.showSearch ? r.$refs.searchInputRef.focusSearchInput() : r.$refs.emojiSelectorRef.focusEmojiSelector()),
|
|
949
949
|
onSelectedTabset: v,
|
|
@@ -966,7 +966,7 @@ const Ye = { class: "d-emoji-picker__selector" }, Qe = {
|
|
|
966
966
|
ref: "emojiSelectorRef",
|
|
967
967
|
"emoji-filter": f.value,
|
|
968
968
|
"skin-tone": t.skinTone,
|
|
969
|
-
"tabset-labels":
|
|
969
|
+
"tabset-labels": C,
|
|
970
970
|
"search-results-label": k(w),
|
|
971
971
|
"search-no-results-label": k(o),
|
|
972
972
|
"recently-used-emojis": t.recentlyUsedEmojis,
|