@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.
Files changed (26) hide show
  1. package/lib/cjs/build.test.js +34 -0
  2. package/lib/cjs/build.test.js.map +1 -0
  3. package/lib/cjs/components/emoji-picker/emoji-picker-emojis/EmojiPickerEmojis.js +48 -219
  4. package/lib/cjs/components/emoji-picker/emoji-picker-emojis/EmojiPickerEmojis.js.map +1 -1
  5. package/lib/cjs/components/emoji-picker/emoji-picker-emojis/EmojiPickerEmojis.test.js +316 -0
  6. package/lib/cjs/components/emoji-picker/emoji-picker-emojis/EmojiPickerEmojis.test.js.map +1 -0
  7. package/lib/cjs/components/emoji-picker/emoji-picker-emojis/emoji/Emoji.js +1 -0
  8. package/lib/cjs/components/emoji-picker/emoji-picker-emojis/emoji/Emoji.js.map +1 -1
  9. package/lib/cjs/components/emoji-picker/emoji-picker-emojis/emoji-picker-emoji-list/EmojiPickerEmojiList.js +109 -0
  10. package/lib/cjs/components/emoji-picker/emoji-picker-emojis/emoji-picker-emoji-list/EmojiPickerEmojiList.js.map +1 -0
  11. package/lib/esm/build.test.js +32 -0
  12. package/lib/esm/build.test.js.map +1 -0
  13. package/lib/esm/components/emoji-picker/emoji-picker-emojis/EmojiPickerEmojis.js +47 -218
  14. package/lib/esm/components/emoji-picker/emoji-picker-emojis/EmojiPickerEmojis.js.map +1 -1
  15. package/lib/esm/components/emoji-picker/emoji-picker-emojis/EmojiPickerEmojis.test.js +312 -0
  16. package/lib/esm/components/emoji-picker/emoji-picker-emojis/EmojiPickerEmojis.test.js.map +1 -0
  17. package/lib/esm/components/emoji-picker/emoji-picker-emojis/emoji/Emoji.js +1 -0
  18. package/lib/esm/components/emoji-picker/emoji-picker-emojis/emoji/Emoji.js.map +1 -1
  19. package/lib/esm/components/emoji-picker/emoji-picker-emojis/emoji-picker-emoji-list/EmojiPickerEmojiList.js +101 -0
  20. package/lib/esm/components/emoji-picker/emoji-picker-emojis/emoji-picker-emoji-list/EmojiPickerEmojiList.js.map +1 -0
  21. package/lib/types/components/emoji-picker/emoji-picker-emojis/emoji-picker-emoji-list/EmojiPickerEmojiList.d.ts +15 -0
  22. package/package.json +3 -3
  23. package/lib/types/components/emoji-input/EmojiInput.test.d.ts +0 -1
  24. package/lib/types/utils/emoji.test.d.ts +0 -1
  25. package/lib/types/utils/selection.test.d.ts +0 -1
  26. package/lib/types/utils/text.test.d.ts +0 -1
@@ -1,12 +1,8 @@
1
- // @ts-nocheck
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 Emoji from './emoji/Emoji';
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
- const [shouldPreventListener, ref] = useIsMeasuredClone();
35
- const emojiRef = useRef(null);
36
- const shouldPreventEmojiControlsRef = useRef(false);
37
- const combinedRef = useCombinedRefs(emojiRef, ref);
38
- const {
39
- addOrUpdateEmojiInHistory,
40
- historyEmojis
41
- } = useEmojiHistory({
42
- accessToken,
43
- personId,
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
- name,
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
- }, [searchString, selectedCategory, focusedIndex, shouldShowSkinTonePopup, handleRightClick, handlePopupVisibilityChange, handleSelect, historyEmojis]);
237
- const shouldShowNoContentInfo = !emojis || emojis.length === 0;
238
- return /*#__PURE__*/React.createElement(StyledEmojiPickerEmojis, {
239
- className: "chayns-scrollbar",
240
- $shouldPreventScroll: shouldPreventScroll,
241
- $shouldShowNoContentInfo: shouldShowNoContentInfo,
242
- ref: combinedRef
243
- }, emojis, shouldShowNoContentInfo && /*#__PURE__*/React.createElement(StyledEmojiPickerEmojisNoContentInfo, null, "Hier werden die zuletzt verwendeten Emojis angezeigt, die \xFCber diese Auswahl gew\xE4hlt wurden."));
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