UNPKG

@dialpad/dialtone-vue

Version:

Vue component library for Dialpad's design system Dialtone

452 lines (451 loc) • 17.6 kB
import { emojisGrouped } from "@dialpad/dialtone-emojis"; import { CDN_URL, EMOJIS_PER_ROW } from "../emoji_picker_constants.js"; import normalizeComponent from "../../../_virtual/_plugin-vue2_normalizer.js"; const _sfc_main = { name: "EmojiSelector", props: { emojiFilter: { type: String, default: "" }, skinTone: { type: String, required: true }, tabSetLabels: { type: Array, required: true }, selectedTabset: { type: Object, required: true }, searchResultsLabel: { type: String, required: true }, searchNoResultsLabel: { type: String, required: true }, recentlyUsedEmojis: { type: Array, default: () => [] } }, data() { return { tabLabelsRefs: [], emojiRefs: [], emojiFilteredRefs: [], isFiltering: false, hoverFirstEmoji: true, fixedLabel: "", filteredEmojis: [], TABS_DATA: ["Recently used", "People", "Nature", "Food", "Activity", "Travel", "Objects", "Symbols", "Flags"], tabLabelObserver: null }; }, computed: { /* eslint-disable-next-line complexity */ currentEmojis() { return [ ...this.emojis[`People${this.skinTone}`] || [], ...this.emojis.Nature || [], ...this.emojis.Food || [], ...this.emojis[`Activity${this.skinTone}`] || [], ...this.emojis.Travel || [], ...this.emojis[`Objects${this.skinTone}`] || [], ...this.emojis.Symbols || [], ...this.emojis.Flags || [] ]; }, emojis() { return emojisGrouped; }, CDN_URL() { return CDN_URL; }, tabLabels() { return this.recentlyUsedEmojis.length ? this.tabSetLabels.map((label) => ({ label })) : this.tabSetLabels.slice(1).map((label) => ({ label })); }, tabs() { return this.recentlyUsedEmojis.length ? this.TABS_DATA : this.TABS_DATA.slice(1); } }, watch: { currentEmojis: { handler() { this.searchByNameAndKeywords(); }, immediate: true }, recentlyUsedEmojis: { handler(newValue) { this.emojis["Recently used"] = newValue; }, immediate: true }, emojiFilter: { handler(newFilter) { this.resetScroll(); if (newFilter) { this.isFiltering = true; } else { this.isFiltering = false; this.$emit("highlighted-emoji", null); } this.debouncedSearch(); } }, selectedTabset: { handler(newValue) { this.scrollToTab(newValue.tabId); }, deep: true } }, created() { this.debouncedSearch = this.debounce(this.searchByNameAndKeywords, 300); }, mounted() { this.$nextTick(() => { this.setupEmojiRefs(); this.setupFilteredRefs(); this.setupTabLabelRefs(); this.setTabLabelObserver(); }); }, beforeDestroy() { if (this.tabLabelObserver) { this.tabLabelObserver.disconnect(); } }, methods: { setupTabLabelRefs() { var _a; (_a = this.tabSetLabels) == null ? void 0 : _a.forEach((_, index) => { const refKey = `tabLabelRef-${index}`; if (this.$refs[refKey]) { this.$set(this.tabLabelsRefs, index, { ref: this.$refs[refKey] }); } }); }, setupFilteredRefs() { this.emojiFilteredRefs = []; this.filteredEmojis.forEach((emoji, index) => { const refKey = `filteredEmoji-${index}`; if (this.$refs[refKey]) { this.setFilteredRef(this.$refs[refKey], index); } }); }, setupEmojiRefs() { for (let i = 0; i < this.tabs.length; i++) { const refKey = `emojiRef-${i}`; if (this.$refs[refKey]) { this.$refs[refKey].forEach((el, indexEmoji) => { if (el) { this.setEmojiRef(el, i, indexEmoji); } }); } } }, searchByNameAndKeywords() { const searchStr = this.emojiFilter.toLowerCase(); this.filteredEmojis = this.currentEmojis.filter(function(obj) { const nameIncludesSearchStr = obj.name.toLowerCase().includes(searchStr); const keywordsIncludeSearchStr = obj.keywords.some(function(keyword) { return keyword.toLowerCase().includes(searchStr); }); return nameIncludesSearchStr || keywordsIncludeSearchStr; }); this.$nextTick(function() { if (searchStr) { this.hoverEmoji(this.filteredEmojis[0], true); this.setupFilteredRefs(); } }); }, debounce: function(fn, delay) { if (delay === void 0) { delay = 300; } let timeout; return function() { const args = []; let len = arguments.length; while (len--) args[len] = arguments[len]; clearTimeout(timeout); timeout = setTimeout(function() { fn.apply(void 0, args); }, delay); }; }, getImgSrc: function(emoji) { return this.CDN_URL + emoji + ".png"; }, handleImageError: function(event) { event.target.parentNode.style.display = "none"; }, scrollToTab: function(tabIndex, focusFirstEmoji) { const vm = this; if (focusFirstEmoji === void 0) { focusFirstEmoji = true; } const tabElement = vm.tabLabelsRefs[tabIndex - 1].ref[0]; vm.$nextTick(function() { const container = vm.$refs.listRef; const offsetTop = tabIndex === 1 ? 0 : tabElement.offsetTop - 15; container.scrollTop = offsetTop; if (focusFirstEmoji) { vm.focusEmoji(tabIndex - 1, 0); } }); }, resetScroll: function() { const container = this.$refs.listRef; container.scrollTop = 0; }, focusEmojiSelector: function() { this.focusEmoji(0, 0); }, hoverEmoji(emoji, isFirst) { if (isFirst === void 0) { isFirst = false; } this.hoverFirstEmoji = isFirst; this.$emit("highlighted-emoji", emoji); }, setEmojiRef: function(el, indexTab, indexEmoji) { if (!this.emojiRefs[indexTab]) { this.$set(this.emojiRefs, indexTab, []); } this.$set(this.emojiRefs[indexTab], indexEmoji, el); }, setFilteredRef: function(el, index) { this.$set(this.emojiFilteredRefs, index, el); }, focusEmoji: function(indexTab, indexEmoji) { var _a; const emojiRef = this.isFiltering ? (_a = this.emojiFilteredRefs[indexEmoji]) == null ? void 0 : _a[0] : this.emojiRefs[indexTab] && this.emojiRefs[indexTab][indexEmoji]; if (emojiRef) { emojiRef.focus(); return true; } return false; }, // eslint-disable-next-line complexity handleKeyDown: function(event, indexTab, indexEmoji, emoji) { var _a, _b; event.preventDefault(); if (event.key === "ArrowUp") { const position = indexEmoji % EMOJIS_PER_ROW; if (indexTab === 0) { const numberOfMissingEmojis = EMOJIS_PER_ROW - this.emojiRefs[this.emojiRefs.length - 1].length % EMOJIS_PER_ROW; const emojiToJump = this.emojiRefs[this.emojiRefs.length - 1].length + numberOfMissingEmojis - (EMOJIS_PER_ROW - position); if (!this.focusEmoji(this.emojiRefs.length - 1, emojiToJump)) { this.focusEmoji(this.emojiRefs.length - 1, this.emojiRefs[this.emojiRefs.length - 1].length - 1); } return; } if (!this.focusEmoji(indexTab, indexEmoji - EMOJIS_PER_ROW)) { const previousTab = indexTab - 1 < 0 ? 0 : indexTab - 1; const emojisInPreviousTab = this.emojiRefs[previousTab].length; const lastEmojiPosition = emojisInPreviousTab - emojisInPreviousTab % EMOJIS_PER_ROW + position; if (!this.focusEmoji(previousTab, lastEmojiPosition)) { this.focusEmoji(indexTab - 1, this.emojiRefs[indexTab - 1].length - 1); } } } if (event.key === "ArrowDown") { if (!this.focusEmoji(indexTab, indexEmoji + EMOJIS_PER_ROW)) { const position = indexEmoji % EMOJIS_PER_ROW; if ((_b = (_a = this.emojiRefs) == null ? void 0 : _a[indexTab]) == null ? void 0 : _b[indexEmoji + (EMOJIS_PER_ROW - position)]) { this.focusEmoji(indexTab, this.emojiRefs[indexTab].length - 1); } else { if (!this.focusEmoji(indexTab + 1, position)) { if (!this.focusEmoji(0, position)) { this.focusEmoji(0, this.emojiRefs[0].length - 1); } } } } } if (event.key === "ArrowLeft") { this.handleHorizontalNavigation("left", indexTab, indexEmoji); } if (event.key === "ArrowRight") { this.handleHorizontalNavigation("right", indexTab, indexEmoji); } if (event.key === "Tab" && !event.shiftKey) { if (this.focusEmoji(indexTab + 1, 0)) { this.scrollToTab(indexTab + 1 + 1, false); } else { this.$emit("focus-skin-selector"); } } if (event.key === "Tab" && event.shiftKey) { if (this.focusEmoji(indexTab, 0) && indexTab > 0) { this.scrollToTab(indexTab, true); } else { this.scrollToTab(1, false); this.$emit("focus-search-input"); } } if (event.key === "Enter") { this.handleEmojiSelection(emoji, event); } }, /* eslint-disable-next-line complexity */ handleHorizontalNavigation: function(direction, indexTab, indexEmoji) { if (this.isFiltering) { if (direction === "left") { this.handleArrowLeftFiltered(indexTab, indexEmoji); } else if (direction === "right") { this.handleArrowRightFiltered(indexTab, indexEmoji); } } else { if (direction === "left") { this.handleArrowLeft(indexTab, indexEmoji); } else if (direction === "right") { this.handleArrowRight(indexTab, indexEmoji); } } }, handleArrowLeftFiltered: function(indexTab, indexEmoji) { if (!this.focusEmoji(0, indexEmoji - 1)) { this.focusEmoji(0, this.emojiFilteredRefs.length - 1); } }, handleArrowRightFiltered: function(indexTab, indexEmoji) { if (!this.focusEmoji(0, indexEmoji + 1)) { this.focusEmoji(0, 0); } }, handleArrowLeft: function(indexTab, indexEmoji) { if (!this.focusEmoji(indexTab, indexEmoji - 1)) { if (this.emojiRefs[indexTab - 1]) { this.focusEmoji(indexTab - 1, this.emojiRefs[indexTab - 1].length - 1); } else { this.focusEmoji(this.emojiRefs.length - 1, this.emojiRefs[this.emojiRefs.length - 1].length - 1); } } }, handleArrowRight: function(indexTab, indexEmoji) { if (!this.focusEmoji(indexTab, indexEmoji + 1)) { if (!this.focusEmoji(indexTab + 1, 0)) { this.focusEmoji(0, 0); } } }, handleEmojiSelection(emoji, event) { this.$emit("selected-emoji", { ...emoji, shift_key: event.shiftKey }); }, /* eslint-disable-next-line complexity */ handleKeyDownFilteredEmojis(event, indexEmoji, emoji) { var _a; event.preventDefault(); this.hoverFirstEmoji = false; if (event.key === "ArrowUp") { const position = indexEmoji % EMOJIS_PER_ROW; if (!this.focusEmoji(0, indexEmoji - EMOJIS_PER_ROW)) { const lastEmojiPosition = this.emojiFilteredRefs.length - this.emojiFilteredRefs.length % EMOJIS_PER_ROW + position; this.focusEmoji(0, lastEmojiPosition); if (!this.focusEmoji(0, lastEmojiPosition)) { this.focusEmoji(0, this.emojiFilteredRefs.length - 1); } } } if (event.key === "ArrowDown") { if (!this.focusEmoji(0, indexEmoji + EMOJIS_PER_ROW)) { const position = indexEmoji % EMOJIS_PER_ROW; if ((_a = this.emojiFilteredRefs) == null ? void 0 : _a[indexEmoji + (EMOJIS_PER_ROW - position)]) { this.focusEmoji(0, this.emojiFilteredRefs.length - 1); } else { this.focusEmoji(0, position); } } } if (event.key === "ArrowLeft") { this.handleHorizontalNavigation("left", 0, indexEmoji); } if (event.key === "ArrowRight") { this.handleHorizontalNavigation("right", 0, indexEmoji); } if (event.key === "Tab") { this.$emit("focus-skin-selector"); } if (event.key === "Enter") { this.handleEmojiSelection(emoji, event); } }, setTabLabelObserver() { this.tabLabelObserver = new IntersectionObserver((entries) => { entries.forEach((entry) => { var _a, _b, _c, _d, _e, _f; const { target } = entry; const index = parseInt(target.dataset.index); if (entry.isIntersecting && target.offsetTop <= ((_a = this.$refs.tabCategoryRef) == null ? void 0 : _a.offsetTop) + 50) { this.fixedLabel = ((_b = this.tabLabels[index - 1]) == null ? void 0 : _b.label) ?? ((_c = this.tabLabels[0]) == null ? void 0 : _c.label); this.$emit("scroll-into-tab", index - 1); } else if (entry.boundingClientRect.bottom <= ((_d = this.$refs.tabCategoryRef) == null ? void 0 : _d.getBoundingClientRect().bottom)) { this.$emit("scroll-into-tab", index); this.fixedLabel = (_e = this.tabLabels[index]) == null ? void 0 : _e.label; } else if (index === 1) { this.$emit("scroll-into-tab", index); this.fixedLabel = (_f = this.tabLabels[0]) == null ? void 0 : _f.label; } }); }); this.tabLabelObserver.observe(this.$refs.tabCategoryRef); Array.from(this.$refs.listRef.children).forEach((child, index) => { this.tabLabelObserver.observe(child); child.dataset.index = index; }); }, focusLastEmoji() { this.scrollToTab(this.tabs.length, true); } } }; var _sfc_render = function render() { var _vm = this, _c = _vm._self._c; return _c("div", { staticClass: "d-emoji-picker__selector" }, [_c("div", { ref: "listRef", staticClass: "d-emoji-picker__list", attrs: { "id": "d-emoji-picker-list" } }, [_vm.emojiFilter ? _c("p", { staticClass: "d-emoji-picker__search-label d-emoji-picker__alignment" }, [_vm._v(" " + _vm._s(_vm.filteredEmojis.length > 0 ? _vm.searchResultsLabel : _vm.searchNoResultsLabel) + " ")]) : _c("div", { ref: "tabCategoryRef", staticClass: "d-emoji-picker__category d-emoji-picker__alignment" }, [_c("p", [_vm._v(" " + _vm._s(_vm.fixedLabel) + " ")])]), _vm._l(_vm.tabLabels, function(tabLabel, indexTab) { return _c("div", { directives: [{ name: "show", rawName: "v-show", value: !_vm.emojiFilter, expression: "!emojiFilter" }], key: indexTab, ref: `tabLabelRef-${indexTab}`, refInFor: true, staticClass: "d-emoji-picker__alignment" }, [indexTab ? _c("p", [_vm._v(" " + _vm._s(tabLabel.label) + " ")]) : _vm._e(), _c("div", { staticClass: "d-emoji-picker__tab" }, _vm._l(_vm.emojis[_vm.tabs[indexTab] + _vm.skinTone] ? _vm.emojis[_vm.tabs[indexTab] + _vm.skinTone] : _vm.emojis[_vm.tabs[indexTab]], function(emoji, indexEmoji) { return _c("button", { key: emoji.shortname, ref: `emojiRef-${indexTab}`, refInFor: true, attrs: { "type": "button", "aria-label": emoji.name }, on: { "click": (event) => _vm.handleEmojiSelection(emoji, event), "focusin": function($event) { return _vm.$emit("highlighted-emoji", emoji); }, "focusout": function($event) { return _vm.$emit("highlighted-emoji", null); }, "mouseover": function($event) { return _vm.$emit("highlighted-emoji", emoji); }, "mouseleave": function($event) { return _vm.$emit("highlighted-emoji", null); }, "keydown": (event) => _vm.handleKeyDown(event, indexTab, indexEmoji, emoji) } }, [_c("img", { staticClass: "d-icon d-icon--size-500", attrs: { "alt": emoji.name, "aria-label": emoji.name, "title": emoji.name, "src": _vm.getImgSrc(emoji.unicode_character) }, on: { "error": _vm.handleImageError } })]); }), 0)]); }), _vm.emojiFilter ? _c("div", { staticClass: "d-emoji-picker__alignment" }, [_c("div", { staticClass: "d-emoji-picker__tab", attrs: { "data-qa": "filtered-emojis" } }, _vm._l(_vm.filteredEmojis, function(emoji, index) { return _c("button", { key: emoji.shortname, ref: `filteredEmoji-${index}`, refInFor: true, class: { "hover-emoji": index === 0 && _vm.hoverFirstEmoji }, attrs: { "type": "button", "aria-label": emoji.name }, on: { "click": (event) => _vm.handleEmojiSelection(emoji, event), "focusin": function($event) { return _vm.$emit("highlighted-emoji", emoji); }, "focusout": function($event) { return _vm.$emit("highlighted-emoji", null); }, "mouseover": function($event) { return _vm.hoverEmoji(emoji); }, "mouseleave": function($event) { return _vm.hoverEmoji(null); }, "keydown": (event) => _vm.handleKeyDownFilteredEmojis(event, index, emoji) } }, [_c("img", { staticClass: "d-icon d-icon--size-500", attrs: { "alt": emoji.name, "aria-label": emoji.name, "title": emoji.name, "src": `${_vm.CDN_URL + emoji.unicode_character}.png` } })]); }), 0)]) : _vm._e()], 2)]); }; var _sfc_staticRenderFns = []; var __component__ = /* @__PURE__ */ normalizeComponent( _sfc_main, _sfc_render, _sfc_staticRenderFns ); const EmojiSelector = __component__.exports; export { EmojiSelector as default }; //# sourceMappingURL=emoji_selector.vue.js.map