{"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=\"showCustomEmojisTab && !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\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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"}