@liveblocks/react-ui 2.21.0-emails3 → 2.22.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.
Files changed (108) hide show
  1. package/dist/_private/index.cjs +2 -2
  2. package/dist/_private/index.d.cts +2 -2
  3. package/dist/_private/index.d.ts +2 -2
  4. package/dist/_private/index.js +1 -1
  5. package/dist/components/Comment.cjs +3 -3
  6. package/dist/components/Comment.cjs.map +1 -1
  7. package/dist/components/Comment.js +3 -3
  8. package/dist/components/Comment.js.map +1 -1
  9. package/dist/components/Composer.cjs.map +1 -1
  10. package/dist/components/Composer.js.map +1 -1
  11. package/dist/components/HistoryVersionSummary.cjs.map +1 -1
  12. package/dist/components/HistoryVersionSummary.js.map +1 -1
  13. package/dist/components/HistoryVersionSummaryList.cjs.map +1 -1
  14. package/dist/components/HistoryVersionSummaryList.js.map +1 -1
  15. package/dist/components/InboxNotification.cjs.map +1 -1
  16. package/dist/components/InboxNotification.js.map +1 -1
  17. package/dist/components/InboxNotificationList.cjs.map +1 -1
  18. package/dist/components/InboxNotificationList.js.map +1 -1
  19. package/dist/components/Thread.cjs.map +1 -1
  20. package/dist/components/Thread.js.map +1 -1
  21. package/dist/components/internal/Attachment.cjs.map +1 -1
  22. package/dist/components/internal/Attachment.js.map +1 -1
  23. package/dist/components/internal/Avatar.cjs.map +1 -1
  24. package/dist/components/internal/Avatar.js.map +1 -1
  25. package/dist/components/internal/Button.cjs.map +1 -1
  26. package/dist/components/internal/Button.js.map +1 -1
  27. package/dist/components/internal/Dropdown.cjs.map +1 -1
  28. package/dist/components/internal/Dropdown.js.map +1 -1
  29. package/dist/components/internal/EmojiPicker.cjs +68 -82
  30. package/dist/components/internal/EmojiPicker.cjs.map +1 -1
  31. package/dist/components/internal/EmojiPicker.js +70 -84
  32. package/dist/components/internal/EmojiPicker.js.map +1 -1
  33. package/dist/components/internal/Room.cjs.map +1 -1
  34. package/dist/components/internal/Room.js.map +1 -1
  35. package/dist/components/internal/Tooltip.cjs.map +1 -1
  36. package/dist/components/internal/Tooltip.js.map +1 -1
  37. package/dist/components/internal/User.cjs.map +1 -1
  38. package/dist/components/internal/User.js.map +1 -1
  39. package/dist/components.cjs.map +1 -1
  40. package/dist/components.js.map +1 -1
  41. package/dist/config.cjs.map +1 -1
  42. package/dist/config.js.map +1 -1
  43. package/dist/icon.cjs +16 -0
  44. package/dist/icon.cjs.map +1 -1
  45. package/dist/icon.js +8 -0
  46. package/dist/icon.js.map +1 -1
  47. package/dist/icons/{EmojiAdd.cjs → EmojiPlus.cjs} +3 -3
  48. package/dist/icons/EmojiPlus.cjs.map +1 -0
  49. package/dist/icons/{EmojiAdd.js → EmojiPlus.js} +3 -3
  50. package/dist/icons/EmojiPlus.js.map +1 -0
  51. package/dist/icons/index.cjs +2 -2
  52. package/dist/icons/index.js +1 -1
  53. package/dist/index.d.cts +25 -0
  54. package/dist/index.d.ts +25 -0
  55. package/dist/overrides.cjs +1 -0
  56. package/dist/overrides.cjs.map +1 -1
  57. package/dist/overrides.js +1 -0
  58. package/dist/overrides.js.map +1 -1
  59. package/dist/primitives/Composer/index.cjs.map +1 -1
  60. package/dist/primitives/Composer/index.js.map +1 -1
  61. package/dist/primitives/FileSize.cjs.map +1 -1
  62. package/dist/primitives/FileSize.js.map +1 -1
  63. package/dist/primitives/Timestamp.cjs.map +1 -1
  64. package/dist/primitives/Timestamp.js.map +1 -1
  65. package/dist/primitives/index.cjs +0 -2
  66. package/dist/primitives/index.cjs.map +1 -1
  67. package/dist/primitives/index.d.cts +4 -165
  68. package/dist/primitives/index.d.ts +4 -165
  69. package/dist/primitives/index.js +0 -2
  70. package/dist/primitives/index.js.map +1 -1
  71. package/dist/slate/plugins/paste.cjs +8 -1
  72. package/dist/slate/plugins/paste.cjs.map +1 -1
  73. package/dist/slate/plugins/paste.js +8 -1
  74. package/dist/slate/plugins/paste.js.map +1 -1
  75. package/dist/utils/Persist.cjs.map +1 -1
  76. package/dist/utils/Persist.js.map +1 -1
  77. package/dist/utils/Portal.cjs.map +1 -1
  78. package/dist/utils/Portal.js.map +1 -1
  79. package/dist/version.cjs +1 -1
  80. package/dist/version.cjs.map +1 -1
  81. package/dist/version.js +1 -1
  82. package/dist/version.js.map +1 -1
  83. package/package.json +5 -7
  84. package/src/styles/index.css +54 -10
  85. package/styles.css +1 -1
  86. package/styles.css.map +1 -1
  87. package/dist/icons/EmojiAdd.cjs.map +0 -1
  88. package/dist/icons/EmojiAdd.js.map +0 -1
  89. package/dist/primitives/EmojiPicker/contexts.cjs +0 -19
  90. package/dist/primitives/EmojiPicker/contexts.cjs.map +0 -1
  91. package/dist/primitives/EmojiPicker/contexts.js +0 -16
  92. package/dist/primitives/EmojiPicker/contexts.js.map +0 -1
  93. package/dist/primitives/EmojiPicker/index.cjs +0 -516
  94. package/dist/primitives/EmojiPicker/index.cjs.map +0 -1
  95. package/dist/primitives/EmojiPicker/index.js +0 -512
  96. package/dist/primitives/EmojiPicker/index.js.map +0 -1
  97. package/dist/primitives/EmojiPicker/utils.cjs +0 -330
  98. package/dist/primitives/EmojiPicker/utils.cjs.map +0 -1
  99. package/dist/primitives/EmojiPicker/utils.js +0 -326
  100. package/dist/primitives/EmojiPicker/utils.js.map +0 -1
  101. package/dist/utils/request-idle-callback.cjs +0 -15
  102. package/dist/utils/request-idle-callback.cjs.map +0 -1
  103. package/dist/utils/request-idle-callback.js +0 -12
  104. package/dist/utils/request-idle-callback.js.map +0 -1
  105. package/dist/utils/visually-hidden.cjs +0 -17
  106. package/dist/utils/visually-hidden.cjs.map +0 -1
  107. package/dist/utils/visually-hidden.js +0 -15
  108. package/dist/utils/visually-hidden.js.map +0 -1
@@ -1,512 +0,0 @@
1
- "use client";
2
- import { jsx, jsxs } from 'react/jsx-runtime';
3
- import { useLayoutEffect } from '@liveblocks/react/_private';
4
- import { Slot } from '@radix-ui/react-slot';
5
- import { useRef, useTransition, useState, useCallback, useEffect, forwardRef, useMemo } from 'react';
6
- import { GroupedVirtuoso } from 'react-virtuoso';
7
- import { isKey } from '../../utils/is-key.js';
8
- import { requestIdleCallback, cancelIdleCallback } from '../../utils/request-idle-callback.js';
9
- import { visuallyHidden } from '../../utils/visually-hidden.js';
10
- import { Emoji } from '../internal/Emoji.js';
11
- import { EmojiPickerContext, useEmojiPicker } from './contexts.js';
12
- import { filterEmojis, generateEmojiPickerData, getEmojiData } from './utils.js';
13
-
14
-
15
- const DEFAULT_COLUMNS = 10;
16
- const DEFAULT_LOCALE = "en";
17
- const LOADING_MINIMUM_TIMEOUT = 100;
18
- const EMOJIPICKER_ROOT_NAME = "EmojiPickerRoot";
19
- const EMOJIPICKER_CONTENT_NAME = "EmojiPickerContent";
20
- const EMOJIPICKER_SEARCH_NAME = "EmojiPickerSearch";
21
- function EmojiPickerRoot({
22
- columns = DEFAULT_COLUMNS,
23
- locale = DEFAULT_LOCALE,
24
- onEmojiSelect,
25
- children
26
- }) {
27
- const emojiData = useRef();
28
- const search = useRef("");
29
- const [, startEmojisTransition] = useTransition();
30
- const [data, setData] = useState();
31
- const [error, setError] = useState();
32
- const [selectedColumnIndex, setSelectedColumnIndex] = useState(0);
33
- const [selectedRowIndex, setSelectedRowIndex] = useState(0);
34
- const [interaction, setInteraction] = useState("none");
35
- const selectCurrentEmoji = useCallback(() => {
36
- if (onEmojiSelect) {
37
- const emoji = data?.rows[selectedRowIndex]?.[selectedColumnIndex];
38
- if (emoji) {
39
- onEmojiSelect(emoji.emoji);
40
- }
41
- }
42
- }, [data?.rows, onEmojiSelect, selectedColumnIndex, selectedRowIndex]);
43
- const resetSelection = useCallback(() => {
44
- setSelectedColumnIndex(0);
45
- setSelectedRowIndex(0);
46
- }, []);
47
- const setPointerSelection = useCallback(
48
- (columnIndex, rowIndex) => {
49
- setInteraction("pointer");
50
- setSelectedColumnIndex(columnIndex);
51
- setSelectedRowIndex(rowIndex);
52
- },
53
- []
54
- );
55
- const moveSelection = useCallback(
56
- (direction, event) => {
57
- if (!data) {
58
- return;
59
- }
60
- event.preventDefault();
61
- if (interaction === "none") {
62
- setInteraction("keyboard");
63
- return;
64
- }
65
- setInteraction("keyboard");
66
- switch (direction) {
67
- case "left": {
68
- if (selectedColumnIndex === 0) {
69
- const previousRowIndex = selectedRowIndex - 1;
70
- const previousRow = data.rows[previousRowIndex];
71
- if (previousRow) {
72
- setSelectedRowIndex(previousRowIndex);
73
- setSelectedColumnIndex(previousRow.length - 1);
74
- }
75
- } else {
76
- setSelectedColumnIndex(selectedColumnIndex - 1);
77
- }
78
- break;
79
- }
80
- case "right": {
81
- const currentRow = data.rows[selectedRowIndex];
82
- if (!currentRow) {
83
- return;
84
- }
85
- if (selectedColumnIndex === currentRow.length - 1) {
86
- const nextRowIndex = selectedRowIndex + 1;
87
- const nextRow = data.rows[nextRowIndex];
88
- if (nextRow) {
89
- setSelectedRowIndex(nextRowIndex);
90
- setSelectedColumnIndex(0);
91
- }
92
- } else {
93
- setSelectedColumnIndex(selectedColumnIndex + 1);
94
- }
95
- break;
96
- }
97
- case "up": {
98
- const previousRow = data.rows[selectedRowIndex - 1];
99
- if (previousRow) {
100
- setSelectedRowIndex(selectedRowIndex - 1);
101
- if (!previousRow[selectedColumnIndex]) {
102
- setSelectedColumnIndex(previousRow.length - 1);
103
- }
104
- }
105
- break;
106
- }
107
- case "down": {
108
- const nextRow = data.rows[selectedRowIndex + 1];
109
- if (nextRow) {
110
- setSelectedRowIndex(selectedRowIndex + 1);
111
- if (!nextRow[selectedColumnIndex]) {
112
- setSelectedColumnIndex(nextRow.length - 1);
113
- }
114
- }
115
- break;
116
- }
117
- }
118
- },
119
- [data, interaction, selectedColumnIndex, selectedRowIndex]
120
- );
121
- const updateEmojis = useCallback(() => {
122
- if (!emojiData.current) {
123
- return;
124
- }
125
- startEmojisTransition(() => {
126
- setData(() => {
127
- if (!emojiData.current) {
128
- return;
129
- }
130
- const filteredEmojis = filterEmojis(
131
- emojiData.current.emojis,
132
- search.current
133
- );
134
- return generateEmojiPickerData(
135
- filteredEmojis,
136
- emojiData.current.categories,
137
- columns
138
- );
139
- });
140
- resetSelection();
141
- });
142
- }, [columns, resetSelection]);
143
- const handleSearch = useCallback(
144
- (value) => {
145
- search.current = value;
146
- updateEmojis();
147
- },
148
- [updateEmojis]
149
- );
150
- const initializeEmojiData = useCallback(
151
- async (locale2) => {
152
- try {
153
- emojiData.current = await getEmojiData(locale2);
154
- updateEmojis();
155
- } catch (error2) {
156
- setError(error2);
157
- }
158
- },
159
- [updateEmojis]
160
- );
161
- useEffect(() => {
162
- let idleCallbackId;
163
- const timeoutId = setTimeout(() => {
164
- idleCallbackId = requestIdleCallback(() => {
165
- initializeEmojiData(locale);
166
- });
167
- }, LOADING_MINIMUM_TIMEOUT);
168
- return () => {
169
- clearTimeout(timeoutId);
170
- cancelIdleCallback(idleCallbackId);
171
- };
172
- }, [locale]);
173
- useEffect(() => {
174
- if (interaction === "none") {
175
- resetSelection();
176
- }
177
- }, [interaction]);
178
- return /* @__PURE__ */ jsx(EmojiPickerContext.Provider, {
179
- value: {
180
- data,
181
- error,
182
- isLoading: !data && !error,
183
- columns,
184
- onSearch: handleSearch,
185
- onEmojiSelect,
186
- selectCurrentEmoji,
187
- selectedRowIndex,
188
- selectedColumnIndex,
189
- moveSelection,
190
- setPointerSelection,
191
- interaction,
192
- setInteraction
193
- },
194
- children
195
- });
196
- }
197
- const EmojiPickerSearch = forwardRef(
198
- ({ asChild, value, defaultValue, onChange, ...props }, forwardedRef) => {
199
- const Component = asChild ? Slot : "input";
200
- const {
201
- onSearch,
202
- selectCurrentEmoji,
203
- moveSelection,
204
- interaction,
205
- setInteraction
206
- } = useEmojiPicker();
207
- const handleChange = useCallback(
208
- (event) => {
209
- onChange?.(event);
210
- if (event.isDefaultPrevented()) {
211
- return;
212
- }
213
- const value2 = event.target.value;
214
- setInteraction(value2 ? "keyboard" : "none");
215
- onSearch(value2);
216
- },
217
- [onChange, onSearch, setInteraction]
218
- );
219
- const handleKeyDown = useCallback(
220
- (event) => {
221
- if (event.isDefaultPrevented()) {
222
- return;
223
- }
224
- if (isKey(event, "ArrowLeft")) {
225
- moveSelection("left", event);
226
- } else if (isKey(event, "ArrowRight")) {
227
- moveSelection("right", event);
228
- } else if (isKey(event, "ArrowUp")) {
229
- moveSelection("up", event);
230
- } else if (isKey(event, "ArrowDown")) {
231
- moveSelection("down", event);
232
- } else if (isKey(event, "Enter")) {
233
- if (interaction !== "none") {
234
- event.preventDefault();
235
- selectCurrentEmoji();
236
- }
237
- }
238
- },
239
- [interaction, moveSelection, selectCurrentEmoji]
240
- );
241
- useEffect(() => {
242
- onSearch(
243
- value ? String(value) : defaultValue ? String(defaultValue) : ""
244
- );
245
- }, []);
246
- return /* @__PURE__ */ jsx(Component, {
247
- type: "search",
248
- value,
249
- defaultValue,
250
- onChange: handleChange,
251
- onKeyDown: handleKeyDown,
252
- ...props,
253
- ref: forwardedRef
254
- });
255
- }
256
- );
257
- const defaultContentComponents = {
258
- CategoryHeader: ({ category, ...props }) => /* @__PURE__ */ jsx("div", {
259
- ...props,
260
- children: category
261
- }),
262
- Row: ({ children, attributes, ...props }) => /* @__PURE__ */ jsx("div", {
263
- ...props,
264
- children
265
- }),
266
- Emoji: ({ emoji, ...props }) => /* @__PURE__ */ jsx("button", {
267
- ...props,
268
- children: /* @__PURE__ */ jsx(Emoji, {
269
- emoji
270
- })
271
- }),
272
- Loading: (props) => /* @__PURE__ */ jsx("div", {
273
- ...props
274
- }),
275
- Empty: (props) => /* @__PURE__ */ jsx("div", {
276
- ...props
277
- }),
278
- Grid: (props) => /* @__PURE__ */ jsx("div", {
279
- ...props
280
- }),
281
- Error: ({ error, ...props }) => /* @__PURE__ */ jsx("div", {
282
- ...props
283
- })
284
- };
285
- const placeholderRowAttributes = {
286
- rowIndex: -1,
287
- categoryRowIndex: -1,
288
- categoryRowsCount: 0
289
- };
290
- const VirtuosoScroller = forwardRef(
291
- ({ children, ...props }, forwardedRef) => {
292
- return /* @__PURE__ */ jsx("div", {
293
- ...props,
294
- tabIndex: -1,
295
- "data-testid": void 0,
296
- ref: forwardedRef,
297
- children
298
- });
299
- }
300
- );
301
- const VirtuosoTopList = forwardRef(
302
- ({ children, ...props }, forwardedRef) => {
303
- return /* @__PURE__ */ jsx("div", {
304
- ...props,
305
- "data-testid": void 0,
306
- ref: forwardedRef,
307
- children
308
- });
309
- }
310
- );
311
- const EmojiPickerContent = forwardRef(
312
- ({ components, asChild, ...props }, forwardedRef) => {
313
- const Component = asChild ? Slot : "div";
314
- const virtuosoRef = useRef(null);
315
- const placeholderContainerRef = useRef(null);
316
- const rowScrollMarginTopRef = useRef(0);
317
- const rowScrollMarginBottomRef = useRef(0);
318
- const categoryHeaderHeightRef = useRef(0);
319
- const {
320
- data,
321
- error,
322
- isLoading,
323
- columns,
324
- onEmojiSelect,
325
- selectedColumnIndex,
326
- selectedRowIndex,
327
- setPointerSelection,
328
- interaction,
329
- setInteraction
330
- } = useEmojiPicker();
331
- const selectedEmoji = useMemo(
332
- () => data?.rows[selectedRowIndex]?.[selectedColumnIndex],
333
- [data?.rows, selectedColumnIndex, selectedRowIndex]
334
- );
335
- const { Loading, Empty, Error, CategoryHeader, Grid, Row, Emoji } = useMemo(
336
- () => ({ ...defaultContentComponents, ...components }),
337
- [components]
338
- );
339
- const VirtuosoList = useMemo(
340
- () => forwardRef(
341
- ({ children, ...props2 }, forwardedRef2) => {
342
- return /* @__PURE__ */ jsx("div", {
343
- role: "grid",
344
- "aria-colcount": columns,
345
- ...props2,
346
- "data-testid": void 0,
347
- ref: forwardedRef2,
348
- children
349
- });
350
- }
351
- ),
352
- [columns]
353
- );
354
- const placeholderColumns = useMemo(
355
- () => Array(columns).fill("\u{1F32B}\uFE0F"),
356
- [columns]
357
- );
358
- const preventDefault = useCallback((event) => {
359
- event.preventDefault();
360
- }, []);
361
- const handleEmojiPointerLeave = useCallback(() => {
362
- if (interaction === "pointer") {
363
- setInteraction("none");
364
- }
365
- }, [interaction, setInteraction]);
366
- useLayoutEffect(() => {
367
- if (!placeholderContainerRef.current) {
368
- return;
369
- }
370
- const row = placeholderContainerRef.current.childNodes[0];
371
- const categoryHeader = placeholderContainerRef.current.childNodes[1];
372
- if (row instanceof HTMLElement) {
373
- const style = window.getComputedStyle(row);
374
- rowScrollMarginTopRef.current = parseFloat(style.scrollMarginTop);
375
- rowScrollMarginBottomRef.current = parseFloat(style.scrollMarginBottom);
376
- }
377
- if (categoryHeader instanceof HTMLElement) {
378
- categoryHeaderHeightRef.current = categoryHeader.offsetHeight;
379
- }
380
- }, []);
381
- const calculateViewLocation = useCallback(
382
- ({
383
- itemTop,
384
- itemBottom,
385
- viewportTop,
386
- viewportBottom,
387
- locationParams: { behavior, align, ...params }
388
- }) => {
389
- if (itemTop - (categoryHeaderHeightRef.current + rowScrollMarginTopRef.current) < viewportTop) {
390
- return {
391
- ...params,
392
- behavior,
393
- align: align ?? "start"
394
- };
395
- }
396
- if (itemBottom > viewportBottom) {
397
- return {
398
- ...params,
399
- behavior,
400
- align: align ?? "end",
401
- offset: rowScrollMarginBottomRef.current
402
- };
403
- }
404
- return null;
405
- },
406
- []
407
- );
408
- useEffect(() => {
409
- if (interaction === "keyboard") {
410
- virtuosoRef.current?.scrollIntoView({
411
- index: selectedRowIndex,
412
- behavior: "auto",
413
- calculateViewLocation
414
- });
415
- }
416
- }, [interaction, selectedRowIndex, calculateViewLocation]);
417
- return /* @__PURE__ */ jsxs(Component, {
418
- ...props,
419
- ref: forwardedRef,
420
- children: [
421
- /* @__PURE__ */ jsxs("div", {
422
- style: {
423
- visibility: "hidden",
424
- height: 0
425
- },
426
- ref: placeholderContainerRef,
427
- children: [
428
- /* @__PURE__ */ jsx(Row, {
429
- attributes: placeholderRowAttributes,
430
- children: placeholderColumns.map((placeholder, index) => /* @__PURE__ */ jsx(Emoji, {
431
- emoji: placeholder
432
- }, index))
433
- }),
434
- /* @__PURE__ */ jsx(CategoryHeader, {
435
- category: "Category"
436
- })
437
- ]
438
- }),
439
- isLoading ? /* @__PURE__ */ jsx(Loading, {}) : error ? /* @__PURE__ */ jsx(Error, {
440
- error
441
- }) : data.count === 0 ? /* @__PURE__ */ jsx(Empty, {}) : /* @__PURE__ */ jsx(Grid, {
442
- children: /* @__PURE__ */ jsx(GroupedVirtuoso, {
443
- ref: virtuosoRef,
444
- components: {
445
- Scroller: VirtuosoScroller,
446
- List: VirtuosoList,
447
- TopItemList: VirtuosoTopList
448
- },
449
- groupCounts: data.categoriesRowCounts,
450
- groupContent: (groupIndex) => {
451
- const category = data.categories[groupIndex];
452
- if (!category) {
453
- return null;
454
- }
455
- return /* @__PURE__ */ jsx(CategoryHeader, {
456
- category
457
- });
458
- },
459
- itemContent: (rowIndex, groupIndex) => {
460
- const categoryRow = data.rows[rowIndex];
461
- const categoryRowIndex = data.categoriesRowIndices[groupIndex]?.indexOf(rowIndex);
462
- const categoryRowsCount = data.categoriesRowCounts[groupIndex];
463
- if (categoryRow === void 0 || categoryRowIndex === void 0 || categoryRowsCount === void 0) {
464
- return null;
465
- }
466
- return /* @__PURE__ */ jsx(Row, {
467
- attributes: {
468
- rowIndex,
469
- categoryRowIndex,
470
- categoryRowsCount
471
- },
472
- children: categoryRow.map((emoji, columnIndex) => {
473
- const isSelected = interaction !== "none" && selectedColumnIndex === columnIndex && selectedRowIndex === rowIndex;
474
- return /* @__PURE__ */ jsx(Emoji, {
475
- role: "gridcell",
476
- "aria-colindex": columnIndex,
477
- "aria-selected": isSelected || void 0,
478
- "data-selected": isSelected || void 0,
479
- onMouseDown: preventDefault,
480
- tabIndex: -1,
481
- onPointerEnter: () => {
482
- setPointerSelection(columnIndex, rowIndex);
483
- },
484
- onPointerLeave: handleEmojiPointerLeave,
485
- onClick: (event) => {
486
- onEmojiSelect?.(emoji.emoji);
487
- event.stopPropagation();
488
- },
489
- emoji: emoji.emoji
490
- }, emoji.emoji);
491
- })
492
- });
493
- }
494
- })
495
- }),
496
- selectedEmoji && interaction !== "none" && /* @__PURE__ */ jsx("div", {
497
- "aria-live": "polite",
498
- style: visuallyHidden,
499
- children: selectedEmoji.name
500
- })
501
- ]
502
- });
503
- }
504
- );
505
- if (process.env.NODE_ENV !== "production") {
506
- EmojiPickerRoot.displayName = EMOJIPICKER_ROOT_NAME;
507
- EmojiPickerContent.displayName = EMOJIPICKER_CONTENT_NAME;
508
- EmojiPickerSearch.displayName = EMOJIPICKER_SEARCH_NAME;
509
- }
510
-
511
- export { EmojiPickerContent as Content, EmojiPickerRoot as Root, EmojiPickerSearch as Search };
512
- //# sourceMappingURL=index.js.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"index.js","sources":["../../../src/primitives/EmojiPicker/index.tsx"],"sourcesContent":["\"use client\";\n\nimport { useLayoutEffect } from \"@liveblocks/react/_private\";\nimport { Slot } from \"@radix-ui/react-slot\";\nimport type { ChangeEvent, KeyboardEvent, SyntheticEvent } from \"react\";\nimport {\n forwardRef,\n useCallback,\n useEffect,\n useMemo,\n useRef,\n useState,\n useTransition,\n} from \"react\";\nimport type {\n CalculateViewLocationParams,\n GroupedVirtuosoHandle,\n ListProps as VirtuosoListProps,\n ScrollerProps,\n TopItemListProps,\n} from \"react-virtuoso\";\nimport { GroupedVirtuoso } from \"react-virtuoso\";\n\nimport { isKey } from \"../../utils/is-key\";\nimport {\n cancelIdleCallback,\n requestIdleCallback,\n} from \"../../utils/request-idle-callback\";\nimport { visuallyHidden } from \"../../utils/visually-hidden\";\nimport { Emoji as EmojiPrimitive } from \"../internal/Emoji\";\nimport { EmojiPickerContext, useEmojiPicker } from \"./contexts\";\nimport type {\n EmojiData,\n EmojiPickerContentComponents,\n EmojiPickerContentEmojiRowAttributes,\n EmojiPickerContentProps,\n EmojiPickerData,\n EmojiPickerRootProps,\n EmojiPickerSearchProps,\n EmojiPickerSelectionDirection,\n} from \"./types\";\nimport { filterEmojis, generateEmojiPickerData, getEmojiData } from \"./utils\";\n\nconst DEFAULT_COLUMNS = 10;\nconst DEFAULT_LOCALE = \"en\";\nconst LOADING_MINIMUM_TIMEOUT = 100;\n\nconst EMOJIPICKER_ROOT_NAME = \"EmojiPickerRoot\";\nconst EMOJIPICKER_CONTENT_NAME = \"EmojiPickerContent\";\nconst EMOJIPICKER_SEARCH_NAME = \"EmojiPickerSearch\";\n\n/**\n * @private\n * The EmojiPicker primitive is undocumented for now and subject to change,\n * use at your own risk. If you have any feedback on it, please let us know!\n * See how we use it in the default components to learn how to use it:\n * https://github.com/liveblocks/liveblocks/blob/main/packages/liveblocks-react-ui/src/components/internal/EmojiPicker.tsx.\n *\n * Surrounds the emoji picker, it handles emoji data and coordinates\n * `EmojiPicker.Search` and `EmojiPicker.Content`.\n *\n * @example\n * <EmojiPicker.Root>\n * <EmojiPicker.Search />\n * <EmojiPicker.Content />\n * </EmojiPicker.Root>\n */\nfunction EmojiPickerRoot({\n columns = DEFAULT_COLUMNS,\n locale = DEFAULT_LOCALE,\n onEmojiSelect,\n children,\n}: EmojiPickerRootProps) {\n const emojiData = useRef<EmojiData>();\n const search = useRef(\"\");\n const [, startEmojisTransition] = useTransition();\n const [data, setData] = useState<EmojiPickerData>();\n const [error, setError] = useState<Error>();\n const [selectedColumnIndex, setSelectedColumnIndex] = useState(0);\n const [selectedRowIndex, setSelectedRowIndex] = useState(0);\n const [interaction, setInteraction] = useState<\n \"keyboard\" | \"pointer\" | \"none\"\n >(\"none\");\n\n const selectCurrentEmoji = useCallback(() => {\n if (onEmojiSelect) {\n const emoji = data?.rows[selectedRowIndex]?.[selectedColumnIndex];\n\n if (emoji) {\n onEmojiSelect(emoji.emoji);\n }\n }\n }, [data?.rows, onEmojiSelect, selectedColumnIndex, selectedRowIndex]);\n\n const resetSelection = useCallback(() => {\n setSelectedColumnIndex(0);\n setSelectedRowIndex(0);\n }, []);\n\n const setPointerSelection = useCallback(\n (columnIndex: number, rowIndex: number) => {\n setInteraction(\"pointer\");\n setSelectedColumnIndex(columnIndex);\n setSelectedRowIndex(rowIndex);\n },\n []\n );\n\n const moveSelection = useCallback(\n (\n direction: EmojiPickerSelectionDirection,\n event: KeyboardEvent<HTMLInputElement>\n ) => {\n if (!data) {\n return;\n }\n\n event.preventDefault();\n\n if (interaction === \"none\") {\n setInteraction(\"keyboard\");\n return;\n }\n\n setInteraction(\"keyboard\");\n\n switch (direction) {\n // If first column, move to last column of previous row (if available)\n // Otherwise, move to previous column\n case \"left\": {\n if (selectedColumnIndex === 0) {\n const previousRowIndex = selectedRowIndex - 1;\n const previousRow = data.rows[previousRowIndex];\n\n if (previousRow) {\n setSelectedRowIndex(previousRowIndex);\n setSelectedColumnIndex(previousRow.length - 1);\n }\n } else {\n setSelectedColumnIndex(selectedColumnIndex - 1);\n }\n\n break;\n }\n\n // If last column, move to first column of next row (if available)\n // Otherwise, move to next column\n case \"right\": {\n const currentRow = data.rows[selectedRowIndex];\n\n if (!currentRow) {\n return;\n }\n\n if (selectedColumnIndex === currentRow.length - 1) {\n const nextRowIndex = selectedRowIndex + 1;\n const nextRow = data.rows[nextRowIndex];\n\n if (nextRow) {\n setSelectedRowIndex(nextRowIndex);\n setSelectedColumnIndex(0);\n }\n } else {\n setSelectedColumnIndex(selectedColumnIndex + 1);\n }\n\n break;\n }\n\n // Move to same column of previous row\n // If same column is not available, move to last column of previous row\n case \"up\": {\n const previousRow = data.rows[selectedRowIndex - 1];\n\n if (previousRow) {\n setSelectedRowIndex(selectedRowIndex - 1);\n\n if (!previousRow[selectedColumnIndex]) {\n setSelectedColumnIndex(previousRow.length - 1);\n }\n }\n\n break;\n }\n\n // Move to same column of next row\n // If same column is not available, move to last column of next row\n case \"down\": {\n const nextRow = data.rows[selectedRowIndex + 1];\n\n if (nextRow) {\n setSelectedRowIndex(selectedRowIndex + 1);\n\n if (!nextRow[selectedColumnIndex]) {\n setSelectedColumnIndex(nextRow.length - 1);\n }\n }\n\n break;\n }\n }\n },\n [data, interaction, selectedColumnIndex, selectedRowIndex]\n );\n\n const updateEmojis = useCallback(() => {\n if (!emojiData.current) {\n return;\n }\n\n startEmojisTransition(() => {\n setData(() => {\n if (!emojiData.current) {\n return;\n }\n\n const filteredEmojis = filterEmojis(\n emojiData.current.emojis,\n search.current\n );\n\n return generateEmojiPickerData(\n filteredEmojis,\n emojiData.current.categories,\n columns\n );\n });\n resetSelection();\n });\n }, [columns, resetSelection]);\n\n const handleSearch = useCallback(\n (value: string) => {\n search.current = value;\n updateEmojis();\n },\n [updateEmojis]\n );\n\n const initializeEmojiData = useCallback(\n async (locale: string) => {\n try {\n emojiData.current = await getEmojiData(locale);\n updateEmojis();\n } catch (error) {\n setError(error as Error);\n }\n },\n [updateEmojis]\n );\n\n useEffect(() => {\n let idleCallbackId: number;\n const timeoutId = setTimeout(() => {\n idleCallbackId = requestIdleCallback(() => {\n initializeEmojiData(locale);\n });\n }, LOADING_MINIMUM_TIMEOUT);\n\n return () => {\n clearTimeout(timeoutId);\n cancelIdleCallback(idleCallbackId);\n };\n }, [locale]); // eslint-disable-line react-hooks/exhaustive-deps\n\n useEffect(() => {\n if (interaction === \"none\") {\n resetSelection();\n }\n }, [interaction]); // eslint-disable-line react-hooks/exhaustive-deps\n\n return (\n <EmojiPickerContext.Provider\n value={{\n data: data as EmojiPickerData,\n error: error as undefined,\n isLoading: (!data && !error) as false,\n columns,\n onSearch: handleSearch,\n onEmojiSelect,\n selectCurrentEmoji,\n selectedRowIndex,\n selectedColumnIndex,\n moveSelection,\n setPointerSelection,\n interaction,\n setInteraction,\n }}\n >\n {children}\n </EmojiPickerContext.Provider>\n );\n}\n\n/**\n * @private\n * The EmojiPicker primitive is undocumented for now and subject to change,\n * use at your own risk. If you have any feedback on it, please let us know!\n * See how we use it in the default components to learn how to use it:\n * https://github.com/liveblocks/liveblocks/blob/main/packages/liveblocks-react-ui/src/components/internal/EmojiPicker.tsx.\n *\n * The search input of the emoji picker. It also affects the focus and selection\n * within `EmojiPicker.Content`.\n *\n * @example\n * <EmojiPicker.Search />\n */\nconst EmojiPickerSearch = forwardRef<HTMLInputElement, EmojiPickerSearchProps>(\n ({ asChild, value, defaultValue, onChange, ...props }, forwardedRef) => {\n const Component = asChild ? Slot : \"input\";\n const {\n onSearch,\n selectCurrentEmoji,\n moveSelection,\n interaction,\n setInteraction,\n } = useEmojiPicker();\n\n const handleChange = useCallback(\n (event: ChangeEvent<HTMLInputElement>) => {\n onChange?.(event);\n\n if (event.isDefaultPrevented()) {\n return;\n }\n\n const value = event.target.value;\n setInteraction(value ? \"keyboard\" : \"none\");\n onSearch(value);\n },\n [onChange, onSearch, setInteraction]\n );\n\n const handleKeyDown = useCallback(\n (event: KeyboardEvent<HTMLInputElement>) => {\n if (event.isDefaultPrevented()) {\n return;\n }\n\n if (isKey(event, \"ArrowLeft\")) {\n moveSelection(\"left\", event);\n } else if (isKey(event, \"ArrowRight\")) {\n moveSelection(\"right\", event);\n } else if (isKey(event, \"ArrowUp\")) {\n moveSelection(\"up\", event);\n } else if (isKey(event, \"ArrowDown\")) {\n moveSelection(\"down\", event);\n } else if (isKey(event, \"Enter\")) {\n if (interaction !== \"none\") {\n event.preventDefault();\n selectCurrentEmoji();\n }\n }\n },\n [interaction, moveSelection, selectCurrentEmoji]\n );\n\n useEffect(() => {\n onSearch(\n value ? String(value) : defaultValue ? String(defaultValue) : \"\"\n );\n }, []); // eslint-disable-line react-hooks/exhaustive-deps\n\n return (\n <Component\n type=\"search\"\n value={value}\n defaultValue={defaultValue}\n onChange={handleChange}\n onKeyDown={handleKeyDown}\n {...props}\n ref={forwardedRef}\n />\n );\n }\n);\n\nconst defaultContentComponents: EmojiPickerContentComponents = {\n CategoryHeader: ({ category, ...props }) => <div {...props}>{category}</div>,\n // eslint-disable-next-line @typescript-eslint/no-unused-vars\n Row: ({ children, attributes, ...props }) => <div {...props}>{children}</div>,\n Emoji: ({ emoji, ...props }) => (\n <button {...props}>\n <EmojiPrimitive emoji={emoji} />\n </button>\n ),\n Loading: (props) => <div {...props} />,\n Empty: (props) => <div {...props} />,\n Grid: (props) => <div {...props} />,\n // eslint-disable-next-line @typescript-eslint/no-unused-vars\n Error: ({ error, ...props }) => <div {...props} />,\n};\n\nconst placeholderRowAttributes: EmojiPickerContentEmojiRowAttributes = {\n rowIndex: -1,\n categoryRowIndex: -1,\n categoryRowsCount: 0,\n};\n\n// About `data-testid={undefined}`: Virtuoso bakes test IDs into the components we pass\n// to it, so we manually remove them.\n\nconst VirtuosoScroller = forwardRef<HTMLDivElement, ScrollerProps>(\n ({ children, ...props }, forwardedRef) => {\n return (\n <div {...props} tabIndex={-1} data-testid={undefined} ref={forwardedRef}>\n {children}\n </div>\n );\n }\n);\n\nconst VirtuosoTopList = forwardRef<HTMLDivElement, TopItemListProps>(\n ({ children, ...props }, forwardedRef) => {\n return (\n <div {...props} data-testid={undefined} ref={forwardedRef}>\n {children}\n </div>\n );\n }\n);\n\n/**\n * @private\n * The EmojiPicker primitive is undocumented for now and subject to change,\n * use at your own risk. If you have any feedback on it, please let us know!\n * See how we use it in the default components to learn how to use it:\n * https://github.com/liveblocks/liveblocks/blob/main/packages/liveblocks-react-ui/src/components/internal/EmojiPicker.tsx.\n *\n * The main content of the emoji picker, either displaying the emoji grid or various\n * alternative states (loading, empty, and error).\n *\n * @example\n * <EmojiPicker.Content\n * components={{\n * Loading: EmojiPickerLoading,\n * Empty: EmojiPickerEmpty,\n * Error: EmojiPickerError,\n * CategoryHeader: EmojiPickerCategoryHeader,\n * Grid: EmojiPickerGrid,\n * Row: EmojiPickerRow,\n * Emoji: EmojiPickerEmoji,\n * }}\n * />\n */\nconst EmojiPickerContent = forwardRef<HTMLDivElement, EmojiPickerContentProps>(\n ({ components, asChild, ...props }, forwardedRef) => {\n const Component = asChild ? Slot : \"div\";\n const virtuosoRef = useRef<GroupedVirtuosoHandle>(null);\n const placeholderContainerRef = useRef<HTMLDivElement>(null);\n const rowScrollMarginTopRef = useRef<number>(0);\n const rowScrollMarginBottomRef = useRef<number>(0);\n const categoryHeaderHeightRef = useRef<number>(0);\n const {\n data,\n error,\n isLoading,\n columns,\n onEmojiSelect,\n selectedColumnIndex,\n selectedRowIndex,\n setPointerSelection,\n interaction,\n setInteraction,\n } = useEmojiPicker();\n const selectedEmoji = useMemo(\n () => data?.rows[selectedRowIndex]?.[selectedColumnIndex],\n [data?.rows, selectedColumnIndex, selectedRowIndex]\n );\n const { Loading, Empty, Error, CategoryHeader, Grid, Row, Emoji } = useMemo(\n () => ({ ...defaultContentComponents, ...components }),\n [components]\n );\n const VirtuosoList = useMemo(\n () =>\n forwardRef<HTMLDivElement, VirtuosoListProps>(\n ({ children, ...props }, forwardedRef) => {\n return (\n <div\n role=\"grid\"\n aria-colcount={columns}\n {...props}\n data-testid={undefined}\n ref={forwardedRef}\n >\n {children}\n </div>\n );\n }\n ),\n [columns]\n );\n const placeholderColumns = useMemo(\n () => Array<string>(columns).fill(\"🌫️\"),\n [columns]\n );\n\n const preventDefault = useCallback((event: SyntheticEvent) => {\n event.preventDefault();\n }, []);\n\n const handleEmojiPointerLeave = useCallback(() => {\n if (interaction === \"pointer\") {\n setInteraction(\"none\");\n }\n }, [interaction, setInteraction]);\n\n useLayoutEffect(() => {\n if (!placeholderContainerRef.current) {\n return;\n }\n\n const row = placeholderContainerRef.current.childNodes[0];\n const categoryHeader = placeholderContainerRef.current.childNodes[1];\n\n if (row instanceof HTMLElement) {\n const style = window.getComputedStyle(row);\n\n rowScrollMarginTopRef.current = parseFloat(style.scrollMarginTop);\n rowScrollMarginBottomRef.current = parseFloat(style.scrollMarginBottom);\n }\n\n if (categoryHeader instanceof HTMLElement) {\n categoryHeaderHeightRef.current = categoryHeader.offsetHeight;\n }\n }, []);\n\n // Customize `scrollIntoView` behavior to take into account category headers and margins\n const calculateViewLocation = useCallback(\n ({\n itemTop,\n itemBottom,\n viewportTop,\n viewportBottom,\n locationParams: { behavior, align, ...params },\n }: CalculateViewLocationParams) => {\n if (\n itemTop -\n (categoryHeaderHeightRef.current + rowScrollMarginTopRef.current) <\n viewportTop\n ) {\n return {\n ...params,\n behavior,\n align: align ?? \"start\",\n };\n }\n\n if (itemBottom > viewportBottom) {\n return {\n ...params,\n behavior,\n align: align ?? \"end\",\n offset: rowScrollMarginBottomRef.current,\n };\n }\n\n return null;\n },\n []\n );\n\n useEffect(() => {\n if (interaction === \"keyboard\") {\n virtuosoRef.current?.scrollIntoView({\n index: selectedRowIndex,\n behavior: \"auto\",\n calculateViewLocation,\n });\n }\n }, [interaction, selectedRowIndex, calculateViewLocation]);\n\n return (\n <Component {...props} ref={forwardedRef}>\n <div\n style={{\n visibility: \"hidden\",\n height: 0,\n }}\n ref={placeholderContainerRef}\n >\n {/* Virtualized rows are absolutely positioned so they won't make\n the container automatically pick up their width. To achieve\n an automatic width, we add a relative (but hidden) full row. */}\n <Row attributes={placeholderRowAttributes}>\n {placeholderColumns.map((placeholder, index) => (\n <Emoji emoji={placeholder} key={index} />\n ))}\n </Row>\n {/* We also add a hidden category header to get its computed height. */}\n <CategoryHeader category=\"Category\" />\n </div>\n {isLoading ? (\n <Loading />\n ) : error ? (\n <Error error={error} />\n ) : data.count === 0 ? (\n <Empty />\n ) : (\n <Grid>\n <GroupedVirtuoso\n ref={virtuosoRef}\n components={{\n Scroller: VirtuosoScroller,\n List: VirtuosoList,\n TopItemList: VirtuosoTopList,\n }}\n groupCounts={data.categoriesRowCounts}\n groupContent={(groupIndex) => {\n const category = data.categories[groupIndex];\n\n if (!category) {\n return null;\n }\n\n return <CategoryHeader category={category} />;\n }}\n itemContent={(rowIndex, groupIndex) => {\n const categoryRow = data.rows[rowIndex];\n const categoryRowIndex =\n data.categoriesRowIndices[groupIndex]?.indexOf(rowIndex);\n const categoryRowsCount = data.categoriesRowCounts[groupIndex];\n\n if (\n categoryRow === undefined ||\n categoryRowIndex === undefined ||\n categoryRowsCount === undefined\n ) {\n return null;\n }\n\n return (\n <Row\n attributes={{\n rowIndex,\n categoryRowIndex,\n categoryRowsCount,\n }}\n >\n {categoryRow.map((emoji, columnIndex) => {\n const isSelected =\n interaction !== \"none\" &&\n selectedColumnIndex === columnIndex &&\n selectedRowIndex === rowIndex;\n\n return (\n <Emoji\n key={emoji.emoji}\n role=\"gridcell\"\n aria-colindex={columnIndex}\n aria-selected={isSelected || undefined}\n data-selected={isSelected || undefined}\n onMouseDown={preventDefault}\n tabIndex={-1}\n onPointerEnter={() => {\n setPointerSelection(columnIndex, rowIndex);\n }}\n onPointerLeave={handleEmojiPointerLeave}\n onClick={(event) => {\n onEmojiSelect?.(emoji.emoji);\n event.stopPropagation();\n }}\n emoji={emoji.emoji}\n />\n );\n })}\n </Row>\n );\n }}\n />\n </Grid>\n )}\n {selectedEmoji && interaction !== \"none\" && (\n <div aria-live=\"polite\" style={visuallyHidden}>\n {selectedEmoji.name}\n </div>\n )}\n </Component>\n );\n }\n);\n\nif (process.env.NODE_ENV !== \"production\") {\n EmojiPickerRoot.displayName = EMOJIPICKER_ROOT_NAME;\n EmojiPickerContent.displayName = EMOJIPICKER_CONTENT_NAME;\n EmojiPickerSearch.displayName = EMOJIPICKER_SEARCH_NAME;\n}\n\n// NOTE: Every export from this file will be available publicly as EmojiPicker.*\nexport {\n EmojiPickerContent as Content,\n EmojiPickerRoot as Root,\n EmojiPickerSearch as Search,\n};\n"],"names":[],"mappings":";;;;;;;;;;;;;AAAA;AA2CA;AACA;AACA;AAEA;AACA;AACA;AAkBA;AAAyB;AACb;AACD;AACT;AAEF;AACE;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AAIA;AACE;AACE;AAEA;AACE;AAAyB;AAC3B;AACF;AAGF;AACE;AACA;AAAqB;AAGvB;AAA4B;AAExB;AACA;AACA;AAA4B;AAC9B;AACC;AAGH;AAAsB;AAKlB;AACE;AAAA;AAGF;AAEA;AACE;AACA;AAAA;AAGF;AAEA;AAAmB;AAIf;AACE;AACA;AAEA;AACE;AACA;AAA6C;AAC/C;AAEA;AAA8C;AAGhD;AAAA;AACF;AAKE;AAEA;AACE;AAAA;AAGF;AACE;AACA;AAEA;AACE;AACA;AAAwB;AAC1B;AAEA;AAA8C;AAGhD;AAAA;AACF;AAKE;AAEA;AACE;AAEA;AACE;AAA6C;AAC/C;AAGF;AAAA;AACF;AAKE;AAEA;AACE;AAEA;AACE;AAAyC;AAC3C;AAGF;AAAA;AACF;AACF;AACF;AACyD;AAG3D;AACE;AACE;AAAA;AAGF;AACE;AACE;AACE;AAAA;AAGF;AAAuB;AACH;AACX;AAGT;AAAO;AACL;AACkB;AAClB;AACF;AAEF;AAAe;AAChB;AAGH;AAAqB;AAEjB;AACA;AAAa;AACf;AACa;AAGf;AAA4B;AAExB;AACE;AACA;AAAa;AAEb;AAAuB;AACzB;AACF;AACa;AAGf;AACE;AACA;AACE;AACE;AAA0B;AAC3B;AAGH;AACE;AACA;AAAiC;AACnC;AAGF;AACE;AACE;AAAe;AACjB;AAGF;AACG;AACQ;AACL;AACA;AACsB;AACtB;AACU;AACV;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACF;AAEC;AAGP;AAeA;AAA0B;AAEtB;AACA;AAAM;AACJ;AACA;AACA;AACA;AACA;AAGF;AAAqB;AAEjB;AAEA;AACE;AAAA;AAGF;AACA;AACA;AAAc;AAChB;AACmC;AAGrC;AAAsB;AAElB;AACE;AAAA;AAGF;AACE;AAA2B;AAE3B;AAA4B;AAE5B;AAAyB;AAEzB;AAA2B;AAE3B;AACE;AACA;AAAmB;AACrB;AACF;AACF;AAC+C;AAGjD;AACE;AAAA;AACgE;AAChE;AAGF;AACG;AACM;AACL;AACA;AACU;AACC;AACP;AACC;AACP;AAGN;AAEA;AAA+D;AAChB;AAAQ;AAAQ;AAAS;AAExB;AAAQ;AAAQ;AAAS;AAEpE;AAAW;AACT;AAAe;AAAc;AAChC;AAEmB;AAAQ;AAAO;AACjB;AAAQ;AAAO;AAChB;AAAQ;AAAO;AAEA;AAAQ;AAC3C;AAEA;AAAuE;AAC3D;AACQ;AAEpB;AAKA;AAAyB;AAErB;AACG;AAAQ;AAAiB;AAAiB;AAAgB;AACxD;AACH;AAGN;AAEA;AAAwB;AAEpB;AACG;AAAQ;AAAoB;AAAgB;AAC1C;AACH;AAGN;AAyBA;AAA2B;AAEvB;AACA;AACA;AACA;AACA;AACA;AACA;AAAM;AACJ;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AAEF;AAAsB;AACiB;AACa;AAEpD;AAAoE;AACd;AACzC;AAEb;AAAqB;AAEjB;AAEI;AACG;AACM;AACU;AACX;AACS;AACR;AAEJ;AACH;AAEJ;AACF;AACM;AAEV;AAA2B;AACc;AAC/B;AAGV;AACE;AAAqB;AAGvB;AACE;AACE;AAAqB;AACvB;AAGF;AACE;AACE;AAAA;AAGF;AACA;AAEA;AACE;AAEA;AACA;AAAsE;AAGxE;AACE;AAAiD;AACnD;AAIF;AAA8B;AAC3B;AACC;AACA;AACA;AACA;AAC6C;AAE7C;AAKE;AAAO;AACF;AACH;AACgB;AAClB;AAGF;AACE;AAAO;AACF;AACH;AACgB;AACiB;AACnC;AAGF;AAAO;AACT;AACC;AAGH;AACE;AACE;AAAoC;AAC3B;AACG;AACV;AACD;AACH;AAGF;AACG;AAAc;AAAY;AACzB;AAAC;AACQ;AACO;AACJ;AACV;AACK;AAKL;AAAC;AAAgB;AAEZ;AAAa;AACf;AACH;AAEC;AAAwB;AAAW;AAAA;AACtC;AAIG;AAAM;AAIN;AACE;AACM;AACO;AACA;AACJ;AACO;AACf;AACkB;AAEhB;AAEA;AACE;AAAO;AAGT;AAAQ;AAAe;AAAoB;AAC7C;AAEE;AACA;AAEA;AAEA;AAKE;AAAO;AAGT;AACG;AACa;AACV;AACA;AACA;AACF;AAGE;AAKA;AACG;AAEM;AACU;AACc;AACA;AAChB;AACH;AAER;AAAyC;AAC3C;AACgB;AAEd;AACA;AAAsB;AACxB;AACa;AACf;AAEH;AACH;AAEJ;AACF;AACF;AAGC;AAAc;AAAgB;AACd;AACjB;AAAA;AAEJ;AAGN;AAEA;AACE;AACA;AACA;AACF;;"}