@chayns-components/emoji-input 5.6.6 → 5.6.9
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/lib/cjs/build.test.js +34 -0
- package/lib/cjs/build.test.js.map +1 -0
- package/lib/cjs/components/emoji-picker/emoji-picker-emojis/EmojiPickerEmojis.js +48 -219
- package/lib/cjs/components/emoji-picker/emoji-picker-emojis/EmojiPickerEmojis.js.map +1 -1
- package/lib/cjs/components/emoji-picker/emoji-picker-emojis/EmojiPickerEmojis.test.js +316 -0
- package/lib/cjs/components/emoji-picker/emoji-picker-emojis/EmojiPickerEmojis.test.js.map +1 -0
- package/lib/cjs/components/emoji-picker/emoji-picker-emojis/emoji/Emoji.js +1 -0
- package/lib/cjs/components/emoji-picker/emoji-picker-emojis/emoji/Emoji.js.map +1 -1
- package/lib/cjs/components/emoji-picker/emoji-picker-emojis/emoji-picker-emoji-list/EmojiPickerEmojiList.js +109 -0
- package/lib/cjs/components/emoji-picker/emoji-picker-emojis/emoji-picker-emoji-list/EmojiPickerEmojiList.js.map +1 -0
- package/lib/esm/build.test.js +32 -0
- package/lib/esm/build.test.js.map +1 -0
- package/lib/esm/components/emoji-picker/emoji-picker-emojis/EmojiPickerEmojis.js +47 -218
- package/lib/esm/components/emoji-picker/emoji-picker-emojis/EmojiPickerEmojis.js.map +1 -1
- package/lib/esm/components/emoji-picker/emoji-picker-emojis/EmojiPickerEmojis.test.js +312 -0
- package/lib/esm/components/emoji-picker/emoji-picker-emojis/EmojiPickerEmojis.test.js.map +1 -0
- package/lib/esm/components/emoji-picker/emoji-picker-emojis/emoji/Emoji.js +1 -0
- package/lib/esm/components/emoji-picker/emoji-picker-emojis/emoji/Emoji.js.map +1 -1
- package/lib/esm/components/emoji-picker/emoji-picker-emojis/emoji-picker-emoji-list/EmojiPickerEmojiList.js +101 -0
- package/lib/esm/components/emoji-picker/emoji-picker-emojis/emoji-picker-emoji-list/EmojiPickerEmojiList.js.map +1 -0
- package/lib/types/components/emoji-picker/emoji-picker-emojis/emoji-picker-emoji-list/EmojiPickerEmojiList.d.ts +15 -0
- package/package.json +3 -3
- package/lib/types/components/emoji-input/EmojiInput.test.d.ts +0 -1
- package/lib/types/utils/emoji.test.d.ts +0 -1
- package/lib/types/utils/selection.test.d.ts +0 -1
- package/lib/types/utils/text.test.d.ts +0 -1
|
@@ -1,12 +1,8 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
import { useCombinedRefs, useIsMeasuredClone } from '@chayns-components/core';
|
|
1
|
+
import React, { useCallback, useEffect, useState } from 'react';
|
|
4
2
|
import emojiLib from 'emojilib';
|
|
5
|
-
import React, { useCallback, useEffect, useMemo, useRef, useState } from 'react';
|
|
6
3
|
import germanEmojiLib from '../../../constants/emoji-de-DE.json';
|
|
7
4
|
import { useEmojiHistory } from '../../../hooks/emojiHistory';
|
|
8
|
-
import
|
|
9
|
-
import { StyledEmojiPickerEmojis, StyledEmojiPickerEmojisNoContentInfo } from './EmojiPickerEmojis.styles';
|
|
5
|
+
import EmojiPickerEmojiList from './emoji-picker-emoji-list/EmojiPickerEmojiList';
|
|
10
6
|
const EmojiPickerEmojis = ({
|
|
11
7
|
accessToken,
|
|
12
8
|
onSelect,
|
|
@@ -14,11 +10,20 @@ const EmojiPickerEmojis = ({
|
|
|
14
10
|
searchString,
|
|
15
11
|
selectedCategory
|
|
16
12
|
}) => {
|
|
17
|
-
const [shouldPreventScroll, setShouldPreventScroll] = useState(false);
|
|
18
|
-
const [shouldShowSkinTonePopup, setShouldShowSkinTonePopup] = useState(false);
|
|
19
|
-
const [focusedIndex, setFocusedIndex] = useState(0);
|
|
20
13
|
const [emojiCategories, setEmojiCategories] = useState([]);
|
|
21
|
-
const [emojiList, setEmojiList] = useState(
|
|
14
|
+
const [emojiList, setEmojiList] = useState({});
|
|
15
|
+
const {
|
|
16
|
+
addOrUpdateEmojiInHistory,
|
|
17
|
+
historyEmojis
|
|
18
|
+
} = useEmojiHistory({
|
|
19
|
+
accessToken,
|
|
20
|
+
personId,
|
|
21
|
+
selectedCategory
|
|
22
|
+
});
|
|
23
|
+
const handleSelect = useCallback((emoji, shouldRestoreInputFocus = false) => {
|
|
24
|
+
onSelect(emoji.emoji, shouldRestoreInputFocus);
|
|
25
|
+
void addOrUpdateEmojiInHistory(emoji);
|
|
26
|
+
}, [addOrUpdateEmojiInHistory, onSelect]);
|
|
22
27
|
useEffect(() => {
|
|
23
28
|
void import('unicode-emoji-json/data-by-group.json').then(({
|
|
24
29
|
default: categories
|
|
@@ -31,216 +36,40 @@ const EmojiPickerEmojis = ({
|
|
|
31
36
|
setEmojiList(emojis);
|
|
32
37
|
});
|
|
33
38
|
}, []);
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
selectedCategory
|
|
45
|
-
});
|
|
46
|
-
const handlePopupVisibilityChange = useCallback(isVisible => {
|
|
47
|
-
setShouldShowSkinTonePopup(isVisible);
|
|
48
|
-
shouldPreventEmojiControlsRef.current = isVisible;
|
|
49
|
-
setShouldPreventScroll(isVisible);
|
|
50
|
-
}, []);
|
|
51
|
-
const handleSelect = useCallback(({
|
|
52
|
-
emoji,
|
|
53
|
-
name,
|
|
54
|
-
skin_tone_support,
|
|
55
|
-
index
|
|
56
|
-
}, shouldRestoreInputFocus = false) => {
|
|
57
|
-
onSelect(emoji, shouldRestoreInputFocus);
|
|
58
|
-
if (index) {
|
|
59
|
-
setFocusedIndex(index);
|
|
60
|
-
}
|
|
61
|
-
void addOrUpdateEmojiInHistory({
|
|
39
|
+
let visibleEmojis;
|
|
40
|
+
if (searchString.trim() !== '') {
|
|
41
|
+
const lowerSearchString = searchString.toLowerCase();
|
|
42
|
+
visibleEmojis = Object.entries(emojiList).filter(([emoji, {
|
|
43
|
+
name
|
|
44
|
+
}]) => {
|
|
45
|
+
const keywords = emojiLib[emoji];
|
|
46
|
+
const germanKeywords = germanEmojiLib[emoji];
|
|
47
|
+
return name.includes(lowerSearchString) || keywords?.some(keyword => keyword.includes(lowerSearchString)) || germanKeywords?.some(keyword => keyword.includes(lowerSearchString));
|
|
48
|
+
}).map(([emoji, data]) => ({
|
|
62
49
|
emoji,
|
|
63
|
-
|
|
64
|
-
skin_tone_support
|
|
65
|
-
});
|
|
66
|
-
}, [addOrUpdateEmojiInHistory, onSelect]);
|
|
67
|
-
useEffect(() => {
|
|
68
|
-
if (selectedCategory) {
|
|
69
|
-
setFocusedIndex(0);
|
|
70
|
-
const container = emojiRef.current;
|
|
71
|
-
if (!container) {
|
|
72
|
-
return;
|
|
73
|
-
}
|
|
74
|
-
container.scrollTop = 0;
|
|
75
|
-
}
|
|
76
|
-
}, [selectedCategory]);
|
|
77
|
-
useEffect(() => {
|
|
78
|
-
const handleKeyDown = event => {
|
|
79
|
-
if (shouldPreventListener) {
|
|
80
|
-
return;
|
|
81
|
-
}
|
|
82
|
-
if (!shouldPreventEmojiControlsRef.current && (event.key === 'ArrowUp' || event.key === 'ArrowDown' || event.key === 'ArrowLeft' || event.key === 'ArrowRight')) {
|
|
83
|
-
event.preventDefault();
|
|
84
|
-
const children = emojiRef.current?.children;
|
|
85
|
-
if (children && children.length > 0) {
|
|
86
|
-
const container = emojiRef.current;
|
|
87
|
-
let newIndex = focusedIndex !== null ? focusedIndex : 0;
|
|
88
|
-
if (event.ctrlKey) {
|
|
89
|
-
return;
|
|
90
|
-
}
|
|
91
|
-
if (event.key === 'ArrowUp') {
|
|
92
|
-
newIndex = (newIndex - 6) % children.length;
|
|
93
|
-
} else if (event.key === 'ArrowDown') {
|
|
94
|
-
newIndex = (newIndex + 6) % children.length;
|
|
95
|
-
} else if (event.key === 'ArrowLeft') {
|
|
96
|
-
newIndex = (newIndex - 1) % children.length;
|
|
97
|
-
} else if (event.key === 'ArrowRight') {
|
|
98
|
-
newIndex = (newIndex + 1) % children.length;
|
|
99
|
-
}
|
|
100
|
-
|
|
101
|
-
// remove focus from the old element
|
|
102
|
-
if (focusedIndex !== null) {
|
|
103
|
-
const prevElement = children[focusedIndex];
|
|
104
|
-
prevElement.tabIndex = -1;
|
|
105
|
-
}
|
|
106
|
-
if (newIndex < 0) {
|
|
107
|
-
newIndex = children.length - 1;
|
|
108
|
-
} else if (newIndex > children.length - 1) {
|
|
109
|
-
newIndex = 0;
|
|
110
|
-
}
|
|
111
|
-
setFocusedIndex(newIndex);
|
|
112
|
-
|
|
113
|
-
// Set focus to the element
|
|
114
|
-
const newElement = children[newIndex];
|
|
115
|
-
newElement.tabIndex = 0;
|
|
116
|
-
const containerRect = container.getBoundingClientRect();
|
|
117
|
-
const elementRect = newElement.getBoundingClientRect();
|
|
118
|
-
if (elementRect.bottom > containerRect.bottom) {
|
|
119
|
-
container.scrollTop += elementRect.bottom - containerRect.bottom;
|
|
120
|
-
} else if (elementRect.top < containerRect.top) {
|
|
121
|
-
container.scrollTop -= containerRect.top - elementRect.top;
|
|
122
|
-
}
|
|
123
|
-
}
|
|
124
|
-
} else if (event.key === 'Enter' && !shouldPreventEmojiControlsRef.current && focusedIndex !== null) {
|
|
125
|
-
if (event.ctrlKey) {
|
|
126
|
-
setShouldShowSkinTonePopup(true);
|
|
127
|
-
return;
|
|
128
|
-
}
|
|
129
|
-
const {
|
|
130
|
-
dataset
|
|
131
|
-
} = emojiRef.current?.children[focusedIndex];
|
|
132
|
-
const {
|
|
133
|
-
emoji,
|
|
134
|
-
name,
|
|
135
|
-
skinToneSupport
|
|
136
|
-
} = dataset;
|
|
137
|
-
if (!emoji || !name || !skinToneSupport) {
|
|
138
|
-
return;
|
|
139
|
-
}
|
|
140
|
-
handleSelect({
|
|
141
|
-
emoji,
|
|
142
|
-
name,
|
|
143
|
-
skin_tone_support: skinToneSupport === 'true'
|
|
144
|
-
}, true);
|
|
145
|
-
}
|
|
146
|
-
};
|
|
147
|
-
document.addEventListener('keydown', handleKeyDown);
|
|
148
|
-
return () => {
|
|
149
|
-
document.removeEventListener('keydown', handleKeyDown);
|
|
150
|
-
};
|
|
151
|
-
}, [focusedIndex, handleSelect, shouldPreventListener]);
|
|
152
|
-
const handleRightClick = useCallback(index => {
|
|
153
|
-
setFocusedIndex(index);
|
|
154
|
-
}, []);
|
|
155
|
-
const emojis = useMemo(() => {
|
|
156
|
-
if (searchString.trim() !== '') {
|
|
157
|
-
const lowerSearchString = searchString.toLowerCase();
|
|
158
|
-
const searchResults = [];
|
|
159
|
-
Object.entries(emojiList).forEach(([emoji, {
|
|
160
|
-
name,
|
|
161
|
-
skin_tone_support
|
|
162
|
-
}], index) => {
|
|
163
|
-
const keywords = emojiLib[emoji];
|
|
164
|
-
const germanKeywords = germanEmojiLib[emoji];
|
|
165
|
-
if (name.includes(lowerSearchString) || keywords?.some(keyword => keyword.includes(lowerSearchString)) || germanKeywords?.some(keyword => keyword.includes(lowerSearchString))) {
|
|
166
|
-
searchResults.push(/*#__PURE__*/React.createElement(Emoji, {
|
|
167
|
-
shouldShowSkinTonePopup: index === focusedIndex && skin_tone_support && shouldShowSkinTonePopup,
|
|
168
|
-
isSelected: index === focusedIndex,
|
|
169
|
-
emoji: emoji,
|
|
170
|
-
index: index,
|
|
171
|
-
onRightClick: handleRightClick,
|
|
172
|
-
isSkinToneSupported: skin_tone_support,
|
|
173
|
-
key: name,
|
|
174
|
-
name: name,
|
|
175
|
-
onPopupVisibilityChange: handlePopupVisibilityChange,
|
|
176
|
-
onSelect: e => handleSelect({
|
|
177
|
-
emoji: e,
|
|
178
|
-
name,
|
|
179
|
-
skin_tone_support,
|
|
180
|
-
index
|
|
181
|
-
}),
|
|
182
|
-
emojiList: emojiList
|
|
183
|
-
}));
|
|
184
|
-
}
|
|
185
|
-
});
|
|
186
|
-
return searchResults;
|
|
187
|
-
}
|
|
188
|
-
if (selectedCategory === 'history') {
|
|
189
|
-
return historyEmojis.map(({
|
|
190
|
-
emoji,
|
|
191
|
-
name,
|
|
192
|
-
skin_tone_support
|
|
193
|
-
}, index) => /*#__PURE__*/React.createElement(Emoji, {
|
|
194
|
-
isSelected: index === focusedIndex,
|
|
195
|
-
shouldShowSkinTonePopup: index === focusedIndex && skin_tone_support && shouldShowSkinTonePopup,
|
|
196
|
-
emoji: emoji,
|
|
197
|
-
name: name,
|
|
198
|
-
key: name,
|
|
199
|
-
index: index,
|
|
200
|
-
onRightClick: handleRightClick,
|
|
201
|
-
onPopupVisibilityChange: handlePopupVisibilityChange,
|
|
202
|
-
onSelect: e => handleSelect({
|
|
203
|
-
emoji: e,
|
|
204
|
-
name,
|
|
205
|
-
skin_tone_support,
|
|
206
|
-
index
|
|
207
|
-
}),
|
|
208
|
-
isSkinToneSupported: false,
|
|
209
|
-
emojiList: emojiList
|
|
210
|
-
}));
|
|
211
|
-
}
|
|
212
|
-
return emojiCategories.find(({
|
|
213
|
-
slug
|
|
214
|
-
}) => slug === selectedCategory)?.emojis.map(({
|
|
215
|
-
emoji,
|
|
216
|
-
name,
|
|
217
|
-
skin_tone_support
|
|
218
|
-
}, index) => /*#__PURE__*/React.createElement(Emoji, {
|
|
219
|
-
isSelected: index === focusedIndex,
|
|
220
|
-
shouldShowSkinTonePopup: index === focusedIndex && skin_tone_support && shouldShowSkinTonePopup,
|
|
221
|
-
emoji: emoji,
|
|
222
|
-
name: name,
|
|
223
|
-
index: index,
|
|
224
|
-
onRightClick: handleRightClick,
|
|
225
|
-
isSkinToneSupported: skin_tone_support,
|
|
226
|
-
key: name,
|
|
227
|
-
onPopupVisibilityChange: handlePopupVisibilityChange,
|
|
228
|
-
onSelect: e => handleSelect({
|
|
229
|
-
emoji: e,
|
|
230
|
-
name,
|
|
231
|
-
skin_tone_support,
|
|
232
|
-
index
|
|
233
|
-
}),
|
|
234
|
-
emojiList: emojiList
|
|
50
|
+
...data
|
|
235
51
|
}));
|
|
236
|
-
}
|
|
237
|
-
|
|
238
|
-
|
|
239
|
-
|
|
240
|
-
|
|
241
|
-
|
|
242
|
-
|
|
243
|
-
|
|
52
|
+
} else if (selectedCategory === 'history') {
|
|
53
|
+
visibleEmojis = historyEmojis;
|
|
54
|
+
} else {
|
|
55
|
+
visibleEmojis = emojiCategories.find(({
|
|
56
|
+
slug
|
|
57
|
+
}) => slug === selectedCategory)?.emojis ?? [];
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
// Reset navigation and dismiss popups when the displayed identities or their order change,
|
|
61
|
+
// following the existing category-change rule without taking focus from the search field.
|
|
62
|
+
const isHistory = searchString.trim() === '' && selectedCategory === 'history';
|
|
63
|
+
const listKey = JSON.stringify([selectedCategory, isHistory, visibleEmojis.map(({
|
|
64
|
+
emoji
|
|
65
|
+
}) => emoji)]);
|
|
66
|
+
return /*#__PURE__*/React.createElement(EmojiPickerEmojiList, {
|
|
67
|
+
key: listKey,
|
|
68
|
+
emojis: visibleEmojis,
|
|
69
|
+
emojiList: emojiList,
|
|
70
|
+
isHistory: isHistory,
|
|
71
|
+
onSelect: handleSelect
|
|
72
|
+
});
|
|
244
73
|
};
|
|
245
74
|
EmojiPickerEmojis.displayName = 'EmojiPickerEmojis';
|
|
246
75
|
export default EmojiPickerEmojis;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"EmojiPickerEmojis.js","names":["useCombinedRefs","useIsMeasuredClone","emojiLib","React","useCallback","useEffect","useMemo","useRef","useState","germanEmojiLib","useEmojiHistory","Emoji","StyledEmojiPickerEmojis","StyledEmojiPickerEmojisNoContentInfo","EmojiPickerEmojis","accessToken","onSelect","personId","searchString","selectedCategory","shouldPreventScroll","setShouldPreventScroll","shouldShowSkinTonePopup","setShouldShowSkinTonePopup","focusedIndex","setFocusedIndex","emojiCategories","setEmojiCategories","emojiList","setEmojiList","then","default","categories","emojis","shouldPreventListener","ref","emojiRef","shouldPreventEmojiControlsRef","combinedRef","addOrUpdateEmojiInHistory","historyEmojis","handlePopupVisibilityChange","isVisible","current","handleSelect","emoji","name","skin_tone_support","index","shouldRestoreInputFocus","container","scrollTop","handleKeyDown","event","key","preventDefault","children","length","newIndex","ctrlKey","prevElement","tabIndex","newElement","containerRect","getBoundingClientRect","elementRect","bottom","top","dataset","skinToneSupport","document","addEventListener","removeEventListener","handleRightClick","trim","lowerSearchString","toLowerCase","searchResults","Object","entries","forEach","keywords","germanKeywords","includes","some","keyword","push","createElement","isSelected","onRightClick","isSkinToneSupported","onPopupVisibilityChange","e","map","find","slug","shouldShowNoContentInfo","className","$shouldPreventScroll","$shouldShowNoContentInfo","displayName"],"sources":["../../../../../src/components/emoji-picker/emoji-picker-emojis/EmojiPickerEmojis.tsx"],"sourcesContent":["// @ts-nocheck\n\nimport { useCombinedRefs, useIsMeasuredClone } from '@chayns-components/core';\nimport emojiLib from 'emojilib';\nimport React, { FC, useCallback, useEffect, useMemo, useRef, useState } from 'react';\nimport germanEmojiLib from '../../../constants/emoji-de-DE.json';\nimport { useEmojiHistory } from '../../../hooks/emojiHistory';\nimport type { Category } from '../../../types/category';\nimport Emoji from './emoji/Emoji';\nimport {\n StyledEmojiPickerEmojis,\n StyledEmojiPickerEmojisNoContentInfo,\n} from './EmojiPickerEmojis.styles';\n\nexport type EmojiPickerEmojisProps = {\n accessToken?: string;\n onSelect: (emoji: string, shouldRestoreInputFocus?: boolean) => void;\n personId?: string;\n searchString: string;\n selectedCategory: Category;\n};\n\ninterface EmojiType {\n emoji: string;\n skin_tone_support: boolean;\n name: string;\n slug: string;\n unicode_version: string;\n emoji_version: string;\n group?: string;\n}\n\ninterface EmojiCategory {\n name: string;\n slug: string;\n emojis: EmojiType[];\n}\n\ntype EmojiData = EmojiCategory[];\ninterface EmojiDictionary {\n [key: string]: EmojiType;\n}\n\nconst EmojiPickerEmojis: FC<EmojiPickerEmojisProps> = ({\n accessToken,\n onSelect,\n personId,\n searchString,\n selectedCategory,\n}) => {\n const [shouldPreventScroll, setShouldPreventScroll] = useState(false);\n const [shouldShowSkinTonePopup, setShouldShowSkinTonePopup] = useState(false);\n const [focusedIndex, setFocusedIndex] = useState<number>(0);\n const [emojiCategories, setEmojiCategories] = useState<EmojiData>([]);\n const [emojiList, setEmojiList] = useState<EmojiDictionary[]>([]);\n\n useEffect(() => {\n void import('unicode-emoji-json/data-by-group.json').then(({ default: categories }) => {\n setEmojiCategories(categories);\n });\n void import('unicode-emoji-json/data-by-emoji.json').then(({ default: emojis }) => {\n setEmojiList(emojis);\n });\n }, []);\n\n const [shouldPreventListener, ref] = useIsMeasuredClone();\n\n const emojiRef = useRef<HTMLDivElement>(null);\n const shouldPreventEmojiControlsRef = useRef(false);\n\n const combinedRef = useCombinedRefs(emojiRef, ref);\n\n const { addOrUpdateEmojiInHistory, historyEmojis } = useEmojiHistory({\n accessToken,\n personId,\n selectedCategory,\n });\n\n const handlePopupVisibilityChange = useCallback((isVisible: boolean) => {\n setShouldShowSkinTonePopup(isVisible);\n shouldPreventEmojiControlsRef.current = isVisible;\n setShouldPreventScroll(isVisible);\n }, []);\n\n const handleSelect = useCallback(\n (\n {\n emoji,\n name,\n skin_tone_support,\n index,\n }: {\n emoji: string;\n name: string;\n skin_tone_support: boolean;\n index?: number;\n },\n shouldRestoreInputFocus = false,\n ) => {\n onSelect(emoji, shouldRestoreInputFocus);\n\n if (index) {\n setFocusedIndex(index);\n }\n\n void addOrUpdateEmojiInHistory({ emoji, name, skin_tone_support });\n },\n [addOrUpdateEmojiInHistory, onSelect],\n );\n\n useEffect(() => {\n if (selectedCategory) {\n setFocusedIndex(0);\n\n const container = emojiRef.current;\n\n if (!container) {\n return;\n }\n\n container.scrollTop = 0;\n }\n }, [selectedCategory]);\n\n useEffect(() => {\n const handleKeyDown = (event: KeyboardEvent) => {\n if (shouldPreventListener) {\n return;\n }\n\n if (\n !shouldPreventEmojiControlsRef.current &&\n (event.key === 'ArrowUp' ||\n event.key === 'ArrowDown' ||\n event.key === 'ArrowLeft' ||\n event.key === 'ArrowRight')\n ) {\n event.preventDefault();\n const children = emojiRef.current?.children;\n if (children && children.length > 0) {\n const container = emojiRef.current;\n let newIndex = focusedIndex !== null ? focusedIndex : 0;\n\n if (event.ctrlKey) {\n return;\n }\n\n if (event.key === 'ArrowUp') {\n newIndex = (newIndex - 6) % children.length;\n } else if (event.key === 'ArrowDown') {\n newIndex = (newIndex + 6) % children.length;\n } else if (event.key === 'ArrowLeft') {\n newIndex = (newIndex - 1) % children.length;\n } else if (event.key === 'ArrowRight') {\n newIndex = (newIndex + 1) % children.length;\n }\n\n // remove focus from the old element\n if (focusedIndex !== null) {\n const prevElement = children[focusedIndex] as HTMLDivElement;\n prevElement.tabIndex = -1;\n }\n\n if (newIndex < 0) {\n newIndex = children.length - 1;\n } else if (newIndex > children.length - 1) {\n newIndex = 0;\n }\n\n setFocusedIndex(newIndex);\n\n // Set focus to the element\n const newElement = children[newIndex] as HTMLDivElement;\n newElement.tabIndex = 0;\n\n const containerRect = container.getBoundingClientRect();\n const elementRect = newElement.getBoundingClientRect();\n\n if (elementRect.bottom > containerRect.bottom) {\n container.scrollTop += elementRect.bottom - containerRect.bottom;\n } else if (elementRect.top < containerRect.top) {\n container.scrollTop -= containerRect.top - elementRect.top;\n }\n }\n } else if (\n event.key === 'Enter' &&\n !shouldPreventEmojiControlsRef.current &&\n focusedIndex !== null\n ) {\n if (event.ctrlKey) {\n setShouldShowSkinTonePopup(true);\n\n return;\n }\n\n const { dataset } = emojiRef.current?.children[focusedIndex] as HTMLDivElement;\n\n const { emoji, name, skinToneSupport } = dataset;\n\n if (!emoji || !name || !skinToneSupport) {\n return;\n }\n\n handleSelect({ emoji, name, skin_tone_support: skinToneSupport === 'true' }, true);\n }\n };\n\n document.addEventListener('keydown', handleKeyDown);\n\n return () => {\n document.removeEventListener('keydown', handleKeyDown);\n };\n }, [focusedIndex, handleSelect, shouldPreventListener]);\n\n const handleRightClick = useCallback((index: number) => {\n setFocusedIndex(index);\n }, []);\n\n const emojis = useMemo(() => {\n if (searchString.trim() !== '') {\n const lowerSearchString = searchString.toLowerCase();\n\n const searchResults: JSX.Element[] = [];\n\n Object.entries(emojiList).forEach(([emoji, { name, skin_tone_support }], index) => {\n const keywords = (emojiLib as { [key: string]: string[] })[emoji] as\n | string[]\n | undefined;\n\n const germanKeywords = (germanEmojiLib as { [key: string]: string[] })[emoji] as\n | string[]\n | undefined;\n\n if (\n name.includes(lowerSearchString) ||\n keywords?.some((keyword) => keyword.includes(lowerSearchString)) ||\n germanKeywords?.some((keyword) => keyword.includes(lowerSearchString))\n ) {\n searchResults.push(\n <Emoji\n shouldShowSkinTonePopup={\n index === focusedIndex &&\n skin_tone_support &&\n shouldShowSkinTonePopup\n }\n isSelected={index === focusedIndex}\n emoji={emoji}\n index={index}\n onRightClick={handleRightClick}\n isSkinToneSupported={skin_tone_support}\n key={name}\n name={name}\n onPopupVisibilityChange={handlePopupVisibilityChange}\n onSelect={(e) =>\n handleSelect({ emoji: e, name, skin_tone_support, index })\n }\n emojiList={emojiList}\n />,\n );\n }\n });\n\n return searchResults;\n }\n\n if (selectedCategory === 'history') {\n return historyEmojis.map(({ emoji, name, skin_tone_support }, index) => (\n <Emoji\n isSelected={index === focusedIndex}\n shouldShowSkinTonePopup={\n index === focusedIndex && skin_tone_support && shouldShowSkinTonePopup\n }\n emoji={emoji}\n name={name}\n key={name}\n index={index}\n onRightClick={handleRightClick}\n onPopupVisibilityChange={handlePopupVisibilityChange}\n onSelect={(e) => handleSelect({ emoji: e, name, skin_tone_support, index })}\n isSkinToneSupported={false}\n emojiList={emojiList}\n />\n ));\n }\n\n return emojiCategories\n .find(({ slug }) => slug === selectedCategory)\n ?.emojis.map(({ emoji, name, skin_tone_support }, index) => (\n <Emoji\n isSelected={index === focusedIndex}\n shouldShowSkinTonePopup={\n index === focusedIndex && skin_tone_support && shouldShowSkinTonePopup\n }\n emoji={emoji}\n name={name}\n index={index}\n onRightClick={handleRightClick}\n isSkinToneSupported={skin_tone_support}\n key={name}\n onPopupVisibilityChange={handlePopupVisibilityChange}\n onSelect={(e) => handleSelect({ emoji: e, name, skin_tone_support, index })}\n emojiList={emojiList}\n />\n ));\n }, [\n searchString,\n selectedCategory,\n focusedIndex,\n shouldShowSkinTonePopup,\n handleRightClick,\n handlePopupVisibilityChange,\n handleSelect,\n historyEmojis,\n ]);\n\n const shouldShowNoContentInfo = !emojis || emojis.length === 0;\n\n return (\n <StyledEmojiPickerEmojis\n className=\"chayns-scrollbar\"\n $shouldPreventScroll={shouldPreventScroll}\n $shouldShowNoContentInfo={shouldShowNoContentInfo}\n ref={combinedRef}\n >\n {emojis}\n {shouldShowNoContentInfo && (\n <StyledEmojiPickerEmojisNoContentInfo>\n Hier werden die zuletzt verwendeten Emojis angezeigt, die über diese Auswahl\n gewählt wurden.\n </StyledEmojiPickerEmojisNoContentInfo>\n )}\n </StyledEmojiPickerEmojis>\n );\n};\n\nEmojiPickerEmojis.displayName = 'EmojiPickerEmojis';\n\nexport default EmojiPickerEmojis;\n"],"mappings":"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","ignoreList":[]}
|
|
1
|
+
{"version":3,"file":"EmojiPickerEmojis.js","names":["React","useCallback","useEffect","useState","emojiLib","germanEmojiLib","useEmojiHistory","EmojiPickerEmojiList","EmojiPickerEmojis","accessToken","onSelect","personId","searchString","selectedCategory","emojiCategories","setEmojiCategories","emojiList","setEmojiList","addOrUpdateEmojiInHistory","historyEmojis","handleSelect","emoji","shouldRestoreInputFocus","then","default","categories","emojis","visibleEmojis","trim","lowerSearchString","toLowerCase","Object","entries","filter","name","keywords","germanKeywords","includes","some","keyword","map","data","find","slug","isHistory","listKey","JSON","stringify","createElement","key","displayName"],"sources":["../../../../../src/components/emoji-picker/emoji-picker-emojis/EmojiPickerEmojis.tsx"],"sourcesContent":["import React, { FC, useCallback, useEffect, useState } from 'react';\nimport emojiLib from 'emojilib';\nimport germanEmojiLib from '../../../constants/emoji-de-DE.json';\nimport { useEmojiHistory } from '../../../hooks/emojiHistory';\nimport type { Category } from '../../../types/category';\nimport EmojiPickerEmojiList, {\n type PickerEmoji,\n} from './emoji-picker-emoji-list/EmojiPickerEmojiList';\n\nexport type EmojiPickerEmojisProps = {\n accessToken?: string;\n onSelect: (emoji: string, shouldRestoreInputFocus?: boolean) => void;\n personId?: string;\n searchString: string;\n selectedCategory: Category;\n};\n\ntype EmojiDictionary = Record<string, Omit<PickerEmoji, 'emoji'>>;\ntype EmojiCategory = { slug: string; emojis: PickerEmoji[] };\n\nconst EmojiPickerEmojis: FC<EmojiPickerEmojisProps> = ({\n accessToken,\n onSelect,\n personId,\n searchString,\n selectedCategory,\n}) => {\n const [emojiCategories, setEmojiCategories] = useState<EmojiCategory[]>([]);\n const [emojiList, setEmojiList] = useState<EmojiDictionary>({});\n\n const { addOrUpdateEmojiInHistory, historyEmojis } = useEmojiHistory({\n accessToken,\n personId,\n selectedCategory,\n });\n\n const handleSelect = useCallback(\n (emoji: PickerEmoji, shouldRestoreInputFocus = false) => {\n onSelect(emoji.emoji, shouldRestoreInputFocus);\n void addOrUpdateEmojiInHistory(emoji);\n },\n [addOrUpdateEmojiInHistory, onSelect],\n );\n\n useEffect(() => {\n void import('unicode-emoji-json/data-by-group.json').then(({ default: categories }) => {\n setEmojiCategories(categories);\n });\n void import('unicode-emoji-json/data-by-emoji.json').then(({ default: emojis }) => {\n setEmojiList(emojis);\n });\n }, []);\n\n let visibleEmojis: PickerEmoji[];\n\n if (searchString.trim() !== '') {\n const lowerSearchString = searchString.toLowerCase();\n visibleEmojis = Object.entries(emojiList)\n .filter(([emoji, { name }]) => {\n const keywords = (emojiLib as Record<string, string[]>)[emoji];\n const germanKeywords = (germanEmojiLib as Record<string, string[]>)[emoji];\n\n return (\n name.includes(lowerSearchString) ||\n keywords?.some((keyword) => keyword.includes(lowerSearchString)) ||\n germanKeywords?.some((keyword) => keyword.includes(lowerSearchString))\n );\n })\n .map(([emoji, data]) => ({ emoji, ...data }));\n } else if (selectedCategory === 'history') {\n visibleEmojis = historyEmojis;\n } else {\n visibleEmojis = emojiCategories.find(({ slug }) => slug === selectedCategory)?.emojis ?? [];\n }\n\n // Reset navigation and dismiss popups when the displayed identities or their order change,\n // following the existing category-change rule without taking focus from the search field.\n const isHistory = searchString.trim() === '' && selectedCategory === 'history';\n const listKey = JSON.stringify([\n selectedCategory,\n isHistory,\n visibleEmojis.map(({ emoji }) => emoji),\n ]);\n\n return (\n <EmojiPickerEmojiList\n key={listKey}\n emojis={visibleEmojis}\n emojiList={emojiList}\n isHistory={isHistory}\n onSelect={handleSelect}\n />\n );\n};\n\nEmojiPickerEmojis.displayName = 'EmojiPickerEmojis';\n\nexport default EmojiPickerEmojis;\n"],"mappings":"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","ignoreList":[]}
|
|
@@ -0,0 +1,312 @@
|
|
|
1
|
+
import { fireEvent, render, screen, waitFor } from '@testing-library/react';
|
|
2
|
+
import React from 'react';
|
|
3
|
+
import { ThemeProvider } from 'styled-components';
|
|
4
|
+
import { beforeEach, describe, expect, it, vi } from 'vitest';
|
|
5
|
+
import EmojiPickerEmojis from './EmojiPickerEmojis';
|
|
6
|
+
const fixtures = vi.hoisted(() => ({
|
|
7
|
+
emojis: [{
|
|
8
|
+
emoji: '😀',
|
|
9
|
+
name: 'grinning face',
|
|
10
|
+
skin_tone_support: false
|
|
11
|
+
}, {
|
|
12
|
+
emoji: '😃',
|
|
13
|
+
name: 'smiling face',
|
|
14
|
+
skin_tone_support: false
|
|
15
|
+
}, {
|
|
16
|
+
emoji: '😄',
|
|
17
|
+
name: 'laughing face',
|
|
18
|
+
skin_tone_support: false
|
|
19
|
+
}, {
|
|
20
|
+
emoji: '🐈',
|
|
21
|
+
name: 'cat',
|
|
22
|
+
skin_tone_support: false
|
|
23
|
+
}, {
|
|
24
|
+
emoji: '👍',
|
|
25
|
+
name: 'thumbs up',
|
|
26
|
+
skin_tone_support: true
|
|
27
|
+
}, {
|
|
28
|
+
emoji: '👎',
|
|
29
|
+
name: 'thumbs down',
|
|
30
|
+
skin_tone_support: true
|
|
31
|
+
}, {
|
|
32
|
+
emoji: '👋',
|
|
33
|
+
name: 'waving hand',
|
|
34
|
+
skin_tone_support: true
|
|
35
|
+
}, {
|
|
36
|
+
emoji: '🤝',
|
|
37
|
+
name: 'handshake',
|
|
38
|
+
skin_tone_support: true
|
|
39
|
+
}],
|
|
40
|
+
addHistory: vi.fn(),
|
|
41
|
+
history: []
|
|
42
|
+
}));
|
|
43
|
+
vi.mock('unicode-emoji-json/data-by-group.json', () => ({
|
|
44
|
+
default: [{
|
|
45
|
+
slug: 'smileys_emotion',
|
|
46
|
+
emojis: fixtures.emojis
|
|
47
|
+
}, {
|
|
48
|
+
slug: 'people_body',
|
|
49
|
+
emojis: fixtures.emojis.slice(4)
|
|
50
|
+
}]
|
|
51
|
+
}));
|
|
52
|
+
vi.mock('unicode-emoji-json/data-by-emoji.json', () => ({
|
|
53
|
+
default: Object.fromEntries(fixtures.emojis.map(({
|
|
54
|
+
emoji,
|
|
55
|
+
...data
|
|
56
|
+
}) => [emoji, data]))
|
|
57
|
+
}));
|
|
58
|
+
vi.mock('../../../hooks/emojiHistory', () => ({
|
|
59
|
+
useEmojiHistory: () => ({
|
|
60
|
+
addOrUpdateEmojiInHistory: fixtures.addHistory,
|
|
61
|
+
historyEmojis: fixtures.history.slice()
|
|
62
|
+
})
|
|
63
|
+
}));
|
|
64
|
+
vi.mock('@chayns-components/core', async () => {
|
|
65
|
+
const {
|
|
66
|
+
useRef
|
|
67
|
+
} = await import('react');
|
|
68
|
+
return {
|
|
69
|
+
...(await import('../../../../../core/src/hooks/ref')),
|
|
70
|
+
useIsMeasuredClone: () => [false, useRef(null)]
|
|
71
|
+
};
|
|
72
|
+
});
|
|
73
|
+
const setup = async () => {
|
|
74
|
+
const onSelect = vi.fn();
|
|
75
|
+
const renderPicker = (searchString = '', selectedCategory = 'smileys_emotion') => /*#__PURE__*/React.createElement(ThemeProvider, {
|
|
76
|
+
theme: {
|
|
77
|
+
'secondary-102': 'rgb(255, 0, 0)'
|
|
78
|
+
}
|
|
79
|
+
}, /*#__PURE__*/React.createElement("input", {
|
|
80
|
+
"aria-label": "Search"
|
|
81
|
+
}), /*#__PURE__*/React.createElement(EmojiPickerEmojis, {
|
|
82
|
+
onSelect: onSelect,
|
|
83
|
+
searchString: searchString,
|
|
84
|
+
selectedCategory: selectedCategory
|
|
85
|
+
}));
|
|
86
|
+
const view = render(renderPicker());
|
|
87
|
+
await waitFor(() => expect(view.container.querySelectorAll('[data-emoji]')).toHaveLength(8));
|
|
88
|
+
return {
|
|
89
|
+
...view,
|
|
90
|
+
onSelect,
|
|
91
|
+
update: (search = '', category) => view.rerender(renderPicker(search, category))
|
|
92
|
+
};
|
|
93
|
+
};
|
|
94
|
+
const key = (key, ctrlKey = false) => fireEvent.keyDown(document, {
|
|
95
|
+
key,
|
|
96
|
+
ctrlKey
|
|
97
|
+
});
|
|
98
|
+
const navigate = () => {
|
|
99
|
+
for (let index = 0; index < 7; index += 1) key('ArrowRight');
|
|
100
|
+
};
|
|
101
|
+
const selected = element => expect(getComputedStyle(element).backgroundColor).toBe('rgb(255, 0, 0)');
|
|
102
|
+
beforeEach(() => {
|
|
103
|
+
fixtures.addHistory.mockReset();
|
|
104
|
+
fixtures.history = [];
|
|
105
|
+
});
|
|
106
|
+
describe('EmojiPickerEmojis changing results', () => {
|
|
107
|
+
it('resets to the first result before Enter after narrowing the search', async () => {
|
|
108
|
+
const {
|
|
109
|
+
onSelect,
|
|
110
|
+
update
|
|
111
|
+
} = await setup();
|
|
112
|
+
navigate();
|
|
113
|
+
screen.getByRole('textbox', {
|
|
114
|
+
name: 'Search'
|
|
115
|
+
}).focus();
|
|
116
|
+
update('thumbs');
|
|
117
|
+
key('Enter');
|
|
118
|
+
expect(onSelect).toHaveBeenCalledTimes(1);
|
|
119
|
+
expect(onSelect).toHaveBeenCalledWith('👍', true);
|
|
120
|
+
expect(document.activeElement).toBe(screen.getByRole('textbox', {
|
|
121
|
+
name: 'Search'
|
|
122
|
+
}));
|
|
123
|
+
});
|
|
124
|
+
it('does not select the hint or throw on Enter and Ctrl+Enter without results', async () => {
|
|
125
|
+
const {
|
|
126
|
+
onSelect,
|
|
127
|
+
update,
|
|
128
|
+
container
|
|
129
|
+
} = await setup();
|
|
130
|
+
navigate();
|
|
131
|
+
update('no-matching-emoji-9284');
|
|
132
|
+
key('Enter');
|
|
133
|
+
key('Enter', true);
|
|
134
|
+
expect(onSelect).not.toHaveBeenCalled();
|
|
135
|
+
expect(container.querySelector('[data-emoji]')).toBeNull();
|
|
136
|
+
expect(container.querySelector('[tabindex="0"]')).toBeNull();
|
|
137
|
+
});
|
|
138
|
+
it.each(['thumbs', 'no-matching-emoji-9284'])('handles every arrow after searching for %s', async search => {
|
|
139
|
+
const {
|
|
140
|
+
onSelect,
|
|
141
|
+
update,
|
|
142
|
+
container
|
|
143
|
+
} = await setup();
|
|
144
|
+
navigate();
|
|
145
|
+
update(search);
|
|
146
|
+
for (const direction of ['ArrowRight', 'ArrowLeft', 'ArrowUp', 'ArrowDown']) key(direction);
|
|
147
|
+
key('Enter');
|
|
148
|
+
if (search === 'thumbs') {
|
|
149
|
+
expect(onSelect).toHaveBeenCalledTimes(1);
|
|
150
|
+
expect(onSelect).toHaveBeenCalledWith('👍', true);
|
|
151
|
+
selected(container.querySelector('[data-emoji="👍"]'));
|
|
152
|
+
} else expect(onSelect).not.toHaveBeenCalled();
|
|
153
|
+
});
|
|
154
|
+
it('recovers after clearing an empty search', async () => {
|
|
155
|
+
const {
|
|
156
|
+
onSelect,
|
|
157
|
+
update,
|
|
158
|
+
container
|
|
159
|
+
} = await setup();
|
|
160
|
+
navigate();
|
|
161
|
+
update('no-matching-emoji-9284');
|
|
162
|
+
key('ArrowRight');
|
|
163
|
+
update('');
|
|
164
|
+
key('ArrowRight');
|
|
165
|
+
key('Enter');
|
|
166
|
+
expect(onSelect).toHaveBeenCalledTimes(1);
|
|
167
|
+
expect(onSelect).toHaveBeenCalledWith('😃', true);
|
|
168
|
+
selected(container.querySelector('[data-emoji="😃"]'));
|
|
169
|
+
});
|
|
170
|
+
it('resets on category changes and keeps an empty history unselectable', async () => {
|
|
171
|
+
const {
|
|
172
|
+
onSelect,
|
|
173
|
+
update
|
|
174
|
+
} = await setup();
|
|
175
|
+
navigate();
|
|
176
|
+
update('', 'people_body');
|
|
177
|
+
key('Enter');
|
|
178
|
+
expect(onSelect).toHaveBeenLastCalledWith('👍', true);
|
|
179
|
+
onSelect.mockClear();
|
|
180
|
+
update('', 'history');
|
|
181
|
+
key('ArrowRight');
|
|
182
|
+
key('ArrowDown');
|
|
183
|
+
key('Enter');
|
|
184
|
+
expect(onSelect).not.toHaveBeenCalled();
|
|
185
|
+
});
|
|
186
|
+
it('uses visible positions for highlight, keyboard selection, and mouse selection including index zero', async () => {
|
|
187
|
+
const {
|
|
188
|
+
onSelect,
|
|
189
|
+
update,
|
|
190
|
+
container
|
|
191
|
+
} = await setup();
|
|
192
|
+
update('thumbs');
|
|
193
|
+
selected(container.querySelector('[data-emoji="👍"]'));
|
|
194
|
+
key('ArrowRight');
|
|
195
|
+
selected(container.querySelector('[data-emoji="👎"]'));
|
|
196
|
+
key('Enter');
|
|
197
|
+
expect(onSelect).toHaveBeenLastCalledWith('👎', true);
|
|
198
|
+
fireEvent.click(container.querySelector('[data-emoji="👍"]'));
|
|
199
|
+
selected(container.querySelector('[data-emoji="👍"]'));
|
|
200
|
+
expect(onSelect).toHaveBeenLastCalledWith('👍', false);
|
|
201
|
+
});
|
|
202
|
+
it('opens the skin tone popup for the visible right-clicked emoji after filtering', async () => {
|
|
203
|
+
const {
|
|
204
|
+
update,
|
|
205
|
+
onSelect,
|
|
206
|
+
container
|
|
207
|
+
} = await setup();
|
|
208
|
+
update('thumbs');
|
|
209
|
+
fireEvent.contextMenu(container.querySelector('[data-emoji="👎"]'));
|
|
210
|
+
selected(container.querySelector('[data-emoji="👎"]'));
|
|
211
|
+
key('ArrowRight');
|
|
212
|
+
key('Enter');
|
|
213
|
+
expect(onSelect).toHaveBeenCalledTimes(1);
|
|
214
|
+
expect(onSelect).toHaveBeenCalledWith('👎🏼', false);
|
|
215
|
+
});
|
|
216
|
+
it('closes a stale popup on result changes and resumes grid controls', async () => {
|
|
217
|
+
const {
|
|
218
|
+
update,
|
|
219
|
+
onSelect,
|
|
220
|
+
container
|
|
221
|
+
} = await setup();
|
|
222
|
+
update('thumbs');
|
|
223
|
+
key('Enter', true);
|
|
224
|
+
expect(container.querySelector('[data-skin-tone]')).not.toBeNull();
|
|
225
|
+
update('cat');
|
|
226
|
+
expect(container.querySelector('[data-skin-tone]')).toBeNull();
|
|
227
|
+
key('ArrowRight');
|
|
228
|
+
key('Enter');
|
|
229
|
+
expect(onSelect).toHaveBeenCalledTimes(1);
|
|
230
|
+
expect(onSelect).toHaveBeenCalledWith('🐈', true);
|
|
231
|
+
});
|
|
232
|
+
it('dismisses the old popup even when its emoji remains in a smaller result list', async () => {
|
|
233
|
+
const {
|
|
234
|
+
update,
|
|
235
|
+
onSelect,
|
|
236
|
+
container
|
|
237
|
+
} = await setup();
|
|
238
|
+
update('thumbs');
|
|
239
|
+
fireEvent.contextMenu(container.querySelector('[data-emoji="👍"]'));
|
|
240
|
+
expect(container.querySelector('[data-skin-tone]')).not.toBeNull();
|
|
241
|
+
update('thumbs up');
|
|
242
|
+
expect(container.querySelector('[data-skin-tone]')).toBeNull();
|
|
243
|
+
selected(container.querySelector('[data-emoji="👍"]'));
|
|
244
|
+
key('Enter');
|
|
245
|
+
expect(onSelect).toHaveBeenCalledTimes(1);
|
|
246
|
+
expect(onSelect).toHaveBeenCalledWith('👍', true);
|
|
247
|
+
});
|
|
248
|
+
it('does not carry an unsupported Ctrl+Enter popup request to the next emoji', async () => {
|
|
249
|
+
const {
|
|
250
|
+
update,
|
|
251
|
+
onSelect,
|
|
252
|
+
container
|
|
253
|
+
} = await setup();
|
|
254
|
+
update('cat');
|
|
255
|
+
key('Enter', true);
|
|
256
|
+
update('thumbs');
|
|
257
|
+
expect(container.querySelector('[data-skin-tone]')).toBeNull();
|
|
258
|
+
key('ArrowRight');
|
|
259
|
+
key('Enter');
|
|
260
|
+
expect(onSelect).toHaveBeenCalledTimes(1);
|
|
261
|
+
expect(onSelect).toHaveBeenCalledWith('👎', true);
|
|
262
|
+
});
|
|
263
|
+
it('keeps navigation stable when history is returned as a fresh array', async () => {
|
|
264
|
+
fixtures.history = fixtures.emojis.slice(0, 3);
|
|
265
|
+
const {
|
|
266
|
+
update,
|
|
267
|
+
onSelect,
|
|
268
|
+
container
|
|
269
|
+
} = await setup();
|
|
270
|
+
update('', 'history');
|
|
271
|
+
key('ArrowRight');
|
|
272
|
+
update('', 'history');
|
|
273
|
+
key('ArrowRight');
|
|
274
|
+
selected(container.querySelector('[data-emoji="😄"]'));
|
|
275
|
+
expect(container.querySelectorAll('[data-emoji][tabindex="0"]')).toHaveLength(1);
|
|
276
|
+
key('Enter');
|
|
277
|
+
expect(onSelect).toHaveBeenCalledTimes(1);
|
|
278
|
+
expect(onSelect).toHaveBeenCalledWith('😄', true);
|
|
279
|
+
});
|
|
280
|
+
it('clears a search popup when returning to history with the same visible emoji', async () => {
|
|
281
|
+
fixtures.history = [fixtures.emojis[4]];
|
|
282
|
+
const {
|
|
283
|
+
update,
|
|
284
|
+
container
|
|
285
|
+
} = await setup();
|
|
286
|
+
update('thumbs up', 'history');
|
|
287
|
+
key('Enter', true);
|
|
288
|
+
expect(container.querySelector('[data-skin-tone]')).not.toBeNull();
|
|
289
|
+
update('', 'history');
|
|
290
|
+
expect(container.querySelector('[data-skin-tone]')).toBeNull();
|
|
291
|
+
key('Enter', true);
|
|
292
|
+
expect(container.querySelector('[data-skin-tone]')).toBeNull();
|
|
293
|
+
});
|
|
294
|
+
it('keeps normal six-column keyboard navigation and history callbacks', async () => {
|
|
295
|
+
const {
|
|
296
|
+
onSelect,
|
|
297
|
+
container
|
|
298
|
+
} = await setup();
|
|
299
|
+
key('ArrowDown');
|
|
300
|
+
selected(container.querySelector('[data-emoji="👋"]'));
|
|
301
|
+
key('Enter');
|
|
302
|
+
expect(onSelect).toHaveBeenCalledTimes(1);
|
|
303
|
+
expect(onSelect).toHaveBeenCalledWith('👋', true);
|
|
304
|
+
expect(fixtures.addHistory).toHaveBeenCalledTimes(1);
|
|
305
|
+
expect(fixtures.addHistory).toHaveBeenCalledWith({
|
|
306
|
+
emoji: '👋',
|
|
307
|
+
name: 'waving hand',
|
|
308
|
+
skin_tone_support: true
|
|
309
|
+
});
|
|
310
|
+
});
|
|
311
|
+
});
|
|
312
|
+
//# sourceMappingURL=EmojiPickerEmojis.test.js.map
|