@geomak/ui 7.8.0 → 7.10.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.
package/dist/index.cjs CHANGED
@@ -2,7 +2,7 @@
2
2
 
3
3
  var chunk4V4U2W7K_cjs = require('./chunk-4V4U2W7K.cjs');
4
4
  var chunkCNUDNGJM_cjs = require('./chunk-CNUDNGJM.cjs');
5
- var React34 = require('react');
5
+ var React36 = require('react');
6
6
  var reactDom = require('react-dom');
7
7
  var jsxRuntime = require('react/jsx-runtime');
8
8
  var AvatarPrimitive = require('@radix-ui/react-avatar');
@@ -41,7 +41,7 @@ function _interopNamespace(e) {
41
41
  return Object.freeze(n);
42
42
  }
43
43
 
44
- var React34__default = /*#__PURE__*/_interopDefault(React34);
44
+ var React36__default = /*#__PURE__*/_interopDefault(React36);
45
45
  var AvatarPrimitive__namespace = /*#__PURE__*/_interopNamespace(AvatarPrimitive);
46
46
  var DropdownMenu2__namespace = /*#__PURE__*/_interopNamespace(DropdownMenu2);
47
47
  var Dialog__namespace = /*#__PURE__*/_interopNamespace(Dialog);
@@ -67,8 +67,8 @@ function cx(...values) {
67
67
  return out;
68
68
  }
69
69
  function Portal({ children, target }) {
70
- const [resolved, setResolved] = React34.useState(null);
71
- React34.useEffect(() => {
70
+ const [resolved, setResolved] = React36.useState(null);
71
+ React36.useEffect(() => {
72
72
  if (target === null) {
73
73
  setResolved(null);
74
74
  return;
@@ -489,7 +489,7 @@ function Typography({
489
489
  }
490
490
  );
491
491
  }
492
- var IconButton = React34__default.default.forwardRef(function IconButton2({
492
+ var IconButton = React36__default.default.forwardRef(function IconButton2({
493
493
  icon,
494
494
  onClick,
495
495
  type = "primary",
@@ -502,7 +502,7 @@ var IconButton = React34__default.default.forwardRef(function IconButton2({
502
502
  className = "",
503
503
  style
504
504
  }, ref) {
505
- const colorScheme = React34.useMemo(() => {
505
+ const colorScheme = React36.useMemo(() => {
506
506
  if (type === "primary") {
507
507
  return "bg-accent text-accent-fg hover:bg-accent-hover";
508
508
  }
@@ -598,7 +598,7 @@ var SIZE_CLASSES = {
598
598
  md: "h-9 px-4 text-sm gap-1.5 rounded-lg",
599
599
  lg: "h-11 px-5 text-sm gap-2 rounded-xl"
600
600
  };
601
- var Button = React34__default.default.forwardRef(function Button2({
601
+ var Button = React36__default.default.forwardRef(function Button2({
602
602
  content,
603
603
  variant = "primary",
604
604
  size = "md",
@@ -706,7 +706,7 @@ function MenuButton({
706
706
  "data-[state=open]:animate-in data-[state=open]:fade-in-0 data-[state=open]:zoom-in-95",
707
707
  "data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=closed]:zoom-out-95"
708
708
  ].join(" "),
709
- children: items.map((item) => /* @__PURE__ */ jsxRuntime.jsxs(React34__default.default.Fragment, { children: [
709
+ children: items.map((item) => /* @__PURE__ */ jsxRuntime.jsxs(React36__default.default.Fragment, { children: [
710
710
  item.separatorBefore && /* @__PURE__ */ jsxRuntime.jsx(DropdownMenu2__namespace.Separator, { className: "my-1 h-px bg-border" }),
711
711
  /* @__PURE__ */ jsxRuntime.jsxs(
712
712
  DropdownMenu2__namespace.Item,
@@ -729,6 +729,10 @@ function MenuButton({
729
729
  ) })
730
730
  ] });
731
731
  }
732
+ var DialogContainerContext = React36.createContext(null);
733
+ function useDialogContainer() {
734
+ return React36.useContext(DialogContainerContext);
735
+ }
732
736
  var SIZE_MAP = {
733
737
  sm: 400,
734
738
  md: 600,
@@ -753,6 +757,7 @@ function Modal({
753
757
  className = ""
754
758
  }) {
755
759
  const reduced = framerMotion.useReducedMotion();
760
+ const [panelEl, setPanelEl] = React36.useState(null);
756
761
  const maxWidth = width ?? SIZE_MAP[size];
757
762
  return /* @__PURE__ */ jsxRuntime.jsx(Dialog__namespace.Root, { open, onOpenChange: (next) => {
758
763
  if (!next) onClose?.();
@@ -770,6 +775,7 @@ function Modal({
770
775
  /* @__PURE__ */ jsxRuntime.jsx(framerMotion.AnimatePresence, { children: open && /* @__PURE__ */ jsxRuntime.jsx(Dialog__namespace.Content, { asChild: true, children: /* @__PURE__ */ jsxRuntime.jsxs(
771
776
  framerMotion.motion.div,
772
777
  {
778
+ ref: setPanelEl,
773
779
  className: `fixed left-1/2 top-1/2 z-modal flex flex-col w-[calc(100%-2rem)] max-h-[90dvh] bg-surface rounded-2xl shadow-xl overflow-hidden focus:outline-none ${className}`.trim(),
774
780
  style: {
775
781
  maxWidth,
@@ -797,7 +803,7 @@ function Modal({
797
803
  }
798
804
  ) })
799
805
  ] }),
800
- /* @__PURE__ */ jsxRuntime.jsx("div", { className: `flex-1 overflow-y-auto p-5 ${hasFooter ? "" : "pb-5"}`, children }),
806
+ /* @__PURE__ */ jsxRuntime.jsx("div", { className: `flex-1 overflow-y-auto p-5 ${hasFooter ? "" : "pb-5"}`, children: /* @__PURE__ */ jsxRuntime.jsx(DialogContainerContext.Provider, { value: panelEl, children }) }),
801
807
  hasFooter && /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex flex-shrink-0 items-center justify-end gap-3 border-t border-border px-5 py-3", children: [
802
808
  /* @__PURE__ */ jsxRuntime.jsx(
803
809
  Button_default,
@@ -848,6 +854,7 @@ function Drawer({
848
854
  className = ""
849
855
  }) {
850
856
  const reduced = framerMotion.useReducedMotion();
857
+ const [panelEl, setPanelEl] = React36.useState(null);
851
858
  const isRight = placement === "right";
852
859
  const hiddenX = isRight ? "100%" : "-100%";
853
860
  const resolvedWidth = width ?? SIZE_MAP2[size];
@@ -868,6 +875,7 @@ function Drawer({
868
875
  /* @__PURE__ */ jsxRuntime.jsx(framerMotion.AnimatePresence, { children: open && /* @__PURE__ */ jsxRuntime.jsx(Dialog__namespace.Content, { asChild: true, children: /* @__PURE__ */ jsxRuntime.jsxs(
869
876
  framerMotion.motion.div,
870
877
  {
878
+ ref: setPanelEl,
871
879
  className: `fixed top-0 bottom-0 ${isRight ? "right-0" : "left-0"} z-modal flex flex-col bg-surface shadow-xl focus:outline-none ${className}`.trim(),
872
880
  style: { width: `min(calc(100vw - 1rem), ${widthCss})` },
873
881
  initial: { x: reduced ? 0 : hiddenX, opacity: reduced ? 0 : 1 },
@@ -894,7 +902,7 @@ function Drawer({
894
902
  }
895
903
  ) })
896
904
  ] }),
897
- /* @__PURE__ */ jsxRuntime.jsx("div", { className: "flex-1 overflow-y-auto p-5", children }),
905
+ /* @__PURE__ */ jsxRuntime.jsx("div", { className: "flex-1 overflow-y-auto p-5", children: /* @__PURE__ */ jsxRuntime.jsx(DialogContainerContext.Provider, { value: panelEl, children }) }),
898
906
  hasFooter && /* @__PURE__ */ jsxRuntime.jsxs("div", { className: `flex flex-shrink-0 items-center gap-3 border-t border-border px-5 py-3 ${isRight ? "justify-start" : "justify-end"}`, children: [
899
907
  /* @__PURE__ */ jsxRuntime.jsx(Button_default, { style: { width: 90 }, variant: cancelVariant, content: cancelText, onClick: onCancel }),
900
908
  /* @__PURE__ */ jsxRuntime.jsx(Button_default, { style: { width: 90 }, variant: okVariant, content: okText, onClick: onOk })
@@ -955,9 +963,9 @@ function Tooltip({
955
963
  ] }) });
956
964
  }
957
965
  var TooltipProvider = TooltipPrimitive__namespace.Provider;
958
- var TabsContext = React34.createContext(null);
966
+ var TabsContext = React36.createContext(null);
959
967
  function useTabsContext() {
960
- const ctx = React34.useContext(TabsContext);
968
+ const ctx = React36.useContext(TabsContext);
961
969
  if (!ctx) throw new Error("Tabs.List / Tabs.Trigger / Tabs.Panel must be rendered inside <Tabs>.");
962
970
  return ctx;
963
971
  }
@@ -979,26 +987,26 @@ function Tabs({
979
987
  children
980
988
  }) {
981
989
  const isControlled = value !== void 0;
982
- const [internal, setInternal] = React34.useState(defaultValue);
990
+ const [internal, setInternal] = React36.useState(defaultValue);
983
991
  const current = isControlled ? value : internal;
984
992
  const reduced = !!framerMotion.useReducedMotion();
985
- const indicatorId = React34.useId();
986
- const select = React34.useCallback((next) => {
993
+ const indicatorId = React36.useId();
994
+ const select = React36.useCallback((next) => {
987
995
  if (!isControlled) setInternal(next);
988
996
  onChange?.(next);
989
997
  }, [isControlled, onChange]);
990
- const registry = React34.useRef(/* @__PURE__ */ new Map());
991
- const orderRef = React34.useRef(0);
992
- const [, bump] = React34.useState(0);
993
- const registerTab = React34.useCallback((val, meta) => {
998
+ const registry = React36.useRef(/* @__PURE__ */ new Map());
999
+ const orderRef = React36.useRef(0);
1000
+ const [, bump] = React36.useState(0);
1001
+ const registerTab = React36.useCallback((val, meta) => {
994
1002
  const existing = registry.current.get(val);
995
1003
  registry.current.set(val, { ...meta, order: existing?.order ?? orderRef.current++ });
996
1004
  if (!existing) bump((v) => v + 1);
997
1005
  }, []);
998
- const unregisterTab = React34.useCallback((val) => {
1006
+ const unregisterTab = React36.useCallback((val) => {
999
1007
  if (registry.current.delete(val)) bump((v) => v + 1);
1000
1008
  }, []);
1001
- const getTabs = React34.useCallback(() => [...registry.current.entries()].sort((a, b) => a[1].order - b[1].order).map(([val, m]) => ({ value: val, label: m.label, icon: m.icon, disabled: m.disabled })), []);
1009
+ const getTabs = React36.useCallback(() => [...registry.current.entries()].sort((a, b) => a[1].order - b[1].order).map(([val, m]) => ({ value: val, label: m.label, icon: m.icon, disabled: m.disabled })), []);
1002
1010
  return /* @__PURE__ */ jsxRuntime.jsx(TabsContext.Provider, { value: { value: current, variant, size, orientation, indicatorId, reduced, select, registerTab, unregisterTab, getTabs }, children: /* @__PURE__ */ jsxRuntime.jsx(
1003
1011
  TabsPrimitive__namespace.Root,
1004
1012
  {
@@ -1018,10 +1026,10 @@ function Tabs({
1018
1026
  function TabsList({ children, "aria-label": ariaLabel, className = "" }) {
1019
1027
  const { variant, orientation, reduced, value } = useTabsContext();
1020
1028
  const horizontal = orientation === "horizontal";
1021
- const scrollRef = React34.useRef(null);
1022
- const [edges, setEdges] = React34.useState({ start: false, end: false });
1029
+ const scrollRef = React36.useRef(null);
1030
+ const [edges, setEdges] = React36.useState({ start: false, end: false });
1023
1031
  const scrollable = variant !== "segmented";
1024
- React34.useLayoutEffect(() => {
1032
+ React36.useLayoutEffect(() => {
1025
1033
  const el = scrollRef.current;
1026
1034
  if (!el || !scrollable) return;
1027
1035
  const update = () => {
@@ -1046,13 +1054,13 @@ function TabsList({ children, "aria-label": ariaLabel, className = "" }) {
1046
1054
  ro.disconnect();
1047
1055
  };
1048
1056
  }, [horizontal, scrollable, children]);
1049
- const nudge = React34.useCallback((dir) => {
1057
+ const nudge = React36.useCallback((dir) => {
1050
1058
  const el = scrollRef.current;
1051
1059
  if (!el) return;
1052
1060
  const amount = (horizontal ? el.clientWidth : el.clientHeight) * 0.7 * dir;
1053
1061
  el.scrollBy({ [horizontal ? "left" : "top"]: amount, behavior: reduced ? "auto" : "smooth" });
1054
1062
  }, [horizontal, reduced]);
1055
- React34.useLayoutEffect(() => {
1063
+ React36.useLayoutEffect(() => {
1056
1064
  const el = scrollRef.current;
1057
1065
  if (!el || !scrollable) return;
1058
1066
  const active = el.querySelector("[role=tab][data-state=active]");
@@ -1110,9 +1118,9 @@ function Chevron2({ side, orientation, onClick }) {
1110
1118
  function OverflowMenu() {
1111
1119
  const { getTabs, value, select, orientation } = useTabsContext();
1112
1120
  const horizontal = orientation === "horizontal";
1113
- const [open, setOpen] = React34.useState(false);
1114
- const wrapRef = React34.useRef(null);
1115
- const timer = React34.useRef(null);
1121
+ const [open, setOpen] = React36.useState(false);
1122
+ const wrapRef = React36.useRef(null);
1123
+ const timer = React36.useRef(null);
1116
1124
  const openNow = () => {
1117
1125
  if (timer.current) clearTimeout(timer.current);
1118
1126
  setOpen(true);
@@ -1120,7 +1128,7 @@ function OverflowMenu() {
1120
1128
  const closeSoon = () => {
1121
1129
  timer.current = setTimeout(() => setOpen(false), 160);
1122
1130
  };
1123
- React34.useLayoutEffect(() => {
1131
+ React36.useLayoutEffect(() => {
1124
1132
  if (!open) return;
1125
1133
  const onDoc = (e) => {
1126
1134
  if (wrapRef.current && !wrapRef.current.contains(e.target)) setOpen(false);
@@ -1201,7 +1209,7 @@ function TabsTrigger({ value, icon, badge, closeable, onClose, disabled, classNa
1201
1209
  const isActive = active === value;
1202
1210
  const horizontal = orientation === "horizontal";
1203
1211
  const sz = SIZE[size];
1204
- React34.useLayoutEffect(() => {
1212
+ React36.useLayoutEffect(() => {
1205
1213
  registerTab(value, { label: children, icon, disabled });
1206
1214
  return () => unregisterTab(value);
1207
1215
  }, [value, children, icon, disabled, registerTab, unregisterTab]);
@@ -1400,7 +1408,7 @@ function Tree({
1400
1408
  item.key
1401
1409
  )) });
1402
1410
  }
1403
- var AccordionCtx = React34.createContext({ variant: "separated" });
1411
+ var AccordionCtx = React36.createContext({ variant: "separated" });
1404
1412
  function Accordion2({
1405
1413
  children,
1406
1414
  type = "single",
@@ -1459,7 +1467,7 @@ var Chevron3 = /* @__PURE__ */ jsxRuntime.jsx(
1459
1467
  }
1460
1468
  );
1461
1469
  function AccordionItem({ value, title, icon, children, disabled, className = "" }) {
1462
- const { variant } = React34.useContext(AccordionCtx);
1470
+ const { variant } = React36.useContext(AccordionCtx);
1463
1471
  return /* @__PURE__ */ jsxRuntime.jsxs(
1464
1472
  AccordionPrimitive__namespace.Item,
1465
1473
  {
@@ -1518,7 +1526,7 @@ function Breadcrumbs({
1518
1526
  className = "",
1519
1527
  style
1520
1528
  }) {
1521
- const [expanded, setExpanded] = React34.useState(false);
1529
+ const [expanded, setExpanded] = React36.useState(false);
1522
1530
  const shouldCollapse = maxItems > 0 && items.length > maxItems && !expanded;
1523
1531
  const visible = [];
1524
1532
  if (shouldCollapse) {
@@ -1743,8 +1751,8 @@ function Stepper({
1743
1751
  className = ""
1744
1752
  }) {
1745
1753
  const reduced = framerMotion.useReducedMotion();
1746
- const [forcedVertical, setForcedVertical] = React34.useState(false);
1747
- React34.useEffect(() => {
1754
+ const [forcedVertical, setForcedVertical] = React36.useState(false);
1755
+ React36.useEffect(() => {
1748
1756
  if (!responsive || orientation === "vertical") return;
1749
1757
  if (typeof window === "undefined" || typeof window.matchMedia !== "function") return;
1750
1758
  const mq = window.matchMedia("(max-width: 767px)");
@@ -1853,7 +1861,7 @@ function Kbd({
1853
1861
  style
1854
1862
  }) {
1855
1863
  if (keys && keys.length > 0) {
1856
- return /* @__PURE__ */ jsxRuntime.jsx("span", { className: cx("inline-flex items-center gap-1", className), style, children: keys.map((k, i) => /* @__PURE__ */ jsxRuntime.jsxs(React34__default.default.Fragment, { children: [
1864
+ return /* @__PURE__ */ jsxRuntime.jsx("span", { className: cx("inline-flex items-center gap-1", className), style, children: keys.map((k, i) => /* @__PURE__ */ jsxRuntime.jsxs(React36__default.default.Fragment, { children: [
1857
1865
  i > 0 && /* @__PURE__ */ jsxRuntime.jsx("span", { className: "text-foreground-muted text-xs select-none", children: separator }),
1858
1866
  /* @__PURE__ */ jsxRuntime.jsx("kbd", { className: [cap, SIZE3[size]].join(" "), children: k })
1859
1867
  ] }, `${k}-${i}`)) });
@@ -1944,13 +1952,13 @@ function FlatCarousel({
1944
1952
  className = "",
1945
1953
  style
1946
1954
  }) {
1947
- const scrollerRef = React34.useRef(null);
1948
- const slides = React34__default.default.Children.toArray(children);
1949
- const [active, setActive] = React34.useState(0);
1950
- const [atStart, setAtStart] = React34.useState(true);
1951
- const [atEnd, setAtEnd] = React34.useState(false);
1955
+ const scrollerRef = React36.useRef(null);
1956
+ const slides = React36__default.default.Children.toArray(children);
1957
+ const [active, setActive] = React36.useState(0);
1958
+ const [atStart, setAtStart] = React36.useState(true);
1959
+ const [atEnd, setAtEnd] = React36.useState(false);
1952
1960
  const width = typeof itemWidth === "number" ? `${itemWidth}px` : itemWidth;
1953
- const update = React34.useCallback(() => {
1961
+ const update = React36.useCallback(() => {
1954
1962
  const el = scrollerRef.current;
1955
1963
  if (!el) return;
1956
1964
  setAtStart(el.scrollLeft <= 1);
@@ -1959,7 +1967,7 @@ function FlatCarousel({
1959
1967
  const slideW = first ? first.getBoundingClientRect().width + gap : el.clientWidth;
1960
1968
  setActive(Math.round(el.scrollLeft / slideW));
1961
1969
  }, [gap]);
1962
- React34.useEffect(() => {
1970
+ React36.useEffect(() => {
1963
1971
  update();
1964
1972
  const el = scrollerRef.current;
1965
1973
  if (!el) return;
@@ -2000,9 +2008,9 @@ function RotatingCarousel({
2000
2008
  className = "",
2001
2009
  style
2002
2010
  }) {
2003
- const slides = React34__default.default.Children.toArray(children);
2011
+ const slides = React36__default.default.Children.toArray(children);
2004
2012
  const count = slides.length;
2005
- const [active, setActive] = React34.useState(0);
2013
+ const [active, setActive] = React36.useState(0);
2006
2014
  const reduced = framerMotion.useReducedMotion();
2007
2015
  const wrap = (n) => count > 0 ? (n % count + count) % count : 0;
2008
2016
  const idx = wrap(active);
@@ -2240,13 +2248,13 @@ function Chat({
2240
2248
  className = "",
2241
2249
  style
2242
2250
  }) {
2243
- const listRef = React34.useRef(null);
2244
- const atBottomRef = React34.useRef(true);
2245
- const [showJump, setShowJump] = React34.useState(false);
2246
- const [draft, setDraft] = React34.useState("");
2251
+ const listRef = React36.useRef(null);
2252
+ const atBottomRef = React36.useRef(true);
2253
+ const [showJump, setShowJump] = React36.useState(false);
2254
+ const [draft, setDraft] = React36.useState("");
2247
2255
  const hasHeader = title != null || subtitle != null || avatar != null || headerActions != null;
2248
2256
  const isTyping = typingNames.length > 0;
2249
- const scrollToBottom = React34.useCallback((smooth = true) => {
2257
+ const scrollToBottom = React36.useCallback((smooth = true) => {
2250
2258
  const el = listRef.current;
2251
2259
  if (!el) return;
2252
2260
  if (typeof el.scrollTo === "function") el.scrollTo({ top: el.scrollHeight, behavior: smooth ? "smooth" : "auto" });
@@ -2259,10 +2267,10 @@ function Chat({
2259
2267
  atBottomRef.current = near;
2260
2268
  setShowJump(!near);
2261
2269
  };
2262
- React34.useEffect(() => {
2270
+ React36.useEffect(() => {
2263
2271
  if (atBottomRef.current) scrollToBottom(messages.length > 0);
2264
2272
  }, [messages.length, isTyping]);
2265
- React34.useEffect(() => {
2273
+ React36.useEffect(() => {
2266
2274
  scrollToBottom(false);
2267
2275
  }, [scrollToBottom]);
2268
2276
  const send = () => {
@@ -2452,7 +2460,7 @@ function FAB({
2452
2460
  className = "",
2453
2461
  style
2454
2462
  }) {
2455
- const [open, setOpen] = React34.useState(false);
2463
+ const [open, setOpen] = React36.useState(false);
2456
2464
  const reduced = framerMotion.useReducedMotion();
2457
2465
  const hasDial = !!actions && actions.length > 0;
2458
2466
  const bottom = position.startsWith("bottom");
@@ -2554,8 +2562,8 @@ function PopConfirm({
2554
2562
  onOpenChange,
2555
2563
  className = ""
2556
2564
  }) {
2557
- const [uncontrolledOpen, setUncontrolledOpen] = React34.useState(false);
2558
- const [loading, setLoading] = React34.useState(false);
2565
+ const [uncontrolledOpen, setUncontrolledOpen] = React36.useState(false);
2566
+ const [loading, setLoading] = React36.useState(false);
2559
2567
  const isOpen = open ?? uncontrolledOpen;
2560
2568
  const setOpen = (next) => {
2561
2569
  onOpenChange?.(next);
@@ -2658,16 +2666,16 @@ function LogoutTimer({
2658
2666
  logoutLabel = "Sign out now"
2659
2667
  }) {
2660
2668
  const reduced = framerMotion.useReducedMotion();
2661
- const [warning, setWarning] = React34.useState(false);
2662
- const [remaining, setRemaining] = React34.useState(countdown);
2663
- const idleTimer = React34.useRef(null);
2664
- const tick = React34.useRef(null);
2665
- const deadline = React34.useRef(0);
2666
- const warningRef = React34.useRef(false);
2667
- const lastReset = React34.useRef(0);
2668
- const cbs = React34.useRef({ onLogout, onContinue, onWarning });
2669
+ const [warning, setWarning] = React36.useState(false);
2670
+ const [remaining, setRemaining] = React36.useState(countdown);
2671
+ const idleTimer = React36.useRef(null);
2672
+ const tick = React36.useRef(null);
2673
+ const deadline = React36.useRef(0);
2674
+ const warningRef = React36.useRef(false);
2675
+ const lastReset = React36.useRef(0);
2676
+ const cbs = React36.useRef({ onLogout, onContinue, onWarning });
2669
2677
  cbs.current = { onLogout, onContinue, onWarning };
2670
- const clearTimers = React34.useCallback(() => {
2678
+ const clearTimers = React36.useCallback(() => {
2671
2679
  if (idleTimer.current) {
2672
2680
  clearTimeout(idleTimer.current);
2673
2681
  idleTimer.current = null;
@@ -2677,13 +2685,13 @@ function LogoutTimer({
2677
2685
  tick.current = null;
2678
2686
  }
2679
2687
  }, []);
2680
- const logout = React34.useCallback(() => {
2688
+ const logout = React36.useCallback(() => {
2681
2689
  clearTimers();
2682
2690
  warningRef.current = false;
2683
2691
  setWarning(false);
2684
2692
  cbs.current.onLogout();
2685
2693
  }, [clearTimers]);
2686
- const startIdle = React34.useCallback(() => {
2694
+ const startIdle = React36.useCallback(() => {
2687
2695
  if (idleTimer.current) clearTimeout(idleTimer.current);
2688
2696
  idleTimer.current = setTimeout(() => {
2689
2697
  warningRef.current = true;
@@ -2698,7 +2706,7 @@ function LogoutTimer({
2698
2706
  }, 250);
2699
2707
  }, timeout);
2700
2708
  }, [timeout, countdown, logout]);
2701
- const stay = React34.useCallback(() => {
2709
+ const stay = React36.useCallback(() => {
2702
2710
  if (tick.current) {
2703
2711
  clearInterval(tick.current);
2704
2712
  tick.current = null;
@@ -2708,7 +2716,7 @@ function LogoutTimer({
2708
2716
  cbs.current.onContinue?.();
2709
2717
  startIdle();
2710
2718
  }, [startIdle]);
2711
- React34.useEffect(() => {
2719
+ React36.useEffect(() => {
2712
2720
  if (!enabled) {
2713
2721
  clearTimers();
2714
2722
  warningRef.current = false;
@@ -2773,11 +2781,11 @@ function SegmentedControl({
2773
2781
  "aria-label": ariaLabel
2774
2782
  }) {
2775
2783
  const sz = SIZE5[size];
2776
- const groupId = React34.useId();
2777
- const errorId = React34.useId();
2784
+ const groupId = React36.useId();
2785
+ const errorId = React36.useId();
2778
2786
  const hasError = errorMessage != null;
2779
2787
  const isControlled = value !== void 0;
2780
- const [internal, setInternal] = React34.useState(defaultValue);
2788
+ const [internal, setInternal] = React36.useState(defaultValue);
2781
2789
  const current = isControlled ? value : internal;
2782
2790
  const handle = (v) => {
2783
2791
  if (!v) return;
@@ -2938,22 +2946,22 @@ function Scheduler({
2938
2946
  style
2939
2947
  }) {
2940
2948
  const reduced = framerMotion.useReducedMotion();
2941
- const [view, setView] = React34.useState(defaultView);
2942
- const [cursor, setCursor] = React34.useState(() => defaultDate ?? /* @__PURE__ */ new Date());
2943
- const [loaded, setLoaded] = React34.useState([]);
2944
- const [loading, setLoading] = React34.useState(false);
2945
- const [error, setError] = React34.useState(null);
2946
- const [reloadKey, setReloadKey] = React34.useState(0);
2947
- const [dir, setDir] = React34.useState(0);
2948
- const cbRef = React34.useRef({ loadEvents, onError });
2949
+ const [view, setView] = React36.useState(defaultView);
2950
+ const [cursor, setCursor] = React36.useState(() => defaultDate ?? /* @__PURE__ */ new Date());
2951
+ const [loaded, setLoaded] = React36.useState([]);
2952
+ const [loading, setLoading] = React36.useState(false);
2953
+ const [error, setError] = React36.useState(null);
2954
+ const [reloadKey, setReloadKey] = React36.useState(0);
2955
+ const [dir, setDir] = React36.useState(0);
2956
+ const cbRef = React36.useRef({ loadEvents, onError });
2949
2957
  cbRef.current = { loadEvents, onError };
2950
- const range = React34.useMemo(
2958
+ const range = React36.useMemo(
2951
2959
  () => view === "month" ? monthRange(cursor) : weekRange(cursor, weekStartsOn),
2952
2960
  [view, cursor, weekStartsOn]
2953
2961
  );
2954
2962
  const fromKey = range.from.getTime();
2955
2963
  const toKey = range.to.getTime();
2956
- React34.useEffect(() => {
2964
+ React36.useEffect(() => {
2957
2965
  const { loadEvents: loader, onError: onErr } = cbRef.current;
2958
2966
  if (!loader) return;
2959
2967
  let cancelled = false;
@@ -2973,16 +2981,16 @@ function Scheduler({
2973
2981
  cancelled = true;
2974
2982
  };
2975
2983
  }, [fromKey, toKey, view, reloadKey]);
2976
- const retry = React34.useCallback(() => setReloadKey((k) => k + 1), []);
2977
- const events = React34.useMemo(
2984
+ const retry = React36.useCallback(() => setReloadKey((k) => k + 1), []);
2985
+ const events = React36.useMemo(
2978
2986
  () => (controlledEvents ?? loaded).map(normalize),
2979
2987
  [controlledEvents, loaded]
2980
2988
  );
2981
- const go = React34.useCallback((delta) => {
2989
+ const go = React36.useCallback((delta) => {
2982
2990
  setDir(delta);
2983
2991
  setCursor((c) => view === "month" ? addMonths(c, delta) : addDays(c, delta * 7));
2984
2992
  }, [view]);
2985
- const goToday = React34.useCallback(() => {
2993
+ const goToday = React36.useCallback(() => {
2986
2994
  setDir(0);
2987
2995
  setCursor(/* @__PURE__ */ new Date());
2988
2996
  }, []);
@@ -3092,9 +3100,9 @@ function SchedulerError({ onRetry }) {
3092
3100
  ] });
3093
3101
  }
3094
3102
  function MonthYearPicker({ label, cursor, onPick }) {
3095
- const [open, setOpen] = React34.useState(false);
3096
- const [viewYear, setViewYear] = React34.useState(cursor.getFullYear());
3097
- React34.useEffect(() => {
3103
+ const [open, setOpen] = React36.useState(false);
3104
+ const [viewYear, setViewYear] = React36.useState(cursor.getFullYear());
3105
+ React36.useEffect(() => {
3098
3106
  if (open) setViewYear(cursor.getFullYear());
3099
3107
  }, [open, cursor]);
3100
3108
  return /* @__PURE__ */ jsxRuntime.jsxs(Popover__namespace.Root, { open, onOpenChange: setOpen, children: [
@@ -3168,8 +3176,8 @@ function MonthView({
3168
3176
  onSelectSlot,
3169
3177
  onSelectEvent
3170
3178
  }) {
3171
- const grid = React34.useMemo(() => buildMonthGrid(cursor, weekStartsOn), [cursor, weekStartsOn]);
3172
- const eventsByDay = React34.useMemo(() => bucketByDay(events), [events]);
3179
+ const grid = React36.useMemo(() => buildMonthGrid(cursor, weekStartsOn), [cursor, weekStartsOn]);
3180
+ const eventsByDay = React36.useMemo(() => bucketByDay(events), [events]);
3173
3181
  const labels = weekdayLabels(weekStartsOn);
3174
3182
  return /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex h-full flex-col", children: [
3175
3183
  /* @__PURE__ */ jsxRuntime.jsx("div", { className: "grid grid-cols-7 border-b border-border", children: labels.map((l) => /* @__PURE__ */ jsxRuntime.jsx("div", { className: "px-2 py-1.5 text-center text-[11px] font-medium uppercase tracking-wide text-foreground-muted", children: l }, l)) }),
@@ -3243,12 +3251,12 @@ function WeekView({
3243
3251
  onSelectSlot,
3244
3252
  onSelectEvent
3245
3253
  }) {
3246
- const days = React34.useMemo(() => getWeekDays(cursor, weekStartsOn), [cursor, weekStartsOn]);
3247
- const eventsByDay = React34.useMemo(() => bucketByDay(events), [events]);
3248
- const labels = React34.useMemo(() => weekdayLabels(weekStartsOn), [weekStartsOn]);
3254
+ const days = React36.useMemo(() => getWeekDays(cursor, weekStartsOn), [cursor, weekStartsOn]);
3255
+ const eventsByDay = React36.useMemo(() => bucketByDay(events), [events]);
3256
+ const labels = React36.useMemo(() => weekdayLabels(weekStartsOn), [weekStartsOn]);
3249
3257
  const dow = (d) => labels[(d.getDay() - weekStartsOn + 7) % 7];
3250
3258
  const [startHour, endHour] = dayHours;
3251
- const hours = React34.useMemo(
3259
+ const hours = React36.useMemo(
3252
3260
  () => Array.from({ length: endHour - startHour }, (_, i) => startHour + i),
3253
3261
  [startHour, endHour]
3254
3262
  );
@@ -3439,17 +3447,17 @@ function Cart({
3439
3447
  ] })
3440
3448
  ] });
3441
3449
  }
3442
- var CartContext = React34.createContext(null);
3450
+ var CartContext = React36.createContext(null);
3443
3451
  var clampQty = (qty, max) => {
3444
3452
  const lower = Math.max(1, Math.round(qty));
3445
3453
  return max != null ? Math.min(lower, max) : lower;
3446
3454
  };
3447
3455
  function CartProvider({ children, initialItems = [], onChange }) {
3448
- const [items, setItems] = React34.useState(initialItems);
3449
- React34.useEffect(() => {
3456
+ const [items, setItems] = React36.useState(initialItems);
3457
+ React36.useEffect(() => {
3450
3458
  onChange?.(items);
3451
3459
  }, [items]);
3452
- const addToCart = React34.useCallback((item, quantity) => {
3460
+ const addToCart = React36.useCallback((item, quantity) => {
3453
3461
  const addQty = quantity ?? item.quantity ?? 1;
3454
3462
  setItems((prev) => {
3455
3463
  const existing = prev.find((it) => it.id === item.id);
@@ -3462,29 +3470,29 @@ function CartProvider({ children, initialItems = [], onChange }) {
3462
3470
  return [...prev, { ...rest, quantity: clampQty(addQty, item.max) }];
3463
3471
  });
3464
3472
  }, []);
3465
- const removeFromCart = React34.useCallback((id) => {
3473
+ const removeFromCart = React36.useCallback((id) => {
3466
3474
  setItems((prev) => prev.filter((it) => it.id !== id));
3467
3475
  }, []);
3468
- const updateQuantity = React34.useCallback((id, quantity) => {
3476
+ const updateQuantity = React36.useCallback((id, quantity) => {
3469
3477
  setItems(
3470
3478
  (prev) => prev.map((it) => it.id === id ? { ...it, quantity: clampQty(quantity, it.max) } : it)
3471
3479
  );
3472
3480
  }, []);
3473
- const clearCart = React34.useCallback(() => setItems([]), []);
3474
- const isInCart = React34.useCallback((id) => items.some((it) => it.id === id), [items]);
3475
- const getItemCount = React34.useCallback(() => items.reduce((sum, it) => sum + it.quantity, 0), [items]);
3476
- const getCartTotal = React34.useCallback(
3481
+ const clearCart = React36.useCallback(() => setItems([]), []);
3482
+ const isInCart = React36.useCallback((id) => items.some((it) => it.id === id), [items]);
3483
+ const getItemCount = React36.useCallback(() => items.reduce((sum, it) => sum + it.quantity, 0), [items]);
3484
+ const getCartTotal = React36.useCallback(
3477
3485
  () => items.reduce((sum, it) => sum + it.price * it.quantity, 0),
3478
3486
  [items]
3479
3487
  );
3480
- const value = React34.useMemo(
3488
+ const value = React36.useMemo(
3481
3489
  () => ({ items, addToCart, removeFromCart, updateQuantity, clearCart, isInCart, getItemCount, getCartTotal }),
3482
3490
  [items, addToCart, removeFromCart, updateQuantity, clearCart, isInCart, getItemCount, getCartTotal]
3483
3491
  );
3484
3492
  return /* @__PURE__ */ jsxRuntime.jsx(CartContext.Provider, { value, children });
3485
3493
  }
3486
3494
  function useCart() {
3487
- const ctx = React34.useContext(CartContext);
3495
+ const ctx = React36.useContext(CartContext);
3488
3496
  if (!ctx) {
3489
3497
  throw new Error("useCart must be used within a <CartProvider>.");
3490
3498
  }
@@ -3826,11 +3834,11 @@ function buildBindings(store, name, kind, snap) {
3826
3834
 
3827
3835
  // src/form/useForm.ts
3828
3836
  function useForm(options = {}) {
3829
- const ref = React34.useRef(null);
3837
+ const ref = React36.useRef(null);
3830
3838
  if (ref.current === null) ref.current = new FormStore(options);
3831
3839
  const store = ref.current;
3832
- React34.useSyncExternalStore(store.subscribe, store.getRootSnapshot, store.getRootSnapshot);
3833
- const make = React34.useCallback(
3840
+ React36.useSyncExternalStore(store.subscribe, store.getRootSnapshot, store.getRootSnapshot);
3841
+ const make = React36.useCallback(
3834
3842
  (kind) => (name, rules) => {
3835
3843
  if (rules !== void 0) store.setRule(name, rules);
3836
3844
  return buildBindings(store, name, kind, store.getFieldSnapshot(name));
@@ -3860,9 +3868,9 @@ function useForm(options = {}) {
3860
3868
  fieldTarget: make("target")
3861
3869
  };
3862
3870
  }
3863
- var FormContext = React34.createContext(null);
3871
+ var FormContext = React36.createContext(null);
3864
3872
  function useFormStore() {
3865
- const store = React34.useContext(FormContext);
3873
+ const store = React36.useContext(FormContext);
3866
3874
  if (!store) {
3867
3875
  throw new Error("useFormStore must be used within a <Form>. Did you forget to wrap your fields?");
3868
3876
  }
@@ -3876,8 +3884,8 @@ function Form({
3876
3884
  children,
3877
3885
  ...rest
3878
3886
  }) {
3879
- const ref = React34.useRef(null);
3880
- const bypass = React34.useRef(false);
3887
+ const ref = React36.useRef(null);
3888
+ const bypass = React36.useRef(false);
3881
3889
  const handleSubmit = async (e) => {
3882
3890
  if (bypass.current) {
3883
3891
  bypass.current = false;
@@ -3934,12 +3942,12 @@ function useFormField(name, options = {}) {
3934
3942
  const store = useFormStore();
3935
3943
  const { kind = "value", rules } = options;
3936
3944
  if (rules !== void 0 && store.getRule(name) !== rules) store.setRule(name, rules);
3937
- React34.useEffect(() => {
3945
+ React36.useEffect(() => {
3938
3946
  return () => {
3939
3947
  if (rules !== void 0) store.removeRule(name);
3940
3948
  };
3941
3949
  }, [store, name]);
3942
- const snap = React34.useSyncExternalStore(
3950
+ const snap = React36.useSyncExternalStore(
3943
3951
  store.subscribe,
3944
3952
  () => store.getFieldSnapshot(name)
3945
3953
  );
@@ -3951,7 +3959,7 @@ function FormField({ name, kind, rules, children }) {
3951
3959
  }
3952
3960
  function useFieldArray(name) {
3953
3961
  const store = useFormStore();
3954
- React34.useSyncExternalStore(store.subscribe, store.getRootSnapshot, store.getRootSnapshot);
3962
+ React36.useSyncExternalStore(store.subscribe, store.getRootSnapshot, store.getRootSnapshot);
3955
3963
  const arr = store.getValue(name) ?? [];
3956
3964
  const keys = store.getKeys(name);
3957
3965
  return {
@@ -3984,7 +3992,7 @@ function TextInput({
3984
3992
  suffix,
3985
3993
  id
3986
3994
  }) {
3987
- const errorId = React34.useId();
3995
+ const errorId = React36.useId();
3988
3996
  const hasError = errorMessage != null;
3989
3997
  const hasAdornment = prefix != null || suffix != null;
3990
3998
  const inputId = htmlFor ?? id;
@@ -4145,7 +4153,7 @@ function CreditCardForm({
4145
4153
  className = "",
4146
4154
  style
4147
4155
  }) {
4148
- const initial = React34.useRef({
4156
+ const initial = React36.useRef({
4149
4157
  number: formatCardNumber(defaultValue?.number ?? ""),
4150
4158
  name: defaultValue?.name ?? "",
4151
4159
  expiry: formatExpiry(defaultValue?.expiry ?? ""),
@@ -4154,7 +4162,7 @@ function CreditCardForm({
4154
4162
  const form = useForm({ initialValues: initial });
4155
4163
  const numberStr = String(form.values.number ?? "");
4156
4164
  const brand = detectBrand(numberStr);
4157
- React34.useEffect(() => {
4165
+ React36.useEffect(() => {
4158
4166
  onChange?.(toCard(form.values));
4159
4167
  }, [form.values.number, form.values.name, form.values.expiry, form.values.cvv]);
4160
4168
  const numberBind = form.fieldNative("number", {
@@ -4277,7 +4285,7 @@ function Checkout({
4277
4285
  ] })
4278
4286
  ] });
4279
4287
  }
4280
- var NotificationContext = React34.createContext({
4288
+ var NotificationContext = React36.createContext({
4281
4289
  open: () => void 0,
4282
4290
  close: () => void 0
4283
4291
  });
@@ -4335,26 +4343,26 @@ function NotificationItem({
4335
4343
  onClose,
4336
4344
  reduced
4337
4345
  }) {
4338
- const [paused, setPaused] = React34.useState(false);
4346
+ const [paused, setPaused] = React36.useState(false);
4339
4347
  const duration = n.duration ?? 4e3;
4340
4348
  const isAutoDismissing = isFinite(duration) && duration > 0;
4341
4349
  const showProgress = !reduced && isAutoDismissing;
4342
- const timerRef = React34.useRef(null);
4343
- const startTimeRef = React34.useRef(0);
4344
- const remainingRef = React34.useRef(duration);
4345
- const clearTimer = React34.useCallback(() => {
4350
+ const timerRef = React36.useRef(null);
4351
+ const startTimeRef = React36.useRef(0);
4352
+ const remainingRef = React36.useRef(duration);
4353
+ const clearTimer = React36.useCallback(() => {
4346
4354
  if (timerRef.current !== null) {
4347
4355
  clearTimeout(timerRef.current);
4348
4356
  timerRef.current = null;
4349
4357
  }
4350
4358
  }, []);
4351
- const scheduleDismiss = React34.useCallback((ms) => {
4359
+ const scheduleDismiss = React36.useCallback((ms) => {
4352
4360
  clearTimer();
4353
4361
  if (!isAutoDismissing) return;
4354
4362
  startTimeRef.current = Date.now();
4355
4363
  timerRef.current = setTimeout(() => onClose(n.id), ms);
4356
4364
  }, [clearTimer, isAutoDismissing, n.id, onClose]);
4357
- React34.useEffect(() => {
4365
+ React36.useEffect(() => {
4358
4366
  if (paused || !isAutoDismissing) return;
4359
4367
  scheduleDismiss(remainingRef.current);
4360
4368
  return clearTimer;
@@ -4437,15 +4445,15 @@ function NotificationProvider({
4437
4445
  children,
4438
4446
  position = "top-right"
4439
4447
  }) {
4440
- const [notifications, setNotifications] = React34.useState([]);
4448
+ const [notifications, setNotifications] = React36.useState([]);
4441
4449
  const reduced = framerMotion.useReducedMotion();
4442
- const open = React34.useCallback((payload) => {
4450
+ const open = React36.useCallback((payload) => {
4443
4451
  setNotifications((prev) => [
4444
4452
  ...prev,
4445
4453
  { duration: 4e3, ...payload, id: Date.now() + Math.random() }
4446
4454
  ]);
4447
4455
  }, []);
4448
- const close = React34.useCallback((id) => {
4456
+ const close = React36.useCallback((id) => {
4449
4457
  setNotifications((prev) => prev.filter((n) => n.id !== id));
4450
4458
  }, []);
4451
4459
  return /* @__PURE__ */ jsxRuntime.jsxs(NotificationContext.Provider, { value: { open, close }, children: [
@@ -4474,7 +4482,7 @@ function NotificationProvider({
4474
4482
  ] });
4475
4483
  }
4476
4484
  function useNotification() {
4477
- const { open } = React34.useContext(NotificationContext);
4485
+ const { open } = React36.useContext(NotificationContext);
4478
4486
  return {
4479
4487
  info: (props) => open({ type: "info", ...props }),
4480
4488
  success: (props) => open({ type: "success", ...props }),
@@ -4591,10 +4599,10 @@ function FadingBase({
4591
4599
  isMounted = false,
4592
4600
  children
4593
4601
  }) {
4594
- const [shouldRender, setShouldRender] = React34.useState(isMounted);
4595
- const [visible, setVisible] = React34.useState(false);
4596
- const timerRef = React34.useRef(null);
4597
- React34.useEffect(() => {
4602
+ const [shouldRender, setShouldRender] = React36.useState(isMounted);
4603
+ const [visible, setVisible] = React36.useState(false);
4604
+ const timerRef = React36.useRef(null);
4605
+ React36.useEffect(() => {
4598
4606
  if (isMounted) {
4599
4607
  setShouldRender(true);
4600
4608
  const rafId = requestAnimationFrame(() => setVisible(true));
@@ -4706,14 +4714,14 @@ function ScalableContainer({
4706
4714
  togglePosition = "top-right",
4707
4715
  className = ""
4708
4716
  }) {
4709
- const containerRef = React34.useRef(null);
4710
- const [internalScaled, setInternalScaled] = React34.useState(false);
4717
+ const containerRef = React36.useRef(null);
4718
+ const [internalScaled, setInternalScaled] = React36.useState(false);
4711
4719
  const isScaled = expanded ?? internalScaled;
4712
4720
  const reduced = framerMotion.useReducedMotion();
4713
- const prevScaled = React34.useRef(isScaled);
4721
+ const prevScaled = React36.useRef(isScaled);
4714
4722
  const expandW = targetWidth ?? expandedWidth;
4715
4723
  const expandH = targetHeight ?? expandedHeight;
4716
- React34.useEffect(() => {
4724
+ React36.useEffect(() => {
4717
4725
  if (isScaled === prevScaled.current) return;
4718
4726
  prevScaled.current = isScaled;
4719
4727
  if (typeof window === "undefined") return;
@@ -4860,17 +4868,17 @@ function CatalogGrid({ items, buttonText, onOpen, className = "" }) {
4860
4868
  return /* @__PURE__ */ jsxRuntime.jsx("div", { className: `flex flex-wrap gap-2 ${className}`.trim(), children: items.map((item) => /* @__PURE__ */ jsxRuntime.jsx(GridCard, { item, buttonText, onOpen }, item.key)) });
4861
4869
  }
4862
4870
  function CatalogCarousel({ items, buttonText, onOpen, className = "" }) {
4863
- const [activeIndex, setActiveIndex] = React34.useState(0);
4864
- const [indexPool, setIndexPool] = React34.useState([]);
4865
- const cardRefs = React34.useRef([]);
4866
- const getIndexes = React34.useMemo(() => {
4871
+ const [activeIndex, setActiveIndex] = React36.useState(0);
4872
+ const [indexPool, setIndexPool] = React36.useState([]);
4873
+ const cardRefs = React36.useRef([]);
4874
+ const getIndexes = React36.useMemo(() => {
4867
4875
  let nextIndex = activeIndex + 1;
4868
4876
  let previousIndex = activeIndex - 1;
4869
4877
  if (activeIndex === 0) previousIndex = items.length - 1;
4870
4878
  if (activeIndex === items.length - 1) nextIndex = 0;
4871
4879
  return { previousIndex, nextIndex };
4872
4880
  }, [activeIndex, items.length]);
4873
- React34.useEffect(() => {
4881
+ React36.useEffect(() => {
4874
4882
  const { nextIndex, previousIndex } = getIndexes;
4875
4883
  let indexes = [previousIndex, activeIndex, nextIndex];
4876
4884
  if (activeIndex !== 0 && activeIndex !== items.length - 1) {
@@ -5043,8 +5051,8 @@ function writeDismissed(key) {
5043
5051
  }
5044
5052
  }
5045
5053
  function useTargetBbox(ref) {
5046
- const [bbox, setBbox] = React34.useState(null);
5047
- React34.useLayoutEffect(() => {
5054
+ const [bbox, setBbox] = React36.useState(null);
5055
+ React36.useLayoutEffect(() => {
5048
5056
  const el = ref?.current;
5049
5057
  if (!el) {
5050
5058
  setBbox(null);
@@ -5074,7 +5082,7 @@ function tooltipStyleFor(bbox, placement) {
5074
5082
  return { left: bbox.left + bbox.width / 2, top: bbox.top - TOOLTIP_GAP, transform: "translate(-50%, -100%)", width: TOOLTIP_WIDTH };
5075
5083
  }
5076
5084
  function useFocusTrap(containerRef, active) {
5077
- React34.useEffect(() => {
5085
+ React36.useEffect(() => {
5078
5086
  if (!active) return;
5079
5087
  const el = containerRef.current;
5080
5088
  if (!el) return;
@@ -5113,16 +5121,16 @@ function Wizard({
5113
5121
  onComplete,
5114
5122
  onSkip
5115
5123
  }) {
5116
- const tooltipRef = React34.useRef(null);
5117
- const tooltipTitleId = React34.useId();
5118
- const tooltipBodyId = React34.useId();
5124
+ const tooltipRef = React36.useRef(null);
5125
+ const tooltipTitleId = React36.useId();
5126
+ const tooltipBodyId = React36.useId();
5119
5127
  const reduced = framerMotion.useReducedMotion();
5120
- const [open, setOpen] = React34.useState(() => steps.length > 0 && !readDismissed(storageKey));
5121
- const [activeIndex, setActiveIndex] = React34.useState(0);
5128
+ const [open, setOpen] = React36.useState(() => steps.length > 0 && !readDismissed(storageKey));
5129
+ const [activeIndex, setActiveIndex] = React36.useState(0);
5122
5130
  const step = steps[activeIndex];
5123
5131
  const bbox = useTargetBbox(step?.stepRef);
5124
5132
  useFocusTrap(tooltipRef, open);
5125
- React34.useEffect(() => {
5133
+ React36.useEffect(() => {
5126
5134
  if (!open || !dismissible) return;
5127
5135
  const onKey = (e) => {
5128
5136
  if (e.key === "Escape") {
@@ -5133,12 +5141,12 @@ function Wizard({
5133
5141
  document.addEventListener("keydown", onKey);
5134
5142
  return () => document.removeEventListener("keydown", onKey);
5135
5143
  }, [open, dismissible]);
5136
- const handleSkip = React34.useCallback(() => {
5144
+ const handleSkip = React36.useCallback(() => {
5137
5145
  writeDismissed(storageKey);
5138
5146
  setOpen(false);
5139
5147
  onSkip?.();
5140
5148
  }, [storageKey, onSkip]);
5141
- const handleComplete = React34.useCallback(() => {
5149
+ const handleComplete = React36.useCallback(() => {
5142
5150
  writeDismissed(storageKey);
5143
5151
  setOpen(false);
5144
5152
  onComplete?.();
@@ -5281,7 +5289,7 @@ function Wizard({
5281
5289
  ] });
5282
5290
  }
5283
5291
  var SearchIcon = /* @__PURE__ */ jsxRuntime.jsx("svg", { xmlns: "http://www.w3.org/2000/svg", viewBox: "0 0 24 24", fill: "currentColor", className: "w-4 h-4", "aria-hidden": "true", children: /* @__PURE__ */ jsxRuntime.jsx("path", { fillRule: "evenodd", d: "M10.5 3.75a6.75 6.75 0 100 13.5 6.75 6.75 0 000-13.5zM2.25 10.5a8.25 8.25 0 1114.59 5.28l4.69 4.69a.75.75 0 11-1.06 1.06l-4.69-4.69A8.25 8.25 0 012.25 10.5z", clipRule: "evenodd" }) });
5284
- var SearchInput = React34__default.default.forwardRef(function SearchInput2({ value, onChange, disabled, label, htmlFor, placeholder, name, inputStyle, style, layout = "vertical", size = "md", icon, helperText, className }, ref) {
5292
+ var SearchInput = React36__default.default.forwardRef(function SearchInput2({ value, onChange, disabled, label, htmlFor, placeholder, name, inputStyle, style, layout = "vertical", size = "md", icon, helperText, className }, ref) {
5285
5293
  return /* @__PURE__ */ jsxRuntime.jsx(Field, { className, label, htmlFor, layout, helperText, children: /* @__PURE__ */ jsxRuntime.jsxs(
5286
5294
  "div",
5287
5295
  {
@@ -5516,15 +5524,15 @@ function EditableCell({
5516
5524
  rowIndex,
5517
5525
  onCellEdit
5518
5526
  }) {
5519
- const [editing, setEditing] = React34.useState(false);
5520
- const editRef = React34.useRef(null);
5527
+ const [editing, setEditing] = React36.useState(false);
5528
+ const editRef = React36.useRef(null);
5521
5529
  const value = row[col.keyBind];
5522
5530
  const commit = (next) => {
5523
5531
  setEditing(false);
5524
5532
  onCellEdit?.({ row, key: col.keyBind, value: next, rowIndex });
5525
5533
  };
5526
5534
  const cancel = () => setEditing(false);
5527
- React34.useEffect(() => {
5535
+ React36.useEffect(() => {
5528
5536
  if (!editing || !col.editor) return;
5529
5537
  const onMouseDown = (e) => {
5530
5538
  const target = e.target;
@@ -5583,7 +5591,7 @@ function TableBody({
5583
5591
  getRowKey,
5584
5592
  onCellEdit
5585
5593
  }) {
5586
- const [expanded, setExpanded] = React34.useState(() => /* @__PURE__ */ new Set());
5594
+ const [expanded, setExpanded] = React36.useState(() => /* @__PURE__ */ new Set());
5587
5595
  const reduced = framerMotion.useReducedMotion();
5588
5596
  const toggleRow = (rowKey) => {
5589
5597
  setExpanded((prev) => {
@@ -5598,7 +5606,7 @@ function TableBody({
5598
5606
  return /* @__PURE__ */ jsxRuntime.jsx("tbody", { children: rows.map((row, i) => {
5599
5607
  const rowKey = getRowKey(row, i);
5600
5608
  const isExpanded = expanded.has(rowKey);
5601
- return /* @__PURE__ */ jsxRuntime.jsxs(React34__default.default.Fragment, { children: [
5609
+ return /* @__PURE__ */ jsxRuntime.jsxs(React36__default.default.Fragment, { children: [
5602
5610
  /* @__PURE__ */ jsxRuntime.jsxs(
5603
5611
  "tr",
5604
5612
  {
@@ -5710,13 +5718,13 @@ function Table({
5710
5718
  className = "",
5711
5719
  style
5712
5720
  }) {
5713
- const searchRef = React34.useRef(null);
5714
- const [searchTerm, setSearchTerm] = React34.useState("");
5715
- const [perPage, setPerPage] = React34.useState(
5721
+ const searchRef = React36.useRef(null);
5722
+ const [searchTerm, setSearchTerm] = React36.useState("");
5723
+ const [perPage, setPerPage] = React36.useState(
5716
5724
  typeof pagination.perPage === "number" ? pagination.perPage : 15
5717
5725
  );
5718
- const [activePage, setActivePage] = React34.useState(0);
5719
- const [sortState, setSortState] = React34.useState(defaultSort);
5726
+ const [activePage, setActivePage] = React36.useState(0);
5727
+ const [sortState, setSortState] = React36.useState(defaultSort);
5720
5728
  const isServerSide = !!(pagination.enabled && pagination.serverSide);
5721
5729
  const handleSort = (col) => {
5722
5730
  const key = col.keyBind;
@@ -5728,8 +5736,8 @@ function Table({
5728
5736
  onSortChange?.(next);
5729
5737
  };
5730
5738
  const debounceMs = search?.debounceMs ?? 0;
5731
- const [debouncedTerm, setDebouncedTerm] = React34.useState("");
5732
- React34.useEffect(() => {
5739
+ const [debouncedTerm, setDebouncedTerm] = React36.useState("");
5740
+ React36.useEffect(() => {
5733
5741
  if (debounceMs <= 0) {
5734
5742
  setDebouncedTerm(searchTerm);
5735
5743
  return;
@@ -5738,7 +5746,7 @@ function Table({
5738
5746
  return () => clearTimeout(t);
5739
5747
  }, [searchTerm, debounceMs]);
5740
5748
  const term = debounceMs > 0 ? debouncedTerm : searchTerm;
5741
- const filteredRows = React34.useMemo(() => {
5749
+ const filteredRows = React36.useMemo(() => {
5742
5750
  if (isServerSide || !term) return rows;
5743
5751
  if (search?.predicate) return rows.filter((row) => search.predicate(row, term));
5744
5752
  const cs = !!search?.caseSensitive;
@@ -5752,7 +5760,7 @@ function Table({
5752
5760
  };
5753
5761
  return rows.filter((row) => keys ? keys.some((k) => test(row[k])) : Object.values(row).some(test));
5754
5762
  }, [rows, term, isServerSide, search?.predicate, search?.caseSensitive, search?.matchMode, search?.keys]);
5755
- const sortedRows = React34.useMemo(() => {
5763
+ const sortedRows = React36.useMemo(() => {
5756
5764
  if (isServerSide || !sortState) return filteredRows;
5757
5765
  const col = columns.find((c) => c.keyBind === sortState.key);
5758
5766
  const accessor = col?.sortAccessor ?? ((r) => r[sortState.key]);
@@ -5760,29 +5768,29 @@ function Table({
5760
5768
  if (sortState.direction === "desc") out.reverse();
5761
5769
  return out;
5762
5770
  }, [filteredRows, sortState, isServerSide, columns]);
5763
- const datasets = React34.useMemo(() => {
5771
+ const datasets = React36.useMemo(() => {
5764
5772
  if (isServerSide) return [rows];
5765
5773
  return createDatasets(sortedRows, pagination.enabled ? perPage : null);
5766
5774
  }, [sortedRows, perPage, pagination.enabled, isServerSide, rows]);
5767
- const MAX_PAGE = React34.useMemo(() => {
5775
+ const MAX_PAGE = React36.useMemo(() => {
5768
5776
  if (isServerSide && typeof pagination.maxPage === "number") return Math.max(0, pagination.maxPage);
5769
5777
  if (isServerSide && typeof pagination.totalCount === "number")
5770
5778
  return Math.max(0, Math.ceil(pagination.totalCount / perPage) - 1);
5771
5779
  return datasets.length ? datasets.length - 1 : 0;
5772
5780
  }, [isServerSide, pagination.maxPage, pagination.totalCount, perPage, datasets.length]);
5773
- const currentPageRows = React34.useMemo(() => {
5781
+ const currentPageRows = React36.useMemo(() => {
5774
5782
  if (isServerSide) return rows;
5775
5783
  return datasets[activePage] ?? [];
5776
5784
  }, [isServerSide, rows, datasets, activePage]);
5777
- React34.useEffect(() => {
5785
+ React36.useEffect(() => {
5778
5786
  if (pagination.enabled && !isServerSide && typeof pagination.perPage === "number") {
5779
5787
  setPerPage(pagination.perPage);
5780
5788
  }
5781
5789
  }, [pagination.enabled, pagination.perPage, isServerSide]);
5782
- React34.useEffect(() => {
5790
+ React36.useEffect(() => {
5783
5791
  if (isServerSide && typeof pagination.perPage === "number") setPerPage(pagination.perPage);
5784
5792
  }, [isServerSide, pagination.perPage]);
5785
- React34.useEffect(() => {
5793
+ React36.useEffect(() => {
5786
5794
  if (isServerSide && typeof pagination.page === "number" && pagination.page >= 1)
5787
5795
  setActivePage(pagination.page - 1);
5788
5796
  }, [isServerSide, pagination.page]);
@@ -5871,7 +5879,7 @@ function TableSkeletonBody({
5871
5879
  i
5872
5880
  )) });
5873
5881
  }
5874
- var useIsoLayoutEffect = typeof window !== "undefined" ? React34.useLayoutEffect : React34.useEffect;
5882
+ var useIsoLayoutEffect = typeof window !== "undefined" ? React36.useLayoutEffect : React36.useEffect;
5875
5883
  function VirtualList({
5876
5884
  items,
5877
5885
  rowHeight,
@@ -5888,10 +5896,10 @@ function VirtualList({
5888
5896
  className = "",
5889
5897
  style
5890
5898
  }) {
5891
- const scrollRef = React34.useRef(null);
5892
- const [scrollTop, setScrollTop] = React34.useState(0);
5893
- const [viewport, setViewport] = React34.useState(typeof height === "number" ? height : 400);
5894
- const [term, setTerm] = React34.useState("");
5899
+ const scrollRef = React36.useRef(null);
5900
+ const [scrollTop, setScrollTop] = React36.useState(0);
5901
+ const [viewport, setViewport] = React36.useState(typeof height === "number" ? height : 400);
5902
+ const [term, setTerm] = React36.useState("");
5895
5903
  useIsoLayoutEffect(() => {
5896
5904
  const el = scrollRef.current;
5897
5905
  if (!el) return;
@@ -5902,7 +5910,7 @@ function VirtualList({
5902
5910
  ro.observe(el);
5903
5911
  return () => ro.disconnect();
5904
5912
  }, []);
5905
- const filtered = React34.useMemo(() => {
5913
+ const filtered = React36.useMemo(() => {
5906
5914
  if (!searchable || !term) return items;
5907
5915
  if (filter) return items.filter((it) => filter(it, term));
5908
5916
  const needle = term.toLowerCase();
@@ -5973,6 +5981,15 @@ async function sourceToBytes(source, remote) {
5973
5981
  }
5974
5982
  throw new Error("Unsupported source type");
5975
5983
  }
5984
+ function downloadBlob(blob, name) {
5985
+ if (typeof document === "undefined") return;
5986
+ const url = URL.createObjectURL(blob);
5987
+ const a = document.createElement("a");
5988
+ a.href = url;
5989
+ a.download = name;
5990
+ a.click();
5991
+ setTimeout(() => URL.revokeObjectURL(url), 1e3);
5992
+ }
5976
5993
  function sourceName(source) {
5977
5994
  if (typeof File !== "undefined" && source instanceof File) return source.name;
5978
5995
  if (isUrlSource(source)) {
@@ -5983,17 +6000,45 @@ function sourceName(source) {
5983
6000
  return void 0;
5984
6001
  }
5985
6002
  var pdfjsPromise = null;
5986
- function loadPdfjs() {
6003
+ function loadPdfjs(workerSrc) {
5987
6004
  if (pdfjsPromise) return pdfjsPromise;
5988
6005
  pdfjsPromise = import('pdfjs-dist').then((pdfjs) => {
5989
6006
  if (!pdfjs.GlobalWorkerOptions.workerSrc) {
5990
- pdfjs.GlobalWorkerOptions.workerSrc = `https://cdn.jsdelivr.net/npm/pdfjs-dist@${pdfjs.version}/build/pdf.worker.min.mjs`;
6007
+ pdfjs.GlobalWorkerOptions.workerSrc = workerSrc ?? `https://cdn.jsdelivr.net/npm/pdfjs-dist@${pdfjs.version}/build/pdf.worker.min.mjs`;
5991
6008
  }
5992
6009
  return pdfjs;
5993
6010
  });
5994
6011
  return pdfjsPromise;
5995
6012
  }
5996
6013
  var GAP = 12;
6014
+ var SEARCH_DEBOUNCE = 220;
6015
+ var TEXT_LAYER_STYLE_ID = "oxygen-pdf-textlayer";
6016
+ var TEXT_LAYER_CSS = `
6017
+ .oxy-textLayer{position:absolute;inset:0;overflow:clip;line-height:1;text-size-adjust:none;forced-color-adjust:none;transform-origin:0 0}
6018
+ .oxy-textLayer span,.oxy-textLayer br{color:transparent;position:absolute;white-space:pre;cursor:text;transform-origin:0 0}
6019
+ .oxy-textLayer span.markedContent{top:0;height:0}
6020
+ .oxy-textLayer ::selection{background:color-mix(in srgb, var(--color-accent) 35%, transparent)}
6021
+ `;
6022
+ function ensureTextLayerStyles() {
6023
+ if (typeof document === "undefined" || document.getElementById(TEXT_LAYER_STYLE_ID)) return;
6024
+ const el = document.createElement("style");
6025
+ el.id = TEXT_LAYER_STYLE_ID;
6026
+ el.textContent = TEXT_LAYER_CSS;
6027
+ document.head.appendChild(el);
6028
+ }
6029
+ function pageIndexAt(offsets, y) {
6030
+ let lo = 0;
6031
+ let hi = offsets.length - 1;
6032
+ let ans = 0;
6033
+ while (lo <= hi) {
6034
+ const mid = lo + hi >> 1;
6035
+ if (offsets[mid] <= y) {
6036
+ ans = mid;
6037
+ lo = mid + 1;
6038
+ } else hi = mid - 1;
6039
+ }
6040
+ return ans;
6041
+ }
5997
6042
  function PdfViewer({
5998
6043
  source,
5999
6044
  remote,
@@ -6002,37 +6047,53 @@ function PdfViewer({
6002
6047
  toolbar = true,
6003
6048
  thumbnails = false,
6004
6049
  textLayer = true,
6050
+ workerSrc,
6005
6051
  onLoad,
6006
6052
  onError,
6007
6053
  onPageChange,
6054
+ height = 600,
6055
+ width,
6008
6056
  className = "",
6009
6057
  style
6010
6058
  }) {
6011
- const [pdfjs, setPdfjs] = React34.useState(null);
6012
- const [doc, setDoc] = React34.useState(null);
6013
- const [numPages, setNumPages] = React34.useState(0);
6014
- const [baseSize, setBaseSize] = React34.useState(null);
6015
- const [status, setStatus] = React34.useState("loading");
6016
- const [error, setError] = React34.useState(null);
6017
- const [reloadKey, setReloadKey] = React34.useState(0);
6018
- const scrollRef = React34.useRef(null);
6019
- const [scrollTop, setScrollTop] = React34.useState(0);
6020
- const [viewport, setViewport] = React34.useState({ w: 0, h: 0 });
6021
- const [zoomMode, setZoomMode] = React34.useState(zoom);
6022
- const [page, setPage] = React34.useState(initialPage);
6023
- const [showSearch, setShowSearch] = React34.useState(false);
6024
- const [query, setQuery] = React34.useState("");
6025
- const [matchPages, setMatchPages] = React34.useState(null);
6026
- const [matchIdx, setMatchIdx] = React34.useState(0);
6059
+ const [pdfjs, setPdfjs] = React36.useState(null);
6060
+ const [doc, setDoc] = React36.useState(null);
6061
+ const [numPages, setNumPages] = React36.useState(0);
6062
+ const [baseSize, setBaseSize] = React36.useState(null);
6063
+ const [sizes, setSizes] = React36.useState([]);
6064
+ const [status, setStatus] = React36.useState("loading");
6065
+ const [error, setError] = React36.useState(null);
6066
+ const [reloadKey, setReloadKey] = React36.useState(0);
6067
+ const scrollRef = React36.useRef(null);
6068
+ const [scrollTop, setScrollTop] = React36.useState(0);
6069
+ const [viewport, setViewport] = React36.useState({ w: 0, h: 0 });
6070
+ const [zoomMode, setZoomMode] = React36.useState(zoom);
6071
+ const [page, setPage] = React36.useState(initialPage);
6072
+ const [showSearch, setShowSearch] = React36.useState(false);
6073
+ const [query, setQuery] = React36.useState("");
6074
+ const [matchPages, setMatchPages] = React36.useState(null);
6075
+ const [matchIdx, setMatchIdx] = React36.useState(0);
6076
+ const [searching, setSearching] = React36.useState(false);
6077
+ const [pageDraft, setPageDraft] = React36.useState("");
6078
+ const pageEditing = React36.useRef(false);
6079
+ const pageText = React36.useRef(/* @__PURE__ */ new Map());
6080
+ const searchSeq = React36.useRef(0);
6081
+ const searchTimer = React36.useRef(null);
6082
+ const measured = React36.useRef(/* @__PURE__ */ new Set());
6027
6083
  const tb = toolbar === true ? { zoom: true, pager: true, download: true, print: true, search: true } : toolbar || {};
6028
- React34.useEffect(() => {
6084
+ React36.useEffect(() => {
6029
6085
  let cancelled = false;
6030
6086
  let task;
6031
6087
  setStatus("loading");
6032
6088
  setError(null);
6033
6089
  setDoc(null);
6034
6090
  setBaseSize(null);
6035
- loadPdfjs().then(async (pdfjs2) => {
6091
+ setSizes([]);
6092
+ pageText.current.clear();
6093
+ measured.current = /* @__PURE__ */ new Set();
6094
+ setMatchPages(null);
6095
+ setMatchIdx(0);
6096
+ loadPdfjs(workerSrc).then(async (pdfjs2) => {
6036
6097
  if (cancelled) return;
6037
6098
  setPdfjs(pdfjs2);
6038
6099
  const params = isUrlSource(source) ? { url: urlHref(source), httpHeaders: remote?.httpHeaders, withCredentials: remote?.withCredentials } : { data: source instanceof Uint8Array || source instanceof ArrayBuffer ? source : new Uint8Array(await source.arrayBuffer()) };
@@ -6045,9 +6106,12 @@ function PdfViewer({
6045
6106
  const first = await pdf.getPage(1);
6046
6107
  const vp = first.getViewport({ scale: 1 });
6047
6108
  if (cancelled) return;
6109
+ const base = { width: vp.width, height: vp.height };
6048
6110
  setDoc(pdf);
6049
6111
  setNumPages(pdf.numPages);
6050
- setBaseSize({ width: vp.width, height: vp.height });
6112
+ setBaseSize(base);
6113
+ setSizes(Array.from({ length: pdf.numPages }, () => base));
6114
+ measured.current.add(1);
6051
6115
  setStatus("ready");
6052
6116
  onLoad?.({ numPages: pdf.numPages });
6053
6117
  }).catch((err) => {
@@ -6060,11 +6124,11 @@ function PdfViewer({
6060
6124
  cancelled = true;
6061
6125
  task?.destroy?.();
6062
6126
  };
6063
- }, [source, remote, reloadKey]);
6064
- React34.useEffect(() => () => {
6127
+ }, [source, remote, reloadKey, workerSrc]);
6128
+ React36.useEffect(() => () => {
6065
6129
  doc?.destroy?.();
6066
6130
  }, [doc]);
6067
- React34.useEffect(() => {
6131
+ React36.useEffect(() => {
6068
6132
  const el = scrollRef.current;
6069
6133
  if (!el || typeof ResizeObserver === "undefined") return;
6070
6134
  const measure = () => setViewport({ w: el.clientWidth, h: el.clientHeight });
@@ -6073,83 +6137,119 @@ function PdfViewer({
6073
6137
  ro.observe(el);
6074
6138
  return () => ro.disconnect();
6075
6139
  }, [status]);
6076
- const scale = React34.useMemo(() => {
6140
+ const handleMeasure = React36.useCallback((p, size) => {
6141
+ setSizes((prev) => {
6142
+ const cur = prev[p - 1];
6143
+ if (cur && Math.abs(cur.width - size.width) < 0.5 && Math.abs(cur.height - size.height) < 0.5) return prev;
6144
+ const next = prev.slice();
6145
+ next[p - 1] = size;
6146
+ return next;
6147
+ });
6148
+ }, []);
6149
+ const scale = React36.useMemo(() => {
6077
6150
  if (!baseSize) return 1;
6078
6151
  if (typeof zoomMode === "number") return zoomMode;
6079
- const avail = Math.max(0, (viewport.w || baseSize.width) - 32);
6152
+ const avail = Math.max(1, (viewport.w || baseSize.width) - 32);
6080
6153
  if (zoomMode === "page-width" || zoomMode === "auto") return avail / baseSize.width;
6081
6154
  if (zoomMode === "page-fit") {
6082
- const availH = Math.max(0, (viewport.h || baseSize.height) - 32);
6155
+ const availH = Math.max(1, (viewport.h || baseSize.height) - 32);
6083
6156
  return Math.min(avail / baseSize.width, availH / baseSize.height);
6084
6157
  }
6085
6158
  return 1;
6086
6159
  }, [zoomMode, baseSize, viewport]);
6087
- const pageH = baseSize ? baseSize.height * scale + GAP : 0;
6088
- const pageW = baseSize ? baseSize.width * scale : 0;
6089
- const total = numPages * pageH;
6160
+ const { offsets, total } = React36.useMemo(() => {
6161
+ const offs = new Array(sizes.length);
6162
+ let acc = 0;
6163
+ for (let i = 0; i < sizes.length; i++) {
6164
+ offs[i] = acc;
6165
+ acc += sizes[i].height * scale + GAP;
6166
+ }
6167
+ return { offsets: offs, total: acc };
6168
+ }, [sizes, scale]);
6090
6169
  const overscan = 1;
6091
- const startIdx = pageH ? Math.max(0, Math.floor(scrollTop / pageH) - overscan) : 0;
6092
- const endIdx = pageH ? Math.min(numPages, Math.ceil((scrollTop + viewport.h) / pageH) + overscan) : 0;
6170
+ const hasLayout = offsets.length > 0 && total > 0;
6171
+ const startIdx = hasLayout ? Math.max(0, pageIndexAt(offsets, scrollTop) - overscan) : 0;
6172
+ const endIdx = hasLayout ? Math.min(numPages, pageIndexAt(offsets, scrollTop + viewport.h) + 1 + overscan) : 0;
6093
6173
  const visiblePages = Array.from({ length: Math.max(0, endIdx - startIdx) }, (_, i) => startIdx + i + 1);
6094
- React34.useEffect(() => {
6095
- if (!pageH) return;
6096
- const cur = Math.min(numPages, Math.max(1, Math.floor((scrollTop + viewport.h / 2) / pageH) + 1));
6174
+ const scrollToPage = React36.useCallback((p) => {
6175
+ const el = scrollRef.current;
6176
+ if (!el || !offsets.length) return;
6177
+ const clamped = Math.min(offsets.length, Math.max(1, p));
6178
+ el.scrollTo({ top: offsets[clamped - 1] ?? 0, behavior: "smooth" });
6179
+ }, [offsets]);
6180
+ React36.useEffect(() => {
6181
+ if (!hasLayout) return;
6182
+ const cur = pageIndexAt(offsets, scrollTop + viewport.h / 2) + 1;
6097
6183
  if (cur !== page) {
6098
6184
  setPage(cur);
6099
6185
  onPageChange?.(cur);
6100
6186
  }
6101
- }, [scrollTop, pageH, viewport.h, numPages]);
6102
- const scrollToPage = React34.useCallback((p) => {
6103
- const el = scrollRef.current;
6104
- if (!el || !pageH) return;
6105
- el.scrollTo({ top: (p - 1) * pageH, behavior: "smooth" });
6106
- }, [pageH]);
6107
- React34.useEffect(() => {
6187
+ }, [scrollTop, offsets, viewport.h, numPages]);
6188
+ React36.useEffect(() => {
6108
6189
  if (status === "ready" && initialPage > 1) scrollToPage(initialPage);
6109
- }, [status]);
6110
- const runSearch = React34.useCallback(async (q) => {
6111
- setQuery(q);
6112
- if (!doc || !q.trim()) {
6190
+ }, [status, initialPage]);
6191
+ const runSearch = React36.useCallback(async (q) => {
6192
+ const needle = q.trim().toLowerCase();
6193
+ if (!doc || !needle) {
6113
6194
  setMatchPages(null);
6114
6195
  setMatchIdx(0);
6196
+ setSearching(false);
6115
6197
  return;
6116
6198
  }
6117
- const needle = q.toLowerCase();
6199
+ const seq = ++searchSeq.current;
6200
+ setSearching(true);
6118
6201
  const hits = [];
6119
6202
  for (let p = 1; p <= numPages; p++) {
6120
- const pg = await doc.getPage(p);
6121
- const tc = await pg.getTextContent();
6122
- const text = tc.items.map((it) => "str" in it ? it.str : "").join(" ").toLowerCase();
6203
+ let text = pageText.current.get(p);
6204
+ if (text === void 0) {
6205
+ const pg = await doc.getPage(p);
6206
+ const tc = await pg.getTextContent();
6207
+ const built = tc.items.map((it) => "str" in it ? it.str : "").join(" ").toLowerCase();
6208
+ pageText.current.set(p, built);
6209
+ text = built;
6210
+ }
6211
+ if (seq !== searchSeq.current) return;
6123
6212
  if (text.includes(needle)) hits.push(p);
6124
6213
  }
6214
+ if (seq !== searchSeq.current) return;
6125
6215
  setMatchPages(hits);
6126
6216
  setMatchIdx(0);
6217
+ setSearching(false);
6127
6218
  if (hits.length) scrollToPage(hits[0]);
6128
6219
  }, [doc, numPages, scrollToPage]);
6220
+ const onQueryChange = React36.useCallback((v) => {
6221
+ setQuery(v);
6222
+ if (searchTimer.current) clearTimeout(searchTimer.current);
6223
+ if (!v.trim()) {
6224
+ searchSeq.current++;
6225
+ setMatchPages(null);
6226
+ setMatchIdx(0);
6227
+ setSearching(false);
6228
+ return;
6229
+ }
6230
+ searchTimer.current = setTimeout(() => runSearch(v), SEARCH_DEBOUNCE);
6231
+ }, [runSearch]);
6232
+ React36.useEffect(() => () => {
6233
+ if (searchTimer.current) clearTimeout(searchTimer.current);
6234
+ }, []);
6129
6235
  const gotoMatch = (dir) => {
6130
6236
  if (!matchPages?.length) return;
6131
6237
  const next = (matchIdx + dir + matchPages.length) % matchPages.length;
6132
6238
  setMatchIdx(next);
6133
6239
  scrollToPage(matchPages[next]);
6134
6240
  };
6135
- const getBytes = React34.useCallback(async () => {
6241
+ const getBytes = React36.useCallback(async () => {
6136
6242
  if (doc?.getData) return doc.getData();
6137
6243
  if (source instanceof Uint8Array) return source;
6138
6244
  if (source instanceof ArrayBuffer) return new Uint8Array(source);
6139
6245
  if (typeof Blob !== "undefined" && source instanceof Blob) return new Uint8Array(await source.arrayBuffer());
6140
6246
  throw new Error("No bytes available");
6141
6247
  }, [doc, source]);
6142
- const download2 = React34.useCallback(async () => {
6248
+ const download = React36.useCallback(async () => {
6143
6249
  const bytes = await getBytes();
6144
- const blob = new Blob([bytes], { type: "application/pdf" });
6145
- const url = URL.createObjectURL(blob);
6146
- const a = document.createElement("a");
6147
- a.href = url;
6148
- a.download = sourceName(source) || "document.pdf";
6149
- a.click();
6150
- setTimeout(() => URL.revokeObjectURL(url), 1e3);
6250
+ downloadBlob(new Blob([bytes], { type: "application/pdf" }), sourceName(source) || "document.pdf");
6151
6251
  }, [getBytes, source]);
6152
- const print = React34.useCallback(async () => {
6252
+ const print = React36.useCallback(async () => {
6153
6253
  const bytes = await getBytes();
6154
6254
  const blob = new Blob([bytes], { type: "application/pdf" });
6155
6255
  const url = URL.createObjectURL(blob);
@@ -6173,6 +6273,12 @@ function PdfViewer({
6173
6273
  const cur = typeof zoomMode === "number" ? zoomMode : scale;
6174
6274
  setZoomMode(Math.min(5, Math.max(0.25, +(cur * factor).toFixed(2))));
6175
6275
  };
6276
+ const zoomPct = Math.round(scale * 100);
6277
+ const commitPageDraft = () => {
6278
+ pageEditing.current = false;
6279
+ const n = parseInt(pageDraft, 10);
6280
+ if (Number.isFinite(n)) scrollToPage(n);
6281
+ };
6176
6282
  if (status === "error") {
6177
6283
  return /* @__PURE__ */ jsxRuntime.jsxs("div", { className: cx("flex flex-col items-center justify-center gap-3 rounded-lg border border-border bg-surface p-8 text-center", className), style, children: [
6178
6284
  /* @__PURE__ */ jsxRuntime.jsx("p", { className: "text-sm font-medium text-status-error", children: "Couldn\u2019t load the PDF" }),
@@ -6180,89 +6286,137 @@ function PdfViewer({
6180
6286
  /* @__PURE__ */ jsxRuntime.jsx(Button_default, { content: "Retry", size: "sm", variant: "outline", onClick: () => setReloadKey((k) => k + 1) })
6181
6287
  ] });
6182
6288
  }
6183
- return /* @__PURE__ */ jsxRuntime.jsxs("div", { className: cx("flex flex-col overflow-hidden rounded-lg border border-border bg-surface-raised", className), style: { height: 600, ...style }, children: [
6184
- toolbar !== false && /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex flex-shrink-0 flex-wrap items-center gap-2 border-b border-border bg-surface px-2 py-1.5", children: [
6185
- tb.pager && /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex items-center gap-1", children: [
6186
- /* @__PURE__ */ jsxRuntime.jsx(IconButton_default, { type: "ghost", size: "sm", title: "Previous page", onClick: () => scrollToPage(Math.max(1, page - 1)), icon: /* @__PURE__ */ jsxRuntime.jsx(Chevron5, { dir: "up" }), disabled: status !== "ready" }),
6187
- /* @__PURE__ */ jsxRuntime.jsxs("span", { className: "px-1 text-xs tabular-nums text-foreground-secondary select-none", children: [
6188
- status === "ready" ? page : "\u2013",
6189
- " / ",
6190
- numPages || "\u2013"
6289
+ const ready = status === "ready";
6290
+ return /* @__PURE__ */ jsxRuntime.jsxs("div", { className: cx("flex flex-col overflow-hidden rounded-lg border border-border bg-surface-raised", className), style: { height, width, ...style }, children: [
6291
+ toolbar !== false && /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex flex-shrink-0 flex-col border-b border-border bg-surface", children: [
6292
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex items-center gap-1 px-2 py-1.5", children: [
6293
+ tb.pager && /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex items-center gap-1", children: [
6294
+ /* @__PURE__ */ jsxRuntime.jsx(IconButton_default, { type: "ghost", size: "sm", title: "Previous page", onClick: () => scrollToPage(page - 1), icon: /* @__PURE__ */ jsxRuntime.jsx(Chevron5, { dir: "up" }), disabled: !ready || page <= 1 }),
6295
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex items-center gap-1 text-xs text-foreground-secondary select-none", children: [
6296
+ /* @__PURE__ */ jsxRuntime.jsx(
6297
+ "input",
6298
+ {
6299
+ value: pageEditing.current ? pageDraft : ready ? String(page) : "\u2013",
6300
+ onFocus: () => {
6301
+ pageEditing.current = true;
6302
+ setPageDraft(String(page));
6303
+ },
6304
+ onChange: (e) => setPageDraft(e.target.value.replace(/[^\d]/g, "")),
6305
+ onBlur: commitPageDraft,
6306
+ onKeyDown: (e) => {
6307
+ if (e.key === "Enter") e.target.blur();
6308
+ },
6309
+ disabled: !ready,
6310
+ "aria-label": "Page number",
6311
+ className: "h-6 w-9 rounded border border-border bg-surface-raised text-center tabular-nums text-foreground outline-none focus:border-accent disabled:opacity-50"
6312
+ }
6313
+ ),
6314
+ /* @__PURE__ */ jsxRuntime.jsxs("span", { className: "tabular-nums", children: [
6315
+ "/ ",
6316
+ numPages || "\u2013"
6317
+ ] })
6318
+ ] }),
6319
+ /* @__PURE__ */ jsxRuntime.jsx(IconButton_default, { type: "ghost", size: "sm", title: "Next page", onClick: () => scrollToPage(page + 1), icon: /* @__PURE__ */ jsxRuntime.jsx(Chevron5, { dir: "down" }), disabled: !ready || page >= numPages })
6191
6320
  ] }),
6192
- /* @__PURE__ */ jsxRuntime.jsx(IconButton_default, { type: "ghost", size: "sm", title: "Next page", onClick: () => scrollToPage(Math.min(numPages, page + 1)), icon: /* @__PURE__ */ jsxRuntime.jsx(Chevron5, { dir: "down" }), disabled: status !== "ready" })
6193
- ] }),
6194
- tb.zoom && /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "ml-1 flex items-center gap-1", children: [
6195
- /* @__PURE__ */ jsxRuntime.jsx(IconButton_default, { type: "ghost", size: "sm", title: "Zoom out", onClick: () => setZoomNum(1 / 1.2), icon: /* @__PURE__ */ jsxRuntime.jsx("span", { className: "text-base leading-none", children: "\u2212" }), disabled: status !== "ready" }),
6196
- /* @__PURE__ */ jsxRuntime.jsx(IconButton_default, { type: "ghost", size: "sm", title: "Zoom in", onClick: () => setZoomNum(1.2), icon: /* @__PURE__ */ jsxRuntime.jsx("span", { className: "text-base leading-none", children: "+" }), disabled: status !== "ready" }),
6197
- /* @__PURE__ */ jsxRuntime.jsx(IconButton_default, { type: "ghost", size: "sm", title: "Fit width", onClick: () => setZoomMode("page-width"), icon: /* @__PURE__ */ jsxRuntime.jsx(FitWidthIcon, {}), disabled: status !== "ready" }),
6198
- /* @__PURE__ */ jsxRuntime.jsx(IconButton_default, { type: "ghost", size: "sm", title: "Fit page", onClick: () => setZoomMode("page-fit"), icon: /* @__PURE__ */ jsxRuntime.jsx(FitPageIcon, {}), disabled: status !== "ready" })
6199
- ] }),
6200
- /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "ml-auto flex items-center gap-1", children: [
6201
- tb.search && /* @__PURE__ */ jsxRuntime.jsx(IconButton_default, { type: "ghost", size: "sm", title: "Search", onClick: () => setShowSearch((s) => !s), icon: /* @__PURE__ */ jsxRuntime.jsx(SearchIcon2, {}), disabled: status !== "ready" }),
6202
- tb.download && /* @__PURE__ */ jsxRuntime.jsx(IconButton_default, { type: "ghost", size: "sm", title: "Download", onClick: download2, icon: /* @__PURE__ */ jsxRuntime.jsx(DownloadIcon, {}), disabled: status !== "ready" }),
6203
- tb.print && /* @__PURE__ */ jsxRuntime.jsx(IconButton_default, { type: "ghost", size: "sm", title: "Print", onClick: print, icon: /* @__PURE__ */ jsxRuntime.jsx(PrintIcon, {}), disabled: status !== "ready" })
6321
+ tb.pager && tb.zoom && /* @__PURE__ */ jsxRuntime.jsx("span", { className: "mx-1 h-5 w-px bg-border", "aria-hidden": "true" }),
6322
+ tb.zoom && /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex items-center gap-1", children: [
6323
+ /* @__PURE__ */ jsxRuntime.jsx(IconButton_default, { type: "ghost", size: "sm", title: "Zoom out", onClick: () => setZoomNum(1 / 1.2), icon: /* @__PURE__ */ jsxRuntime.jsx(MinusIcon, {}), disabled: !ready }),
6324
+ /* @__PURE__ */ jsxRuntime.jsx("span", { className: "w-10 text-center text-xs tabular-nums text-foreground-secondary select-none", children: ready ? `${zoomPct}%` : "\u2013" }),
6325
+ /* @__PURE__ */ jsxRuntime.jsx(IconButton_default, { type: "ghost", size: "sm", title: "Zoom in", onClick: () => setZoomNum(1.2), icon: /* @__PURE__ */ jsxRuntime.jsx(PlusIcon, {}), disabled: !ready }),
6326
+ /* @__PURE__ */ jsxRuntime.jsx(IconButton_default, { type: "ghost", size: "sm", title: "Fit width", onClick: () => setZoomMode("page-width"), icon: /* @__PURE__ */ jsxRuntime.jsx(FitWidthIcon, {}), disabled: !ready }),
6327
+ /* @__PURE__ */ jsxRuntime.jsx(IconButton_default, { type: "ghost", size: "sm", title: "Fit page", onClick: () => setZoomMode("page-fit"), icon: /* @__PURE__ */ jsxRuntime.jsx(FitPageIcon, {}), disabled: !ready })
6328
+ ] }),
6329
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "ml-auto flex items-center gap-1", children: [
6330
+ tb.search && /* @__PURE__ */ jsxRuntime.jsx(IconButton_default, { type: showSearch ? "bordered" : "ghost", size: "sm", title: "Search", onClick: () => setShowSearch((s) => !s), icon: /* @__PURE__ */ jsxRuntime.jsx(SearchIcon2, {}), disabled: !ready }),
6331
+ tb.search && (tb.download || tb.print) && /* @__PURE__ */ jsxRuntime.jsx("span", { className: "mx-1 h-5 w-px bg-border", "aria-hidden": "true" }),
6332
+ tb.download && /* @__PURE__ */ jsxRuntime.jsx(IconButton_default, { type: "ghost", size: "sm", title: "Download", onClick: download, icon: /* @__PURE__ */ jsxRuntime.jsx(DownloadIcon, {}), disabled: !ready }),
6333
+ tb.print && /* @__PURE__ */ jsxRuntime.jsx(IconButton_default, { type: "ghost", size: "sm", title: "Print", onClick: print, icon: /* @__PURE__ */ jsxRuntime.jsx(PrintIcon, {}), disabled: !ready })
6334
+ ] })
6204
6335
  ] }),
6205
- tb.search && showSearch && /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex w-full items-center gap-2 pt-1", children: [
6336
+ tb.search && showSearch && /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex items-center gap-2 border-t border-border px-2 py-1.5", children: [
6337
+ /* @__PURE__ */ jsxRuntime.jsx(SearchIcon2, {}),
6206
6338
  /* @__PURE__ */ jsxRuntime.jsx(
6207
6339
  "input",
6208
6340
  {
6209
6341
  autoFocus: true,
6210
6342
  value: query,
6211
- onChange: (e) => runSearch(e.target.value),
6343
+ onChange: (e) => onQueryChange(e.target.value),
6344
+ onKeyDown: (e) => {
6345
+ if (e.key === "Enter") gotoMatch(e.shiftKey ? -1 : 1);
6346
+ },
6212
6347
  placeholder: "Find in document\u2026",
6213
- className: "h-7 flex-1 rounded-md border border-border bg-surface px-2 text-sm text-foreground outline-none focus:border-accent"
6348
+ className: "h-7 flex-1 bg-transparent text-sm text-foreground outline-none placeholder:text-foreground-muted"
6214
6349
  }
6215
6350
  ),
6216
- /* @__PURE__ */ jsxRuntime.jsx("span", { className: "text-xs tabular-nums text-foreground-muted", children: matchPages == null ? "" : matchPages.length ? `${matchIdx + 1}/${matchPages.length} pages` : "no matches" }),
6351
+ /* @__PURE__ */ jsxRuntime.jsx("span", { className: "text-xs tabular-nums text-foreground-muted", children: searching ? "Searching\u2026" : matchPages == null ? "" : matchPages.length ? `${matchIdx + 1} of ${matchPages.length}` : "No matches" }),
6217
6352
  /* @__PURE__ */ jsxRuntime.jsx(IconButton_default, { type: "ghost", size: "sm", title: "Previous match", onClick: () => gotoMatch(-1), icon: /* @__PURE__ */ jsxRuntime.jsx(Chevron5, { dir: "up" }), disabled: !matchPages?.length }),
6218
- /* @__PURE__ */ jsxRuntime.jsx(IconButton_default, { type: "ghost", size: "sm", title: "Next match", onClick: () => gotoMatch(1), icon: /* @__PURE__ */ jsxRuntime.jsx(Chevron5, { dir: "down" }), disabled: !matchPages?.length })
6353
+ /* @__PURE__ */ jsxRuntime.jsx(IconButton_default, { type: "ghost", size: "sm", title: "Next match", onClick: () => gotoMatch(1), icon: /* @__PURE__ */ jsxRuntime.jsx(Chevron5, { dir: "down" }), disabled: !matchPages?.length }),
6354
+ /* @__PURE__ */ jsxRuntime.jsx(IconButton_default, { type: "ghost", size: "sm", title: "Close search", onClick: () => {
6355
+ setShowSearch(false);
6356
+ onQueryChange("");
6357
+ }, icon: /* @__PURE__ */ jsxRuntime.jsx(CloseIcon, {}) })
6219
6358
  ] })
6220
6359
  ] }),
6221
6360
  /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex min-h-0 flex-1", children: [
6222
- thumbnails && status === "ready" && doc && baseSize && /* @__PURE__ */ jsxRuntime.jsx("div", { className: "w-32 flex-shrink-0 overflow-y-auto border-r border-border bg-surface p-2", children: Array.from({ length: numPages }, (_, i) => i + 1).map((p) => /* @__PURE__ */ jsxRuntime.jsx(
6223
- "button",
6224
- {
6225
- type: "button",
6226
- onClick: () => scrollToPage(p),
6227
- className: cx(
6228
- "mb-2 block w-full overflow-hidden rounded border bg-surface-raised transition-colors",
6229
- p === page ? "border-accent ring-1 ring-accent" : "border-border hover:border-border-strong"
6230
- ),
6231
- style: { aspectRatio: `${baseSize.width} / ${baseSize.height}` },
6232
- "aria-label": `Page ${p}`,
6233
- children: Math.abs(p - page) <= 8 ? /* @__PURE__ */ jsxRuntime.jsx(PdfPage, { pdfjs, doc, page: p, scale: 112 / baseSize.width, textLayer: false }) : /* @__PURE__ */ jsxRuntime.jsx("span", { className: "block py-4 text-center text-xs text-foreground-muted", children: p })
6234
- },
6235
- p
6236
- )) }),
6361
+ thumbnails && ready && doc && baseSize && /* @__PURE__ */ jsxRuntime.jsx("div", { className: "w-32 flex-shrink-0 overflow-y-auto border-r border-border bg-surface p-2", children: Array.from({ length: numPages }, (_, i) => i + 1).map((p) => {
6362
+ const s = sizes[p - 1] ?? baseSize;
6363
+ return /* @__PURE__ */ jsxRuntime.jsx(
6364
+ "button",
6365
+ {
6366
+ type: "button",
6367
+ onClick: () => scrollToPage(p),
6368
+ className: cx(
6369
+ "mb-2 block w-full overflow-hidden rounded border bg-surface-raised transition-colors",
6370
+ p === page ? "border-accent ring-1 ring-accent" : "border-border hover:border-border-strong"
6371
+ ),
6372
+ style: { aspectRatio: `${s.width} / ${s.height}` },
6373
+ "aria-label": `Page ${p}`,
6374
+ "aria-current": p === page,
6375
+ children: Math.abs(p - page) <= 8 ? /* @__PURE__ */ jsxRuntime.jsx(PdfPage, { pdfjs, doc, page: p, scale: 112 / s.width, textLayer: false }) : /* @__PURE__ */ jsxRuntime.jsx("span", { className: "block py-4 text-center text-xs text-foreground-muted", children: p })
6376
+ },
6377
+ p
6378
+ );
6379
+ }) }),
6237
6380
  /* @__PURE__ */ jsxRuntime.jsx(
6238
6381
  "div",
6239
6382
  {
6240
6383
  ref: scrollRef,
6241
6384
  onScroll: (e) => setScrollTop(e.currentTarget.scrollTop),
6242
6385
  className: "relative flex-1 overflow-auto bg-background",
6243
- children: status === "loading" || !baseSize ? /* @__PURE__ */ jsxRuntime.jsx("div", { className: "flex flex-col items-center gap-3 p-6", children: /* @__PURE__ */ jsxRuntime.jsx(SkeletonBox, { width: Math.min(viewport.w - 48, 560) || 480, height: 680, className: "rounded" }) }) : numPages === 0 ? /* @__PURE__ */ jsxRuntime.jsx("div", { className: "flex h-full items-center justify-center text-sm text-foreground-muted", children: "Empty document" }) : /* @__PURE__ */ jsxRuntime.jsx("div", { style: { height: total, position: "relative" }, children: visiblePages.map((p) => /* @__PURE__ */ jsxRuntime.jsx(
6244
- "div",
6245
- {
6246
- style: { position: "absolute", top: (p - 1) * pageH, left: 0, right: 0, height: pageH, display: "flex", justifyContent: "center", paddingTop: GAP / 2, paddingBottom: GAP / 2 },
6247
- children: /* @__PURE__ */ jsxRuntime.jsx("div", { className: "relative shadow-md", style: { width: pageW, height: baseSize.height * scale }, children: /* @__PURE__ */ jsxRuntime.jsx(PdfPage, { pdfjs, doc, page: p, scale, textLayer }) })
6248
- },
6249
- p
6250
- )) })
6386
+ children: !ready || !baseSize ? /* @__PURE__ */ jsxRuntime.jsx("div", { className: "flex flex-col items-center gap-3 p-6", children: /* @__PURE__ */ jsxRuntime.jsx(SkeletonBox, { width: Math.min((viewport.w || 528) - 48, 560), height: 680, className: "rounded" }) }) : numPages === 0 ? /* @__PURE__ */ jsxRuntime.jsx("div", { className: "flex h-full items-center justify-center text-sm text-foreground-muted", children: "Empty document" }) : /* @__PURE__ */ jsxRuntime.jsx("div", { style: { height: total, position: "relative" }, children: visiblePages.map((p) => {
6387
+ const s = sizes[p - 1] ?? baseSize;
6388
+ return /* @__PURE__ */ jsxRuntime.jsx(
6389
+ "div",
6390
+ {
6391
+ style: { position: "absolute", top: offsets[p - 1], left: 0, right: 0, display: "flex", justifyContent: "center", paddingTop: GAP / 2 },
6392
+ children: /* @__PURE__ */ jsxRuntime.jsx("div", { className: "relative shadow-md", style: { width: s.width * scale, height: s.height * scale }, children: /* @__PURE__ */ jsxRuntime.jsx(PdfPage, { pdfjs, doc, page: p, scale, textLayer, onMeasure: handleMeasure }) })
6393
+ },
6394
+ p
6395
+ );
6396
+ }) })
6251
6397
  }
6252
6398
  )
6253
6399
  ] })
6254
6400
  ] });
6255
6401
  }
6256
- function PdfPage({ pdfjs, doc, page, scale, textLayer }) {
6257
- const canvasRef = React34.useRef(null);
6258
- const textRef = React34.useRef(null);
6259
- React34.useEffect(() => {
6402
+ function PdfPage({
6403
+ pdfjs,
6404
+ doc,
6405
+ page,
6406
+ scale,
6407
+ textLayer,
6408
+ onMeasure
6409
+ }) {
6410
+ const canvasRef = React36.useRef(null);
6411
+ const textRef = React36.useRef(null);
6412
+ React36.useEffect(() => {
6260
6413
  let cancelled = false;
6261
6414
  let renderTask;
6262
6415
  (async () => {
6263
6416
  const pg = await doc.getPage(page);
6264
6417
  if (cancelled) return;
6265
6418
  const viewport = pg.getViewport({ scale });
6419
+ onMeasure?.(page, { width: viewport.width / scale, height: viewport.height / scale });
6266
6420
  const canvas = canvasRef.current;
6267
6421
  if (!canvas) return;
6268
6422
  const ratio = typeof window !== "undefined" ? window.devicePixelRatio || 1 : 1;
@@ -6279,6 +6433,7 @@ function PdfPage({ pdfjs, doc, page, scale, textLayer }) {
6279
6433
  }
6280
6434
  if (cancelled || !textLayer || !textRef.current || !pdfjs?.TextLayer) return;
6281
6435
  try {
6436
+ ensureTextLayerStyles();
6282
6437
  textRef.current.innerHTML = "";
6283
6438
  textRef.current.style.setProperty("--scale-factor", String(scale));
6284
6439
  const tl = new pdfjs.TextLayer({ textContentSource: pg.streamTextContent(), container: textRef.current, viewport });
@@ -6290,17 +6445,20 @@ function PdfPage({ pdfjs, doc, page, scale, textLayer }) {
6290
6445
  cancelled = true;
6291
6446
  renderTask?.cancel?.();
6292
6447
  };
6293
- }, [pdfjs, doc, page, scale, textLayer]);
6448
+ }, [pdfjs, doc, page, scale, textLayer, onMeasure]);
6294
6449
  return /* @__PURE__ */ jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [
6295
6450
  /* @__PURE__ */ jsxRuntime.jsx("canvas", { ref: canvasRef, className: "block bg-white" }),
6296
- textLayer && /* @__PURE__ */ jsxRuntime.jsx("div", { ref: textRef, className: "textLayer pointer-events-auto absolute inset-0 overflow-hidden leading-none", style: { opacity: 0.25 }, "aria-hidden": "true" })
6451
+ textLayer && /* @__PURE__ */ jsxRuntime.jsx("div", { ref: textRef, className: "oxy-textLayer", "aria-hidden": "true" })
6297
6452
  ] });
6298
6453
  }
6299
6454
  var Chevron5 = ({ dir }) => /* @__PURE__ */ jsxRuntime.jsx("svg", { viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: 2, className: "h-4 w-4", "aria-hidden": "true", children: /* @__PURE__ */ jsxRuntime.jsx("path", { strokeLinecap: "round", strokeLinejoin: "round", d: dir === "up" ? "m6 15 6-6 6 6" : "m6 9 6 6 6-6" }) });
6300
- var SearchIcon2 = () => /* @__PURE__ */ jsxRuntime.jsxs("svg", { viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: 2, className: "h-4 w-4", "aria-hidden": "true", children: [
6455
+ var MinusIcon = () => /* @__PURE__ */ jsxRuntime.jsx("svg", { viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: 2, className: "h-4 w-4", "aria-hidden": "true", children: /* @__PURE__ */ jsxRuntime.jsx("path", { strokeLinecap: "round", d: "M5 12h14" }) });
6456
+ var PlusIcon = () => /* @__PURE__ */ jsxRuntime.jsx("svg", { viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: 2, className: "h-4 w-4", "aria-hidden": "true", children: /* @__PURE__ */ jsxRuntime.jsx("path", { strokeLinecap: "round", d: "M12 5v14M5 12h14" }) });
6457
+ var SearchIcon2 = () => /* @__PURE__ */ jsxRuntime.jsxs("svg", { viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: 2, className: "h-4 w-4 text-foreground-muted", "aria-hidden": "true", children: [
6301
6458
  /* @__PURE__ */ jsxRuntime.jsx("circle", { cx: "11", cy: "11", r: "7" }),
6302
6459
  /* @__PURE__ */ jsxRuntime.jsx("path", { strokeLinecap: "round", d: "m21 21-4.3-4.3" })
6303
6460
  ] });
6461
+ var CloseIcon = () => /* @__PURE__ */ jsxRuntime.jsx("svg", { viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: 2, className: "h-4 w-4", "aria-hidden": "true", children: /* @__PURE__ */ jsxRuntime.jsx("path", { strokeLinecap: "round", d: "M6 6l12 12M18 6 6 18" }) });
6304
6462
  var DownloadIcon = () => /* @__PURE__ */ jsxRuntime.jsx("svg", { viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: 2, className: "h-4 w-4", "aria-hidden": "true", children: /* @__PURE__ */ jsxRuntime.jsx("path", { strokeLinecap: "round", strokeLinejoin: "round", d: "M12 3v12m0 0 4-4m-4 4-4-4M4 21h16" }) });
6305
6463
  var PrintIcon = () => /* @__PURE__ */ jsxRuntime.jsx("svg", { viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: 2, className: "h-4 w-4", "aria-hidden": "true", children: /* @__PURE__ */ jsxRuntime.jsx("path", { strokeLinecap: "round", strokeLinejoin: "round", d: "M6 9V3h12v6M6 18H4v-7h16v7h-2M8 14h8v7H8z" }) });
6306
6464
  var FitWidthIcon = () => /* @__PURE__ */ jsxRuntime.jsx("svg", { viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: 2, className: "h-4 w-4", "aria-hidden": "true", children: /* @__PURE__ */ jsxRuntime.jsx("path", { strokeLinecap: "round", strokeLinejoin: "round", d: "M3 12h18m0 0-4-4m4 4-4 4M3 12l4-4m-4 4 4 4" }) });
@@ -6310,11 +6468,20 @@ var FitPageIcon = () => /* @__PURE__ */ jsxRuntime.jsxs("svg", { viewBox: "0 0 2
6310
6468
  ] });
6311
6469
  var DEFAULT_COL_WIDTH = 140;
6312
6470
  var GUTTER = 52;
6471
+ var END_PAD = 12;
6472
+ function compareValues2(a, b) {
6473
+ if (a == null && b == null) return 0;
6474
+ if (a == null) return 1;
6475
+ if (b == null) return -1;
6476
+ if (typeof a === "number" && typeof b === "number") return a - b;
6477
+ if (typeof a === "boolean" && typeof b === "boolean") return a === b ? 0 : a ? 1 : -1;
6478
+ return String(a).localeCompare(String(b), void 0, { numeric: true, sensitivity: "base" });
6479
+ }
6313
6480
  function resolveWidth(w) {
6314
- if (typeof w === "number") return w;
6481
+ if (typeof w === "number" && Number.isFinite(w)) return w;
6315
6482
  if (typeof w === "string") {
6316
- const n = parseFloat(w);
6317
- if (!Number.isNaN(n) && /^\d/.test(w.trim())) return n;
6483
+ const m = /^\s*(\d+(?:\.\d+)?)(px)?\s*$/.exec(w);
6484
+ if (m) return parseFloat(m[1]);
6318
6485
  }
6319
6486
  return DEFAULT_COL_WIDTH;
6320
6487
  }
@@ -6328,7 +6495,11 @@ function DataGrid({
6328
6495
  rowHeight = 34,
6329
6496
  headerHeight = 38,
6330
6497
  height = 480,
6498
+ width,
6331
6499
  editable = false,
6500
+ sortable = false,
6501
+ sort: sortProp,
6502
+ onSortChange,
6332
6503
  virtualize = true,
6333
6504
  overscan = 4,
6334
6505
  rowNumbers = true,
@@ -6337,13 +6508,16 @@ function DataGrid({
6337
6508
  style,
6338
6509
  emptyState = "No data"
6339
6510
  }) {
6340
- const scrollRef = React34.useRef(null);
6341
- const [scroll, setScroll] = React34.useState({ top: 0, left: 0 });
6342
- const [viewport, setViewport] = React34.useState({ w: 0, h: 0 });
6343
- const [editing, setEditing] = React34.useState(null);
6344
- const [draft, setDraft] = React34.useState("");
6511
+ const scrollRef = React36.useRef(null);
6512
+ const [scroll, setScroll] = React36.useState({ top: 0, left: 0 });
6513
+ const [viewport, setViewport] = React36.useState({ w: 0, h: 0 });
6514
+ const [editing, setEditing] = React36.useState(null);
6515
+ const [draft, setDraft] = React36.useState("");
6516
+ const [internalSort, setInternalSort] = React36.useState(null);
6517
+ const sort = sortProp !== void 0 ? sortProp : internalSort;
6345
6518
  const gutter = rowNumbers ? GUTTER : 0;
6346
- const { widths, offsets, totalWidth } = React34.useMemo(() => {
6519
+ const colSortable = (c) => c.sortable ?? sortable;
6520
+ const { widths, offsets, totalWidth } = React36.useMemo(() => {
6347
6521
  const widths2 = columns.map((c) => resolveWidth(c.width));
6348
6522
  const offsets2 = [];
6349
6523
  let acc = 0;
@@ -6353,8 +6527,20 @@ function DataGrid({
6353
6527
  }
6354
6528
  return { widths: widths2, offsets: offsets2, totalWidth: acc };
6355
6529
  }, [columns]);
6530
+ const order = React36.useMemo(() => {
6531
+ const idx = rows.map((_, i) => i);
6532
+ if (!sort) return idx;
6533
+ const dir = sort.dir === "asc" ? 1 : -1;
6534
+ return idx.sort((ia, ib) => dir * compareValues2(rows[ia]?.[sort.key] ?? null, rows[ib]?.[sort.key] ?? null));
6535
+ }, [rows, sort]);
6536
+ const toggleSort = (key) => {
6537
+ const nextDir = sort?.key !== key ? "asc" : sort.dir === "asc" ? "desc" : null;
6538
+ const next = nextDir ? { key, dir: nextDir } : null;
6539
+ if (sortProp === void 0) setInternalSort(next);
6540
+ onSortChange?.(next);
6541
+ };
6356
6542
  const totalHeight = rows.length * rowHeight;
6357
- React34.useEffect(() => {
6543
+ React36.useEffect(() => {
6358
6544
  const el = scrollRef.current;
6359
6545
  if (!el || typeof ResizeObserver === "undefined") return;
6360
6546
  const measure = () => setViewport({ w: el.clientWidth, h: el.clientHeight });
@@ -6380,17 +6566,17 @@ function DataGrid({
6380
6566
  }
6381
6567
  const visibleRows = Array.from({ length: Math.max(0, rowEnd - rowStart) }, (_, i) => rowStart + i);
6382
6568
  const visibleCols = Array.from({ length: Math.max(0, colEnd - colStart) }, (_, i) => colStart + i);
6383
- const commit = React34.useCallback(() => {
6569
+ const commit = React36.useCallback(() => {
6384
6570
  if (!editing) return;
6385
6571
  const col = columns[editing.col];
6386
- onCellEdit?.({ row: editing.row, column: col.key, value: draft });
6572
+ onCellEdit?.({ row: order[editing.disp], column: col.key, value: draft });
6387
6573
  setEditing(null);
6388
- }, [editing, columns, draft, onCellEdit]);
6389
- const startEdit = (row, col) => {
6574
+ }, [editing, columns, draft, onCellEdit, order]);
6575
+ const startEdit = (disp, col) => {
6390
6576
  const c = columns[col];
6391
6577
  if (!(c.editable ?? editable)) return;
6392
- setDraft(displayValue(rows[row]?.[c.key] ?? ""));
6393
- setEditing({ row, col });
6578
+ setDraft(displayValue(rows[order[disp]]?.[c.key] ?? ""));
6579
+ setEditing({ disp, col });
6394
6580
  };
6395
6581
  return /* @__PURE__ */ jsxRuntime.jsxs(
6396
6582
  "div",
@@ -6398,12 +6584,12 @@ function DataGrid({
6398
6584
  ref: scrollRef,
6399
6585
  onScroll: (e) => setScroll({ top: e.currentTarget.scrollTop, left: e.currentTarget.scrollLeft }),
6400
6586
  className: cx("relative overflow-auto rounded-lg border border-border bg-surface-raised text-sm", className),
6401
- style: { height, ...style },
6587
+ style: { height, width, ...style },
6402
6588
  role: "grid",
6403
6589
  "aria-rowcount": rows.length,
6404
6590
  "aria-colcount": columns.length,
6405
6591
  children: [
6406
- /* @__PURE__ */ jsxRuntime.jsxs("div", { style: { position: "relative", width: gutter + totalWidth, height: headerHeight + totalHeight }, children: [
6592
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { style: { position: "relative", width: gutter + totalWidth + END_PAD, height: headerHeight + totalHeight + END_PAD }, children: [
6407
6593
  rowNumbers && /* @__PURE__ */ jsxRuntime.jsx(
6408
6594
  "div",
6409
6595
  {
@@ -6413,11 +6599,18 @@ function DataGrid({
6413
6599
  ),
6414
6600
  visibleCols.map((ci) => {
6415
6601
  const c = columns[ci];
6416
- return /* @__PURE__ */ jsxRuntime.jsx(
6602
+ const sortDir = sort?.key === c.key ? sort.dir : null;
6603
+ const canSort = colSortable(c);
6604
+ return /* @__PURE__ */ jsxRuntime.jsxs(
6417
6605
  "div",
6418
6606
  {
6419
6607
  role: "columnheader",
6420
- className: "flex items-center border-b border-r border-border bg-surface px-3 font-medium text-foreground-secondary",
6608
+ "aria-sort": sortDir ? sortDir === "asc" ? "ascending" : "descending" : void 0,
6609
+ onClick: canSort ? () => toggleSort(c.key) : void 0,
6610
+ className: cx(
6611
+ "flex items-center gap-1 border-b border-r border-border bg-surface px-3 font-medium text-foreground-secondary",
6612
+ canSort && "cursor-pointer select-none hover:text-foreground"
6613
+ ),
6421
6614
  style: {
6422
6615
  position: "absolute",
6423
6616
  top: scroll.top,
@@ -6427,38 +6620,42 @@ function DataGrid({
6427
6620
  zIndex: 2,
6428
6621
  justifyContent: c.align === "right" ? "flex-end" : c.align === "center" ? "center" : "flex-start"
6429
6622
  },
6430
- children: /* @__PURE__ */ jsxRuntime.jsx("span", { className: "truncate", children: c.label ?? c.key })
6623
+ children: [
6624
+ /* @__PURE__ */ jsxRuntime.jsx("span", { className: "truncate", children: c.label ?? c.key }),
6625
+ canSort && /* @__PURE__ */ jsxRuntime.jsx(SortCaret, { dir: sortDir })
6626
+ ]
6431
6627
  },
6432
6628
  `h-${c.key}`
6433
6629
  );
6434
6630
  }),
6435
- rowNumbers && visibleRows.map((ri) => /* @__PURE__ */ jsxRuntime.jsx(
6631
+ rowNumbers && visibleRows.map((disp) => /* @__PURE__ */ jsxRuntime.jsx(
6436
6632
  "div",
6437
6633
  {
6438
6634
  className: "flex items-center justify-center border-b border-r border-border bg-surface text-xs tabular-nums text-foreground-muted",
6439
- style: { position: "absolute", left: scroll.left, top: headerHeight + ri * rowHeight, width: gutter, height: rowHeight, zIndex: 1 },
6440
- children: ri + 1
6635
+ style: { position: "absolute", left: scroll.left, top: headerHeight + disp * rowHeight, width: gutter, height: rowHeight, zIndex: 1 },
6636
+ children: disp + 1
6441
6637
  },
6442
- `g-${ri}`
6638
+ `g-${disp}`
6443
6639
  )),
6444
- visibleRows.map(
6445
- (ri) => visibleCols.map((ci) => {
6640
+ visibleRows.map((disp) => {
6641
+ const ri = order[disp];
6642
+ return visibleCols.map((ci) => {
6446
6643
  const c = columns[ci];
6447
- const isEditing = editing?.row === ri && editing?.col === ci;
6644
+ const isEditing = editing?.disp === disp && editing?.col === ci;
6448
6645
  const canEdit = c.editable ?? editable;
6449
6646
  return /* @__PURE__ */ jsxRuntime.jsx(
6450
6647
  "div",
6451
6648
  {
6452
6649
  role: "gridcell",
6453
- onDoubleClick: () => startEdit(ri, ci),
6650
+ onDoubleClick: () => startEdit(disp, ci),
6454
6651
  className: cx(
6455
6652
  "flex items-center border-b border-r border-border px-3",
6456
- ri % 2 ? "bg-surface-raised" : "bg-surface",
6653
+ disp % 2 ? "bg-surface-raised" : "bg-surface",
6457
6654
  canEdit && "cursor-text"
6458
6655
  ),
6459
6656
  style: {
6460
6657
  position: "absolute",
6461
- top: headerHeight + ri * rowHeight,
6658
+ top: headerHeight + disp * rowHeight,
6462
6659
  left: gutter + offsets[ci],
6463
6660
  width: widths[ci],
6464
6661
  height: rowHeight,
@@ -6479,16 +6676,22 @@ function DataGrid({
6479
6676
  }
6480
6677
  ) : /* @__PURE__ */ jsxRuntime.jsx("span", { className: "truncate text-foreground", children: displayValue(rows[ri]?.[c.key] ?? "") })
6481
6678
  },
6482
- `${ri}-${c.key}`
6679
+ `${disp}-${c.key}`
6483
6680
  );
6484
- })
6485
- )
6681
+ });
6682
+ })
6486
6683
  ] }),
6487
6684
  rows.length === 0 && /* @__PURE__ */ jsxRuntime.jsx("div", { className: "absolute inset-0 flex items-center justify-center text-foreground-muted", style: { top: headerHeight }, children: emptyState })
6488
6685
  ]
6489
6686
  }
6490
6687
  );
6491
6688
  }
6689
+ function SortCaret({ dir }) {
6690
+ return /* @__PURE__ */ jsxRuntime.jsxs("svg", { viewBox: "0 0 16 16", className: "h-3 w-3 flex-shrink-0", fill: "none", stroke: "currentColor", strokeWidth: 1.75, "aria-hidden": "true", children: [
6691
+ /* @__PURE__ */ jsxRuntime.jsx("path", { strokeLinecap: "round", strokeLinejoin: "round", d: "M5 6.5 8 3.5l3 3", className: dir === "asc" ? "text-accent" : "text-foreground-muted opacity-50" }),
6692
+ /* @__PURE__ */ jsxRuntime.jsx("path", { strokeLinecap: "round", strokeLinejoin: "round", d: "M5 9.5 8 12.5l3-3", className: dir === "desc" ? "text-accent" : "text-foreground-muted opacity-50" })
6693
+ ] });
6694
+ }
6492
6695
  function toColumns(cols) {
6493
6696
  return cols.map((c) => typeof c === "string" ? { key: c, label: c } : { ...c, label: c.label ?? c.key });
6494
6697
  }
@@ -6507,13 +6710,16 @@ var xlsxPromise = null;
6507
6710
  var loadXlsx = () => xlsxPromise ??= import('xlsx');
6508
6711
  var jspdfPromise = null;
6509
6712
  var loadJspdf = () => jspdfPromise ??= import('jspdf');
6510
- function download(blob, name) {
6511
- const url = URL.createObjectURL(blob);
6512
- const a = document.createElement("a");
6513
- a.href = url;
6514
- a.download = name;
6515
- a.click();
6516
- setTimeout(() => URL.revokeObjectURL(url), 1e3);
6713
+ function coerceToCellType(prev, next) {
6714
+ if (typeof prev === "number") {
6715
+ const n = Number(next);
6716
+ return next.trim() !== "" && Number.isFinite(n) ? n : next;
6717
+ }
6718
+ if (typeof prev === "boolean") {
6719
+ if (/^(true|false)$/i.test(next.trim())) return next.trim().toLowerCase() === "true";
6720
+ return next;
6721
+ }
6722
+ return next;
6517
6723
  }
6518
6724
  function Spreadsheet({
6519
6725
  source,
@@ -6524,15 +6730,18 @@ function Spreadsheet({
6524
6730
  export: exportFormats = ["xlsx", "csv", "pdf"],
6525
6731
  fileName,
6526
6732
  virtualize = true,
6733
+ sortable = true,
6734
+ height = 480,
6735
+ width,
6527
6736
  className = "",
6528
6737
  style
6529
6738
  }) {
6530
- const [sheets, setSheets] = React34.useState(Array.isArray(source) ? source : null);
6531
- const [active, setActive] = React34.useState(0);
6532
- const [status, setStatus] = React34.useState(Array.isArray(source) ? "ready" : "loading");
6533
- const [error, setError] = React34.useState(null);
6534
- const [reloadKey, setReloadKey] = React34.useState(0);
6535
- React34.useEffect(() => {
6739
+ const [sheets, setSheets] = React36.useState(Array.isArray(source) ? source : null);
6740
+ const [active, setActive] = React36.useState(0);
6741
+ const [status, setStatus] = React36.useState(Array.isArray(source) ? "ready" : "loading");
6742
+ const [error, setError] = React36.useState(null);
6743
+ const [reloadKey, setReloadKey] = React36.useState(0);
6744
+ React36.useEffect(() => {
6536
6745
  if (Array.isArray(source)) {
6537
6746
  setSheets(source);
6538
6747
  setStatus("ready");
@@ -6578,35 +6787,38 @@ function Spreadsheet({
6578
6787
  };
6579
6788
  }, [source, remote, reloadKey]);
6580
6789
  const sheet = sheets?.[active];
6581
- const columns = React34.useMemo(() => sheet ? toColumns(sheet.columns) : [], [sheet]);
6582
- const plainRows = React34.useMemo(() => sheet ? toPlainRows(sheet, columns) : [], [sheet, columns]);
6583
- const handleCellEdit = React34.useCallback(({ row, column, value }) => {
6790
+ const columns = React36.useMemo(() => sheet ? toColumns(sheet.columns) : [], [sheet]);
6791
+ const plainRows = React36.useMemo(() => sheet ? toPlainRows(sheet, columns) : [], [sheet, columns]);
6792
+ const handleCellEdit = React36.useCallback(({ row, column, value }) => {
6793
+ let coerced = value;
6584
6794
  setSheets((prev) => {
6585
6795
  if (!prev) return prev;
6586
6796
  const next = prev.map((s, i) => i === active ? { ...s, rows: s.rows.map((r) => ({ ...r })) } : s);
6587
6797
  const target = next[active];
6588
6798
  const existing = target.rows[row]?.[column];
6799
+ const prevValue = cellValue(existing);
6800
+ coerced = coerceToCellType(prevValue, value);
6589
6801
  if (existing != null && typeof existing === "object" && "value" in existing) {
6590
- target.rows[row][column] = { ...existing, value };
6802
+ target.rows[row][column] = { ...existing, value: coerced };
6591
6803
  } else {
6592
- target.rows[row][column] = value;
6804
+ target.rows[row][column] = coerced;
6593
6805
  }
6594
6806
  onChange?.(next);
6595
6807
  return next;
6596
6808
  });
6597
- onCellEdit?.({ sheet: sheets?.[active]?.name ?? "", row, column, value });
6809
+ onCellEdit?.({ sheet: sheets?.[active]?.name ?? "", row, column, value: coerced });
6598
6810
  }, [active, onCellEdit, onChange, sheets]);
6599
- const baseName = React34.useMemo(
6811
+ const baseName = React36.useMemo(
6600
6812
  () => (fileName || (typeof source === "object" && "name" in source ? sourceName(source) : null) || "spreadsheet").replace(/\.[^.]+$/, ""),
6601
6813
  [fileName, source]
6602
6814
  );
6603
- const sheetAoa = React34.useCallback((s) => {
6815
+ const sheetAoa = React36.useCallback((s) => {
6604
6816
  const cols = toColumns(s.columns);
6605
6817
  const header = cols.map((c) => typeof c.label === "string" ? c.label : c.key);
6606
6818
  const body = s.rows.map((r) => cols.map((c) => cellValue(r[c.key])));
6607
6819
  return [header, ...body];
6608
6820
  }, []);
6609
- const exportXlsx = React34.useCallback(async () => {
6821
+ const exportXlsx = React36.useCallback(async () => {
6610
6822
  if (!sheets) return;
6611
6823
  const XLSX = await loadXlsx();
6612
6824
  const wb = XLSX.utils.book_new();
@@ -6615,9 +6827,9 @@ function Spreadsheet({
6615
6827
  XLSX.utils.book_append_sheet(wb, ws, (s.name || "Sheet").slice(0, 31));
6616
6828
  });
6617
6829
  const out = XLSX.write(wb, { bookType: "xlsx", type: "array" });
6618
- download(new Blob([out], { type: "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet" }), `${baseName}.xlsx`);
6830
+ downloadBlob(new Blob([out], { type: "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet" }), `${baseName}.xlsx`);
6619
6831
  }, [sheets, sheetAoa, baseName]);
6620
- const exportCsv = React34.useCallback(() => {
6832
+ const exportCsv = React36.useCallback(() => {
6621
6833
  if (!sheet) return;
6622
6834
  const aoa = sheetAoa(sheet);
6623
6835
  const esc = (v) => {
@@ -6625,9 +6837,9 @@ function Spreadsheet({
6625
6837
  return /[",\n]/.test(s) ? `"${s.replace(/"/g, '""')}"` : s;
6626
6838
  };
6627
6839
  const csv = aoa.map((row) => row.map(esc).join(",")).join("\r\n");
6628
- download(new Blob([`\uFEFF${csv}`], { type: "text/csv;charset=utf-8" }), `${baseName}.csv`);
6840
+ downloadBlob(new Blob([`\uFEFF${csv}`], { type: "text/csv;charset=utf-8" }), `${baseName}.csv`);
6629
6841
  }, [sheet, sheetAoa, baseName]);
6630
- const exportPdf = React34.useCallback(async () => {
6842
+ const exportPdf = React36.useCallback(async () => {
6631
6843
  if (!sheet) return;
6632
6844
  const { jsPDF } = await loadJspdf();
6633
6845
  const doc = new jsPDF({ orientation: "landscape", unit: "pt", format: "a4" });
@@ -6668,52 +6880,89 @@ function Spreadsheet({
6668
6880
  else void exportPdf();
6669
6881
  };
6670
6882
  if (status === "error") {
6671
- return /* @__PURE__ */ jsxRuntime.jsxs("div", { className: cx("flex flex-col items-center justify-center gap-3 rounded-lg border border-border bg-surface p-8 text-center", className), style, children: [
6883
+ return /* @__PURE__ */ jsxRuntime.jsxs("div", { className: cx("flex flex-col items-center justify-center gap-3 rounded-lg border border-border bg-surface p-8 text-center", className), style: { height, width, ...style }, children: [
6672
6884
  /* @__PURE__ */ jsxRuntime.jsx("p", { className: "text-sm font-medium text-status-error", children: "Couldn\u2019t load the spreadsheet" }),
6673
6885
  error?.message && /* @__PURE__ */ jsxRuntime.jsx("p", { className: "max-w-md text-xs text-foreground-muted", children: error.message }),
6674
6886
  /* @__PURE__ */ jsxRuntime.jsx(Button_default, { content: "Retry", size: "sm", variant: "outline", onClick: () => setReloadKey((k) => k + 1) })
6675
6887
  ] });
6676
6888
  }
6677
6889
  if (status === "loading" || !sheets) {
6678
- return /* @__PURE__ */ jsxRuntime.jsxs("div", { className: cx("rounded-lg border border-border bg-surface-raised p-4", className), style, children: [
6890
+ return /* @__PURE__ */ jsxRuntime.jsxs("div", { className: cx("overflow-hidden rounded-lg border border-border bg-surface-raised p-4", className), style: { height, width, ...style }, children: [
6679
6891
  /* @__PURE__ */ jsxRuntime.jsx(SkeletonBox, { height: 32, className: "mb-3 rounded" }),
6680
- /* @__PURE__ */ jsxRuntime.jsx(SkeletonBox, { height: 360, className: "rounded" })
6892
+ /* @__PURE__ */ jsxRuntime.jsx(SkeletonBox, { height: "calc(100% - 44px)", className: "rounded" })
6681
6893
  ] });
6682
6894
  }
6683
6895
  const formats = exportFormats || [];
6684
- return /* @__PURE__ */ jsxRuntime.jsxs("div", { className: cx("flex flex-col gap-2", className), style, children: [
6685
- (sheets.length > 1 || formats.length > 0) && /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex flex-wrap items-center gap-2", children: [
6686
- sheets.length > 1 && /* @__PURE__ */ jsxRuntime.jsx("div", { role: "tablist", className: "flex flex-wrap items-center gap-1 rounded-lg border border-border bg-surface p-1", children: sheets.map((s, i) => /* @__PURE__ */ jsxRuntime.jsx(
6687
- "button",
6688
- {
6689
- role: "tab",
6690
- type: "button",
6691
- "aria-selected": i === active,
6692
- onClick: () => setActive(i),
6693
- className: cx(
6694
- "rounded-md px-3 py-1 text-sm transition-colors",
6695
- i === active ? "bg-accent text-accent-fg" : "text-foreground-secondary hover:bg-surface-raised hover:text-foreground"
6696
- ),
6697
- children: s.name || `Sheet ${i + 1}`
6698
- },
6699
- `${s.name}-${i}`
6700
- )) }),
6701
- formats.length > 0 && /* @__PURE__ */ jsxRuntime.jsx("div", { className: "ml-auto flex items-center gap-1.5", children: formats.map((fmt) => /* @__PURE__ */ jsxRuntime.jsx(Button_default, { content: fmt.toUpperCase(), size: "sm", variant: "outline", onClick: () => runExport(fmt) }, fmt)) })
6896
+ const exportLabels = {
6897
+ xlsx: "Excel workbook (.xlsx)",
6898
+ csv: "CSV \u2014 this sheet (.csv)",
6899
+ pdf: "PDF table (.pdf)"
6900
+ };
6901
+ return /* @__PURE__ */ jsxRuntime.jsxs("div", { className: cx("flex flex-col overflow-hidden rounded-lg border border-border bg-surface-raised", className), style: { height, width, ...style }, children: [
6902
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex flex-shrink-0 items-center gap-2 border-b border-border bg-surface px-3 py-1.5", children: [
6903
+ /* @__PURE__ */ jsxRuntime.jsx("span", { className: "min-w-0 flex-1 truncate text-sm font-semibold text-foreground", children: sheet?.name || "Sheet 1" }),
6904
+ /* @__PURE__ */ jsxRuntime.jsxs("span", { className: "hidden flex-shrink-0 text-xs tabular-nums text-foreground-muted sm:inline", children: [
6905
+ plainRows.length.toLocaleString(),
6906
+ " ",
6907
+ plainRows.length === 1 ? "row" : "rows",
6908
+ " \xB7 ",
6909
+ columns.length,
6910
+ " cols"
6911
+ ] }),
6912
+ formats.length > 0 && /* @__PURE__ */ jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [
6913
+ /* @__PURE__ */ jsxRuntime.jsx("span", { className: "h-5 w-px flex-shrink-0 bg-border", "aria-hidden": "true" }),
6914
+ /* @__PURE__ */ jsxRuntime.jsx(
6915
+ MenuButton,
6916
+ {
6917
+ label: "Export",
6918
+ size: "sm",
6919
+ variant: "outline",
6920
+ align: "end",
6921
+ icon: /* @__PURE__ */ jsxRuntime.jsx(DownloadIcon2, {}),
6922
+ items: formats.map((fmt) => ({
6923
+ key: fmt,
6924
+ label: exportLabels[fmt],
6925
+ onSelect: () => runExport(fmt)
6926
+ }))
6927
+ }
6928
+ )
6929
+ ] })
6702
6930
  ] }),
6703
- /* @__PURE__ */ jsxRuntime.jsx(
6931
+ /* @__PURE__ */ jsxRuntime.jsx("div", { className: "min-h-0 flex-1", children: /* @__PURE__ */ jsxRuntime.jsx(
6704
6932
  DataGrid,
6705
6933
  {
6706
6934
  columns,
6707
6935
  rows: plainRows,
6708
6936
  editable,
6937
+ sortable,
6709
6938
  virtualize,
6710
- onCellEdit: handleCellEdit
6711
- }
6712
- )
6939
+ onCellEdit: handleCellEdit,
6940
+ height: "100%",
6941
+ className: "!rounded-none !border-0"
6942
+ },
6943
+ active
6944
+ ) }),
6945
+ sheets.length > 1 && /* @__PURE__ */ jsxRuntime.jsx("div", { role: "tablist", "aria-label": "Sheets", className: "flex flex-shrink-0 items-center gap-1 overflow-x-auto border-t border-border bg-surface px-2 py-1", children: sheets.map((s, i) => /* @__PURE__ */ jsxRuntime.jsx(
6946
+ "button",
6947
+ {
6948
+ role: "tab",
6949
+ type: "button",
6950
+ "aria-selected": i === active,
6951
+ onClick: () => setActive(i),
6952
+ className: cx(
6953
+ "flex-shrink-0 rounded-md px-3 py-1 text-xs font-medium transition-colors",
6954
+ "focus:outline-none focus-visible:ring-2 focus-visible:ring-accent",
6955
+ i === active ? "bg-surface-raised text-foreground shadow-sm" : "text-foreground-secondary hover:bg-surface-raised hover:text-foreground"
6956
+ ),
6957
+ children: s.name || `Sheet ${i + 1}`
6958
+ },
6959
+ `${s.name}-${i}`
6960
+ )) })
6713
6961
  ] });
6714
6962
  }
6963
+ var DownloadIcon2 = () => /* @__PURE__ */ jsxRuntime.jsx("svg", { viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: 2, className: "h-4 w-4", "aria-hidden": "true", children: /* @__PURE__ */ jsxRuntime.jsx("path", { strokeLinecap: "round", strokeLinejoin: "round", d: "M12 3v12m0 0 4-4m-4 4-4-4M4 21h16" }) });
6715
6964
  function ThemeSwitch({ checked, onChange, label = "Toggle dark mode", className = "" }) {
6716
- const id = React34.useId();
6965
+ const id = React36.useId();
6717
6966
  return /* @__PURE__ */ jsxRuntime.jsx("label", { htmlFor: id, className: `flex items-center gap-2 cursor-pointer select-none ${className}`.trim(), children: /* @__PURE__ */ jsxRuntime.jsx(
6718
6967
  SwitchPrimitive__namespace.Root,
6719
6968
  {
@@ -6811,8 +7060,8 @@ function FlyoutItems({ items }) {
6811
7060
  }) });
6812
7061
  }
6813
7062
  function CollapsedFlyout({ item, trigger }) {
6814
- const [open, setOpen] = React34.useState(false);
6815
- const closeTimer = React34__default.default.useRef(void 0);
7063
+ const [open, setOpen] = React36.useState(false);
7064
+ const closeTimer = React36__default.default.useRef(void 0);
6816
7065
  const openNow = () => {
6817
7066
  window.clearTimeout(closeTimer.current);
6818
7067
  setOpen(true);
@@ -6821,7 +7070,7 @@ function CollapsedFlyout({ item, trigger }) {
6821
7070
  window.clearTimeout(closeTimer.current);
6822
7071
  closeTimer.current = window.setTimeout(() => setOpen(false), 150);
6823
7072
  };
6824
- React34__default.default.useEffect(() => () => window.clearTimeout(closeTimer.current), []);
7073
+ React36__default.default.useEffect(() => () => window.clearTimeout(closeTimer.current), []);
6825
7074
  return /* @__PURE__ */ jsxRuntime.jsxs(DropdownMenu2__namespace.Root, { open, onOpenChange: setOpen, modal: false, children: [
6826
7075
  /* @__PURE__ */ jsxRuntime.jsx(
6827
7076
  DropdownMenu2__namespace.Trigger,
@@ -6859,7 +7108,7 @@ function NavItem({
6859
7108
  depth = 0
6860
7109
  }) {
6861
7110
  const hasChildren = !!(item.items && item.items.length);
6862
- const [open, setOpen] = React34.useState(item.defaultOpen ?? (hasChildren && hasActiveDescendant(item)));
7111
+ const [open, setOpen] = React36.useState(item.defaultOpen ?? (hasChildren && hasActiveDescendant(item)));
6863
7112
  const handleClick = () => {
6864
7113
  if (hasChildren && isExpanded) setOpen((o) => !o);
6865
7114
  item.onClick?.();
@@ -6997,7 +7246,7 @@ function Sidebar({
6997
7246
  }
6998
7247
  ) });
6999
7248
  }
7000
- var MegaMenuContext = React34.createContext({ align: "start" });
7249
+ var MegaMenuContext = React36.createContext({ align: "start" });
7001
7250
  function MegaMenu({
7002
7251
  children,
7003
7252
  align = "start",
@@ -7028,7 +7277,7 @@ function MegaMenu({
7028
7277
  }
7029
7278
  var TOP_ITEM = "group/top inline-flex items-center gap-1.5 h-10 px-3 rounded-md text-sm font-medium select-none text-foreground-secondary hover:text-foreground hover:bg-surface-raised data-[state=open]:text-accent data-[active]:text-accent transition-colors focus:outline-none focus-visible:ring-2 focus-visible:ring-accent";
7030
7279
  function MegaMenuItem({ label, icon, href, children, className = "" }) {
7031
- const { align } = React34.useContext(MegaMenuContext);
7280
+ const { align } = React36.useContext(MegaMenuContext);
7032
7281
  const pos = align === "center" ? "left-1/2 -translate-x-1/2" : align === "end" ? "right-0" : "left-0";
7033
7282
  if (!children) {
7034
7283
  return /* @__PURE__ */ jsxRuntime.jsx(NavigationMenu__namespace.Item, { children: /* @__PURE__ */ jsxRuntime.jsxs(NavigationMenu__namespace.Link, { href, className: cx(TOP_ITEM, className), children: [
@@ -7113,8 +7362,8 @@ function MegaMenuLink({ href, icon, description, active, onClick, children, clas
7113
7362
  function MegaMenuFeatured({ children, className = "" }) {
7114
7363
  return /* @__PURE__ */ jsxRuntime.jsx("div", { className: cx("min-w-0 rounded-lg bg-surface-raised border border-border p-4 flex flex-col", className), children });
7115
7364
  }
7116
- var elementsOfType = (children, type) => React34__default.default.Children.toArray(children).filter(
7117
- (c) => React34__default.default.isValidElement(c) && c.type === type
7365
+ var elementsOfType = (children, type) => React36__default.default.Children.toArray(children).filter(
7366
+ (c) => React36__default.default.isValidElement(c) && c.type === type
7118
7367
  );
7119
7368
  var MOBILE_CHEVRON = /* @__PURE__ */ jsxRuntime.jsx(
7120
7369
  "svg",
@@ -7151,9 +7400,9 @@ function MobileLinkRow({ link, onNavigate }) {
7151
7400
  );
7152
7401
  }
7153
7402
  function MobilePanel({ panel, onNavigate }) {
7154
- const nodes = React34__default.default.Children.toArray(panel.props.children);
7403
+ const nodes = React36__default.default.Children.toArray(panel.props.children);
7155
7404
  return /* @__PURE__ */ jsxRuntime.jsx("div", { className: "flex flex-col gap-4 px-2 pb-3 pt-1", children: nodes.map((node, i) => {
7156
- if (!React34__default.default.isValidElement(node)) return null;
7405
+ if (!React36__default.default.isValidElement(node)) return null;
7157
7406
  const el = node;
7158
7407
  if (el.type === MegaMenuSection) {
7159
7408
  const { title, children } = el.props;
@@ -7172,8 +7421,8 @@ function MegaMenuMobile({
7172
7421
  children,
7173
7422
  label
7174
7423
  }) {
7175
- const [open, setOpen] = React34.useState(false);
7176
- const [expanded, setExpanded] = React34.useState(null);
7424
+ const [open, setOpen] = React36.useState(false);
7425
+ const [expanded, setExpanded] = React36.useState(null);
7177
7426
  const items = elementsOfType(children, MegaMenuItem);
7178
7427
  return /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "md:hidden w-full", children: [
7179
7428
  /* @__PURE__ */ jsxRuntime.jsxs(
@@ -7246,17 +7495,17 @@ function AppShell({
7246
7495
  children,
7247
7496
  className = ""
7248
7497
  }) {
7249
- const [expanded, setExpanded] = React34.useState(sidebarDefaultExpanded);
7250
- const [isMobile, setIsMobile] = React34.useState(false);
7251
- const [mobileOpen, setMobileOpen] = React34.useState(false);
7252
- React34.useEffect(() => {
7498
+ const [expanded, setExpanded] = React36.useState(sidebarDefaultExpanded);
7499
+ const [isMobile, setIsMobile] = React36.useState(false);
7500
+ const [mobileOpen, setMobileOpen] = React36.useState(false);
7501
+ React36.useEffect(() => {
7253
7502
  const mq = window.matchMedia("(max-width: 767px)");
7254
7503
  const update = (e) => setIsMobile(e.matches);
7255
7504
  update(mq);
7256
7505
  mq.addEventListener("change", update);
7257
7506
  return () => mq.removeEventListener("change", update);
7258
7507
  }, []);
7259
- React34.useEffect(() => {
7508
+ React36.useEffect(() => {
7260
7509
  if (!isMobile) setMobileOpen(false);
7261
7510
  }, [isMobile]);
7262
7511
  const hasSidebar = sidebarSections.length > 0;
@@ -7383,7 +7632,7 @@ function SecureLayout({
7383
7632
  className = ""
7384
7633
  }) {
7385
7634
  const reduced = framerMotion.useReducedMotion();
7386
- const cbs = React34.useRef({ canAccess, onGranted, onDeny });
7635
+ const cbs = React36.useRef({ canAccess, onGranted, onDeny });
7387
7636
  cbs.current = { canAccess, onGranted, onDeny };
7388
7637
  const rolesKey = JSON.stringify(roles);
7389
7638
  const requiredRolesKey = JSON.stringify(requiredRoles);
@@ -7398,10 +7647,10 @@ function SecureLayout({
7398
7647
  if (requiredPermissions?.length && !has(permissions, requiredPermissions, requireAllPermissions)) return false;
7399
7648
  return true;
7400
7649
  };
7401
- const [state, setState] = React34.useState(
7650
+ const [state, setState] = React36.useState(
7402
7651
  () => !passesSync() ? "denied" : canAccess ? "checking" : "granted"
7403
7652
  );
7404
- React34.useEffect(() => {
7653
+ React36.useEffect(() => {
7405
7654
  let cancelled = false;
7406
7655
  const { canAccess: check, onGranted: granted, onDeny: deny } = cbs.current;
7407
7656
  const finish = (ok) => {
@@ -7562,10 +7811,10 @@ function ThemeProvider({
7562
7811
  className = "",
7563
7812
  style
7564
7813
  }) {
7565
- const id = React34__default.default.useId().replace(/:/g, "");
7814
+ const id = React36__default.default.useId().replace(/:/g, "");
7566
7815
  const scopeClass = `geo-th-${id}`;
7567
- const divRef = React34.useRef(null);
7568
- React34.useEffect(() => {
7816
+ const divRef = React36.useRef(null);
7817
+ React36.useEffect(() => {
7569
7818
  const el = divRef.current;
7570
7819
  if (!el) return;
7571
7820
  if (colorScheme === "auto") return;
@@ -7580,8 +7829,8 @@ function ThemeProvider({
7580
7829
  }
7581
7830
  el.classList.toggle("dark", colorScheme === "dark");
7582
7831
  }, [colorScheme]);
7583
- const lightVars = React34.useMemo(() => toCssVars(theme), [theme]);
7584
- const darkVarStr = React34.useMemo(() => {
7832
+ const lightVars = React36.useMemo(() => toCssVars(theme), [theme]);
7833
+ const darkVarStr = React36.useMemo(() => {
7585
7834
  if (!darkTheme) return "";
7586
7835
  const dvars = toCssVars(darkTheme);
7587
7836
  if (!Object.keys(dvars).length) return "";
@@ -7623,7 +7872,7 @@ function NumberInput({
7623
7872
  readOnly = false,
7624
7873
  precision
7625
7874
  }) {
7626
- const errorId = React34.useId();
7875
+ const errorId = React36.useId();
7627
7876
  const hasError = errorMessage != null;
7628
7877
  const inferredPrecision = precision ?? (Number.isInteger(step) ? 0 : String(step).split(".")[1]?.length ?? 0);
7629
7878
  const round = (n) => {
@@ -7754,8 +8003,8 @@ function Password({
7754
8003
  showIcon,
7755
8004
  hideIcon
7756
8005
  }) {
7757
- const [visible, setVisible] = React34.useState(false);
7758
- const errorId = React34.useId();
8006
+ const [visible, setVisible] = React36.useState(false);
8007
+ const errorId = React36.useId();
7759
8008
  const hasError = errorMessage != null;
7760
8009
  return /* @__PURE__ */ jsxRuntime.jsx(
7761
8010
  Field,
@@ -7855,7 +8104,7 @@ function PasswordStrength({
7855
8104
  className = "",
7856
8105
  style
7857
8106
  }) {
7858
- const { score, label } = React34.useMemo(() => scorer(value), [scorer, value]);
8107
+ const { score, label } = React36.useMemo(() => scorer(value), [scorer, value]);
7859
8108
  const showMatch = confirmValue != null && (value.length > 0 || confirmValue.length > 0);
7860
8109
  const matches = value.length > 0 && value === confirmValue;
7861
8110
  return /* @__PURE__ */ jsxRuntime.jsxs("div", { className: cx("flex flex-col gap-2", className), style, "aria-live": "polite", children: [
@@ -7914,8 +8163,8 @@ function RadioTile({
7914
8163
  errorMessage,
7915
8164
  className
7916
8165
  }) {
7917
- const groupId = React34.useId();
7918
- const errorId = React34.useId();
8166
+ const groupId = React36.useId();
8167
+ const errorId = React36.useId();
7919
8168
  const hasError = errorMessage != null;
7920
8169
  return /* @__PURE__ */ jsxRuntime.jsx(
7921
8170
  Field,
@@ -7990,7 +8239,7 @@ function Checkbox({
7990
8239
  }) {
7991
8240
  const isChecked = checked ?? value ?? false;
7992
8241
  const labelFirst = labelPosition === "left";
7993
- const errorId = React34.useId();
8242
+ const errorId = React36.useId();
7994
8243
  const hasError = errorMessage != null;
7995
8244
  const box = /* @__PURE__ */ jsxRuntime.jsx(
7996
8245
  CheckboxPrimitive__namespace.Root,
@@ -8098,8 +8347,8 @@ function RadioGroup({
8098
8347
  className,
8099
8348
  errorMessage
8100
8349
  }) {
8101
- const errorId = React34.useId();
8102
- const groupId = React34.useId();
8350
+ const errorId = React36.useId();
8351
+ const groupId = React36.useId();
8103
8352
  const hasError = errorMessage != null;
8104
8353
  const labelFirst = labelPosition === "left";
8105
8354
  return /* @__PURE__ */ jsxRuntime.jsx(
@@ -8199,11 +8448,11 @@ function Switch({
8199
8448
  disabled,
8200
8449
  errorMessage
8201
8450
  }) {
8202
- const id = React34.useId();
8203
- const errorId = React34.useId();
8451
+ const id = React36.useId();
8452
+ const errorId = React36.useId();
8204
8453
  const hasError = errorMessage != null;
8205
8454
  const isControlled = checked !== void 0;
8206
- const [internal, setInternal] = React34.useState(defaultChecked);
8455
+ const [internal, setInternal] = React36.useState(defaultChecked);
8207
8456
  const isOn = isControlled ? checked : internal;
8208
8457
  const handle = (c) => {
8209
8458
  if (!isControlled) setInternal(c);
@@ -8279,11 +8528,11 @@ function MultiTagRow({
8279
8528
  labelFor,
8280
8529
  onRemove
8281
8530
  }) {
8282
- const wrapRef = React34.useRef(null);
8283
- const measureRef = React34.useRef(null);
8284
- const [visibleCount, setVisibleCount] = React34.useState(values.length);
8531
+ const wrapRef = React36.useRef(null);
8532
+ const measureRef = React36.useRef(null);
8533
+ const [visibleCount, setVisibleCount] = React36.useState(values.length);
8285
8534
  const key = values.map(String).join("|");
8286
- React34.useLayoutEffect(() => {
8535
+ React36.useLayoutEffect(() => {
8287
8536
  const wrap = wrapRef.current;
8288
8537
  const measure = measureRef.current;
8289
8538
  if (!wrap || !measure) return;
@@ -8375,18 +8624,21 @@ function Dropdown({
8375
8624
  labelStyle = {},
8376
8625
  placeholder,
8377
8626
  size = "md",
8378
- className = ""
8627
+ className = "",
8628
+ container
8379
8629
  }) {
8380
- const [open, setOpen] = React34.useState(false);
8381
- const [selectedItems, setSelectedItems] = React34.useState([]);
8382
- const [searchTerm, setSearchTerm] = React34.useState("");
8383
- const [innerItems, setInnerItems] = React34.useState([]);
8384
- const errorId = React34.useId();
8630
+ const dialogContainer = useDialogContainer();
8631
+ const portalContainer = container ?? dialogContainer ?? void 0;
8632
+ const [open, setOpen] = React36.useState(false);
8633
+ const [selectedItems, setSelectedItems] = React36.useState([]);
8634
+ const [searchTerm, setSearchTerm] = React36.useState("");
8635
+ const [innerItems, setInnerItems] = React36.useState([]);
8636
+ const errorId = React36.useId();
8385
8637
  const hasError = errorMessage != null;
8386
- React34.useEffect(() => {
8638
+ React36.useEffect(() => {
8387
8639
  setInnerItems(items);
8388
8640
  }, [items]);
8389
- React34.useEffect(() => {
8641
+ React36.useEffect(() => {
8390
8642
  if (isMultiselect && Array.isArray(value)) {
8391
8643
  setSelectedItems(value);
8392
8644
  }
@@ -8482,7 +8734,7 @@ function Dropdown({
8482
8734
  ]
8483
8735
  }
8484
8736
  ) }),
8485
- /* @__PURE__ */ jsxRuntime.jsx(Popover__namespace.Portal, { children: /* @__PURE__ */ jsxRuntime.jsxs(
8737
+ /* @__PURE__ */ jsxRuntime.jsx(Popover__namespace.Portal, { container: portalContainer, children: /* @__PURE__ */ jsxRuntime.jsxs(
8486
8738
  Popover__namespace.Content,
8487
8739
  {
8488
8740
  align: "start",
@@ -8579,19 +8831,19 @@ function AutoComplete({
8579
8831
  required,
8580
8832
  htmlFor
8581
8833
  }) {
8582
- const errorId = React34.useId();
8834
+ const errorId = React36.useId();
8583
8835
  const hasError = errorMessage != null;
8584
- const [term, setTerm] = React34.useState("");
8585
- const [open, setOpen] = React34.useState(false);
8586
- const [asyncItems, setAsyncItems] = React34.useState([]);
8587
- const [loading, setLoading] = React34.useState(false);
8836
+ const [term, setTerm] = React36.useState("");
8837
+ const [open, setOpen] = React36.useState(false);
8838
+ const [asyncItems, setAsyncItems] = React36.useState([]);
8839
+ const [loading, setLoading] = React36.useState(false);
8588
8840
  const isAsync = typeof onSearch === "function";
8589
- const debounceRef = React34.useRef(null);
8590
- const requestIdRef = React34.useRef(0);
8841
+ const debounceRef = React36.useRef(null);
8842
+ const requestIdRef = React36.useRef(0);
8591
8843
  const staticFiltered = isAsync || !items ? [] : term.trim() ? items.filter(
8592
8844
  ({ key, label: label2 }) => label2.toLowerCase().includes(term.toLowerCase()) || key.toLowerCase().includes(term.toLowerCase())
8593
8845
  ) : [];
8594
- React34.useEffect(() => {
8846
+ React36.useEffect(() => {
8595
8847
  if (!isAsync) return;
8596
8848
  if (debounceRef.current) clearTimeout(debounceRef.current);
8597
8849
  if (!term.trim()) {
@@ -8748,15 +9000,15 @@ function TreeSelect({
8748
9000
  defaultExpandedKeys = [],
8749
9001
  size = "md"
8750
9002
  }) {
8751
- const errorId = React34.useId();
9003
+ const errorId = React36.useId();
8752
9004
  const hasError = errorMessage != null;
8753
- const [open, setOpen] = React34.useState(false);
8754
- const [expanded, setExpanded] = React34.useState(() => new Set(defaultExpandedKeys));
8755
- const [activeIndex, setActiveIndex] = React34.useState(0);
8756
- const listRef = React34.useRef(null);
8757
- const visible = React34.useMemo(() => flattenVisible(items, expanded), [items, expanded]);
8758
- const didSyncOnOpenRef = React34.useRef(false);
8759
- React34.useEffect(() => {
9005
+ const [open, setOpen] = React36.useState(false);
9006
+ const [expanded, setExpanded] = React36.useState(() => new Set(defaultExpandedKeys));
9007
+ const [activeIndex, setActiveIndex] = React36.useState(0);
9008
+ const listRef = React36.useRef(null);
9009
+ const visible = React36.useMemo(() => flattenVisible(items, expanded), [items, expanded]);
9010
+ const didSyncOnOpenRef = React36.useRef(false);
9011
+ React36.useEffect(() => {
8760
9012
  if (!open) {
8761
9013
  didSyncOnOpenRef.current = false;
8762
9014
  return;
@@ -8766,7 +9018,7 @@ function TreeSelect({
8766
9018
  setActiveIndex(selectedIdx >= 0 ? selectedIdx : 0);
8767
9019
  didSyncOnOpenRef.current = true;
8768
9020
  }, [open, value]);
8769
- const selectedNode = React34.useMemo(
9021
+ const selectedNode = React36.useMemo(
8770
9022
  () => value != null ? findNodeByKey(items, value) : null,
8771
9023
  [items, value]
8772
9024
  );
@@ -8998,11 +9250,11 @@ function FileInput({
8998
9250
  required,
8999
9251
  icon
9000
9252
  }) {
9001
- const inputRef = React34.useRef(null);
9002
- const errorId = React34.useId();
9003
- const [files, setFiles] = React34.useState([]);
9004
- const [dragging, setDragging] = React34.useState(false);
9005
- const [sizeError, setSizeError] = React34.useState(null);
9253
+ const inputRef = React36.useRef(null);
9254
+ const errorId = React36.useId();
9255
+ const [files, setFiles] = React36.useState([]);
9256
+ const [dragging, setDragging] = React36.useState(false);
9257
+ const [sizeError, setSizeError] = React36.useState(null);
9006
9258
  const effectiveError = errorMessage ?? sizeError ?? void 0;
9007
9259
  const openPicker = () => {
9008
9260
  if (!disabled) inputRef.current?.click();
@@ -9193,30 +9445,30 @@ function DatePicker({
9193
9445
  size = "md",
9194
9446
  className = ""
9195
9447
  }) {
9196
- const errorId = React34.useId();
9448
+ const errorId = React36.useId();
9197
9449
  const hasError = errorMessage != null;
9198
- const [open, setOpen] = React34.useState(false);
9199
- const [viewMonth, setViewMonth] = React34.useState(() => startOfMonth2(value ?? /* @__PURE__ */ new Date()));
9200
- const [focusDate, setFocusDate] = React34.useState(() => value ?? /* @__PURE__ */ new Date());
9201
- const [view, setView] = React34.useState("days");
9202
- const gridRef = React34.useRef(null);
9203
- React34.useEffect(() => {
9450
+ const [open, setOpen] = React36.useState(false);
9451
+ const [viewMonth, setViewMonth] = React36.useState(() => startOfMonth2(value ?? /* @__PURE__ */ new Date()));
9452
+ const [focusDate, setFocusDate] = React36.useState(() => value ?? /* @__PURE__ */ new Date());
9453
+ const [view, setView] = React36.useState("days");
9454
+ const gridRef = React36.useRef(null);
9455
+ React36.useEffect(() => {
9204
9456
  if (!open) return;
9205
9457
  const target = value ?? /* @__PURE__ */ new Date();
9206
9458
  setViewMonth(startOfMonth2(target));
9207
9459
  setFocusDate(target);
9208
9460
  setView("days");
9209
9461
  }, [open, value]);
9210
- React34.useEffect(() => {
9462
+ React36.useEffect(() => {
9211
9463
  if (!open) return;
9212
9464
  const cell = gridRef.current?.querySelector(`[data-day="${defaultFormat3(focusDate)}"]`);
9213
9465
  cell?.focus();
9214
9466
  }, [open, focusDate]);
9215
- const weekdays = React34.useMemo(() => {
9467
+ const weekdays = React36.useMemo(() => {
9216
9468
  const ordered = WEEKDAY_SHORT.slice(weekStartsOn).concat(WEEKDAY_SHORT.slice(0, weekStartsOn));
9217
9469
  return ordered;
9218
9470
  }, [weekStartsOn]);
9219
- const grid = React34.useMemo(() => buildGrid(viewMonth, weekStartsOn), [viewMonth, weekStartsOn]);
9471
+ const grid = React36.useMemo(() => buildGrid(viewMonth, weekStartsOn), [viewMonth, weekStartsOn]);
9220
9472
  const isDisabled = (d) => {
9221
9473
  if (min && d < min) return true;
9222
9474
  if (max && d > max) return true;
@@ -9507,10 +9759,10 @@ function TextArea({
9507
9759
  style,
9508
9760
  inputStyle
9509
9761
  }) {
9510
- const errorId = React34.useId();
9762
+ const errorId = React36.useId();
9511
9763
  const hasError = errorMessage != null;
9512
- const ref = React34.useRef(null);
9513
- React34.useLayoutEffect(() => {
9764
+ const ref = React36.useRef(null);
9765
+ React36.useLayoutEffect(() => {
9514
9766
  if (!autoGrow) return;
9515
9767
  const el = ref.current;
9516
9768
  if (!el) return;
@@ -9582,14 +9834,14 @@ function Slider({
9582
9834
  name,
9583
9835
  htmlFor
9584
9836
  }) {
9585
- const errorId = React34.useId();
9837
+ const errorId = React36.useId();
9586
9838
  const hasError = errorMessage != null;
9587
9839
  const isRange = Array.isArray(value ?? defaultValue);
9588
- const [internal, setInternal] = React34.useState(
9840
+ const [internal, setInternal] = React36.useState(
9589
9841
  () => toArray(value) ?? toArray(defaultValue) ?? [min]
9590
9842
  );
9591
9843
  const current = toArray(value) ?? internal;
9592
- const [dragging, setDragging] = React34.useState(false);
9844
+ const [dragging, setDragging] = React36.useState(false);
9593
9845
  const emit = (arr) => {
9594
9846
  setInternal(arr);
9595
9847
  const next = isRange ? [arr[0], arr[1]] : arr[0];
@@ -9684,11 +9936,11 @@ function TagsInput({
9684
9936
  validate,
9685
9937
  separators = ["Enter", ","]
9686
9938
  }) {
9687
- const errorId = React34.useId();
9688
- const inputRef = React34.useRef(null);
9689
- const [internal, setInternal] = React34.useState(defaultValue ?? []);
9690
- const [draft, setDraft] = React34.useState("");
9691
- const [localError, setLocalError] = React34.useState(null);
9939
+ const errorId = React36.useId();
9940
+ const inputRef = React36.useRef(null);
9941
+ const [internal, setInternal] = React36.useState(defaultValue ?? []);
9942
+ const [draft, setDraft] = React36.useState("");
9943
+ const [localError, setLocalError] = React36.useState(null);
9692
9944
  const tags = value ?? internal;
9693
9945
  const hasError = errorMessage != null || localError != null;
9694
9946
  const errorText = errorMessage ?? localError ?? void 0;
@@ -9819,9 +10071,9 @@ function OtpInput({
9819
10071
  className,
9820
10072
  groupAfter
9821
10073
  }) {
9822
- const errorId = React34.useId();
10074
+ const errorId = React36.useId();
9823
10075
  const hasError = errorMessage != null;
9824
- const refs = React34.useRef([]);
10076
+ const refs = React36.useRef([]);
9825
10077
  const chars = Array.from({ length }, (_, i) => value[i] ?? "");
9826
10078
  const pattern = mode === "numeric" ? /[0-9]/ : /[a-zA-Z0-9]/;
9827
10079
  const emit = (next) => {
@@ -9870,7 +10122,7 @@ function OtpInput({
9870
10122
  emit(valid.join(""));
9871
10123
  focusBox(valid.length);
9872
10124
  };
9873
- return /* @__PURE__ */ jsxRuntime.jsx(Field, { className, label, htmlFor, errorId, errorMessage, required, layout, helperText, children: /* @__PURE__ */ jsxRuntime.jsx("div", { className: "flex flex-wrap items-center gap-2", role: "group", "aria-label": typeof label === "string" ? label : "One-time code", children: chars.map((char, idx) => /* @__PURE__ */ jsxRuntime.jsxs(React34__default.default.Fragment, { children: [
10125
+ return /* @__PURE__ */ jsxRuntime.jsx(Field, { className, label, htmlFor, errorId, errorMessage, required, layout, helperText, children: /* @__PURE__ */ jsxRuntime.jsx("div", { className: "flex flex-wrap items-center gap-2", role: "group", "aria-label": typeof label === "string" ? label : "One-time code", children: chars.map((char, idx) => /* @__PURE__ */ jsxRuntime.jsxs(React36__default.default.Fragment, { children: [
9874
10126
  /* @__PURE__ */ jsxRuntime.jsx(
9875
10127
  "input",
9876
10128
  {
@@ -9928,9 +10180,9 @@ function Rating({
9928
10180
  className,
9929
10181
  required
9930
10182
  }) {
9931
- const errorId = React34.useId();
9932
- const [internal, setInternal] = React34.useState(defaultValue);
9933
- const [hover, setHover] = React34.useState(null);
10183
+ const errorId = React36.useId();
10184
+ const [internal, setInternal] = React36.useState(defaultValue);
10185
+ const [hover, setHover] = React36.useState(null);
9934
10186
  const current = value ?? internal;
9935
10187
  const display2 = hover ?? current;
9936
10188
  const interactive = !readOnly && !disabled;
@@ -10053,9 +10305,9 @@ function TimePicker({
10053
10305
  required,
10054
10306
  style
10055
10307
  }) {
10056
- const errorId = React34.useId();
10308
+ const errorId = React36.useId();
10057
10309
  const hasError = errorMessage != null;
10058
- const [open, setOpen] = React34.useState(false);
10310
+ const [open, setOpen] = React36.useState(false);
10059
10311
  const parsed = parse(value) ?? { h: 0, m: 0, s: 0 };
10060
10312
  const update = (next) => {
10061
10313
  const merged = { ...parsed, ...next };
@@ -10180,13 +10432,13 @@ function DateRangePicker({
10180
10432
  required,
10181
10433
  style
10182
10434
  }) {
10183
- const errorId = React34.useId();
10435
+ const errorId = React36.useId();
10184
10436
  const hasError = errorMessage != null;
10185
- const [open, setOpen] = React34.useState(false);
10186
- const [leftMonth, setLeftMonth] = React34.useState(() => startOfMonth3(value.start ?? /* @__PURE__ */ new Date()));
10187
- const [pendingStart, setPendingStart] = React34.useState(null);
10188
- const [hoverDate, setHoverDate] = React34.useState(null);
10189
- const weekdays = React34.useMemo(
10437
+ const [open, setOpen] = React36.useState(false);
10438
+ const [leftMonth, setLeftMonth] = React36.useState(() => startOfMonth3(value.start ?? /* @__PURE__ */ new Date()));
10439
+ const [pendingStart, setPendingStart] = React36.useState(null);
10440
+ const [hoverDate, setHoverDate] = React36.useState(null);
10441
+ const weekdays = React36.useMemo(
10190
10442
  () => WEEKDAY.slice(weekStartsOn).concat(WEEKDAY.slice(0, weekStartsOn)),
10191
10443
  [weekStartsOn]
10192
10444
  );
@@ -10363,10 +10615,10 @@ function ColorPicker({
10363
10615
  required,
10364
10616
  placeholder = "Pick a colour\u2026"
10365
10617
  }) {
10366
- const errorId = React34.useId();
10618
+ const errorId = React36.useId();
10367
10619
  const hasError = errorMessage != null;
10368
- const [open, setOpen] = React34.useState(false);
10369
- const [draft, setDraft] = React34.useState(value);
10620
+ const [open, setOpen] = React36.useState(false);
10621
+ const [draft, setDraft] = React36.useState(value);
10370
10622
  const valid = HEX_RE.test(value);
10371
10623
  const pick = (hex) => {
10372
10624
  onChange?.(hex);
@@ -10454,7 +10706,7 @@ function ColorPicker({
10454
10706
  }
10455
10707
  var CUSTOM_EVENT = "oxy-local-storage";
10456
10708
  function useLocalStorage(key, initialValue) {
10457
- const read = React34.useCallback(() => {
10709
+ const read = React36.useCallback(() => {
10458
10710
  if (typeof window === "undefined") return initialValue;
10459
10711
  try {
10460
10712
  const item = window.localStorage.getItem(key);
@@ -10463,8 +10715,8 @@ function useLocalStorage(key, initialValue) {
10463
10715
  return initialValue;
10464
10716
  }
10465
10717
  }, [key]);
10466
- const [stored, setStored] = React34.useState(read);
10467
- const setValue = React34.useCallback((value) => {
10718
+ const [stored, setStored] = React36.useState(read);
10719
+ const setValue = React36.useCallback((value) => {
10468
10720
  setStored((prev) => {
10469
10721
  const next = value instanceof Function ? value(prev) : value;
10470
10722
  try {
@@ -10477,7 +10729,7 @@ function useLocalStorage(key, initialValue) {
10477
10729
  return next;
10478
10730
  });
10479
10731
  }, [key]);
10480
- const remove = React34.useCallback(() => {
10732
+ const remove = React36.useCallback(() => {
10481
10733
  try {
10482
10734
  if (typeof window !== "undefined") {
10483
10735
  window.localStorage.removeItem(key);
@@ -10487,10 +10739,10 @@ function useLocalStorage(key, initialValue) {
10487
10739
  }
10488
10740
  setStored(initialValue);
10489
10741
  }, [key]);
10490
- React34.useEffect(() => {
10742
+ React36.useEffect(() => {
10491
10743
  setStored(read());
10492
10744
  }, [key, read]);
10493
- React34.useEffect(() => {
10745
+ React36.useEffect(() => {
10494
10746
  if (typeof window === "undefined") return;
10495
10747
  const onStorage = (e) => {
10496
10748
  if (e.key === null || e.key === key) setStored(read());
@@ -10509,8 +10761,8 @@ function useLocalStorage(key, initialValue) {
10509
10761
  }
10510
10762
  function useMediaQuery(query) {
10511
10763
  const get = () => typeof window !== "undefined" && typeof window.matchMedia === "function" ? window.matchMedia(query).matches : false;
10512
- const [matches, setMatches] = React34.useState(get);
10513
- React34.useEffect(() => {
10764
+ const [matches, setMatches] = React36.useState(get);
10765
+ React36.useEffect(() => {
10514
10766
  if (typeof window === "undefined" || typeof window.matchMedia !== "function") return;
10515
10767
  const mql = window.matchMedia(query);
10516
10768
  const onChange = () => setMatches(mql.matches);
@@ -10541,8 +10793,8 @@ function decodeSegment(seg) {
10541
10793
  }
10542
10794
  }
10543
10795
  function useJwt(token) {
10544
- const [, tick] = React34.useState(0);
10545
- const decoded = React34.useMemo(() => {
10796
+ const [, tick] = React36.useState(0);
10797
+ const decoded = React36.useMemo(() => {
10546
10798
  if (!token) return { payload: null, header: null, exp: null };
10547
10799
  const [h, p] = token.split(".");
10548
10800
  const header = decodeSegment(h);
@@ -10550,7 +10802,7 @@ function useJwt(token) {
10550
10802
  const exp = payload && typeof payload.exp === "number" ? payload.exp : null;
10551
10803
  return { payload, header, exp };
10552
10804
  }, [token]);
10553
- React34.useEffect(() => {
10805
+ React36.useEffect(() => {
10554
10806
  if (decoded.exp == null) return;
10555
10807
  const ms = decoded.exp * 1e3 - Date.now();
10556
10808
  if (ms <= 0) return;
@@ -10724,13 +10976,13 @@ function SlideShow({
10724
10976
  style
10725
10977
  }) {
10726
10978
  const reduced = framerMotion.useReducedMotion();
10727
- const [index, setIndex] = React34.useState(0);
10728
- const [paused, setPaused] = React34.useState(false);
10979
+ const [index, setIndex] = React36.useState(0);
10980
+ const [paused, setPaused] = React36.useState(false);
10729
10981
  const count = slides.length;
10730
10982
  const idx = count ? (index % count + count) % count : 0;
10731
- const go = React34.useCallback((d) => setIndex((i) => i + d), []);
10732
- const timer = React34.useRef(null);
10733
- React34.useEffect(() => {
10983
+ const go = React36.useCallback((d) => setIndex((i) => i + d), []);
10984
+ const timer = React36.useRef(null);
10985
+ React36.useEffect(() => {
10734
10986
  if (!autoPlay || paused || count <= 1) return;
10735
10987
  timer.current = setInterval(() => setIndex((i) => i + 1), interval);
10736
10988
  return () => {
@@ -10806,7 +11058,7 @@ function Video({
10806
11058
  className = "",
10807
11059
  style
10808
11060
  }) {
10809
- const [playing, setPlaying] = React34.useState(autoPlay);
11061
+ const [playing, setPlaying] = React36.useState(autoPlay);
10810
11062
  const frame = cx("relative w-full overflow-hidden bg-backdrop", framed ? "rounded-2xl border border-border shadow-sm" : "", className);
10811
11063
  const ratio = aspect.replace("/", " / ");
10812
11064
  return /* @__PURE__ */ jsxRuntime.jsx("div", { className: frame, style: { aspectRatio: ratio, ...style }, children: embedUrl ? /* @__PURE__ */ jsxRuntime.jsx(
@@ -10861,7 +11113,7 @@ function Parallax({
10861
11113
  style
10862
11114
  }) {
10863
11115
  const reduced = framerMotion.useReducedMotion();
10864
- const ref = React34.useRef(null);
11116
+ const ref = React36.useRef(null);
10865
11117
  const { scrollYProgress } = framerMotion.useScroll({ target: ref, offset: ["start end", "end start"] });
10866
11118
  const shift = Math.max(0, Math.min(1, speed)) * 100;
10867
11119
  const y = framerMotion.useTransform(scrollYProgress, [0, 1], reduced ? ["0%", "0%"] : [`-${shift / 2}%`, `${shift / 2}%`]);
@@ -10929,7 +11181,7 @@ function Blog({
10929
11181
  post.tag != null && !post.image && /* @__PURE__ */ jsxRuntime.jsx("div", { children: /* @__PURE__ */ jsxRuntime.jsx(Badge, { tone: "accent", variant: "soft", size: "sm", children: post.tag }) }),
10930
11182
  /* @__PURE__ */ jsxRuntime.jsx("h3", { className: "text-base font-semibold leading-snug text-foreground transition-colors group-hover:text-accent", children: post.title }),
10931
11183
  post.excerpt != null && /* @__PURE__ */ jsxRuntime.jsx("p", { className: "line-clamp-3 text-sm leading-relaxed text-foreground-secondary", children: post.excerpt }),
10932
- meta.length > 0 && /* @__PURE__ */ jsxRuntime.jsx("div", { className: "mt-auto flex flex-wrap items-center gap-x-2 gap-y-1 pt-3 text-xs text-foreground-muted", children: meta.map((m, j) => /* @__PURE__ */ jsxRuntime.jsxs(React34__default.default.Fragment, { children: [
11184
+ meta.length > 0 && /* @__PURE__ */ jsxRuntime.jsx("div", { className: "mt-auto flex flex-wrap items-center gap-x-2 gap-y-1 pt-3 text-xs text-foreground-muted", children: meta.map((m, j) => /* @__PURE__ */ jsxRuntime.jsxs(React36__default.default.Fragment, { children: [
10933
11185
  j > 0 && /* @__PURE__ */ jsxRuntime.jsx("span", { "aria-hidden": "true", children: "\xB7" }),
10934
11186
  /* @__PURE__ */ jsxRuntime.jsx("span", { children: m })
10935
11187
  ] }, j)) })
@@ -11058,8 +11310,8 @@ function LeadCapture({
11058
11310
  className = "",
11059
11311
  style
11060
11312
  }) {
11061
- const [email, setEmail] = React34.useState("");
11062
- const [done, setDone] = React34.useState(false);
11313
+ const [email, setEmail] = React36.useState("");
11314
+ const [done, setDone] = React36.useState(false);
11063
11315
  const submit = (e) => {
11064
11316
  e.preventDefault();
11065
11317
  const value = email.trim();