@tensor_1/react 2.26.2 → 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/index.cjs +224 -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
package/dist/overlay-position.js
CHANGED
|
@@ -21,10 +21,15 @@ function fitsOn(side, a, f, vp, offset, padding) {
|
|
|
21
21
|
return spaceOn(side, a, vp, offset) >= need + padding;
|
|
22
22
|
}
|
|
23
23
|
function computePosition(anchor, floating, viewport, options = {}) {
|
|
24
|
-
const { placement = "bottom-start", offset = 6, padding = 8, flip = true, shift = true } = options;
|
|
24
|
+
const { placement = "bottom-start", offset = 6, padding = 8, flip = true, shift = true, stickySide } = options;
|
|
25
25
|
const { side: preferred, align } = parsePlacement(placement);
|
|
26
26
|
let side = preferred;
|
|
27
|
-
|
|
27
|
+
const sticky = stickySide === preferred || stickySide === OPPOSITE[preferred] ? stickySide : void 0;
|
|
28
|
+
if (flip && sticky) {
|
|
29
|
+
side = sticky;
|
|
30
|
+
const opp = OPPOSITE[side];
|
|
31
|
+
if (!fitsOn(side, anchor, floating, viewport, offset, padding) && fitsOn(opp, anchor, floating, viewport, offset, padding)) side = opp;
|
|
32
|
+
} else if (flip && !fitsOn(side, anchor, floating, viewport, offset, padding)) {
|
|
28
33
|
const opp = OPPOSITE[side];
|
|
29
34
|
if (fitsOn(opp, anchor, floating, viewport, offset, padding) || spaceOn(opp, anchor, viewport, offset) > spaceOn(side, anchor, viewport, offset)) {
|
|
30
35
|
side = opp;
|
package/dist/rich-text.cjs
CHANGED
|
@@ -79,10 +79,15 @@ function fitsOn(side, a, f, vp, offset, padding) {
|
|
|
79
79
|
return spaceOn(side, a, vp, offset) >= need + padding;
|
|
80
80
|
}
|
|
81
81
|
function computePosition(anchor, floating, viewport, options = {}) {
|
|
82
|
-
const { placement = "bottom-start", offset = 6, padding = 8, flip = true, shift = true } = options;
|
|
82
|
+
const { placement = "bottom-start", offset = 6, padding = 8, flip = true, shift = true, stickySide } = options;
|
|
83
83
|
const { side: preferred, align } = parsePlacement(placement);
|
|
84
84
|
let side = preferred;
|
|
85
|
-
|
|
85
|
+
const sticky = stickySide === preferred || stickySide === OPPOSITE[preferred] ? stickySide : void 0;
|
|
86
|
+
if (flip && sticky) {
|
|
87
|
+
side = sticky;
|
|
88
|
+
const opp = OPPOSITE[side];
|
|
89
|
+
if (!fitsOn(side, anchor, floating, viewport, offset, padding) && fitsOn(opp, anchor, floating, viewport, offset, padding)) side = opp;
|
|
90
|
+
} else if (flip && !fitsOn(side, anchor, floating, viewport, offset, padding)) {
|
|
86
91
|
const opp = OPPOSITE[side];
|
|
87
92
|
if (fitsOn(opp, anchor, floating, viewport, offset, padding) || spaceOn(opp, anchor, viewport, offset) > spaceOn(side, anchor, viewport, offset)) {
|
|
88
93
|
side = opp;
|
|
@@ -762,57 +767,206 @@ var import_react4 = require("react");
|
|
|
762
767
|
// src/hooks/useAnchoredPosition.ts
|
|
763
768
|
var import_react3 = require("react");
|
|
764
769
|
var useIsomorphicLayoutEffect = typeof document !== "undefined" ? import_react3.useLayoutEffect : import_react3.useEffect;
|
|
765
|
-
var
|
|
770
|
+
var resolveAnchor = (a) => a && typeof a === "object" && "current" in a ? a.current : a ?? null;
|
|
771
|
+
var anchoringSupported;
|
|
772
|
+
function supportsAnchoring() {
|
|
773
|
+
if (anchoringSupported === void 0) {
|
|
774
|
+
try {
|
|
775
|
+
const css = typeof CSS !== "undefined" ? CSS : void 0;
|
|
776
|
+
anchoringSupported = !!css && typeof css.supports === "function" && css.supports("anchor-name", "--uix-a") && css.supports("position-anchor", "--uix-a") && css.supports("top", "round(anchor(bottom) + 1px, 1px)");
|
|
777
|
+
} catch {
|
|
778
|
+
anchoringSupported = false;
|
|
779
|
+
}
|
|
780
|
+
}
|
|
781
|
+
return anchoringSupported;
|
|
782
|
+
}
|
|
783
|
+
var anchorCount = 0;
|
|
784
|
+
var namesOf = (value) => value.split(",").map((n) => n.trim()).filter((n) => n.startsWith("--"));
|
|
785
|
+
function addAnchorName(el, name) {
|
|
786
|
+
const names = namesOf(getComputedStyle(el).getPropertyValue("anchor-name"));
|
|
787
|
+
if (!names.includes(name)) names.push(name);
|
|
788
|
+
el.style.setProperty("anchor-name", names.join(", "));
|
|
789
|
+
}
|
|
790
|
+
function removeAnchorName(el, name) {
|
|
791
|
+
const names = namesOf(el.style.getPropertyValue("anchor-name")).filter((n) => n !== name);
|
|
792
|
+
if (names.length) el.style.setProperty("anchor-name", names.join(", "));
|
|
793
|
+
else el.style.removeProperty("anchor-name");
|
|
794
|
+
}
|
|
795
|
+
function translationOf(el) {
|
|
796
|
+
const t = getComputedStyle(el).transform;
|
|
797
|
+
if (!t || t === "none" || typeof DOMMatrixReadOnly === "undefined") return { x: 0, y: 0 };
|
|
798
|
+
try {
|
|
799
|
+
const m = new DOMMatrixReadOnly(t);
|
|
800
|
+
return { x: m.m41, y: m.m42 };
|
|
801
|
+
} catch {
|
|
802
|
+
return { x: 0, y: 0 };
|
|
803
|
+
}
|
|
804
|
+
}
|
|
805
|
+
var signed = (n) => `${n < 0 ? "-" : "+"} ${Math.round(Math.abs(n) * 100) / 100}px`;
|
|
806
|
+
var prepared = /* @__PURE__ */ new WeakSet();
|
|
766
807
|
function useAnchoredPosition(anchor, floatingRef, { open, placement = "bottom-start", offset = 6, padding = 8 }) {
|
|
767
808
|
const opts = (0, import_react3.useRef)({ placement, offset, padding });
|
|
768
809
|
opts.current = { placement, offset, padding };
|
|
810
|
+
const session = (0, import_react3.useRef)(false);
|
|
811
|
+
const side = (0, import_react3.useRef)(null);
|
|
812
|
+
const written = (0, import_react3.useRef)("");
|
|
813
|
+
const anchoring = (0, import_react3.useRef)(null);
|
|
814
|
+
const anchoringFailed = (0, import_react3.useRef)(false);
|
|
815
|
+
const anchorName = (0, import_react3.useRef)("");
|
|
816
|
+
const release = (0, import_react3.useCallback)((keepPlace) => {
|
|
817
|
+
const current = anchoring.current;
|
|
818
|
+
if (!current) return;
|
|
819
|
+
anchoring.current = null;
|
|
820
|
+
written.current = "";
|
|
821
|
+
const floating = floatingRef.current;
|
|
822
|
+
if (floating) {
|
|
823
|
+
const s = floating.style;
|
|
824
|
+
if (keepPlace && current.anchor.isConnected) {
|
|
825
|
+
const a = current.anchor.getBoundingClientRect();
|
|
826
|
+
s.top = `${Math.round((current.yEdge === "bottom" ? a.bottom : a.top) + current.dy)}px`;
|
|
827
|
+
s.left = `${Math.round((current.xEdge === "right" ? a.right : a.left) + current.dx)}px`;
|
|
828
|
+
}
|
|
829
|
+
s.removeProperty("position-anchor");
|
|
830
|
+
}
|
|
831
|
+
removeAnchorName(current.anchor, current.name);
|
|
832
|
+
}, [floatingRef]);
|
|
769
833
|
const reposition = (0, import_react3.useCallback)(() => {
|
|
770
|
-
const anchorEl =
|
|
834
|
+
const anchorEl = resolveAnchor(anchor);
|
|
771
835
|
const floating = floatingRef.current;
|
|
772
836
|
if (!anchorEl || !floating) return;
|
|
773
837
|
const s = floating.style;
|
|
774
|
-
|
|
775
|
-
|
|
776
|
-
|
|
838
|
+
if (!prepared.has(floating)) {
|
|
839
|
+
s.position = "fixed";
|
|
840
|
+
s.inset = "auto";
|
|
841
|
+
s.margin = "0";
|
|
842
|
+
prepared.add(floating);
|
|
843
|
+
written.current = "";
|
|
844
|
+
}
|
|
777
845
|
const a = anchorEl.getBoundingClientRect();
|
|
846
|
+
const size = { width: floating.offsetWidth, height: floating.offsetHeight };
|
|
778
847
|
const { placement: p, offset: o, padding: pad } = opts.current;
|
|
779
848
|
const pos = computePosition(
|
|
780
849
|
{ x: a.x, y: a.y, width: a.width, height: a.height },
|
|
781
|
-
|
|
850
|
+
size,
|
|
782
851
|
{ width: window.innerWidth, height: window.innerHeight },
|
|
783
|
-
{ placement: p, offset: o, padding: pad }
|
|
852
|
+
{ placement: p, offset: o, padding: pad, stickySide: side.current ?? void 0 }
|
|
784
853
|
);
|
|
785
|
-
|
|
786
|
-
|
|
787
|
-
floating.dataset.placement = pos.placement;
|
|
788
|
-
|
|
854
|
+
const measured = size.width > 0 || size.height > 0;
|
|
855
|
+
if (measured && session.current) side.current = pos.side;
|
|
856
|
+
if (floating.dataset.placement !== pos.placement) floating.dataset.placement = pos.placement;
|
|
857
|
+
const writeFixed = (at) => {
|
|
858
|
+
const left2 = `${Math.round(at.x)}px`;
|
|
859
|
+
const top2 = `${Math.round(at.y)}px`;
|
|
860
|
+
const key2 = `fixed ${left2} ${top2}`;
|
|
861
|
+
if (key2 === written.current) return;
|
|
862
|
+
s.left = left2;
|
|
863
|
+
s.top = top2;
|
|
864
|
+
written.current = key2;
|
|
865
|
+
};
|
|
866
|
+
if (anchoringFailed.current || !supportsAnchoring()) {
|
|
867
|
+
writeFixed(pos);
|
|
868
|
+
return;
|
|
869
|
+
}
|
|
870
|
+
if (anchoring.current && anchoring.current.anchor !== anchorEl) release(false);
|
|
871
|
+
if (!anchoring.current) {
|
|
872
|
+
anchorName.current || (anchorName.current = `--uix-anchor-${++anchorCount}`);
|
|
873
|
+
addAnchorName(anchorEl, anchorName.current);
|
|
874
|
+
s.setProperty("position-anchor", anchorName.current);
|
|
875
|
+
anchoring.current = { anchor: anchorEl, name: anchorName.current, yEdge: "bottom", xEdge: "left", dy: 0, dx: 0, verified: false };
|
|
876
|
+
written.current = "";
|
|
877
|
+
}
|
|
878
|
+
const current = anchoring.current;
|
|
879
|
+
current.yEdge = pos.side === "bottom" ? "bottom" : "top";
|
|
880
|
+
current.xEdge = pos.side === "right" ? "right" : "left";
|
|
881
|
+
current.dy = pos.y - (current.yEdge === "bottom" ? a.bottom : a.top);
|
|
882
|
+
current.dx = pos.x - (current.xEdge === "right" ? a.right : a.left);
|
|
883
|
+
const top = `round(anchor(${current.yEdge}) ${signed(current.dy)}, 1px)`;
|
|
884
|
+
const left = `round(anchor(${current.xEdge}) ${signed(current.dx)}, 1px)`;
|
|
885
|
+
const key = `anchored ${top} ${left}`;
|
|
886
|
+
if (key !== written.current) {
|
|
887
|
+
s.top = top;
|
|
888
|
+
s.left = left;
|
|
889
|
+
written.current = key;
|
|
890
|
+
}
|
|
891
|
+
if (!current.verified && measured) {
|
|
892
|
+
current.verified = true;
|
|
893
|
+
const box = floating.getBoundingClientRect();
|
|
894
|
+
const t = translationOf(floating);
|
|
895
|
+
const dxc = box.left + box.width / 2 - t.x - (pos.x + size.width / 2);
|
|
896
|
+
const dyc = box.top + box.height / 2 - t.y - (pos.y + size.height / 2);
|
|
897
|
+
if (Math.abs(dxc) > 2 || Math.abs(dyc) > 2) {
|
|
898
|
+
anchoringFailed.current = true;
|
|
899
|
+
release(false);
|
|
900
|
+
writeFixed(pos);
|
|
901
|
+
}
|
|
902
|
+
}
|
|
903
|
+
}, [anchor, floatingRef, release]);
|
|
789
904
|
useIsomorphicLayoutEffect(() => {
|
|
790
905
|
if (!open) return;
|
|
906
|
+
session.current = true;
|
|
791
907
|
reposition();
|
|
792
|
-
const
|
|
908
|
+
const anchorEl = resolveAnchor(anchor);
|
|
909
|
+
const floating = floatingRef.current;
|
|
910
|
+
const onScroll = (event) => {
|
|
911
|
+
const target = event.target;
|
|
912
|
+
if (target && typeof target.contains === "function") {
|
|
913
|
+
if (floating?.contains(target)) return;
|
|
914
|
+
if (anchorEl && !target.contains(anchorEl)) return;
|
|
915
|
+
}
|
|
916
|
+
reposition();
|
|
917
|
+
};
|
|
918
|
+
const onResize = () => reposition();
|
|
793
919
|
window.addEventListener("scroll", onScroll, { passive: true, capture: true });
|
|
794
|
-
window.addEventListener("resize",
|
|
920
|
+
window.addEventListener("resize", onResize);
|
|
921
|
+
const observer = typeof ResizeObserver === "function" ? new ResizeObserver(() => reposition()) : null;
|
|
922
|
+
if (floating) observer?.observe(floating);
|
|
923
|
+
if (anchorEl) observer?.observe(anchorEl);
|
|
795
924
|
return () => {
|
|
796
925
|
window.removeEventListener("scroll", onScroll, true);
|
|
797
|
-
window.removeEventListener("resize",
|
|
926
|
+
window.removeEventListener("resize", onResize);
|
|
927
|
+
observer?.disconnect();
|
|
928
|
+
session.current = false;
|
|
929
|
+
side.current = null;
|
|
930
|
+
anchoringFailed.current = false;
|
|
931
|
+
release(true);
|
|
798
932
|
};
|
|
799
|
-
}, [open, reposition]);
|
|
933
|
+
}, [open, reposition, anchor, floatingRef, release]);
|
|
934
|
+
(0, import_react3.useEffect)(() => () => release(false), [release]);
|
|
800
935
|
return reposition;
|
|
801
936
|
}
|
|
802
937
|
|
|
803
938
|
// src/components/Popover.tsx
|
|
804
939
|
var import_jsx_runtime4 = require("react/jsx-runtime");
|
|
940
|
+
var useIsomorphicLayoutEffect2 = typeof document !== "undefined" ? import_react4.useLayoutEffect : import_react4.useEffect;
|
|
941
|
+
var PLACING = "data-uix-placing";
|
|
942
|
+
var isPopoverOpen = (el) => {
|
|
943
|
+
try {
|
|
944
|
+
return el.matches(":popover-open");
|
|
945
|
+
} catch {
|
|
946
|
+
return false;
|
|
947
|
+
}
|
|
948
|
+
};
|
|
949
|
+
var settle = (el) => {
|
|
950
|
+
if (!el.hasAttribute(PLACING)) return;
|
|
951
|
+
getComputedStyle(el).getPropertyValue("transform");
|
|
952
|
+
el.removeAttribute(PLACING);
|
|
953
|
+
};
|
|
805
954
|
function Popover({
|
|
806
955
|
popover = "auto",
|
|
807
956
|
anchor,
|
|
808
957
|
placement = "bottom-start",
|
|
809
958
|
offset = 6,
|
|
959
|
+
closeWhenAnchorHidden = false,
|
|
960
|
+
onAnchorHidden,
|
|
810
961
|
className,
|
|
811
962
|
children,
|
|
812
963
|
...props
|
|
813
964
|
}) {
|
|
814
965
|
const ref = (0, import_react4.useRef)(null);
|
|
815
966
|
const [open, setOpen] = (0, import_react4.useState)(false);
|
|
967
|
+
const openRef = (0, import_react4.useRef)(false);
|
|
968
|
+
const onAnchorHiddenRef = (0, import_react4.useRef)(onAnchorHidden);
|
|
969
|
+
onAnchorHiddenRef.current = onAnchorHidden;
|
|
816
970
|
const popoverAttr = { popover };
|
|
817
971
|
const reposition = useAnchoredPosition(anchor ?? null, ref, {
|
|
818
972
|
open: open && !!anchor,
|
|
@@ -822,14 +976,55 @@ function Popover({
|
|
|
822
976
|
(0, import_react4.useEffect)(() => {
|
|
823
977
|
const el = ref.current;
|
|
824
978
|
if (!el || !anchor) return;
|
|
979
|
+
const hold = (event) => {
|
|
980
|
+
if (event.newState !== "open") return;
|
|
981
|
+
el.setAttribute(PLACING, "");
|
|
982
|
+
window.setTimeout(() => settle(el), 150);
|
|
983
|
+
};
|
|
825
984
|
const sync = () => {
|
|
826
|
-
|
|
827
|
-
|
|
828
|
-
|
|
985
|
+
if (!isPopoverOpen(el)) {
|
|
986
|
+
el.removeAttribute(PLACING);
|
|
987
|
+
setOpen(false);
|
|
988
|
+
return;
|
|
989
|
+
}
|
|
990
|
+
reposition();
|
|
991
|
+
window.setTimeout(() => {
|
|
992
|
+
if (!isPopoverOpen(el)) return;
|
|
993
|
+
if (!openRef.current) {
|
|
994
|
+
setOpen(true);
|
|
995
|
+
return;
|
|
996
|
+
}
|
|
997
|
+
reposition();
|
|
998
|
+
settle(el);
|
|
999
|
+
}, 0);
|
|
829
1000
|
};
|
|
1001
|
+
el.addEventListener("beforetoggle", hold);
|
|
830
1002
|
el.addEventListener("toggle", sync);
|
|
831
|
-
return () =>
|
|
1003
|
+
return () => {
|
|
1004
|
+
el.removeEventListener("beforetoggle", hold);
|
|
1005
|
+
el.removeEventListener("toggle", sync);
|
|
1006
|
+
el.removeAttribute(PLACING);
|
|
1007
|
+
};
|
|
832
1008
|
}, [anchor, reposition]);
|
|
1009
|
+
useIsomorphicLayoutEffect2(() => {
|
|
1010
|
+
openRef.current = open;
|
|
1011
|
+
if (open && ref.current) settle(ref.current);
|
|
1012
|
+
}, [open]);
|
|
1013
|
+
(0, import_react4.useEffect)(() => {
|
|
1014
|
+
const el = ref.current;
|
|
1015
|
+
const anchorEl = resolveAnchor(anchor);
|
|
1016
|
+
if (!closeWhenAnchorHidden || !open || !el || !anchorEl || typeof IntersectionObserver !== "function") return;
|
|
1017
|
+
const observer = new IntersectionObserver((entries) => {
|
|
1018
|
+
const latest = entries[entries.length - 1];
|
|
1019
|
+
if (!latest || latest.isIntersecting || !isPopoverOpen(el)) return;
|
|
1020
|
+
onAnchorHiddenRef.current?.();
|
|
1021
|
+
const active = el.ownerDocument.activeElement;
|
|
1022
|
+
if (active && el.contains(active)) active.blur();
|
|
1023
|
+
el.hidePopover();
|
|
1024
|
+
});
|
|
1025
|
+
observer.observe(anchorEl);
|
|
1026
|
+
return () => observer.disconnect();
|
|
1027
|
+
}, [closeWhenAnchorHidden, open, anchor]);
|
|
833
1028
|
return /* @__PURE__ */ (0, import_jsx_runtime4.jsx)("div", { ref, className: cx("uix-popover", className), ...popoverAttr, ...props, children });
|
|
834
1029
|
}
|
|
835
1030
|
|
|
@@ -846,6 +1041,14 @@ var DEFAULT_EMOJI_PICKER_LABELS = {
|
|
|
846
1041
|
loadFailed: "Emoji could not be loaded."
|
|
847
1042
|
};
|
|
848
1043
|
var EMOJI_GRID_COLUMNS = 8;
|
|
1044
|
+
var useIsomorphicLayoutEffect3 = typeof document !== "undefined" ? import_react5.useLayoutEffect : import_react5.useEffect;
|
|
1045
|
+
function revealInGrid(grid, cell) {
|
|
1046
|
+
const g = grid.getBoundingClientRect();
|
|
1047
|
+
const c = cell.getBoundingClientRect();
|
|
1048
|
+
const top = g.top + (parseFloat(getComputedStyle(grid).scrollPaddingTop) || 0);
|
|
1049
|
+
if (c.top < top) grid.scrollTop -= top - c.top;
|
|
1050
|
+
else if (c.bottom > g.bottom) grid.scrollTop += c.bottom - g.bottom;
|
|
1051
|
+
}
|
|
849
1052
|
function EmojiPicker({
|
|
850
1053
|
onSelect,
|
|
851
1054
|
trigger,
|
|
@@ -867,6 +1070,8 @@ function EmojiPicker({
|
|
|
867
1070
|
const searchRef = (0, import_react5.useRef)(null);
|
|
868
1071
|
const gridRef = (0, import_react5.useRef)(null);
|
|
869
1072
|
const pointerWasOpen = (0, import_react5.useRef)(null);
|
|
1073
|
+
const closedByAnchor = (0, import_react5.useRef)(false);
|
|
1074
|
+
const pendingJump = (0, import_react5.useRef)(null);
|
|
870
1075
|
const [open, setOpen] = (0, import_react5.useState)(false);
|
|
871
1076
|
const [data, setData] = (0, import_react5.useState)(null);
|
|
872
1077
|
const [failed, setFailed] = (0, import_react5.useState)(false);
|
|
@@ -890,10 +1095,14 @@ function EmojiPicker({
|
|
|
890
1095
|
setOpen(nowOpen);
|
|
891
1096
|
onOpenChange?.(nowOpen);
|
|
892
1097
|
if (nowOpen) {
|
|
1098
|
+
closedByAnchor.current = false;
|
|
1099
|
+
pendingJump.current = null;
|
|
893
1100
|
setRecent(readRecentEmoji(recentStorageKey));
|
|
894
1101
|
setQuery("");
|
|
895
1102
|
setActive(0);
|
|
896
|
-
requestAnimationFrame(() => searchRef.current?.focus());
|
|
1103
|
+
requestAnimationFrame(() => searchRef.current?.focus({ preventScroll: true }));
|
|
1104
|
+
} else if (closedByAnchor.current) {
|
|
1105
|
+
closedByAnchor.current = false;
|
|
897
1106
|
} else if (el.contains(document.activeElement) || document.activeElement === document.body) {
|
|
898
1107
|
focusTrigger();
|
|
899
1108
|
}
|
|
@@ -925,10 +1134,7 @@ function EmojiPicker({
|
|
|
925
1134
|
const el = popoverEl();
|
|
926
1135
|
if (el && isOpen(el)) el.hidePopover();
|
|
927
1136
|
};
|
|
928
|
-
const
|
|
929
|
-
if (query.trim()) {
|
|
930
|
-
return data ? [{ key: "results", title: labels.search, emojis: searchEmoji(data, query).map((e) => e.emoji) }] : [];
|
|
931
|
-
}
|
|
1137
|
+
const browseSections = (0, import_react5.useMemo)(() => {
|
|
932
1138
|
const list = [];
|
|
933
1139
|
if (quickPicks?.length) list.push({ key: "quick", title: labels.quickPicks, emojis: [...new Set(quickPicks)] });
|
|
934
1140
|
if (recent.length) list.push({ key: "recent", title: labels.recent, emojis: recent });
|
|
@@ -938,7 +1144,11 @@ function EmojiPicker({
|
|
|
938
1144
|
});
|
|
939
1145
|
}
|
|
940
1146
|
return list;
|
|
941
|
-
}, [
|
|
1147
|
+
}, [data, quickPicks, recent, labels.quickPicks, labels.recent]);
|
|
1148
|
+
const sections = (0, import_react5.useMemo)(() => {
|
|
1149
|
+
if (!query.trim()) return browseSections;
|
|
1150
|
+
return data ? [{ key: "results", title: labels.search, emojis: searchEmoji(data, query).map((e) => e.emoji) }] : [];
|
|
1151
|
+
}, [query, data, browseSections, labels.search]);
|
|
942
1152
|
const flat = (0, import_react5.useMemo)(() => sections.flatMap((s) => s.emojis), [sections]);
|
|
943
1153
|
const sectionStart = (0, import_react5.useMemo)(() => {
|
|
944
1154
|
const starts = /* @__PURE__ */ new Map();
|
|
@@ -955,13 +1165,43 @@ function EmojiPicker({
|
|
|
955
1165
|
onSelect(emoji);
|
|
956
1166
|
hide();
|
|
957
1167
|
};
|
|
958
|
-
const focusCell = (0, import_react5.useCallback)((index) => {
|
|
1168
|
+
const focusCell = (0, import_react5.useCallback)((index, reveal = true) => {
|
|
959
1169
|
setActive(index);
|
|
960
1170
|
const find = () => gridRef.current?.querySelector(`[data-emoji-index="${index}"]`);
|
|
1171
|
+
const move = (cell2) => {
|
|
1172
|
+
cell2.focus({ preventScroll: true });
|
|
1173
|
+
if (reveal && gridRef.current) revealInGrid(gridRef.current, cell2);
|
|
1174
|
+
};
|
|
961
1175
|
const cell = find();
|
|
962
|
-
if (cell) cell
|
|
963
|
-
else requestAnimationFrame(() =>
|
|
1176
|
+
if (cell) move(cell);
|
|
1177
|
+
else requestAnimationFrame(() => {
|
|
1178
|
+
const later = find();
|
|
1179
|
+
if (later) move(later);
|
|
1180
|
+
});
|
|
964
1181
|
}, []);
|
|
1182
|
+
const showSection = (key) => {
|
|
1183
|
+
const grid = gridRef.current;
|
|
1184
|
+
const section = grid?.querySelector(`[data-section="${key}"]`);
|
|
1185
|
+
if (!grid || !section) return;
|
|
1186
|
+
grid.scrollTop += section.getBoundingClientRect().top - grid.getBoundingClientRect().top;
|
|
1187
|
+
const start = sectionStart.get(key);
|
|
1188
|
+
if (start !== void 0) focusCell(start, false);
|
|
1189
|
+
};
|
|
1190
|
+
const onCategory = (key) => {
|
|
1191
|
+
if (!query.trim()) {
|
|
1192
|
+
showSection(key);
|
|
1193
|
+
return;
|
|
1194
|
+
}
|
|
1195
|
+
pendingJump.current = key;
|
|
1196
|
+
setQuery("");
|
|
1197
|
+
setActive(0);
|
|
1198
|
+
};
|
|
1199
|
+
useIsomorphicLayoutEffect3(() => {
|
|
1200
|
+
const key = pendingJump.current;
|
|
1201
|
+
if (key === null || query.trim()) return;
|
|
1202
|
+
pendingJump.current = null;
|
|
1203
|
+
showSection(key);
|
|
1204
|
+
}, [query, sections]);
|
|
965
1205
|
const onGridKeyDown = (event) => {
|
|
966
1206
|
const target = event.target;
|
|
967
1207
|
const index = Number(target.dataset.emojiIndex ?? -1);
|
|
@@ -969,7 +1209,7 @@ function EmojiPicker({
|
|
|
969
1209
|
const next = emojiGridMove(index, event.key, flat.length, EMOJI_GRID_COLUMNS);
|
|
970
1210
|
if (event.key === "ArrowUp" && next === null) {
|
|
971
1211
|
event.preventDefault();
|
|
972
|
-
searchRef.current?.focus();
|
|
1212
|
+
searchRef.current?.focus({ preventScroll: true });
|
|
973
1213
|
return;
|
|
974
1214
|
}
|
|
975
1215
|
if (next === null) return;
|
|
@@ -1025,6 +1265,10 @@ function EmojiPicker({
|
|
|
1025
1265
|
className: "uix-emoji-picker-popover",
|
|
1026
1266
|
role: "dialog",
|
|
1027
1267
|
"aria-label": labels.dialog,
|
|
1268
|
+
closeWhenAnchorHidden: true,
|
|
1269
|
+
onAnchorHidden: () => {
|
|
1270
|
+
closedByAnchor.current = true;
|
|
1271
|
+
},
|
|
1028
1272
|
children: open ? /* @__PURE__ */ (0, import_jsx_runtime5.jsxs)("div", { className: "uix-emoji-picker uix-emoji-picker--full", lang: locale, children: [
|
|
1029
1273
|
/* @__PURE__ */ (0, import_jsx_runtime5.jsx)(
|
|
1030
1274
|
"input",
|
|
@@ -1044,50 +1288,56 @@ function EmojiPicker({
|
|
|
1044
1288
|
spellCheck: false
|
|
1045
1289
|
}
|
|
1046
1290
|
),
|
|
1047
|
-
|
|
1048
|
-
"
|
|
1291
|
+
/* @__PURE__ */ (0, import_jsx_runtime5.jsx)(
|
|
1292
|
+
"div",
|
|
1049
1293
|
{
|
|
1050
|
-
|
|
1051
|
-
|
|
1052
|
-
"aria-label":
|
|
1053
|
-
|
|
1054
|
-
|
|
1055
|
-
|
|
1056
|
-
|
|
1057
|
-
|
|
1058
|
-
|
|
1059
|
-
|
|
1060
|
-
|
|
1061
|
-
|
|
1062
|
-
|
|
1063
|
-
|
|
1064
|
-
|
|
1065
|
-
|
|
1066
|
-
|
|
1067
|
-
|
|
1068
|
-
|
|
1069
|
-
|
|
1070
|
-
|
|
1071
|
-
|
|
1072
|
-
|
|
1073
|
-
|
|
1074
|
-
|
|
1075
|
-
|
|
1076
|
-
|
|
1077
|
-
|
|
1078
|
-
|
|
1079
|
-
|
|
1080
|
-
|
|
1081
|
-
|
|
1082
|
-
|
|
1083
|
-
|
|
1084
|
-
|
|
1085
|
-
|
|
1086
|
-
|
|
1087
|
-
|
|
1088
|
-
|
|
1089
|
-
|
|
1090
|
-
|
|
1294
|
+
className: "uix-emoji-picker__nav",
|
|
1295
|
+
role: data ? "group" : void 0,
|
|
1296
|
+
"aria-label": data ? labels.categories : void 0,
|
|
1297
|
+
children: data ? browseSections.map((section) => /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(
|
|
1298
|
+
"button",
|
|
1299
|
+
{
|
|
1300
|
+
type: "button",
|
|
1301
|
+
className: "uix-emoji-picker__nav-btn",
|
|
1302
|
+
"aria-label": section.title,
|
|
1303
|
+
title: section.title,
|
|
1304
|
+
onClick: () => onCategory(section.key),
|
|
1305
|
+
children: /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("span", { "aria-hidden": "true", children: section.emojis[0] ? renderEmoji(section.emojis[0]) : null })
|
|
1306
|
+
},
|
|
1307
|
+
section.key
|
|
1308
|
+
)) : null
|
|
1309
|
+
}
|
|
1310
|
+
),
|
|
1311
|
+
/* @__PURE__ */ (0, import_jsx_runtime5.jsxs)("div", { className: "uix-emoji-picker__grid", ref: gridRef, onKeyDown: onGridKeyDown, children: [
|
|
1312
|
+
sections.map((section) => {
|
|
1313
|
+
const start = offset;
|
|
1314
|
+
offset += section.emojis.length;
|
|
1315
|
+
if (!section.emojis.length) return null;
|
|
1316
|
+
const headingId = `${id}-${section.key}`;
|
|
1317
|
+
return /* @__PURE__ */ (0, import_jsx_runtime5.jsxs)("section", { className: "uix-emoji-picker__section", "data-section": section.key, "aria-labelledby": headingId, children: [
|
|
1318
|
+
/* @__PURE__ */ (0, import_jsx_runtime5.jsx)("h3", { id: headingId, className: "uix-emoji-picker__heading", children: section.title }),
|
|
1319
|
+
/* @__PURE__ */ (0, import_jsx_runtime5.jsx)("div", { className: "uix-emoji-picker__cells", role: "group", "aria-labelledby": headingId, children: section.emojis.map((emoji, i) => {
|
|
1320
|
+
const index = start + i;
|
|
1321
|
+
return /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(
|
|
1322
|
+
"button",
|
|
1323
|
+
{
|
|
1324
|
+
type: "button",
|
|
1325
|
+
className: "uix-emoji-picker__btn",
|
|
1326
|
+
"data-emoji-index": index,
|
|
1327
|
+
tabIndex: index === activeIndex ? 0 : -1,
|
|
1328
|
+
"aria-label": names?.get(emoji) ?? emoji,
|
|
1329
|
+
title: names?.get(emoji),
|
|
1330
|
+
onClick: () => choose(emoji),
|
|
1331
|
+
onFocus: () => setActive(index),
|
|
1332
|
+
children: renderEmoji(emoji)
|
|
1333
|
+
},
|
|
1334
|
+
`${section.key}-${emoji}`
|
|
1335
|
+
);
|
|
1336
|
+
}) })
|
|
1337
|
+
] }, section.key);
|
|
1338
|
+
}),
|
|
1339
|
+
/* @__PURE__ */ (0, import_jsx_runtime5.jsx)("p", { className: "uix-emoji-picker__status", role: "status", children: status })
|
|
1340
|
+
] })
|
|
1091
1341
|
] }) : null
|
|
1092
1342
|
}
|
|
1093
1343
|
)
|
package/dist/rich-text.d.cts
CHANGED
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
import * as react from 'react';
|
|
2
2
|
import { ReactNode } from 'react';
|
|
3
|
-
import { E as EmojiPickerLabels, a as EmojiLocale } from './emoji-image-
|
|
4
|
-
export { l as emojiImageFileName } from './emoji-image-
|
|
5
|
-
import './overlay-position-
|
|
3
|
+
import { E as EmojiPickerLabels, a as EmojiLocale } from './emoji-image-6mPZ15Zy.cjs';
|
|
4
|
+
export { l as emojiImageFileName } from './emoji-image-6mPZ15Zy.cjs';
|
|
5
|
+
import './overlay-position-Cjv5E7mn.cjs';
|
|
6
6
|
|
|
7
7
|
type RichTextFeatures = 'full' | 'comment' | 'template';
|
|
8
8
|
type RichTextHeadingLevel = 1 | 2 | 3;
|