@devoxin/emoji-picker 1.0.0

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.
@@ -0,0 +1,618 @@
1
+ import * as react1 from "react";
2
+ import { ComponentProps, ComponentType, ReactNode } from "react";
3
+ import * as react_jsx_runtime0 from "react/jsx-runtime";
4
+
5
+ //#region ../../node_modules/.bun/emojibase@16.0.0/node_modules/emojibase/lib/types.d.ts
6
+ type SkinToneKey = 'dark' | 'light' | 'medium-dark' | 'medium-light' | 'medium';
7
+ type Locale$1 = 'bn' | 'da' | 'de' | 'en-gb' | 'en' | 'es-mx' | 'es' | 'et' | 'fi' | 'fr' | 'hi' | 'hu' | 'it' | 'ja' | 'ko' | 'lt' | 'ms' | 'nb' | 'nl' | 'pl' | 'pt' | 'ru' | 'sv' | 'th' | 'uk' | 'vi' | 'zh-hant' | 'zh';
8
+ //#endregion
9
+ //#region src/types.d.ts
10
+ type Resolve<T> = T extends ((...args: unknown[]) => unknown) ? T : { [K in keyof T]: T[K] };
11
+ type Locale = Resolve<Locale$1>;
12
+ type SkinTone = Resolve<"none" | SkinToneKey>;
13
+ type SkinToneVariation = {
14
+ skinTone: SkinTone;
15
+ emoji: string;
16
+ };
17
+ type Emoji = Resolve<EmojiPickerEmoji>;
18
+ type Category = Resolve<EmojiPickerCategory>;
19
+ type CustomCategory = {
20
+ /**
21
+ * The unique identifier of the category (used to associate emojis with categories).
22
+ */
23
+ id?: number;
24
+ /**
25
+ * The index of the category (determines display order).
26
+ */
27
+ index: number;
28
+ /**
29
+ * The name/label of the category.
30
+ */
31
+ label: string;
32
+ /**
33
+ * The icon for the category (emoji character or URL).
34
+ */
35
+ icon?: string;
36
+ /**
37
+ * Whether the icon is a custom image (URL) rather than an emoji character.
38
+ */
39
+ isCustomIcon?: boolean;
40
+ };
41
+ type EmojiPickerEmoji = {
42
+ emoji: string;
43
+ label: string;
44
+ isCustom?: boolean;
45
+ tags?: string[];
46
+ category?: number;
47
+ };
48
+ type EmojiPickerCategory = {
49
+ label: string;
50
+ icon?: string;
51
+ isCustomIcon?: boolean;
52
+ };
53
+ type EmojiPickerListComponents = {
54
+ /**
55
+ * The component used to render a sticky category header in the list.
56
+ *
57
+ * @details
58
+ * All category headers should be of the same size.
59
+ */
60
+ CategoryHeader: ComponentType<EmojiPickerListCategoryHeaderProps>;
61
+ /**
62
+ * The component used to render a row of emojis in the list.
63
+ *
64
+ * @details
65
+ * All rows should be of the same size.
66
+ */
67
+ Row: ComponentType<EmojiPickerListRowProps>;
68
+ /**
69
+ * The component used to render an emoji button in the list.
70
+ *
71
+ * @details
72
+ * All emojis should be of the same size.
73
+ */
74
+ Emoji: ComponentType<EmojiPickerListEmojiProps>;
75
+ };
76
+ type EmojiPickerListRowProps = ComponentProps<"div">;
77
+ interface EmojiPickerListCategoryHeaderProps extends Omit<ComponentProps<"div">, "children"> {
78
+ /**
79
+ * The category for this sticky header.
80
+ */
81
+ category: Category;
82
+ }
83
+ interface EmojiPickerListEmojiProps extends Omit<ComponentProps<"button">, "children"> {
84
+ /**
85
+ * The emoji for this button, its label, and whether the emoji is currently
86
+ * active (either hovered or selected via keyboard navigation).
87
+ */
88
+ emoji: Resolve<Emoji & {
89
+ isActive: boolean;
90
+ }>;
91
+ }
92
+ interface EmojiPickerListProps extends ComponentProps<"div"> {
93
+ /**
94
+ * The inner components of the list.
95
+ */
96
+ components?: Partial<EmojiPickerListComponents>;
97
+ }
98
+ interface EmojiPickerRootProps extends ComponentProps<"div"> {
99
+ /**
100
+ * A callback invoked when an emoji is selected.
101
+ */
102
+ onEmojiSelect?: (emoji: Emoji) => void;
103
+ /**
104
+ * The locale of the emoji picker.
105
+ *
106
+ * @default "en"
107
+ */
108
+ locale?: Locale;
109
+ /**
110
+ * The skin tone of the emoji picker.
111
+ *
112
+ * @default "none"
113
+ */
114
+ skinTone?: SkinTone;
115
+ /**
116
+ * The number of columns in the list.
117
+ *
118
+ * @default 10
119
+ */
120
+ columns?: number;
121
+ /**
122
+ * Which {@link https://emojipedia.org/emoji-versions | Emoji version} to use,
123
+ * to manually control which emojis are visible regardless of the current
124
+ * browser's supported Emoji versions.
125
+ *
126
+ * @default The most recent version supported by the current browser
127
+ */
128
+ emojiVersion?: number;
129
+ /**
130
+ * The base URL of where the {@link https://emojibase.dev/docs/datasets/ | Emojibase data}
131
+ * should be fetched from, used as follows: `${emojibaseUrl}/${locale}/${file}.json`.
132
+ * (e.g. `${emojibaseUrl}/en/data.json`).
133
+ *
134
+ * The URL can be set to another CDN hosting the {@link https://www.npmjs.com/package/emojibase-data | `emojibase-data`}
135
+ * package and its raw JSON files, or to a self-hosted location. When self-hosting
136
+ * with a single locale (e.g. `en`), only that locale's directory needs to be hosted
137
+ * instead of the entire package.
138
+ *
139
+ * @example "https://unpkg.com/emojibase-data"
140
+ *
141
+ * @example "https://example.com/self-hosted-emojibase-data"
142
+ *
143
+ * @default "https://cdn.jsdelivr.net/npm/emojibase-data"
144
+ */
145
+ emojibaseUrl?: string;
146
+ /**
147
+ * Custom emojis to include in the picker.
148
+ */
149
+ customEmojis?: Emoji[];
150
+ /**
151
+ * Custom categories to include in the picker.
152
+ */
153
+ customCategories?: CustomCategory[];
154
+ /**
155
+ * Whether the category headers should be sticky.
156
+ *
157
+ * @default true
158
+ */
159
+ sticky?: boolean;
160
+ }
161
+ type EmojiPickerViewportProps = ComponentProps<"div">;
162
+ type EmojiPickerSearchProps = ComponentProps<"input">;
163
+ interface EmojiPickerSkinToneSelectorProps extends Omit<ComponentProps<"button">, "children"> {
164
+ /**
165
+ * The emoji to use as visual for the skin tone variations.
166
+ *
167
+ * @default "βœ‹"
168
+ */
169
+ emoji?: string;
170
+ }
171
+ type EmojiPickerLoadingProps = ComponentProps<"span">;
172
+ type EmojiPickerEmptyRenderProps = {
173
+ /**
174
+ * The current search value.
175
+ */
176
+ search: string;
177
+ };
178
+ interface EmojiPickerEmptyProps extends Omit<ComponentProps<"span">, "children"> {
179
+ /**
180
+ * The content to render when no emoji is found for the current search, or
181
+ * a render callback which receives the current search value.
182
+ */
183
+ children?: ReactNode | ((props: EmojiPickerEmptyRenderProps) => ReactNode);
184
+ }
185
+ type EmojiPickerActiveEmojiRenderProps = {
186
+ /**
187
+ * The currently active emoji (either hovered or selected
188
+ * via keyboard navigation).
189
+ */
190
+ emoji?: Emoji;
191
+ };
192
+ type EmojiPickerActiveEmojiProps = {
193
+ /**
194
+ * A render callback which receives the currently active emoji (either hovered or selected
195
+ * via keyboard navigation).
196
+ */
197
+ children: (props: EmojiPickerActiveEmojiRenderProps) => ReactNode;
198
+ };
199
+ type EmojiPickerCategoryNavItem = {
200
+ /**
201
+ * The category to navigate to.
202
+ */
203
+ category: Category;
204
+ /**
205
+ * Whether this category is currently active in the viewport.
206
+ */
207
+ isActive: boolean;
208
+ /**
209
+ * Scrolls the list to the corresponding category.
210
+ */
211
+ scrollTo: () => void;
212
+ };
213
+ type EmojiPickerCategoryNavRenderProps = {
214
+ /**
215
+ * The available categories and their scroll handlers.
216
+ */
217
+ categories: EmojiPickerCategoryNavItem[];
218
+ };
219
+ type EmojiPickerCategoryNavProps = {
220
+ /**
221
+ * A render callback which receives the available categories and their scroll handlers.
222
+ */
223
+ children: (props: EmojiPickerCategoryNavRenderProps) => ReactNode;
224
+ };
225
+ type EmojiPickerSkinToneRenderProps = {
226
+ /**
227
+ * The current skin tone.
228
+ */
229
+ skinTone: SkinTone;
230
+ /**
231
+ * A function to change the current skin tone.
232
+ */
233
+ setSkinTone: (skinTone: SkinTone) => void;
234
+ /**
235
+ * The skin tone variations of the specified emoji.
236
+ */
237
+ skinToneVariations: SkinToneVariation[];
238
+ };
239
+ type EmojiPickerSkinToneProps = {
240
+ /**
241
+ * The emoji to use as visual for the skin tone variations.
242
+ *
243
+ * @default "βœ‹"
244
+ */
245
+ emoji?: string;
246
+ /**
247
+ * A render callback which receives the current skin tone and a function
248
+ * to change it, as well as the skin tone variations of the specified emoji.
249
+ */
250
+ children: (props: EmojiPickerSkinToneRenderProps) => ReactNode;
251
+ };
252
+ //#endregion
253
+ //#region src/components/emoji-picker/active-emoji.d.ts
254
+ /**
255
+ * Exposes the currently active emoji (either hovered or selected
256
+ * via keyboard navigation) via a render callback.
257
+ *
258
+ * @example
259
+ * ```tsx
260
+ * <EmojiPicker.ActiveEmoji>
261
+ * {({ emoji }) => <span>{emoji}</span>}
262
+ * </EmojiPicker.ActiveEmoji>
263
+ * ```
264
+ *
265
+ * It can be used to build a preview area next to the list.
266
+ *
267
+ * @example
268
+ * ```tsx
269
+ * <EmojiPicker.ActiveEmoji>
270
+ * {({ emoji }) => (
271
+ * <div>
272
+ * {emoji ? (
273
+ * <span>{emoji.emoji} {emoji.label}</span>
274
+ * ) : (
275
+ * <span>Select an emoji…</span>
276
+ * )}
277
+ * </div>
278
+ * )}
279
+ * </EmojiPicker.ActiveEmoji>
280
+ * ```
281
+ *
282
+ * @see
283
+ * If you prefer to use a hook rather than a component,
284
+ * {@link useActiveEmoji} is also available.
285
+ */
286
+ declare function EmojiPickerActiveEmoji({
287
+ children
288
+ }: EmojiPickerActiveEmojiProps): react1.ReactNode;
289
+ //#endregion
290
+ //#region src/components/emoji-picker/category-nav.d.ts
291
+ /**
292
+ * Exposes the emoji categories and provides scroll handlers to navigate
293
+ * to each category via a render callback.
294
+ *
295
+ * @example
296
+ * ```tsx
297
+ * <EmojiPicker.CategoryNav>
298
+ * {({ categories }) => (
299
+ * <div>
300
+ * {categories.map(({ category, scrollTo }) => (
301
+ * <button key={category.label} onClick={scrollTo}>
302
+ * {category.label}
303
+ * </button>
304
+ * ))}
305
+ * </div>
306
+ * )}
307
+ * </EmojiPicker.CategoryNav>
308
+ * ```
309
+ *
310
+ * This component allows building custom category navigation that can scroll
311
+ * to the corresponding section in the emoji list.
312
+ */
313
+ declare function EmojiPickerCategoryNav({
314
+ children
315
+ }: EmojiPickerCategoryNavProps): react1.ReactNode;
316
+ //#endregion
317
+ //#region src/components/emoji-picker/list.d.ts
318
+ /**
319
+ * The list of emojis.
320
+ *
321
+ * @example
322
+ * ```tsx
323
+ * <EmojiPicker.Root>
324
+ * <EmojiPicker.Search />
325
+ * <EmojiPicker.Viewport>
326
+ * <EmojiPicker.List />
327
+ * </EmojiPicker.Viewport>
328
+ * </EmojiPicker.Root>
329
+ * ```
330
+ *
331
+ * Inner components within the list can be customized via the `components` prop.
332
+ *
333
+ * @example
334
+ * ```tsx
335
+ * <EmojiPicker.List
336
+ * components={{
337
+ * CategoryHeader: ({ category, ...props }) => (
338
+ * <div {...props}>{category.label}</div>
339
+ * ),
340
+ * Emoji: ({ emoji, ...props }) => (
341
+ * <button {...props}>
342
+ * {emoji.emoji}
343
+ * </button>
344
+ * ),
345
+ * Row: ({ children, ...props }) => <div {...props}>{children}</div>,
346
+ * }}
347
+ * />
348
+ * ```
349
+ */
350
+ declare const EmojiPickerList: react1.ForwardRefExoticComponent<Omit<EmojiPickerListProps, "ref"> & react1.RefAttributes<HTMLDivElement>>;
351
+ //#endregion
352
+ //#region src/components/emoji-picker/status.d.ts
353
+ /**
354
+ * Only renders when the emoji data is loading.
355
+ *
356
+ * @example
357
+ * ```tsx
358
+ * <EmojiPicker.Root>
359
+ * <EmojiPicker.Search />
360
+ * <EmojiPicker.Viewport>
361
+ * <EmojiPicker.Loading>Loading…</EmojiPicker.Loading>
362
+ * <EmojiPicker.List />
363
+ * </EmojiPicker.Viewport>
364
+ * </EmojiPicker.Root>
365
+ * ```
366
+ */
367
+ declare function EmojiPickerLoading({
368
+ children,
369
+ ...props
370
+ }: EmojiPickerLoadingProps): react_jsx_runtime0.JSX.Element | null;
371
+ /**
372
+ * Only renders when no emoji is found for the current search. The content is
373
+ * rendered without any surrounding DOM element.
374
+ *
375
+ * @example
376
+ * ```tsx
377
+ * <EmojiPicker.Root>
378
+ * <EmojiPicker.Search />
379
+ * <EmojiPicker.Viewport>
380
+ * <EmojiPicker.Empty>No emoji found.</EmojiPicker.Empty>
381
+ * <EmojiPicker.List />
382
+ * </EmojiPicker.Viewport>
383
+ * </EmojiPicker.Root>
384
+ * ```
385
+ *
386
+ * It can also expose the current search via a render callback to build
387
+ * a more detailed empty state.
388
+ *
389
+ * @example
390
+ * ```tsx
391
+ * <EmojiPicker.Empty>
392
+ * {({ search }) => <>No emoji found for "{search}"</>}
393
+ * </EmojiPicker.Empty>
394
+ * ```
395
+ */
396
+ declare function EmojiPickerEmpty({
397
+ children,
398
+ ...props
399
+ }: EmojiPickerEmptyProps): react_jsx_runtime0.JSX.Element | null;
400
+ //#endregion
401
+ //#region src/components/emoji-picker/root.d.ts
402
+ /**
403
+ * Surrounds all the emoji picker parts.
404
+ *
405
+ * @example
406
+ * ```tsx
407
+ * <EmojiPicker.Root onEmojiSelect={({ emoji }) => console.log(emoji)}>
408
+ * <EmojiPicker.Search />
409
+ * <EmojiPicker.Viewport>
410
+ * <EmojiPicker.List />
411
+ * </EmojiPicker.Viewport>
412
+ * </EmojiPicker.Root>
413
+ * ```
414
+ *
415
+ * Options affecting the entire emoji picker are available on this
416
+ * component as props.
417
+ *
418
+ * @example
419
+ * ```tsx
420
+ * <EmojiPicker.Root locale="fr" columns={10} skinTone="medium">
421
+ * {\/* ... *\/}
422
+ * </EmojiPicker.Root>
423
+ * ```
424
+ */
425
+ declare const EmojiPickerRoot: react1.ForwardRefExoticComponent<Omit<EmojiPickerRootProps, "ref"> & react1.RefAttributes<HTMLDivElement>>;
426
+ //#endregion
427
+ //#region src/components/emoji-picker/search.d.ts
428
+ /**
429
+ * A search input to filter the list of emojis.
430
+ *
431
+ * @example
432
+ * ```tsx
433
+ * <EmojiPicker.Root>
434
+ * <EmojiPicker.Search />
435
+ * <EmojiPicker.Viewport>
436
+ * <EmojiPicker.List />
437
+ * </EmojiPicker.Viewport>
438
+ * </EmojiPicker.Root>
439
+ * ```
440
+ *
441
+ * It can be controlled or uncontrolled.
442
+ *
443
+ * @example
444
+ * ```tsx
445
+ * const [search, setSearch] = useState("");
446
+ *
447
+ * return (
448
+ * <EmojiPicker.Root>
449
+ * <EmojiPicker.Search
450
+ * value={search}
451
+ * onChange={(event) => setSearch(event.target.value)}
452
+ * />
453
+ * {\/* ... *\/}
454
+ * </EmojiPicker.Root>
455
+ * );
456
+ * ```
457
+ */
458
+ declare const EmojiPickerSearch: react1.ForwardRefExoticComponent<Omit<react1.DetailedHTMLProps<react1.InputHTMLAttributes<HTMLInputElement>, HTMLInputElement>, "ref"> & react1.RefAttributes<HTMLInputElement>>;
459
+ //#endregion
460
+ //#region src/components/emoji-picker/skin-tone.d.ts
461
+ /**
462
+ * A button to change the current skin tone by cycling through the
463
+ * available skin tones.
464
+ *
465
+ * @example
466
+ * ```tsx
467
+ * <EmojiPicker.SkinToneSelector />
468
+ * ```
469
+ *
470
+ * The emoji used as visual can be customized (by default, βœ‹).
471
+ *
472
+ * @example
473
+ * ```tsx
474
+ * <EmojiPicker.SkinToneSelector emoji="πŸ‘‹" />
475
+ * ```
476
+ *
477
+ * @see
478
+ * If you want to build a custom skin tone selector, you can use the
479
+ * {@link EmojiPickerSkinTone|`<EmojiPicker.SkinTone />`} component or
480
+ * {@link useSkinTone|`useSkinTone`} hook.
481
+ */
482
+ declare const EmojiPickerSkinToneSelector: react1.ForwardRefExoticComponent<Omit<EmojiPickerSkinToneSelectorProps, "ref"> & react1.RefAttributes<HTMLButtonElement>>;
483
+ /**
484
+ * Exposes the current skin tone and a function to change it via a render
485
+ * callback.
486
+ *
487
+ * @example
488
+ * ```tsx
489
+ * <EmojiPicker.SkinTone>
490
+ * {({ skinTone, setSkinTone }) => (
491
+ * <div>
492
+ * <span>{skinTone}</span>
493
+ * <button onClick={() => setSkinTone("none")}>Reset skin tone</button>
494
+ * </div>
495
+ * )}
496
+ * </EmojiPicker.SkinTone>
497
+ * ```
498
+ *
499
+ * It can be used to build a custom skin tone selector: pass an emoji
500
+ * you want to use as visual (by default, βœ‹) and it will return its skin tone
501
+ * variations.
502
+ *
503
+ * @example
504
+ * ```tsx
505
+ * const [skinTone, setSkinTone, skinToneVariations] = useSkinTone("πŸ‘‹");
506
+ *
507
+ * // (πŸ‘‹) (πŸ‘‹πŸ») (πŸ‘‹πŸΌ) (πŸ‘‹πŸ½) (πŸ‘‹πŸΎ) (πŸ‘‹πŸΏ)
508
+ * <EmojiPicker.SkinTone emoji="πŸ‘‹">
509
+ * {({ skinTone, setSkinTone, skinToneVariations }) => (
510
+ * skinToneVariations.map(({ skinTone, emoji }) => (
511
+ * <button key={skinTone} onClick={() => setSkinTone(skinTone)}>
512
+ * {emoji}
513
+ * </button>
514
+ * ))
515
+ * )}
516
+ * </EmojiPicker.SkinTone>
517
+ * ```
518
+ *
519
+ * @see
520
+ * If you prefer to use a hook rather than a component,
521
+ * {@link useSkinTone} is also available.
522
+ *
523
+ * @see
524
+ * An already-built skin tone selector is also available,
525
+ * {@link EmojiPicker.SkinToneSelector|`<EmojiPicker.SkinToneSelector />`}.
526
+ */
527
+ declare function EmojiPickerSkinTone({
528
+ children,
529
+ emoji
530
+ }: EmojiPickerSkinToneProps): react1.ReactNode;
531
+ //#endregion
532
+ //#region src/components/emoji-picker/viewport.d.ts
533
+ /**
534
+ * The scrolling container of the emoji picker.
535
+ *
536
+ * @example
537
+ * ```tsx
538
+ * <EmojiPicker.Root>
539
+ * <EmojiPicker.Search />
540
+ * <EmojiPicker.Viewport>
541
+ * <EmojiPicker.Loading>Loading…</EmojiPicker.Loading>
542
+ * <EmojiPicker.Empty>No emoji found.</EmojiPicker.Empty>
543
+ * <EmojiPicker.List />
544
+ * </EmojiPicker.Viewport>
545
+ * </EmojiPicker.Root>
546
+ * ```
547
+ */
548
+ declare const EmojiPickerViewport: react1.ForwardRefExoticComponent<Omit<react1.DetailedHTMLProps<react1.HTMLAttributes<HTMLDivElement>, HTMLDivElement>, "ref"> & react1.RefAttributes<HTMLDivElement>>;
549
+ declare namespace emoji_picker_d_exports {
550
+ export { EmojiPickerActiveEmoji as ActiveEmoji, EmojiPickerCategoryNav as CategoryNav, EmojiPickerEmpty as Empty, EmojiPickerList as List, EmojiPickerLoading as Loading, EmojiPickerRoot as Root, EmojiPickerSearch as Search, EmojiPickerSkinTone as SkinTone, EmojiPickerSkinToneSelector as SkinToneSelector, EmojiPickerViewport as Viewport };
551
+ }
552
+ //#endregion
553
+ //#region src/hooks.d.ts
554
+ /**
555
+ * Returns the currently active emoji (either hovered or selected
556
+ * via keyboard navigation).
557
+ *
558
+ * @example
559
+ * ```tsx
560
+ * const activeEmoji = useActiveEmoji();
561
+ * ```
562
+ *
563
+ * It can be used to build a preview area next to the list.
564
+ *
565
+ * @example
566
+ * ```tsx
567
+ * const activeEmoji = useActiveEmoji();
568
+ *
569
+ * <div>
570
+ * {activeEmoji ? (
571
+ * <span>{activeEmoji.emoji} {activeEmoji.label}</span>
572
+ * ) : (
573
+ * <span>Select an emoji…</span>
574
+ * )}
575
+ * </div>
576
+ * ```
577
+ *
578
+ * @see
579
+ * If you prefer to use a component rather than a hook,
580
+ * {@link EmojiPicker.ActiveEmoji|`<EmojiPicker.ActiveEmoji />`} is also available.
581
+ */
582
+ declare function useActiveEmoji(): Emoji | undefined;
583
+ /**
584
+ * Returns the current skin tone and a function to change it.
585
+ *
586
+ * @example
587
+ * ```tsx
588
+ * const [skinTone, setSkinTone] = useSkinTone();
589
+ * ```
590
+ *
591
+ * It can be used to build a custom skin tone selector: pass an emoji
592
+ * you want to use as visual (by default, βœ‹) and it will return its skin tone
593
+ * variations.
594
+ *
595
+ * @example
596
+ * ```tsx
597
+ * const [skinTone, setSkinTone, skinToneVariations] = useSkinTone("πŸ‘‹");
598
+ *
599
+ * // (πŸ‘‹) (πŸ‘‹πŸ») (πŸ‘‹πŸΌ) (πŸ‘‹πŸ½) (πŸ‘‹πŸΎ) (πŸ‘‹πŸΏ)
600
+ * skinToneVariations.map(({ skinTone, emoji }) => (
601
+ * <button key={skinTone} onClick={() => setSkinTone(skinTone)}>
602
+ * {emoji}
603
+ * </button>
604
+ * ));
605
+ * ```
606
+ *
607
+ * @see
608
+ * If you prefer to use a component rather than a hook,
609
+ * {@link EmojiPicker.SkinTone|`<EmojiPicker.SkinTone />`} is also available.
610
+ *
611
+ * @see
612
+ * An already-built skin tone selector is also available,
613
+ * {@link EmojiPicker.SkinToneSelector|`<EmojiPicker.SkinToneSelector />`}.
614
+ */
615
+ declare function useSkinTone(emoji?: string): [SkinTone, (skinTone: SkinTone) => void, SkinToneVariation[]];
616
+ //#endregion
617
+ export { type Category, type CustomCategory, type Emoji, emoji_picker_d_exports as EmojiPicker, type EmojiPickerActiveEmojiProps, type EmojiPickerCategoryNavProps, type EmojiPickerEmptyProps, type EmojiPickerListCategoryHeaderProps, type EmojiPickerListComponents, type EmojiPickerListEmojiProps, type EmojiPickerListProps, type EmojiPickerListRowProps, type EmojiPickerLoadingProps, type EmojiPickerRootProps, type EmojiPickerSearchProps, type EmojiPickerSkinToneProps, type EmojiPickerSkinToneSelectorProps, type EmojiPickerViewportProps, type Locale, type SkinTone, useActiveEmoji, useSkinTone };
618
+ //# sourceMappingURL=index.d.mts.map
package/dist/index.mjs ADDED
@@ -0,0 +1,2 @@
1
+ import{t as e}from"./chunk-Cke89iAU.mjs";import{Fragment as t,createContext as n,forwardRef as r,memo as i,useCallback as a,useContext as o,useDebugValue as s,useDeferredValue as c,useEffect as l,useImperativeHandle as u,useLayoutEffect as d,useMemo as f,useRef as p,useState as m}from"react";import{jsx as h,jsxs as g}from"react/jsx-runtime";function _(e){let t={},n=null,r=null,i=new Set,a=()=>{if(n){t=n,n=null;for(let e of i)e(t)}r=null},o=()=>n??t,s=e=>{n??=t,Object.assign(n,typeof e==`function`?e(o()):e),r||=requestAnimationFrame(a)};return t=e(s,o),{get:o,set:s,subscribe:e=>(i.add(e),()=>i.delete(e))}}function v(e){let[t]=m(e);return t}function y(e){let t=n(null);return{useStore:()=>{let n=o(t);if(!n)throw Error(e);return n},Provider:({store:e,children:n})=>h(t.Provider,{value:e,children:n})}}function b(e,t,n=Object.is){let[r,i]=m(()=>t(e.get()));return l(()=>e.subscribe(()=>{let r=t(e.get());i(e=>n(e,r)?e:r)}),[e,t,n]),s(r),r}function x(e,t,n){return b(e,a(e=>e[t],[t]),n)}function S(e,t,n,r,i){let a=0;return _((o,s)=>({locale:t,columns:n,sticky:r,skinTone:i,onEmojiSelect:e,data:null,search:``,interaction:`none`,activeColumnIndex:0,activeRowIndex:0,rowHeight:null,categoryHeaderHeight:null,viewportWidth:null,viewportHeight:null,viewportCurrentCategoryIndex:0,viewportStartCategoryIndex:0,viewportStartRowIndex:0,viewportEndRowIndex:0,rootRef:null,searchRef:null,viewportRef:null,listRef:null,updateViewportState:e=>{let t=s(),n=e?.data??t.data,r=e?.categoryHeaderHeight??t.categoryHeaderHeight,i=e?.rowHeight??t.rowHeight,c=e?.viewportHeight??t.viewportHeight;if(!n||n.rows.length===0||!r||!i||!c)return o({...e,viewportCurrentCategoryIndex:0,viewportStartCategoryIndex:0,viewportStartRowIndex:0,viewportEndRowIndex:0});let l=0,u=0,d=a+1;for(let e=0;e<n.categories.length;e++){let t=n.categories[e],o=e*r+t.startRowIndex*i;if(o<=d&&(u=e),o<a)l+=r;else break}let f=n.categories.length*r+n.rows.length*i,p=Math.floor(2*i/2),m=Math.ceil(2*i/2),h=Math.min(a-l-p,f-c),g=h+c+m,_=Math.max(0,Math.floor(h/i)),v=Math.min(n.rows.length-1,Math.ceil(g/i)),y=n.rows[_]?.categoryIndex;return o(y===void 0&&e?{...e,viewportCurrentCategoryIndex:u}:{...e,viewportCurrentCategoryIndex:u,viewportStartCategoryIndex:y,viewportStartRowIndex:_,viewportEndRowIndex:v})},onDataChange:e=>{s().updateViewportState({data:e,activeColumnIndex:0,activeRowIndex:0})},onSearchChange:e=>{o({search:e,interaction:e?`keyboard`:`none`})},onActiveEmojiChange:(e,t,n)=>{if(o({interaction:e,activeColumnIndex:t,activeRowIndex:n}),e!==`keyboard`)return;let{listRef:r,viewportRef:i,sticky:c,rowHeight:l,viewportHeight:u,categoryHeaderHeight:d}=s(),f=r?.current,p=i?.current;if(!f||!p||!l||!d||!u)return;let m=n;m===0&&p.scrollTo({top:0,behavior:`instant`});let h=f.querySelector(`[aria-rowindex="${m}"]`);if(!(h instanceof HTMLElement))return;let g=h.offsetTop,_=getComputedStyle(h),v=Number.parseFloat(_.scrollMarginTop),y=Number.parseFloat(_.scrollMarginBottom),b=a+v;c&&g<a+u/2&&(b+=d);let x=b+u-y;(g<b||g+l>x)&&p.scrollTo({top:Math.max(g<b+d?g-Math.max(c?d:0,v):g-u+l+y,0),behavior:`instant`})},onActiveEmojiReset:()=>{o({interaction:`none`,activeColumnIndex:0,activeRowIndex:0})},onRowHeightChange:e=>{s().updateViewportState({rowHeight:e})},onCategoryHeaderHeightChange:e=>{s().updateViewportState({categoryHeaderHeight:e})},onViewportSizeChange:(e,t)=>{s().updateViewportState({viewportWidth:e,viewportHeight:t})},onViewportScroll:e=>{a=e,s().updateViewportState()}}))}const{useStore:C,Provider:w}=y(`EmojiPicker.Root is missing.`);function T(e){return e.search}function E(e){if(e.interaction!==`none`)return e.data?.rows[e.activeRowIndex]?.emojis[e.activeColumnIndex]}function D(e){return e.data===void 0||typeof e.data?.count==`number`&&e.data.count===0}function O(e){return e.data===null||e.viewportHeight===null||e.rowHeight===null||e.categoryHeaderHeight===null}function k(e){return e.data?.rows.length}function A(e){return e.data?.categories.length}function ee(e){return e.data?.categoriesStartRowIndices}function j(e){return e.data?.skinTones}function M(e,t){return e?.emoji===t?.emoji}function te(e,t){return e?.categoryIndex!==t?.categoryIndex||e?.emojis.length!==t?.emojis.length?!1:!!e?.emojis.every((e,n)=>M(e,t?.emojis[n]))}const N=`'Apple Color Emoji', 'Noto Color Emoji', 'Twemoji Mozilla', 'Android Emoji', 'Segoe UI Emoji', 'Segoe UI Symbol', EmojiSymbols, sans-serif`,P=[`none`,`light`,`medium-light`,`medium`,`medium-dark`,`dark`],F=/\p{Emoji_Modifier_Base}/u,ne=/\uFE0F$/,re=/\u{1F3FB}|\u{1F3FC}|\u{1F3FD}|\u{1F3FE}|\u{1F3FF}/gu,ie={light:`🏻`,"medium-light":`🏼`,medium:`🏽`,"medium-dark":`🏾`,dark:`🏿`};function ae(e,t){if(!e.split(`‍`).some(e=>F.test(e)))return e;let n=e.split(`‍`).map(e=>e.replace(re,``)).join(`‍`);return t===`none`?n:n.split(`‍`).map((e,n,r)=>{let i=r.length>1;return!F.test(e)||i&&e===`🀝`?e:e.replace(ne,``)+ie[t]}).join(`‍`)}function oe(e){return P.map(t=>({skinTone:t,emoji:ae(e,t)}))}function I(){return c(b(C(),E,M))}function L(e=`βœ‹`){let t=C(),n=x(t,`skinTone`),r=f(()=>oe(e),[e]);return[n,a(e=>{t.set({skinTone:e})},[]),r]}function R({children:e}){return e({emoji:I()})}function z({children:e}){let t=C(),n=x(t,`data`),r=x(t,`viewportRef`),i=x(t,`rowHeight`),a=x(t,`categoryHeaderHeight`),o=x(t,`onViewportScroll`),s=x(t,`viewportCurrentCategoryIndex`);return e({categories:f(()=>!n?.categories||!r||!i||!a?[]:n.categories.map((e,t)=>({category:{label:e.label,icon:e.icon,isCustomIcon:e.isCustomIcon},isActive:t===s,scrollTo:()=>{let n=r.current;if(!n)return;let s=t*a+e.startRowIndex*i;n.scrollTo({top:s}),requestAnimationFrame(()=>{o(n.scrollTop)})}})),[n?.categories,r,i,a,s,o])})}function B(e,t){if(Object.is(e,t))return!0;if(typeof e!=`object`||typeof t!=`object`||e===null||t===null||Array.isArray(e)!==Array.isArray(t))return!1;let n=Object.keys(e),r=Object.keys(t);return n.length===r.length?n.every(n=>n in t&&e[n]===t[n]):!1}const V=typeof window<`u`?d:l;function H(e,t,n){return{emoji:{...e,isActive:n},role:`gridcell`,"aria-colindex":t,"aria-selected":n||void 0,"aria-label":e.label,"data-active":n?``:void 0,"frimousse-emoji":``,style:{fontFamily:`var(--frimousse-emoji-font)`},tabIndex:-1}}function U(e,t=!1){return{role:t?void 0:`row`,"aria-rowindex":t?void 0:e,"frimousse-row":``,style:{contain:t?void 0:`content`,height:t?void 0:`var(--frimousse-row-height)`,display:`flex`}}}function W(e,t){return{"frimousse-category":``,style:{contain:`content`,top:t?`calc(${e} * var(--frimousse-category-header-height) + ${t.startRowIndex} * var(--frimousse-row-height))`:void 0,height:t?`calc(var(--frimousse-category-header-height) + ${t.rowsCount} * var(--frimousse-row-height))`:void 0,width:`100%`,pointerEvents:`none`,position:`absolute`}}}function G(e,t=!1,n=!0){return{category:e,"frimousse-category-header":``,style:{contain:t?void 0:`layout paint`,height:t?void 0:`var(--frimousse-category-header-height)`,pointerEvents:`auto`,position:n?`sticky`:void 0,top:0}}}function K(e,t,n,r){return{"frimousse-list-sizer":``,style:{position:`relative`,boxSizing:`border-box`,height:`calc(${e} * var(--frimousse-row-height) + ${t} * var(--frimousse-category-header-height))`,paddingTop:`calc(${n} * var(--frimousse-row-height) + ${r} * var(--frimousse-category-header-height))`}}}function q(e,t,n){return{"aria-colcount":e,"aria-rowcount":t,"frimousse-list":``,style:{"--frimousse-list-columns":e,...n},role:`grid`}}function se(e){e.preventDefault()}const ce=i(({Emoji:e,emoji:t,columnIndex:n,rowIndex:r})=>{let i=C(),o=b(i,e=>E(e)?.emoji===t.emoji),s=a(()=>{i.get().onEmojiSelect(t)},[t]),c=a(()=>{i.get().onActiveEmojiChange(`pointer`,n,r)},[n,r]),l=a(()=>{i.get().onActiveEmojiReset()},[]);return h(e,{...H(t,n,o),onClick:s,onPointerDown:se,onPointerEnter:c,onPointerLeave:l})}),le=i(({Row:e,Emoji:t,rowIndex:n})=>{let r=b(C(),e=>e.data?.rows[n],te);return r?h(e,{...U(n),children:r.emojis.map((e,r)=>h(ce,{columnIndex:r,Emoji:t,emoji:e,rowIndex:n},e.label))}):null}),ue=i(({CategoryHeader:e,categoryIndex:t})=>{let n=C(),r=b(n,e=>e.data?.categories[t],B),i=x(n,`sticky`);return r?h(`div`,{...W(t,r),children:h(e,{...G({label:r.label,icon:r.icon,isCustomIcon:r.isCustomIcon},!1,i)})}):null}),de=i(({CategoryHeader:e,Row:t,Emoji:n})=>{let r=p(null),i=C(),a=x(i,`columns`),o=f(()=>Array(a).fill({emoji:`πŸ™‚`,label:``}),[a]),s=f(()=>({label:`Category`,icon:`πŸ“`}),[]),c=p(null),l=p(null);return V(()=>{let e=r.current?.parentElement?.parentElement;if(!e||!c.current||!l.current)return;let t=new ResizeObserver(e=>{for(let t of e){let e=t.contentRect.height,{onRowHeightChange:n,onCategoryHeaderHeightChange:r,rowHeight:a,categoryHeaderHeight:o}=i.get();t.target===c.current&&a!==e&&n(e),t.target===l.current&&o!==e&&r(e)}});t.observe(e),t.observe(c.current),t.observe(l.current);let{onRowHeightChange:n,onCategoryHeaderHeightChange:a}=i.get();return n(c.current.clientHeight),a(l.current.clientHeight),()=>{t.disconnect()}},[]),g(`div`,{"aria-hidden":!0,ref:r,style:{height:0,visibility:`hidden`},children:[h(`div`,{"frimousse-row-sizer":``,ref:c,children:h(t,{...U(-1,!0),children:o.map((e,t)=>h(n,{...H(e,t,!1)},t))})}),h(`div`,{...W(-1),children:h(`div`,{"frimousse-category-header-sizer":``,ref:l,children:h(e,{...G(s,!0)})})})]})});function fe({category:e,...t}){return g(`div`,{...t,children:[e.icon&&h(`span`,{style:{marginRight:`0.5em`},children:e.isCustomIcon?h(`img`,{alt:``,src:e.icon,style:{width:`1em`,height:`1em`,objectFit:`contain`,verticalAlign:`middle`}}):e.icon}),e.label]})}function pe({emoji:e,...t}){return h(`button`,{type:`button`,...t,children:e.isCustom?h(`img`,{alt:e.label,src:e.emoji,style:{width:`1em`,height:`1em`,objectFit:`contain`,verticalAlign:`middle`}}):e.emoji})}function me({...e}){return h(`div`,{...e})}const he=r(({style:e,components:n,...r},i)=>{let o=C(),s=p(null),c=a(e=>{e&&(s.current=e,o.set({listRef:s}))},[]),l=n?.CategoryHeader??fe,d=n?.Emoji??pe,m=n?.Row??me,_=x(o,`columns`),v=x(o,`viewportStartRowIndex`),y=x(o,`viewportEndRowIndex`),S=b(o,k),w=b(o,ee,B),T=f(()=>w?.filter(e=>e<v).length??0,[w,v]),E=w?.length??0;return u(i,()=>s.current),!S||!w||E===0?h(`div`,{...q(_,0,e),...r,children:h(`div`,{...K(0,0,0,0),children:h(de,{CategoryHeader:l,Emoji:d,Row:m})})}):h(`div`,{...q(_,S,e),...r,ref:c,children:g(`div`,{...K(S,E,v,T),children:[h(de,{CategoryHeader:l,Emoji:d,Row:m}),Array.from({length:y-v+1},(e,n)=>{let r=v+n;return g(t,{children:[w.indexOf(r)>=0&&h(`div`,{style:{height:`var(--frimousse-category-header-height)`}}),h(le,{Emoji:d,Row:m,rowIndex:r})]},r)}),Array.from({length:E},(e,t)=>h(ue,{CategoryHeader:l,categoryIndex:t},t))]})})});function ge({children:e,...t}){return b(C(),O)?h(`span`,{"frimousse-loading":``,...t,children:e}):null}function _e({children:e}){return e({search:b(C(),T)})}function ve({children:e,...t}){return b(C(),D)?h(`span`,{"frimousse-empty":``,...t,children:typeof e==`function`?h(_e,{children:e}):e}):null}function J(e){return e.charAt(0).toUpperCase()+e.slice(1)}let Y=null;function ye(e){try{Y??=document.createElement(`canvas`).getContext(`2d`,{willReadFrequently:!0})}catch{}if(!Y||(queueMicrotask(()=>{Y&&=null}),Y.canvas.width=2,Y.canvas.height=2,Y.font=`2px ${N}`,Y.textBaseline=`middle`,Y.measureText(e).width>=4))return!1;Y.fillStyle=`#00f`,Y.fillText(e,0,0);let t=Y.getImageData(0,0,2,2).data;Y.clearRect(0,0,2,2),Y.fillStyle=`#f00`,Y.fillText(e,0,0);let n=Y.getImageData(0,0,2,2).data;for(let e=0;e<16;e+=4)if(t[e]!==n[e]||t[e+1]!==n[e+1]||t[e+2]!==n[e+2])return!1;return!0}function be(e,t,n){try{let r=e.getItem(t);if(!r)throw Error(`No value found for "${t}".`);return n(JSON.parse(r))}catch{return null}}function xe(e,t,n){e.setItem(t,JSON.stringify(n))}function Se(e){return t=>t===void 0?void 0:e(t)}function Ce(e){return t=>t===null?null:e(t)}function X(e){if(typeof e!=`string`)throw Error();return e}function Z(e){if(typeof e!=`number`)throw Error();return e}function we(e){if(typeof e!=`boolean`)throw Error();return e}function Q(e){return t=>{if(typeof t!=`object`||!t)throw Error();let n={};for(let r in e){let i=t[r];i===void 0&&e[r](void 0),n[r]=e[r](i)}return n}}function $(e){return t=>{if(!Array.isArray(t))throw Error();return t.length>0&&e(t[0]),t}}const Te=(e,t)=>`${e}/${t}/data.json`,Ee=(e,t)=>`${e}/${t}/messages.json`,De=`bn.da.de.en-gb.en.es-mx.es.et.fi.fr.hi.hu.it.ja.ko.lt.ms.nb.nl.pl.pt.ru.sv.th.uk.vi.zh-hant.zh`.split(`.`),Oe=e=>`frimousse/data/${e}`,ke=`frimousse/metadata`;async function Ae(e,t){try{return(await fetch(e,{method:`HEAD`,signal:t})).headers.get(`etag`)}catch{return null}}async function je(e,t,n){let[{emojis:r,emojisEtag:i},{messages:a,messagesEtag:o}]=await Promise.all([fetch(Te(e,t),{signal:n}).then(async e=>({emojis:await e.json(),emojisEtag:e.headers.get(`etag`)})),fetch(Ee(e,t),{signal:n}).then(async e=>({messages:await e.json(),messagesEtag:e.headers.get(`etag`)}))]);return{emojis:r,messages:a,emojisEtag:i,messagesEtag:o}}async function Me(e,t,n){let[r,i]=await Promise.all([Ae(Te(e,t),n),Ae(Ee(e,t),n)]);return{emojisEtag:r,messagesEtag:i}}function Ne(e){if(e.skins)return e.skins.filter(e=>typeof e.tone==`number`).reduce((e,t)=>{let n=P[t.tone];return e[n]=t.emoji,e},{})}async function Pe(e,t,n){let{emojis:r,emojisEtag:i,messages:a,messagesEtag:o}=await je(e,t,n),s=a.subgroups.find(e=>e.key===`country-flag`||e.key===`subdivision-flag`),c=a.groups.filter(e=>e.key!==`component`),l=r.filter(e=>`group`in e),u=c.map(e=>({index:e.order,label:J(e.message)})),d=a.skinTones.reduce((e,t)=>(e[t.key]=J(t.message),e),{}),f={locale:t,emojis:l.map(e=>({emoji:e.emoji,category:e.group,version:e.version,label:J(e.label),tags:e.tags??[],countryFlag:s&&e.subgroup===s.order||void 0,skins:Ne(e)})),categories:u,skinTones:d};return xe(localStorage,Oe(t),{data:f,metadata:{emojisEtag:i,messagesEtag:o}}),f}function Fe(e,t){let n=new Map;for(let t of e)n.has(t.version)||n.set(t.version,t.emoji);let r=[...n.keys()].sort((e,t)=>t-e),i=r[0]??0,a=ye(`πŸ‡ͺπŸ‡Ί`);if(typeof t==`number`)return{emojiVersion:t,countryFlags:a};for(let e of r)if(ye(n.get(e)))return{emojiVersion:e,countryFlags:a};return{emojiVersion:i,countryFlags:a}}const Ie=Q({emojiVersion:Z,countryFlags:we}),Le=Q({data:Q({locale:X,emojis:$(Q({emoji:X,category:Z,label:X,version:Z,tags:$(X),countryFlag:Se(we),skins:Se(Q({light:X,"medium-light":X,medium:X,"medium-dark":X,dark:X}))})),categories:$(Q({index:Z,label:X})),skinTones:Q({light:X,"medium-light":X,medium:X,"medium-dark":X,dark:X})}),metadata:Q({emojisEtag:Ce(X),messagesEtag:Ce(X)})});async function Re({locale:e,emojiVersion:t,emojibaseUrl:n,signal:r}){let i=typeof n==`string`?n:`https://cdn.jsdelivr.net/npm/emojibase-data@${typeof t==`number`?Math.floor(t):`latest`}`,a=be(sessionStorage,ke,Ie),o=be(localStorage,Oe(e),Le),s;if(!o)s=await Pe(i,e,r);else if(a)s=o.data;else try{let{emojisEtag:t,messagesEtag:n}=await Me(i,e,r);s=!t||!n||t!==o.metadata.emojisEtag||n!==o.metadata.messagesEtag?await Pe(i,e,r):o.data}catch{s=o.data}return a??=Fe(s.emojis,t),xe(sessionStorage,ke,a),{locale:e,emojis:s.emojis.filter(e=>{let t=e.version<=a.emojiVersion;return e.countryFlag?t&&a.countryFlags:t}),categories:s.categories,skinTones:s.skinTones}}function ze(e){return De.includes(e)?e:(console.warn(`Locale "${e}" is not supported, using "en" instead.`),`en`)}function Be(e){return P.includes(e)?e:(console.warn(`Skin tone "${e}" is not valid, using "none" instead.`),`none`)}function Ve(e,t){let n=[];if(t<=0)return n;for(let r=0,i=e.length;r<i;r+=t)n.push(e.slice(r,r+t));return n}function He(e,t){if(!t)return e;let n=t.toLowerCase().trim(),r=new WeakMap;return e.filter(e=>{let t=0;e.label.toLowerCase().includes(n)&&(t+=10);for(let r of e.tags)r.toLowerCase().includes(n)&&(t+=1);return t>0?(r.set(e,t),!0):!1}).sort((e,t)=>(r.get(t)??0)-(r.get(e)??0))}function Ue(e,t,n,r){let i=He(e.emojis,r),a=[],o=[],s=[],c={},l=0,u=0;for(let e of i)c[e.category]||(c[e.category]=[]),c[e.category].push({emoji:n&&n!==`none`&&e.skins?e.skins[n]:e.emoji,label:e.label,isCustom:e.isCustom});for(let n of e.categories){let e=c[n.index];if(!e||e.length===0)continue;let r=Ve(Array.from(e),t).map(e=>({categoryIndex:l,emojis:e}));a.push(...r),o.push({label:n.label,rowsCount:r.length,startRowIndex:u,icon:n.icon,isCustomIcon:n.isCustomIcon}),s.push(u),l++,u+=r.length}return{count:i.length,categories:o,categoriesStartRowIndices:s,rows:a,skinTones:e.skinTones}}function We(...e){}function Ge(e,t){let n=null;if(typeof window.requestIdleCallback==`function`)n=window.requestIdleCallback(e,t);else{let r=Date.now();n=window.setTimeout(()=>{e({didTimeout:!1,timeRemaining:()=>Math.max(0,(t?.timeout??50)-(Date.now()-r))})},10)}return()=>{typeof window.cancelIdleCallback==`function`?window.cancelIdleCallback(n):window.clearTimeout(n)}}function Ke(e){let t=p(e);return V(()=>{t.current=e}),a((...e)=>t.current(...e),[])}function qe({emojiVersion:e,emojibaseUrl:t,customEmojis:n,customCategories:r}){let[i,a]=m(void 0),o=C(),s=x(o,`locale`),c=x(o,`columns`),u=x(o,`skinTone`),d=x(o,`search`);return l(()=>{let i=new AbortController,o=i.signal;return Re({locale:s,emojiVersion:e,emojibaseUrl:t,signal:o}).then(t=>{let i=[...t.categories],o=Math.max(...t.categories.map(e=>e.index))+1;if(r&&r.length>0&&(i=[...[...r].sort((e,t)=>e.index-t.index).map(e=>({index:e.index,label:e.label,icon:e.icon,isCustomIcon:e.isCustomIcon})),...i],o=Math.max(...i.map(e=>e.index))+1),n&&n.length>0){let s=new Map;r&&r.forEach(e=>{s.set(e.id??e.index,e.index)});let c=n.map(t=>{let n=s.get(t.category??0)??t.category??o;return{emoji:t.emoji,category:n,label:t.label,version:e??99,tags:t.tags??[],countryFlag:void 0,skins:void 0,isCustom:t.isCustom}});n.some(e=>e.category===void 0)&&(i=[...i,{index:o,label:`Custom`}]),a({...t,emojis:[...t.emojis,...c],categories:i})}else a({...t,categories:i})}).catch(e=>{o.aborted||console.error(e)}),()=>{i.abort()}},[e,t,s,n,r]),l(()=>{if(i)return Ge(()=>{o.get().onDataChange(Ue(i,c,u,d))},{timeout:100})},[i,c,u,d]),null}const Je=r(({locale:e=`en`,columns:t=9,skinTone:n=`none`,onEmojiSelect:r=We,emojiVersion:i,emojibaseUrl:o,customEmojis:s,customCategories:c,onFocusCapture:d,onBlurCapture:f,children:_,style:y,sticky:b=!0,...x},C)=>{let T=Ke(r),D=v(()=>S(T,ze(e),t,b,Be(n))),[O,k]=m(!1),A=p(null),ee=a(e=>{e&&(A.current=e,D.set({rootRef:A}))},[]);V(()=>{D.set({locale:ze(e)})},[e]),V(()=>{D.set({columns:t})},[t]),V(()=>{D.set({sticky:b})},[b]),V(()=>{D.set({skinTone:Be(n)})},[n]);let j=a(e=>{d?.(e);let{searchRef:t,viewportRef:n}=D.get(),r=e.target===t?.current||e.target.hasAttribute(`frimousse-search`),i=e.target===n?.current||e.target.hasAttribute(`frimousse-viewport`);e.isDefaultPrevented()||(k(r||i),e.isDefaultPrevented()||(k(r||i),i?D.get().onActiveEmojiChange(`keyboard`,0,0):r&&D.get().search===``&&D.set({interaction:`none`})))},[d]),M=a(e=>{f?.(e),!e.isDefaultPrevented()&&!e.currentTarget.contains(e.relatedTarget)&&k(!1)},[f]);return V(()=>{O||D.get().onActiveEmojiReset()},[O]),u(C,()=>A.current),l(()=>{if(!O)return;function e(e){if(e.defaultPrevented||!e.key.startsWith(`Arrow`)&&e.key!==`Enter`)return;let{data:t,onEmojiSelect:n,onActiveEmojiChange:r,interaction:i,activeColumnIndex:a,activeRowIndex:o}=D.get();if(e.key===`Enter`){let t=E(D.get());t&&(e.preventDefault(),n(t))}if(e.key.startsWith(`Arrow`)){let n=a,s=o;if(e.preventDefault(),i!==`none`){if(t?.rows&&t.rows.length>0)switch(e.key){case`ArrowLeft`:if(n===0){let e=s-1,r=t.rows[e];r&&(s=e,n=r.emojis.length-1)}else --n;break;case`ArrowRight`:if(n===t.rows[s].emojis.length-1){let e=s+1;t.rows[e]&&(s=e,n=0)}else n+=1;break;case`ArrowUp`:{let e=t.rows[s-1];e&&(--s,e.emojis[n]||(n=e.emojis.length-1));break}case`ArrowDown`:{let e=t.rows[s+1];e&&(s+=1,e.emojis[n]||(n=e.emojis.length-1));break}}r(`keyboard`,n,s)}else r(`keyboard`,0,0)}}return document.addEventListener(`keydown`,e),()=>{document.removeEventListener(`keydown`,e)}},[O]),V(()=>{let e=null,t=null,n=null,r=null,i=D.subscribe(i=>{A.current&&(e!==i.viewportWidth&&(e=i.viewportWidth,A.current.style.setProperty(`--frimousse-viewport-width`,`${i.viewportWidth}px`)),t!==i.viewportHeight&&(t=i.viewportHeight,A.current.style.setProperty(`--frimousse-viewport-height`,`${i.viewportHeight}px`)),n!==i.rowHeight&&(n=i.rowHeight,A.current.style.setProperty(`--frimousse-row-height`,`${i.rowHeight}px`)),r!==i.categoryHeaderHeight&&(r=i.categoryHeaderHeight,A.current.style.setProperty(`--frimousse-category-header-height`,`${i.categoryHeaderHeight}px`)))}),{viewportWidth:a,viewportHeight:o,rowHeight:s,categoryHeaderHeight:c}=D.get();return a&&A.current.style.setProperty(`--frimousse-viewport-width`,`${a}px`),o&&A.current.style.setProperty(`--frimousse-viewport-height`,`${o}px`),s&&A.current.style.setProperty(`--frimousse-row-height`,`${s}px`),c&&A.current.style.setProperty(`--frimousse-category-header-height`,`${c}px`),i},[]),h(`div`,{"data-focused":O?``:void 0,"frimousse-root":``,onBlurCapture:M,onFocusCapture:j,...x,ref:ee,style:{"--frimousse-emoji-font":N,...y},children:g(w,{store:D,children:[h(qe,{customCategories:c,customEmojis:s,emojibaseUrl:o,emojiVersion:i}),_]})})}),Ye=r(({value:e,defaultValue:t,onChange:n,...r},i)=>{let o=C(),s=p(null),c=a(e=>{e&&(s.current=e,o.set({searchRef:s}))},[]),d=typeof e==`string`,f=p(d);l(()=>{process.env.NODE_ENV!==`production`&&f.current!==d&&console.warn(`EmojiPicker.Search is changing from ${f?`controlled`:`uncontrolled`} to ${d?`controlled`:`uncontrolled`}.`),f.current=d},[d]),V(()=>{o.set({search:typeof e==`string`?e:typeof t==`string`?t:``})},[]),V(()=>{typeof e==`string`&&o.get().onSearchChange(e)},[e]);let m=a(e=>{n?.(e),e.isDefaultPrevented()||o.get().onSearchChange(e.target.value)},[n]);return u(i,()=>s.current),h(`input`,{autoCapitalize:`off`,autoComplete:`off`,autoCorrect:`off`,enterKeyHint:`done`,"frimousse-search":``,placeholder:`Search…`,spellCheck:!1,type:`search`,...r,defaultValue:t,onChange:m,ref:c,value:e})}),Xe=r(({emoji:e,onClick:t,"aria-label":n=`Change skin tone`,...r},i)=>{let o=b(C(),j,B),[s,c,l]=L(e),u=f(()=>Math.max(0,l.findIndex(e=>e.skinTone===s)),[s,l]),d=l[u],p=l[(u+1)%l.length].skinTone,m=p===`none`?void 0:o?.[p],g=a(e=>{t?.(e),e.isDefaultPrevented()||c(p)},[t,c,p]);return h(`button`,{type:`button`,...r,"aria-label":n+(m?` (${m})`:``),"aria-live":`polite`,"frimousse-skin-tone-selector":``,onClick:g,ref:i,children:d.emoji})});function Ze({children:e,emoji:t}){let[n,r,i]=L(t);return e({skinTone:n,setSkinTone:r,skinToneVariations:i})}const Qe=i(()=>{let e=I();return e?h(`div`,{"aria-live":`polite`,style:{border:0,clip:`rect(0, 0, 0, 0)`,height:1,margin:-1,overflow:`hidden`,padding:0,position:`absolute`,whiteSpace:`nowrap`,width:1,wordWrap:`normal`},children:e.label}):null}),$e=r(({children:e,onScroll:t,onKeyDown:n,style:r,...i},o)=>{let s=C(),c=p(null),l=a(e=>{e&&(c.current=e,s.set({viewportRef:c}))},[]),d=b(s,k),f=b(s,A),m=a(e=>{t?.(e),s.get().onViewportScroll(e.currentTarget.scrollTop)},[t]);return V(()=>{if(!c.current)return;let e=new ResizeObserver(([e])=>{let t=e?.borderBoxSize[0]?.inlineSize??0,n=e?.borderBoxSize[0]?.blockSize??0,{onViewportSizeChange:r,viewportHeight:i,viewportWidth:a}=s.get();(i!==n||a!==t)&&r(t,n)});return e.observe(c.current),s.get().onViewportSizeChange(c.current.offsetWidth,c.current.clientHeight),()=>{e.disconnect()}},[]),u(o,()=>c.current),g(`div`,{"frimousse-viewport":``,...i,onScroll:m,ref:l,style:{position:`relative`,boxSizing:`border-box`,contain:`layout paint`,containIntrinsicSize:typeof d==`number`&&typeof f==`number`?`var(--frimousse-viewport-width, auto) calc(${d} * var(--frimousse-row-height) + ${f} * var(--frimousse-category-header-height))`:void 0,overflowY:`auto`,overscrollBehavior:`contain`,scrollbarGutter:`stable`,willChange:`scroll-position`,...r},children:[h(Qe,{}),e]})});var et=e({ActiveEmoji:()=>R,CategoryNav:()=>z,Empty:()=>ve,List:()=>he,Loading:()=>ge,Root:()=>Je,Search:()=>Ye,SkinTone:()=>Ze,SkinToneSelector:()=>Xe,Viewport:()=>$e});Je.displayName=`EmojiPicker.Root`,Ye.displayName=`EmojiPicker.Search`,$e.displayName=`EmojiPicker.Viewport`,he.displayName=`EmojiPicker.List`,ge.displayName=`EmojiPicker.Loading`,ve.displayName=`EmojiPicker.Empty`,Xe.displayName=`EmojiPicker.SkinToneSelector`,R.displayName=`EmojiPicker.ActiveEmoji`,z.displayName=`EmojiPicker.CategoryNav`,Ze.displayName=`EmojiPicker.SkinTone`;export{et as EmojiPicker,I as useActiveEmoji,L as useSkinTone};
2
+ //# sourceMappingURL=index.mjs.map