@anoki/fse-ui
Version:
FSE UI components library
626 lines (625 loc) • 22.1 kB
JavaScript
import * as r from "react";
import { composeEventHandlers as M } from "./index.es470.js";
import { createCollection as Xe } from "./index.es482.js";
import { useComposedRefs as k, composeRefs as He } from "./index.es471.js";
import { createContextScope as We } from "./index.es472.js";
import { useDirection as ze } from "./index.es483.js";
import { DismissableLayer as Ze } from "./index.es484.js";
import { useFocusGuards as $e } from "./index.es485.js";
import { FocusScope as qe } from "./index.es486.js";
import { createPopperScope as pe, Root as Je, Anchor as Qe, Content as et, Arrow as tt } from "./index.es487.js";
import { Portal as nt } from "./index.es488.js";
import { Presence as H } from "./index.es489.js";
import { Primitive as N, dispatchDiscreteCustomEvent as ot } from "./index.es474.js";
import { createRovingFocusGroupScope as ve, Item as rt, Root as ct } from "./index.es490.js";
import { createSlot as st } from "./index.es481.js";
import { useCallbackRef as Me } from "./index.es480.js";
import { hideOthers as at } from "./index.es491.js";
import ut from "./index.es492.js";
import { j as u } from "./index.es244.js";
var Q = ["Enter", " "], it = ["ArrowDown", "PageUp", "Home"], he = ["ArrowUp", "PageDown", "End"], lt = [...it, ...he], dt = {
ltr: [...Q, "ArrowRight"],
rtl: [...Q, "ArrowLeft"]
}, ft = {
ltr: ["ArrowLeft"],
rtl: ["ArrowRight"]
}, F = "Menu", [D, mt, pt] = Xe(F), [w, tn] = We(F, [
pt,
pe,
ve
]), W = pe(), Ce = ve(), [vt, S] = w(F), [Mt, L] = w(F), xe = (e) => {
const { __scopeMenu: n, open: t = !1, children: o, dir: a, onOpenChange: c, modal: l = !0 } = e, m = W(n), [p, v] = r.useState(null), f = r.useRef(!1), s = Me(c), d = ze(a);
return r.useEffect(() => {
const C = () => {
f.current = !0, document.addEventListener("pointerdown", h, { capture: !0, once: !0 }), document.addEventListener("pointermove", h, { capture: !0, once: !0 });
}, h = () => f.current = !1;
return document.addEventListener("keydown", C, { capture: !0 }), () => {
document.removeEventListener("keydown", C, { capture: !0 }), document.removeEventListener("pointerdown", h, { capture: !0 }), document.removeEventListener("pointermove", h, { capture: !0 });
};
}, []), /* @__PURE__ */ u.jsx(Je, { ...m, children: /* @__PURE__ */ u.jsx(
vt,
{
scope: n,
open: t,
onOpenChange: s,
content: p,
onContentChange: v,
children: /* @__PURE__ */ u.jsx(
Mt,
{
scope: n,
onClose: r.useCallback(() => s(!1), [s]),
isUsingKeyboardRef: f,
dir: d,
modal: l,
children: o
}
)
}
) });
};
xe.displayName = F;
var ht = "MenuAnchor", ee = r.forwardRef(
(e, n) => {
const { __scopeMenu: t, ...o } = e, a = W(t);
return /* @__PURE__ */ u.jsx(Qe, { ...a, ...o, ref: n });
}
);
ee.displayName = ht;
var te = "MenuPortal", [Ct, _e] = w(te, {
forceMount: void 0
}), ge = (e) => {
const { __scopeMenu: n, forceMount: t, children: o, container: a } = e, c = S(te, n);
return /* @__PURE__ */ u.jsx(Ct, { scope: n, forceMount: t, children: /* @__PURE__ */ u.jsx(H, { present: t || c.open, children: /* @__PURE__ */ u.jsx(nt, { asChild: !0, container: a, children: o }) }) });
};
ge.displayName = te;
var _ = "MenuContent", [xt, ne] = w(_), Re = r.forwardRef(
(e, n) => {
const t = _e(_, e.__scopeMenu), { forceMount: o = t.forceMount, ...a } = e, c = S(_, e.__scopeMenu), l = L(_, e.__scopeMenu);
return /* @__PURE__ */ u.jsx(D.Provider, { scope: e.__scopeMenu, children: /* @__PURE__ */ u.jsx(H, { present: o || c.open, children: /* @__PURE__ */ u.jsx(D.Slot, { scope: e.__scopeMenu, children: l.modal ? /* @__PURE__ */ u.jsx(_t, { ...a, ref: n }) : /* @__PURE__ */ u.jsx(gt, { ...a, ref: n }) }) }) });
}
), _t = r.forwardRef(
(e, n) => {
const t = S(_, e.__scopeMenu), o = r.useRef(null), a = k(n, o);
return r.useEffect(() => {
const c = o.current;
if (c) return at(c);
}, []), /* @__PURE__ */ u.jsx(
oe,
{
...e,
ref: a,
trapFocus: t.open,
disableOutsidePointerEvents: t.open,
disableOutsideScroll: !0,
onFocusOutside: M(
e.onFocusOutside,
(c) => c.preventDefault(),
{ checkForDefaultPrevented: !1 }
),
onDismiss: () => t.onOpenChange(!1)
}
);
}
), gt = r.forwardRef((e, n) => {
const t = S(_, e.__scopeMenu);
return /* @__PURE__ */ u.jsx(
oe,
{
...e,
ref: n,
trapFocus: !1,
disableOutsidePointerEvents: !1,
disableOutsideScroll: !1,
onDismiss: () => t.onOpenChange(!1)
}
);
}), Rt = st("MenuContent.ScrollLock"), oe = r.forwardRef(
(e, n) => {
const {
__scopeMenu: t,
loop: o = !1,
trapFocus: a,
onOpenAutoFocus: c,
onCloseAutoFocus: l,
disableOutsidePointerEvents: m,
onEntryFocus: p,
onEscapeKeyDown: v,
onPointerDownOutside: f,
onFocusOutside: s,
onInteractOutside: d,
onDismiss: C,
disableOutsideScroll: h,
...E
} = e, I = S(_, t), T = L(_, t), K = W(t), G = Ce(t), ae = mt(t), [Ke, ue] = r.useState(null), U = r.useRef(null), Ge = k(n, U, I.onContentChange), B = r.useRef(0), V = r.useRef(""), Ue = r.useRef(0), Z = r.useRef(null), ie = r.useRef("right"), $ = r.useRef(0), Be = h ? ut : r.Fragment, Ve = h ? { as: Rt, allowPinchZoom: !0 } : void 0, Ye = (i) => {
var b, de;
const x = V.current + i, g = ae().filter((R) => !R.disabled), P = document.activeElement, q = (b = g.find((R) => R.ref.current === P)) == null ? void 0 : b.textValue, J = g.map((R) => R.textValue), le = jt(J, x, q), A = (de = g.find((R) => R.textValue === le)) == null ? void 0 : de.ref.current;
(function R(fe) {
V.current = fe, window.clearTimeout(B.current), fe !== "" && (B.current = window.setTimeout(() => R(""), 1e3));
})(x), A && setTimeout(() => A.focus());
};
r.useEffect(() => () => window.clearTimeout(B.current), []), $e();
const y = r.useCallback((i) => {
var g, P;
return ie.current === ((g = Z.current) == null ? void 0 : g.side) && Nt(i, (P = Z.current) == null ? void 0 : P.area);
}, []);
return /* @__PURE__ */ u.jsx(
xt,
{
scope: t,
searchRef: V,
onItemEnter: r.useCallback(
(i) => {
y(i) && i.preventDefault();
},
[y]
),
onItemLeave: r.useCallback(
(i) => {
var x;
y(i) || ((x = U.current) == null || x.focus(), ue(null));
},
[y]
),
onTriggerLeave: r.useCallback(
(i) => {
y(i) && i.preventDefault();
},
[y]
),
pointerGraceTimerRef: Ue,
onPointerGraceIntentChange: r.useCallback((i) => {
Z.current = i;
}, []),
children: /* @__PURE__ */ u.jsx(Be, { ...Ve, children: /* @__PURE__ */ u.jsx(
qe,
{
asChild: !0,
trapped: a,
onMountAutoFocus: M(c, (i) => {
var x;
i.preventDefault(), (x = U.current) == null || x.focus({ preventScroll: !0 });
}),
onUnmountAutoFocus: l,
children: /* @__PURE__ */ u.jsx(
Ze,
{
asChild: !0,
disableOutsidePointerEvents: m,
onEscapeKeyDown: v,
onPointerDownOutside: f,
onFocusOutside: s,
onInteractOutside: d,
onDismiss: C,
children: /* @__PURE__ */ u.jsx(
ct,
{
asChild: !0,
...G,
dir: T.dir,
orientation: "vertical",
loop: o,
currentTabStopId: Ke,
onCurrentTabStopIdChange: ue,
onEntryFocus: M(p, (i) => {
T.isUsingKeyboardRef.current || i.preventDefault();
}),
preventScrollOnEntryFocus: !0,
children: /* @__PURE__ */ u.jsx(
et,
{
role: "menu",
"aria-orientation": "vertical",
"data-state": Le(I.open),
"data-radix-menu-content": "",
dir: T.dir,
...K,
...E,
ref: Ge,
style: { outline: "none", ...E.style },
onKeyDown: M(E.onKeyDown, (i) => {
const g = i.target.closest("[data-radix-menu-content]") === i.currentTarget, P = i.ctrlKey || i.altKey || i.metaKey, q = i.key.length === 1;
g && (i.key === "Tab" && i.preventDefault(), !P && q && Ye(i.key));
const J = U.current;
if (i.target !== J || !lt.includes(i.key)) return;
i.preventDefault();
const A = ae().filter((b) => !b.disabled).map((b) => b.ref.current);
he.includes(i.key) && A.reverse(), Ot(A);
}),
onBlur: M(e.onBlur, (i) => {
i.currentTarget.contains(i.target) || (window.clearTimeout(B.current), V.current = "");
}),
onPointerMove: M(
e.onPointerMove,
j((i) => {
const x = i.target, g = $.current !== i.clientX;
if (i.currentTarget.contains(x) && g) {
const P = i.clientX > $.current ? "right" : "left";
ie.current = P, $.current = i.clientX;
}
})
)
}
)
}
)
}
)
}
) })
}
);
}
);
Re.displayName = _;
var Pt = "MenuGroup", re = r.forwardRef(
(e, n) => {
const { __scopeMenu: t, ...o } = e;
return /* @__PURE__ */ u.jsx(N.div, { role: "group", ...o, ref: n });
}
);
re.displayName = Pt;
var Et = "MenuLabel", Pe = r.forwardRef(
(e, n) => {
const { __scopeMenu: t, ...o } = e;
return /* @__PURE__ */ u.jsx(N.div, { ...o, ref: n });
}
);
Pe.displayName = Et;
var Y = "MenuItem", me = "menu.itemSelect", z = r.forwardRef(
(e, n) => {
const { disabled: t = !1, onSelect: o, ...a } = e, c = r.useRef(null), l = L(Y, e.__scopeMenu), m = ne(Y, e.__scopeMenu), p = k(n, c), v = r.useRef(!1), f = () => {
const s = c.current;
if (!t && s) {
const d = new CustomEvent(me, { bubbles: !0, cancelable: !0 });
s.addEventListener(me, (C) => o == null ? void 0 : o(C), { once: !0 }), ot(s, d), d.defaultPrevented ? v.current = !1 : l.onClose();
}
};
return /* @__PURE__ */ u.jsx(
Ee,
{
...a,
ref: p,
disabled: t,
onClick: M(e.onClick, f),
onPointerDown: (s) => {
var d;
(d = e.onPointerDown) == null || d.call(e, s), v.current = !0;
},
onPointerUp: M(e.onPointerUp, (s) => {
var d;
v.current || (d = s.currentTarget) == null || d.click();
}),
onKeyDown: M(e.onKeyDown, (s) => {
const d = m.searchRef.current !== "";
t || d && s.key === " " || Q.includes(s.key) && (s.currentTarget.click(), s.preventDefault());
})
}
);
}
);
z.displayName = Y;
var Ee = r.forwardRef(
(e, n) => {
const { __scopeMenu: t, disabled: o = !1, textValue: a, ...c } = e, l = ne(Y, t), m = Ce(t), p = r.useRef(null), v = k(n, p), [f, s] = r.useState(!1), [d, C] = r.useState("");
return r.useEffect(() => {
const h = p.current;
h && C((h.textContent ?? "").trim());
}, [c.children]), /* @__PURE__ */ u.jsx(
D.ItemSlot,
{
scope: t,
disabled: o,
textValue: a ?? d,
children: /* @__PURE__ */ u.jsx(rt, { asChild: !0, ...m, focusable: !o, children: /* @__PURE__ */ u.jsx(
N.div,
{
role: "menuitem",
"data-highlighted": f ? "" : void 0,
"aria-disabled": o || void 0,
"data-disabled": o ? "" : void 0,
...c,
ref: v,
onPointerMove: M(
e.onPointerMove,
j((h) => {
o ? l.onItemLeave(h) : (l.onItemEnter(h), h.defaultPrevented || h.currentTarget.focus({ preventScroll: !0 }));
})
),
onPointerLeave: M(
e.onPointerLeave,
j((h) => l.onItemLeave(h))
),
onFocus: M(e.onFocus, () => s(!0)),
onBlur: M(e.onBlur, () => s(!1))
}
) })
}
);
}
), wt = "MenuCheckboxItem", we = r.forwardRef(
(e, n) => {
const { checked: t = !1, onCheckedChange: o, ...a } = e;
return /* @__PURE__ */ u.jsx(Te, { scope: e.__scopeMenu, checked: t, children: /* @__PURE__ */ u.jsx(
z,
{
role: "menuitemcheckbox",
"aria-checked": X(t) ? "mixed" : t,
...a,
ref: n,
"data-state": se(t),
onSelect: M(
a.onSelect,
() => o == null ? void 0 : o(X(t) ? !0 : !t),
{ checkForDefaultPrevented: !1 }
)
}
) });
}
);
we.displayName = wt;
var Se = "MenuRadioGroup", [St, It] = w(
Se,
{ value: void 0, onValueChange: () => {
} }
), Ie = r.forwardRef(
(e, n) => {
const { value: t, onValueChange: o, ...a } = e, c = Me(o);
return /* @__PURE__ */ u.jsx(St, { scope: e.__scopeMenu, value: t, onValueChange: c, children: /* @__PURE__ */ u.jsx(re, { ...a, ref: n }) });
}
);
Ie.displayName = Se;
var ye = "MenuRadioItem", be = r.forwardRef(
(e, n) => {
const { value: t, ...o } = e, a = It(ye, e.__scopeMenu), c = t === a.value;
return /* @__PURE__ */ u.jsx(Te, { scope: e.__scopeMenu, checked: c, children: /* @__PURE__ */ u.jsx(
z,
{
role: "menuitemradio",
"aria-checked": c,
...o,
ref: n,
"data-state": se(c),
onSelect: M(
o.onSelect,
() => {
var l;
return (l = a.onValueChange) == null ? void 0 : l.call(a, t);
},
{ checkForDefaultPrevented: !1 }
)
}
) });
}
);
be.displayName = ye;
var ce = "MenuItemIndicator", [Te, yt] = w(
ce,
{ checked: !1 }
), Ae = r.forwardRef(
(e, n) => {
const { __scopeMenu: t, forceMount: o, ...a } = e, c = yt(ce, t);
return /* @__PURE__ */ u.jsx(
H,
{
present: o || X(c.checked) || c.checked === !0,
children: /* @__PURE__ */ u.jsx(
N.span,
{
...a,
ref: n,
"data-state": se(c.checked)
}
)
}
);
}
);
Ae.displayName = ce;
var bt = "MenuSeparator", Oe = r.forwardRef(
(e, n) => {
const { __scopeMenu: t, ...o } = e;
return /* @__PURE__ */ u.jsx(
N.div,
{
role: "separator",
"aria-orientation": "horizontal",
...o,
ref: n
}
);
}
);
Oe.displayName = bt;
var Tt = "MenuArrow", De = r.forwardRef(
(e, n) => {
const { __scopeMenu: t, ...o } = e, a = W(t);
return /* @__PURE__ */ u.jsx(tt, { ...a, ...o, ref: n });
}
);
De.displayName = Tt;
var At = "MenuSub", [nn, je] = w(At), O = "MenuSubTrigger", ke = r.forwardRef(
(e, n) => {
const t = S(O, e.__scopeMenu), o = L(O, e.__scopeMenu), a = je(O, e.__scopeMenu), c = ne(O, e.__scopeMenu), l = r.useRef(null), { pointerGraceTimerRef: m, onPointerGraceIntentChange: p } = c, v = { __scopeMenu: e.__scopeMenu }, f = r.useCallback(() => {
l.current && window.clearTimeout(l.current), l.current = null;
}, []);
return r.useEffect(() => f, [f]), r.useEffect(() => {
const s = m.current;
return () => {
window.clearTimeout(s), p(null);
};
}, [m, p]), /* @__PURE__ */ u.jsx(ee, { asChild: !0, ...v, children: /* @__PURE__ */ u.jsx(
Ee,
{
id: a.triggerId,
"aria-haspopup": "menu",
"aria-expanded": t.open,
"aria-controls": a.contentId,
"data-state": Le(t.open),
...e,
ref: He(n, a.onTriggerChange),
onClick: (s) => {
var d;
(d = e.onClick) == null || d.call(e, s), !(e.disabled || s.defaultPrevented) && (s.currentTarget.focus(), t.open || t.onOpenChange(!0));
},
onPointerMove: M(
e.onPointerMove,
j((s) => {
c.onItemEnter(s), !s.defaultPrevented && !e.disabled && !t.open && !l.current && (c.onPointerGraceIntentChange(null), l.current = window.setTimeout(() => {
t.onOpenChange(!0), f();
}, 100));
})
),
onPointerLeave: M(
e.onPointerLeave,
j((s) => {
var C, h;
f();
const d = (C = t.content) == null ? void 0 : C.getBoundingClientRect();
if (d) {
const E = (h = t.content) == null ? void 0 : h.dataset.side, I = E === "right", T = I ? -5 : 5, K = d[I ? "left" : "right"], G = d[I ? "right" : "left"];
c.onPointerGraceIntentChange({
area: [
// Apply a bleed on clientX to ensure that our exit point is
// consistently within polygon bounds
{ x: s.clientX + T, y: s.clientY },
{ x: K, y: d.top },
{ x: G, y: d.top },
{ x: G, y: d.bottom },
{ x: K, y: d.bottom }
],
side: E
}), window.clearTimeout(m.current), m.current = window.setTimeout(
() => c.onPointerGraceIntentChange(null),
300
);
} else {
if (c.onTriggerLeave(s), s.defaultPrevented) return;
c.onPointerGraceIntentChange(null);
}
})
),
onKeyDown: M(e.onKeyDown, (s) => {
var C;
const d = c.searchRef.current !== "";
e.disabled || d && s.key === " " || dt[o.dir].includes(s.key) && (t.onOpenChange(!0), (C = t.content) == null || C.focus(), s.preventDefault());
})
}
) });
}
);
ke.displayName = O;
var Ne = "MenuSubContent", Fe = r.forwardRef(
(e, n) => {
const t = _e(_, e.__scopeMenu), { forceMount: o = t.forceMount, ...a } = e, c = S(_, e.__scopeMenu), l = L(_, e.__scopeMenu), m = je(Ne, e.__scopeMenu), p = r.useRef(null), v = k(n, p);
return /* @__PURE__ */ u.jsx(D.Provider, { scope: e.__scopeMenu, children: /* @__PURE__ */ u.jsx(H, { present: o || c.open, children: /* @__PURE__ */ u.jsx(D.Slot, { scope: e.__scopeMenu, children: /* @__PURE__ */ u.jsx(
oe,
{
id: m.contentId,
"aria-labelledby": m.triggerId,
...a,
ref: v,
align: "start",
side: l.dir === "rtl" ? "left" : "right",
disableOutsidePointerEvents: !1,
disableOutsideScroll: !1,
trapFocus: !1,
onOpenAutoFocus: (f) => {
var s;
l.isUsingKeyboardRef.current && ((s = p.current) == null || s.focus()), f.preventDefault();
},
onCloseAutoFocus: (f) => f.preventDefault(),
onFocusOutside: M(e.onFocusOutside, (f) => {
f.target !== m.trigger && c.onOpenChange(!1);
}),
onEscapeKeyDown: M(e.onEscapeKeyDown, (f) => {
l.onClose(), f.preventDefault();
}),
onKeyDown: M(e.onKeyDown, (f) => {
var C;
const s = f.currentTarget.contains(f.target), d = ft[l.dir].includes(f.key);
s && d && (c.onOpenChange(!1), (C = m.trigger) == null || C.focus(), f.preventDefault());
})
}
) }) }) });
}
);
Fe.displayName = Ne;
function Le(e) {
return e ? "open" : "closed";
}
function X(e) {
return e === "indeterminate";
}
function se(e) {
return X(e) ? "indeterminate" : e ? "checked" : "unchecked";
}
function Ot(e) {
const n = document.activeElement;
for (const t of e)
if (t === n || (t.focus(), document.activeElement !== n)) return;
}
function Dt(e, n) {
return e.map((t, o) => e[(n + o) % e.length]);
}
function jt(e, n, t) {
const a = n.length > 1 && Array.from(n).every((v) => v === n[0]) ? n[0] : n, c = t ? e.indexOf(t) : -1;
let l = Dt(e, Math.max(c, 0));
a.length === 1 && (l = l.filter((v) => v !== t));
const p = l.find(
(v) => v.toLowerCase().startsWith(a.toLowerCase())
);
return p !== t ? p : void 0;
}
function kt(e, n) {
const { x: t, y: o } = e;
let a = !1;
for (let c = 0, l = n.length - 1; c < n.length; l = c++) {
const m = n[c].x, p = n[c].y, v = n[l].x, f = n[l].y;
p > o != f > o && t < (v - m) * (o - p) / (f - p) + m && (a = !a);
}
return a;
}
function Nt(e, n) {
if (!n) return !1;
const t = { x: e.clientX, y: e.clientY };
return kt(t, n);
}
function j(e) {
return (n) => n.pointerType === "mouse" ? e(n) : void 0;
}
var on = xe, rn = ee, cn = ge, sn = Re, an = re, un = Pe, ln = z, dn = we, fn = Ie, mn = be, pn = Ae, vn = Oe, Mn = De, hn = ke, Cn = Fe;
export {
rn as Anchor,
Mn as Arrow,
dn as CheckboxItem,
sn as Content,
an as Group,
ln as Item,
pn as ItemIndicator,
un as Label,
xe as Menu,
ee as MenuAnchor,
De as MenuArrow,
we as MenuCheckboxItem,
Re as MenuContent,
re as MenuGroup,
z as MenuItem,
Ae as MenuItemIndicator,
Pe as MenuLabel,
ge as MenuPortal,
Ie as MenuRadioGroup,
be as MenuRadioItem,
Oe as MenuSeparator,
Fe as MenuSubContent,
ke as MenuSubTrigger,
cn as Portal,
fn as RadioGroup,
mn as RadioItem,
on as Root,
vn as Separator,
Cn as SubContent,
hn as SubTrigger,
tn as createMenuScope
};
//# sourceMappingURL=index.es475.js.map