@flytedan/flytebot-design-system 0.72.0 → 0.73.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.js CHANGED
@@ -937,26 +937,57 @@ function Collapsible({
937
937
  }
938
938
 
939
939
  // src/components/surfaces/Drawer.tsx
940
- import * as React6 from "react";
940
+ import * as React7 from "react";
941
941
  import { createPortal as createPortal2 } from "react-dom";
942
- import { jsx as jsx9, jsxs as jsxs6 } from "react/jsx-runtime";
943
- function Drawer({ open: open2 = true, title, onClose, footer, bare = false, children, className = "", ...rest }) {
944
- const asideRef = React6.useRef(null);
942
+
943
+ // src/kits/useClosingAnimation.ts
944
+ import * as React6 from "react";
945
+ function useClosingAnimation(open2, onClose, durationMs) {
945
946
  const [closing, setClosing] = React6.useState(false);
947
+ const timer = React6.useRef(null);
948
+ const cancel = React6.useCallback(() => {
949
+ if (timer.current !== null) clearTimeout(timer.current);
950
+ timer.current = null;
951
+ }, []);
952
+ React6.useEffect(() => {
953
+ if (!open2) {
954
+ cancel();
955
+ setClosing(false);
956
+ }
957
+ }, [open2, cancel]);
958
+ React6.useEffect(() => cancel, [cancel]);
946
959
  const close2 = React6.useCallback(() => {
947
960
  if (!onClose) return;
961
+ cancel();
948
962
  setClosing(true);
949
- setTimeout(onClose, 210);
950
- }, [onClose]);
963
+ timer.current = setTimeout(() => {
964
+ timer.current = null;
965
+ onClose();
966
+ }, durationMs);
967
+ }, [onClose, durationMs, cancel]);
968
+ return { closing, close: close2 };
969
+ }
970
+
971
+ // src/components/surfaces/Drawer.tsx
972
+ import { jsx as jsx9, jsxs as jsxs6 } from "react/jsx-runtime";
973
+ function Drawer({ open: open2 = true, title, label, onClose, footer, bare = false, children, className = "", ...rest }) {
974
+ const asideRef = React7.useRef(null);
975
+ const { closing, close: close2 } = useClosingAnimation(!!open2, onClose, 210);
951
976
  const layer = useStackedLayer({ active: !!open2, containerRef: asideRef, trap: true, onEscape: onClose ? close2 : void 0 });
952
977
  const zIndex = useLayerZIndex(layer);
978
+ const titleId = React7.useId();
979
+ const accessibleName = bare ? label ?? (typeof title === "string" ? title : void 0) : label;
980
+ const unnamed = !!open2 && bare && !accessibleName;
981
+ React7.useEffect(() => {
982
+ if (process.env.NODE_ENV !== "production" && unnamed) console.warn("Drawer: a bare Drawer has no header to name it. Pass `label`, or a string `title`, so the dialog has an accessible name.");
983
+ }, [unnamed]);
953
984
  if (!open2) return null;
954
985
  return createPortal2(
955
986
  /* @__PURE__ */ jsxs6(StackedLayerProvider, { layer, children: [
956
987
  /* @__PURE__ */ jsx9("div", { className: "fd-scrim" + (closing ? " is-closing" : ""), style: { display: "block", zIndex: zIndex - LAYER_STEP }, onClick: close2 }),
957
- /* @__PURE__ */ jsxs6("aside", { ref: asideRef, className: ["fd-drawer", bare ? "is-bare" : "", closing ? "is-closing" : "", className].filter(Boolean).join(" "), role: "dialog", "aria-modal": "true", "aria-label": bare && typeof title === "string" ? title : void 0, ...rest, style: { zIndex }, children: [
988
+ /* @__PURE__ */ jsxs6("aside", { ref: asideRef, className: ["fd-drawer", bare ? "is-bare" : "", closing ? "is-closing" : "", className].filter(Boolean).join(" "), role: "dialog", "aria-modal": "true", "aria-label": accessibleName, "aria-labelledby": bare || label ? void 0 : titleId, ...rest, style: { zIndex }, children: [
958
989
  bare ? null : /* @__PURE__ */ jsxs6("div", { className: "fd-card-head", style: { flex: "none" }, children: [
959
- /* @__PURE__ */ jsx9("span", { className: "fd-card-head-title", title: truncationTitle(title), children: title }),
990
+ /* @__PURE__ */ jsx9("span", { id: titleId, className: "fd-card-head-title", title: truncationTitle(title), children: title }),
960
991
  onClose ? /* @__PURE__ */ jsx9("button", { type: "button", className: "fd-btn-icon", "aria-label": "Close", onClick: close2, children: /* @__PURE__ */ jsx9("i", { className: "ph ph-x" }) }) : null
961
992
  ] }),
962
993
  /* @__PURE__ */ jsx9("div", { style: bare ? { flex: "1 1 auto", minHeight: 0, display: "flex", flexDirection: "column" } : { flex: "1 1 auto", minHeight: 0, overflow: "auto", padding: 20 }, children: typeof children === "function" ? children(close2) : children }),
@@ -968,17 +999,12 @@ function Drawer({ open: open2 = true, title, onClose, footer, bare = false, chil
968
999
  }
969
1000
 
970
1001
  // src/components/surfaces/Modal.tsx
971
- import * as React7 from "react";
1002
+ import * as React8 from "react";
972
1003
  import { createPortal as createPortal3 } from "react-dom";
973
1004
  import { jsx as jsx10, jsxs as jsxs7 } from "react/jsx-runtime";
974
1005
  function Modal({ open: open2 = true, title, description, onClose, footer, wide = false, children, className = "", ...rest }) {
975
- const [closing, setClosing] = React7.useState(false);
976
- const boxRef = React7.useRef(null);
977
- const close2 = React7.useCallback(() => {
978
- if (!onClose) return;
979
- setClosing(true);
980
- setTimeout(onClose, 190);
981
- }, [onClose]);
1006
+ const boxRef = React8.useRef(null);
1007
+ const { closing, close: close2 } = useClosingAnimation(!!open2, onClose, 190);
982
1008
  const layer = useStackedLayer({ active: !!open2, containerRef: boxRef, trap: true, onEscape: onClose ? close2 : void 0 });
983
1009
  const zIndex = useLayerZIndex(layer);
984
1010
  if (!open2) return null;
@@ -1061,13 +1087,13 @@ function ScreenHead({ kicker, title, lede, actions }) {
1061
1087
  }
1062
1088
 
1063
1089
  // src/components/layout/CardGrid.tsx
1064
- import * as React8 from "react";
1090
+ import * as React9 from "react";
1065
1091
  import { jsx as jsx12 } from "react/jsx-runtime";
1066
1092
  function flattenFragments(children) {
1067
1093
  const out = [];
1068
- React8.Children.forEach(children, (child) => {
1094
+ React9.Children.forEach(children, (child) => {
1069
1095
  if (child === null || child === void 0 || typeof child === "boolean") return;
1070
- if (React8.isValidElement(child) && child.type === React8.Fragment) {
1096
+ if (React9.isValidElement(child) && child.type === React9.Fragment) {
1071
1097
  const fragmentChildren = child.props.children;
1072
1098
  out.push(...flattenFragments(fragmentChildren));
1073
1099
  return;
@@ -1085,7 +1111,7 @@ function CardGrid({ children, minCardWidth = 280, gap = "lg", className = "", st
1085
1111
  className: ["fd-card-grid", "fd-gap-" + gap, className].filter(Boolean).join(" "),
1086
1112
  style: { ["--card-grid-min"]: minCardWidth + "px", ...style },
1087
1113
  children: items.map((child, i) => {
1088
- if (React8.isValidElement(child)) {
1114
+ if (React9.isValidElement(child)) {
1089
1115
  const existingRole = child.props.role;
1090
1116
  if (existingRole) return child;
1091
1117
  return /* @__PURE__ */ jsx12("div", { role: "listitem", children: child }, child.key ?? i);
@@ -1135,10 +1161,10 @@ function LoadingRegion({
1135
1161
  }
1136
1162
 
1137
1163
  // src/components/loading/JobTray.tsx
1138
- import * as React10 from "react";
1164
+ import * as React11 from "react";
1139
1165
 
1140
1166
  // src/kits/cornerStack.tsx
1141
- import * as React9 from "react";
1167
+ import * as React10 from "react";
1142
1168
  import { createPortal as createPortal4 } from "react-dom";
1143
1169
  var CORNER_STACK_INSET_PROPERTY = "--fd-corner-stack-inset";
1144
1170
  var SLOTS = ["jobs", "toasts"];
@@ -1188,9 +1214,9 @@ function release(slot) {
1188
1214
  slotElements.clear();
1189
1215
  }
1190
1216
  }
1191
- var useSlotEffect = typeof document === "undefined" ? React9.useEffect : React9.useLayoutEffect;
1217
+ var useSlotEffect = typeof document === "undefined" ? React10.useEffect : React10.useLayoutEffect;
1192
1218
  function useCornerStackSlot(slot) {
1193
- const [element, setElement] = React9.useState(null);
1219
+ const [element, setElement] = React10.useState(null);
1194
1220
  useSlotEffect(() => {
1195
1221
  setElement(acquire(slot));
1196
1222
  return () => {
@@ -1247,9 +1273,9 @@ function announcementFor(job) {
1247
1273
  return title + ": in progress";
1248
1274
  }
1249
1275
  function JobTray({ jobs: jobs2, onDismiss, className = "" }) {
1250
- const [announcement, setAnnouncement] = React10.useState("");
1251
- const prevStatuses = React10.useRef({});
1252
- React10.useEffect(() => {
1276
+ const [announcement, setAnnouncement] = React11.useState("");
1277
+ const prevStatuses = React11.useRef({});
1278
+ React11.useEffect(() => {
1253
1279
  let next = "";
1254
1280
  for (const job of jobs2) {
1255
1281
  if (prevStatuses.current[job.id] !== job.status) {
@@ -1300,7 +1326,7 @@ function JobCard({ job, onDismiss }) {
1300
1326
  }
1301
1327
 
1302
1328
  // src/components/loading/PhasedProgress.tsx
1303
- import * as React11 from "react";
1329
+ import * as React12 from "react";
1304
1330
  import { jsx as jsx16, jsxs as jsxs12 } from "react/jsx-runtime";
1305
1331
  var ICON = {
1306
1332
  pending: "ph-circle",
@@ -1313,9 +1339,9 @@ function textOf2(node) {
1313
1339
  return "";
1314
1340
  }
1315
1341
  function PhasedProgress({ phases, summary, className = "" }) {
1316
- const [announcement, setAnnouncement] = React11.useState("");
1317
- const prevStatuses = React11.useRef({});
1318
- React11.useEffect(() => {
1342
+ const [announcement, setAnnouncement] = React12.useState("");
1343
+ const prevStatuses = React12.useRef({});
1344
+ React12.useEffect(() => {
1319
1345
  let next = "";
1320
1346
  for (const phase of phases) {
1321
1347
  if (prevStatuses.current[phase.id] !== phase.status) {
@@ -1395,12 +1421,12 @@ function Spinner({ size = "md", label = "Loading", className = "", style, ...res
1395
1421
  }
1396
1422
 
1397
1423
  // src/components/navigation/SidebarNav.tsx
1398
- import * as React12 from "react";
1424
+ import * as React13 from "react";
1399
1425
  import { jsx as jsx20, jsxs as jsxs14 } from "react/jsx-runtime";
1400
1426
  function Tip({ label, children }) {
1401
1427
  return /* @__PURE__ */ jsx20("span", { title: label, style: { display: "inline-flex", flex: "none" }, children });
1402
1428
  }
1403
- var SidebarNav = React12.forwardRef(function SidebarNav2({ brand, groups = [], current: current2, onNavigate, footer, open: open2 = false, className = "", ...rest }, ref) {
1429
+ var SidebarNav = React13.forwardRef(function SidebarNav2({ brand, groups = [], current: current2, onNavigate, footer, open: open2 = false, className = "", ...rest }, ref) {
1404
1430
  return /* @__PURE__ */ jsxs14(
1405
1431
  "nav",
1406
1432
  {
@@ -1439,15 +1465,15 @@ var SidebarNav = React12.forwardRef(function SidebarNav2({ brand, groups = [], c
1439
1465
  });
1440
1466
 
1441
1467
  // src/components/navigation/Topbar.tsx
1442
- import * as React14 from "react";
1468
+ import * as React15 from "react";
1443
1469
 
1444
1470
  // src/kits/useIsNarrow.ts
1445
- import * as React13 from "react";
1471
+ import * as React14 from "react";
1446
1472
  function useIsNarrow(breakpoint) {
1447
- const [narrow, setNarrow] = React13.useState(
1473
+ const [narrow, setNarrow] = React14.useState(
1448
1474
  () => typeof window !== "undefined" && typeof window.matchMedia === "function" && window.matchMedia(`(max-width: ${breakpoint}px)`).matches
1449
1475
  );
1450
- React13.useEffect(() => {
1476
+ React14.useEffect(() => {
1451
1477
  if (typeof window === "undefined" || typeof window.matchMedia !== "function") return;
1452
1478
  const mq = window.matchMedia(`(max-width: ${breakpoint}px)`);
1453
1479
  const apply = () => setNarrow(mq.matches);
@@ -1471,11 +1497,11 @@ function Topbar({
1471
1497
  ...rest
1472
1498
  }) {
1473
1499
  const narrow = useIsNarrow(overflowBreakpoint);
1474
- const [moreOpen, setMoreOpen] = React14.useState(false);
1475
- const moreRef = React14.useRef(null);
1500
+ const [moreOpen, setMoreOpen] = React15.useState(false);
1501
+ const moreRef = React15.useRef(null);
1476
1502
  return /* @__PURE__ */ jsxs15("header", { className: ["fd-topbar", narrow ? "is-narrow" : "", className].filter(Boolean).join(" "), ...rest, children: [
1477
1503
  onMenu ? /* @__PURE__ */ jsx21("button", { type: "button", className: "fd-btn-icon", "aria-label": "Menu", onClick: onMenu, children: /* @__PURE__ */ jsx21("i", { className: "ph ph-list" }) }) : null,
1478
- /* @__PURE__ */ jsx21("nav", { className: "fd-crumb", "aria-label": "Breadcrumb", children: crumbs.map((c, i) => /* @__PURE__ */ jsxs15(React14.Fragment, { children: [
1504
+ /* @__PURE__ */ jsx21("nav", { className: "fd-crumb", "aria-label": "Breadcrumb", children: crumbs.map((c, i) => /* @__PURE__ */ jsxs15(React15.Fragment, { children: [
1479
1505
  i > 0 ? /* @__PURE__ */ jsx21("i", { className: "ph ph-caret-right", style: { fontSize: 11, opacity: 0.6 }, "aria-hidden": "true" }) : null,
1480
1506
  i === crumbs.length - 1 ? (
1481
1507
  // MP-141: the current crumb mixes a static route label with (usually) a
@@ -1528,29 +1554,37 @@ function Topbar({
1528
1554
  }
1529
1555
 
1530
1556
  // src/kits/useResponsiveRail.ts
1531
- import * as React15 from "react";
1557
+ import * as React16 from "react";
1558
+
1559
+ // src/kits/overlayLayout.ts
1560
+ var OVERLAY_BREAKPOINT = 1024;
1561
+ function useOverlayLayout() {
1562
+ return useIsNarrow(OVERLAY_BREAKPOINT);
1563
+ }
1564
+
1565
+ // src/kits/useResponsiveRail.ts
1532
1566
  function useResponsiveRail(options = {}) {
1533
- const { breakpoint = 1024, initialOpen = true, onPersist } = options;
1534
- const navRef = React15.useRef(null);
1567
+ const { breakpoint = OVERLAY_BREAKPOINT, initialOpen = true, onPersist } = options;
1568
+ const navRef = React16.useRef(null);
1535
1569
  const overlay = useIsNarrow(breakpoint);
1536
- const [open2, setOpenRaw] = React15.useState(() => overlay ? false : initialOpen);
1537
- const setOpen = React15.useCallback(
1570
+ const [open2, setOpenRaw] = React16.useState(() => overlay ? false : initialOpen);
1571
+ const setOpen = React16.useCallback(
1538
1572
  (value) => {
1539
1573
  setOpenRaw(value);
1540
1574
  if (!overlay) onPersist?.(value);
1541
1575
  },
1542
1576
  [overlay, onPersist]
1543
1577
  );
1544
- const toggle = React15.useCallback(() => setOpen(!open2), [open2, setOpen]);
1545
- const close2 = React15.useCallback(() => setOpenRaw(false), []);
1546
- const lastOverlay = React15.useRef(overlay);
1547
- React15.useEffect(() => {
1578
+ const toggle = React16.useCallback(() => setOpen(!open2), [open2, setOpen]);
1579
+ const close2 = React16.useCallback(() => setOpenRaw(false), []);
1580
+ const lastOverlay = React16.useRef(overlay);
1581
+ React16.useEffect(() => {
1548
1582
  if (lastOverlay.current === overlay) return;
1549
1583
  lastOverlay.current = overlay;
1550
1584
  setOpenRaw(!overlay);
1551
1585
  }, [overlay]);
1552
1586
  const layer = useStackedLayer({ active: overlay && open2, containerRef: navRef, trap: true, onEscape: close2 });
1553
- React15.useEffect(() => {
1587
+ React16.useEffect(() => {
1554
1588
  if (!overlay || !open2) return;
1555
1589
  const previousOverflow = document.body.style.overflow;
1556
1590
  document.body.style.overflow = "hidden";
@@ -1571,7 +1605,7 @@ function AppShell({
1571
1605
  navFooter,
1572
1606
  initialNavOpen = true,
1573
1607
  onNavOpenChange,
1574
- railBreakpoint = 1024,
1608
+ railBreakpoint = OVERLAY_BREAKPOINT,
1575
1609
  crumbs,
1576
1610
  loading,
1577
1611
  actions,
@@ -1677,20 +1711,20 @@ function installFlytedeskFavicon(url) {
1677
1711
  }
1678
1712
 
1679
1713
  // src/components/navigation/Tabs.tsx
1680
- import * as React16 from "react";
1714
+ import * as React17 from "react";
1681
1715
  import { jsx as jsx24, jsxs as jsxs18 } from "react/jsx-runtime";
1682
1716
  var FADE_WIDTH = 32;
1683
1717
  function Tabs({ tabs = [], value, onChange, className = "", ...rest }) {
1684
- const strip = React16.useRef(null);
1685
- const [more, setMore] = React16.useState({ start: false, end: false });
1686
- const measure = React16.useCallback(() => {
1718
+ const strip = React17.useRef(null);
1719
+ const [more, setMore] = React17.useState({ start: false, end: false });
1720
+ const measure = React17.useCallback(() => {
1687
1721
  const el = strip.current;
1688
1722
  if (!el) return;
1689
1723
  const start = el.scrollLeft > 1;
1690
1724
  const end = el.scrollLeft + el.clientWidth < el.scrollWidth - 1;
1691
1725
  setMore((m) => m.start === start && m.end === end ? m : { start, end });
1692
1726
  }, []);
1693
- React16.useLayoutEffect(() => {
1727
+ React17.useLayoutEffect(() => {
1694
1728
  const el = strip.current;
1695
1729
  measure();
1696
1730
  if (!el || typeof ResizeObserver === "undefined") return;
@@ -1698,7 +1732,7 @@ function Tabs({ tabs = [], value, onChange, className = "", ...rest }) {
1698
1732
  observer.observe(el);
1699
1733
  return () => observer.disconnect();
1700
1734
  }, [measure, tabs]);
1701
- const revealActive = React16.useCallback(() => {
1735
+ const revealActive = React17.useCallback(() => {
1702
1736
  const el = strip.current;
1703
1737
  const active = el?.querySelector('[aria-selected="true"]');
1704
1738
  if (!el || !active || el.scrollWidth <= el.clientWidth) return;
@@ -1708,9 +1742,9 @@ function Tabs({ tabs = [], value, onChange, className = "", ...rest }) {
1708
1742
  else if (tab.right > box.right - FADE_WIDTH) el.scrollLeft += tab.right - box.right + FADE_WIDTH;
1709
1743
  measure();
1710
1744
  }, [measure]);
1711
- React16.useLayoutEffect(revealActive, [value, revealActive]);
1745
+ React17.useLayoutEffect(revealActive, [value, revealActive]);
1712
1746
  const tabKeys = tabs.map((t) => typeof t === "string" ? t : t.value).join(",");
1713
- React16.useLayoutEffect(() => {
1747
+ React17.useLayoutEffect(() => {
1714
1748
  const el = strip.current;
1715
1749
  if (!el || typeof ResizeObserver === "undefined") return;
1716
1750
  const observer = new ResizeObserver(revealActive);
@@ -1965,15 +1999,15 @@ function Toast({ title, children, tone = "success", onUndo, onDismiss, className
1965
1999
  }
1966
2000
 
1967
2001
  // src/components/feedback/ToastProvider.tsx
1968
- import * as React17 from "react";
2002
+ import * as React18 from "react";
1969
2003
  import { jsx as jsx33, jsxs as jsxs26 } from "react/jsx-runtime";
1970
2004
  var DEFAULT_TOAST_DURATION_MS = 5e3;
1971
- var ToastContext = React17.createContext(null);
2005
+ var ToastContext = React18.createContext(null);
1972
2006
  function ToastProvider({ children }) {
1973
- const [items, setItems] = React17.useState([]);
1974
- const timers = React17.useRef(/* @__PURE__ */ new Map());
1975
- const nextId = React17.useRef(1);
1976
- const dismiss = React17.useCallback((id) => {
2007
+ const [items, setItems] = React18.useState([]);
2008
+ const timers = React18.useRef(/* @__PURE__ */ new Map());
2009
+ const nextId = React18.useRef(1);
2010
+ const dismiss = React18.useCallback((id) => {
1977
2011
  setItems((current2) => current2.filter((item) => item.id !== id));
1978
2012
  const timer = timers.current.get(id);
1979
2013
  if (timer !== void 0) {
@@ -1981,7 +2015,7 @@ function ToastProvider({ children }) {
1981
2015
  timers.current.delete(id);
1982
2016
  }
1983
2017
  }, []);
1984
- const show = React17.useCallback(
2018
+ const show = React18.useCallback(
1985
2019
  (title, options = {}) => {
1986
2020
  const { tone = "success", duration = DEFAULT_TOAST_DURATION_MS } = options;
1987
2021
  const id = nextId.current++;
@@ -1990,36 +2024,36 @@ function ToastProvider({ children }) {
1990
2024
  },
1991
2025
  [dismiss]
1992
2026
  );
1993
- React17.useEffect(() => {
2027
+ React18.useEffect(() => {
1994
2028
  const pending = timers.current;
1995
2029
  return () => {
1996
2030
  pending.forEach(clearTimeout);
1997
2031
  pending.clear();
1998
2032
  };
1999
2033
  }, []);
2000
- const api = React17.useMemo(() => ({ show }), [show]);
2034
+ const api = React18.useMemo(() => ({ show }), [show]);
2001
2035
  return /* @__PURE__ */ jsxs26(ToastContext.Provider, { value: api, children: [
2002
2036
  children,
2003
2037
  /* @__PURE__ */ jsx33(CornerStackPortal, { slot: "toasts", children: /* @__PURE__ */ jsx33("div", { className: "fd-toast-region", "aria-live": "polite", children: items.map((item) => /* @__PURE__ */ jsx33(Toast, { title: item.title, tone: item.tone, onDismiss: () => dismiss(item.id) }, item.id)) }) })
2004
2038
  ] });
2005
2039
  }
2006
2040
  function useToast() {
2007
- const api = React17.useContext(ToastContext);
2041
+ const api = React18.useContext(ToastContext);
2008
2042
  if (!api) throw new Error("useToast must be used inside a <ToastProvider>");
2009
2043
  return api;
2010
2044
  }
2011
2045
 
2012
2046
  // src/components/feedback/Tooltip.tsx
2013
- import * as React19 from "react";
2047
+ import * as React20 from "react";
2014
2048
 
2015
2049
  // src/components/feedback/useTooltip.tsx
2016
- import * as React18 from "react";
2050
+ import * as React19 from "react";
2017
2051
  import { jsx as jsx34 } from "react/jsx-runtime";
2018
2052
  var CLOSE_DELAY_MS = 120;
2019
2053
  var isMouse = (e) => e.pointerType === "mouse";
2020
2054
  function TooltipBubble({ open: open2, labels, placement, className, onHide, onEnter, onLeave }) {
2021
- const anchorRef = React18.useRef(open2.anchor);
2022
- const bubbleRef = React18.useRef(null);
2055
+ const anchorRef = React19.useRef(open2.anchor);
2056
+ const bubbleRef = React19.useRef(null);
2023
2057
  const pos = usePopoverPosition(true, anchorRef, {
2024
2058
  placement: placement === "bottom" ? "bottom-center" : "top-center",
2025
2059
  offset: 8,
@@ -2030,7 +2064,7 @@ function TooltipBubble({ open: open2, labels, placement, className, onHide, onEn
2030
2064
  });
2031
2065
  const layer = useStackedLayer({ active: true, containerRef: bubbleRef, onEscape: onHide, returnFocus: false });
2032
2066
  const zIndex = useLayerZIndex(layer);
2033
- React18.useEffect(() => {
2067
+ React19.useEffect(() => {
2034
2068
  const away = (e) => {
2035
2069
  const t = e.target;
2036
2070
  if (open2.anchor.contains(t)) return;
@@ -2061,16 +2095,16 @@ function TooltipBubble({ open: open2, labels, placement, className, onHide, onEn
2061
2095
  );
2062
2096
  }
2063
2097
  function useTooltip({ placement = "top", className = "" } = {}) {
2064
- const [open2, setOpen] = React18.useState(null);
2065
- const closeTimer = React18.useRef(null);
2066
- const focused = React18.useRef(null);
2067
- const cancelClose = React18.useCallback(() => {
2098
+ const [open2, setOpen] = React19.useState(null);
2099
+ const closeTimer = React19.useRef(null);
2100
+ const focused = React19.useRef(null);
2101
+ const cancelClose = React19.useCallback(() => {
2068
2102
  if (closeTimer.current) {
2069
2103
  clearTimeout(closeTimer.current);
2070
2104
  closeTimer.current = null;
2071
2105
  }
2072
2106
  }, []);
2073
- const hide = React18.useCallback(() => {
2107
+ const hide = React19.useCallback(() => {
2074
2108
  cancelClose();
2075
2109
  focused.current = null;
2076
2110
  setOpen(null);
@@ -2090,7 +2124,7 @@ function useTooltip({ placement = "top", className = "" } = {}) {
2090
2124
  setOpen((o) => o && o.reason === "hover" ? focused.current : o);
2091
2125
  }, CLOSE_DELAY_MS);
2092
2126
  };
2093
- React18.useEffect(() => cancelClose, [cancelClose]);
2127
+ React19.useEffect(() => cancelClose, [cancelClose]);
2094
2128
  const labels = /* @__PURE__ */ new Map();
2095
2129
  const bind = (id, label) => {
2096
2130
  labels.set(id, label);
@@ -2143,17 +2177,17 @@ function useTooltip({ placement = "top", className = "" } = {}) {
2143
2177
  // src/components/feedback/Tooltip.tsx
2144
2178
  import { jsx as jsx35, jsxs as jsxs27 } from "react/jsx-runtime";
2145
2179
  function Tooltip({ label, placement = "top", children, className = "" }) {
2146
- const id = React19.useId();
2180
+ const id = React20.useId();
2147
2181
  const descId = id + "-desc";
2148
2182
  const tip = useTooltip({ placement, className });
2149
- const described = React19.isValidElement(children) ? React19.cloneElement(children, {
2183
+ const described = React20.isValidElement(children) ? React20.cloneElement(children, {
2150
2184
  "aria-describedby": [children.props["aria-describedby"], descId].filter(Boolean).join(" ")
2151
2185
  }) : children;
2152
2186
  return /* @__PURE__ */ jsxs27(
2153
2187
  "span",
2154
2188
  {
2155
2189
  className: "fd-tooltip-anchor",
2156
- "aria-describedby": React19.isValidElement(children) ? void 0 : descId,
2190
+ "aria-describedby": React20.isValidElement(children) ? void 0 : descId,
2157
2191
  ...tip.bind(id, label),
2158
2192
  children: [
2159
2193
  described,
@@ -2165,16 +2199,16 @@ function Tooltip({ label, placement = "top", children, className = "" }) {
2165
2199
  }
2166
2200
 
2167
2201
  // src/components/data/AnimNum.tsx
2168
- import * as React20 from "react";
2202
+ import * as React21 from "react";
2169
2203
  import { Fragment as Fragment6, jsx as jsx36 } from "react/jsx-runtime";
2170
2204
  function shouldSkipEasing() {
2171
2205
  if (typeof document !== "undefined" && document.hidden) return true;
2172
2206
  return window.matchMedia?.("(prefers-reduced-motion: reduce)").matches ?? false;
2173
2207
  }
2174
2208
  function AnimNum({ value, format, duration = 550 }) {
2175
- const [display, setDisplay] = React20.useState(value);
2176
- const prev = React20.useRef(value);
2177
- React20.useEffect(() => {
2209
+ const [display, setDisplay] = React21.useState(value);
2210
+ const prev = React21.useRef(value);
2211
+ React21.useEffect(() => {
2178
2212
  const from = prev.current;
2179
2213
  const to = value;
2180
2214
  prev.current = to;
@@ -2202,14 +2236,14 @@ function AnimNum({ value, format, duration = 550 }) {
2202
2236
  }
2203
2237
 
2204
2238
  // src/components/data/TrendChart.tsx
2205
- import * as React23 from "react";
2239
+ import * as React24 from "react";
2206
2240
 
2207
2241
  // src/components/useMeasuredWidth.ts
2208
- import * as React21 from "react";
2242
+ import * as React22 from "react";
2209
2243
  function useMeasuredWidth(fallback) {
2210
- const [element, setElement] = React21.useState(null);
2211
- const [width, setWidth] = React21.useState(fallback);
2212
- React21.useLayoutEffect(() => {
2244
+ const [element, setElement] = React22.useState(null);
2245
+ const [width, setWidth] = React22.useState(fallback);
2246
+ React22.useLayoutEffect(() => {
2213
2247
  if (!element || typeof ResizeObserver === "undefined") return;
2214
2248
  const measure = () => {
2215
2249
  const measured = Math.round(element.getBoundingClientRect().width);
@@ -2224,7 +2258,7 @@ function useMeasuredWidth(fallback) {
2224
2258
  }
2225
2259
 
2226
2260
  // src/components/data/SegmentedMeter.tsx
2227
- import * as React22 from "react";
2261
+ import * as React23 from "react";
2228
2262
 
2229
2263
  // src/kits/files.ts
2230
2264
  function formatBytes(n) {
@@ -2429,7 +2463,7 @@ function SegmentedMeter({
2429
2463
  const pct = safeTotal ? Math.min(100, Math.round(used / safeTotal * 100)) : 0;
2430
2464
  const w = (v) => safeTotal ? Math.max(0, Math.min(100, Number(v) / safeTotal * 100)) : 0;
2431
2465
  const fill = (s, i) => s.color || (s.variant ? VARIANT_FILL[s.variant] : void 0) || CHART[i % CHART.length];
2432
- const generatedId = React22.useId();
2466
+ const generatedId = React23.useId();
2433
2467
  const uid2 = id || generatedId;
2434
2468
  return /* @__PURE__ */ jsxs28("div", { className: ["fd-segmeter", className].filter(Boolean).join(" "), onClick, children: [
2435
2469
  label || showTotal ? /* @__PURE__ */ jsxs28("div", { className: "fd-segmeter-head", children: [
@@ -2580,8 +2614,8 @@ function TrendChart({
2580
2614
  onRetry,
2581
2615
  className = ""
2582
2616
  }) {
2583
- const [activeId, setActiveId] = React23.useState(null);
2584
- const [pointTip, setPointTip] = React23.useState(null);
2617
+ const [activeId, setActiveId] = React24.useState(null);
2618
+ const [pointTip, setPointTip] = React24.useState(null);
2585
2619
  const isEmpty = state === "ready" && (!categories.length || !series.length || series.every((s) => !s.values.length));
2586
2620
  const effectiveState = isEmpty ? "empty" : state;
2587
2621
  const [plotRef, VBW] = useMeasuredWidth(INITIAL_WIDTH);
@@ -2695,7 +2729,7 @@ function TrendChart({
2695
2729
  }
2696
2730
 
2697
2731
  // src/components/data/DonutChart.tsx
2698
- import * as React24 from "react";
2732
+ import * as React25 from "react";
2699
2733
  import { jsx as jsx40, jsxs as jsxs31 } from "react/jsx-runtime";
2700
2734
  function DonutChart({
2701
2735
  segments,
@@ -2710,7 +2744,7 @@ function DonutChart({
2710
2744
  onRetry,
2711
2745
  className = ""
2712
2746
  }) {
2713
- const [activeId, setActiveId] = React24.useState(null);
2747
+ const [activeId, setActiveId] = React25.useState(null);
2714
2748
  const items = segments.filter((s) => Number(s.value) > 0);
2715
2749
  const total = items.reduce((n, s) => n + Number(s.value), 0);
2716
2750
  const isEmpty = state === "ready" && (!items.length || total <= 0);
@@ -2802,7 +2836,7 @@ function DonutChart({
2802
2836
  }
2803
2837
 
2804
2838
  // src/components/data/BarList.tsx
2805
- import * as React25 from "react";
2839
+ import * as React26 from "react";
2806
2840
  import { jsx as jsx41, jsxs as jsxs32 } from "react/jsx-runtime";
2807
2841
  var wholePercent = (share) => formatPercent(Math.round(share * 100));
2808
2842
  function BarList({
@@ -2819,7 +2853,7 @@ function BarList({
2819
2853
  onRetry,
2820
2854
  className = ""
2821
2855
  }) {
2822
- const ordered = React25.useMemo(() => {
2856
+ const ordered = React26.useMemo(() => {
2823
2857
  const list = sort ? [...rows].sort((a, b) => Number(b.value) - Number(a.value)) : rows;
2824
2858
  return maxRows ? list.slice(0, maxRows) : list;
2825
2859
  }, [rows, sort, maxRows]);
@@ -2961,7 +2995,7 @@ function FunnelChart({
2961
2995
  }
2962
2996
 
2963
2997
  // src/components/data/Clamp.tsx
2964
- import * as React26 from "react";
2998
+ import * as React27 from "react";
2965
2999
  import { jsx as jsx43, jsxs as jsxs34 } from "react/jsx-runtime";
2966
3000
  function Clamp({
2967
3001
  children,
@@ -2973,16 +3007,16 @@ function Clamp({
2973
3007
  onToggle,
2974
3008
  className = ""
2975
3009
  }) {
2976
- const [open2, setOpen] = React26.useState(false);
2977
- const [overflows, setOverflows] = React26.useState(false);
2978
- const bodyRef = React26.useRef(null);
2979
- const charClamped = React26.useMemo(() => {
3010
+ const [open2, setOpen] = React27.useState(false);
3011
+ const [overflows, setOverflows] = React27.useState(false);
3012
+ const bodyRef = React27.useRef(null);
3013
+ const charClamped = React27.useMemo(() => {
2980
3014
  if (open2 || !maxChars || typeof text !== "string" || text.length <= maxChars) return null;
2981
3015
  const cut = text.slice(0, maxChars);
2982
3016
  const at = cut.lastIndexOf(" ");
2983
3017
  return (at > maxChars * 0.6 ? cut.slice(0, at) : cut).trimEnd() + "\u2026";
2984
3018
  }, [text, maxChars, open2]);
2985
- React26.useLayoutEffect(() => {
3019
+ React27.useLayoutEffect(() => {
2986
3020
  const node = bodyRef.current;
2987
3021
  if (maxChars || !node || !maxHeight) return;
2988
3022
  const measure = () => {
@@ -3240,16 +3274,16 @@ function StackedRows({ columns, rows, rowKey, loading, stale, skeletonRows, sort
3240
3274
  }
3241
3275
 
3242
3276
  // src/components/data/FilterBar.tsx
3243
- import * as React32 from "react";
3277
+ import * as React33 from "react";
3244
3278
 
3245
3279
  // src/components/forms/NumberInput.tsx
3246
- import * as React29 from "react";
3280
+ import * as React30 from "react";
3247
3281
 
3248
3282
  // src/components/forms/field.tsx
3249
- import * as React27 from "react";
3283
+ import * as React28 from "react";
3250
3284
  import { jsx as jsx46, jsxs as jsxs37 } from "react/jsx-runtime";
3251
3285
  function useFieldId(id) {
3252
- const generated = React27.useId();
3286
+ const generated = React28.useId();
3253
3287
  return id || generated;
3254
3288
  }
3255
3289
  function FieldLabel({ htmlFor, id, required = false, onClick, children }) {
@@ -3268,10 +3302,10 @@ function HiddenFieldLabel({ id, children }) {
3268
3302
  }
3269
3303
 
3270
3304
  // src/components/useLatest.ts
3271
- import * as React28 from "react";
3305
+ import * as React29 from "react";
3272
3306
  function useLatest(value) {
3273
- const ref = React28.useRef(value);
3274
- React28.useInsertionEffect(() => {
3307
+ const ref = React29.useRef(value);
3308
+ React29.useInsertionEffect(() => {
3275
3309
  ref.current = value;
3276
3310
  });
3277
3311
  return ref;
@@ -3354,20 +3388,20 @@ function NumberInput({
3354
3388
  const n = typeof v === "number" ? v : parseNumberText(v);
3355
3389
  return n == null || Number.isNaN(n) ? null : n;
3356
3390
  };
3357
- const [text, setText] = React29.useState(() => toText(value));
3358
- const [editing, setEditing] = React29.useState(false);
3391
+ const [text, setText] = React30.useState(() => toText(value));
3392
+ const [editing, setEditing] = React30.useState(false);
3359
3393
  const parsed = parseNumberText(text);
3360
3394
  const invalidMessage = parsed == null ? null : Number.isNaN(parsed) ? "Enter a number" : integer && !Number.isInteger(parsed) ? "Enter a whole number" : parsed < lo ? "Must be \u2265 " + lo : parsed > hi ? "Must be \u2264 " + hi : null;
3361
3395
  const valid = invalidMessage == null;
3362
- const committedRef = React29.useRef(toNumber(value));
3396
+ const committedRef = React30.useRef(toNumber(value));
3363
3397
  const onChangeRef = useLatest(onChange);
3364
3398
  const onValidityChangeRef = useLatest(onValidityChange);
3365
- const focusedRef = React29.useRef(false);
3366
- React29.useEffect(() => {
3399
+ const focusedRef = React30.useRef(false);
3400
+ React30.useEffect(() => {
3367
3401
  committedRef.current = toNumber(value);
3368
3402
  if (!focusedRef.current) setText(toText(value));
3369
3403
  }, [value]);
3370
- React29.useLayoutEffect(() => {
3404
+ React30.useLayoutEffect(() => {
3371
3405
  onValidityChangeRef.current?.(valid);
3372
3406
  }, [valid, onValidityChangeRef]);
3373
3407
  const fire = (n) => {
@@ -3383,7 +3417,7 @@ function NumberInput({
3383
3417
  return true;
3384
3418
  };
3385
3419
  const bumpRef = useLatest(bump);
3386
- const holdTimer = React29.useRef(null);
3420
+ const holdTimer = React30.useRef(null);
3387
3421
  const release2 = () => {
3388
3422
  if (holdTimer.current) clearTimeout(holdTimer.current);
3389
3423
  holdTimer.current = null;
@@ -3402,7 +3436,7 @@ function NumberInput({
3402
3436
  };
3403
3437
  holdTimer.current = setTimeout(tick, HOLD_DELAY_MS);
3404
3438
  };
3405
- React29.useEffect(() => () => {
3439
+ React30.useEffect(() => () => {
3406
3440
  if (holdTimer.current) clearTimeout(holdTimer.current);
3407
3441
  }, []);
3408
3442
  const current2 = committedRef.current;
@@ -3505,7 +3539,7 @@ function NumberInput({
3505
3539
  }
3506
3540
 
3507
3541
  // src/components/forms/DatePicker.tsx
3508
- import * as React30 from "react";
3542
+ import * as React31 from "react";
3509
3543
  import { jsx as jsx48, jsxs as jsxs39 } from "react/jsx-runtime";
3510
3544
  var MONTHS = ["January", "February", "March", "April", "May", "June", "July", "August", "September", "October", "November", "December"];
3511
3545
  var DOW = ["Su", "Mo", "Tu", "We", "Th", "Fr", "Sa"];
@@ -3538,10 +3572,10 @@ function Calendar({ value, range = false, onPick, initialMonth, months = 1 }) {
3538
3572
  const today = /* @__PURE__ */ new Date();
3539
3573
  const sel = range ? value || {} : { start: value, end: value };
3540
3574
  const anchor = parse(sel.start) || parse(initialMonth) || today;
3541
- const [vy, setVy] = React30.useState(anchor.getFullYear());
3542
- const [vm, setVm] = React30.useState(anchor.getMonth());
3543
- const [mode2, setMode] = React30.useState("days");
3544
- const [hover, setHover] = React30.useState(null);
3575
+ const [vy, setVy] = React31.useState(anchor.getFullYear());
3576
+ const [vm, setVm] = React31.useState(anchor.getMonth());
3577
+ const [mode2, setMode] = React31.useState("days");
3578
+ const [hover, setHover] = React31.useState(null);
3545
3579
  const s = parse(sel.start), e = parse(sel.end);
3546
3580
  const hoverEnd = range && s && !e && hover ? parse(hover) : null;
3547
3581
  const inRange = (d) => {
@@ -3552,12 +3586,12 @@ function Calendar({ value, range = false, onPick, initialMonth, months = 1 }) {
3552
3586
  const isEnd = (d) => !!e && iso(d) === iso(e);
3553
3587
  const isEdge = (d) => isStart(d) || isEnd(d);
3554
3588
  const nextY = vm === 11 ? vy + 1 : vy, nextM = (vm + 1) % 12;
3555
- const [activeDate, setActiveDate] = React30.useState(() => {
3589
+ const [activeDate, setActiveDate] = React31.useState(() => {
3556
3590
  if (s) return s;
3557
3591
  if (sameMonth(today, anchor.getFullYear(), anchor.getMonth())) return today;
3558
3592
  return new Date(anchor.getFullYear(), anchor.getMonth(), 1);
3559
3593
  });
3560
- const calRef = React30.useRef(null);
3594
+ const calRef = React31.useRef(null);
3561
3595
  const pageToShow = (y, m) => {
3562
3596
  const idx = y * 12 + m, firstIdx = vy * 12 + vm, secondIdx = firstIdx + 1;
3563
3597
  if (idx === firstIdx || months > 1 && idx === secondIdx) return;
@@ -3574,7 +3608,7 @@ function Calendar({ value, range = false, onPick, initialMonth, months = 1 }) {
3574
3608
  setActiveDate(next);
3575
3609
  pageToShow(next.getFullYear(), next.getMonth());
3576
3610
  };
3577
- React30.useEffect(() => {
3611
+ React31.useEffect(() => {
3578
3612
  const el = calRef.current?.querySelector('[data-iso="' + iso(activeDate) + '"]');
3579
3613
  if (el) el.focus({ preventScroll: true });
3580
3614
  }, [activeDate, vy, vm]);
@@ -3767,9 +3801,9 @@ function Calendar({ value, range = false, onPick, initialMonth, months = 1 }) {
3767
3801
  }
3768
3802
  function DatePicker({ label, help, error, required = false, disabled = false, range = false, value, onChange, placeholder, id, className = "", style, "aria-label": hiddenLabel, ...rest }) {
3769
3803
  const { fieldId, labelId, ariaLabelledBy } = useTriggerLabelling(label, id, hiddenLabel);
3770
- const [open2, setOpen] = React30.useState(false);
3771
- const rootRef = React30.useRef(null);
3772
- const boxRef = React30.useRef(null);
3804
+ const [open2, setOpen] = React31.useState(false);
3805
+ const rootRef = React31.useRef(null);
3806
+ const boxRef = React31.useRef(null);
3773
3807
  const display = range ? value && value.start ? fmt(value.start) + (value.end ? " \u2192 " + fmt(value.end) : " \u2192 \u2026") : "" : fmt(value);
3774
3808
  const toggle = () => {
3775
3809
  if (!disabled) setOpen(!open2);
@@ -3858,9 +3892,9 @@ function Textarea({ label, help, error, required = false, rows = 4, disabled = f
3858
3892
  }
3859
3893
 
3860
3894
  // src/components/forms/listbox.ts
3861
- import * as React31 from "react";
3895
+ import * as React32 from "react";
3862
3896
  function useListboxNav({ count, onSelect }) {
3863
- const [active, setActive] = React31.useState(-1);
3897
+ const [active, setActive] = React32.useState(-1);
3864
3898
  return {
3865
3899
  active,
3866
3900
  setActive,
@@ -3873,7 +3907,7 @@ function useListboxNav({ count, onSelect }) {
3873
3907
  };
3874
3908
  }
3875
3909
  function useListboxScrollIntoView(active, listRef, enabled) {
3876
- React31.useEffect(() => {
3910
+ React32.useEffect(() => {
3877
3911
  if (!enabled || active < 0 || !listRef.current) return;
3878
3912
  const list = listRef.current;
3879
3913
  const el = list.querySelector('[data-i="' + active + '"]');
@@ -3891,7 +3925,7 @@ import { jsx as jsx50, jsxs as jsxs41 } from "react/jsx-runtime";
3891
3925
  var TAIL_CHARS = 12;
3892
3926
  var graphemes = new Intl.Segmenter(void 0, { granularity: "grapheme" });
3893
3927
  function splitForMiddleEllipsis(text) {
3894
- const chars = Array.from(graphemes.segment(text), (part) => part.segment);
3928
+ const chars = Array.from(graphemes.segment(text), (part2) => part2.segment);
3895
3929
  if (chars.length <= TAIL_CHARS) return { head: text, tail: "" };
3896
3930
  return { head: chars.slice(0, -TAIL_CHARS).join(""), tail: chars.slice(-TAIL_CHARS).join("") };
3897
3931
  }
@@ -4094,13 +4128,13 @@ function MultiSelectPanel({
4094
4128
  onClose
4095
4129
  }) {
4096
4130
  const allowedOps = operatorsFor(field);
4097
- const [draftOperator, setDraftOperator] = React32.useState(value?.operator ?? allowedOps[0]);
4131
+ const [draftOperator, setDraftOperator] = React33.useState(value?.operator ?? allowedOps[0]);
4098
4132
  const operator = allowedOps.length === 1 ? allowedOps[0] : value?.operator ?? draftOperator;
4099
4133
  const selected = value?.values ?? [];
4100
4134
  const selectedRef = useLatest(selected);
4101
4135
  const operatorRef = useLatest(operator);
4102
- const mountedRef = React32.useRef(true);
4103
- React32.useEffect(() => {
4136
+ const mountedRef = React33.useRef(true);
4137
+ React33.useEffect(() => {
4104
4138
  mountedRef.current = true;
4105
4139
  return () => {
4106
4140
  mountedRef.current = false;
@@ -4114,20 +4148,20 @@ function MultiSelectPanel({
4114
4148
  if (selectedRef.current.length > 0) commit(selectedRef.current, op);
4115
4149
  else setDraftOperator(op);
4116
4150
  };
4117
- const [mode2, setMode] = React32.useState("search");
4118
- const [query, setQuery] = React32.useState("");
4119
- const [asyncState, setAsyncState] = React32.useState(
4151
+ const [mode2, setMode] = React33.useState("search");
4152
+ const [query, setQuery] = React33.useState("");
4153
+ const [asyncState, setAsyncState] = React33.useState(
4120
4154
  { options: null, loading: !!field.loadOptions, error: false }
4121
4155
  );
4122
- const [retryTick, setRetryTick] = React32.useState(0);
4123
- const inputRef = React32.useRef(null);
4124
- const listRef = React32.useRef(null);
4125
- const listId = React32.useId();
4156
+ const [retryTick, setRetryTick] = React33.useState(0);
4157
+ const inputRef = React33.useRef(null);
4158
+ const listRef = React33.useRef(null);
4159
+ const listId = React33.useId();
4126
4160
  const loadOptionsRef = useLatest(field.loadOptions);
4127
- React32.useEffect(() => {
4161
+ React33.useEffect(() => {
4128
4162
  inputRef.current?.focus();
4129
4163
  }, []);
4130
- React32.useEffect(() => {
4164
+ React33.useEffect(() => {
4131
4165
  const load = loadOptionsRef.current;
4132
4166
  if (!load) return;
4133
4167
  const controller = new AbortController();
@@ -4160,17 +4194,17 @@ function MultiSelectPanel({
4160
4194
  };
4161
4195
  const nav = useListboxNav({ count: options.length, onSelect: (i) => toggle(options[i]) });
4162
4196
  useListboxScrollIntoView(nav.active, listRef, hasListbox);
4163
- React32.useEffect(() => {
4197
+ React33.useEffect(() => {
4164
4198
  nav.setActive(0);
4165
4199
  }, [query, options.length]);
4166
4200
  const activeId = hasListbox && options[nav.active] ? listId + "-opt-" + nav.active : void 0;
4167
4201
  const liveMessage = showLoading ? "Loading\u2026" : showError ? "Couldn't load options." : options.length === 0 ? query === "" && field.emptyText || "No matches" : atLimit ? "Limit reached: at most " + field.maxValues + " values" : "";
4168
- const [pasteText, setPasteText] = React32.useState("");
4169
- const [pasteLoading, setPasteLoading] = React32.useState(false);
4170
- const [unmatchedTokens, setUnmatchedTokens] = React32.useState([]);
4171
- const [pasteError, setPasteError] = React32.useState(null);
4172
- const pasteWrapRef = React32.useRef(null);
4173
- React32.useEffect(() => {
4202
+ const [pasteText, setPasteText] = React33.useState("");
4203
+ const [pasteLoading, setPasteLoading] = React33.useState(false);
4204
+ const [unmatchedTokens, setUnmatchedTokens] = React33.useState([]);
4205
+ const [pasteError, setPasteError] = React33.useState(null);
4206
+ const pasteWrapRef = React33.useRef(null);
4207
+ React33.useEffect(() => {
4174
4208
  if (mode2 === "paste") pasteWrapRef.current?.querySelector("textarea")?.focus();
4175
4209
  }, [mode2]);
4176
4210
  const doResolve = () => {
@@ -4343,8 +4377,8 @@ function MultiSelectPanel({
4343
4377
  );
4344
4378
  }
4345
4379
  function useTextValidity(onFlip) {
4346
- const invalidRef = React32.useRef(/* @__PURE__ */ new Set());
4347
- const [, rerender] = React32.useReducer((n) => n + 1, 0);
4380
+ const invalidRef = React33.useRef(/* @__PURE__ */ new Set());
4381
+ const [, rerender] = React33.useReducer((n) => n + 1, 0);
4348
4382
  const onFlipRef = useLatest(onFlip);
4349
4383
  const record = (name, valid) => {
4350
4384
  const invalid = invalidRef.current;
@@ -4387,15 +4421,15 @@ function sameValue(a, b) {
4387
4421
  return true;
4388
4422
  }
4389
4423
  function useReseedFromProps(value, applies, reseed) {
4390
- const seen = React32.useRef(value);
4391
- React32.useLayoutEffect(() => {
4424
+ const seen = React33.useRef(value);
4425
+ React33.useLayoutEffect(() => {
4392
4426
  if (seen.current === value) return;
4393
4427
  seen.current = value;
4394
4428
  if (!sameValue(value, applies())) reseed(value);
4395
4429
  }, [value, applies, reseed]);
4396
4430
  }
4397
4431
  function usePreserveFocusAcrossRemount(seed, fields) {
4398
- const pendingName = React32.useRef(null);
4432
+ const pendingName = React33.useRef(null);
4399
4433
  const fieldsRef = useLatest(fields);
4400
4434
  const capture = () => {
4401
4435
  const active = document.activeElement;
@@ -4408,7 +4442,7 @@ function usePreserveFocusAcrossRemount(seed, fields) {
4408
4442
  }
4409
4443
  }
4410
4444
  };
4411
- React32.useLayoutEffect(() => {
4445
+ React33.useLayoutEffect(() => {
4412
4446
  const name = pendingName.current;
4413
4447
  if (!name) return;
4414
4448
  pendingName.current = null;
@@ -4424,14 +4458,14 @@ function RangePanel({
4424
4458
  onCommit,
4425
4459
  onClose
4426
4460
  }) {
4427
- const [draft, setDraft] = React32.useState(() => rangeDraft(value));
4428
- const [seed, setSeed] = React32.useState(0);
4429
- const minId = React32.useId();
4430
- const maxId = React32.useId();
4431
- const minWrapRef = React32.useRef(null);
4432
- const maxWrapRef = React32.useRef(null);
4461
+ const [draft, setDraft] = React33.useState(() => rangeDraft(value));
4462
+ const [seed, setSeed] = React33.useState(0);
4463
+ const minId = React33.useId();
4464
+ const maxId = React33.useId();
4465
+ const minWrapRef = React33.useRef(null);
4466
+ const maxWrapRef = React33.useRef(null);
4433
4467
  const preserveFocus = usePreserveFocusAcrossRemount(seed, { min: minWrapRef, max: maxWrapRef });
4434
- const draftRef = React32.useRef(draft);
4468
+ const draftRef = React33.useRef(draft);
4435
4469
  const shown = () => {
4436
4470
  const { min, max } = draftRef.current;
4437
4471
  return applicable(field, min == null && max == null ? void 0 : { min, max }, validity.allValid());
@@ -4523,15 +4557,15 @@ function DatePanel({
4523
4557
  onClose
4524
4558
  }) {
4525
4559
  const maxDays = effectiveMaxDays(field);
4526
- const [initial] = React32.useState(() => dateDraft(field, value));
4527
- const [kind, setKind] = React32.useState(initial.kind);
4528
- const [daysDraft, setDaysDraft] = React32.useState(initial.days);
4529
- const daysRef = React32.useRef(daysDraft);
4530
- const daysConfirmed = React32.useRef(value?.kind === "withinDays");
4531
- const [between, setBetween] = React32.useState(initial.between);
4532
- const [seed, setSeed] = React32.useState(0);
4533
- const daysId = React32.useId();
4534
- const daysWrapRef = React32.useRef(null);
4560
+ const [initial] = React33.useState(() => dateDraft(field, value));
4561
+ const [kind, setKind] = React33.useState(initial.kind);
4562
+ const [daysDraft, setDaysDraft] = React33.useState(initial.days);
4563
+ const daysRef = React33.useRef(daysDraft);
4564
+ const daysConfirmed = React33.useRef(value?.kind === "withinDays");
4565
+ const [between, setBetween] = React33.useState(initial.between);
4566
+ const [seed, setSeed] = React33.useState(0);
4567
+ const daysId = React33.useId();
4568
+ const daysWrapRef = React33.useRef(null);
4535
4569
  const preserveFocus = usePreserveFocusAcrossRemount(seed, { days: daysWrapRef });
4536
4570
  const shownWithinDays = () => {
4537
4571
  const days = daysRef.current;
@@ -4649,11 +4683,11 @@ function FilterButton({ children, ...rest }) {
4649
4683
  ] });
4650
4684
  }
4651
4685
  function FilterBar({ fields = [], filters, onFilterChange, onFilterRemove, align = "left", actions, onClearAll, showActiveCount = false, loading = false, loadingLabel = "Loading the filters", className = "", ...rest }) {
4652
- const [panel, setPanel] = React32.useState(null);
4653
- const editAnchorRef = React32.useRef(null);
4654
- const addAnchorRef = React32.useRef(null);
4655
- const textInputRef = React32.useRef(null);
4656
- const optionsRef = React32.useRef(null);
4686
+ const [panel, setPanel] = React33.useState(null);
4687
+ const editAnchorRef = React33.useRef(null);
4688
+ const addAnchorRef = React33.useRef(null);
4689
+ const textInputRef = React33.useRef(null);
4690
+ const optionsRef = React33.useRef(null);
4657
4691
  if (process.env.NODE_ENV !== "production") {
4658
4692
  for (const f of fields) assertValidFieldDefinition(f);
4659
4693
  }
@@ -4676,7 +4710,7 @@ function FilterBar({ fields = [], filters, onFilterChange, onFilterRemove, align
4676
4710
  const editingField = panel && panel.kind === "edit" ? fields.find((f) => f.key === panel.key) : void 0;
4677
4711
  const startEditing = (key) => setPanel({ kind: "edit", key });
4678
4712
  const closeEditing = () => setPanel(null);
4679
- React32.useEffect(() => {
4713
+ React33.useEffect(() => {
4680
4714
  if (!panel || panel.kind !== "edit") return;
4681
4715
  if (editingField?.type === "text") {
4682
4716
  textInputRef.current?.focus();
@@ -4931,10 +4965,10 @@ function StatTile(props) {
4931
4965
  }
4932
4966
 
4933
4967
  // src/components/data/CodeBlock.tsx
4934
- import * as React34 from "react";
4968
+ import * as React35 from "react";
4935
4969
 
4936
4970
  // src/kits/clipboard.ts
4937
- import * as React33 from "react";
4971
+ import * as React34 from "react";
4938
4972
  var COPIED_FEEDBACK_MS = 1600;
4939
4973
  function copyThroughSelection(text) {
4940
4974
  const previouslyFocused = document.activeElement instanceof HTMLElement ? document.activeElement : null;
@@ -4964,17 +4998,17 @@ async function copyToClipboard(text) {
4964
4998
  return copyThroughSelection(text);
4965
4999
  }
4966
5000
  function useCopyToClipboard() {
4967
- const [copied, setCopied] = React33.useState(false);
4968
- const timer = React33.useRef(null);
4969
- const mounted = React33.useRef(true);
4970
- React33.useEffect(() => {
5001
+ const [copied, setCopied] = React34.useState(false);
5002
+ const timer = React34.useRef(null);
5003
+ const mounted = React34.useRef(true);
5004
+ React34.useEffect(() => {
4971
5005
  mounted.current = true;
4972
5006
  return () => {
4973
5007
  mounted.current = false;
4974
5008
  if (timer.current) clearTimeout(timer.current);
4975
5009
  };
4976
5010
  }, []);
4977
- const copy = React33.useCallback(async (text) => {
5011
+ const copy = React34.useCallback(async (text) => {
4978
5012
  const ok = await copyToClipboard(text);
4979
5013
  if (ok && mounted.current) {
4980
5014
  setCopied(true);
@@ -5142,7 +5176,7 @@ function tokenize(src, lang) {
5142
5176
  return out;
5143
5177
  }
5144
5178
  function Highlighted({ code, lang }) {
5145
- const toks = React34.useMemo(() => tokenize(code, lang), [code, lang]);
5179
+ const toks = React35.useMemo(() => tokenize(code, lang), [code, lang]);
5146
5180
  return /* @__PURE__ */ jsx54(Fragment9, { children: toks.map((tk, i) => tk.c ? /* @__PURE__ */ jsx54("span", { className: "tok-" + tk.c, children: tk.t }, i) : tk.t) });
5147
5181
  }
5148
5182
  function CodeBlock({
@@ -5156,8 +5190,8 @@ function CodeBlock({
5156
5190
  actions,
5157
5191
  className = ""
5158
5192
  }) {
5159
- const [wrap, setWrap] = React34.useState(!!wrapDefault);
5160
- const [open2, setOpen] = React34.useState(false);
5193
+ const [wrap, setWrap] = React35.useState(!!wrapDefault);
5194
+ const [open2, setOpen] = React35.useState(false);
5161
5195
  const [copied, copy] = useCopyToClipboard();
5162
5196
  const body = String(code).replace(/\n$/, "");
5163
5197
  const lines = body.split("\n");
@@ -5186,7 +5220,7 @@ function CodeBlock({
5186
5220
  ] });
5187
5221
  }
5188
5222
  function DiffBlock({ diff = "", filename, collapseAfter = 34, className = "" }) {
5189
- const [open2, setOpen] = React34.useState(false);
5223
+ const [open2, setOpen] = React35.useState(false);
5190
5224
  const [copied, copy] = useCopyToClipboard();
5191
5225
  const raw = String(diff).replace(/\n$/, "");
5192
5226
  const all = raw.split("\n").map((line) => {
@@ -5232,7 +5266,7 @@ function DiffBlock({ diff = "", filename, collapseAfter = 34, className = "" })
5232
5266
  }
5233
5267
 
5234
5268
  // src/components/data/Markdown.tsx
5235
- import * as React35 from "react";
5269
+ import * as React36 from "react";
5236
5270
  import { jsx as jsx55, jsxs as jsxs45 } from "react/jsx-runtime";
5237
5271
  var SAFE = /^(?:https?:|mailto:|tel:|#|\/|\.{1,2}\/)/i;
5238
5272
  var safeHref = (h) => SAFE.test(String(h || "").trim()) ? String(h).trim() : null;
@@ -5275,7 +5309,7 @@ function hiddenInlineNodes(hidden, ctx, keyBase) {
5275
5309
  const href = safeHref(d(g(2)));
5276
5310
  out.push(href ? /* @__PURE__ */ jsx55("a", { href, title: g(3) ? d(g(3)) : void 0, target: /^https?:/i.test(href) ? "_blank" : void 0, rel: "noopener noreferrer", onClick: ctx.onLinkClick, children: hiddenInlineNodes(g(1), ctx, key()) }, key()) : /* @__PURE__ */ jsx55("span", { children: d(g(1)) }, key()));
5277
5311
  } else if (kind === "cite") {
5278
- out.push(ctx.renderCitation ? /* @__PURE__ */ jsx55(React35.Fragment, { children: ctx.renderCitation(d(g(1))) }, key()) : /* @__PURE__ */ jsx55("sup", { className: "fd-md-cite", children: d(g(1)) }, key()));
5312
+ out.push(ctx.renderCitation ? /* @__PURE__ */ jsx55(React36.Fragment, { children: ctx.renderCitation(d(g(1))) }, key()) : /* @__PURE__ */ jsx55("sup", { className: "fd-md-cite", children: d(g(1)) }, key()));
5279
5313
  } else if (kind === "strongem") out.push(/* @__PURE__ */ jsx55("strong", { children: /* @__PURE__ */ jsx55("em", { children: hiddenInlineNodes(g(1), ctx, key()) }) }, key()));
5280
5314
  else if (kind === "strong") out.push(/* @__PURE__ */ jsx55("strong", { children: hiddenInlineNodes(g(1) || g(2), ctx, key()) }, key()));
5281
5315
  else if (kind === "em") out.push(/* @__PURE__ */ jsx55("em", { children: hiddenInlineNodes(g(1) || g(2), ctx, key()) }, key()));
@@ -5462,7 +5496,7 @@ function Markdown({
5462
5496
  tone = "default"
5463
5497
  }) {
5464
5498
  const ctx = { allowImages, headingOffset, renderCitation, onLinkClick, codeProps };
5465
- const blocks = React35.useMemo(() => parseBlocks(source), [source]);
5499
+ const blocks = React36.useMemo(() => parseBlocks(source), [source]);
5466
5500
  return /* @__PURE__ */ jsx55("div", { className: mdClass("fd-md", size, tone, className), children: renderBlocks(blocks, ctx, "b") });
5467
5501
  }
5468
5502
  function MarkdownInline({ source = "", className = "", onLinkClick, size, tone }) {
@@ -5573,7 +5607,7 @@ function Pagination({
5573
5607
  }
5574
5608
 
5575
5609
  // src/components/data/RelativeTime.tsx
5576
- import * as React36 from "react";
5610
+ import * as React37 from "react";
5577
5611
  import { jsxs as jsxs48 } from "react/jsx-runtime";
5578
5612
  var MIN = 6e4;
5579
5613
  var HOUR = 36e5;
@@ -5625,9 +5659,9 @@ function formatDuration(ms) {
5625
5659
  return h + "h" + (m % 60 ? " " + m % 60 + "m" : "");
5626
5660
  }
5627
5661
  function RelativeTime({ value, prefix, className = "", refresh: refresh2 = true, ...rest }) {
5628
- const [, force] = React36.useState(0);
5662
+ const [, force] = React37.useState(0);
5629
5663
  const t = value instanceof Date ? value.getTime() : Date.parse(value);
5630
- React36.useEffect(() => {
5664
+ React37.useEffect(() => {
5631
5665
  if (!refresh2 || !t || isNaN(t)) return;
5632
5666
  const abs = Math.abs(t - Date.now());
5633
5667
  if (abs > DAY) return;
@@ -5643,7 +5677,7 @@ function RelativeTime({ value, prefix, className = "", refresh: refresh2 = true,
5643
5677
  }
5644
5678
 
5645
5679
  // src/components/data/ScoreMeter.tsx
5646
- import * as React37 from "react";
5680
+ import * as React38 from "react";
5647
5681
  import { jsx as jsx58, jsxs as jsxs49 } from "react/jsx-runtime";
5648
5682
  function ScoreMeter({
5649
5683
  score,
@@ -5658,10 +5692,10 @@ function ScoreMeter({
5658
5692
  breakdownWidth = 280,
5659
5693
  className = ""
5660
5694
  }) {
5661
- const [open2, setOpen] = React37.useState(false);
5662
- const ref = React37.useRef(null);
5695
+ const [open2, setOpen] = React38.useState(false);
5696
+ const ref = React38.useRef(null);
5663
5697
  const value = Math.max(0, Math.min(100, Math.round(Number(score) || 0)));
5664
- const body = /* @__PURE__ */ jsxs49(React37.Fragment, { children: [
5698
+ const body = /* @__PURE__ */ jsxs49(React38.Fragment, { children: [
5665
5699
  /* @__PURE__ */ jsx58("span", { className: "fd-scoremeter-rail", style: { width }, "aria-hidden": "true", children: /* @__PURE__ */ jsx58(SegmentedMeter, { total: 100, segments, height, showTotal: false, showPercent: false, legend: false }) }),
5666
5700
  showScore ? /* @__PURE__ */ jsx58("span", { className: "fd-scoremeter-value fd-tabular", "aria-hidden": "true", children: value }) : null
5667
5701
  ] });
@@ -5680,7 +5714,7 @@ function ScoreMeter({
5680
5714
  }
5681
5715
  );
5682
5716
  }
5683
- return /* @__PURE__ */ jsxs49(React37.Fragment, { children: [
5717
+ return /* @__PURE__ */ jsxs49(React38.Fragment, { children: [
5684
5718
  /* @__PURE__ */ jsx58(
5685
5719
  "button",
5686
5720
  {
@@ -5711,11 +5745,11 @@ function ScoreMeter({
5711
5745
  }
5712
5746
 
5713
5747
  // src/components/actions/inlinePanel.tsx
5714
- import * as React38 from "react";
5748
+ import * as React39 from "react";
5715
5749
  import { jsx as jsx59 } from "react/jsx-runtime";
5716
5750
  function useInlinePanel() {
5717
- const [open2, setOpen] = React38.useState(false);
5718
- const ref = React38.useRef(null);
5751
+ const [open2, setOpen] = React39.useState(false);
5752
+ const ref = React39.useRef(null);
5719
5753
  return { open: open2, setOpen, ref };
5720
5754
  }
5721
5755
  function InlinePanelSurface({ panel, align = "right", ...popover }) {
@@ -5886,7 +5920,7 @@ function SortMenu({
5886
5920
  }
5887
5921
 
5888
5922
  // src/components/data/StepList.tsx
5889
- import * as React39 from "react";
5923
+ import * as React40 from "react";
5890
5924
  import { jsx as jsx61, jsxs as jsxs51 } from "react/jsx-runtime";
5891
5925
  var KIND_ICON = { tool: "wrench", search: "magnifying-glass", read: "file-text", write: "pencil-simple", reasoning: "brain", run: "terminal", fetch: "cloud-arrow-down" };
5892
5926
  function StepList({
@@ -5900,9 +5934,9 @@ function StepList({
5900
5934
  className = "",
5901
5935
  active = false
5902
5936
  }) {
5903
- const [openState, setOpenState] = React39.useState(defaultOpen);
5937
+ const [openState, setOpenState] = React40.useState(defaultOpen);
5904
5938
  const open2 = openProp == null ? openState : openProp;
5905
- const [expanded, setExpanded] = React39.useState({});
5939
+ const [expanded, setExpanded] = React40.useState({});
5906
5940
  if (!steps.length) return null;
5907
5941
  const running = steps.some((s) => s.status === "running");
5908
5942
  const failed = steps.filter((s) => s.status === "error").length;
@@ -5960,7 +5994,7 @@ function StepList({
5960
5994
  }
5961
5995
 
5962
5996
  // src/components/data/VirtualList.tsx
5963
- import * as React40 from "react";
5997
+ import * as React41 from "react";
5964
5998
  import { jsx as jsx62, jsxs as jsxs52 } from "react/jsx-runtime";
5965
5999
  var VIRTUAL_LIST_BUFFER_ROWS = 20;
5966
6000
  var VIRTUAL_LIST_ROW_GAP = 6;
@@ -6012,35 +6046,35 @@ function VirtualList({
6012
6046
  className = "",
6013
6047
  style
6014
6048
  }) {
6015
- const [scrollTop, setScrollTop] = React40.useState(0);
6016
- const loaded = React40.useMemo(
6049
+ const [scrollTop, setScrollTop] = React41.useState(0);
6050
+ const loaded = React41.useMemo(
6017
6051
  () => ({ firstItemIndex, count: items.length }),
6018
6052
  [firstItemIndex, items.length]
6019
6053
  );
6020
6054
  const total = Math.max(totalCount == null ? 0 : totalCount, firstItemIndex + items.length);
6021
6055
  const bandKey = firstItemIndex + ":" + items.length;
6022
- const win = React40.useMemo(
6056
+ const win = React41.useMemo(
6023
6057
  () => computeVirtualWindow({ scrollTop, viewportHeight: height, itemHeight, itemCount: total, loaded }),
6024
6058
  [scrollTop, height, itemHeight, total, loaded]
6025
6059
  );
6026
- const need = React40.useMemo(() => computeNeedMore(win, loaded), [win, loaded]);
6060
+ const need = React41.useMemo(() => computeNeedMore(win, loaded), [win, loaded]);
6027
6061
  const wantStart = need.start && hasMore?.start !== false;
6028
6062
  const wantEnd = need.end && hasMore?.end !== false;
6029
6063
  const bucket2 = Math.floor(win.visibleStart / VIRTUAL_LIST_BUFFER_ROWS);
6030
6064
  const askKey = bandKey + "@" + bucket2;
6031
- const asked = React40.useRef({ start: null, end: null });
6032
- React40.useEffect(() => {
6065
+ const asked = React41.useRef({ start: null, end: null });
6066
+ React41.useEffect(() => {
6033
6067
  if (loading || !wantStart || asked.current.start === askKey) return;
6034
6068
  asked.current.start = askKey;
6035
6069
  onNeedMore("start", win);
6036
6070
  }, [wantStart, loading, askKey, onNeedMore, win]);
6037
- React40.useEffect(() => {
6071
+ React41.useEffect(() => {
6038
6072
  if (loading || !wantEnd || asked.current.end === askKey) return;
6039
6073
  asked.current.end = askKey;
6040
6074
  onNeedMore("end", win);
6041
6075
  }, [wantEnd, loading, askKey, onNeedMore, win]);
6042
- const lastKeysRef = React40.useRef(null);
6043
- const newKeys = React40.useMemo(() => {
6076
+ const lastKeysRef = React41.useRef(null);
6077
+ const newKeys = React41.useMemo(() => {
6044
6078
  const prev = lastKeysRef.current;
6045
6079
  if (!prev) return /* @__PURE__ */ new Set();
6046
6080
  const fresh = /* @__PURE__ */ new Set();
@@ -6050,7 +6084,7 @@ function VirtualList({
6050
6084
  }
6051
6085
  return fresh;
6052
6086
  }, [items]);
6053
- React40.useEffect(() => {
6087
+ React41.useEffect(() => {
6054
6088
  lastKeysRef.current = new Set(items.map(keyOf));
6055
6089
  }, [items]);
6056
6090
  const gapStyle = { "--fd-vlist-gap": rowGap + "px" };
@@ -6095,7 +6129,7 @@ function VirtualList({
6095
6129
  }
6096
6130
 
6097
6131
  // src/components/data/EntityRow.tsx
6098
- import * as React41 from "react";
6132
+ import * as React42 from "react";
6099
6133
  import { jsx as jsx63, jsxs as jsxs53 } from "react/jsx-runtime";
6100
6134
  var ENTITY_ROW_METRIC_WIDTH = 74;
6101
6135
  var METRIC_TONE_COLOR = {
@@ -6108,7 +6142,7 @@ function EntityRowMetrics({ metrics, className = "", style }) {
6108
6142
  const key = m.id || m.label || i;
6109
6143
  const className2 = ["fd-erow-metric", m.tone && m.tone !== "default" ? "is-" + m.tone : "", m.tooltip != null ? "is-described" : ""].filter(Boolean).join(" ");
6110
6144
  const tone = { color: METRIC_TONE_COLOR[m.tone || "default"] };
6111
- const content = /* @__PURE__ */ jsxs53(React41.Fragment, { children: [
6145
+ const content = /* @__PURE__ */ jsxs53(React42.Fragment, { children: [
6112
6146
  m.icon ? /* @__PURE__ */ jsx63("i", { className: "ph ph-" + m.icon, "aria-hidden": "true" }) : null,
6113
6147
  /* @__PURE__ */ jsx63("span", { className: "fd-erow-metric-value fd-tabular", children: m.value }),
6114
6148
  /* @__PURE__ */ jsx63("span", { className: "fd-sr", children: " " + m.label })
@@ -6200,7 +6234,7 @@ function EntityRow({
6200
6234
  }
6201
6235
 
6202
6236
  // src/components/data/TransferList.tsx
6203
- import * as React42 from "react";
6237
+ import * as React43 from "react";
6204
6238
  import { createPortal as createPortal5 } from "react-dom";
6205
6239
 
6206
6240
  // src/components/forms/Input.tsx
@@ -6306,12 +6340,12 @@ function TransferList({
6306
6340
  listHeight = 440,
6307
6341
  className = ""
6308
6342
  }) {
6309
- const [drag, setDrag] = React42.useState(null);
6310
- const [dragOverSide, setDragOverSide] = React42.useState(null);
6311
- const dragRef = React42.useRef(null);
6312
- const armedRef = React42.useRef(null);
6313
- const sideRefs = React42.useRef({ left: null, right: null });
6314
- const hitTestSide = React42.useCallback((x, y) => {
6343
+ const [drag, setDrag] = React43.useState(null);
6344
+ const [dragOverSide, setDragOverSide] = React43.useState(null);
6345
+ const dragRef = React43.useRef(null);
6346
+ const armedRef = React43.useRef(null);
6347
+ const sideRefs = React43.useRef({ left: null, right: null });
6348
+ const hitTestSide = React43.useCallback((x, y) => {
6315
6349
  for (const side of ["left", "right"]) {
6316
6350
  const el = sideRefs.current[side];
6317
6351
  if (!el) continue;
@@ -6320,7 +6354,7 @@ function TransferList({
6320
6354
  }
6321
6355
  return null;
6322
6356
  }, []);
6323
- const findItem = React42.useCallback(
6357
+ const findItem = React43.useCallback(
6324
6358
  (side, key) => (side === "left" ? left.items : right.items).find((it) => keyOf(it) === key),
6325
6359
  [left.items, right.items, keyOf]
6326
6360
  );
@@ -6342,7 +6376,7 @@ function TransferList({
6342
6376
  height: rect.height
6343
6377
  };
6344
6378
  };
6345
- React42.useEffect(() => {
6379
+ React43.useEffect(() => {
6346
6380
  const onMovePointer = (e) => {
6347
6381
  const armed = armedRef.current;
6348
6382
  if (!armed || e.pointerId !== armed.pointerId) return;
@@ -6395,7 +6429,7 @@ function TransferList({
6395
6429
  window.removeEventListener("pointercancel", endDrag);
6396
6430
  };
6397
6431
  }, [hitTestSide, findItem, onMove]);
6398
- React42.useEffect(() => {
6432
+ React43.useEffect(() => {
6399
6433
  if (!drag || typeof document === "undefined") return;
6400
6434
  const prev = document.body.style.userSelect;
6401
6435
  document.body.style.userSelect = "none";
@@ -6512,7 +6546,7 @@ function FactList({ facts = [], className = "", ...rest }) {
6512
6546
  }
6513
6547
 
6514
6548
  // src/components/data/USChoropleth.tsx
6515
- import * as React44 from "react";
6549
+ import * as React45 from "react";
6516
6550
 
6517
6551
  // src/components/data/usChoropleth/mapBox.ts
6518
6552
  var MAP_WIDTH = 975;
@@ -6577,11 +6611,11 @@ function buildChoroplethModel(values, topN, givenTotal) {
6577
6611
  }
6578
6612
 
6579
6613
  // src/components/data/usChoropleth/useUsStateShapes.ts
6580
- import * as React43 from "react";
6614
+ import * as React44 from "react";
6581
6615
  function useUsStateShapes() {
6582
- const [token, setToken] = React43.useState(0);
6583
- const [settled, setSettled] = React43.useState(null);
6584
- React43.useEffect(() => {
6616
+ const [token, setToken] = React44.useState(0);
6617
+ const [settled, setSettled] = React44.useState(null);
6618
+ React44.useEffect(() => {
6585
6619
  let current2 = true;
6586
6620
  import("./usStateShapes-JJARDNLL.js").then(({ STATE_SHAPES }) => {
6587
6621
  if (current2) setSettled({ token, state: { status: "ready", shapes: STATE_SHAPES } });
@@ -6623,7 +6657,7 @@ function nextCode(key, from) {
6623
6657
  }
6624
6658
  function StateMap({ shapes, model, figures, label, formatReadout }) {
6625
6659
  const tip = useTooltip();
6626
- const [stop, setStop] = React44.useState(US_STATE_CODES[0]);
6660
+ const [stop, setStop] = React45.useState(US_STATE_CODES[0]);
6627
6661
  const onKeyDown = (event) => {
6628
6662
  const from = event.target.getAttribute("data-state");
6629
6663
  const to = from && nextCode(event.key, from);
@@ -6671,8 +6705,8 @@ function StateTable({ model, valueLabel, formatValue }) {
6671
6705
  return /* @__PURE__ */ jsx68(Collapsible, { title: TABLE_TITLE, children: /* @__PURE__ */ jsx68(DataTable, { columns, rows: model.rows, rowKey: "code", compact: true }) });
6672
6706
  }
6673
6707
  function USChoropleth({ values, label, valueLabel, formatValue, formatReadout, topN, total, className = "" }) {
6674
- const model = React44.useMemo(() => buildChoroplethModel(values, topN ?? 0, total), [values, topN, total]);
6675
- const figures = React44.useMemo(() => new Map(model.rows.map((row) => [row.code, row])), [model]);
6708
+ const model = React45.useMemo(() => buildChoroplethModel(values, topN ?? 0, total), [values, topN, total]);
6709
+ const figures = React45.useMemo(() => new Map(model.rows.map((row) => [row.code, row])), [model]);
6676
6710
  const { state, retry } = useUsStateShapes();
6677
6711
  return /* @__PURE__ */ jsxs57("div", { className: ["fd-uschoro", className].filter(Boolean).join(" "), children: [
6678
6712
  /* @__PURE__ */ jsxs57("div", { className: "fd-uschoro-layout", children: [
@@ -6707,11 +6741,11 @@ function USChoropleth({ values, label, valueLabel, formatValue, formatReadout, t
6707
6741
  }
6708
6742
 
6709
6743
  // src/components/forms/Checkbox.tsx
6710
- import * as React45 from "react";
6744
+ import * as React46 from "react";
6711
6745
  import { jsx as jsx69, jsxs as jsxs58 } from "react/jsx-runtime";
6712
6746
  function Checkbox({ label, description, card = false, indeterminate = false, className = "", ...rest }) {
6713
- const ref = React45.useRef(null);
6714
- React45.useEffect(() => {
6747
+ const ref = React46.useRef(null);
6748
+ React46.useEffect(() => {
6715
6749
  if (ref.current) ref.current.indeterminate = indeterminate;
6716
6750
  }, [indeterminate]);
6717
6751
  return /* @__PURE__ */ jsxs58("label", { className: ["fd-choice", card ? "fd-choice-card" : "", className].filter(Boolean).join(" "), children: [
@@ -6758,7 +6792,7 @@ function Switch({ label, description, className = "", ...rest }) {
6758
6792
  }
6759
6793
 
6760
6794
  // src/components/forms/Select.tsx
6761
- import * as React46 from "react";
6795
+ import * as React47 from "react";
6762
6796
  import { jsx as jsx72, jsxs as jsxs61 } from "react/jsx-runtime";
6763
6797
  var norm = (o) => typeof o === "string" ? { value: o, label: o } : o;
6764
6798
  function Select({
@@ -6786,12 +6820,12 @@ function Select({
6786
6820
  const isOn = (v) => multiple ? vals.includes(v) : v === value;
6787
6821
  const hasSearch = searchable === void 0 ? opts.length > 8 : searchable;
6788
6822
  const { fieldId, labelId, ariaLabelledBy } = useTriggerLabelling(label, id, hiddenLabel);
6789
- const [open2, setOpen] = React46.useState(false);
6790
- const [q, setQ] = React46.useState("");
6791
- const rootRef = React46.useRef(null);
6792
- const boxRef = React46.useRef(null);
6793
- const listRef = React46.useRef(null);
6794
- const typeBuf = React46.useRef({ s: "", t: 0 });
6823
+ const [open2, setOpen] = React47.useState(false);
6824
+ const [q, setQ] = React47.useState("");
6825
+ const rootRef = React47.useRef(null);
6826
+ const boxRef = React47.useRef(null);
6827
+ const listRef = React47.useRef(null);
6828
+ const typeBuf = React47.useRef({ s: "", t: 0 });
6795
6829
  const selected = multiple ? null : opts.find((o) => o.value === value);
6796
6830
  const chosen = multiple ? opts.filter((o) => vals.includes(o.value)) : [];
6797
6831
  const boxText = multiple ? chosen.length === 0 ? placeholder : chosen.length === 1 ? chosen[0].label : summary ? summary(chosen.map((o) => o.value)) : chosen.length + " selected" : selected ? selected.label : placeholder;
@@ -6927,7 +6961,7 @@ function Select({
6927
6961
  ),
6928
6962
  q ? /* @__PURE__ */ jsx72("span", { className: "fd-body-sm fd-muted", children: visible.length }) : null
6929
6963
  ] }) : void 0,
6930
- footer: multiple ? /* @__PURE__ */ jsxs61(React46.Fragment, { children: [
6964
+ footer: multiple ? /* @__PURE__ */ jsxs61(React47.Fragment, { children: [
6931
6965
  /* @__PURE__ */ jsx72(
6932
6966
  "button",
6933
6967
  {
@@ -6958,7 +6992,7 @@ function Select({
6958
6992
  'Nothing matches "',
6959
6993
  q,
6960
6994
  '".'
6961
- ] }) : groups.map((grp) => /* @__PURE__ */ jsxs61(React46.Fragment, { children: [
6995
+ ] }) : groups.map((grp) => /* @__PURE__ */ jsxs61(React47.Fragment, { children: [
6962
6996
  grp.g ? /* @__PURE__ */ jsx72("div", { className: "fd-pop-group", children: grp.g }) : null,
6963
6997
  grp.items.map(({ o, i }) => /* @__PURE__ */ jsxs61(
6964
6998
  "button",
@@ -6995,7 +7029,7 @@ function Select({
6995
7029
  }
6996
7030
 
6997
7031
  // src/components/forms/TimePicker.tsx
6998
- import * as React47 from "react";
7032
+ import * as React48 from "react";
6999
7033
  import { jsx as jsx73, jsxs as jsxs62 } from "react/jsx-runtime";
7000
7034
  var pad = (n) => String(n).padStart(2, "0");
7001
7035
  function ClockFace({ value = "09:00", onChange }) {
@@ -7004,9 +7038,9 @@ function ClockFace({ value = "09:00", onChange }) {
7004
7038
  if (isNaN(m)) m = 0;
7005
7039
  const pm = h24 >= 12;
7006
7040
  const h12 = h24 % 12 === 0 ? 12 : h24 % 12;
7007
- const [mode2, setMode] = React47.useState("h");
7008
- const faceRef = React47.useRef(null);
7009
- const dragging = React47.useRef(false);
7041
+ const [mode2, setMode] = React48.useState("h");
7042
+ const faceRef = React48.useRef(null);
7043
+ const dragging = React48.useRef(false);
7010
7044
  const set = (h, mm, isPm) => onChange((isPm ? h % 12 + 12 : h % 12) + ":" + pad(mm));
7011
7045
  const R = 108, NR = 80;
7012
7046
  const nums = mode2 === "h" ? Array.from({ length: 12 }, (_, i) => i + 1) : Array.from({ length: 12 }, (_, i) => i * 5);
@@ -7079,9 +7113,9 @@ function ClockFace({ value = "09:00", onChange }) {
7079
7113
  }
7080
7114
  function TimePicker({ label, help, error, required = false, disabled = false, value = "", onChange, placeholder = "Pick a time", id, className = "", style }) {
7081
7115
  const { fieldId, labelId, ariaLabelledBy } = useTriggerLabelling(label, id);
7082
- const [open2, setOpen] = React47.useState(false);
7083
- const rootRef = React47.useRef(null);
7084
- const boxRef = React47.useRef(null);
7116
+ const [open2, setOpen] = React48.useState(false);
7117
+ const rootRef = React48.useRef(null);
7118
+ const boxRef = React48.useRef(null);
7085
7119
  const disp = () => {
7086
7120
  if (!value) return "";
7087
7121
  const [h, m] = value.split(":").map(Number);
@@ -7124,7 +7158,7 @@ function TimePicker({ label, help, error, required = false, disabled = false, va
7124
7158
  offset: 6,
7125
7159
  width: 262,
7126
7160
  role: "presentation",
7127
- footer: /* @__PURE__ */ jsxs62(React47.Fragment, { children: [
7161
+ footer: /* @__PURE__ */ jsxs62(React48.Fragment, { children: [
7128
7162
  /* @__PURE__ */ jsx73(
7129
7163
  "button",
7130
7164
  {
@@ -7152,7 +7186,7 @@ function TimePicker({ label, help, error, required = false, disabled = false, va
7152
7186
  }
7153
7187
 
7154
7188
  // src/components/forms/Slider.tsx
7155
- import * as React48 from "react";
7189
+ import * as React49 from "react";
7156
7190
  import { jsx as jsx74, jsxs as jsxs63 } from "react/jsx-runtime";
7157
7191
  function Slider({
7158
7192
  label,
@@ -7170,7 +7204,7 @@ function Slider({
7170
7204
  ...rest
7171
7205
  }) {
7172
7206
  const fieldId = useFieldId(id);
7173
- const [dragging, setDragging] = React48.useState(false);
7207
+ const [dragging, setDragging] = React49.useState(false);
7174
7208
  const v = value === void 0 ? min : Number(value);
7175
7209
  const pct = max === min ? 0 : (v - min) / (max - min) * 100;
7176
7210
  return /* @__PURE__ */ jsxs63("div", { className: ["fd-field", className].filter(Boolean).join(" "), children: [
@@ -7204,7 +7238,7 @@ function Slider({
7204
7238
  }
7205
7239
 
7206
7240
  // src/components/forms/RangeSlider.tsx
7207
- import * as React49 from "react";
7241
+ import * as React50 from "react";
7208
7242
  import { jsx as jsx75, jsxs as jsxs64 } from "react/jsx-runtime";
7209
7243
  function RangeSlider({
7210
7244
  label,
@@ -7224,9 +7258,9 @@ function RangeSlider({
7224
7258
  }) {
7225
7259
  const fmt2 = format || ((v) => String(v));
7226
7260
  const [a, b] = value || [min, max];
7227
- const [drag, setDrag] = React49.useState(null);
7228
- const [focus, setFocus] = React49.useState(null);
7229
- const railRef = React49.useRef(null);
7261
+ const [drag, setDrag] = React50.useState(null);
7262
+ const [focus, setFocus] = React50.useState(null);
7263
+ const railRef = React50.useRef(null);
7230
7264
  const pct = (v) => max === min ? 0 : (v - min) / (max - min) * 100;
7231
7265
  const clampPair = (i, v) => {
7232
7266
  v = Math.min(max, Math.max(min, Math.round(v / step) * step));
@@ -7241,7 +7275,7 @@ function RangeSlider({
7241
7275
  const r = railRef.current.getBoundingClientRect();
7242
7276
  return min + Math.min(1, Math.max(0, (e.clientX - r.left) / r.width)) * (max - min);
7243
7277
  };
7244
- React49.useEffect(() => {
7278
+ React50.useEffect(() => {
7245
7279
  if (drag === null) return;
7246
7280
  const mv = (e) => onChange && onChange(clampPair(drag, fromEvent(e)));
7247
7281
  const upH = () => setDrag(null);
@@ -7322,7 +7356,7 @@ function RangeSlider({
7322
7356
  /* @__PURE__ */ jsxs64("div", { className: "fd-range" + (hasLabels ? " has-labels" : ""), onPointerDown: onRailDown, children: [
7323
7357
  /* @__PURE__ */ jsx75("span", { className: "fd-range-rail", ref: railRef }),
7324
7358
  /* @__PURE__ */ jsx75("span", { className: "fd-range-fill", style: { left: pct(a) + "%", width: pct(b) - pct(a) + "%" } }),
7325
- marks.map((m) => /* @__PURE__ */ jsxs64(React49.Fragment, { children: [
7359
+ marks.map((m) => /* @__PURE__ */ jsxs64(React50.Fragment, { children: [
7326
7360
  /* @__PURE__ */ jsx75("span", { className: "fd-range-mark" + (m.value >= a && m.value <= b ? " is-in" : ""), style: { left: pct(m.value) + "%" } }),
7327
7361
  m.label ? /* @__PURE__ */ jsx75("span", { className: "fd-range-mark-label", style: { left: pct(m.value) + "%" }, children: m.label }) : null
7328
7362
  ] }, m.value)),
@@ -7351,7 +7385,7 @@ function RangeSlider({
7351
7385
  }
7352
7386
 
7353
7387
  // src/components/forms/Dropzone.tsx
7354
- import * as React50 from "react";
7388
+ import * as React51 from "react";
7355
7389
  import { jsx as jsx76, jsxs as jsxs65 } from "react/jsx-runtime";
7356
7390
  function Dropzone({
7357
7391
  onFiles,
@@ -7366,8 +7400,8 @@ function Dropzone({
7366
7400
  className = "",
7367
7401
  style
7368
7402
  }) {
7369
- const [over, setOver] = React50.useState(false);
7370
- const depth = React50.useRef(0);
7403
+ const [over, setOver] = React51.useState(false);
7404
+ const depth = React51.useRef(0);
7371
7405
  const has = (e) => {
7372
7406
  const dt = e.dataTransfer;
7373
7407
  if (!dt) return false;
@@ -7429,8 +7463,8 @@ function FilePickButton({
7429
7463
  className = "",
7430
7464
  children
7431
7465
  }) {
7432
- const ref = React50.useRef(null);
7433
- return /* @__PURE__ */ jsxs65(React50.Fragment, { children: [
7466
+ const ref = React51.useRef(null);
7467
+ return /* @__PURE__ */ jsxs65(React51.Fragment, { children: [
7434
7468
  /* @__PURE__ */ jsx76(
7435
7469
  "button",
7436
7470
  {
@@ -7463,10 +7497,10 @@ function FilePickButton({
7463
7497
  }
7464
7498
  function useStagedFiles(upload, opts) {
7465
7499
  const o = opts || {};
7466
- const [items, setItems] = React50.useState([]);
7467
- const controllers = React50.useRef({});
7500
+ const [items, setItems] = React51.useState([]);
7501
+ const controllers = React51.useRef({});
7468
7502
  const patch = (id, next) => setItems((list) => list.map((f) => f.id === id ? Object.assign({}, f, next) : f));
7469
- const run = React50.useCallback((att) => {
7503
+ const run = React51.useCallback((att) => {
7470
7504
  if (!upload) return;
7471
7505
  const ac = typeof AbortController !== "undefined" ? new AbortController() : null;
7472
7506
  controllers.current[att.id] = ac;
@@ -7483,14 +7517,14 @@ function useStagedFiles(upload, opts) {
7483
7517
  delete controllers.current[att.id];
7484
7518
  });
7485
7519
  }, [upload]);
7486
- const add = React50.useCallback((files) => {
7520
+ const add = React51.useCallback((files) => {
7487
7521
  if (!upload) return [];
7488
7522
  const atts = Array.from(files).map((f) => toAttachment(f));
7489
7523
  setItems((list) => list.concat(atts));
7490
7524
  atts.forEach(run);
7491
7525
  return atts;
7492
7526
  }, [upload, run]);
7493
- const remove = React50.useCallback((att) => {
7527
+ const remove = React51.useCallback((att) => {
7494
7528
  const ac = controllers.current[att.id];
7495
7529
  if (ac) {
7496
7530
  try {
@@ -7501,10 +7535,10 @@ function useStagedFiles(upload, opts) {
7501
7535
  }
7502
7536
  setItems((list) => list.filter((f) => f.id !== att.id));
7503
7537
  }, []);
7504
- const retry = React50.useCallback((att) => {
7538
+ const retry = React51.useCallback((att) => {
7505
7539
  run(att);
7506
7540
  }, [run]);
7507
- const clear = React50.useCallback(() => {
7541
+ const clear = React51.useCallback(() => {
7508
7542
  Object.values(controllers.current).forEach((ac) => {
7509
7543
  try {
7510
7544
  ac && ac.abort();
@@ -7628,7 +7662,7 @@ function FileGrid({ files = [], onOpen, onRemove, onRetry, tiles = true, maxHeig
7628
7662
  }
7629
7663
 
7630
7664
  // src/components/forms/MarkdownEditor.tsx
7631
- import * as React51 from "react";
7665
+ import * as React52 from "react";
7632
7666
  import { jsx as jsx78, jsxs as jsxs67 } from "react/jsx-runtime";
7633
7667
  var isMac = typeof navigator !== "undefined" && /Mac|iPhone|iPad/.test(navigator.platform || navigator.userAgent || "");
7634
7668
  var INLINE_RE = /(\*\*\*[^*\n]+\*\*\*|\*\*[^*\n]+\*\*|__[^_\n]+__|~~[^~\n]+~~|`[^`\n]+`|\*[^*\s][^*\n]*\*|(?<![A-Za-z0-9_])_[^_\s][^_\n]*_|\[[^\]\n]*\]\([^)\s\n]*\)|https?:\/\/\S+)/g;
@@ -7842,7 +7876,7 @@ function syncDom(root, value) {
7842
7876
  while (root.children.length > lines.length) root.removeChild(root.lastChild);
7843
7877
  }
7844
7878
  var LIST_CONT = RE_LI;
7845
- var MarkdownEditor = React51.forwardRef(function MarkdownEditor2({
7879
+ var MarkdownEditor = React52.forwardRef(function MarkdownEditor2({
7846
7880
  value = "",
7847
7881
  onChange,
7848
7882
  onSubmit,
@@ -7861,10 +7895,10 @@ var MarkdownEditor = React51.forwardRef(function MarkdownEditor2({
7861
7895
  className = "",
7862
7896
  id
7863
7897
  }, ref) {
7864
- const boxRef = React51.useRef(null);
7865
- const composing = React51.useRef(false);
7866
- const pendingCaret = React51.useRef(null);
7867
- React51.useLayoutEffect(() => {
7898
+ const boxRef = React52.useRef(null);
7899
+ const composing = React52.useRef(false);
7900
+ const pendingCaret = React52.useRef(null);
7901
+ React52.useLayoutEffect(() => {
7868
7902
  const root = boxRef.current;
7869
7903
  if (!root || composing.current) return;
7870
7904
  const active = document.activeElement === root || root.contains(document.activeElement);
@@ -7873,7 +7907,7 @@ var MarkdownEditor = React51.forwardRef(function MarkdownEditor2({
7873
7907
  pendingCaret.current = null;
7874
7908
  if (active && caret != null) placeCaret(root, caret);
7875
7909
  }, [value]);
7876
- React51.useEffect(() => {
7910
+ React52.useEffect(() => {
7877
7911
  if (autoFocus && boxRef.current) boxRef.current.focus();
7878
7912
  }, [autoFocus]);
7879
7913
  const caretNow = () => {
@@ -7940,8 +7974,8 @@ var MarkdownEditor = React51.forwardRef(function MarkdownEditor2({
7940
7974
  api.replaceRange(from, to, next, from + next.length);
7941
7975
  }
7942
7976
  };
7943
- React51.useImperativeHandle(ref, () => api);
7944
- const caretAtKeydown = React51.useRef(-1);
7977
+ React52.useImperativeHandle(ref, () => api);
7978
+ const caretAtKeydown = React52.useRef(-1);
7945
7979
  function detect(text, caret) {
7946
7980
  if (!onTrigger) return;
7947
7981
  const upto = text.slice(0, caret);
@@ -8094,7 +8128,7 @@ var MarkdownEditor = React51.forwardRef(function MarkdownEditor2({
8094
8128
  });
8095
8129
 
8096
8130
  // src/components/forms/CodeEditor.tsx
8097
- import * as React52 from "react";
8131
+ import * as React53 from "react";
8098
8132
  import { EditorView, keymap, lineNumbers, placeholder as cmPlaceholder, drawSelection, Decoration } from "@codemirror/view";
8099
8133
  import { EditorState, StateEffect, StateField, Compartment } from "@codemirror/state";
8100
8134
  import { defaultKeymap, history, historyKeymap, indentMore, indentLess } from "@codemirror/commands";
@@ -8198,16 +8232,16 @@ function CodeEditor({
8198
8232
  const fieldId = useFieldId(id);
8199
8233
  const descId = fieldId + "-desc";
8200
8234
  const liveId = fieldId + "-live";
8201
- const hostRef = React52.useRef(null);
8202
- const viewRef = React52.useRef(null);
8203
- const valueRef = React52.useRef(value);
8204
- const onChangeRef = React52.useRef(onChange);
8235
+ const hostRef = React53.useRef(null);
8236
+ const viewRef = React53.useRef(null);
8237
+ const valueRef = React53.useRef(value);
8238
+ const onChangeRef = React53.useRef(onChange);
8205
8239
  onChangeRef.current = onChange;
8206
- const editableCompartment = React52.useRef(new Compartment()).current;
8207
- const attributesCompartment = React52.useRef(new Compartment()).current;
8208
- const errorRef = React52.useRef(error);
8240
+ const editableCompartment = React53.useRef(new Compartment()).current;
8241
+ const attributesCompartment = React53.useRef(new Compartment()).current;
8242
+ const errorRef = React53.useRef(error);
8209
8243
  errorRef.current = error;
8210
- const diagnosticsCountRef = React52.useRef(diagnostics.length);
8244
+ const diagnosticsCountRef = React53.useRef(diagnostics.length);
8211
8245
  diagnosticsCountRef.current = diagnostics.length;
8212
8246
  function contentAttributes() {
8213
8247
  return {
@@ -8217,7 +8251,7 @@ function CodeEditor({
8217
8251
  ...label ? { "aria-label": label } : {}
8218
8252
  };
8219
8253
  }
8220
- React52.useEffect(() => {
8254
+ React53.useEffect(() => {
8221
8255
  const host2 = hostRef.current;
8222
8256
  if (!host2) return;
8223
8257
  const updateListener = EditorView.updateListener.of((update) => {
@@ -8259,7 +8293,7 @@ function CodeEditor({
8259
8293
  viewRef.current = null;
8260
8294
  };
8261
8295
  }, []);
8262
- React52.useEffect(() => {
8296
+ React53.useEffect(() => {
8263
8297
  const view = viewRef.current;
8264
8298
  if (!view) return;
8265
8299
  const current2 = view.state.doc.toString();
@@ -8268,12 +8302,12 @@ function CodeEditor({
8268
8302
  }
8269
8303
  valueRef.current = value;
8270
8304
  }, [value]);
8271
- React52.useEffect(() => {
8305
+ React53.useEffect(() => {
8272
8306
  const view = viewRef.current;
8273
8307
  if (!view) return;
8274
8308
  view.dispatch({ effects: editableCompartment.reconfigure(EditorView.editable.of(!disabled)) });
8275
8309
  }, [disabled, editableCompartment]);
8276
- React52.useEffect(() => {
8310
+ React53.useEffect(() => {
8277
8311
  const view = viewRef.current;
8278
8312
  if (!view) return;
8279
8313
  view.dispatch({
@@ -8331,11 +8365,11 @@ function CodeEditor({
8331
8365
  }
8332
8366
 
8333
8367
  // src/components/forms/RadioGroup.tsx
8334
- import * as React53 from "react";
8368
+ import * as React54 from "react";
8335
8369
  import { jsx as jsx80, jsxs as jsxs69 } from "react/jsx-runtime";
8336
8370
  function RadioGroup({ label, labelledBy, options, value, onChange, card = false, disabled = false, name, className = "" }) {
8337
- const autoName = React53.useId();
8338
- const labelId = React53.useId();
8371
+ const autoName = React54.useId();
8372
+ const labelId = React54.useId();
8339
8373
  return /* @__PURE__ */ jsxs69("div", { role: "radiogroup", "aria-labelledby": labelledBy ?? labelId, "aria-disabled": disabled || void 0, className: ["fd-radiogroup", className].filter(Boolean).join(" "), children: [
8340
8374
  labelledBy === void 0 && /* @__PURE__ */ jsx80("span", { id: labelId, className: "fd-radiogroup-label", children: label }),
8341
8375
  options.map((o) => /* @__PURE__ */ jsx80(
@@ -8363,16 +8397,16 @@ function Fieldset({ busy = false, className = "", ...rest }) {
8363
8397
  }
8364
8398
 
8365
8399
  // src/components/platform/AccountMenu.tsx
8366
- import * as React55 from "react";
8400
+ import * as React56 from "react";
8367
8401
 
8368
8402
  // src/kits/sessionContext.tsx
8369
- import * as React54 from "react";
8370
- var SessionContext = React54.createContext(null);
8403
+ import * as React55 from "react";
8404
+ var SessionContext = React55.createContext(null);
8371
8405
  function SessionProvider({ value, children }) {
8372
- return React54.createElement(SessionContext.Provider, { value }, children);
8406
+ return React55.createElement(SessionContext.Provider, { value }, children);
8373
8407
  }
8374
8408
  function useSessionContext() {
8375
- const ctx = React54.useContext(SessionContext);
8409
+ const ctx = React55.useContext(SessionContext);
8376
8410
  if (!ctx) {
8377
8411
  throw new Error(
8378
8412
  "useSessionContext() was called outside a <SessionProvider>. Wrap your app root in <SessionProvider value={...}> with your real session, or \u2014 in the docs site or a demo \u2014 in <DemoSessionProvider>, before rendering AccountMenu, Gate, ProfilePage or AppSwitcher."
@@ -8412,11 +8446,11 @@ function AccountMenu({
8412
8446
  ...rest
8413
8447
  }) {
8414
8448
  const { user, roles, can: can2, signOut: ctxSignOut, demo, pending } = useSessionContext();
8415
- const [open2, setOpen] = React55.useState(false);
8416
- const [switching, setSwitching] = React55.useState(false);
8417
- const [signingOut, setSigningOut] = React55.useState(false);
8418
- const [signOutError, setSignOutError] = React55.useState(null);
8419
- const ref = React55.useRef(null);
8449
+ const [open2, setOpen] = React56.useState(false);
8450
+ const [switching, setSwitching] = React56.useState(false);
8451
+ const [signingOut, setSigningOut] = React56.useState(false);
8452
+ const [signOutError, setSignOutError] = React56.useState(null);
8453
+ const ref = React56.useRef(null);
8420
8454
  const visibleLinks = links.filter((l) => !l.perm || !pending && can2(l.perm));
8421
8455
  const visibleGroups = groups.map((g) => ({ label: g.label, links: g.links.filter((l) => !l.perm || !pending && can2(l.perm)) })).filter((g) => g.links.length);
8422
8456
  const closeMenu = () => {
@@ -8541,13 +8575,13 @@ function AccountMenu({
8541
8575
  }
8542
8576
 
8543
8577
  // src/components/platform/AppSwitcher.tsx
8544
- import * as React56 from "react";
8578
+ import * as React57 from "react";
8545
8579
  import { jsx as jsx83, jsxs as jsxs71 } from "react/jsx-runtime";
8546
8580
  function AppSwitcher({ apps: appsProp, onNavigate, className = "" }) {
8547
8581
  const { apps: contextApps } = useSessionContext();
8548
8582
  const apps = appsProp ?? contextApps ?? [];
8549
- const [open2, setOpen] = React56.useState(false);
8550
- const anchorRef = React56.useRef(null);
8583
+ const [open2, setOpen] = React57.useState(false);
8584
+ const anchorRef = React57.useRef(null);
8551
8585
  if (!apps.length) return null;
8552
8586
  const items = apps.map((app) => ({
8553
8587
  id: app.key,
@@ -8561,7 +8595,7 @@ function AppSwitcher({ apps: appsProp, onNavigate, className = "" }) {
8561
8595
  window.location.href = app.url;
8562
8596
  }
8563
8597
  }));
8564
- return /* @__PURE__ */ jsxs71(React56.Fragment, { children: [
8598
+ return /* @__PURE__ */ jsxs71(React57.Fragment, { children: [
8565
8599
  /* @__PURE__ */ jsx83("span", { ref: anchorRef, className: ["fd-appswitch-anchor", className].filter(Boolean).join(" "), style: { display: "inline-flex" }, children: /* @__PURE__ */ jsx83(
8566
8600
  IconButton,
8567
8601
  {
@@ -8590,10 +8624,10 @@ function AppSwitcher({ apps: appsProp, onNavigate, className = "" }) {
8590
8624
  }
8591
8625
 
8592
8626
  // src/components/platform/AppearanceMenu.tsx
8593
- import * as React59 from "react";
8627
+ import * as React60 from "react";
8594
8628
 
8595
8629
  // src/kits/appearance.ts
8596
- import * as React57 from "react";
8630
+ import * as React58 from "react";
8597
8631
  var DEFAULT_STORAGE_KEY = "fd-appearance";
8598
8632
  var DEFAULT_PREFS = {
8599
8633
  theme: "system",
@@ -8705,8 +8739,8 @@ function watchAppearance(store, root = document.documentElement) {
8705
8739
  };
8706
8740
  }
8707
8741
  function useAppearancePrefs(store) {
8708
- const prefs = React57.useSyncExternalStore(store.subscribe, store.getSnapshot);
8709
- const update = React57.useCallback(
8742
+ const prefs = React58.useSyncExternalStore(store.subscribe, store.getSnapshot);
8743
+ const update = React58.useCallback(
8710
8744
  (patch) => {
8711
8745
  store.write({ ...store.getSnapshot(), ...patch });
8712
8746
  },
@@ -8716,15 +8750,15 @@ function useAppearancePrefs(store) {
8716
8750
  }
8717
8751
 
8718
8752
  // src/components/platform/AppearanceProvider.tsx
8719
- import * as React58 from "react";
8753
+ import * as React59 from "react";
8720
8754
  import { jsx as jsx84 } from "react/jsx-runtime";
8721
- var AppearanceStoreContext = React58.createContext(null);
8755
+ var AppearanceStoreContext = React59.createContext(null);
8722
8756
  function AppearanceProvider({ store, children }) {
8723
- React58.useLayoutEffect(() => watchAppearance(store), [store]);
8757
+ React59.useLayoutEffect(() => watchAppearance(store), [store]);
8724
8758
  return /* @__PURE__ */ jsx84(AppearanceStoreContext.Provider, { value: store, children });
8725
8759
  }
8726
8760
  function useAppearanceStore() {
8727
- const store = React58.useContext(AppearanceStoreContext);
8761
+ const store = React59.useContext(AppearanceStoreContext);
8728
8762
  if (!store) throw new Error("AppearanceMenu and useAppearanceStore must be rendered inside an <AppearanceProvider>.");
8729
8763
  return store;
8730
8764
  }
@@ -8744,10 +8778,10 @@ var TEXT_SCALE_OPTIONS = [
8744
8778
  ];
8745
8779
  function AppearanceMenu({ className = "" }) {
8746
8780
  const [prefs, update] = useAppearancePrefs(useAppearanceStore());
8747
- const [open2, setOpen] = React59.useState(false);
8748
- const anchorRef = React59.useRef(null);
8781
+ const [open2, setOpen] = React60.useState(false);
8782
+ const anchorRef = React60.useRef(null);
8749
8783
  const patch = (p) => update(p);
8750
- return /* @__PURE__ */ jsxs72(React59.Fragment, { children: [
8784
+ return /* @__PURE__ */ jsxs72(React60.Fragment, { children: [
8751
8785
  /* @__PURE__ */ jsx85("span", { ref: anchorRef, className: ["fd-appearance-anchor", className].filter(Boolean).join(" "), style: { display: "inline-flex" }, children: /* @__PURE__ */ jsx85(
8752
8786
  IconButton,
8753
8787
  {
@@ -8816,14 +8850,14 @@ function AppearanceMenu({ className = "" }) {
8816
8850
  }
8817
8851
 
8818
8852
  // src/components/platform/ApiSpecBrowser.tsx
8819
- import * as React60 from "react";
8853
+ import * as React61 from "react";
8820
8854
  import { jsx as jsx86, jsxs as jsxs73 } from "react/jsx-runtime";
8821
8855
  var METHOD_TONE = { GET: "success", POST: "info", PATCH: "warning", PUT: "warning", DELETE: "danger" };
8822
8856
  function Json({ obj }) {
8823
8857
  return /* @__PURE__ */ jsx86("pre", { className: "fd-json", children: JSON.stringify(obj, null, 2) });
8824
8858
  }
8825
8859
  function Endpoint({ s, onRequest }) {
8826
- const [tried, setTried] = React60.useState(null);
8860
+ const [tried, setTried] = React61.useState(null);
8827
8861
  const run = async () => {
8828
8862
  setTried("busy");
8829
8863
  const t0 = (window.performance || Date).now();
@@ -8896,10 +8930,10 @@ function ApiSpecBrowser({
8896
8930
  className = "",
8897
8931
  ...rest
8898
8932
  }) {
8899
- const [q, setQ] = React60.useState("");
8900
- const [method, setMethod] = React60.useState(null);
8901
- const [mod, setMod] = React60.useState(null);
8902
- const [listOnly, setListOnly] = React60.useState(false);
8933
+ const [q, setQ] = React61.useState("");
8934
+ const [method, setMethod] = React61.useState(null);
8935
+ const [mod, setMod] = React61.useState(null);
8936
+ const [listOnly, setListOnly] = React61.useState(false);
8903
8937
  const activeModule = modules && modules.find((m) => m.id === mod);
8904
8938
  const hits = spec.filter((s) => (!method || s.method === method) && (!listOnly || s.isList) && (!activeModule || activeModule.endpoints.indexOf(s.id) >= 0) && (!q || (s.path + " " + s.title + " " + s.purpose + " " + (s.usedBy || []).join(" ")).toLowerCase().includes(q.toLowerCase())));
8905
8939
  const effGroups = groups && groups.length ? groups : [["All endpoints", spec.map((s) => s.id)]];
@@ -8978,7 +9012,7 @@ function ApiSpecBrowser({
8978
9012
  }
8979
9013
 
8980
9014
  // src/components/platform/ProfilePage.tsx
8981
- import * as React61 from "react";
9015
+ import * as React62 from "react";
8982
9016
  import { jsx as jsx87, jsxs as jsxs74 } from "react/jsx-runtime";
8983
9017
  function fieldInitialValue(field, user) {
8984
9018
  if (field.value) return field.value(user);
@@ -9014,21 +9048,21 @@ function ProfilePage({
9014
9048
  }) {
9015
9049
  const { user: sessionUser, roles, permissions, saveProfile: saveProfile2 } = useSessionContext();
9016
9050
  const user = userProp || sessionUser;
9017
- const initialFieldValues = React61.useMemo(() => {
9051
+ const initialFieldValues = React62.useMemo(() => {
9018
9052
  const values2 = {};
9019
9053
  for (const field of fields) values2[field.key] = fieldInitialValue(field, user);
9020
9054
  return values2;
9021
9055
  }, [user.id, fields]);
9022
- const initialNotify = React61.useMemo(() => {
9056
+ const initialNotify = React62.useMemo(() => {
9023
9057
  const values2 = {};
9024
9058
  for (const n of notifications) values2[n.key] = !!user.notify?.[n.key];
9025
9059
  return values2;
9026
9060
  }, [user.id, notifications]);
9027
- const [values, setValues] = React61.useState(initialFieldValues);
9028
- const [notify, setNotify] = React61.useState(initialNotify);
9029
- const [saving, setSaving] = React61.useState(false);
9030
- const [saved, setSaved] = React61.useState(false);
9031
- const [prevUserId, setPrevUserId] = React61.useState(user.id);
9061
+ const [values, setValues] = React62.useState(initialFieldValues);
9062
+ const [notify, setNotify] = React62.useState(initialNotify);
9063
+ const [saving, setSaving] = React62.useState(false);
9064
+ const [saved, setSaved] = React62.useState(false);
9065
+ const [prevUserId, setPrevUserId] = React62.useState(user.id);
9032
9066
  if (user.id !== prevUserId) {
9033
9067
  setPrevUserId(user.id);
9034
9068
  setValues(initialFieldValues);
@@ -9216,7 +9250,7 @@ function ProfilePage({
9216
9250
  }
9217
9251
 
9218
9252
  // src/components/platform/SessionScreen.tsx
9219
- import * as React62 from "react";
9253
+ import * as React63 from "react";
9220
9254
  import { Fragment as Fragment22, jsx as jsx88, jsxs as jsxs75 } from "react/jsx-runtime";
9221
9255
  var COPY = {
9222
9256
  "signing-in": { busy: "Signing you in\u2026" },
@@ -9230,13 +9264,13 @@ function SessionScreen({ kind, error, onRetry, productName }) {
9230
9264
  const copy = COPY[kind];
9231
9265
  const busyMessage = "busy" in copy ? copy.busy : null;
9232
9266
  const failureTitle = "failure" in copy ? copy.failure : null;
9233
- const [announced, setAnnounced] = React62.useState("");
9234
- React62.useEffect(() => {
9267
+ const [announced, setAnnounced] = React63.useState("");
9268
+ React63.useEffect(() => {
9235
9269
  setAnnounced(busyMessage ?? "");
9236
9270
  }, [busyMessage]);
9237
- const titleRef = React62.useRef(null);
9271
+ const titleRef = React63.useRef(null);
9238
9272
  const failed = failureTitle !== null;
9239
- React62.useEffect(() => {
9273
+ React63.useEffect(() => {
9240
9274
  titleRef.current?.focus({ preventScroll: true });
9241
9275
  }, [failed]);
9242
9276
  return /* @__PURE__ */ jsx88("main", { className: "fd-session-screen", children: /* @__PURE__ */ jsxs75("div", { className: "fd-session-screen-inner", children: [
@@ -9259,10 +9293,10 @@ function SessionScreen({ kind, error, onRetry, productName }) {
9259
9293
  }
9260
9294
 
9261
9295
  // src/components/platform/RoadmapTimeline.tsx
9262
- import * as React65 from "react";
9296
+ import * as React66 from "react";
9263
9297
 
9264
9298
  // src/kits/session.ts
9265
- import * as React63 from "react";
9299
+ import * as React64 from "react";
9266
9300
  var PERMISSION_CATALOG = [
9267
9301
  { group: "Plans", items: [
9268
9302
  { key: "plan.view", label: "View plans", detail: "Read any plan in the workspace." },
@@ -10829,8 +10863,8 @@ function roadmap(overrides) {
10829
10863
  };
10830
10864
  }
10831
10865
  function useSession() {
10832
- const [s, setS] = React63.useState(getSession);
10833
- React63.useEffect(() => subscribe(setS), []);
10866
+ const [s, setS] = React64.useState(getSession);
10867
+ React64.useEffect(() => subscribe(setS), []);
10834
10868
  return s;
10835
10869
  }
10836
10870
  var SessionKit = {
@@ -10863,7 +10897,7 @@ var SessionKit = {
10863
10897
  };
10864
10898
  function DemoSessionProvider({ children }) {
10865
10899
  const session = useSession();
10866
- const value = React63.useMemo(
10900
+ const value = React64.useMemo(
10867
10901
  () => ({
10868
10902
  user: session.user,
10869
10903
  roles: session.roles,
@@ -10879,11 +10913,11 @@ function DemoSessionProvider({ children }) {
10879
10913
  }),
10880
10914
  [session]
10881
10915
  );
10882
- return React63.createElement(SessionProvider, { value }, children);
10916
+ return React64.createElement(SessionProvider, { value }, children);
10883
10917
  }
10884
10918
 
10885
10919
  // src/kits/runtime.ts
10886
- import * as React64 from "react";
10920
+ import * as React65 from "react";
10887
10921
  var WIRED_ENDPOINTS = [
10888
10922
  // Nothing yet. Every id below would come from a real service:
10889
10923
  // "plan.get", "placements.list", …
@@ -11054,8 +11088,8 @@ var RuntimeKit = {
11054
11088
  };
11055
11089
  RuntimeKit.declare(FEATURE_NEEDS);
11056
11090
  function useRuntimeMode() {
11057
- const [m, setM] = React64.useState(RuntimeKit.getMode());
11058
- React64.useEffect(() => RuntimeKit.subscribe(setM), []);
11091
+ const [m, setM] = React65.useState(RuntimeKit.getMode());
11092
+ React65.useEffect(() => RuntimeKit.subscribe(setM), []);
11059
11093
  return m;
11060
11094
  }
11061
11095
  function useFeatureStatus(key) {
@@ -11138,12 +11172,12 @@ function RoadmapCard({ item, byKey, onOpenFlag }) {
11138
11172
  }
11139
11173
  function RoadmapTimeline({ onOpenFlag, title = "Roadmap", lede }) {
11140
11174
  const session = SessionKit.useSession();
11141
- const [project, setProject] = React65.useState("");
11142
- const [q, setQ] = React65.useState("");
11143
- const scrollRef = React65.useRef(null);
11144
- const nowRef = React65.useRef(null);
11145
- const rm = React65.useMemo(() => SessionKit.roadmap({ isComplete: RuntimeKit.isComplete }), [session]);
11146
- const byKey = React65.useMemo(() => {
11175
+ const [project, setProject] = React66.useState("");
11176
+ const [q, setQ] = React66.useState("");
11177
+ const scrollRef = React66.useRef(null);
11178
+ const nowRef = React66.useRef(null);
11179
+ const rm = React66.useMemo(() => SessionKit.roadmap({ isComplete: RuntimeKit.isComplete }), [session]);
11180
+ const byKey = React66.useMemo(() => {
11147
11181
  const m = {};
11148
11182
  rm.items.forEach((i) => {
11149
11183
  m[i.key] = i;
@@ -11152,7 +11186,7 @@ function RoadmapTimeline({ onOpenFlag, title = "Roadmap", lede }) {
11152
11186
  }, [rm]);
11153
11187
  const items = rm.items.filter((i) => (!project || i.project === project) && (!q || (i.label + " " + i.description + " " + (i.backend || "") + " " + i.key).toLowerCase().includes(q.toLowerCase())));
11154
11188
  const projects = [...new Set(rm.items.map((i) => i.project))];
11155
- React65.useEffect(() => {
11189
+ React66.useEffect(() => {
11156
11190
  let raf1 = 0, raf2 = 0;
11157
11191
  const place = () => {
11158
11192
  const box = scrollRef.current, mark = nowRef.current;
@@ -11226,7 +11260,7 @@ function RoadmapTimeline({ onOpenFlag, title = "Roadmap", lede }) {
11226
11260
  lastPhase = item.phase;
11227
11261
  const inPhase = items.filter((i) => i.phase === item.phase).length;
11228
11262
  const isBoundary = n === firstPending;
11229
- return /* @__PURE__ */ jsxs76(React65.Fragment, { children: [
11263
+ return /* @__PURE__ */ jsxs76(React66.Fragment, { children: [
11230
11264
  showPhase ? /* @__PURE__ */ jsxs76("div", { className: "fd-rm-era", children: [
11231
11265
  /* @__PURE__ */ jsxs76("span", { className: "fd-row", style: { gap: 8, flexWrap: "wrap", alignItems: "baseline" }, children: [
11232
11266
  /* @__PURE__ */ jsx89("span", { style: { fontWeight: 700 }, children: item.phase === 0 ? "Shipped" : "Phase " + item.phase + " \u2014 " + item.phaseName }),
@@ -11270,7 +11304,7 @@ function RoadmapTimeline({ onOpenFlag, title = "Roadmap", lede }) {
11270
11304
  }
11271
11305
 
11272
11306
  // src/components/platform/ComingSoon.tsx
11273
- import * as React66 from "react";
11307
+ import * as React67 from "react";
11274
11308
  import { createPortal as createPortal6 } from "react-dom";
11275
11309
  import { Fragment as Fragment24, jsx as jsx90, jsxs as jsxs77 } from "react/jsx-runtime";
11276
11310
  var BYPASS_STORE = "fd.soon.bypass.v1";
@@ -11288,8 +11322,8 @@ function writeBypassed(list) {
11288
11322
  }
11289
11323
  }
11290
11324
  function useBypass(key) {
11291
- const [on, setOn] = React66.useState(() => !!key && readBypassed().indexOf(key) >= 0);
11292
- React66.useEffect(() => {
11325
+ const [on, setOn] = React67.useState(() => !!key && readBypassed().indexOf(key) >= 0);
11326
+ React67.useEffect(() => {
11293
11327
  setOn(!!key && readBypassed().indexOf(key) >= 0);
11294
11328
  }, [key]);
11295
11329
  const set = (next) => {
@@ -11336,9 +11370,9 @@ function SoonCard({ label, detail, backend, eta, effort, onRoadmap, allowed, onB
11336
11370
  ] });
11337
11371
  }
11338
11372
  function useHoverCard(open2) {
11339
- const anchor = React66.useRef(null);
11340
- const [pos, setPos] = React66.useState(null);
11341
- React66.useLayoutEffect(() => {
11373
+ const anchor = React67.useRef(null);
11374
+ const [pos, setPos] = React67.useState(null);
11375
+ React67.useLayoutEffect(() => {
11342
11376
  if (!open2 || !anchor.current) {
11343
11377
  setPos(null);
11344
11378
  return;
@@ -11465,12 +11499,12 @@ function ComingSoon({
11465
11499
  ] });
11466
11500
  }
11467
11501
  function InlineSoon({ label, detail, backend, eta, effort, onRoadmap, allowed, onBypass, blur, tip, className, rest, children }) {
11468
- const [open2, setOpen] = React66.useState(false);
11502
+ const [open2, setOpen] = React67.useState(false);
11469
11503
  const [anchor, pos] = useHoverCard(open2);
11470
- const hoverCardRef = React66.useRef(null);
11504
+ const hoverCardRef = React67.useRef(null);
11471
11505
  const hoverLayer = useStackedLayer({ active: open2, containerRef: hoverCardRef, returnFocus: false });
11472
11506
  const zIndex = useLayerZIndex(hoverLayer);
11473
- const close2 = React66.useRef(null);
11507
+ const close2 = React67.useRef(null);
11474
11508
  const show = () => {
11475
11509
  if (close2.current) {
11476
11510
  clearTimeout(close2.current);
@@ -11486,7 +11520,7 @@ function InlineSoon({ label, detail, backend, eta, effort, onRoadmap, allowed, o
11486
11520
  setOpen(false);
11487
11521
  }, 140);
11488
11522
  };
11489
- React66.useEffect(() => () => {
11523
+ React67.useEffect(() => () => {
11490
11524
  if (close2.current) clearTimeout(close2.current);
11491
11525
  }, []);
11492
11526
  return /* @__PURE__ */ jsxs77(
@@ -11938,7 +11972,7 @@ function SaturationDistribution({ campuses = [], floorBand, floorScore, onSelect
11938
11972
  }
11939
11973
 
11940
11974
  // src/components/planner/MixGap.tsx
11941
- import * as React67 from "react";
11975
+ import * as React68 from "react";
11942
11976
  import { Fragment as Fragment26, jsx as jsx95, jsxs as jsxs82 } from "react/jsx-runtime";
11943
11977
  var MIX_GAP_LAYOUT = {
11944
11978
  trackHeight: 30,
@@ -11953,7 +11987,7 @@ function mixGapOffset(value, max) {
11953
11987
  }
11954
11988
  function MixGap({ rows = [], loading = false, className = "" }) {
11955
11989
  const max = Math.max(1, ...rows.flatMap((r) => [r.target, r.realized]));
11956
- const [hover, setHover] = React67.useState(null);
11990
+ const [hover, setHover] = React68.useState(null);
11957
11991
  const toneOf = (gap) => gap >= -1 ? "ok" : gap >= -4 ? "warn" : "danger";
11958
11992
  const TONE = { ok: "var(--ok-solid)", warn: "var(--warn-solid)", danger: "var(--danger-solid)" };
11959
11993
  const { trackHeight, barHeight, targetWidth, labelGap } = MIX_GAP_LAYOUT;
@@ -12096,7 +12130,7 @@ function ChannelContribution({
12096
12130
  }
12097
12131
 
12098
12132
  // src/components/planner/BudgetReallocator.tsx
12099
- import * as React68 from "react";
12133
+ import * as React69 from "react";
12100
12134
  import { Fragment as Fragment27, jsx as jsx97, jsxs as jsxs84 } from "react/jsx-runtime";
12101
12135
  var bandFor = (crp) => crp >= 200 ? "dominant" : crp >= 100 ? "strong" : crp >= 50 ? "adequate" : "weak";
12102
12136
  function BudgetReallocator({
@@ -12112,8 +12146,8 @@ function BudgetReallocator({
12112
12146
  onCancel,
12113
12147
  className = ""
12114
12148
  }) {
12115
- const [draft, setDraft] = React68.useState(spend);
12116
- React68.useEffect(() => setDraft(spend), [spend]);
12149
+ const [draft, setDraft] = React69.useState(spend);
12150
+ React69.useEffect(() => setDraft(spend), [spend]);
12117
12151
  const dirty = draft !== spend;
12118
12152
  const nextCrp = scoreFor ? scoreFor(draft) : crp;
12119
12153
  const nextBand = bandFor(nextCrp);
@@ -12128,10 +12162,10 @@ function BudgetReallocator({
12128
12162
  setDraft(spend);
12129
12163
  if (onCancel) onCancel();
12130
12164
  };
12131
- const trackRef = React68.useRef(null);
12132
- const chipRef = React68.useRef(null);
12133
- const [chipLeft, setChipLeft] = React68.useState(null);
12134
- React68.useLayoutEffect(() => {
12165
+ const trackRef = React69.useRef(null);
12166
+ const chipRef = React69.useRef(null);
12167
+ const [chipLeft, setChipLeft] = React69.useState(null);
12168
+ React69.useLayoutEffect(() => {
12135
12169
  const track = trackRef.current;
12136
12170
  if (!dirty || !track) {
12137
12171
  setChipLeft(null);
@@ -12319,7 +12353,7 @@ function ImportanceTag({ level, showLabel = true, size = "sm", className = "", d
12319
12353
  }
12320
12354
 
12321
12355
  // src/components/planner/PreferenceMeter.tsx
12322
- import * as React69 from "react";
12356
+ import * as React70 from "react";
12323
12357
  import { jsx as jsx100, jsxs as jsxs87 } from "react/jsx-runtime";
12324
12358
  function preferenceScore(criteria) {
12325
12359
  const earned = criteria.reduce((n, c) => n + (Number(c.earned) || 0), 0);
@@ -12349,7 +12383,7 @@ function PreferenceMeter({
12349
12383
  className = ""
12350
12384
  }) {
12351
12385
  const value = score == null ? preferenceScore(criteria) : score;
12352
- const segments = React69.useMemo(() => preferenceSegments(criteria), [criteria]);
12386
+ const segments = React70.useMemo(() => preferenceSegments(criteria), [criteria]);
12353
12387
  return /* @__PURE__ */ jsx100(
12354
12388
  ScoreMeter,
12355
12389
  {
@@ -12388,17 +12422,13 @@ function PreferenceMeter({
12388
12422
  }
12389
12423
 
12390
12424
  // src/components/chat/AgentChatPanel.tsx
12391
- import * as React75 from "react";
12425
+ import * as React77 from "react";
12392
12426
 
12393
12427
  // src/components/chat/chatEngine.ts
12394
- import * as React70 from "react";
12395
- var CHAT_UNAVAILABLE = "chat_unavailable";
12396
- var JOB_PENDING = ["queued", "running"];
12397
- var JOB_SUCCESS = ["completed", "recovered"];
12398
- var STORAGE_PREFIX = "fdchat:job:";
12399
- var seq = 0;
12400
- var uid = (p) => p + "_" + ++seq + "_" + Date.now().toString(36);
12401
- var sleep = (ms) => new Promise((r) => setTimeout(r, ms));
12428
+ import * as React72 from "react";
12429
+
12430
+ // src/components/chat/chatStore.ts
12431
+ import * as React71 from "react";
12402
12432
  var safeStore = {
12403
12433
  get(k) {
12404
12434
  try {
@@ -12420,6 +12450,38 @@ var safeStore = {
12420
12450
  }
12421
12451
  }
12422
12452
  };
12453
+ var part = (v) => encodeURIComponent(v);
12454
+ var jobKey = (threadId) => "fdchat:job:" + part(threadId);
12455
+ var draftKey = (owner, contextType, contextId) => "fdchat:draft:" + [owner, contextType, contextId].map(part).join(":");
12456
+ function useChatDraft(owner, contextType, contextId, store = safeStore) {
12457
+ if (owner === "") throw new Error("useChatDraft: draftOwner is an empty string; pass the signed-in user's id, or null for no owner.");
12458
+ const key = owner === null ? null : draftKey(owner, contextType, contextId);
12459
+ const read2 = (k) => k ? store.get(k) || "" : "";
12460
+ const [state, setState] = React71.useState(() => ({ key, text: read2(key) }));
12461
+ let current2 = state;
12462
+ if (state.key !== key) {
12463
+ current2 = { key, text: read2(key) };
12464
+ setState(current2);
12465
+ }
12466
+ const setText = React71.useCallback((text) => {
12467
+ if (key) {
12468
+ if (text) {
12469
+ store.set(key, text);
12470
+ if (store.get(key) !== text) store.del(key);
12471
+ } else store.del(key);
12472
+ }
12473
+ setState({ key, text });
12474
+ }, [key, store]);
12475
+ return [current2.text, setText];
12476
+ }
12477
+
12478
+ // src/components/chat/chatEngine.ts
12479
+ var CHAT_UNAVAILABLE = "chat_unavailable";
12480
+ var JOB_PENDING = ["queued", "running"];
12481
+ var JOB_SUCCESS = ["completed", "recovered"];
12482
+ var seq = 0;
12483
+ var uid = (p) => p + "_" + ++seq + "_" + Date.now().toString(36);
12484
+ var sleep = (ms) => new Promise((r) => setTimeout(r, ms));
12423
12485
  var isSystemMessage = (m) => !!m && (m.role === "system" || m.metadata != null && m.metadata.type === "system");
12424
12486
  var visibleMessages = (list) => (list || []).filter((m) => !isSystemMessage(m));
12425
12487
  function jobBucket(status) {
@@ -12460,33 +12522,33 @@ function useChatEngine(opts) {
12460
12522
  onClear,
12461
12523
  onFeedback
12462
12524
  } = opts || {};
12463
- const [status, setStatus] = React70.useState("idle");
12464
- const [threadId, setThreadId] = React70.useState(null);
12465
- const [messages, setMessages] = React70.useState([]);
12466
- const [queue, setQueue] = React70.useState([]);
12467
- const [fatal, setFatal] = React70.useState(null);
12468
- const [busy, setBusy] = React70.useState(false);
12469
- const [turnStartedAt, setTurnStartedAt] = React70.useState(null);
12470
- const listRef = React70.useRef([]);
12471
- const queueRef = React70.useRef([]);
12472
- const busyRef = React70.useRef(false);
12473
- const loadedRef = React70.useRef(false);
12474
- const stoppedRef = React70.useRef(false);
12475
- const abortRef = React70.useRef(null);
12476
- const serverCount = React70.useRef(0);
12477
- const serverIds = React70.useRef(/* @__PURE__ */ new Set());
12478
- const liveTurn = React70.useRef(null);
12479
- const lastTurnOwn = React70.useRef(/* @__PURE__ */ new Set());
12480
- const retired = React70.useRef(/* @__PURE__ */ new Set());
12481
- const threadRef = React70.useRef(null);
12482
- const mounted = React70.useRef(true);
12483
- React70.useEffect(() => {
12525
+ const [status, setStatus] = React72.useState("idle");
12526
+ const [threadId, setThreadId] = React72.useState(null);
12527
+ const [messages, setMessages] = React72.useState([]);
12528
+ const [queue, setQueue] = React72.useState([]);
12529
+ const [fatal, setFatal] = React72.useState(null);
12530
+ const [busy, setBusy] = React72.useState(false);
12531
+ const [turnStartedAt, setTurnStartedAt] = React72.useState(null);
12532
+ const listRef = React72.useRef([]);
12533
+ const queueRef = React72.useRef([]);
12534
+ const busyRef = React72.useRef(false);
12535
+ const loadedRef = React72.useRef(false);
12536
+ const stoppedRef = React72.useRef(false);
12537
+ const abortRef = React72.useRef(null);
12538
+ const serverCount = React72.useRef(0);
12539
+ const serverIds = React72.useRef(/* @__PURE__ */ new Set());
12540
+ const liveTurn = React72.useRef(null);
12541
+ const lastTurnOwn = React72.useRef(/* @__PURE__ */ new Set());
12542
+ const retired = React72.useRef(/* @__PURE__ */ new Set());
12543
+ const threadRef = React72.useRef(null);
12544
+ const mounted = React72.useRef(true);
12545
+ React72.useEffect(() => {
12484
12546
  mounted.current = true;
12485
12547
  return () => {
12486
12548
  mounted.current = false;
12487
12549
  };
12488
12550
  }, []);
12489
- const describeWaitingRef = React70.useRef(describeWaiting);
12551
+ const describeWaitingRef = React72.useRef(describeWaiting);
12490
12552
  describeWaitingRef.current = describeWaiting;
12491
12553
  const commit = (next) => {
12492
12554
  const derived = withWaiting(next, (pending) => describeWaitingRef.current(pending));
@@ -12505,7 +12567,7 @@ function useChatEngine(opts) {
12505
12567
  }
12506
12568
  return false;
12507
12569
  };
12508
- const loadThread = React70.useCallback(async (id) => {
12570
+ const loadThread = React72.useCallback(async (id) => {
12509
12571
  const data = await apiAdapter.getThread(id);
12510
12572
  const list = [...data && data.messages || []];
12511
12573
  serverCount.current = list.length;
@@ -12545,7 +12607,7 @@ function useChatEngine(opts) {
12545
12607
  packet: progress.packet ?? holder.packet
12546
12608
  });
12547
12609
  }
12548
- React70.useEffect(() => {
12610
+ React72.useEffect(() => {
12549
12611
  if (!apiAdapter) {
12550
12612
  setStatus("idle");
12551
12613
  setFatal(null);
@@ -12592,7 +12654,7 @@ function useChatEngine(opts) {
12592
12654
  setStatus("ready");
12593
12655
  loadedRef.current = true;
12594
12656
  onThreadReady && onThreadReady(id);
12595
- const stored = store.get(STORAGE_PREFIX + id);
12657
+ const stored = store.get(jobKey(id));
12596
12658
  const last = [...visibleMessages(listRef.current)].reverse().find((m) => m.role === "assistant");
12597
12659
  if (stored) resumeJob(stored);
12598
12660
  else if (last && last.working && last.jobId) resumeJob(last.jobId, last.id);
@@ -12611,7 +12673,7 @@ function useChatEngine(opts) {
12611
12673
  };
12612
12674
  }, [apiAdapter, contextType, contextId, threadIdProp]);
12613
12675
  async function pollJob(jobId, placeholderId) {
12614
- store.set(STORAGE_PREFIX + threadRef.current, jobId);
12676
+ store.set(jobKey(threadRef.current), jobId);
12615
12677
  const deadline = Date.now() + pendingTimeoutMs;
12616
12678
  while (true) {
12617
12679
  if (stoppedRef.current) break;
@@ -12659,7 +12721,7 @@ function useChatEngine(opts) {
12659
12721
  }
12660
12722
  }
12661
12723
  async function finishJob(_jobId, _job) {
12662
- store.del(STORAGE_PREFIX + threadRef.current);
12724
+ store.del(jobKey(threadRef.current));
12663
12725
  try {
12664
12726
  const list = await loadThread(threadRef.current);
12665
12727
  const withPacket = [...list].reverse().find((m) => m && m.packet);
@@ -12669,7 +12731,7 @@ function useChatEngine(opts) {
12669
12731
  }
12670
12732
  }
12671
12733
  function recordFailure(placeholderId, code, retryable, job) {
12672
- store.del(STORAGE_PREFIX + threadRef.current);
12734
+ store.del(jobKey(threadRef.current));
12673
12735
  if (!listRef.current.some((m) => m.id === placeholderId)) {
12674
12736
  push({ id: placeholderId, role: "assistant", text: null });
12675
12737
  }
@@ -12777,7 +12839,7 @@ function useChatEngine(opts) {
12777
12839
  await dispatchTurn(turn);
12778
12840
  }
12779
12841
  }
12780
- const send = React70.useCallback((text, attachments) => {
12842
+ const send = React72.useCallback((text, attachments) => {
12781
12843
  const body = (text || "").trim();
12782
12844
  if (!body && !(attachments && attachments.length)) return;
12783
12845
  if (status === "disconnected") return;
@@ -12787,7 +12849,7 @@ function useChatEngine(opts) {
12787
12849
  stoppedRef.current = false;
12788
12850
  drain();
12789
12851
  }, [status]);
12790
- const stop = React70.useCallback(() => {
12852
+ const stop = React72.useCallback(() => {
12791
12853
  stoppedRef.current = true;
12792
12854
  const ac = abortRef.current;
12793
12855
  if (ac) {
@@ -12803,14 +12865,14 @@ function useChatEngine(opts) {
12803
12865
  Promise.resolve(apiAdapter.cancelJob(holder.jobId)).catch(() => {
12804
12866
  });
12805
12867
  }
12806
- store.del(STORAGE_PREFIX + threadRef.current);
12868
+ store.del(jobKey(threadRef.current));
12807
12869
  }
12808
12870
  }, [apiAdapter]);
12809
- const removeQueued = React70.useCallback((id) => {
12871
+ const removeQueued = React72.useCallback((id) => {
12810
12872
  queueRef.current = queueRef.current.filter((t) => t.id !== id);
12811
12873
  setQueue(queueRef.current.slice());
12812
12874
  }, []);
12813
- const retry = React70.useCallback(() => {
12875
+ const retry = React72.useCallback(() => {
12814
12876
  const list = listRef.current;
12815
12877
  let at = -1;
12816
12878
  for (let i = list.length - 1; i >= 0; i--) if (list[i].role === "user") {
@@ -12827,19 +12889,19 @@ function useChatEngine(opts) {
12827
12889
  setQueue(queueRef.current.slice());
12828
12890
  drain();
12829
12891
  }, []);
12830
- const clear = React70.useCallback(() => {
12892
+ const clear = React72.useCallback(() => {
12831
12893
  commit([]);
12832
12894
  serverCount.current = 0;
12833
12895
  queueRef.current = [];
12834
12896
  setQueue([]);
12835
12897
  onClear && onClear();
12836
12898
  }, [onClear]);
12837
- const setFeedback = React70.useCallback((id, value) => {
12899
+ const setFeedback = React72.useCallback((id, value) => {
12838
12900
  patch(id, (m) => ({ feedback: m.feedback === value ? null : value }));
12839
12901
  const msg = listRef.current.find((m) => m.id === id);
12840
12902
  onFeedback && onFeedback({ message: msg, feedback: msg ? msg.feedback : value });
12841
12903
  }, [onFeedback]);
12842
- const reload = React70.useCallback(async () => {
12904
+ const reload = React72.useCallback(async () => {
12843
12905
  if (!threadRef.current) return;
12844
12906
  setStatus("loading");
12845
12907
  try {
@@ -12877,10 +12939,10 @@ var ChatKit = {
12877
12939
  };
12878
12940
 
12879
12941
  // src/components/chat/ChatTranscript.tsx
12880
- import * as React72 from "react";
12942
+ import * as React74 from "react";
12881
12943
 
12882
12944
  // src/components/chat/ChatTurn.tsx
12883
- import * as React71 from "react";
12945
+ import * as React73 from "react";
12884
12946
  import { jsx as jsx101, jsxs as jsxs88 } from "react/jsx-runtime";
12885
12947
  function JsonView({ value }) {
12886
12948
  let text;
@@ -12917,7 +12979,7 @@ function PacketCard({ packet, schema, render, onApply, applied }) {
12917
12979
  ] });
12918
12980
  }
12919
12981
  function ThinkingBlock({ text, durationMs, streaming, defaultOpen = false }) {
12920
- const [open2, setOpen] = React71.useState(defaultOpen);
12982
+ const [open2, setOpen] = React73.useState(defaultOpen);
12921
12983
  if (!text) return null;
12922
12984
  return /* @__PURE__ */ jsxs88("div", { className: "fdc-think" + (open2 ? " is-open" : ""), children: [
12923
12985
  /* @__PURE__ */ jsxs88("button", { type: "button", className: "fdc-think-head", onClick: () => setOpen((v) => !v), "aria-expanded": open2, children: [
@@ -12934,7 +12996,7 @@ function ThinkingBlock({ text, durationMs, streaming, defaultOpen = false }) {
12934
12996
  ] });
12935
12997
  }
12936
12998
  function Citations({ items = [], onOpen }) {
12937
- const [open2, setOpen] = React71.useState(false);
12999
+ const [open2, setOpen] = React73.useState(false);
12938
13000
  if (!items.length) return null;
12939
13001
  return /* @__PURE__ */ jsxs88("div", { className: "fdc-cites", children: [
12940
13002
  /* @__PURE__ */ jsxs88("button", { type: "button", className: "fdc-cites-head", onClick: () => setOpen((v) => !v), "aria-expanded": open2, children: [
@@ -12960,7 +13022,7 @@ function clampText(text, max) {
12960
13022
  return (at > max * 0.6 ? cut.slice(0, at) : cut).trimEnd() + "\u2026";
12961
13023
  }
12962
13024
  function MessageBody({ message: m, ctx }) {
12963
- const [expanded, setExpanded] = React71.useState(false);
13025
+ const [expanded, setExpanded] = React73.useState(false);
12964
13026
  const isUser = m.role === "user";
12965
13027
  const raw = m.text || "";
12966
13028
  const clamped = !expanded && !m.streaming ? clampText(raw, ctx.maxVisibleChars) : null;
@@ -13039,7 +13101,7 @@ function RunActions({ group, ctx }) {
13039
13101
  ] }),
13040
13102
  isAssistant && ctx.onRetry ? /* @__PURE__ */ jsx101("button", { type: "button", className: "fdc-act", onClick: ctx.onRetry, "aria-label": "Retry this turn", children: /* @__PURE__ */ jsx101("i", { className: "ph ph-arrow-clockwise", "aria-hidden": "true" }) }) : null,
13041
13103
  group.role === "user" && ctx.onEdit ? /* @__PURE__ */ jsx101("button", { type: "button", className: "fdc-act", onClick: () => ctx.onEdit(last), "aria-label": "Edit and resend", children: /* @__PURE__ */ jsx101("i", { className: "ph ph-pencil-simple", "aria-hidden": "true" }) }) : null,
13042
- isAssistant && ctx.onFeedback ? /* @__PURE__ */ jsxs88(React71.Fragment, { children: [
13104
+ isAssistant && ctx.onFeedback ? /* @__PURE__ */ jsxs88(React73.Fragment, { children: [
13043
13105
  /* @__PURE__ */ jsx101("button", { type: "button", className: "fdc-act" + (fb === "up" ? " is-on" : ""), onClick: () => ctx.onFeedback(last.id, "up"), "aria-pressed": fb === "up", "aria-label": "Good response", children: /* @__PURE__ */ jsx101("i", { className: "ph ph-thumbs-up", "aria-hidden": "true" }) }),
13044
13106
  /* @__PURE__ */ jsx101("button", { type: "button", className: "fdc-act" + (fb === "down" ? " is-on" : ""), onClick: () => ctx.onFeedback(last.id, "down"), "aria-pressed": fb === "down", "aria-label": "Bad response", children: /* @__PURE__ */ jsx101("i", { className: "ph ph-thumbs-down", "aria-hidden": "true" }) })
13045
13107
  ] }) : null,
@@ -13134,10 +13196,10 @@ function ChatTranscript({
13134
13196
  renderEmpty,
13135
13197
  className = ""
13136
13198
  }) {
13137
- const scroller = React72.useRef(null);
13138
- const stick = React72.useRef(true);
13139
- const [pill, setPill] = React72.useState(0);
13140
- const seen = React72.useRef(0);
13199
+ const scroller = React74.useRef(null);
13200
+ const stick = React74.useRef(true);
13201
+ const [pill, setPill] = React74.useState(0);
13202
+ const seen = React74.useRef(0);
13141
13203
  const toBottom = (smooth) => {
13142
13204
  const el = scroller.current;
13143
13205
  if (!el) return;
@@ -13156,7 +13218,7 @@ function ChatTranscript({
13156
13218
  seen.current = messages.length;
13157
13219
  }
13158
13220
  };
13159
- React72.useLayoutEffect(() => {
13221
+ React74.useLayoutEffect(() => {
13160
13222
  const el = scroller.current;
13161
13223
  if (!el) return;
13162
13224
  if (stick.current) {
@@ -13164,7 +13226,7 @@ function ChatTranscript({
13164
13226
  seen.current = messages.length;
13165
13227
  } else setPill(Math.max(0, messages.length - seen.current));
13166
13228
  }, [messages]);
13167
- React72.useEffect(() => {
13229
+ React74.useEffect(() => {
13168
13230
  const el = scroller.current;
13169
13231
  const inner = el && el.firstChild;
13170
13232
  if (!el || !inner || typeof ResizeObserver === "undefined") return;
@@ -13174,7 +13236,7 @@ function ChatTranscript({
13174
13236
  ro.observe(inner);
13175
13237
  return () => ro.disconnect();
13176
13238
  }, []);
13177
- const groups = React72.useMemo(() => groupMessages(messages), [messages]);
13239
+ const groups = React74.useMemo(() => groupMessages(messages), [messages]);
13178
13240
  const empty = !messages.length && status === "ready";
13179
13241
  return /* @__PURE__ */ jsxs89("div", { className: ["fdc-scroll", className].filter(Boolean).join(" "), ref: scroller, onScroll, children: [
13180
13242
  /* @__PURE__ */ jsxs89("div", { className: "fdc-log", role: "log", "aria-label": "Conversation", children: [
@@ -13198,7 +13260,7 @@ function ChatTranscript({
13198
13260
  const prev = groups[i - 1];
13199
13261
  const k = dayKey(g.messages[0].timestamp);
13200
13262
  const showDay = !!k && (!prev || dayKey(prev.messages[0].timestamp) !== k);
13201
- return /* @__PURE__ */ jsxs89(React72.Fragment, { children: [
13263
+ return /* @__PURE__ */ jsxs89(React74.Fragment, { children: [
13202
13264
  showDay ? /* @__PURE__ */ jsx102("div", { className: "fdc-day", children: /* @__PURE__ */ jsx102("span", { children: dayLabel(k) }) }) : null,
13203
13265
  /* @__PURE__ */ jsx102(ChatTurn, { group: g, ctx })
13204
13266
  ] }, g.key || i);
@@ -13215,7 +13277,7 @@ function ChatTranscript({
13215
13277
  var TranscriptKit = { groupMessages };
13216
13278
 
13217
13279
  // src/components/chat/ChatComposer.tsx
13218
- import * as React73 from "react";
13280
+ import * as React75 from "react";
13219
13281
  import { jsx as jsx103, jsxs as jsxs90 } from "react/jsx-runtime";
13220
13282
  function ChatComposer({
13221
13283
  onSubmit,
@@ -13243,17 +13305,17 @@ function ChatComposer({
13243
13305
  onReject,
13244
13306
  onOpenAttachment
13245
13307
  }) {
13246
- const [text, setText] = React73.useState(draft || "");
13247
- const [trigger, setTrigger] = React73.useState(null);
13248
- const [mentionItems, setMentionItems] = React73.useState([]);
13249
- const [listening, setListening] = React73.useState(false);
13250
- const [notice, setNotice] = React73.useState(null);
13251
- const editor = React73.useRef(null);
13252
- const wrap = React73.useRef(null);
13253
- const stopVoice = React73.useRef(null);
13308
+ const [text, setText] = React75.useState(draft || "");
13309
+ const [trigger, setTrigger] = React75.useState(null);
13310
+ const [mentionItems, setMentionItems] = React75.useState([]);
13311
+ const [listening, setListening] = React75.useState(false);
13312
+ const [notice, setNotice] = React75.useState(null);
13313
+ const editor = React75.useRef(null);
13314
+ const wrap = React75.useRef(null);
13315
+ const stopVoice = React75.useRef(null);
13254
13316
  const staged = useStagedFiles(fileUploadHandler, { onError: () => {
13255
13317
  } });
13256
- React73.useEffect(() => {
13318
+ React75.useEffect(() => {
13257
13319
  if (draft != null && draft !== text) setText(draft);
13258
13320
  }, [draft]);
13259
13321
  const change = (v) => {
@@ -13289,7 +13351,7 @@ function ChatComposer({
13289
13351
  e.preventDefault();
13290
13352
  staged.add(found.files);
13291
13353
  };
13292
- React73.useEffect(() => {
13354
+ React75.useEffect(() => {
13293
13355
  if (!trigger || trigger.type !== "mention" || !mentionSources) {
13294
13356
  setMentionItems([]);
13295
13357
  return;
@@ -13307,7 +13369,7 @@ function ChatComposer({
13307
13369
  const q = (trigger.query || "").toLowerCase();
13308
13370
  setMentionItems(mentionSources.filter((m) => !q || (m.label + " " + (m.description || "")).toLowerCase().includes(q)));
13309
13371
  }, [trigger, mentionSources]);
13310
- const slashItems = React73.useMemo(() => {
13372
+ const slashItems = React75.useMemo(() => {
13311
13373
  if (!trigger || trigger.type !== "slash" || !slashCommands) return [];
13312
13374
  const q = (trigger.query || "").toLowerCase();
13313
13375
  return slashCommands.filter((c) => !q || (c.id + " " + c.label + " " + (c.description || "")).toLowerCase().includes(q));
@@ -13477,12 +13539,12 @@ function ChatComposer({
13477
13539
  }
13478
13540
 
13479
13541
  // src/components/chat/ChatSessionBar.tsx
13480
- import * as React74 from "react";
13542
+ import * as React76 from "react";
13481
13543
  import { jsx as jsx104, jsxs as jsxs91 } from "react/jsx-runtime";
13482
13544
  var compact2 = meterFormats.compact;
13483
13545
  function ChatSessionBar({ sessionStats, contextUsage, usageLimits, onClear, extras }) {
13484
- const [open2, setOpen] = React74.useState(false);
13485
- const anchor = React74.useRef(null);
13546
+ const [open2, setOpen] = React76.useState(false);
13547
+ const anchor = React76.useRef(null);
13486
13548
  const stats = sessionStats || null;
13487
13549
  const cu = contextUsage || null;
13488
13550
  const limits = usageLimits || null;
@@ -13497,7 +13559,7 @@ function ChatSessionBar({ sessionStats, contextUsage, usageLimits, onClear, extr
13497
13559
  if (stats && stats.runningTasks) bits.push(stats.runningTasks + " running task" + (stats.runningTasks === 1 ? "" : "s"));
13498
13560
  if (cu) bits.push(pct + "% context");
13499
13561
  const expandable = !!(cu || limits);
13500
- return /* @__PURE__ */ jsxs91(React74.Fragment, { children: [
13562
+ return /* @__PURE__ */ jsxs91(React76.Fragment, { children: [
13501
13563
  /* @__PURE__ */ jsxs91("div", { className: "fdc-bar", children: [
13502
13564
  /* @__PURE__ */ jsxs91(
13503
13565
  "button",
@@ -13638,7 +13700,7 @@ function ModelControls({
13638
13700
  ] })
13639
13701
  });
13640
13702
  }
13641
- return /* @__PURE__ */ jsxs91(React74.Fragment, { children: [
13703
+ return /* @__PURE__ */ jsxs91(React76.Fragment, { children: [
13642
13704
  /* @__PURE__ */ jsx104(
13643
13705
  MenuButton,
13644
13706
  {
@@ -13677,6 +13739,7 @@ function AgentChatPanel({
13677
13739
  /* required */
13678
13740
  contextType,
13679
13741
  contextId,
13742
+ draftOwner,
13680
13743
  apiAdapter,
13681
13744
  threadId,
13682
13745
  /* identity + chrome */
@@ -13757,11 +13820,11 @@ function AgentChatPanel({
13757
13820
  onFeedback,
13758
13821
  onEditMessage
13759
13822
  }) {
13760
- const [panelWidth, setPanelWidth] = React75.useState(width);
13761
- const [applied, setApplied] = React75.useState({});
13762
- const [draft, setDraft] = React75.useState("");
13763
- const dragging = React75.useRef(null);
13764
- React75.useEffect(() => setPanelWidth(width), [width]);
13823
+ const [panelWidth, setPanelWidth] = React77.useState(width);
13824
+ const [applied, setApplied] = React77.useState({});
13825
+ const [draft, setDraft] = useChatDraft(draftOwner, contextType, contextId);
13826
+ const dragging = React77.useRef(null);
13827
+ React77.useEffect(() => setPanelWidth(width), [width]);
13765
13828
  const engine = useChatEngine({
13766
13829
  contextType,
13767
13830
  contextId,
@@ -13967,7 +14030,7 @@ function AgentChatPanel({
13967
14030
  }
13968
14031
 
13969
14032
  // src/components/files/FileViewer.tsx
13970
- import * as React76 from "react";
14033
+ import * as React78 from "react";
13971
14034
  import { jsx as jsx106, jsxs as jsxs93 } from "react/jsx-runtime";
13972
14035
  function previewKindOf(file) {
13973
14036
  const mime = (file.mime || "").toLowerCase();
@@ -14024,13 +14087,13 @@ function parseDelimited(text, delimiter) {
14024
14087
  return rows;
14025
14088
  }
14026
14089
  function usePreview(file, kind, resolveUrl) {
14027
- const [state, setState] = React76.useState({ status: "loading" });
14028
- const [attempt, setAttempt] = React76.useState(0);
14029
- const resolveRef = React76.useRef(resolveUrl);
14030
- React76.useEffect(() => {
14090
+ const [state, setState] = React78.useState({ status: "loading" });
14091
+ const [attempt, setAttempt] = React78.useState(0);
14092
+ const resolveRef = React78.useRef(resolveUrl);
14093
+ React78.useEffect(() => {
14031
14094
  resolveRef.current = resolveUrl;
14032
14095
  }, [resolveUrl]);
14033
- React76.useEffect(() => {
14096
+ React78.useEffect(() => {
14034
14097
  if (kind === "none") {
14035
14098
  setState({ status: "ready" });
14036
14099
  return;
@@ -14060,7 +14123,7 @@ function usePreview(file, kind, resolveUrl) {
14060
14123
  if (ac) ac.abort();
14061
14124
  };
14062
14125
  }, [file.id, kind, attempt]);
14063
- return { ...state, retry: React76.useCallback(() => setAttempt((a) => a + 1), []) };
14126
+ return { ...state, retry: React78.useCallback(() => setAttempt((a) => a + 1), []) };
14064
14127
  }
14065
14128
  function PreviewBody({ file, kind, state }) {
14066
14129
  if (kind === "image") return /* @__PURE__ */ jsx106("img", { className: "fd-fv-image", src: state.url, alt: file.name || "Preview" });
@@ -14105,13 +14168,13 @@ function PreviewBody({ file, kind, state }) {
14105
14168
  ] });
14106
14169
  }
14107
14170
  function FileViewer({ file, resolveUrl, sidePanel, sidePanelLabel = "Details", onClose, actions, className = "" }) {
14108
- const kind = React76.useMemo(() => previewKindOf(file), [file]);
14171
+ const kind = React78.useMemo(() => previewKindOf(file), [file]);
14109
14172
  const preview = usePreview(file, kind, resolveUrl);
14110
- const [tab, setTab] = React76.useState("preview");
14111
- const [downloading, setDownloading] = React76.useState(false);
14112
- const [downloadError, setDownloadError] = React76.useState(null);
14173
+ const [tab, setTab] = React78.useState("preview");
14174
+ const [downloading, setDownloading] = React78.useState(false);
14175
+ const [downloadError, setDownloadError] = React78.useState(null);
14113
14176
  const hasSide = sidePanel != null;
14114
- React76.useEffect(() => {
14177
+ React78.useEffect(() => {
14115
14178
  setTab("preview");
14116
14179
  }, [file.id]);
14117
14180
  const download = () => {
@@ -14178,7 +14241,7 @@ function FileViewer({ file, resolveUrl, sidePanel, sidePanelLabel = "Details", o
14178
14241
  }
14179
14242
 
14180
14243
  // src/components/files/FileBrowser.tsx
14181
- import * as React77 from "react";
14244
+ import * as React79 from "react";
14182
14245
  import { Fragment as Fragment31, jsx as jsx107, jsxs as jsxs94 } from "react/jsx-runtime";
14183
14246
  function childrenOf(folders, parentId) {
14184
14247
  return folders.filter((f) => f.parentId === parentId).sort((a, b) => a.name.localeCompare(b.name));
@@ -14288,8 +14351,8 @@ function FolderPickerMenu({
14288
14351
  ] });
14289
14352
  }
14290
14353
  function RowShell({ icon, name, meta, onOpen, draggableId, isDropTarget, onDropPayload, actions, className = "" }) {
14291
- const [over, setOver] = React77.useState(false);
14292
- const dragCounter = React77.useRef(0);
14354
+ const [over, setOver] = React79.useState(false);
14355
+ const dragCounter = React79.useRef(0);
14293
14356
  const dropHandlers = isDropTarget ? {
14294
14357
  onDragEnter: (e) => {
14295
14358
  if (!hasInternalPayload(e)) return;
@@ -14337,8 +14400,8 @@ function RowShell({ icon, name, meta, onOpen, draggableId, isDropTarget, onDropP
14337
14400
  }
14338
14401
  function TreeNode({ folder, depth, folders, currentFolderId, onNavigate, onMoveInto, canMove }) {
14339
14402
  const kids = childrenOf(folders, folder.id);
14340
- const [expanded, setExpanded] = React77.useState(() => currentFolderId != null && isSelfOrDescendant(folders, folder.id, currentFolderId));
14341
- React77.useEffect(() => {
14403
+ const [expanded, setExpanded] = React79.useState(() => currentFolderId != null && isSelfOrDescendant(folders, folder.id, currentFolderId));
14404
+ React79.useEffect(() => {
14342
14405
  if (currentFolderId != null && isSelfOrDescendant(folders, folder.id, currentFolderId)) setExpanded(true);
14343
14406
  }, [currentFolderId, folder.id, folders]);
14344
14407
  const isCurrent = folder.id === currentFolderId;
@@ -14404,15 +14467,15 @@ function FileBrowser({
14404
14467
  const canUpload = perm.canUpload !== false && !!onUpload;
14405
14468
  const canRemoveFile = perm.canRemoveFile !== false && !!onRemoveFile;
14406
14469
  const canDeleteFolder = perm.canDeleteFolder !== false && !!onDeleteFolder;
14407
- const [createOpen, setCreateOpen] = React77.useState(false);
14408
- const [createName, setCreateName] = React77.useState("");
14409
- const [renameTarget, setRenameTarget] = React77.useState(null);
14410
- const [renameValue, setRenameValue] = React77.useState("");
14411
- const [deleteTarget, setDeleteTarget] = React77.useState(null);
14412
- const uploadInputRef = React77.useRef(null);
14413
- const crumbFolders = React77.useMemo(() => ancestorsOf(folders, currentFolderId), [folders, currentFolderId]);
14414
- const subfolders = React77.useMemo(() => childrenOf(folders, currentFolderId), [folders, currentFolderId]);
14415
- const currentFiles = React77.useMemo(
14470
+ const [createOpen, setCreateOpen] = React79.useState(false);
14471
+ const [createName, setCreateName] = React79.useState("");
14472
+ const [renameTarget, setRenameTarget] = React79.useState(null);
14473
+ const [renameValue, setRenameValue] = React79.useState("");
14474
+ const [deleteTarget, setDeleteTarget] = React79.useState(null);
14475
+ const uploadInputRef = React79.useRef(null);
14476
+ const crumbFolders = React79.useMemo(() => ancestorsOf(folders, currentFolderId), [folders, currentFolderId]);
14477
+ const subfolders = React79.useMemo(() => childrenOf(folders, currentFolderId), [folders, currentFolderId]);
14478
+ const currentFiles = React79.useMemo(
14416
14479
  () => files.filter((f) => f.folderId === currentFolderId).sort((a, b) => a.name.localeCompare(b.name)),
14417
14480
  [files, currentFolderId]
14418
14481
  );
@@ -14644,8 +14707,8 @@ function BreadcrumbCrumb({
14644
14707
  isDropTarget,
14645
14708
  onDropPayload
14646
14709
  }) {
14647
- const [over, setOver] = React77.useState(false);
14648
- const dragCounter = React77.useRef(0);
14710
+ const [over, setOver] = React79.useState(false);
14711
+ const dragCounter = React79.useRef(0);
14649
14712
  const dropHandlers = isDropTarget ? {
14650
14713
  onDragEnter: (e) => {
14651
14714
  if (!hasInternalPayload(e)) return;
@@ -14674,7 +14737,7 @@ function BreadcrumbCrumb({
14674
14737
  }
14675
14738
 
14676
14739
  // src/kits/query.ts
14677
- import * as React78 from "react";
14740
+ import * as React80 from "react";
14678
14741
 
14679
14742
  // src/kits/queryUrl.ts
14680
14743
  var historyUrlAdapter = {
@@ -14812,38 +14875,38 @@ function requestFor(params, query, paging, after) {
14812
14875
  }
14813
14876
  var toError = (e) => e instanceof Error ? e : new Error(String(e));
14814
14877
  function useServerTable({ endpoint, params, defaults, deps, prefsKey, paging = "page", url }) {
14815
- const [base] = React78.useState(() => {
14878
+ const [base] = React80.useState(() => {
14816
14879
  const store = PREFS || window.PlannerPrefs;
14817
14880
  const saved = prefsKey && store ? store.getTable(prefsKey) : {};
14818
14881
  return { ...DEFAULTS, ...defaults || {}, ...saved.pageSize ? { pageSize: saved.pageSize } : {}, ...saved.sort ? { sort: saved.sort, dir: saved.dir || "desc" } : {} };
14819
14882
  });
14820
- const [mountParams] = React78.useState(() => url ? (url.adapter ?? historyUrlAdapter).read() : null);
14821
- const address = React78.useRef(mountParams);
14822
- const [query, setQuery] = React78.useState(() => url && mountParams ? readQueryFromUrl(mountParams, url.scope, base, paging) : base);
14823
- const savePref = React78.useCallback((patch2) => {
14883
+ const [mountParams] = React80.useState(() => url ? (url.adapter ?? historyUrlAdapter).read() : null);
14884
+ const address = React80.useRef(mountParams);
14885
+ const [query, setQuery] = React80.useState(() => url && mountParams ? readQueryFromUrl(mountParams, url.scope, base, paging) : base);
14886
+ const savePref = React80.useCallback((patch2) => {
14824
14887
  const store = PREFS || window.PlannerPrefs;
14825
14888
  if (prefsKey && store) store.setTable(prefsKey, patch2);
14826
14889
  }, [prefsKey]);
14827
- const [res, setRes] = React78.useState(null);
14828
- const [loading, setLoading] = React78.useState(true);
14829
- const [loadingMore, setLoadingMore] = React78.useState(false);
14830
- const [failure, setFailure] = React78.useState(null);
14831
- const [reloadToken, setReloadToken] = React78.useState(0);
14832
- const moreController = React78.useRef(null);
14890
+ const [res, setRes] = React80.useState(null);
14891
+ const [loading, setLoading] = React80.useState(true);
14892
+ const [loadingMore, setLoadingMore] = React80.useState(false);
14893
+ const [failure, setFailure] = React80.useState(null);
14894
+ const [reloadToken, setReloadToken] = React80.useState(0);
14895
+ const moreController = React80.useRef(null);
14833
14896
  const depKey = (deps || []).join("|");
14834
14897
  const paramKey = JSON.stringify(params || {});
14835
14898
  const queryKey = JSON.stringify(query);
14836
- const lifetime = React78.useRef(null);
14837
- React78.useEffect(() => {
14899
+ const lifetime = React80.useRef(null);
14900
+ React80.useEffect(() => {
14838
14901
  const controller = new AbortController();
14839
14902
  lifetime.current = controller;
14840
14903
  return () => controller.abort();
14841
14904
  }, []);
14842
- const latest = React78.useRef({ res, loading, query, params, endpoint, url, base });
14843
- React78.useLayoutEffect(() => {
14905
+ const latest = React80.useRef({ res, loading, query, params, endpoint, url, base });
14906
+ React80.useLayoutEffect(() => {
14844
14907
  latest.current = { res, loading, query, params, endpoint, url, base };
14845
14908
  });
14846
- React78.useEffect(() => {
14909
+ React80.useEffect(() => {
14847
14910
  const controller = new AbortController();
14848
14911
  const { signal } = controller;
14849
14912
  setLoading(true);
@@ -14879,7 +14942,7 @@ function useServerTable({ endpoint, params, defaults, deps, prefsKey, paging = "
14879
14942
  };
14880
14943
  }, [endpoint, queryKey, paramKey, depKey, paging, reloadToken]);
14881
14944
  const adapter = url ? url.adapter ?? historyUrlAdapter : null;
14882
- React78.useEffect(() => {
14945
+ React80.useEffect(() => {
14883
14946
  if (!adapter) return;
14884
14947
  return adapter.subscribe((params2) => {
14885
14948
  const { url: u, base: b } = latest.current;
@@ -15229,12 +15292,12 @@ function createVersionStore(initialState, options) {
15229
15292
  }
15230
15293
 
15231
15294
  // src/kits/documentTitle.ts
15232
- import * as React79 from "react";
15295
+ import * as React81 from "react";
15233
15296
  function formatDocumentTitle(routeTitle, appName) {
15234
- return [routeTitle, appName, "Flytedesk"].filter((part) => !!part && part.length > 0).join(" \xB7 ");
15297
+ return [routeTitle, appName, "Flytedesk"].filter((part2) => !!part2 && part2.length > 0).join(" \xB7 ");
15235
15298
  }
15236
15299
  function useDocumentTitle(routeTitle, appName) {
15237
- React79.useEffect(() => {
15300
+ React81.useEffect(() => {
15238
15301
  if (typeof document === "undefined") return;
15239
15302
  document.title = formatDocumentTitle(routeTitle, appName);
15240
15303
  }, [routeTitle, appName]);
@@ -15344,6 +15407,7 @@ export {
15344
15407
  ModeSwitch,
15345
15408
  ModelControls,
15346
15409
  NumberInput,
15410
+ OVERLAY_BREAKPOINT,
15347
15411
  OVERLAY_CEILING,
15348
15412
  POPOVER_BODY_MIN,
15349
15413
  PacketCard,
@@ -15468,6 +15532,7 @@ export {
15468
15532
  useDocumentTitle,
15469
15533
  useFeatureStatus,
15470
15534
  useLayerZIndex,
15535
+ useOverlayLayout,
15471
15536
  usePopoverPosition,
15472
15537
  useResponsiveRail,
15473
15538
  useRuntimeMode,