diff --git a/src/picker/components/Picker/PickerTemplate.js b/src/picker/components/Picker/PickerTemplate.js
index f320e12..40e16b6 100644
--- a/src/picker/components/Picker/PickerTemplate.js
+++ b/src/picker/components/Picker/PickerTemplate.js
@@ -4,7 +4,7 @@ export function render (state, helpers, events, container, firstRender) {
const { labelWithSkin, titleForEmoji, unicodeWithSkin } = helpers
const { html, map } = createFramework(state)
- function emojiList (emojis, searchMode, prefix, uniqueId) {
+ function emojiList (emojis, searchMode, prefix) {
return map(emojis, (emoji, i) => {
return html`
`
- }, emoji => emoji.id, uniqueId)
+ // It's important for the cache key to be unique based on the prefix, because the framework caches based on the
+ // unique tokens + cache key, and the same emoji may be used in the tab as well as in the fav bar
+ }, emoji => `${prefix}-${emoji.id}`)
}
const section = () => {
@@ -103,7 +105,7 @@ export function render (state, helpers, events, container, firstRender) {
${skinTone}
`
- }, skinTone => skinTone, 'skintones')
+ }, skinTone => skinTone)
}
@@ -131,7 +133,7 @@ export function render (state, helpers, events, container, firstRender) {
`
- }, group => group.id, 'nav')
+ }, group => group.id)
}
@@ -189,12 +191,12 @@ export function render (state, helpers, events, container, firstRender) {
aria-labelledby="menu-label-${i}"
id=${state.searchMode ? 'search-results' : ''}>
${
- emojiList(emojiWithCategory.emojis, state.searchMode, /* prefix */ 'emo', /* uniqueId */ `emo-${emojiWithCategory.category}`)
+ emojiList(emojiWithCategory.emojis, state.searchMode, /* prefix */ 'emo')
}
`
- }, emojiWithCategory => emojiWithCategory.category, 'emojisWithCategories')
+ }, emojiWithCategory => emojiWithCategory.category)
}
@@ -205,7 +207,7 @@ export function render (state, helpers, events, container, firstRender) {
style="padding-inline-end: ${`${state.scrollbarWidth}px`}"
data-on-click="onEmojiClick">
${
- emojiList(state.currentFavorites, /* searchMode */ false, /* prefix */ 'fav', /* uniqueId */ 'fav')
+ emojiList(state.currentFavorites, /* searchMode */ false, /* prefix */ 'fav')
}
diff --git a/src/picker/components/Picker/framework.js b/src/picker/components/Picker/framework.js
index b38b7da..6d1fda2 100644
--- a/src/picker/components/Picker/framework.js
+++ b/src/picker/components/Picker/framework.js
@@ -1,7 +1,7 @@
import { getFromMap, parseTemplate, toString } from './utils.js'
const parseCache = new WeakMap()
-const updatersCache = new WeakMap()
+const domInstancesCache = new WeakMap()
const unkeyedSymbol = Symbol('un-keyed')
// Not supported in Safari <=13
@@ -263,29 +263,28 @@ function parseHtml (tokens) {
}
export function createFramework (state) {
- let updaters = getFromMap(updatersCache, state, () => new Map())
- let iteratorKey = unkeyedSymbol
+ const domInstances = getFromMap(domInstancesCache, state, () => new Map())
+ let domInstanceCacheKey = unkeyedSymbol
function html (tokens, ...expressions) {
- const updatersForKey = getFromMap(updaters, iteratorKey, () => new WeakMap())
- const updater = getFromMap(updatersForKey, tokens, () => parseHtml(tokens))
+ // Each unique lexical usage of map() is considered unique due to the html`` tagged template call it makes,
+ // which has lexically unique tokens. The unkeyed symbol is just used for html`` usage outside of a map().
+ const domInstancesForTokens = getFromMap(domInstances, tokens, () => new Map())
+ const domInstance = getFromMap(domInstancesForTokens, domInstanceCacheKey, () => parseHtml(tokens))
- return updater(expressions)
+ return domInstance(expressions) // update with expressions
}
- function map (array, callback, keyFunction, mapKey) {
- const originalCacheKey = iteratorKey
- const originalUpdaters = updaters
- updaters = getFromMap(updaters, mapKey, () => new Map())
- try {
- return array.map((item, index) => {
- iteratorKey = keyFunction(item)
+ function map (array, callback, keyFunction) {
+ return array.map((item, index) => {
+ const originalCacheKey = domInstanceCacheKey
+ domInstanceCacheKey = keyFunction(item)
+ try {
return callback(item, index)
- })
- } finally {
- iteratorKey = originalCacheKey
- updaters = originalUpdaters
- }
+ } finally {
+ domInstanceCacheKey = originalCacheKey
+ }
+ })
}
return { map, html }