emoji-picker-react 4.20.0 → 4.20.1
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/README.md +53 -230
- package/dist/Stylesheet/stylesheet.d.ts +16 -4
- package/dist/emoji-picker-react.cjs.development.js +38 -12
- package/dist/emoji-picker-react.cjs.development.js.map +1 -1
- package/dist/emoji-picker-react.cjs.production.min.js +1 -1
- package/dist/emoji-picker-react.cjs.production.min.js.map +1 -1
- package/dist/emoji-picker-react.esm.js +38 -12
- package/dist/emoji-picker-react.esm.js.map +1 -1
- package/dist/hooks/useIsomorphicLayoutEffect.d.ts +2 -0
- package/llms.txt +422 -0
- package/package.json +6 -4
- package/src/components/body/MeasureEmoji.tsx +2 -1
- package/src/components/context/PickerDataContext.tsx +9 -1
- package/src/dataUtils/emojiSelectors.ts +9 -1
- package/src/dataUtils/suggested.ts +6 -3
- package/src/hooks/useDebouncedState.ts +2 -2
- package/src/hooks/useIsomorphicLayoutEffect.ts +6 -0
- package/src/hooks/useMouseDownHandlers.ts +2 -2
package/README.md
CHANGED
|
@@ -1,218 +1,77 @@
|
|
|
1
|
-
#
|
|
1
|
+
# Emoji Picker React
|
|
2
2
|
|
|
3
|
-
|
|
3
|
+
The most popular fully customizable emoji picker for React.
|
|
4
4
|
|
|
5
|
-
|
|
5
|
+
[](https://www.npmjs.com/package/emoji-picker-react)
|
|
6
|
+
|
|
7
|
+
**[Live Demo](https://ealush.com/emoji-picker-react)** | **[Report a Bug](https://github.com/ealush/emoji-picker-react/issues)**
|
|
6
8
|
|
|
7
9
|

|
|
8
10
|
|
|
9
11
|

|
|
10
12
|
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
## ✨ Features
|
|
14
|
-
|
|
15
|
-
- 🎨 **Fully Customizable**: Control styles via CSS variables.
|
|
16
|
-
- 🌗 **Dark Mode**: Native support for light, dark, and auto themes.
|
|
17
|
-
- 🖱️ **Interactivity**: Custom click handlers and reactions picker mode.
|
|
18
|
-
- 🌍 **Multi-Language**: Built-in support for dozens of languages.
|
|
19
|
-
- 🦄 **Custom Emojis**: seamless support for custom image-based emojis.
|
|
20
|
-
- 📦 **Zero-Config**: Works out of the box with sensible defaults.
|
|
21
|
-
- 📱 **Responsive**: Mobile-friendly design.
|
|
22
|
-
- 🍎 **Multiple Styles**: Support for Apple, Google, Facebook, Twitter, and Native system emojis.
|
|
23
|
-
|
|
24
|
-
---
|
|
13
|
+
## Features
|
|
25
14
|
|
|
26
|
-
|
|
15
|
+
- Fully customizable through props and CSS variables
|
|
16
|
+
- Light, dark, and auto themes
|
|
17
|
+
- Reactions picker mode and custom click handlers
|
|
18
|
+
- Dozens of built-in languages
|
|
19
|
+
- Custom image-based emojis
|
|
20
|
+
- Apple, Google, Facebook, Twitter, and native emoji styles
|
|
21
|
+
- Responsive and mobile-friendly
|
|
22
|
+
- SSR-safe
|
|
27
23
|
|
|
28
|
-
|
|
24
|
+
## Installation
|
|
29
25
|
|
|
30
26
|
```bash
|
|
31
27
|
npm install emoji-picker-react
|
|
32
|
-
|
|
33
28
|
```
|
|
34
29
|
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
Render the component in your app. It works immediately with no required props.
|
|
30
|
+
## Usage
|
|
38
31
|
|
|
39
32
|
```jsx
|
|
40
33
|
import EmojiPicker from 'emoji-picker-react';
|
|
41
34
|
|
|
42
35
|
function App() {
|
|
43
36
|
return (
|
|
44
|
-
<
|
|
45
|
-
<EmojiPicker onEmojiClick={(emojiObject) => console.log(emojiObject)} />
|
|
46
|
-
</div>
|
|
37
|
+
<EmojiPicker onEmojiClick={(emojiData) => console.log(emojiData.emoji)} />
|
|
47
38
|
);
|
|
48
39
|
}
|
|
49
40
|
```
|
|
50
41
|
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
## 📚 Props Reference
|
|
54
|
-
|
|
55
|
-
The following is a complete list of all props accepted by `EmojiPicker`.
|
|
56
|
-
|
|
57
|
-
### 🎛️ General Configuration
|
|
58
|
-
|
|
59
|
-
| Prop | Type | Default | Description |
|
|
60
|
-
| ----------------- | ------------ | ------------------ | -------------------------------------------------------------------------------------------- |
|
|
61
|
-
| `open` | `boolean` | `true` | Controls the visibility of the picker. |
|
|
62
|
-
| `theme` | `Theme` | `Theme.LIGHT` | The visual theme. Options: `'light'`, `'dark'`, `'auto'`. |
|
|
63
|
-
| `emojiStyle` | `EmojiStyle` | `EmojiStyle.APPLE` | The emoji set to use. Options: `'apple'`, `'google'`, `'facebook'`, `'twitter'`, `'native'`. |
|
|
64
|
-
| `emojiVersion` | `string` | `null` | Limit emojis to a specific unicode version (e.g., `"14.0"`). |
|
|
65
|
-
| `lazyLoadEmojis` | `boolean` | `false` | If true, emoji images are loaded only when they scroll into view. |
|
|
66
|
-
| `autoFocusSearch` | `boolean` | `true` | Focuses the search input automatically when the picker mounts. |
|
|
67
|
-
| `emojiData` | `object` | `undefined` | Pass imported locale data here for internationalization. |
|
|
68
|
-
|
|
69
|
-
### 📐 Dimensions & Styling
|
|
70
|
-
|
|
71
|
-
| Prop | Type | Default | Description |
|
|
72
|
-
| ----------- | --------------- | -------- | ------------------------------------------ |
|
|
73
|
-
| `width` | `string` | `number` | `350` |
|
|
74
|
-
| `height` | `string` | `number` | `450` |
|
|
75
|
-
| `style` | `CSSProperties` | `{}` | Inline styles applied to the root element. |
|
|
76
|
-
| `className` | `string` | `""` | CSS class applied to the root element. |
|
|
77
|
-
|
|
78
|
-
### 🖱️ Events & Interaction
|
|
79
|
-
|
|
80
|
-
| Prop | Type | Description |
|
|
81
|
-
| ------------------ | -------------------------------------------------------- | -------------------------------------------------------------------- |
|
|
82
|
-
| `onEmojiClick` | `(emojiData: EmojiClickData, event: MouseEvent) => void` | Callback triggered when a user clicks an emoji. |
|
|
83
|
-
| `onReactionClick` | `(emojiData: EmojiClickData, event: MouseEvent) => void` | Callback triggered when a user clicks a reaction (in reaction mode). |
|
|
84
|
-
| `onSkinToneChange` | `(skinTone: SkinTones) => void` | Callback triggered when the user selects a new skin tone. |
|
|
85
|
-
|
|
86
|
-
### 🔎 Search & Categories
|
|
87
|
-
|
|
88
|
-
| Prop | Type | Default | Description |
|
|
89
|
-
| ------------------------ | ------------------------ | ------------------------- | -------------------------------------------------------------------- |
|
|
90
|
-
| `searchDisabled` | `boolean` | `false` | If true, the search bar is completely removed. |
|
|
91
|
-
| `searchPlaceholder` | `string` | `"Search"` | Placeholder text for the search input. |
|
|
92
|
-
| `searchClearButtonLabel` | `string` | `"Clear"` | Aria label for the search clear button. |
|
|
93
|
-
| `categories` | `CategoryConfig[]` | _(All)_ | Array of category objects to customize order or visibility. |
|
|
94
|
-
| `suggestedEmojisMode` | `SuggestionMode` | `SuggestionMode.FREQUENT` | Logic for "Suggested" category. Options: `'recent'`, `'frequent'`. |
|
|
95
|
-
| `defaultSkinTone` | `SkinTones` | `SkinTones.NEUTRAL` | The initial skin tone. |
|
|
96
|
-
| `skinTonesDisabled` | `boolean` | `false` | If true, users cannot change the skin tone. |
|
|
97
|
-
| `skinTonePickerLocation` | `SkinTonePickerLocation` | `SEARCH` | Location of the skin tone trigger. Options: `'SEARCH'`, `'PREVIEW'`. |
|
|
98
|
-
|
|
99
|
-
### 🦄 Customization & Advanced
|
|
100
|
-
|
|
101
|
-
| Prop | Type | Default | Description |
|
|
102
|
-
| --------------- | ------------------------------------------------ | ----------------------- | ------------------------------------------------------------------------ |
|
|
103
|
-
| `customEmojis` | `CustomEmoji[]` | `[]` | Array of custom image-based emojis to inject. |
|
|
104
|
-
| `hiddenEmojis` | `string[]` | `[]` | Array of unified IDs (e.g., `'1f921'`) to hide from the picker. |
|
|
105
|
-
| `previewConfig` | `PreviewConfig` | `{ showPreview: true }` | Configuration for the bottom preview bar. |
|
|
106
|
-
| `getEmojiUrl` | `(unified: string, style: EmojiStyle) => string` | - | Function to override the default CDN URL for emoji images. |
|
|
107
|
-
| `categoryIcons` | `CategoryIcons` | `{}` | Map `Categories` enum values to custom React nodes for navigation icons. |
|
|
108
|
-
| `nonce` | `string` | `undefined` | Content Security Policy (CSP) nonce for the inline style tag. |
|
|
109
|
-
|
|
110
|
-
### ❤️ Reactions Picker Mode
|
|
111
|
-
|
|
112
|
-
| Prop | Type | Default | Description |
|
|
113
|
-
| ---------------------- | ---------- | --------------- | ------------------------------------------------------------------------ |
|
|
114
|
-
| `reactionsDefaultOpen` | `boolean` | `false` | If true, mounts in "Reactions" mode (single row) instead of full picker. |
|
|
115
|
-
| `reactions` | `string[]` | _(Default Set)_ | Array of unified IDs to display in the reactions bar. |
|
|
116
|
-
| `allowExpandReactions` | `boolean` | `true` | If true, shows a `+` button to switch from reactions to full picker. |
|
|
117
|
-
|
|
118
|
-
---
|
|
119
|
-
|
|
120
|
-
## 🛠️ Detailed Configuration
|
|
121
|
-
|
|
122
|
-
### CSS Variables
|
|
123
|
-
|
|
124
|
-
Override default variables by targeting `.EmojiPickerReact` or `aside.EmojiPickerReact`.
|
|
125
|
-
|
|
126
|
-
### CSS Variables
|
|
127
|
-
|
|
128
|
-
You can customize the picker by overriding CSS variables.
|
|
129
|
-
|
|
130
|
-
**[🎨 View Full List of CSS Variables](CSS_VARIABLES.md)**
|
|
131
|
-
|
|
132
|
-
### Custom Emojis Data Structure
|
|
133
|
-
|
|
134
|
-
When passing `customEmojis`, use this format:
|
|
135
|
-
|
|
136
|
-
```ts
|
|
137
|
-
{
|
|
138
|
-
id: string; // Unique ID
|
|
139
|
-
names: string[]; // Search keywords
|
|
140
|
-
imgUrl: string; // Image source
|
|
141
|
-
}
|
|
142
|
-
|
|
143
|
-
```
|
|
144
|
-
|
|
145
|
-
### Content Security Policy (CSP)
|
|
42
|
+
`onEmojiClick` receives an `EmojiClickData` object (unified code, names, image URL, active skin tone) and the underlying mouse event.
|
|
146
43
|
|
|
147
|
-
|
|
44
|
+
## Configuration
|
|
148
45
|
|
|
149
46
|
```jsx
|
|
150
|
-
<EmojiPicker nonce="your-nonce-value" />
|
|
151
|
-
```
|
|
152
|
-
|
|
153
|
-
### Preview Config
|
|
154
|
-
|
|
155
|
-
Control the footer preview area using `previewConfig`:
|
|
156
|
-
|
|
157
|
-
```ts
|
|
158
|
-
{
|
|
159
|
-
defaultEmoji: string; // Default: "1f60a"
|
|
160
|
-
defaultCaption: string; // Default: "What's your mood?"
|
|
161
|
-
showPreview: boolean; // Default: true
|
|
162
|
-
}
|
|
163
|
-
```
|
|
164
|
-
|
|
165
|
-
### Custom Category Icons
|
|
166
|
-
|
|
167
|
-
You can customize the navigation icons using one of two methods.
|
|
168
|
-
|
|
169
|
-
**Method 1: The `categoryIcons` prop**
|
|
170
|
-
|
|
171
|
-
Map `Categories` enum values to valid React nodes:
|
|
172
|
-
|
|
173
|
-
```tsx
|
|
174
|
-
import EmojiPicker, { Categories } from 'emoji-picker-react';
|
|
175
|
-
|
|
176
47
|
<EmojiPicker
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
}
|
|
181
|
-
|
|
48
|
+
theme="dark"
|
|
49
|
+
emojiStyle="native"
|
|
50
|
+
width={320}
|
|
51
|
+
height={400}
|
|
52
|
+
previewConfig={{ showPreview: false }}
|
|
53
|
+
/>
|
|
182
54
|
```
|
|
183
55
|
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
Define the icon directly within the category configuration object:
|
|
56
|
+
See [PROPS.md](PROPS.md) for the complete props reference.
|
|
187
57
|
|
|
188
|
-
|
|
189
|
-
import EmojiPicker, { Categories } from 'emoji-picker-react';
|
|
58
|
+
## Styling
|
|
190
59
|
|
|
191
|
-
|
|
192
|
-
categories={[
|
|
193
|
-
{
|
|
194
|
-
category: Categories.SUGGESTED,
|
|
195
|
-
name: 'Recently Used',
|
|
196
|
-
icon: <img src="recent.png" alt="Recent" />,
|
|
197
|
-
},
|
|
198
|
-
{
|
|
199
|
-
category: Categories.SMILEYS_PEOPLE,
|
|
200
|
-
name: 'Smileys & People',
|
|
201
|
-
icon: <MyCustomFaceIcon />,
|
|
202
|
-
},
|
|
203
|
-
]}
|
|
204
|
-
/>;
|
|
205
|
-
```
|
|
60
|
+
No stylesheet import needed. All styles are scoped via [Flairup](https://github.com/ealush/flairup) — generated class names are hashed, so the picker's CSS won't leak into or clash with your app's styles.
|
|
206
61
|
|
|
207
|
-
|
|
62
|
+
Restyle the picker by overriding [CSS variables](CSS_VARIABLES.md) on `.EmojiPickerReact`:
|
|
208
63
|
|
|
209
|
-
|
|
64
|
+
```css
|
|
65
|
+
.EmojiPickerReact {
|
|
66
|
+
--epr-emoji-size: 32px;
|
|
67
|
+
}
|
|
68
|
+
```
|
|
210
69
|
|
|
211
|
-
##
|
|
70
|
+
## Internationalization
|
|
212
71
|
|
|
213
|
-
|
|
72
|
+
Pass imported locale data via the `emojiData` prop:
|
|
214
73
|
|
|
215
|
-
```
|
|
74
|
+
```jsx
|
|
216
75
|
import EmojiPicker from 'emoji-picker-react';
|
|
217
76
|
import es from 'emoji-picker-react/dist/data/emojis-es'; // Spanish
|
|
218
77
|
|
|
@@ -221,58 +80,27 @@ function App() {
|
|
|
221
80
|
}
|
|
222
81
|
```
|
|
223
82
|
|
|
224
|
-
|
|
225
|
-
|
|
226
|
-
|
|
227
|
-
|
|
228
|
-
|
|
229
|
-
|
|
230
|
-
|
|
231
|
-
|
|
232
|
-
|
|
233
|
-
- `emojis-es` (Spanish 🇪🇸)
|
|
234
|
-
- `emojis-et` (Estonian 🇪🇪)
|
|
235
|
-
- `emojis-fi` (Finnish 🇫🇮)
|
|
236
|
-
- `emojis-fr` (French 🇫🇷)
|
|
237
|
-
- `emojis-hi` (Hindi 🇮🇳)
|
|
238
|
-
- `emojis-hu` (Hungarian 🇭🇺)
|
|
239
|
-
- `emojis-it` (Italian 🇮🇹)
|
|
240
|
-
- `emojis-ja` (Japanese 🇯🇵)
|
|
241
|
-
- `emojis-ko` (Korean 🇰🇷)
|
|
242
|
-
- `emojis-lt` (Lithuanian 🇱🇹)
|
|
243
|
-
- `emojis-ms` (Malay 🇲🇾)
|
|
244
|
-
- `emojis-nb` (Norwegian Bokmål 🇳🇴)
|
|
245
|
-
- `emojis-nl` (Dutch 🇳🇱)
|
|
246
|
-
- `emojis-pl` (Polish 🇵🇱)
|
|
247
|
-
- `emojis-pt` (Portuguese 🇵🇹)
|
|
248
|
-
- `emojis-ru` (Russian 🇷🇺)
|
|
249
|
-
- `emojis-sv` (Swedish 🇸🇪)
|
|
250
|
-
- `emojis-th` (Thai 🇹🇭)
|
|
251
|
-
- `emojis-uk` (Ukrainian 🇺🇦)
|
|
252
|
-
- `emojis-zh-hant` (Traditional Chinese 🇹🇼)
|
|
253
|
-
- `emojis-zh` (Simplified Chinese 🇨🇳)
|
|
254
|
-
|
|
255
|
-
</details>
|
|
256
|
-
|
|
257
|
-
---
|
|
258
|
-
|
|
259
|
-
## ⚠️ Troubleshooting
|
|
260
|
-
|
|
261
|
-
### Server-Side Rendering (Next.js / Remix)
|
|
262
|
-
|
|
263
|
-
This package relies on the `window` object and must be rendered on the client.
|
|
264
|
-
|
|
265
|
-
**Next.js Example:**
|
|
83
|
+
See [INTERNATIONALIZATION.md](INTERNATIONALIZATION.md) for the supported languages.
|
|
84
|
+
|
|
85
|
+
## Customization
|
|
86
|
+
|
|
87
|
+
Custom emojis, custom category icons, preview configuration, and CSP nonces are covered in [CUSTOMIZATION.md](CUSTOMIZATION.md).
|
|
88
|
+
|
|
89
|
+
## Server-Side Rendering
|
|
90
|
+
|
|
91
|
+
The picker renders on the server, with styles inlined into the server HTML — no setup needed. Since the picker is usually opened on demand rather than shown immediately, lazy-loading it is still recommended to keep the initial bundle small:
|
|
266
92
|
|
|
267
93
|
```javascript
|
|
268
94
|
import dynamic from 'next/dynamic';
|
|
269
95
|
|
|
270
|
-
const Picker = dynamic(() => import('emoji-picker-react')
|
|
96
|
+
const Picker = dynamic(() => import('emoji-picker-react'));
|
|
271
97
|
```
|
|
272
98
|
|
|
273
|
-
|
|
99
|
+
## Troubleshooting
|
|
274
100
|
|
|
275
|
-
|
|
101
|
+
### `global is not defined` (Vite)
|
|
102
|
+
|
|
103
|
+
Add this to your HTML:
|
|
276
104
|
|
|
277
105
|
```html
|
|
278
106
|
<script>
|
|
@@ -280,17 +108,12 @@ If you encounter `global is not defined`, add this to your HTML:
|
|
|
280
108
|
</script>
|
|
281
109
|
```
|
|
282
110
|
|
|
283
|
-
---
|
|
284
|
-
|
|
285
111
|
## More from the maintainer
|
|
286
112
|
|
|
287
113
|
Building complex forms? Check out [**Vest**](https://vestjs.dev) — a validation framework for stateful, async, and dependent validation.
|
|
288
114
|
|
|
289
|
-
|
|
290
|
-
|
|
291
|
-
## 🤝 Contributing
|
|
115
|
+
## Contributing
|
|
292
116
|
|
|
293
|
-
|
|
117
|
+
Contributions are welcome — see the [Contributing Guide](https://github.com/ealush/emoji-picker-react/blob/master/CONTRIBUTING.md).
|
|
294
118
|
|
|
295
|
-
**Shout Outs:**
|
|
296
119
|
Design inspiration by [Pavel Bolo](https://pavelbolo.com).
|
|
@@ -1,10 +1,16 @@
|
|
|
1
1
|
import { Styles } from 'flairup';
|
|
2
2
|
import * as React from 'react';
|
|
3
3
|
export declare const stylesheet: {
|
|
4
|
-
create: <K extends string>(styles: Partial<{ [k in K]: Partial<
|
|
4
|
+
create: <K extends string>(styles: Partial<{ [k in K]: Partial<{
|
|
5
5
|
'.'?: string | string[] | undefined;
|
|
6
6
|
'--'?: any;
|
|
7
|
-
}
|
|
7
|
+
}> | Partial<Partial<CSSStyleDeclaration> & Partial<{
|
|
8
|
+
'.'?: string | string[] | undefined;
|
|
9
|
+
'--'?: any;
|
|
10
|
+
}>>; }> | Partial<{}>) => Record<Exclude<Exclude<K, any>, any>, Set<string>> & Record<never, Set<string>>;
|
|
11
|
+
keyframes: <KF extends string>(keyframesInput: Record<KF, {
|
|
12
|
+
[stage: string]: Partial<CSSStyleDeclaration>;
|
|
13
|
+
}>) => Record<KF, string>;
|
|
8
14
|
getStyle: () => string;
|
|
9
15
|
isApplied: () => boolean;
|
|
10
16
|
};
|
|
@@ -15,11 +21,17 @@ export declare const PickerStyleTag: React.NamedExoticComponent<{
|
|
|
15
21
|
export declare const commonInteractionStyles: Record<never, Set<string>>;
|
|
16
22
|
export declare function darkMode(key: string, value: Styles): {
|
|
17
23
|
'.epr-dark-theme': {
|
|
18
|
-
[x: string]: Partial<Partial<CSSStyleDeclaration
|
|
24
|
+
[x: string]: Partial<Partial<CSSStyleDeclaration> & Partial<{
|
|
25
|
+
'.'?: string | string[] | undefined;
|
|
26
|
+
'--'?: any;
|
|
27
|
+
}>>;
|
|
19
28
|
};
|
|
20
29
|
'.epr-auto-theme': {
|
|
21
30
|
[x: string]: {
|
|
22
|
-
'@media (prefers-color-scheme: dark)': Partial<Partial<CSSStyleDeclaration
|
|
31
|
+
'@media (prefers-color-scheme: dark)': Partial<Partial<CSSStyleDeclaration> & Partial<{
|
|
32
|
+
'.'?: string | string[] | undefined;
|
|
33
|
+
'--'?: any;
|
|
34
|
+
}>>;
|
|
23
35
|
};
|
|
24
36
|
};
|
|
25
37
|
};
|
|
@@ -521,11 +521,10 @@ function useDebouncedState(initialValue, delay) {
|
|
|
521
521
|
var timer = React.useRef(null);
|
|
522
522
|
function debouncedSetState(value) {
|
|
523
523
|
return new Promise(function (resolve) {
|
|
524
|
-
var _window;
|
|
525
524
|
if (timer.current) {
|
|
526
525
|
clearTimeout(timer.current);
|
|
527
526
|
}
|
|
528
|
-
timer.current =
|
|
527
|
+
timer.current = setTimeout(function () {
|
|
529
528
|
setState(value);
|
|
530
529
|
resolve(value);
|
|
531
530
|
}, delay);
|
|
@@ -26745,14 +26744,24 @@ var defaultEmojiData = {
|
|
|
26745
26744
|
emojis: emojis
|
|
26746
26745
|
};
|
|
26747
26746
|
|
|
26747
|
+
function useIsMounted() {
|
|
26748
|
+
var _React$useState = React.useState(false),
|
|
26749
|
+
isMounted = _React$useState[0],
|
|
26750
|
+
setIsMounted = _React$useState[1];
|
|
26751
|
+
React.useEffect(function () {
|
|
26752
|
+
setIsMounted(true);
|
|
26753
|
+
}, []);
|
|
26754
|
+
return isMounted;
|
|
26755
|
+
}
|
|
26756
|
+
|
|
26748
26757
|
var SUGGESTED_LS_KEY = 'epr_suggested';
|
|
26749
26758
|
function getSuggested(mode) {
|
|
26750
26759
|
try {
|
|
26751
|
-
var _window
|
|
26752
|
-
if (
|
|
26760
|
+
var _window$localStorage$;
|
|
26761
|
+
if (typeof window === 'undefined' || !window.localStorage) {
|
|
26753
26762
|
return [];
|
|
26754
26763
|
}
|
|
26755
|
-
var recent = JSON.parse((_window$localStorage$ =
|
|
26764
|
+
var recent = JSON.parse((_window$localStorage$ = window.localStorage.getItem(SUGGESTED_LS_KEY)) != null ? _window$localStorage$ : '[]');
|
|
26756
26765
|
if (mode === exports.SuggestionMode.FREQUENT) {
|
|
26757
26766
|
return recent.sort(function (a, b) {
|
|
26758
26767
|
return b.count - a.count;
|
|
@@ -26787,8 +26796,10 @@ function setSuggested(emoji, skinTone) {
|
|
|
26787
26796
|
existing.count++;
|
|
26788
26797
|
nextList.length = Math.min(nextList.length, 14);
|
|
26789
26798
|
try {
|
|
26790
|
-
|
|
26791
|
-
|
|
26799
|
+
if (typeof window === 'undefined') {
|
|
26800
|
+
return;
|
|
26801
|
+
}
|
|
26802
|
+
window.localStorage.setItem(SUGGESTED_LS_KEY, JSON.stringify(nextList));
|
|
26792
26803
|
// Prevents the change from being seen immediately.
|
|
26793
26804
|
} catch (_unused2) {
|
|
26794
26805
|
// ignore
|
|
@@ -26827,15 +26838,21 @@ function useGetEmojisByCategory() {
|
|
|
26827
26838
|
var suggestedEmojisModeConfig = useSuggestedEmojisModeConfig();
|
|
26828
26839
|
var _useUpdateSuggested = useUpdateSuggested(),
|
|
26829
26840
|
suggestedUpdated = _useUpdateSuggested[0];
|
|
26841
|
+
// Suggestions come from localStorage, which doesn't exist during SSR.
|
|
26842
|
+
// Read them only after mount so the first client render matches the server.
|
|
26843
|
+
var isMounted = useIsMounted();
|
|
26830
26844
|
var suggested = React__default.useMemo(function () {
|
|
26831
26845
|
var _getSuggested;
|
|
26846
|
+
if (!isMounted) {
|
|
26847
|
+
return [];
|
|
26848
|
+
}
|
|
26832
26849
|
var suggested = (_getSuggested = getSuggested(suggestedEmojisModeConfig)) != null ? _getSuggested : [];
|
|
26833
26850
|
return suggested.map(function (s) {
|
|
26834
26851
|
return emojiByUnified(s.unified);
|
|
26835
26852
|
}).filter(Boolean);
|
|
26836
26853
|
},
|
|
26837
26854
|
// eslint-disable-next-line react-hooks/exhaustive-deps
|
|
26838
|
-
[suggestedUpdated, suggestedEmojisModeConfig]);
|
|
26855
|
+
[isMounted, suggestedUpdated, suggestedEmojisModeConfig]);
|
|
26839
26856
|
return function getEmojisByCategory(category) {
|
|
26840
26857
|
var _emojis$emojis$catego;
|
|
26841
26858
|
if (category === exports.Categories.SUGGESTED) {
|
|
@@ -26958,8 +26975,14 @@ function useGetEmojisByCategory$1() {
|
|
|
26958
26975
|
var suggestedEmojisModeConfig = useSuggestedEmojisModeConfig();
|
|
26959
26976
|
var _useUpdateSuggested = useUpdateSuggested(),
|
|
26960
26977
|
suggestedUpdated = _useUpdateSuggested[0];
|
|
26978
|
+
// Suggestions come from localStorage, which doesn't exist during SSR.
|
|
26979
|
+
// Read them only after mount so the first client render matches the server.
|
|
26980
|
+
var isMounted = useIsMounted();
|
|
26961
26981
|
var suggested = React__default.useMemo(function () {
|
|
26962
26982
|
var _getSuggested;
|
|
26983
|
+
if (!isMounted) {
|
|
26984
|
+
return [];
|
|
26985
|
+
}
|
|
26963
26986
|
var suggested = (_getSuggested = getSuggested(suggestedEmojisModeConfig)) != null ? _getSuggested : [];
|
|
26964
26987
|
return suggested.map(function (s) {
|
|
26965
26988
|
var _extends2;
|
|
@@ -26968,7 +26991,7 @@ function useGetEmojisByCategory$1() {
|
|
|
26968
26991
|
return _extends({}, emoji, (_extends2 = {}, _extends2[EmojiProperties.unified] = s.unified, _extends2));
|
|
26969
26992
|
}).filter(Boolean);
|
|
26970
26993
|
// eslint-disable-next-line react-hooks/exhaustive-deps
|
|
26971
|
-
}, [suggestedUpdated, suggestedEmojisModeConfig, emojiByUnified]);
|
|
26994
|
+
}, [isMounted, suggestedUpdated, suggestedEmojisModeConfig, emojiByUnified]);
|
|
26972
26995
|
return function getEmojisByCategory(category) {
|
|
26973
26996
|
var _emojiData$emojis$cat, _emojiData$emojis;
|
|
26974
26997
|
if (category === exports.Categories.SUGGESTED) {
|
|
@@ -28800,7 +28823,6 @@ function useMouseDownHandlers(ContainerRef, mouseEventSource) {
|
|
|
28800
28823
|
onEmojiClick(emojiClickOutput(emoji, skinToneToUse, activeEmojiStyle, getEmojiUrl), event);
|
|
28801
28824
|
}, [activeSkinTone, closeAllOpenToggles, disallowClickRef, emojiByUnified, onEmojiClick, updateSuggested, getEmojiUrl, activeEmojiStyle]);
|
|
28802
28825
|
var onMouseDown = React.useCallback(function onMouseDown(event) {
|
|
28803
|
-
var _window;
|
|
28804
28826
|
if (mouseDownTimerRef.current) {
|
|
28805
28827
|
clearTimeout(mouseDownTimerRef.current);
|
|
28806
28828
|
}
|
|
@@ -28809,7 +28831,7 @@ function useMouseDownHandlers(ContainerRef, mouseEventSource) {
|
|
|
28809
28831
|
if (!emoji || !emojiHasVariations$1(emoji)) {
|
|
28810
28832
|
return;
|
|
28811
28833
|
}
|
|
28812
|
-
mouseDownTimerRef.current =
|
|
28834
|
+
mouseDownTimerRef.current = setTimeout(function () {
|
|
28813
28835
|
disallowClickRef.current = true;
|
|
28814
28836
|
mouseDownTimerRef.current = undefined;
|
|
28815
28837
|
closeAllOpenToggles();
|
|
@@ -29547,6 +29569,10 @@ var styles$7 = /*#__PURE__*/stylesheet.create({
|
|
|
29547
29569
|
}
|
|
29548
29570
|
});
|
|
29549
29571
|
|
|
29572
|
+
// `useLayoutEffect` warns during SSR since it never runs on the server.
|
|
29573
|
+
// Fall back to `useEffect` there: measurement only matters on the client.
|
|
29574
|
+
var useIsomorphicLayoutEffect = typeof window !== 'undefined' ? React.useLayoutEffect : React.useEffect;
|
|
29575
|
+
|
|
29550
29576
|
function MeasureEmoji() {
|
|
29551
29577
|
var categories = useCategoriesConfig();
|
|
29552
29578
|
var getEmojisByCategory = useGetEmojisByCategory();
|
|
@@ -29559,7 +29585,7 @@ function MeasureEmoji() {
|
|
|
29559
29585
|
emojiSize = _useEmojiSizeState[0],
|
|
29560
29586
|
setEmojiSize = _useEmojiSizeState[1];
|
|
29561
29587
|
var ref = React.useRef(null);
|
|
29562
|
-
|
|
29588
|
+
useIsomorphicLayoutEffect(function () {
|
|
29563
29589
|
if (ref.current) {
|
|
29564
29590
|
setEmojiSize(ref.current.clientHeight);
|
|
29565
29591
|
}
|