@tensor_1/react 2.26.1 → 2.26.3
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/dist/components/EmojiPicker.d.ts +3 -0
- package/dist/components/EmojiPicker.js +109 -54
- package/dist/components/Popover.d.ts +15 -5
- package/dist/components/Popover.js +66 -6
- package/dist/{emoji-image-WQLh8ZQP.d.cts → emoji-image-6mPZ15Zy.d.cts} +4 -1
- package/dist/emoji.cjs +324 -74
- package/dist/emoji.d.cts +3 -3
- package/dist/hooks/useAnchoredPosition.d.ts +13 -5
- package/dist/hooks/useAnchoredPosition.js +146 -15
- package/dist/hooks/useDialog.js +1 -0
- package/dist/index.cjs +225 -29
- package/dist/index.d.cts +26 -11
- package/dist/{overlay-position-CEGSz6Z2.d.cts → overlay-position-Cjv5E7mn.d.cts} +7 -0
- package/dist/overlay-position.d.ts +7 -0
- package/dist/overlay-position.js +7 -2
- package/dist/rich-text.cjs +324 -74
- package/dist/rich-text.d.cts +3 -3
- package/package.json +1 -1
|
@@ -54,6 +54,9 @@ declare const EMOJI_GRID_COLUMNS = 8;
|
|
|
54
54
|
* Emoji picker in a native popover: search, quick picks, recently used and the
|
|
55
55
|
* Unicode categories, with names in English or German. The emoji dataset loads on
|
|
56
56
|
* first open. The grid is one tab stop; arrow keys, Home and End move within it.
|
|
57
|
+
* The picker is one size in every state (loading, searching, failed), so it keeps the
|
|
58
|
+
* side it opened on; it stays attached to its trigger while the page scrolls and
|
|
59
|
+
* closes once the trigger is scrolled out of view.
|
|
57
60
|
*/
|
|
58
61
|
declare function EmojiPicker({ onSelect, trigger, labels: labelOverrides, locale, quickPicks, loadData, recentStorageKey, placement, onOpenChange, className, emojiImageBaseUrl, }: EmojiPickerProps): react.JSX.Element;
|
|
59
62
|
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
"use client";
|
|
2
2
|
import { jsx, jsxs } from "react/jsx-runtime";
|
|
3
|
-
import { cloneElement, isValidElement, useCallback, useEffect, useId, useMemo, useRef, useState } from "react";
|
|
3
|
+
import { cloneElement, isValidElement, useCallback, useEffect, useId, useLayoutEffect, useMemo, useRef, useState } from "react";
|
|
4
4
|
import { cx } from "../cx.js";
|
|
5
5
|
import { Popover } from "./Popover.js";
|
|
6
6
|
import {
|
|
@@ -23,6 +23,14 @@ const DEFAULT_EMOJI_PICKER_LABELS = {
|
|
|
23
23
|
loadFailed: "Emoji could not be loaded."
|
|
24
24
|
};
|
|
25
25
|
const EMOJI_GRID_COLUMNS = 8;
|
|
26
|
+
const useIsomorphicLayoutEffect = typeof document !== "undefined" ? useLayoutEffect : useEffect;
|
|
27
|
+
function revealInGrid(grid, cell) {
|
|
28
|
+
const g = grid.getBoundingClientRect();
|
|
29
|
+
const c = cell.getBoundingClientRect();
|
|
30
|
+
const top = g.top + (parseFloat(getComputedStyle(grid).scrollPaddingTop) || 0);
|
|
31
|
+
if (c.top < top) grid.scrollTop -= top - c.top;
|
|
32
|
+
else if (c.bottom > g.bottom) grid.scrollTop += c.bottom - g.bottom;
|
|
33
|
+
}
|
|
26
34
|
function EmojiPicker({
|
|
27
35
|
onSelect,
|
|
28
36
|
trigger,
|
|
@@ -44,6 +52,8 @@ function EmojiPicker({
|
|
|
44
52
|
const searchRef = useRef(null);
|
|
45
53
|
const gridRef = useRef(null);
|
|
46
54
|
const pointerWasOpen = useRef(null);
|
|
55
|
+
const closedByAnchor = useRef(false);
|
|
56
|
+
const pendingJump = useRef(null);
|
|
47
57
|
const [open, setOpen] = useState(false);
|
|
48
58
|
const [data, setData] = useState(null);
|
|
49
59
|
const [failed, setFailed] = useState(false);
|
|
@@ -67,10 +77,14 @@ function EmojiPicker({
|
|
|
67
77
|
setOpen(nowOpen);
|
|
68
78
|
onOpenChange?.(nowOpen);
|
|
69
79
|
if (nowOpen) {
|
|
80
|
+
closedByAnchor.current = false;
|
|
81
|
+
pendingJump.current = null;
|
|
70
82
|
setRecent(readRecentEmoji(recentStorageKey));
|
|
71
83
|
setQuery("");
|
|
72
84
|
setActive(0);
|
|
73
|
-
requestAnimationFrame(() => searchRef.current?.focus());
|
|
85
|
+
requestAnimationFrame(() => searchRef.current?.focus({ preventScroll: true }));
|
|
86
|
+
} else if (closedByAnchor.current) {
|
|
87
|
+
closedByAnchor.current = false;
|
|
74
88
|
} else if (el.contains(document.activeElement) || document.activeElement === document.body) {
|
|
75
89
|
focusTrigger();
|
|
76
90
|
}
|
|
@@ -102,10 +116,7 @@ function EmojiPicker({
|
|
|
102
116
|
const el = popoverEl();
|
|
103
117
|
if (el && isOpen(el)) el.hidePopover();
|
|
104
118
|
};
|
|
105
|
-
const
|
|
106
|
-
if (query.trim()) {
|
|
107
|
-
return data ? [{ key: "results", title: labels.search, emojis: searchEmoji(data, query).map((e) => e.emoji) }] : [];
|
|
108
|
-
}
|
|
119
|
+
const browseSections = useMemo(() => {
|
|
109
120
|
const list = [];
|
|
110
121
|
if (quickPicks?.length) list.push({ key: "quick", title: labels.quickPicks, emojis: [...new Set(quickPicks)] });
|
|
111
122
|
if (recent.length) list.push({ key: "recent", title: labels.recent, emojis: recent });
|
|
@@ -115,7 +126,11 @@ function EmojiPicker({
|
|
|
115
126
|
});
|
|
116
127
|
}
|
|
117
128
|
return list;
|
|
118
|
-
}, [
|
|
129
|
+
}, [data, quickPicks, recent, labels.quickPicks, labels.recent]);
|
|
130
|
+
const sections = useMemo(() => {
|
|
131
|
+
if (!query.trim()) return browseSections;
|
|
132
|
+
return data ? [{ key: "results", title: labels.search, emojis: searchEmoji(data, query).map((e) => e.emoji) }] : [];
|
|
133
|
+
}, [query, data, browseSections, labels.search]);
|
|
119
134
|
const flat = useMemo(() => sections.flatMap((s) => s.emojis), [sections]);
|
|
120
135
|
const sectionStart = useMemo(() => {
|
|
121
136
|
const starts = /* @__PURE__ */ new Map();
|
|
@@ -132,13 +147,43 @@ function EmojiPicker({
|
|
|
132
147
|
onSelect(emoji);
|
|
133
148
|
hide();
|
|
134
149
|
};
|
|
135
|
-
const focusCell = useCallback((index) => {
|
|
150
|
+
const focusCell = useCallback((index, reveal = true) => {
|
|
136
151
|
setActive(index);
|
|
137
152
|
const find = () => gridRef.current?.querySelector(`[data-emoji-index="${index}"]`);
|
|
153
|
+
const move = (cell2) => {
|
|
154
|
+
cell2.focus({ preventScroll: true });
|
|
155
|
+
if (reveal && gridRef.current) revealInGrid(gridRef.current, cell2);
|
|
156
|
+
};
|
|
138
157
|
const cell = find();
|
|
139
|
-
if (cell) cell
|
|
140
|
-
else requestAnimationFrame(() =>
|
|
158
|
+
if (cell) move(cell);
|
|
159
|
+
else requestAnimationFrame(() => {
|
|
160
|
+
const later = find();
|
|
161
|
+
if (later) move(later);
|
|
162
|
+
});
|
|
141
163
|
}, []);
|
|
164
|
+
const showSection = (key) => {
|
|
165
|
+
const grid = gridRef.current;
|
|
166
|
+
const section = grid?.querySelector(`[data-section="${key}"]`);
|
|
167
|
+
if (!grid || !section) return;
|
|
168
|
+
grid.scrollTop += section.getBoundingClientRect().top - grid.getBoundingClientRect().top;
|
|
169
|
+
const start = sectionStart.get(key);
|
|
170
|
+
if (start !== void 0) focusCell(start, false);
|
|
171
|
+
};
|
|
172
|
+
const onCategory = (key) => {
|
|
173
|
+
if (!query.trim()) {
|
|
174
|
+
showSection(key);
|
|
175
|
+
return;
|
|
176
|
+
}
|
|
177
|
+
pendingJump.current = key;
|
|
178
|
+
setQuery("");
|
|
179
|
+
setActive(0);
|
|
180
|
+
};
|
|
181
|
+
useIsomorphicLayoutEffect(() => {
|
|
182
|
+
const key = pendingJump.current;
|
|
183
|
+
if (key === null || query.trim()) return;
|
|
184
|
+
pendingJump.current = null;
|
|
185
|
+
showSection(key);
|
|
186
|
+
}, [query, sections]);
|
|
142
187
|
const onGridKeyDown = (event) => {
|
|
143
188
|
const target = event.target;
|
|
144
189
|
const index = Number(target.dataset.emojiIndex ?? -1);
|
|
@@ -146,7 +191,7 @@ function EmojiPicker({
|
|
|
146
191
|
const next = emojiGridMove(index, event.key, flat.length, EMOJI_GRID_COLUMNS);
|
|
147
192
|
if (event.key === "ArrowUp" && next === null) {
|
|
148
193
|
event.preventDefault();
|
|
149
|
-
searchRef.current?.focus();
|
|
194
|
+
searchRef.current?.focus({ preventScroll: true });
|
|
150
195
|
return;
|
|
151
196
|
}
|
|
152
197
|
if (next === null) return;
|
|
@@ -202,6 +247,10 @@ function EmojiPicker({
|
|
|
202
247
|
className: "uix-emoji-picker-popover",
|
|
203
248
|
role: "dialog",
|
|
204
249
|
"aria-label": labels.dialog,
|
|
250
|
+
closeWhenAnchorHidden: true,
|
|
251
|
+
onAnchorHidden: () => {
|
|
252
|
+
closedByAnchor.current = true;
|
|
253
|
+
},
|
|
205
254
|
children: open ? /* @__PURE__ */ jsxs("div", { className: "uix-emoji-picker uix-emoji-picker--full", lang: locale, children: [
|
|
206
255
|
/* @__PURE__ */ jsx(
|
|
207
256
|
"input",
|
|
@@ -221,50 +270,56 @@ function EmojiPicker({
|
|
|
221
270
|
spellCheck: false
|
|
222
271
|
}
|
|
223
272
|
),
|
|
224
|
-
|
|
225
|
-
"
|
|
273
|
+
/* @__PURE__ */ jsx(
|
|
274
|
+
"div",
|
|
226
275
|
{
|
|
227
|
-
|
|
228
|
-
|
|
229
|
-
"aria-label":
|
|
230
|
-
|
|
231
|
-
|
|
232
|
-
|
|
233
|
-
|
|
234
|
-
|
|
235
|
-
|
|
236
|
-
|
|
237
|
-
|
|
238
|
-
|
|
239
|
-
|
|
240
|
-
|
|
241
|
-
|
|
242
|
-
|
|
243
|
-
|
|
244
|
-
|
|
245
|
-
|
|
246
|
-
|
|
247
|
-
|
|
248
|
-
|
|
249
|
-
|
|
250
|
-
|
|
251
|
-
|
|
252
|
-
|
|
253
|
-
|
|
254
|
-
|
|
255
|
-
|
|
256
|
-
|
|
257
|
-
|
|
258
|
-
|
|
259
|
-
|
|
260
|
-
|
|
261
|
-
|
|
262
|
-
|
|
263
|
-
|
|
264
|
-
|
|
265
|
-
|
|
266
|
-
|
|
267
|
-
|
|
276
|
+
className: "uix-emoji-picker__nav",
|
|
277
|
+
role: data ? "group" : void 0,
|
|
278
|
+
"aria-label": data ? labels.categories : void 0,
|
|
279
|
+
children: data ? browseSections.map((section) => /* @__PURE__ */ jsx(
|
|
280
|
+
"button",
|
|
281
|
+
{
|
|
282
|
+
type: "button",
|
|
283
|
+
className: "uix-emoji-picker__nav-btn",
|
|
284
|
+
"aria-label": section.title,
|
|
285
|
+
title: section.title,
|
|
286
|
+
onClick: () => onCategory(section.key),
|
|
287
|
+
children: /* @__PURE__ */ jsx("span", { "aria-hidden": "true", children: section.emojis[0] ? renderEmoji(section.emojis[0]) : null })
|
|
288
|
+
},
|
|
289
|
+
section.key
|
|
290
|
+
)) : null
|
|
291
|
+
}
|
|
292
|
+
),
|
|
293
|
+
/* @__PURE__ */ jsxs("div", { className: "uix-emoji-picker__grid", ref: gridRef, onKeyDown: onGridKeyDown, children: [
|
|
294
|
+
sections.map((section) => {
|
|
295
|
+
const start = offset;
|
|
296
|
+
offset += section.emojis.length;
|
|
297
|
+
if (!section.emojis.length) return null;
|
|
298
|
+
const headingId = `${id}-${section.key}`;
|
|
299
|
+
return /* @__PURE__ */ jsxs("section", { className: "uix-emoji-picker__section", "data-section": section.key, "aria-labelledby": headingId, children: [
|
|
300
|
+
/* @__PURE__ */ jsx("h3", { id: headingId, className: "uix-emoji-picker__heading", children: section.title }),
|
|
301
|
+
/* @__PURE__ */ jsx("div", { className: "uix-emoji-picker__cells", role: "group", "aria-labelledby": headingId, children: section.emojis.map((emoji, i) => {
|
|
302
|
+
const index = start + i;
|
|
303
|
+
return /* @__PURE__ */ jsx(
|
|
304
|
+
"button",
|
|
305
|
+
{
|
|
306
|
+
type: "button",
|
|
307
|
+
className: "uix-emoji-picker__btn",
|
|
308
|
+
"data-emoji-index": index,
|
|
309
|
+
tabIndex: index === activeIndex ? 0 : -1,
|
|
310
|
+
"aria-label": names?.get(emoji) ?? emoji,
|
|
311
|
+
title: names?.get(emoji),
|
|
312
|
+
onClick: () => choose(emoji),
|
|
313
|
+
onFocus: () => setActive(index),
|
|
314
|
+
children: renderEmoji(emoji)
|
|
315
|
+
},
|
|
316
|
+
`${section.key}-${emoji}`
|
|
317
|
+
);
|
|
318
|
+
}) })
|
|
319
|
+
] }, section.key);
|
|
320
|
+
}),
|
|
321
|
+
/* @__PURE__ */ jsx("p", { className: "uix-emoji-picker__status", role: "status", children: status })
|
|
322
|
+
] })
|
|
268
323
|
] }) : null
|
|
269
324
|
}
|
|
270
325
|
)
|
|
@@ -10,16 +10,26 @@ interface PopoverProps extends HTMLAttributes<HTMLDivElement> {
|
|
|
10
10
|
popover?: 'auto' | 'manual';
|
|
11
11
|
/**
|
|
12
12
|
* Element (or ref) to anchor against. When set, the popover is placed with
|
|
13
|
-
* cross-browser JS positioning — flip when it won't fit, shift to stay on-screen
|
|
14
|
-
*
|
|
15
|
-
*
|
|
16
|
-
* the top layer (so it
|
|
13
|
+
* cross-browser JS positioning — flip when it won't fit, shift to stay on-screen.
|
|
14
|
+
* Where the browser supports CSS anchor positioning, the placement is written as an
|
|
15
|
+
* offset from the anchor, so it stays attached while the page scrolls; elsewhere it
|
|
16
|
+
* follows scroll from JS. The native Popover API still provides the top layer (so it
|
|
17
|
+
* escapes `overflow` clipping) and light-dismiss.
|
|
17
18
|
*/
|
|
18
19
|
anchor?: RefObject<HTMLElement | null> | HTMLElement | null;
|
|
19
20
|
/** Preferred placement when `anchor` is set. Default `'bottom-start'`. */
|
|
20
21
|
placement?: Placement;
|
|
21
22
|
/** Gap between the trigger and the popover, in px. Default 6. */
|
|
22
23
|
offset?: number;
|
|
24
|
+
/**
|
|
25
|
+
* Close the popover once its `anchor` has scrolled completely out of view (outside the
|
|
26
|
+
* viewport or a clipping ancestor), e.g. a picker opened from an editor that the user
|
|
27
|
+
* scrolls away from. Focus inside the popover is let go rather than sent back to the
|
|
28
|
+
* hidden anchor. Needs `anchor`. Default `false`.
|
|
29
|
+
*/
|
|
30
|
+
closeWhenAnchorHidden?: boolean;
|
|
31
|
+
/** Called when `closeWhenAnchorHidden` is about to close the popover. */
|
|
32
|
+
onAnchorHidden?: () => void;
|
|
23
33
|
children?: ReactNode;
|
|
24
34
|
}
|
|
25
35
|
/**
|
|
@@ -27,6 +37,6 @@ interface PopoverProps extends HTMLAttributes<HTMLDivElement> {
|
|
|
27
37
|
* things like a filter popover, menu, or rich select by putting controls inside.
|
|
28
38
|
* Pass `anchor` to get collision-aware, cross-browser placement (UIX-FIX-02).
|
|
29
39
|
*/
|
|
30
|
-
declare function Popover({ popover, anchor, placement, offset, className, children, ...props }: PopoverProps): react.JSX.Element;
|
|
40
|
+
declare function Popover({ popover, anchor, placement, offset, closeWhenAnchorHidden, onAnchorHidden, className, children, ...props }: PopoverProps): react.JSX.Element;
|
|
31
41
|
|
|
32
42
|
export { Popover, type PopoverProps };
|
|
@@ -1,19 +1,38 @@
|
|
|
1
1
|
"use client";
|
|
2
2
|
import { jsx } from "react/jsx-runtime";
|
|
3
|
-
import { useEffect, useRef, useState } from "react";
|
|
3
|
+
import { useEffect, useLayoutEffect, useRef, useState } from "react";
|
|
4
4
|
import { cx } from "../cx.js";
|
|
5
|
-
import { useAnchoredPosition } from "../hooks/useAnchoredPosition.js";
|
|
5
|
+
import { resolveAnchor, useAnchoredPosition } from "../hooks/useAnchoredPosition.js";
|
|
6
|
+
const useIsomorphicLayoutEffect = typeof document !== "undefined" ? useLayoutEffect : useEffect;
|
|
7
|
+
const PLACING = "data-uix-placing";
|
|
8
|
+
const isPopoverOpen = (el) => {
|
|
9
|
+
try {
|
|
10
|
+
return el.matches(":popover-open");
|
|
11
|
+
} catch {
|
|
12
|
+
return false;
|
|
13
|
+
}
|
|
14
|
+
};
|
|
15
|
+
const settle = (el) => {
|
|
16
|
+
if (!el.hasAttribute(PLACING)) return;
|
|
17
|
+
getComputedStyle(el).getPropertyValue("transform");
|
|
18
|
+
el.removeAttribute(PLACING);
|
|
19
|
+
};
|
|
6
20
|
function Popover({
|
|
7
21
|
popover = "auto",
|
|
8
22
|
anchor,
|
|
9
23
|
placement = "bottom-start",
|
|
10
24
|
offset = 6,
|
|
25
|
+
closeWhenAnchorHidden = false,
|
|
26
|
+
onAnchorHidden,
|
|
11
27
|
className,
|
|
12
28
|
children,
|
|
13
29
|
...props
|
|
14
30
|
}) {
|
|
15
31
|
const ref = useRef(null);
|
|
16
32
|
const [open, setOpen] = useState(false);
|
|
33
|
+
const openRef = useRef(false);
|
|
34
|
+
const onAnchorHiddenRef = useRef(onAnchorHidden);
|
|
35
|
+
onAnchorHiddenRef.current = onAnchorHidden;
|
|
17
36
|
const popoverAttr = { popover };
|
|
18
37
|
const reposition = useAnchoredPosition(anchor ?? null, ref, {
|
|
19
38
|
open: open && !!anchor,
|
|
@@ -23,14 +42,55 @@ function Popover({
|
|
|
23
42
|
useEffect(() => {
|
|
24
43
|
const el = ref.current;
|
|
25
44
|
if (!el || !anchor) return;
|
|
45
|
+
const hold = (event) => {
|
|
46
|
+
if (event.newState !== "open") return;
|
|
47
|
+
el.setAttribute(PLACING, "");
|
|
48
|
+
window.setTimeout(() => settle(el), 150);
|
|
49
|
+
};
|
|
26
50
|
const sync = () => {
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
51
|
+
if (!isPopoverOpen(el)) {
|
|
52
|
+
el.removeAttribute(PLACING);
|
|
53
|
+
setOpen(false);
|
|
54
|
+
return;
|
|
55
|
+
}
|
|
56
|
+
reposition();
|
|
57
|
+
window.setTimeout(() => {
|
|
58
|
+
if (!isPopoverOpen(el)) return;
|
|
59
|
+
if (!openRef.current) {
|
|
60
|
+
setOpen(true);
|
|
61
|
+
return;
|
|
62
|
+
}
|
|
63
|
+
reposition();
|
|
64
|
+
settle(el);
|
|
65
|
+
}, 0);
|
|
30
66
|
};
|
|
67
|
+
el.addEventListener("beforetoggle", hold);
|
|
31
68
|
el.addEventListener("toggle", sync);
|
|
32
|
-
return () =>
|
|
69
|
+
return () => {
|
|
70
|
+
el.removeEventListener("beforetoggle", hold);
|
|
71
|
+
el.removeEventListener("toggle", sync);
|
|
72
|
+
el.removeAttribute(PLACING);
|
|
73
|
+
};
|
|
33
74
|
}, [anchor, reposition]);
|
|
75
|
+
useIsomorphicLayoutEffect(() => {
|
|
76
|
+
openRef.current = open;
|
|
77
|
+
if (open && ref.current) settle(ref.current);
|
|
78
|
+
}, [open]);
|
|
79
|
+
useEffect(() => {
|
|
80
|
+
const el = ref.current;
|
|
81
|
+
const anchorEl = resolveAnchor(anchor);
|
|
82
|
+
if (!closeWhenAnchorHidden || !open || !el || !anchorEl || typeof IntersectionObserver !== "function") return;
|
|
83
|
+
const observer = new IntersectionObserver((entries) => {
|
|
84
|
+
const latest = entries[entries.length - 1];
|
|
85
|
+
if (!latest || latest.isIntersecting || !isPopoverOpen(el)) return;
|
|
86
|
+
onAnchorHiddenRef.current?.();
|
|
87
|
+
const active = el.ownerDocument.activeElement;
|
|
88
|
+
if (active && el.contains(active)) active.blur();
|
|
89
|
+
el.hidePopover();
|
|
90
|
+
});
|
|
91
|
+
observer.observe(anchorEl);
|
|
92
|
+
return () => observer.disconnect();
|
|
93
|
+
}, [closeWhenAnchorHidden, open, anchor]);
|
|
34
94
|
return /* @__PURE__ */ jsx("div", { ref, className: cx("uix-popover", className), ...popoverAttr, ...props, children });
|
|
35
95
|
}
|
|
36
96
|
export {
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import * as react from 'react';
|
|
2
2
|
import { ReactElement } from 'react';
|
|
3
|
-
import { P as Placement } from './overlay-position-
|
|
3
|
+
import { P as Placement } from './overlay-position-Cjv5E7mn.cjs';
|
|
4
4
|
|
|
5
5
|
type EmojiLocale = 'en' | 'de';
|
|
6
6
|
interface EmojiEntry {
|
|
@@ -106,6 +106,9 @@ declare const EMOJI_GRID_COLUMNS = 8;
|
|
|
106
106
|
* Emoji picker in a native popover: search, quick picks, recently used and the
|
|
107
107
|
* Unicode categories, with names in English or German. The emoji dataset loads on
|
|
108
108
|
* first open. The grid is one tab stop; arrow keys, Home and End move within it.
|
|
109
|
+
* The picker is one size in every state (loading, searching, failed), so it keeps the
|
|
110
|
+
* side it opened on; it stays attached to its trigger while the page scrolls and
|
|
111
|
+
* closes once the trigger is scrolled out of view.
|
|
109
112
|
*/
|
|
110
113
|
declare function EmojiPicker({ onSelect, trigger, labels: labelOverrides, locale, quickPicks, loadData, recentStorageKey, placement, onOpenChange, className, emojiImageBaseUrl, }: EmojiPickerProps): react.JSX.Element;
|
|
111
114
|
|