@geomak/ui 6.26.1 → 6.27.1

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 chunkOAV4TA4B_cjs = require('./chunk-OAV4TA4B.cjs');
4
4
  var jsxRuntime = require('react/jsx-runtime');
5
- var React29 = require('react');
5
+ var React28 = require('react');
6
6
  var reactDom = require('react-dom');
7
7
  var AvatarPrimitive = require('@radix-ui/react-avatar');
8
8
  var DropdownMenu = require('@radix-ui/react-dropdown-menu');
@@ -40,7 +40,7 @@ function _interopNamespace(e) {
40
40
  return Object.freeze(n);
41
41
  }
42
42
 
43
- var React29__default = /*#__PURE__*/_interopDefault(React29);
43
+ var React28__default = /*#__PURE__*/_interopDefault(React28);
44
44
  var AvatarPrimitive__namespace = /*#__PURE__*/_interopNamespace(AvatarPrimitive);
45
45
  var DropdownMenu__namespace = /*#__PURE__*/_interopNamespace(DropdownMenu);
46
46
  var Dialog__namespace = /*#__PURE__*/_interopNamespace(Dialog);
@@ -216,8 +216,8 @@ Icon.Copy = Copy;
216
216
  Icon.CircleStack = CircleStack;
217
217
  var icons_default = Icon;
218
218
  function Portal({ children, target }) {
219
- const [resolved, setResolved] = React29.useState(null);
220
- React29.useEffect(() => {
219
+ const [resolved, setResolved] = React28.useState(null);
220
+ React28.useEffect(() => {
221
221
  if (target === null) {
222
222
  setResolved(null);
223
223
  return;
@@ -651,7 +651,7 @@ function IconButton({
651
651
  className = "",
652
652
  style
653
653
  }) {
654
- const colorScheme = React29.useMemo(() => {
654
+ const colorScheme = React28.useMemo(() => {
655
655
  if (type === "primary") {
656
656
  return "bg-accent text-accent-fg hover:bg-accent-hover";
657
657
  }
@@ -730,7 +730,7 @@ var SIZE_CLASSES = {
730
730
  md: "h-9 px-4 text-sm gap-1.5 rounded-lg",
731
731
  lg: "h-11 px-5 text-sm gap-2 rounded-xl"
732
732
  };
733
- var Button = React29__default.default.forwardRef(function Button2({
733
+ var Button = React28__default.default.forwardRef(function Button2({
734
734
  content,
735
735
  variant = "primary",
736
736
  size = "md",
@@ -838,7 +838,7 @@ function MenuButton({
838
838
  "data-[state=open]:animate-in data-[state=open]:fade-in-0 data-[state=open]:zoom-in-95",
839
839
  "data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=closed]:zoom-out-95"
840
840
  ].join(" "),
841
- children: items.map((item) => /* @__PURE__ */ jsxRuntime.jsxs(React29__default.default.Fragment, { children: [
841
+ children: items.map((item) => /* @__PURE__ */ jsxRuntime.jsxs(React28__default.default.Fragment, { children: [
842
842
  item.separatorBefore && /* @__PURE__ */ jsxRuntime.jsx(DropdownMenu__namespace.Separator, { className: "my-1 h-px bg-border" }),
843
843
  /* @__PURE__ */ jsxRuntime.jsxs(
844
844
  DropdownMenu__namespace.Item,
@@ -1081,9 +1081,9 @@ function Tooltip({
1081
1081
  ] }) });
1082
1082
  }
1083
1083
  var TooltipProvider = TooltipPrimitive__namespace.Provider;
1084
- var TabsContext = React29.createContext(null);
1084
+ var TabsContext = React28.createContext(null);
1085
1085
  function useTabsContext() {
1086
- const ctx = React29.useContext(TabsContext);
1086
+ const ctx = React28.useContext(TabsContext);
1087
1087
  if (!ctx) throw new Error("Tabs.List / Tabs.Trigger / Tabs.Panel must be rendered inside <Tabs>.");
1088
1088
  return ctx;
1089
1089
  }
@@ -1105,26 +1105,26 @@ function Tabs({
1105
1105
  children
1106
1106
  }) {
1107
1107
  const isControlled = value !== void 0;
1108
- const [internal, setInternal] = React29.useState(defaultValue);
1108
+ const [internal, setInternal] = React28.useState(defaultValue);
1109
1109
  const current = isControlled ? value : internal;
1110
1110
  const reduced = !!framerMotion.useReducedMotion();
1111
- const indicatorId = React29.useId();
1112
- const select = React29.useCallback((next) => {
1111
+ const indicatorId = React28.useId();
1112
+ const select = React28.useCallback((next) => {
1113
1113
  if (!isControlled) setInternal(next);
1114
1114
  onValueChange?.(next);
1115
1115
  }, [isControlled, onValueChange]);
1116
- const registry = React29.useRef(/* @__PURE__ */ new Map());
1117
- const orderRef = React29.useRef(0);
1118
- const [, bump] = React29.useState(0);
1119
- const registerTab = React29.useCallback((val, meta) => {
1116
+ const registry = React28.useRef(/* @__PURE__ */ new Map());
1117
+ const orderRef = React28.useRef(0);
1118
+ const [, bump] = React28.useState(0);
1119
+ const registerTab = React28.useCallback((val, meta) => {
1120
1120
  const existing = registry.current.get(val);
1121
1121
  registry.current.set(val, { ...meta, order: existing?.order ?? orderRef.current++ });
1122
1122
  if (!existing) bump((v) => v + 1);
1123
1123
  }, []);
1124
- const unregisterTab = React29.useCallback((val) => {
1124
+ const unregisterTab = React28.useCallback((val) => {
1125
1125
  if (registry.current.delete(val)) bump((v) => v + 1);
1126
1126
  }, []);
1127
- const getTabs = React29.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 })), []);
1127
+ const getTabs = React28.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 })), []);
1128
1128
  return /* @__PURE__ */ jsxRuntime.jsx(TabsContext.Provider, { value: { value: current, variant, size, orientation, indicatorId, reduced, select, registerTab, unregisterTab, getTabs }, children: /* @__PURE__ */ jsxRuntime.jsx(
1129
1129
  TabsPrimitive__namespace.Root,
1130
1130
  {
@@ -1144,10 +1144,10 @@ function Tabs({
1144
1144
  function TabsList({ children, "aria-label": ariaLabel, className = "" }) {
1145
1145
  const { variant, orientation, reduced, value } = useTabsContext();
1146
1146
  const horizontal = orientation === "horizontal";
1147
- const scrollRef = React29.useRef(null);
1148
- const [edges, setEdges] = React29.useState({ start: false, end: false });
1147
+ const scrollRef = React28.useRef(null);
1148
+ const [edges, setEdges] = React28.useState({ start: false, end: false });
1149
1149
  const scrollable = variant !== "segmented";
1150
- React29.useLayoutEffect(() => {
1150
+ React28.useLayoutEffect(() => {
1151
1151
  const el = scrollRef.current;
1152
1152
  if (!el || !scrollable) return;
1153
1153
  const update = () => {
@@ -1172,13 +1172,13 @@ function TabsList({ children, "aria-label": ariaLabel, className = "" }) {
1172
1172
  ro.disconnect();
1173
1173
  };
1174
1174
  }, [horizontal, scrollable, children]);
1175
- const nudge = React29.useCallback((dir) => {
1175
+ const nudge = React28.useCallback((dir) => {
1176
1176
  const el = scrollRef.current;
1177
1177
  if (!el) return;
1178
1178
  const amount = (horizontal ? el.clientWidth : el.clientHeight) * 0.7 * dir;
1179
1179
  el.scrollBy({ [horizontal ? "left" : "top"]: amount, behavior: reduced ? "auto" : "smooth" });
1180
1180
  }, [horizontal, reduced]);
1181
- React29.useLayoutEffect(() => {
1181
+ React28.useLayoutEffect(() => {
1182
1182
  const el = scrollRef.current;
1183
1183
  if (!el || !scrollable) return;
1184
1184
  const active = el.querySelector("[role=tab][data-state=active]");
@@ -1236,9 +1236,9 @@ function Chevron2({ side, orientation, onClick }) {
1236
1236
  function OverflowMenu() {
1237
1237
  const { getTabs, value, select, orientation } = useTabsContext();
1238
1238
  const horizontal = orientation === "horizontal";
1239
- const [open, setOpen] = React29.useState(false);
1240
- const wrapRef = React29.useRef(null);
1241
- const timer = React29.useRef(null);
1239
+ const [open, setOpen] = React28.useState(false);
1240
+ const wrapRef = React28.useRef(null);
1241
+ const timer = React28.useRef(null);
1242
1242
  const openNow = () => {
1243
1243
  if (timer.current) clearTimeout(timer.current);
1244
1244
  setOpen(true);
@@ -1246,7 +1246,7 @@ function OverflowMenu() {
1246
1246
  const closeSoon = () => {
1247
1247
  timer.current = setTimeout(() => setOpen(false), 160);
1248
1248
  };
1249
- React29.useLayoutEffect(() => {
1249
+ React28.useLayoutEffect(() => {
1250
1250
  if (!open) return;
1251
1251
  const onDoc = (e) => {
1252
1252
  if (wrapRef.current && !wrapRef.current.contains(e.target)) setOpen(false);
@@ -1327,7 +1327,7 @@ function TabsTrigger({ value, icon, badge, closeable, onClose, disabled, classNa
1327
1327
  const isActive = active === value;
1328
1328
  const horizontal = orientation === "horizontal";
1329
1329
  const sz = SIZE[size];
1330
- React29.useLayoutEffect(() => {
1330
+ React28.useLayoutEffect(() => {
1331
1331
  registerTab(value, { label: children, icon, disabled });
1332
1332
  return () => unregisterTab(value);
1333
1333
  }, [value, children, icon, disabled, registerTab, unregisterTab]);
@@ -1525,7 +1525,7 @@ function Tree({
1525
1525
  item.key
1526
1526
  )) });
1527
1527
  }
1528
- var AccordionCtx = React29.createContext({ variant: "separated" });
1528
+ var AccordionCtx = React28.createContext({ variant: "separated" });
1529
1529
  function Accordion2({
1530
1530
  children,
1531
1531
  type = "single",
@@ -1584,7 +1584,7 @@ var Chevron3 = /* @__PURE__ */ jsxRuntime.jsx(
1584
1584
  }
1585
1585
  );
1586
1586
  function AccordionItem({ value, title, icon, children, disabled, className = "" }) {
1587
- const { variant } = React29.useContext(AccordionCtx);
1587
+ const { variant } = React28.useContext(AccordionCtx);
1588
1588
  return /* @__PURE__ */ jsxRuntime.jsxs(
1589
1589
  AccordionPrimitive__namespace.Item,
1590
1590
  {
@@ -1643,7 +1643,7 @@ function Breadcrumbs({
1643
1643
  className = "",
1644
1644
  style
1645
1645
  }) {
1646
- const [expanded, setExpanded] = React29.useState(false);
1646
+ const [expanded, setExpanded] = React28.useState(false);
1647
1647
  const shouldCollapse = maxItems > 0 && items.length > maxItems && !expanded;
1648
1648
  const visible = [];
1649
1649
  if (shouldCollapse) {
@@ -1827,8 +1827,8 @@ function Stepper({
1827
1827
  className = ""
1828
1828
  }) {
1829
1829
  const reduced = framerMotion.useReducedMotion();
1830
- const [forcedVertical, setForcedVertical] = React29.useState(false);
1831
- React29.useEffect(() => {
1830
+ const [forcedVertical, setForcedVertical] = React28.useState(false);
1831
+ React28.useEffect(() => {
1832
1832
  if (!responsive || orientation === "vertical") return;
1833
1833
  if (typeof window === "undefined" || typeof window.matchMedia !== "function") return;
1834
1834
  const mq = window.matchMedia("(max-width: 767px)");
@@ -1937,7 +1937,7 @@ function Kbd({
1937
1937
  style
1938
1938
  }) {
1939
1939
  if (keys && keys.length > 0) {
1940
- return /* @__PURE__ */ jsxRuntime.jsx("span", { className: ["inline-flex items-center gap-1", className].filter(Boolean).join(" "), style, children: keys.map((k, i) => /* @__PURE__ */ jsxRuntime.jsxs(React29__default.default.Fragment, { children: [
1940
+ return /* @__PURE__ */ jsxRuntime.jsx("span", { className: ["inline-flex items-center gap-1", className].filter(Boolean).join(" "), style, children: keys.map((k, i) => /* @__PURE__ */ jsxRuntime.jsxs(React28__default.default.Fragment, { children: [
1941
1941
  i > 0 && /* @__PURE__ */ jsxRuntime.jsx("span", { className: "text-foreground-muted text-xs select-none", children: separator }),
1942
1942
  /* @__PURE__ */ jsxRuntime.jsx("kbd", { className: [cap, SIZE3[size]].join(" "), children: k })
1943
1943
  ] }, `${k}-${i}`)) });
@@ -2028,13 +2028,13 @@ function FlatCarousel({
2028
2028
  className = "",
2029
2029
  style
2030
2030
  }) {
2031
- const scrollerRef = React29.useRef(null);
2032
- const slides = React29__default.default.Children.toArray(children);
2033
- const [active, setActive] = React29.useState(0);
2034
- const [atStart, setAtStart] = React29.useState(true);
2035
- const [atEnd, setAtEnd] = React29.useState(false);
2031
+ const scrollerRef = React28.useRef(null);
2032
+ const slides = React28__default.default.Children.toArray(children);
2033
+ const [active, setActive] = React28.useState(0);
2034
+ const [atStart, setAtStart] = React28.useState(true);
2035
+ const [atEnd, setAtEnd] = React28.useState(false);
2036
2036
  const width = typeof itemWidth === "number" ? `${itemWidth}px` : itemWidth;
2037
- const update = React29.useCallback(() => {
2037
+ const update = React28.useCallback(() => {
2038
2038
  const el = scrollerRef.current;
2039
2039
  if (!el) return;
2040
2040
  setAtStart(el.scrollLeft <= 1);
@@ -2043,7 +2043,7 @@ function FlatCarousel({
2043
2043
  const slideW = first ? first.getBoundingClientRect().width + gap : el.clientWidth;
2044
2044
  setActive(Math.round(el.scrollLeft / slideW));
2045
2045
  }, [gap]);
2046
- React29.useEffect(() => {
2046
+ React28.useEffect(() => {
2047
2047
  update();
2048
2048
  const el = scrollerRef.current;
2049
2049
  if (!el) return;
@@ -2084,9 +2084,9 @@ function RotatingCarousel({
2084
2084
  className = "",
2085
2085
  style
2086
2086
  }) {
2087
- const slides = React29__default.default.Children.toArray(children);
2087
+ const slides = React28__default.default.Children.toArray(children);
2088
2088
  const count = slides.length;
2089
- const [active, setActive] = React29.useState(0);
2089
+ const [active, setActive] = React28.useState(0);
2090
2090
  const reduced = framerMotion.useReducedMotion();
2091
2091
  const wrap = (n) => count > 0 ? (n % count + count) % count : 0;
2092
2092
  const idx = wrap(active);
@@ -2236,7 +2236,7 @@ function FAB({
2236
2236
  className = "",
2237
2237
  style
2238
2238
  }) {
2239
- const [open, setOpen] = React29.useState(false);
2239
+ const [open, setOpen] = React28.useState(false);
2240
2240
  const reduced = framerMotion.useReducedMotion();
2241
2241
  const hasDial = !!actions && actions.length > 0;
2242
2242
  const bottom = position.startsWith("bottom");
@@ -2338,8 +2338,8 @@ function PopConfirm({
2338
2338
  onOpenChange,
2339
2339
  className = ""
2340
2340
  }) {
2341
- const [uncontrolledOpen, setUncontrolledOpen] = React29.useState(false);
2342
- const [loading, setLoading] = React29.useState(false);
2341
+ const [uncontrolledOpen, setUncontrolledOpen] = React28.useState(false);
2342
+ const [loading, setLoading] = React28.useState(false);
2343
2343
  const isOpen = open ?? uncontrolledOpen;
2344
2344
  const setOpen = (next) => {
2345
2345
  onOpenChange?.(next);
@@ -2426,16 +2426,16 @@ function LogoutTimer({
2426
2426
  logoutLabel = "Sign out now"
2427
2427
  }) {
2428
2428
  const reduced = framerMotion.useReducedMotion();
2429
- const [warning, setWarning] = React29.useState(false);
2430
- const [remaining, setRemaining] = React29.useState(countdown);
2431
- const idleTimer = React29.useRef(null);
2432
- const tick = React29.useRef(null);
2433
- const deadline = React29.useRef(0);
2434
- const warningRef = React29.useRef(false);
2435
- const lastReset = React29.useRef(0);
2436
- const cbs = React29.useRef({ onLogout, onContinue, onWarning });
2429
+ const [warning, setWarning] = React28.useState(false);
2430
+ const [remaining, setRemaining] = React28.useState(countdown);
2431
+ const idleTimer = React28.useRef(null);
2432
+ const tick = React28.useRef(null);
2433
+ const deadline = React28.useRef(0);
2434
+ const warningRef = React28.useRef(false);
2435
+ const lastReset = React28.useRef(0);
2436
+ const cbs = React28.useRef({ onLogout, onContinue, onWarning });
2437
2437
  cbs.current = { onLogout, onContinue, onWarning };
2438
- const clearTimers = React29.useCallback(() => {
2438
+ const clearTimers = React28.useCallback(() => {
2439
2439
  if (idleTimer.current) {
2440
2440
  clearTimeout(idleTimer.current);
2441
2441
  idleTimer.current = null;
@@ -2445,13 +2445,13 @@ function LogoutTimer({
2445
2445
  tick.current = null;
2446
2446
  }
2447
2447
  }, []);
2448
- const logout = React29.useCallback(() => {
2448
+ const logout = React28.useCallback(() => {
2449
2449
  clearTimers();
2450
2450
  warningRef.current = false;
2451
2451
  setWarning(false);
2452
2452
  cbs.current.onLogout();
2453
2453
  }, [clearTimers]);
2454
- const startIdle = React29.useCallback(() => {
2454
+ const startIdle = React28.useCallback(() => {
2455
2455
  if (idleTimer.current) clearTimeout(idleTimer.current);
2456
2456
  idleTimer.current = setTimeout(() => {
2457
2457
  warningRef.current = true;
@@ -2466,7 +2466,7 @@ function LogoutTimer({
2466
2466
  }, 250);
2467
2467
  }, timeout);
2468
2468
  }, [timeout, countdown, logout]);
2469
- const stay = React29.useCallback(() => {
2469
+ const stay = React28.useCallback(() => {
2470
2470
  if (tick.current) {
2471
2471
  clearInterval(tick.current);
2472
2472
  tick.current = null;
@@ -2476,7 +2476,7 @@ function LogoutTimer({
2476
2476
  cbs.current.onContinue?.();
2477
2477
  startIdle();
2478
2478
  }, [startIdle]);
2479
- React29.useEffect(() => {
2479
+ React28.useEffect(() => {
2480
2480
  if (!enabled) {
2481
2481
  clearTimers();
2482
2482
  warningRef.current = false;
@@ -2548,16 +2548,16 @@ function Calendar2({
2548
2548
  className = "",
2549
2549
  style
2550
2550
  }) {
2551
- const today = React29.useMemo(() => startOfDay(/* @__PURE__ */ new Date()), []);
2552
- const [internalMonth, setInternalMonth] = React29.useState(() => month ?? defaultMonth ?? value ?? today);
2551
+ const today = React28.useMemo(() => startOfDay(/* @__PURE__ */ new Date()), []);
2552
+ const [internalMonth, setInternalMonth] = React28.useState(() => month ?? defaultMonth ?? value ?? today);
2553
2553
  const visible = month ?? internalMonth;
2554
2554
  const setMonth = (next) => {
2555
2555
  onMonthChange?.(next);
2556
2556
  if (month === void 0) setInternalMonth(next);
2557
2557
  };
2558
- const grid = React29.useMemo(() => buildGrid(visible, weekStartsOn), [visible, weekStartsOn]);
2559
- const weekdays = React29.useMemo(() => Array.from({ length: 7 }, (_, i) => WEEKDAYS[(i + weekStartsOn) % 7]), [weekStartsOn]);
2560
- const eventsByDay = React29.useMemo(() => {
2558
+ const grid = React28.useMemo(() => buildGrid(visible, weekStartsOn), [visible, weekStartsOn]);
2559
+ const weekdays = React28.useMemo(() => Array.from({ length: 7 }, (_, i) => WEEKDAYS[(i + weekStartsOn) % 7]), [weekStartsOn]);
2560
+ const eventsByDay = React28.useMemo(() => {
2561
2561
  const map = /* @__PURE__ */ new Map();
2562
2562
  for (const ev of events ?? []) {
2563
2563
  const key = startOfDay(ev.date).toDateString();
@@ -2788,11 +2788,11 @@ function SegmentedControl({
2788
2788
  "aria-label": ariaLabel
2789
2789
  }) {
2790
2790
  const sz = SIZE5[size];
2791
- const groupId = React29.useId();
2792
- const errorId = React29.useId();
2791
+ const groupId = React28.useId();
2792
+ const errorId = React28.useId();
2793
2793
  const hasError = errorMessage != null;
2794
2794
  const isControlled = value !== void 0;
2795
- const [internal, setInternal] = React29.useState(defaultValue);
2795
+ const [internal, setInternal] = React28.useState(defaultValue);
2796
2796
  const current = isControlled ? value : internal;
2797
2797
  const handle = (v) => {
2798
2798
  if (!v) return;
@@ -2947,48 +2947,56 @@ function Scheduler({
2947
2947
  onSelectSlot,
2948
2948
  onSelectEvent,
2949
2949
  onNewEvent,
2950
+ onError,
2950
2951
  className = "",
2951
2952
  style
2952
2953
  }) {
2953
2954
  const reduced = framerMotion.useReducedMotion();
2954
- const [view, setView] = React29.useState(defaultView);
2955
- const [cursor, setCursor] = React29.useState(() => defaultDate ?? /* @__PURE__ */ new Date());
2956
- const [loaded, setLoaded] = React29.useState([]);
2957
- const [loading, setLoading] = React29.useState(false);
2958
- const [dir, setDir] = React29.useState(0);
2959
- const loaderRef = React29.useRef(loadEvents);
2960
- loaderRef.current = loadEvents;
2961
- const range = React29.useMemo(
2955
+ const [view, setView] = React28.useState(defaultView);
2956
+ const [cursor, setCursor] = React28.useState(() => defaultDate ?? /* @__PURE__ */ new Date());
2957
+ const [loaded, setLoaded] = React28.useState([]);
2958
+ const [loading, setLoading] = React28.useState(false);
2959
+ const [error, setError] = React28.useState(null);
2960
+ const [reloadKey, setReloadKey] = React28.useState(0);
2961
+ const [dir, setDir] = React28.useState(0);
2962
+ const cbRef = React28.useRef({ loadEvents, onError });
2963
+ cbRef.current = { loadEvents, onError };
2964
+ const range = React28.useMemo(
2962
2965
  () => view === "month" ? monthRange(cursor) : weekRange(cursor, weekStartsOn),
2963
2966
  [view, cursor, weekStartsOn]
2964
2967
  );
2965
2968
  const fromKey = range.from.getTime();
2966
2969
  const toKey = range.to.getTime();
2967
- React29.useEffect(() => {
2968
- const loader = loaderRef.current;
2970
+ React28.useEffect(() => {
2971
+ const { loadEvents: loader, onError: onErr } = cbRef.current;
2969
2972
  if (!loader) return;
2970
2973
  let cancelled = false;
2971
2974
  setLoading(true);
2975
+ setError(null);
2972
2976
  Promise.resolve(loader({ from: new Date(fromKey), to: new Date(toKey) }, view)).then((evts) => {
2973
2977
  if (!cancelled) setLoaded(evts);
2974
- }).catch(() => {
2975
- if (!cancelled) setLoaded([]);
2978
+ }).catch((err) => {
2979
+ if (!cancelled) {
2980
+ setError(err ?? new Error("Failed to load events"));
2981
+ onErr?.(err);
2982
+ }
2976
2983
  }).finally(() => {
2977
2984
  if (!cancelled) setLoading(false);
2978
2985
  });
2979
2986
  return () => {
2980
2987
  cancelled = true;
2981
2988
  };
2982
- }, [fromKey, toKey, view]);
2983
- const events = React29.useMemo(
2989
+ }, [fromKey, toKey, view, reloadKey]);
2990
+ const retry = React28.useCallback(() => setReloadKey((k) => k + 1), []);
2991
+ const events = React28.useMemo(
2984
2992
  () => (controlledEvents ?? loaded).map(normalize),
2985
2993
  [controlledEvents, loaded]
2986
2994
  );
2987
- const go = React29.useCallback((delta) => {
2995
+ const go = React28.useCallback((delta) => {
2988
2996
  setDir(delta);
2989
2997
  setCursor((c) => view === "month" ? addMonths2(c, delta) : addDays(c, delta * 7));
2990
2998
  }, [view]);
2991
- const goToday = React29.useCallback(() => {
2999
+ const goToday = React28.useCallback(() => {
2992
3000
  setDir(0);
2993
3001
  setCursor(/* @__PURE__ */ new Date());
2994
3002
  }, []);
@@ -3032,7 +3040,7 @@ function Scheduler({
3032
3040
  onNewEvent && /* @__PURE__ */ jsxRuntime.jsx(Button_default, { size: "sm", icon: /* @__PURE__ */ jsxRuntime.jsx(Plus, {}), content: "New event", onClick: onNewEvent })
3033
3041
  ] })
3034
3042
  ] }),
3035
- /* @__PURE__ */ jsxRuntime.jsx("div", { className: "relative flex-1 overflow-hidden", children: /* @__PURE__ */ jsxRuntime.jsx(
3043
+ /* @__PURE__ */ jsxRuntime.jsx("div", { className: "relative flex-1 overflow-hidden", children: error ? /* @__PURE__ */ jsxRuntime.jsx(SchedulerError, { onRetry: retry }) : loadEvents && loading && events.length === 0 ? /* @__PURE__ */ jsxRuntime.jsx(SchedulerSkeleton, { view }) : /* @__PURE__ */ jsxRuntime.jsx(
3036
3044
  framerMotion.motion.div,
3037
3045
  {
3038
3046
  initial: { opacity: 0, x: reduced ? 0 : dir * 24 },
@@ -3067,10 +3075,40 @@ function Scheduler({
3067
3075
  }
3068
3076
  );
3069
3077
  }
3078
+ function SchedulerSkeleton({ view }) {
3079
+ const bar = "rounded bg-background animate-pulse";
3080
+ if (view === "week") {
3081
+ return /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex h-full flex-col p-3", "aria-hidden": "true", children: [
3082
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "mb-3 grid gap-2", style: { gridTemplateColumns: "3.5rem repeat(7, 1fr)" }, children: [
3083
+ /* @__PURE__ */ jsxRuntime.jsx("span", {}),
3084
+ Array.from({ length: 7 }, (_, i) => /* @__PURE__ */ jsxRuntime.jsx("span", { className: `${bar} mx-auto h-8 w-8 rounded-full` }, i))
3085
+ ] }),
3086
+ /* @__PURE__ */ jsxRuntime.jsx("div", { className: "flex flex-1 flex-col gap-3", children: Array.from({ length: 8 }, (_, i) => /* @__PURE__ */ jsxRuntime.jsx("span", { className: `${bar} h-6`, style: { width: `${60 + i * 13 % 35}%` } }, i)) })
3087
+ ] });
3088
+ }
3089
+ return /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex h-full flex-col p-3", "aria-hidden": "true", children: [
3090
+ /* @__PURE__ */ jsxRuntime.jsx("div", { className: "mb-3 grid grid-cols-7 gap-2", children: Array.from({ length: 7 }, (_, i) => /* @__PURE__ */ jsxRuntime.jsx("span", { className: `${bar} h-2.5` }, i)) }),
3091
+ /* @__PURE__ */ jsxRuntime.jsx("div", { className: "grid flex-1 grid-cols-7 grid-rows-5 gap-2", children: Array.from({ length: 35 }, (_, i) => /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex flex-col gap-1.5", children: [
3092
+ /* @__PURE__ */ jsxRuntime.jsx("span", { className: `${bar} h-5 w-5 rounded-full` }),
3093
+ i % 3 === 0 && /* @__PURE__ */ jsxRuntime.jsx("span", { className: `${bar} h-3` }),
3094
+ i % 5 === 0 && /* @__PURE__ */ jsxRuntime.jsx("span", { className: `${bar} h-3`, style: { width: "70%" } })
3095
+ ] }, i)) })
3096
+ ] });
3097
+ }
3098
+ function SchedulerError({ onRetry }) {
3099
+ return /* @__PURE__ */ jsxRuntime.jsxs("div", { role: "alert", className: "flex h-full flex-col items-center justify-center gap-3 p-8 text-center", children: [
3100
+ /* @__PURE__ */ jsxRuntime.jsx("span", { className: "flex h-10 w-10 items-center justify-center rounded-full text-status-error", style: { backgroundColor: "color-mix(in oklab, var(--color-error) 12%, var(--color-surface))" }, children: /* @__PURE__ */ jsxRuntime.jsx("svg", { viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: 2, "aria-hidden": "true", className: "h-5 w-5", children: /* @__PURE__ */ jsxRuntime.jsx("path", { strokeLinecap: "round", strokeLinejoin: "round", d: "M12 9v4m0 4h.01M10.3 3.9 1.8 18a2 2 0 0 0 1.7 3h16.94a2 2 0 0 0 1.7-3L13.7 3.9a2 2 0 0 0-3.4 0z" }) }) }),
3101
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { children: [
3102
+ /* @__PURE__ */ jsxRuntime.jsx("div", { className: "text-sm font-semibold text-foreground", children: "Couldn\u2019t load events" }),
3103
+ /* @__PURE__ */ jsxRuntime.jsx("div", { className: "mt-0.5 text-xs text-foreground-muted", children: "Something went wrong fetching this range." })
3104
+ ] }),
3105
+ /* @__PURE__ */ jsxRuntime.jsx(Button_default, { size: "sm", variant: "secondary", content: "Retry", onClick: onRetry })
3106
+ ] });
3107
+ }
3070
3108
  function MonthYearPicker({ label, cursor, onPick }) {
3071
- const [open, setOpen] = React29.useState(false);
3072
- const [viewYear, setViewYear] = React29.useState(cursor.getFullYear());
3073
- React29.useEffect(() => {
3109
+ const [open, setOpen] = React28.useState(false);
3110
+ const [viewYear, setViewYear] = React28.useState(cursor.getFullYear());
3111
+ React28.useEffect(() => {
3074
3112
  if (open) setViewYear(cursor.getFullYear());
3075
3113
  }, [open, cursor]);
3076
3114
  return /* @__PURE__ */ jsxRuntime.jsxs(Popover__namespace.Root, { open, onOpenChange: setOpen, children: [
@@ -3133,7 +3171,7 @@ function MonthView({
3133
3171
  onSelectSlot,
3134
3172
  onSelectEvent
3135
3173
  }) {
3136
- const grid = React29.useMemo(() => buildMonthGrid(cursor, weekStartsOn), [cursor, weekStartsOn]);
3174
+ const grid = React28.useMemo(() => buildMonthGrid(cursor, weekStartsOn), [cursor, weekStartsOn]);
3137
3175
  const labels = weekdayLabels(weekStartsOn);
3138
3176
  return /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex h-full flex-col", children: [
3139
3177
  /* @__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)) }),
@@ -3207,11 +3245,11 @@ function WeekView({
3207
3245
  onSelectSlot,
3208
3246
  onSelectEvent
3209
3247
  }) {
3210
- const days = React29.useMemo(() => getWeekDays(cursor, weekStartsOn), [cursor, weekStartsOn]);
3211
- const labels = React29.useMemo(() => weekdayLabels(weekStartsOn), [weekStartsOn]);
3248
+ const days = React28.useMemo(() => getWeekDays(cursor, weekStartsOn), [cursor, weekStartsOn]);
3249
+ const labels = React28.useMemo(() => weekdayLabels(weekStartsOn), [weekStartsOn]);
3212
3250
  const dow = (d) => labels[(d.getDay() - weekStartsOn + 7) % 7];
3213
3251
  const [startHour, endHour] = dayHours;
3214
- const hours = React29.useMemo(
3252
+ const hours = React28.useMemo(
3215
3253
  () => Array.from({ length: endHour - startHour }, (_, i) => startHour + i),
3216
3254
  [startHour, endHour]
3217
3255
  );
@@ -3402,17 +3440,17 @@ function Cart({
3402
3440
  ] })
3403
3441
  ] });
3404
3442
  }
3405
- var CartContext = React29.createContext(null);
3443
+ var CartContext = React28.createContext(null);
3406
3444
  var clampQty = (qty, max) => {
3407
3445
  const lower = Math.max(1, Math.round(qty));
3408
3446
  return max != null ? Math.min(lower, max) : lower;
3409
3447
  };
3410
3448
  function CartProvider({ children, initialItems = [], onChange }) {
3411
- const [items, setItems] = React29.useState(initialItems);
3412
- React29.useEffect(() => {
3449
+ const [items, setItems] = React28.useState(initialItems);
3450
+ React28.useEffect(() => {
3413
3451
  onChange?.(items);
3414
3452
  }, [items]);
3415
- const addToCart = React29.useCallback((item, quantity) => {
3453
+ const addToCart = React28.useCallback((item, quantity) => {
3416
3454
  const addQty = quantity ?? item.quantity ?? 1;
3417
3455
  setItems((prev) => {
3418
3456
  const existing = prev.find((it) => it.id === item.id);
@@ -3425,29 +3463,29 @@ function CartProvider({ children, initialItems = [], onChange }) {
3425
3463
  return [...prev, { ...rest, quantity: clampQty(addQty, item.max) }];
3426
3464
  });
3427
3465
  }, []);
3428
- const removeFromCart = React29.useCallback((id) => {
3466
+ const removeFromCart = React28.useCallback((id) => {
3429
3467
  setItems((prev) => prev.filter((it) => it.id !== id));
3430
3468
  }, []);
3431
- const updateQuantity = React29.useCallback((id, quantity) => {
3469
+ const updateQuantity = React28.useCallback((id, quantity) => {
3432
3470
  setItems(
3433
3471
  (prev) => prev.map((it) => it.id === id ? { ...it, quantity: clampQty(quantity, it.max) } : it)
3434
3472
  );
3435
3473
  }, []);
3436
- const clearCart = React29.useCallback(() => setItems([]), []);
3437
- const isInCart = React29.useCallback((id) => items.some((it) => it.id === id), [items]);
3438
- const getItemCount = React29.useCallback(() => items.reduce((sum, it) => sum + it.quantity, 0), [items]);
3439
- const getCartTotal = React29.useCallback(
3474
+ const clearCart = React28.useCallback(() => setItems([]), []);
3475
+ const isInCart = React28.useCallback((id) => items.some((it) => it.id === id), [items]);
3476
+ const getItemCount = React28.useCallback(() => items.reduce((sum, it) => sum + it.quantity, 0), [items]);
3477
+ const getCartTotal = React28.useCallback(
3440
3478
  () => items.reduce((sum, it) => sum + it.price * it.quantity, 0),
3441
3479
  [items]
3442
3480
  );
3443
- const value = React29.useMemo(
3481
+ const value = React28.useMemo(
3444
3482
  () => ({ items, addToCart, removeFromCart, updateQuantity, clearCart, isInCart, getItemCount, getCartTotal }),
3445
3483
  [items, addToCart, removeFromCart, updateQuantity, clearCart, isInCart, getItemCount, getCartTotal]
3446
3484
  );
3447
3485
  return /* @__PURE__ */ jsxRuntime.jsx(CartContext.Provider, { value, children });
3448
3486
  }
3449
3487
  function useCart() {
3450
- const ctx = React29.useContext(CartContext);
3488
+ const ctx = React28.useContext(CartContext);
3451
3489
  if (!ctx) {
3452
3490
  throw new Error("useCart must be used within a <CartProvider>.");
3453
3491
  }
@@ -3781,11 +3819,11 @@ function buildBindings(store, name, kind, snap) {
3781
3819
 
3782
3820
  // src/form/useForm.ts
3783
3821
  function useForm(options = {}) {
3784
- const ref = React29.useRef(null);
3822
+ const ref = React28.useRef(null);
3785
3823
  if (ref.current === null) ref.current = new FormStore(options);
3786
3824
  const store = ref.current;
3787
- React29.useSyncExternalStore(store.subscribe, store.getRootSnapshot, store.getRootSnapshot);
3788
- const make = React29.useCallback(
3825
+ React28.useSyncExternalStore(store.subscribe, store.getRootSnapshot, store.getRootSnapshot);
3826
+ const make = React28.useCallback(
3789
3827
  (kind) => (name, rules) => {
3790
3828
  if (rules !== void 0) store.setRule(name, rules);
3791
3829
  return buildBindings(store, name, kind, store.getFieldSnapshot(name));
@@ -3814,9 +3852,9 @@ function useForm(options = {}) {
3814
3852
  fieldTarget: make("target")
3815
3853
  };
3816
3854
  }
3817
- var FormContext = React29.createContext(null);
3855
+ var FormContext = React28.createContext(null);
3818
3856
  function useFormStore() {
3819
- const store = React29.useContext(FormContext);
3857
+ const store = React28.useContext(FormContext);
3820
3858
  if (!store) {
3821
3859
  throw new Error("useFormStore must be used within a <Form>. Did you forget to wrap your fields?");
3822
3860
  }
@@ -3830,8 +3868,8 @@ function Form({
3830
3868
  children,
3831
3869
  ...rest
3832
3870
  }) {
3833
- const ref = React29.useRef(null);
3834
- const bypass = React29.useRef(false);
3871
+ const ref = React28.useRef(null);
3872
+ const bypass = React28.useRef(false);
3835
3873
  const handleSubmit = async (e) => {
3836
3874
  if (bypass.current) {
3837
3875
  bypass.current = false;
@@ -3883,12 +3921,12 @@ function useFormField(name, options = {}) {
3883
3921
  const store = useFormStore();
3884
3922
  const { kind = "value", rules } = options;
3885
3923
  if (rules !== void 0 && store.getRule(name) !== rules) store.setRule(name, rules);
3886
- React29.useEffect(() => {
3924
+ React28.useEffect(() => {
3887
3925
  return () => {
3888
3926
  if (rules !== void 0) store.removeRule(name);
3889
3927
  };
3890
3928
  }, [store, name]);
3891
- const snap = React29.useSyncExternalStore(
3929
+ const snap = React28.useSyncExternalStore(
3892
3930
  store.subscribe,
3893
3931
  () => store.getFieldSnapshot(name)
3894
3932
  );
@@ -3900,7 +3938,7 @@ function FormField({ name, kind, rules, children }) {
3900
3938
  }
3901
3939
  function useFieldArray(name) {
3902
3940
  const store = useFormStore();
3903
- React29.useSyncExternalStore(store.subscribe, store.getRootSnapshot, store.getRootSnapshot);
3941
+ React28.useSyncExternalStore(store.subscribe, store.getRootSnapshot, store.getRootSnapshot);
3904
3942
  const arr = store.getValue(name) ?? [];
3905
3943
  const keys = store.getKeys(name);
3906
3944
  return {
@@ -3933,7 +3971,7 @@ function TextInput({
3933
3971
  suffix,
3934
3972
  id
3935
3973
  }) {
3936
- const errorId = React29.useId();
3974
+ const errorId = React28.useId();
3937
3975
  const hasError = errorMessage != null;
3938
3976
  const hasAdornment = prefix != null || suffix != null;
3939
3977
  const inputId = htmlFor ?? id;
@@ -4094,7 +4132,7 @@ function CreditCardForm({
4094
4132
  className = "",
4095
4133
  style
4096
4134
  }) {
4097
- const initial = React29.useRef({
4135
+ const initial = React28.useRef({
4098
4136
  number: formatCardNumber(defaultValue?.number ?? ""),
4099
4137
  name: defaultValue?.name ?? "",
4100
4138
  expiry: formatExpiry(defaultValue?.expiry ?? ""),
@@ -4103,7 +4141,7 @@ function CreditCardForm({
4103
4141
  const form = useForm({ initialValues: initial });
4104
4142
  const numberStr = String(form.values.number ?? "");
4105
4143
  const brand = detectBrand(numberStr);
4106
- React29.useEffect(() => {
4144
+ React28.useEffect(() => {
4107
4145
  onChange?.(toCard(form.values));
4108
4146
  }, [form.values.number, form.values.name, form.values.expiry, form.values.cvv]);
4109
4147
  const numberBind = form.fieldNative("number", {
@@ -4226,7 +4264,7 @@ function Checkout({
4226
4264
  ] })
4227
4265
  ] });
4228
4266
  }
4229
- var NotificationContext = React29.createContext({
4267
+ var NotificationContext = React28.createContext({
4230
4268
  open: () => void 0,
4231
4269
  close: () => void 0
4232
4270
  });
@@ -4284,26 +4322,26 @@ function NotificationItem({
4284
4322
  onClose,
4285
4323
  reduced
4286
4324
  }) {
4287
- const [paused, setPaused] = React29.useState(false);
4325
+ const [paused, setPaused] = React28.useState(false);
4288
4326
  const duration = n.duration ?? 4e3;
4289
4327
  const isAutoDismissing = isFinite(duration) && duration > 0;
4290
4328
  const showProgress = !reduced && isAutoDismissing;
4291
- const timerRef = React29.useRef(null);
4292
- const startTimeRef = React29.useRef(0);
4293
- const remainingRef = React29.useRef(duration);
4294
- const clearTimer = React29.useCallback(() => {
4329
+ const timerRef = React28.useRef(null);
4330
+ const startTimeRef = React28.useRef(0);
4331
+ const remainingRef = React28.useRef(duration);
4332
+ const clearTimer = React28.useCallback(() => {
4295
4333
  if (timerRef.current !== null) {
4296
4334
  clearTimeout(timerRef.current);
4297
4335
  timerRef.current = null;
4298
4336
  }
4299
4337
  }, []);
4300
- const scheduleDismiss = React29.useCallback((ms) => {
4338
+ const scheduleDismiss = React28.useCallback((ms) => {
4301
4339
  clearTimer();
4302
4340
  if (!isAutoDismissing) return;
4303
4341
  startTimeRef.current = Date.now();
4304
4342
  timerRef.current = setTimeout(() => onClose(n.id), ms);
4305
4343
  }, [clearTimer, isAutoDismissing, n.id, onClose]);
4306
- React29.useEffect(() => {
4344
+ React28.useEffect(() => {
4307
4345
  if (paused || !isAutoDismissing) return;
4308
4346
  scheduleDismiss(remainingRef.current);
4309
4347
  return clearTimer;
@@ -4386,15 +4424,15 @@ function NotificationProvider({
4386
4424
  children,
4387
4425
  position = "top-right"
4388
4426
  }) {
4389
- const [notifications, setNotifications] = React29.useState([]);
4427
+ const [notifications, setNotifications] = React28.useState([]);
4390
4428
  const reduced = framerMotion.useReducedMotion();
4391
- const open = React29.useCallback((payload) => {
4429
+ const open = React28.useCallback((payload) => {
4392
4430
  setNotifications((prev) => [
4393
4431
  ...prev,
4394
4432
  { duration: 4e3, ...payload, id: Date.now() + Math.random() }
4395
4433
  ]);
4396
4434
  }, []);
4397
- const close = React29.useCallback((id) => {
4435
+ const close = React28.useCallback((id) => {
4398
4436
  setNotifications((prev) => prev.filter((n) => n.id !== id));
4399
4437
  }, []);
4400
4438
  return /* @__PURE__ */ jsxRuntime.jsxs(NotificationContext.Provider, { value: { open, close }, children: [
@@ -4423,7 +4461,7 @@ function NotificationProvider({
4423
4461
  ] });
4424
4462
  }
4425
4463
  function useNotification() {
4426
- const { open } = React29.useContext(NotificationContext);
4464
+ const { open } = React28.useContext(NotificationContext);
4427
4465
  return {
4428
4466
  info: (props) => open({ type: "info", ...props }),
4429
4467
  success: (props) => open({ type: "success", ...props }),
@@ -4540,10 +4578,10 @@ function FadingBase({
4540
4578
  isMounted = false,
4541
4579
  children
4542
4580
  }) {
4543
- const [shouldRender, setShouldRender] = React29.useState(isMounted);
4544
- const [visible, setVisible] = React29.useState(false);
4545
- const timerRef = React29.useRef(null);
4546
- React29.useEffect(() => {
4581
+ const [shouldRender, setShouldRender] = React28.useState(isMounted);
4582
+ const [visible, setVisible] = React28.useState(false);
4583
+ const timerRef = React28.useRef(null);
4584
+ React28.useEffect(() => {
4547
4585
  if (isMounted) {
4548
4586
  setShouldRender(true);
4549
4587
  const rafId = requestAnimationFrame(() => setVisible(true));
@@ -4641,8 +4679,8 @@ function ScalableContainer({
4641
4679
  togglePosition = "top-right",
4642
4680
  className = ""
4643
4681
  }) {
4644
- const containerRef = React29.useRef(null);
4645
- const [internalScaled, setInternalScaled] = React29.useState(false);
4682
+ const containerRef = React28.useRef(null);
4683
+ const [internalScaled, setInternalScaled] = React28.useState(false);
4646
4684
  const isScaled = expanded ?? internalScaled;
4647
4685
  const reduced = framerMotion.useReducedMotion();
4648
4686
  const onToggle = () => {
@@ -4780,17 +4818,17 @@ function CatalogGrid({ items, buttonText, onOpen, className = "" }) {
4780
4818
  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)) });
4781
4819
  }
4782
4820
  function CatalogCarousel({ items, buttonText, onOpen, className = "" }) {
4783
- const [activeIndex, setActiveIndex] = React29.useState(0);
4784
- const [indexPool, setIndexPool] = React29.useState([]);
4785
- const cardRefs = React29.useRef([]);
4786
- const getIndexes = React29.useMemo(() => {
4821
+ const [activeIndex, setActiveIndex] = React28.useState(0);
4822
+ const [indexPool, setIndexPool] = React28.useState([]);
4823
+ const cardRefs = React28.useRef([]);
4824
+ const getIndexes = React28.useMemo(() => {
4787
4825
  let nextIndex = activeIndex + 1;
4788
4826
  let previousIndex = activeIndex - 1;
4789
4827
  if (activeIndex === 0) previousIndex = items.length - 1;
4790
4828
  if (activeIndex === items.length - 1) nextIndex = 0;
4791
4829
  return { previousIndex, nextIndex };
4792
4830
  }, [activeIndex, items.length]);
4793
- React29.useEffect(() => {
4831
+ React28.useEffect(() => {
4794
4832
  const { nextIndex, previousIndex } = getIndexes;
4795
4833
  let indexes = [previousIndex, activeIndex, nextIndex];
4796
4834
  if (activeIndex !== 0 && activeIndex !== items.length - 1) {
@@ -4963,8 +5001,8 @@ function writeDismissed(key) {
4963
5001
  }
4964
5002
  }
4965
5003
  function useTargetBbox(ref) {
4966
- const [bbox, setBbox] = React29.useState(null);
4967
- React29.useLayoutEffect(() => {
5004
+ const [bbox, setBbox] = React28.useState(null);
5005
+ React28.useLayoutEffect(() => {
4968
5006
  const el = ref?.current;
4969
5007
  if (!el) {
4970
5008
  setBbox(null);
@@ -4994,7 +5032,7 @@ function tooltipStyleFor(bbox, placement) {
4994
5032
  return { left: bbox.left + bbox.width / 2, top: bbox.top - TOOLTIP_GAP, transform: "translate(-50%, -100%)", width: TOOLTIP_WIDTH };
4995
5033
  }
4996
5034
  function useFocusTrap(containerRef, active) {
4997
- React29.useEffect(() => {
5035
+ React28.useEffect(() => {
4998
5036
  if (!active) return;
4999
5037
  const el = containerRef.current;
5000
5038
  if (!el) return;
@@ -5033,16 +5071,16 @@ function Wizard({
5033
5071
  onComplete,
5034
5072
  onSkip
5035
5073
  }) {
5036
- const tooltipRef = React29.useRef(null);
5037
- const tooltipTitleId = React29.useId();
5038
- const tooltipBodyId = React29.useId();
5074
+ const tooltipRef = React28.useRef(null);
5075
+ const tooltipTitleId = React28.useId();
5076
+ const tooltipBodyId = React28.useId();
5039
5077
  const reduced = framerMotion.useReducedMotion();
5040
- const [open, setOpen] = React29.useState(() => steps.length > 0 && !readDismissed(storageKey));
5041
- const [activeIndex, setActiveIndex] = React29.useState(0);
5078
+ const [open, setOpen] = React28.useState(() => steps.length > 0 && !readDismissed(storageKey));
5079
+ const [activeIndex, setActiveIndex] = React28.useState(0);
5042
5080
  const step = steps[activeIndex];
5043
5081
  const bbox = useTargetBbox(step?.stepRef);
5044
5082
  useFocusTrap(tooltipRef, open);
5045
- React29.useEffect(() => {
5083
+ React28.useEffect(() => {
5046
5084
  if (!open || !dismissible) return;
5047
5085
  const onKey = (e) => {
5048
5086
  if (e.key === "Escape") {
@@ -5053,12 +5091,12 @@ function Wizard({
5053
5091
  document.addEventListener("keydown", onKey);
5054
5092
  return () => document.removeEventListener("keydown", onKey);
5055
5093
  }, [open, dismissible]);
5056
- const handleSkip = React29.useCallback(() => {
5094
+ const handleSkip = React28.useCallback(() => {
5057
5095
  writeDismissed(storageKey);
5058
5096
  setOpen(false);
5059
5097
  onSkip?.();
5060
5098
  }, [storageKey, onSkip]);
5061
- const handleComplete = React29.useCallback(() => {
5099
+ const handleComplete = React28.useCallback(() => {
5062
5100
  writeDismissed(storageKey);
5063
5101
  setOpen(false);
5064
5102
  onComplete?.();
@@ -5201,7 +5239,7 @@ function Wizard({
5201
5239
  ] });
5202
5240
  }
5203
5241
  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" }) });
5204
- var SearchInput = React29__default.default.forwardRef(function SearchInput2({ value, onChange, disabled, label, htmlFor, placeholder, name, inputStyle, style, layout = "vertical", size = "md", icon, helperText, className }, ref) {
5242
+ var SearchInput = React28__default.default.forwardRef(function SearchInput2({ value, onChange, disabled, label, htmlFor, placeholder, name, inputStyle, style, layout = "vertical", size = "md", icon, helperText, className }, ref) {
5205
5243
  return /* @__PURE__ */ jsxRuntime.jsx(Field, { className, label, htmlFor, layout, helperText, children: /* @__PURE__ */ jsxRuntime.jsxs(
5206
5244
  "div",
5207
5245
  {
@@ -5230,438 +5268,136 @@ var SearchInput = React29__default.default.forwardRef(function SearchInput2({ va
5230
5268
  ) });
5231
5269
  });
5232
5270
  var SearchInput_default = SearchInput;
5233
- function Tag({ children, onRemove, removeLabel, disabled }) {
5234
- return /* @__PURE__ */ jsxRuntime.jsxs("span", { className: "inline-flex items-center gap-1 rounded-md border border-border bg-surface-raised text-foreground text-xs pl-2 pr-1 py-0.5 max-w-full", children: [
5235
- /* @__PURE__ */ jsxRuntime.jsx("span", { className: "truncate", children }),
5236
- onRemove && /* @__PURE__ */ jsxRuntime.jsx(
5237
- "button",
5238
- {
5239
- type: "button",
5240
- disabled,
5241
- onClick: (e) => {
5242
- e.stopPropagation();
5243
- onRemove();
5244
- },
5245
- "aria-label": removeLabel ?? "Remove",
5246
- className: "inline-flex items-center justify-center w-4 h-4 flex-shrink-0 rounded text-foreground-muted hover:text-status-error hover:bg-surface transition-colors focus:outline-none focus-visible:ring-1 focus-visible:ring-accent disabled:cursor-not-allowed",
5247
- children: /* @__PURE__ */ jsxRuntime.jsx("svg", { width: "10", height: "10", viewBox: "0 0 20 20", fill: "none", "aria-hidden": "true", children: /* @__PURE__ */ jsxRuntime.jsx("path", { d: "M15 5L5 15M5 5l10 10", stroke: "currentColor", strokeWidth: "2", strokeLinecap: "round" }) })
5271
+ var SHIMMER = "oxy-skeleton rounded-sm bg-surface-raised";
5272
+ function SkeletonBox({ width, height = 16, radius, className = "", style }) {
5273
+ return /* @__PURE__ */ jsxRuntime.jsx(
5274
+ "span",
5275
+ {
5276
+ role: "presentation",
5277
+ "aria-hidden": "true",
5278
+ className: `block ${SHIMMER} ${className}`,
5279
+ style: {
5280
+ width: width ?? "100%",
5281
+ height,
5282
+ borderRadius: radius ?? "var(--radius-md)",
5283
+ ...style
5248
5284
  }
5249
- )
5250
- ] });
5285
+ }
5286
+ );
5251
5287
  }
5252
- function MultiTagRow({
5253
- values,
5254
- disabled,
5255
- labelFor,
5256
- onRemove
5288
+ function SkeletonText({
5289
+ lines = 3,
5290
+ lastLineWidth = 60,
5291
+ lineHeight = 14,
5292
+ gap = 8,
5293
+ className = "",
5294
+ style
5257
5295
  }) {
5258
- const wrapRef = React29.useRef(null);
5259
- const measureRef = React29.useRef(null);
5260
- const [visibleCount, setVisibleCount] = React29.useState(values.length);
5261
- const key = values.map(String).join("|");
5262
- React29.useLayoutEffect(() => {
5263
- const wrap = wrapRef.current;
5264
- const measure = measureRef.current;
5265
- if (!wrap || !measure) return;
5266
- const GAP = 6;
5267
- const recompute = () => {
5268
- const avail = wrap.clientWidth;
5269
- const tagEls = Array.from(measure.querySelectorAll("[data-mt]"));
5270
- const moreEl = measure.querySelector("[data-mm]");
5271
- const widths = tagEls.map((e) => e.offsetWidth);
5272
- const moreW = moreEl ? moreEl.offsetWidth : 0;
5273
- if (widths.length === 0) {
5274
- setVisibleCount(0);
5275
- return;
5276
- }
5277
- let used = 0;
5278
- let count = 0;
5279
- for (let i = 0; i < widths.length; i++) {
5280
- const w = widths[i] + (i > 0 ? GAP : 0);
5281
- if (used + w <= avail) {
5282
- used += w;
5283
- count++;
5284
- } else break;
5285
- }
5286
- if (count < widths.length) {
5287
- while (count > 0) {
5288
- let t = 0;
5289
- for (let i = 0; i < count; i++) t += widths[i] + (i > 0 ? GAP : 0);
5290
- t += GAP + moreW;
5291
- if (t <= avail) break;
5292
- count--;
5293
- }
5294
- }
5295
- setVisibleCount(count);
5296
- };
5297
- recompute();
5298
- const ro = new ResizeObserver(recompute);
5299
- ro.observe(wrap);
5300
- return () => ro.disconnect();
5301
- }, [key]);
5302
- const hidden = values.length - visibleCount;
5303
- const moreChip = (n) => /* @__PURE__ */ jsxRuntime.jsxs("span", { className: "inline-flex items-center flex-shrink-0 rounded-md border border-border bg-surface-raised text-foreground-secondary text-xs px-2 py-0.5", children: [
5304
- "+",
5305
- n,
5306
- " more"
5307
- ] });
5308
- return /* @__PURE__ */ jsxRuntime.jsxs("div", { ref: wrapRef, className: "relative flex-1 min-w-0 flex flex-nowrap items-center gap-1.5 overflow-hidden", children: [
5309
- /* @__PURE__ */ jsxRuntime.jsxs(
5310
- "div",
5311
- {
5312
- ref: measureRef,
5313
- "aria-hidden": "true",
5314
- className: "absolute invisible pointer-events-none flex flex-nowrap items-center gap-1.5",
5315
- style: { left: -9999, top: -9999 },
5316
- children: [
5317
- values.map((val) => /* @__PURE__ */ jsxRuntime.jsx("span", { "data-mt": true, children: /* @__PURE__ */ jsxRuntime.jsx(Tag, { removeLabel: "x", onRemove: () => {
5318
- }, children: labelFor(val) }) }, `m-${val}`)),
5319
- /* @__PURE__ */ jsxRuntime.jsx("span", { "data-mm": true, children: moreChip(values.length) })
5320
- ]
5296
+ return /* @__PURE__ */ jsxRuntime.jsx(
5297
+ "div",
5298
+ {
5299
+ role: "presentation",
5300
+ "aria-hidden": "true",
5301
+ className: `flex flex-col ${className}`,
5302
+ style: { gap, ...style },
5303
+ children: Array.from({ length: lines }).map((_, i) => {
5304
+ const isLast = i === lines - 1;
5305
+ const width = isLast && lines > 1 ? `${lastLineWidth}%` : "100%";
5306
+ return /* @__PURE__ */ jsxRuntime.jsx(
5307
+ "span",
5308
+ {
5309
+ className: `block ${SHIMMER}`,
5310
+ style: { height: lineHeight, width, borderRadius: "var(--radius-sm)" }
5311
+ },
5312
+ i
5313
+ );
5314
+ })
5315
+ }
5316
+ );
5317
+ }
5318
+ function SkeletonCircle({ size = 40, className = "", style }) {
5319
+ return /* @__PURE__ */ jsxRuntime.jsx(
5320
+ "span",
5321
+ {
5322
+ role: "presentation",
5323
+ "aria-hidden": "true",
5324
+ className: `block flex-shrink-0 ${SHIMMER} ${className}`,
5325
+ style: {
5326
+ width: size,
5327
+ height: size,
5328
+ borderRadius: "50%",
5329
+ ...style
5321
5330
  }
5322
- ),
5323
- values.slice(0, visibleCount).map((val) => /* @__PURE__ */ jsxRuntime.jsx(
5324
- Tag,
5331
+ }
5332
+ );
5333
+ }
5334
+ function SkeletonCard({ hasAvatar = true, lines = 3, className = "", style }) {
5335
+ return /* @__PURE__ */ jsxRuntime.jsxs(
5336
+ "div",
5337
+ {
5338
+ role: "presentation",
5339
+ "aria-hidden": "true",
5340
+ className: `rounded-lg border border-border bg-surface p-4 ${className}`,
5341
+ style,
5342
+ children: [
5343
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex items-center gap-3 mb-4", children: [
5344
+ hasAvatar && /* @__PURE__ */ jsxRuntime.jsx(SkeletonCircle, { size: 36 }),
5345
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex-1 flex flex-col gap-2", children: [
5346
+ /* @__PURE__ */ jsxRuntime.jsx(SkeletonBox, { height: 12, width: "55%" }),
5347
+ /* @__PURE__ */ jsxRuntime.jsx(SkeletonBox, { height: 10, width: "35%" })
5348
+ ] })
5349
+ ] }),
5350
+ /* @__PURE__ */ jsxRuntime.jsx(SkeletonText, { lines, lastLineWidth: 55 }),
5351
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "mt-4 flex gap-2", children: [
5352
+ /* @__PURE__ */ jsxRuntime.jsx(SkeletonBox, { height: 28, width: 72 }),
5353
+ /* @__PURE__ */ jsxRuntime.jsx(SkeletonBox, { height: 28, width: 56 })
5354
+ ] })
5355
+ ]
5356
+ }
5357
+ );
5358
+ }
5359
+ var DEFAULT_PICKER = [
5360
+ { key: 1, value: 5, label: 5 },
5361
+ { key: 2, value: 10, label: 10 },
5362
+ { key: 3, value: 15, label: 15 },
5363
+ { key: 4, value: 20, label: 20 }
5364
+ ];
5365
+ var DEFAULT_PAGINATION = {
5366
+ enabled: true,
5367
+ perPage: 15,
5368
+ withPicker: true,
5369
+ pickerOptions: DEFAULT_PICKER
5370
+ };
5371
+ var DEFAULT_EXPAND = {
5372
+ enabled: false
5373
+ };
5374
+ function createDatasets(rows, perPage) {
5375
+ if (!perPage) return [rows.slice()];
5376
+ const all = [];
5377
+ for (let i = 0; i < rows.length; i += perPage) {
5378
+ all.push(rows.slice(i, i + perPage));
5379
+ }
5380
+ return all;
5381
+ }
5382
+ var defaultGetRowKey = (_row, index) => index;
5383
+ var cellAlign = (align) => align === "left" ? "text-left" : align === "right" ? "text-right" : "text-center";
5384
+ function TableHeader({
5385
+ columns,
5386
+ hasExpand
5387
+ }) {
5388
+ return /* @__PURE__ */ jsxRuntime.jsx("thead", { className: "bg-surface-raised border-b border-border", children: /* @__PURE__ */ jsxRuntime.jsxs("tr", { children: [
5389
+ hasExpand && /* @__PURE__ */ jsxRuntime.jsx("th", { "aria-hidden": "true", className: "w-9" }),
5390
+ columns.map((col) => /* @__PURE__ */ jsxRuntime.jsx(
5391
+ "th",
5325
5392
  {
5326
- disabled,
5327
- removeLabel: `Remove ${labelFor(val)}`,
5328
- onRemove: () => onRemove(val),
5329
- children: labelFor(val)
5393
+ scope: "col",
5394
+ className: `${cellAlign(col.align)} text-sm font-semibold text-foreground py-3 px-3`,
5395
+ style: col.width != null ? { width: col.width } : void 0,
5396
+ children: col.label
5330
5397
  },
5331
- String(val)
5332
- )),
5333
- hidden > 0 && moreChip(hidden)
5334
- ] });
5335
- }
5336
- function Dropdown({
5337
- isMultiselect = false,
5338
- hasSearch = true,
5339
- label,
5340
- name,
5341
- value,
5342
- onChange,
5343
- disabled,
5344
- layout = "horizontal",
5345
- helperText,
5346
- required,
5347
- errorMessage,
5348
- style = {},
5349
- htmlFor,
5350
- items = [],
5351
- labelStyle = {},
5352
- placeholder,
5353
- size = "md",
5354
- className = ""
5355
- }) {
5356
- const [open, setOpen] = React29.useState(false);
5357
- const [selectedItems, setSelectedItems] = React29.useState([]);
5358
- const [searchTerm, setSearchTerm] = React29.useState("");
5359
- const [innerItems, setInnerItems] = React29.useState([]);
5360
- const errorId = React29.useId();
5361
- const hasError = errorMessage != null;
5362
- React29.useEffect(() => {
5363
- setInnerItems(items);
5364
- }, [items]);
5365
- React29.useEffect(() => {
5366
- if (isMultiselect && Array.isArray(value)) {
5367
- setSelectedItems(value);
5368
- }
5369
- }, [isMultiselect, value]);
5370
- const selectItem = (key) => {
5371
- if (isMultiselect) {
5372
- const next = selectedItems.includes(key) ? selectedItems.filter((it) => it !== key) : [...selectedItems, key];
5373
- setSelectedItems(next);
5374
- onChange?.({ target: { value: next, id: htmlFor, name } });
5375
- } else {
5376
- setSelectedItems([key]);
5377
- onChange?.({ target: { value: key, id: htmlFor, name } });
5378
- setOpen(false);
5379
- }
5380
- };
5381
- const removeSelected = (key) => {
5382
- if (isMultiselect) {
5383
- const next = selectedItems.filter((it) => it !== key);
5384
- setSelectedItems(next);
5385
- onChange?.({ target: { value: next, id: htmlFor, name } });
5386
- } else {
5387
- setSelectedItems([]);
5388
- onChange?.({ target: { value: "", id: htmlFor, name } });
5389
- }
5390
- };
5391
- const labelFor = (key) => innerItems.find((it) => it.key === key)?.label ?? String(key);
5392
- const onSearchChange = (e) => {
5393
- const term = e.target.value;
5394
- setSearchTerm(term);
5395
- setInnerItems(
5396
- term.trim() === "" ? items : items.filter(
5397
- (it) => String(it.label).toLowerCase().includes(term.toLowerCase())
5398
- )
5399
- );
5400
- };
5401
- const isSelected = (key) => Array.isArray(value) ? value.includes(key) : value === key;
5402
- return /* @__PURE__ */ jsxRuntime.jsxs("div", { className: className || void 0, children: [
5403
- /* @__PURE__ */ jsxRuntime.jsxs(
5404
- "div",
5405
- {
5406
- className: `flex ${layout === "vertical" ? "flex-col gap-1.5" : "flex-row items-start gap-3"}`,
5407
- children: [
5408
- /* @__PURE__ */ jsxRuntime.jsx(
5409
- FieldLabel,
5410
- {
5411
- label,
5412
- htmlFor,
5413
- required,
5414
- helperText,
5415
- horizontal: layout === "horizontal",
5416
- style: labelStyle
5417
- }
5418
- ),
5419
- /* @__PURE__ */ jsxRuntime.jsxs(Popover__namespace.Root, { open: open && !disabled, onOpenChange: (o) => !disabled && setOpen(o), children: [
5420
- /* @__PURE__ */ jsxRuntime.jsx(Popover__namespace.Trigger, { asChild: true, children: /* @__PURE__ */ jsxRuntime.jsxs(
5421
- "div",
5422
- {
5423
- id: htmlFor,
5424
- role: "combobox",
5425
- "aria-expanded": open,
5426
- "aria-haspopup": "listbox",
5427
- "aria-invalid": hasError || void 0,
5428
- "aria-describedby": hasError ? errorId : void 0,
5429
- style: { width: 240, ...style },
5430
- className: `flex items-center justify-between gap-2 cursor-pointer select-none min-h-[36px] px-3 py-1.5 ${fieldShell({ size, hasError, disabled, sized: false })}`,
5431
- tabIndex: disabled ? -1 : 0,
5432
- onKeyDown: (e) => {
5433
- if (disabled) return;
5434
- if (e.key === "Enter" || e.key === " " || e.key === "ArrowDown" || e.key === "ArrowUp") {
5435
- e.preventDefault();
5436
- setOpen(true);
5437
- }
5438
- },
5439
- children: [
5440
- !value || Array.isArray(value) && value.length === 0 ? /* @__PURE__ */ jsxRuntime.jsx("span", { className: "flex-1 min-w-0 truncate text-foreground-muted text-sm", children: placeholder }) : Array.isArray(value) ? /* @__PURE__ */ jsxRuntime.jsx(
5441
- MultiTagRow,
5442
- {
5443
- values: value,
5444
- disabled,
5445
- labelFor,
5446
- onRemove: removeSelected
5447
- }
5448
- ) : /* @__PURE__ */ jsxRuntime.jsx("div", { className: "flex-1 min-w-0 flex items-center overflow-hidden", children: /* @__PURE__ */ jsxRuntime.jsx(
5449
- Tag,
5450
- {
5451
- disabled,
5452
- removeLabel: `Remove ${labelFor(value)}`,
5453
- onRemove: () => removeSelected(value),
5454
- children: labelFor(value)
5455
- }
5456
- ) }),
5457
- /* @__PURE__ */ jsxRuntime.jsx("div", { className: `flex-shrink-0 text-foreground-muted transition-transform duration-200 ${open ? "rotate-180" : "rotate-0"}`, "aria-hidden": "true", children: /* @__PURE__ */ jsxRuntime.jsx("svg", { viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: 2, className: "h-4 w-4", children: /* @__PURE__ */ jsxRuntime.jsx("path", { strokeLinecap: "round", strokeLinejoin: "round", d: "M19 9l-7 7-7-7" }) }) })
5458
- ]
5459
- }
5460
- ) }),
5461
- /* @__PURE__ */ jsxRuntime.jsx(Popover__namespace.Portal, { children: /* @__PURE__ */ jsxRuntime.jsxs(
5462
- Popover__namespace.Content,
5463
- {
5464
- align: "start",
5465
- sideOffset: 4,
5466
- style: { width: style?.width || 240 },
5467
- className: "bg-surface text-foreground border border-border rounded-lg shadow-md z-50 p-2 animate-in fade-in-0 zoom-in-95 data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=closed]:zoom-out-95",
5468
- onInteractOutside: () => setOpen(false),
5469
- children: [
5470
- hasSearch && /* @__PURE__ */ jsxRuntime.jsx("div", { className: "mb-2", children: /* @__PURE__ */ jsxRuntime.jsx(
5471
- SearchInput_default,
5472
- {
5473
- style: { width: "100%" },
5474
- inputStyle: { width: "100%" },
5475
- value: searchTerm,
5476
- onChange: onSearchChange,
5477
- placeholder: "Search..."
5478
- }
5479
- ) }),
5480
- /* @__PURE__ */ jsxRuntime.jsx("div", { role: "listbox", "aria-multiselectable": isMultiselect, className: "max-h-40 overflow-y-auto", children: innerItems.map((item) => (
5481
- // aria-rowindex was previously set here but
5482
- // it's invalid ARIA on role="option" (it
5483
- // belongs on rows of a grid/treegrid). Dropped.
5484
- // tabIndex={0} + Enter/Space handler makes the
5485
- // option keyboard-activatable; the full
5486
- // combobox roving-tabindex pattern is deferred
5487
- // until the planned Phase-5 rewrite.
5488
- /* @__PURE__ */ jsxRuntime.jsxs(
5489
- "div",
5490
- {
5491
- role: "option",
5492
- "aria-selected": isSelected(item.key),
5493
- tabIndex: 0,
5494
- className: `flex items-center justify-between p-2 hover:bg-accent hover:text-accent-fg transition-colors duration-150 text-sm rounded-lg cursor-pointer focus:outline-none focus-visible:ring-2 focus-visible:ring-accent ${selectedItems.includes(item.key) ? "bg-surface-raised text-foreground" : "text-foreground"}`,
5495
- onClick: () => selectItem(item.key),
5496
- onKeyDown: (e) => {
5497
- if (e.key === "Enter" || e.key === " ") {
5498
- e.preventDefault();
5499
- selectItem(item.key);
5500
- }
5501
- },
5502
- children: [
5503
- /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex items-center gap-2 text-xs", children: [
5504
- item.icon && /* @__PURE__ */ jsxRuntime.jsx("div", { children: item.icon }),
5505
- item.label
5506
- ] }),
5507
- isSelected(item.key) && // currentColor — checkmark follows
5508
- // the item's text colour, which
5509
- // flips automatically on hover.
5510
- /* @__PURE__ */ jsxRuntime.jsx("svg", { width: "16", height: "16", viewBox: "0 0 20 20", fill: "none", "aria-hidden": "true", children: /* @__PURE__ */ jsxRuntime.jsx(
5511
- "path",
5512
- {
5513
- d: "M4 10l4.5 4.5L16 6",
5514
- stroke: "currentColor",
5515
- strokeWidth: "2",
5516
- strokeLinecap: "round",
5517
- strokeLinejoin: "round"
5518
- }
5519
- ) })
5520
- ]
5521
- },
5522
- item.key
5523
- )
5524
- )) })
5525
- ]
5526
- }
5527
- ) })
5528
- ] })
5529
- ]
5530
- }
5531
- ),
5532
- hasError && /* @__PURE__ */ jsxRuntime.jsx("div", { id: errorId, className: "text-status-error text-xs mt-1", children: errorMessage })
5533
- ] });
5534
- }
5535
- var SHIMMER = "oxy-skeleton rounded-sm bg-surface-raised";
5536
- function SkeletonBox({ width, height = 16, radius, className = "", style }) {
5537
- return /* @__PURE__ */ jsxRuntime.jsx(
5538
- "span",
5539
- {
5540
- role: "presentation",
5541
- "aria-hidden": "true",
5542
- className: `block ${SHIMMER} ${className}`,
5543
- style: {
5544
- width: width ?? "100%",
5545
- height,
5546
- borderRadius: radius ?? "var(--radius-md)",
5547
- ...style
5548
- }
5549
- }
5550
- );
5551
- }
5552
- function SkeletonText({
5553
- lines = 3,
5554
- lastLineWidth = 60,
5555
- lineHeight = 14,
5556
- gap = 8,
5557
- className = "",
5558
- style
5559
- }) {
5560
- return /* @__PURE__ */ jsxRuntime.jsx(
5561
- "div",
5562
- {
5563
- role: "presentation",
5564
- "aria-hidden": "true",
5565
- className: `flex flex-col ${className}`,
5566
- style: { gap, ...style },
5567
- children: Array.from({ length: lines }).map((_, i) => {
5568
- const isLast = i === lines - 1;
5569
- const width = isLast && lines > 1 ? `${lastLineWidth}%` : "100%";
5570
- return /* @__PURE__ */ jsxRuntime.jsx(
5571
- "span",
5572
- {
5573
- className: `block ${SHIMMER}`,
5574
- style: { height: lineHeight, width, borderRadius: "var(--radius-sm)" }
5575
- },
5576
- i
5577
- );
5578
- })
5579
- }
5580
- );
5581
- }
5582
- function SkeletonCircle({ size = 40, className = "", style }) {
5583
- return /* @__PURE__ */ jsxRuntime.jsx(
5584
- "span",
5585
- {
5586
- role: "presentation",
5587
- "aria-hidden": "true",
5588
- className: `block flex-shrink-0 ${SHIMMER} ${className}`,
5589
- style: {
5590
- width: size,
5591
- height: size,
5592
- borderRadius: "50%",
5593
- ...style
5594
- }
5595
- }
5596
- );
5597
- }
5598
- function SkeletonCard({ hasAvatar = true, lines = 3, className = "", style }) {
5599
- return /* @__PURE__ */ jsxRuntime.jsxs(
5600
- "div",
5601
- {
5602
- role: "presentation",
5603
- "aria-hidden": "true",
5604
- className: `rounded-lg border border-border bg-surface p-4 ${className}`,
5605
- style,
5606
- children: [
5607
- /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex items-center gap-3 mb-4", children: [
5608
- hasAvatar && /* @__PURE__ */ jsxRuntime.jsx(SkeletonCircle, { size: 36 }),
5609
- /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex-1 flex flex-col gap-2", children: [
5610
- /* @__PURE__ */ jsxRuntime.jsx(SkeletonBox, { height: 12, width: "55%" }),
5611
- /* @__PURE__ */ jsxRuntime.jsx(SkeletonBox, { height: 10, width: "35%" })
5612
- ] })
5613
- ] }),
5614
- /* @__PURE__ */ jsxRuntime.jsx(SkeletonText, { lines, lastLineWidth: 55 }),
5615
- /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "mt-4 flex gap-2", children: [
5616
- /* @__PURE__ */ jsxRuntime.jsx(SkeletonBox, { height: 28, width: 72 }),
5617
- /* @__PURE__ */ jsxRuntime.jsx(SkeletonBox, { height: 28, width: 56 })
5618
- ] })
5619
- ]
5620
- }
5621
- );
5622
- }
5623
- var DEFAULT_PICKER = [
5624
- { key: 1, value: 5, label: 5 },
5625
- { key: 2, value: 10, label: 10 },
5626
- { key: 3, value: 15, label: 15 },
5627
- { key: 4, value: 20, label: 20 }
5628
- ];
5629
- var DEFAULT_PAGINATION = {
5630
- enabled: true,
5631
- perPage: 15,
5632
- withPicker: true,
5633
- pickerOptions: DEFAULT_PICKER
5634
- };
5635
- var DEFAULT_EXPAND = {
5636
- enabled: false
5637
- };
5638
- function createDatasets(rows, perPage) {
5639
- if (!perPage) return [rows.slice()];
5640
- const all = [];
5641
- for (let i = 0; i < rows.length; i += perPage) {
5642
- all.push(rows.slice(i, i + perPage));
5643
- }
5644
- return all;
5645
- }
5646
- var defaultGetRowKey = (_row, index) => index;
5647
- var cellAlign = (align) => align === "left" ? "text-left" : align === "right" ? "text-right" : "text-center";
5648
- function TableHeader({
5649
- columns,
5650
- hasExpand
5651
- }) {
5652
- return /* @__PURE__ */ jsxRuntime.jsx("thead", { className: "bg-surface-raised border-b border-border", children: /* @__PURE__ */ jsxRuntime.jsxs("tr", { children: [
5653
- hasExpand && /* @__PURE__ */ jsxRuntime.jsx("th", { "aria-hidden": "true", className: "w-9" }),
5654
- columns.map((col) => /* @__PURE__ */ jsxRuntime.jsx(
5655
- "th",
5656
- {
5657
- scope: "col",
5658
- className: `${cellAlign(col.align)} text-sm font-semibold text-foreground py-3 px-3`,
5659
- style: col.width != null ? { width: col.width } : void 0,
5660
- children: col.label
5661
- },
5662
- col.key
5663
- ))
5664
- ] }) });
5398
+ col.key
5399
+ ))
5400
+ ] }) });
5665
5401
  }
5666
5402
  var DefaultExpandIcon = /* @__PURE__ */ jsxRuntime.jsx(
5667
5403
  "svg",
@@ -5687,7 +5423,7 @@ function TableBody({
5687
5423
  expandRow,
5688
5424
  getRowKey
5689
5425
  }) {
5690
- const [expanded, setExpanded] = React29.useState(() => /* @__PURE__ */ new Set());
5426
+ const [expanded, setExpanded] = React28.useState(() => /* @__PURE__ */ new Set());
5691
5427
  const reduced = framerMotion.useReducedMotion();
5692
5428
  const toggleRow = (rowKey) => {
5693
5429
  setExpanded((prev) => {
@@ -5702,7 +5438,7 @@ function TableBody({
5702
5438
  return /* @__PURE__ */ jsxRuntime.jsx("tbody", { children: rows.map((row, i) => {
5703
5439
  const rowKey = getRowKey(row, i);
5704
5440
  const isExpanded = expanded.has(rowKey);
5705
- return /* @__PURE__ */ jsxRuntime.jsxs(React29__default.default.Fragment, { children: [
5441
+ return /* @__PURE__ */ jsxRuntime.jsxs(React28__default.default.Fragment, { children: [
5706
5442
  /* @__PURE__ */ jsxRuntime.jsxs(
5707
5443
  "tr",
5708
5444
  {
@@ -5758,14 +5494,16 @@ function Pagination({
5758
5494
  const matchedOption = picker.find(
5759
5495
  (o) => o.label === options.perPage || o.value === options.perPage
5760
5496
  );
5761
- const [perPageKey, setPerPageKey] = React29.useState(() => matchedOption?.key ?? picker[0]?.key);
5497
+ const [perPageKey, setPerPageKey] = React28.useState(() => matchedOption?.key ?? picker[0]?.key);
5762
5498
  const displayPerPageKey = serverSide ? matchedOption?.key ?? perPageKey : perPageKey;
5763
- React29.useEffect(() => {
5499
+ React28.useEffect(() => {
5764
5500
  if (serverSide && options.perPage != null) {
5765
5501
  const next = picker.find((o) => o.label === options.perPage || o.value === options.perPage);
5766
5502
  if (next) setPerPageKey(next.key);
5767
5503
  }
5768
5504
  }, [serverSide, options.perPage, picker]);
5505
+ const currentOpt = picker.find((o) => o.key === displayPerPageKey);
5506
+ const currentPerPageLabel = currentOpt?.label ?? currentOpt?.value ?? options.perPage ?? "";
5769
5507
  const navBtn = (icon, disabled, onClick, title) => /* @__PURE__ */ jsxRuntime.jsx(IconButton, { type: "bordered", size: "sm", disabled, onClick, icon, title });
5770
5508
  const chevronRight = /* @__PURE__ */ jsxRuntime.jsx("svg", { viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: 2, className: "h-4 w-4", children: /* @__PURE__ */ jsxRuntime.jsx("path", { strokeLinecap: "round", strokeLinejoin: "round", d: "M9 5l7 7-7 7" }) });
5771
5509
  const doubleChevronRight = /* @__PURE__ */ jsxRuntime.jsx("svg", { viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: 2, className: "h-4 w-4", children: /* @__PURE__ */ jsxRuntime.jsx("path", { strokeLinecap: "round", strokeLinejoin: "round", d: "M13 5l7 7-7 7M5 5l7 7-7 7" }) });
@@ -5773,21 +5511,20 @@ function Pagination({
5773
5511
  options.withPicker && /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "mr-auto flex items-center gap-2", children: [
5774
5512
  /* @__PURE__ */ jsxRuntime.jsx("span", { className: "whitespace-nowrap text-xs text-foreground-muted", children: "Rows per page" }),
5775
5513
  /* @__PURE__ */ jsxRuntime.jsx(
5776
- Dropdown,
5514
+ MenuButton,
5777
5515
  {
5516
+ variant: "secondary",
5778
5517
  size: "sm",
5779
- style: { width: 76 },
5780
- hasSearch: false,
5781
- items: picker,
5782
- isMultiselect: false,
5783
- value: displayPerPageKey,
5784
- onChange: ({ target: { value } }) => {
5785
- if (Array.isArray(value)) return;
5786
- const numKey = typeof value === "number" ? value : Number(value);
5787
- if (!serverSide) setPerPageKey(numKey);
5788
- const opt = picker.find((o) => o.key === numKey);
5789
- onPerPageChange(opt?.label ?? opt?.value ?? numKey);
5790
- }
5518
+ side: "top",
5519
+ label: String(currentPerPageLabel),
5520
+ items: picker.map((o) => ({
5521
+ key: o.key,
5522
+ label: String(o.label ?? o.value ?? o.key),
5523
+ onSelect: () => {
5524
+ if (!serverSide) setPerPageKey(o.key);
5525
+ onPerPageChange(o.label ?? o.value ?? o.key);
5526
+ }
5527
+ }))
5791
5528
  }
5792
5529
  )
5793
5530
  ] }),
@@ -5821,14 +5558,14 @@ function Table({
5821
5558
  className = "",
5822
5559
  style
5823
5560
  }) {
5824
- const searchRef = React29.useRef(null);
5825
- const [searchTerm, setSearchTerm] = React29.useState("");
5826
- const [perPage, setPerPage] = React29.useState(
5561
+ const searchRef = React28.useRef(null);
5562
+ const [searchTerm, setSearchTerm] = React28.useState("");
5563
+ const [perPage, setPerPage] = React28.useState(
5827
5564
  typeof pagination.perPage === "number" ? pagination.perPage : 15
5828
5565
  );
5829
- const [activePage, setActivePage] = React29.useState(0);
5566
+ const [activePage, setActivePage] = React28.useState(0);
5830
5567
  const isServerSide = !!(pagination.enabled && pagination.serverSide);
5831
- const filteredRows = React29.useMemo(() => {
5568
+ const filteredRows = React28.useMemo(() => {
5832
5569
  if (isServerSide || !searchTerm) return rows;
5833
5570
  const term = searchTerm.toLowerCase();
5834
5571
  return rows.filter(
@@ -5837,29 +5574,29 @@ function Table({
5837
5574
  )
5838
5575
  );
5839
5576
  }, [rows, searchTerm, isServerSide]);
5840
- const datasets = React29.useMemo(() => {
5577
+ const datasets = React28.useMemo(() => {
5841
5578
  if (isServerSide) return [rows];
5842
5579
  return createDatasets(filteredRows, pagination.enabled ? perPage : null);
5843
5580
  }, [filteredRows, perPage, pagination.enabled, isServerSide, rows]);
5844
- const MAX_PAGE = React29.useMemo(() => {
5581
+ const MAX_PAGE = React28.useMemo(() => {
5845
5582
  if (isServerSide && typeof pagination.maxPage === "number") return Math.max(0, pagination.maxPage);
5846
5583
  if (isServerSide && typeof pagination.totalCount === "number")
5847
5584
  return Math.max(0, Math.ceil(pagination.totalCount / perPage) - 1);
5848
5585
  return datasets.length ? datasets.length - 1 : 0;
5849
5586
  }, [isServerSide, pagination.maxPage, pagination.totalCount, perPage, datasets.length]);
5850
- const currentPageRows = React29.useMemo(() => {
5587
+ const currentPageRows = React28.useMemo(() => {
5851
5588
  if (isServerSide) return rows;
5852
5589
  return datasets[activePage] ?? [];
5853
5590
  }, [isServerSide, rows, datasets, activePage]);
5854
- React29.useEffect(() => {
5591
+ React28.useEffect(() => {
5855
5592
  if (pagination.enabled && !isServerSide && typeof pagination.perPage === "number") {
5856
5593
  setPerPage(pagination.perPage);
5857
5594
  }
5858
5595
  }, [pagination.enabled, pagination.perPage, isServerSide]);
5859
- React29.useEffect(() => {
5596
+ React28.useEffect(() => {
5860
5597
  if (isServerSide && typeof pagination.perPage === "number") setPerPage(pagination.perPage);
5861
5598
  }, [isServerSide, pagination.perPage]);
5862
- React29.useEffect(() => {
5599
+ React28.useEffect(() => {
5863
5600
  if (isServerSide && typeof pagination.page === "number" && pagination.page >= 1)
5864
5601
  setActivePage(pagination.page - 1);
5865
5602
  }, [isServerSide, pagination.page]);
@@ -5943,7 +5680,7 @@ function TableSkeletonBody({
5943
5680
  )) });
5944
5681
  }
5945
5682
  function ThemeSwitch({ checked, onChange, label = "Toggle dark mode", className = "" }) {
5946
- const id = React29.useId();
5683
+ const id = React28.useId();
5947
5684
  return /* @__PURE__ */ jsxRuntime.jsx("label", { htmlFor: id, className: `flex items-center gap-2 cursor-pointer select-none ${className}`.trim(), children: /* @__PURE__ */ jsxRuntime.jsx(
5948
5685
  SwitchPrimitive__namespace.Root,
5949
5686
  {
@@ -6127,7 +5864,7 @@ function Sidebar({
6127
5864
  }
6128
5865
  ) });
6129
5866
  }
6130
- var MegaMenuContext = React29.createContext({ align: "start" });
5867
+ var MegaMenuContext = React28.createContext({ align: "start" });
6131
5868
  function MegaMenu({
6132
5869
  children,
6133
5870
  align = "start",
@@ -6158,7 +5895,7 @@ function MegaMenu({
6158
5895
  }
6159
5896
  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";
6160
5897
  function MegaMenuItem({ label, icon, href, children, className = "" }) {
6161
- const { align } = React29.useContext(MegaMenuContext);
5898
+ const { align } = React28.useContext(MegaMenuContext);
6162
5899
  const pos = align === "center" ? "left-1/2 -translate-x-1/2" : align === "end" ? "right-0" : "left-0";
6163
5900
  if (!children) {
6164
5901
  return /* @__PURE__ */ jsxRuntime.jsx(NavigationMenu__namespace.Item, { children: /* @__PURE__ */ jsxRuntime.jsxs(NavigationMenu__namespace.Link, { href, className: [TOP_ITEM, className].filter(Boolean).join(" "), children: [
@@ -6243,8 +5980,8 @@ function MegaMenuLink({ href, icon, description, active, onClick, children, clas
6243
5980
  function MegaMenuFeatured({ children, className = "" }) {
6244
5981
  return /* @__PURE__ */ jsxRuntime.jsx("div", { className: ["min-w-0 rounded-lg bg-surface-raised border border-border p-4 flex flex-col", className].filter(Boolean).join(" "), children });
6245
5982
  }
6246
- var elementsOfType = (children, type) => React29__default.default.Children.toArray(children).filter(
6247
- (c) => React29__default.default.isValidElement(c) && c.type === type
5983
+ var elementsOfType = (children, type) => React28__default.default.Children.toArray(children).filter(
5984
+ (c) => React28__default.default.isValidElement(c) && c.type === type
6248
5985
  );
6249
5986
  var MOBILE_CHEVRON = /* @__PURE__ */ jsxRuntime.jsx(
6250
5987
  "svg",
@@ -6281,9 +6018,9 @@ function MobileLinkRow({ link, onNavigate }) {
6281
6018
  );
6282
6019
  }
6283
6020
  function MobilePanel({ panel, onNavigate }) {
6284
- const nodes = React29__default.default.Children.toArray(panel.props.children);
6021
+ const nodes = React28__default.default.Children.toArray(panel.props.children);
6285
6022
  return /* @__PURE__ */ jsxRuntime.jsx("div", { className: "flex flex-col gap-4 px-2 pb-3 pt-1", children: nodes.map((node, i) => {
6286
- if (!React29__default.default.isValidElement(node)) return null;
6023
+ if (!React28__default.default.isValidElement(node)) return null;
6287
6024
  const el = node;
6288
6025
  if (el.type === MegaMenuSection) {
6289
6026
  const { title, children } = el.props;
@@ -6302,8 +6039,8 @@ function MegaMenuMobile({
6302
6039
  children,
6303
6040
  label
6304
6041
  }) {
6305
- const [open, setOpen] = React29.useState(false);
6306
- const [expanded, setExpanded] = React29.useState(null);
6042
+ const [open, setOpen] = React28.useState(false);
6043
+ const [expanded, setExpanded] = React28.useState(null);
6307
6044
  const items = elementsOfType(children, MegaMenuItem);
6308
6045
  return /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "md:hidden w-full", children: [
6309
6046
  /* @__PURE__ */ jsxRuntime.jsxs(
@@ -6376,17 +6113,17 @@ function AppShell({
6376
6113
  children,
6377
6114
  className = ""
6378
6115
  }) {
6379
- const [expanded, setExpanded] = React29.useState(sidebarDefaultExpanded);
6380
- const [isMobile, setIsMobile] = React29.useState(false);
6381
- const [mobileOpen, setMobileOpen] = React29.useState(false);
6382
- React29.useEffect(() => {
6116
+ const [expanded, setExpanded] = React28.useState(sidebarDefaultExpanded);
6117
+ const [isMobile, setIsMobile] = React28.useState(false);
6118
+ const [mobileOpen, setMobileOpen] = React28.useState(false);
6119
+ React28.useEffect(() => {
6383
6120
  const mq = window.matchMedia("(max-width: 767px)");
6384
6121
  const update = (e) => setIsMobile(e.matches);
6385
6122
  update(mq);
6386
6123
  mq.addEventListener("change", update);
6387
6124
  return () => mq.removeEventListener("change", update);
6388
6125
  }, []);
6389
- React29.useEffect(() => {
6126
+ React28.useEffect(() => {
6390
6127
  if (!isMobile) setMobileOpen(false);
6391
6128
  }, [isMobile]);
6392
6129
  const hasSidebar = sidebarSections.length > 0;
@@ -6513,7 +6250,7 @@ function SecureLayout({
6513
6250
  className = ""
6514
6251
  }) {
6515
6252
  const reduced = framerMotion.useReducedMotion();
6516
- const cbs = React29.useRef({ canAccess, onGranted, onDeny });
6253
+ const cbs = React28.useRef({ canAccess, onGranted, onDeny });
6517
6254
  cbs.current = { canAccess, onGranted, onDeny };
6518
6255
  const rolesKey = JSON.stringify(roles);
6519
6256
  const requiredRolesKey = JSON.stringify(requiredRoles);
@@ -6528,10 +6265,10 @@ function SecureLayout({
6528
6265
  if (requiredPermissions?.length && !has(permissions, requiredPermissions, requireAllPermissions)) return false;
6529
6266
  return true;
6530
6267
  };
6531
- const [state, setState] = React29.useState(
6268
+ const [state, setState] = React28.useState(
6532
6269
  () => !passesSync() ? "denied" : canAccess ? "checking" : "granted"
6533
6270
  );
6534
- React29.useEffect(() => {
6271
+ React28.useEffect(() => {
6535
6272
  let cancelled = false;
6536
6273
  const { canAccess: check, onGranted: granted, onDeny: deny } = cbs.current;
6537
6274
  const finish = (ok) => {
@@ -6692,10 +6429,10 @@ function ThemeProvider({
6692
6429
  className = "",
6693
6430
  style
6694
6431
  }) {
6695
- const id = React29__default.default.useId().replace(/:/g, "");
6432
+ const id = React28__default.default.useId().replace(/:/g, "");
6696
6433
  const scopeClass = `geo-th-${id}`;
6697
- const divRef = React29.useRef(null);
6698
- React29.useEffect(() => {
6434
+ const divRef = React28.useRef(null);
6435
+ React28.useEffect(() => {
6699
6436
  const el = divRef.current;
6700
6437
  if (!el) return;
6701
6438
  if (colorScheme === "auto") return;
@@ -6710,8 +6447,8 @@ function ThemeProvider({
6710
6447
  }
6711
6448
  el.classList.toggle("dark", colorScheme === "dark");
6712
6449
  }, [colorScheme]);
6713
- const lightVars = React29.useMemo(() => toCssVars(theme), [theme]);
6714
- const darkVarStr = React29.useMemo(() => {
6450
+ const lightVars = React28.useMemo(() => toCssVars(theme), [theme]);
6451
+ const darkVarStr = React28.useMemo(() => {
6715
6452
  if (!darkTheme) return "";
6716
6453
  const dvars = toCssVars(darkTheme);
6717
6454
  if (!Object.keys(dvars).length) return "";
@@ -6753,7 +6490,7 @@ function NumberInput({
6753
6490
  readOnly = false,
6754
6491
  precision
6755
6492
  }) {
6756
- const errorId = React29.useId();
6493
+ const errorId = React28.useId();
6757
6494
  const hasError = errorMessage != null;
6758
6495
  const inferredPrecision = precision ?? (Number.isInteger(step) ? 0 : String(step).split(".")[1]?.length ?? 0);
6759
6496
  const round = (n) => {
@@ -6884,8 +6621,8 @@ function Password({
6884
6621
  showIcon,
6885
6622
  hideIcon
6886
6623
  }) {
6887
- const [visible, setVisible] = React29.useState(false);
6888
- const errorId = React29.useId();
6624
+ const [visible, setVisible] = React28.useState(false);
6625
+ const errorId = React28.useId();
6889
6626
  const hasError = errorMessage != null;
6890
6627
  return /* @__PURE__ */ jsxRuntime.jsx(
6891
6628
  Field,
@@ -6958,7 +6695,7 @@ function Checkbox({
6958
6695
  }) {
6959
6696
  const isChecked = checked ?? value ?? false;
6960
6697
  const labelFirst = labelPosition === "left";
6961
- const errorId = React29.useId();
6698
+ const errorId = React28.useId();
6962
6699
  const hasError = errorMessage != null;
6963
6700
  const box = /* @__PURE__ */ jsxRuntime.jsx(
6964
6701
  CheckboxPrimitive__namespace.Root,
@@ -7066,8 +6803,8 @@ function RadioGroup({
7066
6803
  className,
7067
6804
  errorMessage
7068
6805
  }) {
7069
- const errorId = React29.useId();
7070
- const groupId = React29.useId();
6806
+ const errorId = React28.useId();
6807
+ const groupId = React28.useId();
7071
6808
  const hasError = errorMessage != null;
7072
6809
  const labelFirst = labelPosition === "left";
7073
6810
  return /* @__PURE__ */ jsxRuntime.jsx(
@@ -7150,77 +6887,379 @@ function RadioGroup({
7150
6887
  }
7151
6888
  );
7152
6889
  }
7153
- function Switch({
7154
- checked,
7155
- defaultChecked = false,
7156
- onChange,
7157
- checkedIcon,
7158
- uncheckedIcon,
6890
+ function Switch({
6891
+ checked,
6892
+ defaultChecked = false,
6893
+ onChange,
6894
+ checkedIcon,
6895
+ uncheckedIcon,
6896
+ label,
6897
+ layout = "horizontal",
6898
+ helperText,
6899
+ className,
6900
+ offLabel,
6901
+ onLabel,
6902
+ name,
6903
+ required,
6904
+ disabled,
6905
+ errorMessage
6906
+ }) {
6907
+ const id = React28.useId();
6908
+ const errorId = React28.useId();
6909
+ const hasError = errorMessage != null;
6910
+ const isControlled = checked !== void 0;
6911
+ const [internal, setInternal] = React28.useState(defaultChecked);
6912
+ const isOn = isControlled ? checked : internal;
6913
+ const handle = (c) => {
6914
+ if (!isControlled) setInternal(c);
6915
+ onChange?.({ target: { checked: c, name } });
6916
+ };
6917
+ const stateLabel = (active) => [
6918
+ "text-sm select-none transition-colors",
6919
+ active ? "text-foreground font-medium" : "text-foreground-muted",
6920
+ disabled ? "opacity-50" : "cursor-pointer"
6921
+ ].filter(Boolean).join(" ");
6922
+ return /* @__PURE__ */ jsxRuntime.jsx(
6923
+ Field,
6924
+ {
6925
+ className,
6926
+ label,
6927
+ htmlFor: id,
6928
+ errorId,
6929
+ errorMessage,
6930
+ layout,
6931
+ required,
6932
+ helperText,
6933
+ labelAlign: "center",
6934
+ children: /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex items-center gap-2.5", children: [
6935
+ offLabel != null && /* @__PURE__ */ jsxRuntime.jsx("label", { htmlFor: id, className: stateLabel(!isOn), children: offLabel }),
6936
+ /* @__PURE__ */ jsxRuntime.jsx(
6937
+ SwitchPrimitive__namespace.Root,
6938
+ {
6939
+ id,
6940
+ name,
6941
+ checked: isOn,
6942
+ onCheckedChange: handle,
6943
+ disabled,
6944
+ required,
6945
+ "aria-invalid": hasError || void 0,
6946
+ "aria-describedby": hasError ? errorId : void 0,
6947
+ className: "relative inline-flex h-6 w-11 flex-shrink-0 items-center rounded-full bg-foreground-secondary data-[state=checked]:bg-accent transition-colors focus:outline-none focus-visible:ring-[3px] focus-visible:ring-focus-ring disabled:opacity-50 disabled:cursor-not-allowed",
6948
+ children: /* @__PURE__ */ jsxRuntime.jsx(
6949
+ SwitchPrimitive__namespace.Thumb,
6950
+ {
6951
+ className: "pointer-events-none flex h-5 w-5 items-center justify-center rounded-full bg-background text-foreground shadow transition-transform duration-200 data-[state=checked]:translate-x-[22px] data-[state=unchecked]:translate-x-[2px]",
6952
+ children: checkedIcon && uncheckedIcon ? /* @__PURE__ */ jsxRuntime.jsx("span", { className: "flex items-center justify-center w-3 h-3", children: isOn ? checkedIcon : uncheckedIcon }) : null
6953
+ }
6954
+ )
6955
+ }
6956
+ ),
6957
+ onLabel != null && /* @__PURE__ */ jsxRuntime.jsx("label", { htmlFor: id, className: stateLabel(isOn), children: onLabel })
6958
+ ] })
6959
+ }
6960
+ );
6961
+ }
6962
+ function Tag({ children, onRemove, removeLabel, disabled }) {
6963
+ return /* @__PURE__ */ jsxRuntime.jsxs("span", { className: "inline-flex items-center gap-1 rounded-md border border-border bg-surface-raised text-foreground text-xs pl-2 pr-1 py-0.5 max-w-full", children: [
6964
+ /* @__PURE__ */ jsxRuntime.jsx("span", { className: "truncate", children }),
6965
+ onRemove && /* @__PURE__ */ jsxRuntime.jsx(
6966
+ "button",
6967
+ {
6968
+ type: "button",
6969
+ disabled,
6970
+ onClick: (e) => {
6971
+ e.stopPropagation();
6972
+ onRemove();
6973
+ },
6974
+ "aria-label": removeLabel ?? "Remove",
6975
+ className: "inline-flex items-center justify-center w-4 h-4 flex-shrink-0 rounded text-foreground-muted hover:text-status-error hover:bg-surface transition-colors focus:outline-none focus-visible:ring-1 focus-visible:ring-accent disabled:cursor-not-allowed",
6976
+ children: /* @__PURE__ */ jsxRuntime.jsx("svg", { width: "10", height: "10", viewBox: "0 0 20 20", fill: "none", "aria-hidden": "true", children: /* @__PURE__ */ jsxRuntime.jsx("path", { d: "M15 5L5 15M5 5l10 10", stroke: "currentColor", strokeWidth: "2", strokeLinecap: "round" }) })
6977
+ }
6978
+ )
6979
+ ] });
6980
+ }
6981
+ function MultiTagRow({
6982
+ values,
6983
+ disabled,
6984
+ labelFor,
6985
+ onRemove
6986
+ }) {
6987
+ const wrapRef = React28.useRef(null);
6988
+ const measureRef = React28.useRef(null);
6989
+ const [visibleCount, setVisibleCount] = React28.useState(values.length);
6990
+ const key = values.map(String).join("|");
6991
+ React28.useLayoutEffect(() => {
6992
+ const wrap = wrapRef.current;
6993
+ const measure = measureRef.current;
6994
+ if (!wrap || !measure) return;
6995
+ const GAP = 6;
6996
+ const recompute = () => {
6997
+ const avail = wrap.clientWidth;
6998
+ const tagEls = Array.from(measure.querySelectorAll("[data-mt]"));
6999
+ const moreEl = measure.querySelector("[data-mm]");
7000
+ const widths = tagEls.map((e) => e.offsetWidth);
7001
+ const moreW = moreEl ? moreEl.offsetWidth : 0;
7002
+ if (widths.length === 0) {
7003
+ setVisibleCount(0);
7004
+ return;
7005
+ }
7006
+ let used = 0;
7007
+ let count = 0;
7008
+ for (let i = 0; i < widths.length; i++) {
7009
+ const w = widths[i] + (i > 0 ? GAP : 0);
7010
+ if (used + w <= avail) {
7011
+ used += w;
7012
+ count++;
7013
+ } else break;
7014
+ }
7015
+ if (count < widths.length) {
7016
+ while (count > 0) {
7017
+ let t = 0;
7018
+ for (let i = 0; i < count; i++) t += widths[i] + (i > 0 ? GAP : 0);
7019
+ t += GAP + moreW;
7020
+ if (t <= avail) break;
7021
+ count--;
7022
+ }
7023
+ }
7024
+ setVisibleCount(count);
7025
+ };
7026
+ recompute();
7027
+ const ro = new ResizeObserver(recompute);
7028
+ ro.observe(wrap);
7029
+ return () => ro.disconnect();
7030
+ }, [key]);
7031
+ const hidden = values.length - visibleCount;
7032
+ const moreChip = (n) => /* @__PURE__ */ jsxRuntime.jsxs("span", { className: "inline-flex items-center flex-shrink-0 rounded-md border border-border bg-surface-raised text-foreground-secondary text-xs px-2 py-0.5", children: [
7033
+ "+",
7034
+ n,
7035
+ " more"
7036
+ ] });
7037
+ return /* @__PURE__ */ jsxRuntime.jsxs("div", { ref: wrapRef, className: "relative flex-1 min-w-0 flex flex-nowrap items-center gap-1.5 overflow-hidden", children: [
7038
+ /* @__PURE__ */ jsxRuntime.jsxs(
7039
+ "div",
7040
+ {
7041
+ ref: measureRef,
7042
+ "aria-hidden": "true",
7043
+ className: "absolute invisible pointer-events-none flex flex-nowrap items-center gap-1.5",
7044
+ style: { left: -9999, top: -9999 },
7045
+ children: [
7046
+ values.map((val) => /* @__PURE__ */ jsxRuntime.jsx("span", { "data-mt": true, children: /* @__PURE__ */ jsxRuntime.jsx(Tag, { removeLabel: "x", onRemove: () => {
7047
+ }, children: labelFor(val) }) }, `m-${val}`)),
7048
+ /* @__PURE__ */ jsxRuntime.jsx("span", { "data-mm": true, children: moreChip(values.length) })
7049
+ ]
7050
+ }
7051
+ ),
7052
+ values.slice(0, visibleCount).map((val) => /* @__PURE__ */ jsxRuntime.jsx(
7053
+ Tag,
7054
+ {
7055
+ disabled,
7056
+ removeLabel: `Remove ${labelFor(val)}`,
7057
+ onRemove: () => onRemove(val),
7058
+ children: labelFor(val)
7059
+ },
7060
+ String(val)
7061
+ )),
7062
+ hidden > 0 && moreChip(hidden)
7063
+ ] });
7064
+ }
7065
+ function Dropdown({
7066
+ isMultiselect = false,
7067
+ hasSearch = true,
7159
7068
  label,
7069
+ name,
7070
+ value,
7071
+ onChange,
7072
+ disabled,
7160
7073
  layout = "horizontal",
7161
7074
  helperText,
7162
- className,
7163
- offLabel,
7164
- onLabel,
7165
- name,
7166
7075
  required,
7167
- disabled,
7168
- errorMessage
7076
+ errorMessage,
7077
+ style = {},
7078
+ htmlFor,
7079
+ items = [],
7080
+ labelStyle = {},
7081
+ placeholder,
7082
+ size = "md",
7083
+ className = ""
7169
7084
  }) {
7170
- const id = React29.useId();
7171
- const errorId = React29.useId();
7085
+ const [open, setOpen] = React28.useState(false);
7086
+ const [selectedItems, setSelectedItems] = React28.useState([]);
7087
+ const [searchTerm, setSearchTerm] = React28.useState("");
7088
+ const [innerItems, setInnerItems] = React28.useState([]);
7089
+ const errorId = React28.useId();
7172
7090
  const hasError = errorMessage != null;
7173
- const isControlled = checked !== void 0;
7174
- const [internal, setInternal] = React29.useState(defaultChecked);
7175
- const isOn = isControlled ? checked : internal;
7176
- const handle = (c) => {
7177
- if (!isControlled) setInternal(c);
7178
- onChange?.({ target: { checked: c, name } });
7091
+ React28.useEffect(() => {
7092
+ setInnerItems(items);
7093
+ }, [items]);
7094
+ React28.useEffect(() => {
7095
+ if (isMultiselect && Array.isArray(value)) {
7096
+ setSelectedItems(value);
7097
+ }
7098
+ }, [isMultiselect, value]);
7099
+ const selectItem = (key) => {
7100
+ if (isMultiselect) {
7101
+ const next = selectedItems.includes(key) ? selectedItems.filter((it) => it !== key) : [...selectedItems, key];
7102
+ setSelectedItems(next);
7103
+ onChange?.({ target: { value: next, id: htmlFor, name } });
7104
+ } else {
7105
+ setSelectedItems([key]);
7106
+ onChange?.({ target: { value: key, id: htmlFor, name } });
7107
+ setOpen(false);
7108
+ }
7179
7109
  };
7180
- const stateLabel = (active) => [
7181
- "text-sm select-none transition-colors",
7182
- active ? "text-foreground font-medium" : "text-foreground-muted",
7183
- disabled ? "opacity-50" : "cursor-pointer"
7184
- ].filter(Boolean).join(" ");
7185
- return /* @__PURE__ */ jsxRuntime.jsx(
7186
- Field,
7187
- {
7188
- className,
7189
- label,
7190
- htmlFor: id,
7191
- errorId,
7192
- errorMessage,
7193
- layout,
7194
- required,
7195
- helperText,
7196
- labelAlign: "center",
7197
- children: /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex items-center gap-2.5", children: [
7198
- offLabel != null && /* @__PURE__ */ jsxRuntime.jsx("label", { htmlFor: id, className: stateLabel(!isOn), children: offLabel }),
7199
- /* @__PURE__ */ jsxRuntime.jsx(
7200
- SwitchPrimitive__namespace.Root,
7201
- {
7202
- id,
7203
- name,
7204
- checked: isOn,
7205
- onCheckedChange: handle,
7206
- disabled,
7207
- required,
7208
- "aria-invalid": hasError || void 0,
7209
- "aria-describedby": hasError ? errorId : void 0,
7210
- className: "relative inline-flex h-6 w-11 flex-shrink-0 items-center rounded-full bg-foreground-secondary data-[state=checked]:bg-accent transition-colors focus:outline-none focus-visible:ring-[3px] focus-visible:ring-focus-ring disabled:opacity-50 disabled:cursor-not-allowed",
7211
- children: /* @__PURE__ */ jsxRuntime.jsx(
7212
- SwitchPrimitive__namespace.Thumb,
7110
+ const removeSelected = (key) => {
7111
+ if (isMultiselect) {
7112
+ const next = selectedItems.filter((it) => it !== key);
7113
+ setSelectedItems(next);
7114
+ onChange?.({ target: { value: next, id: htmlFor, name } });
7115
+ } else {
7116
+ setSelectedItems([]);
7117
+ onChange?.({ target: { value: "", id: htmlFor, name } });
7118
+ }
7119
+ };
7120
+ const labelFor = (key) => innerItems.find((it) => it.key === key)?.label ?? String(key);
7121
+ const onSearchChange = (e) => {
7122
+ const term = e.target.value;
7123
+ setSearchTerm(term);
7124
+ setInnerItems(
7125
+ term.trim() === "" ? items : items.filter(
7126
+ (it) => String(it.label).toLowerCase().includes(term.toLowerCase())
7127
+ )
7128
+ );
7129
+ };
7130
+ const isSelected = (key) => Array.isArray(value) ? value.includes(key) : value === key;
7131
+ return /* @__PURE__ */ jsxRuntime.jsxs("div", { className: className || void 0, children: [
7132
+ /* @__PURE__ */ jsxRuntime.jsxs(
7133
+ "div",
7134
+ {
7135
+ className: `flex ${layout === "vertical" ? "flex-col gap-1.5" : "flex-row items-start gap-3"}`,
7136
+ children: [
7137
+ /* @__PURE__ */ jsxRuntime.jsx(
7138
+ FieldLabel,
7139
+ {
7140
+ label,
7141
+ htmlFor,
7142
+ required,
7143
+ helperText,
7144
+ horizontal: layout === "horizontal",
7145
+ style: labelStyle
7146
+ }
7147
+ ),
7148
+ /* @__PURE__ */ jsxRuntime.jsxs(Popover__namespace.Root, { open: open && !disabled, onOpenChange: (o) => !disabled && setOpen(o), children: [
7149
+ /* @__PURE__ */ jsxRuntime.jsx(Popover__namespace.Trigger, { asChild: true, children: /* @__PURE__ */ jsxRuntime.jsxs(
7150
+ "div",
7213
7151
  {
7214
- className: "pointer-events-none flex h-5 w-5 items-center justify-center rounded-full bg-background text-foreground shadow transition-transform duration-200 data-[state=checked]:translate-x-[22px] data-[state=unchecked]:translate-x-[2px]",
7215
- children: checkedIcon && uncheckedIcon ? /* @__PURE__ */ jsxRuntime.jsx("span", { className: "flex items-center justify-center w-3 h-3", children: isOn ? checkedIcon : uncheckedIcon }) : null
7152
+ id: htmlFor,
7153
+ role: "combobox",
7154
+ "aria-expanded": open,
7155
+ "aria-haspopup": "listbox",
7156
+ "aria-invalid": hasError || void 0,
7157
+ "aria-describedby": hasError ? errorId : void 0,
7158
+ style: { width: 240, ...style },
7159
+ className: `flex items-center justify-between gap-2 cursor-pointer select-none min-h-[36px] px-3 py-1.5 ${fieldShell({ size, hasError, disabled, sized: false })}`,
7160
+ tabIndex: disabled ? -1 : 0,
7161
+ onKeyDown: (e) => {
7162
+ if (disabled) return;
7163
+ if (e.key === "Enter" || e.key === " " || e.key === "ArrowDown" || e.key === "ArrowUp") {
7164
+ e.preventDefault();
7165
+ setOpen(true);
7166
+ }
7167
+ },
7168
+ children: [
7169
+ !value || Array.isArray(value) && value.length === 0 ? /* @__PURE__ */ jsxRuntime.jsx("span", { className: "flex-1 min-w-0 truncate text-foreground-muted text-sm", children: placeholder }) : Array.isArray(value) ? /* @__PURE__ */ jsxRuntime.jsx(
7170
+ MultiTagRow,
7171
+ {
7172
+ values: value,
7173
+ disabled,
7174
+ labelFor,
7175
+ onRemove: removeSelected
7176
+ }
7177
+ ) : /* @__PURE__ */ jsxRuntime.jsx("div", { className: "flex-1 min-w-0 flex items-center overflow-hidden", children: /* @__PURE__ */ jsxRuntime.jsx(
7178
+ Tag,
7179
+ {
7180
+ disabled,
7181
+ removeLabel: `Remove ${labelFor(value)}`,
7182
+ onRemove: () => removeSelected(value),
7183
+ children: labelFor(value)
7184
+ }
7185
+ ) }),
7186
+ /* @__PURE__ */ jsxRuntime.jsx("div", { className: `flex-shrink-0 text-foreground-muted transition-transform duration-200 ${open ? "rotate-180" : "rotate-0"}`, "aria-hidden": "true", children: /* @__PURE__ */ jsxRuntime.jsx("svg", { viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: 2, className: "h-4 w-4", children: /* @__PURE__ */ jsxRuntime.jsx("path", { strokeLinecap: "round", strokeLinejoin: "round", d: "M19 9l-7 7-7-7" }) }) })
7187
+ ]
7216
7188
  }
7217
- )
7218
- }
7219
- ),
7220
- onLabel != null && /* @__PURE__ */ jsxRuntime.jsx("label", { htmlFor: id, className: stateLabel(isOn), children: onLabel })
7221
- ] })
7222
- }
7223
- );
7189
+ ) }),
7190
+ /* @__PURE__ */ jsxRuntime.jsx(Popover__namespace.Portal, { children: /* @__PURE__ */ jsxRuntime.jsxs(
7191
+ Popover__namespace.Content,
7192
+ {
7193
+ align: "start",
7194
+ sideOffset: 4,
7195
+ style: { width: style?.width || 240 },
7196
+ className: "bg-surface text-foreground border border-border rounded-lg shadow-md z-50 p-2 animate-in fade-in-0 zoom-in-95 data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=closed]:zoom-out-95",
7197
+ onInteractOutside: () => setOpen(false),
7198
+ children: [
7199
+ hasSearch && /* @__PURE__ */ jsxRuntime.jsx("div", { className: "mb-2", children: /* @__PURE__ */ jsxRuntime.jsx(
7200
+ SearchInput_default,
7201
+ {
7202
+ style: { width: "100%" },
7203
+ inputStyle: { width: "100%" },
7204
+ value: searchTerm,
7205
+ onChange: onSearchChange,
7206
+ placeholder: "Search..."
7207
+ }
7208
+ ) }),
7209
+ /* @__PURE__ */ jsxRuntime.jsx("div", { role: "listbox", "aria-multiselectable": isMultiselect, className: "max-h-40 overflow-y-auto", children: innerItems.map((item) => (
7210
+ // aria-rowindex was previously set here but
7211
+ // it's invalid ARIA on role="option" (it
7212
+ // belongs on rows of a grid/treegrid). Dropped.
7213
+ // tabIndex={0} + Enter/Space handler makes the
7214
+ // option keyboard-activatable; the full
7215
+ // combobox roving-tabindex pattern is deferred
7216
+ // until the planned Phase-5 rewrite.
7217
+ /* @__PURE__ */ jsxRuntime.jsxs(
7218
+ "div",
7219
+ {
7220
+ role: "option",
7221
+ "aria-selected": isSelected(item.key),
7222
+ tabIndex: 0,
7223
+ className: `flex items-center justify-between p-2 hover:bg-accent hover:text-accent-fg transition-colors duration-150 text-sm rounded-lg cursor-pointer focus:outline-none focus-visible:ring-2 focus-visible:ring-accent ${selectedItems.includes(item.key) ? "bg-surface-raised text-foreground" : "text-foreground"}`,
7224
+ onClick: () => selectItem(item.key),
7225
+ onKeyDown: (e) => {
7226
+ if (e.key === "Enter" || e.key === " ") {
7227
+ e.preventDefault();
7228
+ selectItem(item.key);
7229
+ }
7230
+ },
7231
+ children: [
7232
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex items-center gap-2 text-xs", children: [
7233
+ item.icon && /* @__PURE__ */ jsxRuntime.jsx("div", { children: item.icon }),
7234
+ item.label
7235
+ ] }),
7236
+ isSelected(item.key) && // currentColor — checkmark follows
7237
+ // the item's text colour, which
7238
+ // flips automatically on hover.
7239
+ /* @__PURE__ */ jsxRuntime.jsx("svg", { width: "16", height: "16", viewBox: "0 0 20 20", fill: "none", "aria-hidden": "true", children: /* @__PURE__ */ jsxRuntime.jsx(
7240
+ "path",
7241
+ {
7242
+ d: "M4 10l4.5 4.5L16 6",
7243
+ stroke: "currentColor",
7244
+ strokeWidth: "2",
7245
+ strokeLinecap: "round",
7246
+ strokeLinejoin: "round"
7247
+ }
7248
+ ) })
7249
+ ]
7250
+ },
7251
+ item.key
7252
+ )
7253
+ )) })
7254
+ ]
7255
+ }
7256
+ ) })
7257
+ ] })
7258
+ ]
7259
+ }
7260
+ ),
7261
+ hasError && /* @__PURE__ */ jsxRuntime.jsx("div", { id: errorId, className: "text-status-error text-xs mt-1", children: errorMessage })
7262
+ ] });
7224
7263
  }
7225
7264
  function AutoComplete({
7226
7265
  disabled,
@@ -7244,19 +7283,19 @@ function AutoComplete({
7244
7283
  required,
7245
7284
  htmlFor
7246
7285
  }) {
7247
- const errorId = React29.useId();
7286
+ const errorId = React28.useId();
7248
7287
  const hasError = errorMessage != null;
7249
- const [term, setTerm] = React29.useState("");
7250
- const [open, setOpen] = React29.useState(false);
7251
- const [asyncItems, setAsyncItems] = React29.useState([]);
7252
- const [loading, setLoading] = React29.useState(false);
7288
+ const [term, setTerm] = React28.useState("");
7289
+ const [open, setOpen] = React28.useState(false);
7290
+ const [asyncItems, setAsyncItems] = React28.useState([]);
7291
+ const [loading, setLoading] = React28.useState(false);
7253
7292
  const isAsync = typeof onSearch === "function";
7254
- const debounceRef = React29.useRef(null);
7255
- const requestIdRef = React29.useRef(0);
7293
+ const debounceRef = React28.useRef(null);
7294
+ const requestIdRef = React28.useRef(0);
7256
7295
  const staticFiltered = isAsync || !items ? [] : term.trim() ? items.filter(
7257
7296
  ({ key, label: label2 }) => label2.toLowerCase().includes(term.toLowerCase()) || key.toLowerCase().includes(term.toLowerCase())
7258
7297
  ) : [];
7259
- React29.useEffect(() => {
7298
+ React28.useEffect(() => {
7260
7299
  if (!isAsync) return;
7261
7300
  if (debounceRef.current) clearTimeout(debounceRef.current);
7262
7301
  if (!term.trim()) {
@@ -7412,15 +7451,15 @@ function TreeSelect({
7412
7451
  defaultExpandedKeys = [],
7413
7452
  size = "md"
7414
7453
  }) {
7415
- const errorId = React29.useId();
7454
+ const errorId = React28.useId();
7416
7455
  const hasError = errorMessage != null;
7417
- const [open, setOpen] = React29.useState(false);
7418
- const [expanded, setExpanded] = React29.useState(() => new Set(defaultExpandedKeys));
7419
- const [activeIndex, setActiveIndex] = React29.useState(0);
7420
- const listRef = React29.useRef(null);
7421
- const visible = React29.useMemo(() => flattenVisible(items, expanded), [items, expanded]);
7422
- const didSyncOnOpenRef = React29.useRef(false);
7423
- React29.useEffect(() => {
7456
+ const [open, setOpen] = React28.useState(false);
7457
+ const [expanded, setExpanded] = React28.useState(() => new Set(defaultExpandedKeys));
7458
+ const [activeIndex, setActiveIndex] = React28.useState(0);
7459
+ const listRef = React28.useRef(null);
7460
+ const visible = React28.useMemo(() => flattenVisible(items, expanded), [items, expanded]);
7461
+ const didSyncOnOpenRef = React28.useRef(false);
7462
+ React28.useEffect(() => {
7424
7463
  if (!open) {
7425
7464
  didSyncOnOpenRef.current = false;
7426
7465
  return;
@@ -7430,7 +7469,7 @@ function TreeSelect({
7430
7469
  setActiveIndex(selectedIdx >= 0 ? selectedIdx : 0);
7431
7470
  didSyncOnOpenRef.current = true;
7432
7471
  }, [open, value]);
7433
- const selectedNode = React29.useMemo(
7472
+ const selectedNode = React28.useMemo(
7434
7473
  () => value != null ? findNodeByKey(items, value) : null,
7435
7474
  [items, value]
7436
7475
  );
@@ -7661,11 +7700,11 @@ function FileInput({
7661
7700
  required,
7662
7701
  icon
7663
7702
  }) {
7664
- const inputRef = React29.useRef(null);
7665
- const errorId = React29.useId();
7666
- const [files, setFiles] = React29.useState([]);
7667
- const [dragging, setDragging] = React29.useState(false);
7668
- const [sizeError, setSizeError] = React29.useState(null);
7703
+ const inputRef = React28.useRef(null);
7704
+ const errorId = React28.useId();
7705
+ const [files, setFiles] = React28.useState([]);
7706
+ const [dragging, setDragging] = React28.useState(false);
7707
+ const [sizeError, setSizeError] = React28.useState(null);
7669
7708
  const effectiveError = errorMessage ?? sizeError ?? void 0;
7670
7709
  const openPicker = () => {
7671
7710
  if (!disabled) inputRef.current?.click();
@@ -7856,30 +7895,30 @@ function DatePicker({
7856
7895
  size = "md",
7857
7896
  className = ""
7858
7897
  }) {
7859
- const errorId = React29.useId();
7898
+ const errorId = React28.useId();
7860
7899
  const hasError = errorMessage != null;
7861
- const [open, setOpen] = React29.useState(false);
7862
- const [viewMonth, setViewMonth] = React29.useState(() => startOfMonth2(value ?? /* @__PURE__ */ new Date()));
7863
- const [focusDate, setFocusDate] = React29.useState(() => value ?? /* @__PURE__ */ new Date());
7864
- const [view, setView] = React29.useState("days");
7865
- const gridRef = React29.useRef(null);
7866
- React29.useEffect(() => {
7900
+ const [open, setOpen] = React28.useState(false);
7901
+ const [viewMonth, setViewMonth] = React28.useState(() => startOfMonth2(value ?? /* @__PURE__ */ new Date()));
7902
+ const [focusDate, setFocusDate] = React28.useState(() => value ?? /* @__PURE__ */ new Date());
7903
+ const [view, setView] = React28.useState("days");
7904
+ const gridRef = React28.useRef(null);
7905
+ React28.useEffect(() => {
7867
7906
  if (!open) return;
7868
7907
  const target = value ?? /* @__PURE__ */ new Date();
7869
7908
  setViewMonth(startOfMonth2(target));
7870
7909
  setFocusDate(target);
7871
7910
  setView("days");
7872
7911
  }, [open, value]);
7873
- React29.useEffect(() => {
7912
+ React28.useEffect(() => {
7874
7913
  if (!open) return;
7875
7914
  const cell = gridRef.current?.querySelector(`[data-day="${defaultFormat3(focusDate)}"]`);
7876
7915
  cell?.focus();
7877
7916
  }, [open, focusDate]);
7878
- const weekdays = React29.useMemo(() => {
7917
+ const weekdays = React28.useMemo(() => {
7879
7918
  const ordered = WEEKDAY_SHORT.slice(weekStartsOn).concat(WEEKDAY_SHORT.slice(0, weekStartsOn));
7880
7919
  return ordered;
7881
7920
  }, [weekStartsOn]);
7882
- const grid = React29.useMemo(() => buildGrid2(viewMonth, weekStartsOn), [viewMonth, weekStartsOn]);
7921
+ const grid = React28.useMemo(() => buildGrid2(viewMonth, weekStartsOn), [viewMonth, weekStartsOn]);
7883
7922
  const isDisabled = (d) => {
7884
7923
  if (min && d < min) return true;
7885
7924
  if (max && d > max) return true;
@@ -8169,10 +8208,10 @@ function TextArea({
8169
8208
  style,
8170
8209
  inputStyle
8171
8210
  }) {
8172
- const errorId = React29.useId();
8211
+ const errorId = React28.useId();
8173
8212
  const hasError = errorMessage != null;
8174
- const ref = React29.useRef(null);
8175
- React29.useLayoutEffect(() => {
8213
+ const ref = React28.useRef(null);
8214
+ React28.useLayoutEffect(() => {
8176
8215
  if (!autoGrow) return;
8177
8216
  const el = ref.current;
8178
8217
  if (!el) return;
@@ -8244,14 +8283,14 @@ function Slider({
8244
8283
  name,
8245
8284
  htmlFor
8246
8285
  }) {
8247
- const errorId = React29.useId();
8286
+ const errorId = React28.useId();
8248
8287
  const hasError = errorMessage != null;
8249
8288
  const isRange = Array.isArray(value ?? defaultValue);
8250
- const [internal, setInternal] = React29.useState(
8289
+ const [internal, setInternal] = React28.useState(
8251
8290
  () => toArray(value) ?? toArray(defaultValue) ?? [min]
8252
8291
  );
8253
8292
  const current = toArray(value) ?? internal;
8254
- const [dragging, setDragging] = React29.useState(false);
8293
+ const [dragging, setDragging] = React28.useState(false);
8255
8294
  const emit = (arr) => {
8256
8295
  setInternal(arr);
8257
8296
  const next = isRange ? [arr[0], arr[1]] : arr[0];
@@ -8346,11 +8385,11 @@ function TagsInput({
8346
8385
  validate,
8347
8386
  separators = ["Enter", ","]
8348
8387
  }) {
8349
- const errorId = React29.useId();
8350
- const inputRef = React29.useRef(null);
8351
- const [internal, setInternal] = React29.useState(defaultValue ?? []);
8352
- const [draft, setDraft] = React29.useState("");
8353
- const [localError, setLocalError] = React29.useState(null);
8388
+ const errorId = React28.useId();
8389
+ const inputRef = React28.useRef(null);
8390
+ const [internal, setInternal] = React28.useState(defaultValue ?? []);
8391
+ const [draft, setDraft] = React28.useState("");
8392
+ const [localError, setLocalError] = React28.useState(null);
8354
8393
  const tags = value ?? internal;
8355
8394
  const hasError = errorMessage != null || localError != null;
8356
8395
  const errorText = errorMessage ?? localError ?? void 0;
@@ -8481,9 +8520,9 @@ function OtpInput({
8481
8520
  className,
8482
8521
  groupAfter
8483
8522
  }) {
8484
- const errorId = React29.useId();
8523
+ const errorId = React28.useId();
8485
8524
  const hasError = errorMessage != null;
8486
- const refs = React29.useRef([]);
8525
+ const refs = React28.useRef([]);
8487
8526
  const chars = Array.from({ length }, (_, i) => value[i] ?? "");
8488
8527
  const pattern = mode === "numeric" ? /[0-9]/ : /[a-zA-Z0-9]/;
8489
8528
  const emit = (next) => {
@@ -8532,7 +8571,7 @@ function OtpInput({
8532
8571
  emit(valid.join(""));
8533
8572
  focusBox(valid.length);
8534
8573
  };
8535
- 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(React29__default.default.Fragment, { children: [
8574
+ 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(React28__default.default.Fragment, { children: [
8536
8575
  /* @__PURE__ */ jsxRuntime.jsx(
8537
8576
  "input",
8538
8577
  {
@@ -8590,9 +8629,9 @@ function Rating({
8590
8629
  className,
8591
8630
  required
8592
8631
  }) {
8593
- const errorId = React29.useId();
8594
- const [internal, setInternal] = React29.useState(defaultValue);
8595
- const [hover, setHover] = React29.useState(null);
8632
+ const errorId = React28.useId();
8633
+ const [internal, setInternal] = React28.useState(defaultValue);
8634
+ const [hover, setHover] = React28.useState(null);
8596
8635
  const current = value ?? internal;
8597
8636
  const display2 = hover ?? current;
8598
8637
  const interactive = !readOnly && !disabled;
@@ -8715,9 +8754,9 @@ function TimePicker({
8715
8754
  required,
8716
8755
  style
8717
8756
  }) {
8718
- const errorId = React29.useId();
8757
+ const errorId = React28.useId();
8719
8758
  const hasError = errorMessage != null;
8720
- const [open, setOpen] = React29.useState(false);
8759
+ const [open, setOpen] = React28.useState(false);
8721
8760
  const parsed = parse(value) ?? { h: 0, m: 0, s: 0 };
8722
8761
  const update = (next) => {
8723
8762
  const merged = { ...parsed, ...next };
@@ -8841,13 +8880,13 @@ function DateRangePicker({
8841
8880
  required,
8842
8881
  style
8843
8882
  }) {
8844
- const errorId = React29.useId();
8883
+ const errorId = React28.useId();
8845
8884
  const hasError = errorMessage != null;
8846
- const [open, setOpen] = React29.useState(false);
8847
- const [leftMonth, setLeftMonth] = React29.useState(() => startOfMonth3(value.start ?? /* @__PURE__ */ new Date()));
8848
- const [pendingStart, setPendingStart] = React29.useState(null);
8849
- const [hoverDate, setHoverDate] = React29.useState(null);
8850
- const weekdays = React29.useMemo(
8885
+ const [open, setOpen] = React28.useState(false);
8886
+ const [leftMonth, setLeftMonth] = React28.useState(() => startOfMonth3(value.start ?? /* @__PURE__ */ new Date()));
8887
+ const [pendingStart, setPendingStart] = React28.useState(null);
8888
+ const [hoverDate, setHoverDate] = React28.useState(null);
8889
+ const weekdays = React28.useMemo(
8851
8890
  () => WEEKDAY.slice(weekStartsOn).concat(WEEKDAY.slice(0, weekStartsOn)),
8852
8891
  [weekStartsOn]
8853
8892
  );
@@ -9023,10 +9062,10 @@ function ColorPicker({
9023
9062
  required,
9024
9063
  placeholder = "Pick a colour\u2026"
9025
9064
  }) {
9026
- const errorId = React29.useId();
9065
+ const errorId = React28.useId();
9027
9066
  const hasError = errorMessage != null;
9028
- const [open, setOpen] = React29.useState(false);
9029
- const [draft, setDraft] = React29.useState(value);
9067
+ const [open, setOpen] = React28.useState(false);
9068
+ const [draft, setDraft] = React28.useState(value);
9030
9069
  const valid = HEX_RE.test(value);
9031
9070
  const pick = (hex) => {
9032
9071
  onChange?.(hex);