diff --git a/src/sites/twitch-twilight/modules/chat/index.js b/src/sites/twitch-twilight/modules/chat/index.js index 425a0f7e..e56815cc 100644 --- a/src/sites/twitch-twilight/modules/chat/index.js +++ b/src/sites/twitch-twilight/modules/chat/index.js @@ -131,6 +131,12 @@ export default class ChatHook extends Module { n => n.collapseCheer && n.saveRenderedMessageRef, Twilight.CHAT_ROUTES ); + + this.TabComplete = this.fine.define( + 'tab-complete-emotes', + n => n.getMatchedEmotes, + Twilight.CHAT_ROUTES + ); // Settings @@ -425,6 +431,73 @@ export default class ChatHook extends Module { for(const inst of instances) this.fixPinnedCheer(inst); }); + + this.TabComplete.ready((cls, instances) => { + for(const inst of instances) + this.setupTabCompletion(inst); + }); + this.TabComplete.on('mount', this.setupTabCompletion, this); + this.TabComplete.on('unmount', inst => { + inst._ffz_getMatchedEmotes = null; + inst._ffz_channelInfo = null; + }, this); + } + + getResultsForSets(input, inst) { + if (!inst._ffz_channelInfo) return []; + + const search = input.substring(1), + results = [], + emotes = Object.values(this.chat.emotes.getEmotes(inst._ffz_channelInfo.props.sessionUser.id, undefined, inst._ffz_channelInfo.props.channelID)); + + for (const emote of emotes) { + if (inst.doesEmoteMatchTerm(emote, search)) { + results.push({ + current: input, + replacement: emote.name, + element: inst.renderEmoteSuggestion({ + token: emote.name, + id: `${emote.token.provider}-${emote.id}`, + srcSet: emote.srcSet + }) + }); + } + } + + return results; + } + + setupTabCompletion(inst) { + const t = this, + old_matched = inst._ffz_getMatchedEmotes || inst.getMatchedEmotes; + + if (!inst._ffz_getMatchedEmotes) inst._ffz_getMatchedEmotes = old_matched; + + inst._ffz_channelInfo = this.fine.searchParent(inst, n => n.props !== undefined + && n.props.channelID !== undefined + && !n.props.roomID + ); + if (!inst._ffz_channelInfo) return; + + inst.doesEmoteMatchTerm = function (emote, term) { + const emote_name = emote.name || emote.token, + emote_lower = emote_name.toLowerCase(), + term_lower = term.toLowerCase(); + + if (emote_lower.startsWith(term_lower)) + return true; + + const idx = emote_name.indexOf(term.charAt(0).toUpperCase()); + if (idx !== -1) + return emote_lower.slice(idx + 1).startsWith(term_lower.slice(1)); + }; + + inst.getMatchedEmotes = function (input) { + const results = old_matched.call(this, input) + .concat(t.getResultsForSets(input, this)) + + return results; + }; } diff --git a/src/sites/twitch-twilight/styles/chat.scss b/src/sites/twitch-twilight/styles/chat.scss index c22fc890..7626df7d 100644 --- a/src/sites/twitch-twilight/styles/chat.scss +++ b/src/sites/twitch-twilight/styles/chat.scss @@ -9,4 +9,21 @@ .chat-list__lines .simplebar-scrollbar { will-change: opacity; +} + +.autocomplete-balloon { + .autocomplete-balloon__item { + > .tw-flex { + > div { + display: flex; + flex-shrink: 0; + } + } + + span { + overflow-x: hidden; + text-overflow: ellipsis; + white-space: nowrap; + } + } } \ No newline at end of file