@flytedan/flytebot-design-system 0.72.0 → 0.73.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.cjs CHANGED
@@ -1013,6 +1013,7 @@ __export(index_exports, {
1013
1013
  ModeSwitch: () => ModeSwitch,
1014
1014
  ModelControls: () => ModelControls,
1015
1015
  NumberInput: () => NumberInput,
1016
+ OVERLAY_BREAKPOINT: () => OVERLAY_BREAKPOINT,
1016
1017
  OVERLAY_CEILING: () => OVERLAY_CEILING,
1017
1018
  POPOVER_BODY_MIN: () => POPOVER_BODY_MIN,
1018
1019
  PacketCard: () => PacketCard,
@@ -1137,6 +1138,7 @@ __export(index_exports, {
1137
1138
  useDocumentTitle: () => useDocumentTitle,
1138
1139
  useFeatureStatus: () => useFeatureStatus,
1139
1140
  useLayerZIndex: () => useLayerZIndex,
1141
+ useOverlayLayout: () => useOverlayLayout,
1140
1142
  usePopoverPosition: () => usePopoverPosition,
1141
1143
  useResponsiveRail: () => useResponsiveRail,
1142
1144
  useRuntimeMode: () => useRuntimeMode,
@@ -2083,7 +2085,7 @@ function Collapsible({
2083
2085
  var React6 = __toESM(require("react"), 1);
2084
2086
  var import_react_dom3 = require("react-dom");
2085
2087
  var import_jsx_runtime9 = require("react/jsx-runtime");
2086
- function Drawer({ open: open2 = true, title, onClose, footer, bare = false, children, className = "", ...rest }) {
2088
+ function Drawer({ open: open2 = true, title, label, onClose, footer, bare = false, children, className = "", ...rest }) {
2087
2089
  const asideRef = React6.useRef(null);
2088
2090
  const [closing, setClosing] = React6.useState(false);
2089
2091
  const close2 = React6.useCallback(() => {
@@ -2093,13 +2095,19 @@ function Drawer({ open: open2 = true, title, onClose, footer, bare = false, chil
2093
2095
  }, [onClose]);
2094
2096
  const layer = useStackedLayer({ active: !!open2, containerRef: asideRef, trap: true, onEscape: onClose ? close2 : void 0 });
2095
2097
  const zIndex = useLayerZIndex(layer);
2098
+ const titleId = React6.useId();
2099
+ const accessibleName = bare ? label ?? (typeof title === "string" ? title : void 0) : label;
2100
+ const unnamed = !!open2 && bare && !accessibleName;
2101
+ React6.useEffect(() => {
2102
+ 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.");
2103
+ }, [unnamed]);
2096
2104
  if (!open2) return null;
2097
2105
  return (0, import_react_dom3.createPortal)(
2098
2106
  /* @__PURE__ */ (0, import_jsx_runtime9.jsxs)(StackedLayerProvider, { layer, children: [
2099
2107
  /* @__PURE__ */ (0, import_jsx_runtime9.jsx)("div", { className: "fd-scrim" + (closing ? " is-closing" : ""), style: { display: "block", zIndex: zIndex - LAYER_STEP }, onClick: close2 }),
2100
- /* @__PURE__ */ (0, import_jsx_runtime9.jsxs)("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: [
2108
+ /* @__PURE__ */ (0, import_jsx_runtime9.jsxs)("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: [
2101
2109
  bare ? null : /* @__PURE__ */ (0, import_jsx_runtime9.jsxs)("div", { className: "fd-card-head", style: { flex: "none" }, children: [
2102
- /* @__PURE__ */ (0, import_jsx_runtime9.jsx)("span", { className: "fd-card-head-title", title: truncationTitle(title), children: title }),
2110
+ /* @__PURE__ */ (0, import_jsx_runtime9.jsx)("span", { id: titleId, className: "fd-card-head-title", title: truncationTitle(title), children: title }),
2103
2111
  onClose ? /* @__PURE__ */ (0, import_jsx_runtime9.jsx)("button", { type: "button", className: "fd-btn-icon", "aria-label": "Close", onClick: close2, children: /* @__PURE__ */ (0, import_jsx_runtime9.jsx)("i", { className: "ph ph-x" }) }) : null
2104
2112
  ] }),
2105
2113
  /* @__PURE__ */ (0, import_jsx_runtime9.jsx)("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 }),
@@ -2672,8 +2680,16 @@ function Topbar({
2672
2680
 
2673
2681
  // src/kits/useResponsiveRail.ts
2674
2682
  var React15 = __toESM(require("react"), 1);
2683
+
2684
+ // src/kits/overlayLayout.ts
2685
+ var OVERLAY_BREAKPOINT = 1024;
2686
+ function useOverlayLayout() {
2687
+ return useIsNarrow(OVERLAY_BREAKPOINT);
2688
+ }
2689
+
2690
+ // src/kits/useResponsiveRail.ts
2675
2691
  function useResponsiveRail(options = {}) {
2676
- const { breakpoint = 1024, initialOpen = true, onPersist } = options;
2692
+ const { breakpoint = OVERLAY_BREAKPOINT, initialOpen = true, onPersist } = options;
2677
2693
  const navRef = React15.useRef(null);
2678
2694
  const overlay = useIsNarrow(breakpoint);
2679
2695
  const [open2, setOpenRaw] = React15.useState(() => overlay ? false : initialOpen);
@@ -2714,7 +2730,7 @@ function AppShell({
2714
2730
  navFooter,
2715
2731
  initialNavOpen = true,
2716
2732
  onNavOpenChange,
2717
- railBreakpoint = 1024,
2733
+ railBreakpoint = OVERLAY_BREAKPOINT,
2718
2734
  crumbs,
2719
2735
  loading,
2720
2736
  actions,
@@ -5034,7 +5050,7 @@ var import_jsx_runtime50 = require("react/jsx-runtime");
5034
5050
  var TAIL_CHARS = 12;
5035
5051
  var graphemes = new Intl.Segmenter(void 0, { granularity: "grapheme" });
5036
5052
  function splitForMiddleEllipsis(text) {
5037
- const chars = Array.from(graphemes.segment(text), (part) => part.segment);
5053
+ const chars = Array.from(graphemes.segment(text), (part2) => part2.segment);
5038
5054
  if (chars.length <= TAIL_CHARS) return { head: text, tail: "" };
5039
5055
  return { head: chars.slice(0, -TAIL_CHARS).join(""), tail: chars.slice(-TAIL_CHARS).join("") };
5040
5056
  }
@@ -13566,17 +13582,13 @@ function PreferenceMeter({
13566
13582
  }
13567
13583
 
13568
13584
  // src/components/chat/AgentChatPanel.tsx
13569
- var React75 = __toESM(require("react"), 1);
13585
+ var React76 = __toESM(require("react"), 1);
13570
13586
 
13571
13587
  // src/components/chat/chatEngine.ts
13588
+ var React71 = __toESM(require("react"), 1);
13589
+
13590
+ // src/components/chat/chatStore.ts
13572
13591
  var React70 = __toESM(require("react"), 1);
13573
- var CHAT_UNAVAILABLE = "chat_unavailable";
13574
- var JOB_PENDING = ["queued", "running"];
13575
- var JOB_SUCCESS = ["completed", "recovered"];
13576
- var STORAGE_PREFIX = "fdchat:job:";
13577
- var seq = 0;
13578
- var uid = (p) => p + "_" + ++seq + "_" + Date.now().toString(36);
13579
- var sleep = (ms) => new Promise((r) => setTimeout(r, ms));
13580
13592
  var safeStore = {
13581
13593
  get(k) {
13582
13594
  try {
@@ -13598,6 +13610,38 @@ var safeStore = {
13598
13610
  }
13599
13611
  }
13600
13612
  };
13613
+ var part = (v) => encodeURIComponent(v);
13614
+ var jobKey = (threadId) => "fdchat:job:" + part(threadId);
13615
+ var draftKey = (owner, contextType, contextId) => "fdchat:draft:" + [owner, contextType, contextId].map(part).join(":");
13616
+ function useChatDraft(owner, contextType, contextId, store = safeStore) {
13617
+ if (owner === "") throw new Error("useChatDraft: draftOwner is an empty string; pass the signed-in user's id, or null for no owner.");
13618
+ const key = owner === null ? null : draftKey(owner, contextType, contextId);
13619
+ const read2 = (k) => k ? store.get(k) || "" : "";
13620
+ const [state, setState] = React70.useState(() => ({ key, text: read2(key) }));
13621
+ let current2 = state;
13622
+ if (state.key !== key) {
13623
+ current2 = { key, text: read2(key) };
13624
+ setState(current2);
13625
+ }
13626
+ const setText = React70.useCallback((text) => {
13627
+ if (key) {
13628
+ if (text) {
13629
+ store.set(key, text);
13630
+ if (store.get(key) !== text) store.del(key);
13631
+ } else store.del(key);
13632
+ }
13633
+ setState({ key, text });
13634
+ }, [key, store]);
13635
+ return [current2.text, setText];
13636
+ }
13637
+
13638
+ // src/components/chat/chatEngine.ts
13639
+ var CHAT_UNAVAILABLE = "chat_unavailable";
13640
+ var JOB_PENDING = ["queued", "running"];
13641
+ var JOB_SUCCESS = ["completed", "recovered"];
13642
+ var seq = 0;
13643
+ var uid = (p) => p + "_" + ++seq + "_" + Date.now().toString(36);
13644
+ var sleep = (ms) => new Promise((r) => setTimeout(r, ms));
13601
13645
  var isSystemMessage = (m) => !!m && (m.role === "system" || m.metadata != null && m.metadata.type === "system");
13602
13646
  var visibleMessages = (list) => (list || []).filter((m) => !isSystemMessage(m));
13603
13647
  function jobBucket(status) {
@@ -13638,33 +13682,33 @@ function useChatEngine(opts) {
13638
13682
  onClear,
13639
13683
  onFeedback
13640
13684
  } = opts || {};
13641
- const [status, setStatus] = React70.useState("idle");
13642
- const [threadId, setThreadId] = React70.useState(null);
13643
- const [messages, setMessages] = React70.useState([]);
13644
- const [queue, setQueue] = React70.useState([]);
13645
- const [fatal, setFatal] = React70.useState(null);
13646
- const [busy, setBusy] = React70.useState(false);
13647
- const [turnStartedAt, setTurnStartedAt] = React70.useState(null);
13648
- const listRef = React70.useRef([]);
13649
- const queueRef = React70.useRef([]);
13650
- const busyRef = React70.useRef(false);
13651
- const loadedRef = React70.useRef(false);
13652
- const stoppedRef = React70.useRef(false);
13653
- const abortRef = React70.useRef(null);
13654
- const serverCount = React70.useRef(0);
13655
- const serverIds = React70.useRef(/* @__PURE__ */ new Set());
13656
- const liveTurn = React70.useRef(null);
13657
- const lastTurnOwn = React70.useRef(/* @__PURE__ */ new Set());
13658
- const retired = React70.useRef(/* @__PURE__ */ new Set());
13659
- const threadRef = React70.useRef(null);
13660
- const mounted = React70.useRef(true);
13661
- React70.useEffect(() => {
13685
+ const [status, setStatus] = React71.useState("idle");
13686
+ const [threadId, setThreadId] = React71.useState(null);
13687
+ const [messages, setMessages] = React71.useState([]);
13688
+ const [queue, setQueue] = React71.useState([]);
13689
+ const [fatal, setFatal] = React71.useState(null);
13690
+ const [busy, setBusy] = React71.useState(false);
13691
+ const [turnStartedAt, setTurnStartedAt] = React71.useState(null);
13692
+ const listRef = React71.useRef([]);
13693
+ const queueRef = React71.useRef([]);
13694
+ const busyRef = React71.useRef(false);
13695
+ const loadedRef = React71.useRef(false);
13696
+ const stoppedRef = React71.useRef(false);
13697
+ const abortRef = React71.useRef(null);
13698
+ const serverCount = React71.useRef(0);
13699
+ const serverIds = React71.useRef(/* @__PURE__ */ new Set());
13700
+ const liveTurn = React71.useRef(null);
13701
+ const lastTurnOwn = React71.useRef(/* @__PURE__ */ new Set());
13702
+ const retired = React71.useRef(/* @__PURE__ */ new Set());
13703
+ const threadRef = React71.useRef(null);
13704
+ const mounted = React71.useRef(true);
13705
+ React71.useEffect(() => {
13662
13706
  mounted.current = true;
13663
13707
  return () => {
13664
13708
  mounted.current = false;
13665
13709
  };
13666
13710
  }, []);
13667
- const describeWaitingRef = React70.useRef(describeWaiting);
13711
+ const describeWaitingRef = React71.useRef(describeWaiting);
13668
13712
  describeWaitingRef.current = describeWaiting;
13669
13713
  const commit = (next) => {
13670
13714
  const derived = withWaiting(next, (pending) => describeWaitingRef.current(pending));
@@ -13683,7 +13727,7 @@ function useChatEngine(opts) {
13683
13727
  }
13684
13728
  return false;
13685
13729
  };
13686
- const loadThread = React70.useCallback(async (id) => {
13730
+ const loadThread = React71.useCallback(async (id) => {
13687
13731
  const data = await apiAdapter.getThread(id);
13688
13732
  const list = [...data && data.messages || []];
13689
13733
  serverCount.current = list.length;
@@ -13723,7 +13767,7 @@ function useChatEngine(opts) {
13723
13767
  packet: progress.packet ?? holder.packet
13724
13768
  });
13725
13769
  }
13726
- React70.useEffect(() => {
13770
+ React71.useEffect(() => {
13727
13771
  if (!apiAdapter) {
13728
13772
  setStatus("idle");
13729
13773
  setFatal(null);
@@ -13770,7 +13814,7 @@ function useChatEngine(opts) {
13770
13814
  setStatus("ready");
13771
13815
  loadedRef.current = true;
13772
13816
  onThreadReady && onThreadReady(id);
13773
- const stored = store.get(STORAGE_PREFIX + id);
13817
+ const stored = store.get(jobKey(id));
13774
13818
  const last = [...visibleMessages(listRef.current)].reverse().find((m) => m.role === "assistant");
13775
13819
  if (stored) resumeJob(stored);
13776
13820
  else if (last && last.working && last.jobId) resumeJob(last.jobId, last.id);
@@ -13789,7 +13833,7 @@ function useChatEngine(opts) {
13789
13833
  };
13790
13834
  }, [apiAdapter, contextType, contextId, threadIdProp]);
13791
13835
  async function pollJob(jobId, placeholderId) {
13792
- store.set(STORAGE_PREFIX + threadRef.current, jobId);
13836
+ store.set(jobKey(threadRef.current), jobId);
13793
13837
  const deadline = Date.now() + pendingTimeoutMs;
13794
13838
  while (true) {
13795
13839
  if (stoppedRef.current) break;
@@ -13837,7 +13881,7 @@ function useChatEngine(opts) {
13837
13881
  }
13838
13882
  }
13839
13883
  async function finishJob(_jobId, _job) {
13840
- store.del(STORAGE_PREFIX + threadRef.current);
13884
+ store.del(jobKey(threadRef.current));
13841
13885
  try {
13842
13886
  const list = await loadThread(threadRef.current);
13843
13887
  const withPacket = [...list].reverse().find((m) => m && m.packet);
@@ -13847,7 +13891,7 @@ function useChatEngine(opts) {
13847
13891
  }
13848
13892
  }
13849
13893
  function recordFailure(placeholderId, code, retryable, job) {
13850
- store.del(STORAGE_PREFIX + threadRef.current);
13894
+ store.del(jobKey(threadRef.current));
13851
13895
  if (!listRef.current.some((m) => m.id === placeholderId)) {
13852
13896
  push({ id: placeholderId, role: "assistant", text: null });
13853
13897
  }
@@ -13955,7 +13999,7 @@ function useChatEngine(opts) {
13955
13999
  await dispatchTurn(turn);
13956
14000
  }
13957
14001
  }
13958
- const send = React70.useCallback((text, attachments) => {
14002
+ const send = React71.useCallback((text, attachments) => {
13959
14003
  const body = (text || "").trim();
13960
14004
  if (!body && !(attachments && attachments.length)) return;
13961
14005
  if (status === "disconnected") return;
@@ -13965,7 +14009,7 @@ function useChatEngine(opts) {
13965
14009
  stoppedRef.current = false;
13966
14010
  drain();
13967
14011
  }, [status]);
13968
- const stop = React70.useCallback(() => {
14012
+ const stop = React71.useCallback(() => {
13969
14013
  stoppedRef.current = true;
13970
14014
  const ac = abortRef.current;
13971
14015
  if (ac) {
@@ -13981,14 +14025,14 @@ function useChatEngine(opts) {
13981
14025
  Promise.resolve(apiAdapter.cancelJob(holder.jobId)).catch(() => {
13982
14026
  });
13983
14027
  }
13984
- store.del(STORAGE_PREFIX + threadRef.current);
14028
+ store.del(jobKey(threadRef.current));
13985
14029
  }
13986
14030
  }, [apiAdapter]);
13987
- const removeQueued = React70.useCallback((id) => {
14031
+ const removeQueued = React71.useCallback((id) => {
13988
14032
  queueRef.current = queueRef.current.filter((t) => t.id !== id);
13989
14033
  setQueue(queueRef.current.slice());
13990
14034
  }, []);
13991
- const retry = React70.useCallback(() => {
14035
+ const retry = React71.useCallback(() => {
13992
14036
  const list = listRef.current;
13993
14037
  let at = -1;
13994
14038
  for (let i = list.length - 1; i >= 0; i--) if (list[i].role === "user") {
@@ -14005,19 +14049,19 @@ function useChatEngine(opts) {
14005
14049
  setQueue(queueRef.current.slice());
14006
14050
  drain();
14007
14051
  }, []);
14008
- const clear = React70.useCallback(() => {
14052
+ const clear = React71.useCallback(() => {
14009
14053
  commit([]);
14010
14054
  serverCount.current = 0;
14011
14055
  queueRef.current = [];
14012
14056
  setQueue([]);
14013
14057
  onClear && onClear();
14014
14058
  }, [onClear]);
14015
- const setFeedback = React70.useCallback((id, value) => {
14059
+ const setFeedback = React71.useCallback((id, value) => {
14016
14060
  patch(id, (m) => ({ feedback: m.feedback === value ? null : value }));
14017
14061
  const msg = listRef.current.find((m) => m.id === id);
14018
14062
  onFeedback && onFeedback({ message: msg, feedback: msg ? msg.feedback : value });
14019
14063
  }, [onFeedback]);
14020
- const reload = React70.useCallback(async () => {
14064
+ const reload = React71.useCallback(async () => {
14021
14065
  if (!threadRef.current) return;
14022
14066
  setStatus("loading");
14023
14067
  try {
@@ -14055,10 +14099,10 @@ var ChatKit = {
14055
14099
  };
14056
14100
 
14057
14101
  // src/components/chat/ChatTranscript.tsx
14058
- var React72 = __toESM(require("react"), 1);
14102
+ var React73 = __toESM(require("react"), 1);
14059
14103
 
14060
14104
  // src/components/chat/ChatTurn.tsx
14061
- var React71 = __toESM(require("react"), 1);
14105
+ var React72 = __toESM(require("react"), 1);
14062
14106
  var import_jsx_runtime102 = require("react/jsx-runtime");
14063
14107
  function JsonView({ value }) {
14064
14108
  let text;
@@ -14095,7 +14139,7 @@ function PacketCard({ packet, schema, render, onApply, applied }) {
14095
14139
  ] });
14096
14140
  }
14097
14141
  function ThinkingBlock({ text, durationMs, streaming, defaultOpen = false }) {
14098
- const [open2, setOpen] = React71.useState(defaultOpen);
14142
+ const [open2, setOpen] = React72.useState(defaultOpen);
14099
14143
  if (!text) return null;
14100
14144
  return /* @__PURE__ */ (0, import_jsx_runtime102.jsxs)("div", { className: "fdc-think" + (open2 ? " is-open" : ""), children: [
14101
14145
  /* @__PURE__ */ (0, import_jsx_runtime102.jsxs)("button", { type: "button", className: "fdc-think-head", onClick: () => setOpen((v) => !v), "aria-expanded": open2, children: [
@@ -14112,7 +14156,7 @@ function ThinkingBlock({ text, durationMs, streaming, defaultOpen = false }) {
14112
14156
  ] });
14113
14157
  }
14114
14158
  function Citations({ items = [], onOpen }) {
14115
- const [open2, setOpen] = React71.useState(false);
14159
+ const [open2, setOpen] = React72.useState(false);
14116
14160
  if (!items.length) return null;
14117
14161
  return /* @__PURE__ */ (0, import_jsx_runtime102.jsxs)("div", { className: "fdc-cites", children: [
14118
14162
  /* @__PURE__ */ (0, import_jsx_runtime102.jsxs)("button", { type: "button", className: "fdc-cites-head", onClick: () => setOpen((v) => !v), "aria-expanded": open2, children: [
@@ -14138,7 +14182,7 @@ function clampText(text, max) {
14138
14182
  return (at > max * 0.6 ? cut.slice(0, at) : cut).trimEnd() + "\u2026";
14139
14183
  }
14140
14184
  function MessageBody({ message: m, ctx }) {
14141
- const [expanded, setExpanded] = React71.useState(false);
14185
+ const [expanded, setExpanded] = React72.useState(false);
14142
14186
  const isUser = m.role === "user";
14143
14187
  const raw = m.text || "";
14144
14188
  const clamped = !expanded && !m.streaming ? clampText(raw, ctx.maxVisibleChars) : null;
@@ -14217,7 +14261,7 @@ function RunActions({ group, ctx }) {
14217
14261
  ] }),
14218
14262
  isAssistant && ctx.onRetry ? /* @__PURE__ */ (0, import_jsx_runtime102.jsx)("button", { type: "button", className: "fdc-act", onClick: ctx.onRetry, "aria-label": "Retry this turn", children: /* @__PURE__ */ (0, import_jsx_runtime102.jsx)("i", { className: "ph ph-arrow-clockwise", "aria-hidden": "true" }) }) : null,
14219
14263
  group.role === "user" && ctx.onEdit ? /* @__PURE__ */ (0, import_jsx_runtime102.jsx)("button", { type: "button", className: "fdc-act", onClick: () => ctx.onEdit(last), "aria-label": "Edit and resend", children: /* @__PURE__ */ (0, import_jsx_runtime102.jsx)("i", { className: "ph ph-pencil-simple", "aria-hidden": "true" }) }) : null,
14220
- isAssistant && ctx.onFeedback ? /* @__PURE__ */ (0, import_jsx_runtime102.jsxs)(React71.Fragment, { children: [
14264
+ isAssistant && ctx.onFeedback ? /* @__PURE__ */ (0, import_jsx_runtime102.jsxs)(React72.Fragment, { children: [
14221
14265
  /* @__PURE__ */ (0, import_jsx_runtime102.jsx)("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__ */ (0, import_jsx_runtime102.jsx)("i", { className: "ph ph-thumbs-up", "aria-hidden": "true" }) }),
14222
14266
  /* @__PURE__ */ (0, import_jsx_runtime102.jsx)("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__ */ (0, import_jsx_runtime102.jsx)("i", { className: "ph ph-thumbs-down", "aria-hidden": "true" }) })
14223
14267
  ] }) : null,
@@ -14312,10 +14356,10 @@ function ChatTranscript({
14312
14356
  renderEmpty,
14313
14357
  className = ""
14314
14358
  }) {
14315
- const scroller = React72.useRef(null);
14316
- const stick = React72.useRef(true);
14317
- const [pill, setPill] = React72.useState(0);
14318
- const seen = React72.useRef(0);
14359
+ const scroller = React73.useRef(null);
14360
+ const stick = React73.useRef(true);
14361
+ const [pill, setPill] = React73.useState(0);
14362
+ const seen = React73.useRef(0);
14319
14363
  const toBottom = (smooth) => {
14320
14364
  const el = scroller.current;
14321
14365
  if (!el) return;
@@ -14334,7 +14378,7 @@ function ChatTranscript({
14334
14378
  seen.current = messages.length;
14335
14379
  }
14336
14380
  };
14337
- React72.useLayoutEffect(() => {
14381
+ React73.useLayoutEffect(() => {
14338
14382
  const el = scroller.current;
14339
14383
  if (!el) return;
14340
14384
  if (stick.current) {
@@ -14342,7 +14386,7 @@ function ChatTranscript({
14342
14386
  seen.current = messages.length;
14343
14387
  } else setPill(Math.max(0, messages.length - seen.current));
14344
14388
  }, [messages]);
14345
- React72.useEffect(() => {
14389
+ React73.useEffect(() => {
14346
14390
  const el = scroller.current;
14347
14391
  const inner = el && el.firstChild;
14348
14392
  if (!el || !inner || typeof ResizeObserver === "undefined") return;
@@ -14352,7 +14396,7 @@ function ChatTranscript({
14352
14396
  ro.observe(inner);
14353
14397
  return () => ro.disconnect();
14354
14398
  }, []);
14355
- const groups = React72.useMemo(() => groupMessages(messages), [messages]);
14399
+ const groups = React73.useMemo(() => groupMessages(messages), [messages]);
14356
14400
  const empty = !messages.length && status === "ready";
14357
14401
  return /* @__PURE__ */ (0, import_jsx_runtime103.jsxs)("div", { className: ["fdc-scroll", className].filter(Boolean).join(" "), ref: scroller, onScroll, children: [
14358
14402
  /* @__PURE__ */ (0, import_jsx_runtime103.jsxs)("div", { className: "fdc-log", role: "log", "aria-label": "Conversation", children: [
@@ -14376,7 +14420,7 @@ function ChatTranscript({
14376
14420
  const prev = groups[i - 1];
14377
14421
  const k = dayKey(g.messages[0].timestamp);
14378
14422
  const showDay = !!k && (!prev || dayKey(prev.messages[0].timestamp) !== k);
14379
- return /* @__PURE__ */ (0, import_jsx_runtime103.jsxs)(React72.Fragment, { children: [
14423
+ return /* @__PURE__ */ (0, import_jsx_runtime103.jsxs)(React73.Fragment, { children: [
14380
14424
  showDay ? /* @__PURE__ */ (0, import_jsx_runtime103.jsx)("div", { className: "fdc-day", children: /* @__PURE__ */ (0, import_jsx_runtime103.jsx)("span", { children: dayLabel(k) }) }) : null,
14381
14425
  /* @__PURE__ */ (0, import_jsx_runtime103.jsx)(ChatTurn, { group: g, ctx })
14382
14426
  ] }, g.key || i);
@@ -14393,7 +14437,7 @@ function ChatTranscript({
14393
14437
  var TranscriptKit = { groupMessages };
14394
14438
 
14395
14439
  // src/components/chat/ChatComposer.tsx
14396
- var React73 = __toESM(require("react"), 1);
14440
+ var React74 = __toESM(require("react"), 1);
14397
14441
  var import_jsx_runtime104 = require("react/jsx-runtime");
14398
14442
  function ChatComposer({
14399
14443
  onSubmit,
@@ -14421,17 +14465,17 @@ function ChatComposer({
14421
14465
  onReject,
14422
14466
  onOpenAttachment
14423
14467
  }) {
14424
- const [text, setText] = React73.useState(draft || "");
14425
- const [trigger, setTrigger] = React73.useState(null);
14426
- const [mentionItems, setMentionItems] = React73.useState([]);
14427
- const [listening, setListening] = React73.useState(false);
14428
- const [notice, setNotice] = React73.useState(null);
14429
- const editor = React73.useRef(null);
14430
- const wrap = React73.useRef(null);
14431
- const stopVoice = React73.useRef(null);
14468
+ const [text, setText] = React74.useState(draft || "");
14469
+ const [trigger, setTrigger] = React74.useState(null);
14470
+ const [mentionItems, setMentionItems] = React74.useState([]);
14471
+ const [listening, setListening] = React74.useState(false);
14472
+ const [notice, setNotice] = React74.useState(null);
14473
+ const editor = React74.useRef(null);
14474
+ const wrap = React74.useRef(null);
14475
+ const stopVoice = React74.useRef(null);
14432
14476
  const staged = useStagedFiles(fileUploadHandler, { onError: () => {
14433
14477
  } });
14434
- React73.useEffect(() => {
14478
+ React74.useEffect(() => {
14435
14479
  if (draft != null && draft !== text) setText(draft);
14436
14480
  }, [draft]);
14437
14481
  const change = (v) => {
@@ -14467,7 +14511,7 @@ function ChatComposer({
14467
14511
  e.preventDefault();
14468
14512
  staged.add(found.files);
14469
14513
  };
14470
- React73.useEffect(() => {
14514
+ React74.useEffect(() => {
14471
14515
  if (!trigger || trigger.type !== "mention" || !mentionSources) {
14472
14516
  setMentionItems([]);
14473
14517
  return;
@@ -14485,7 +14529,7 @@ function ChatComposer({
14485
14529
  const q = (trigger.query || "").toLowerCase();
14486
14530
  setMentionItems(mentionSources.filter((m) => !q || (m.label + " " + (m.description || "")).toLowerCase().includes(q)));
14487
14531
  }, [trigger, mentionSources]);
14488
- const slashItems = React73.useMemo(() => {
14532
+ const slashItems = React74.useMemo(() => {
14489
14533
  if (!trigger || trigger.type !== "slash" || !slashCommands) return [];
14490
14534
  const q = (trigger.query || "").toLowerCase();
14491
14535
  return slashCommands.filter((c) => !q || (c.id + " " + c.label + " " + (c.description || "")).toLowerCase().includes(q));
@@ -14655,12 +14699,12 @@ function ChatComposer({
14655
14699
  }
14656
14700
 
14657
14701
  // src/components/chat/ChatSessionBar.tsx
14658
- var React74 = __toESM(require("react"), 1);
14702
+ var React75 = __toESM(require("react"), 1);
14659
14703
  var import_jsx_runtime105 = require("react/jsx-runtime");
14660
14704
  var compact2 = meterFormats.compact;
14661
14705
  function ChatSessionBar({ sessionStats, contextUsage, usageLimits, onClear, extras }) {
14662
- const [open2, setOpen] = React74.useState(false);
14663
- const anchor = React74.useRef(null);
14706
+ const [open2, setOpen] = React75.useState(false);
14707
+ const anchor = React75.useRef(null);
14664
14708
  const stats = sessionStats || null;
14665
14709
  const cu = contextUsage || null;
14666
14710
  const limits = usageLimits || null;
@@ -14675,7 +14719,7 @@ function ChatSessionBar({ sessionStats, contextUsage, usageLimits, onClear, extr
14675
14719
  if (stats && stats.runningTasks) bits.push(stats.runningTasks + " running task" + (stats.runningTasks === 1 ? "" : "s"));
14676
14720
  if (cu) bits.push(pct + "% context");
14677
14721
  const expandable = !!(cu || limits);
14678
- return /* @__PURE__ */ (0, import_jsx_runtime105.jsxs)(React74.Fragment, { children: [
14722
+ return /* @__PURE__ */ (0, import_jsx_runtime105.jsxs)(React75.Fragment, { children: [
14679
14723
  /* @__PURE__ */ (0, import_jsx_runtime105.jsxs)("div", { className: "fdc-bar", children: [
14680
14724
  /* @__PURE__ */ (0, import_jsx_runtime105.jsxs)(
14681
14725
  "button",
@@ -14816,7 +14860,7 @@ function ModelControls({
14816
14860
  ] })
14817
14861
  });
14818
14862
  }
14819
- return /* @__PURE__ */ (0, import_jsx_runtime105.jsxs)(React74.Fragment, { children: [
14863
+ return /* @__PURE__ */ (0, import_jsx_runtime105.jsxs)(React75.Fragment, { children: [
14820
14864
  /* @__PURE__ */ (0, import_jsx_runtime105.jsx)(
14821
14865
  MenuButton,
14822
14866
  {
@@ -14855,6 +14899,7 @@ function AgentChatPanel({
14855
14899
  /* required */
14856
14900
  contextType,
14857
14901
  contextId,
14902
+ draftOwner,
14858
14903
  apiAdapter,
14859
14904
  threadId,
14860
14905
  /* identity + chrome */
@@ -14935,11 +14980,11 @@ function AgentChatPanel({
14935
14980
  onFeedback,
14936
14981
  onEditMessage
14937
14982
  }) {
14938
- const [panelWidth, setPanelWidth] = React75.useState(width);
14939
- const [applied, setApplied] = React75.useState({});
14940
- const [draft, setDraft] = React75.useState("");
14941
- const dragging = React75.useRef(null);
14942
- React75.useEffect(() => setPanelWidth(width), [width]);
14983
+ const [panelWidth, setPanelWidth] = React76.useState(width);
14984
+ const [applied, setApplied] = React76.useState({});
14985
+ const [draft, setDraft] = useChatDraft(draftOwner, contextType, contextId);
14986
+ const dragging = React76.useRef(null);
14987
+ React76.useEffect(() => setPanelWidth(width), [width]);
14943
14988
  const engine = useChatEngine({
14944
14989
  contextType,
14945
14990
  contextId,
@@ -15145,7 +15190,7 @@ function AgentChatPanel({
15145
15190
  }
15146
15191
 
15147
15192
  // src/components/files/FileViewer.tsx
15148
- var React76 = __toESM(require("react"), 1);
15193
+ var React77 = __toESM(require("react"), 1);
15149
15194
  var import_jsx_runtime107 = require("react/jsx-runtime");
15150
15195
  function previewKindOf(file) {
15151
15196
  const mime = (file.mime || "").toLowerCase();
@@ -15202,13 +15247,13 @@ function parseDelimited(text, delimiter) {
15202
15247
  return rows;
15203
15248
  }
15204
15249
  function usePreview(file, kind, resolveUrl) {
15205
- const [state, setState] = React76.useState({ status: "loading" });
15206
- const [attempt, setAttempt] = React76.useState(0);
15207
- const resolveRef = React76.useRef(resolveUrl);
15208
- React76.useEffect(() => {
15250
+ const [state, setState] = React77.useState({ status: "loading" });
15251
+ const [attempt, setAttempt] = React77.useState(0);
15252
+ const resolveRef = React77.useRef(resolveUrl);
15253
+ React77.useEffect(() => {
15209
15254
  resolveRef.current = resolveUrl;
15210
15255
  }, [resolveUrl]);
15211
- React76.useEffect(() => {
15256
+ React77.useEffect(() => {
15212
15257
  if (kind === "none") {
15213
15258
  setState({ status: "ready" });
15214
15259
  return;
@@ -15238,7 +15283,7 @@ function usePreview(file, kind, resolveUrl) {
15238
15283
  if (ac) ac.abort();
15239
15284
  };
15240
15285
  }, [file.id, kind, attempt]);
15241
- return { ...state, retry: React76.useCallback(() => setAttempt((a) => a + 1), []) };
15286
+ return { ...state, retry: React77.useCallback(() => setAttempt((a) => a + 1), []) };
15242
15287
  }
15243
15288
  function PreviewBody({ file, kind, state }) {
15244
15289
  if (kind === "image") return /* @__PURE__ */ (0, import_jsx_runtime107.jsx)("img", { className: "fd-fv-image", src: state.url, alt: file.name || "Preview" });
@@ -15283,13 +15328,13 @@ function PreviewBody({ file, kind, state }) {
15283
15328
  ] });
15284
15329
  }
15285
15330
  function FileViewer({ file, resolveUrl, sidePanel, sidePanelLabel = "Details", onClose, actions, className = "" }) {
15286
- const kind = React76.useMemo(() => previewKindOf(file), [file]);
15331
+ const kind = React77.useMemo(() => previewKindOf(file), [file]);
15287
15332
  const preview = usePreview(file, kind, resolveUrl);
15288
- const [tab, setTab] = React76.useState("preview");
15289
- const [downloading, setDownloading] = React76.useState(false);
15290
- const [downloadError, setDownloadError] = React76.useState(null);
15333
+ const [tab, setTab] = React77.useState("preview");
15334
+ const [downloading, setDownloading] = React77.useState(false);
15335
+ const [downloadError, setDownloadError] = React77.useState(null);
15291
15336
  const hasSide = sidePanel != null;
15292
- React76.useEffect(() => {
15337
+ React77.useEffect(() => {
15293
15338
  setTab("preview");
15294
15339
  }, [file.id]);
15295
15340
  const download = () => {
@@ -15356,7 +15401,7 @@ function FileViewer({ file, resolveUrl, sidePanel, sidePanelLabel = "Details", o
15356
15401
  }
15357
15402
 
15358
15403
  // src/components/files/FileBrowser.tsx
15359
- var React77 = __toESM(require("react"), 1);
15404
+ var React78 = __toESM(require("react"), 1);
15360
15405
  var import_jsx_runtime108 = require("react/jsx-runtime");
15361
15406
  function childrenOf(folders, parentId) {
15362
15407
  return folders.filter((f) => f.parentId === parentId).sort((a, b) => a.name.localeCompare(b.name));
@@ -15466,8 +15511,8 @@ function FolderPickerMenu({
15466
15511
  ] });
15467
15512
  }
15468
15513
  function RowShell({ icon, name, meta, onOpen, draggableId, isDropTarget, onDropPayload, actions, className = "" }) {
15469
- const [over, setOver] = React77.useState(false);
15470
- const dragCounter = React77.useRef(0);
15514
+ const [over, setOver] = React78.useState(false);
15515
+ const dragCounter = React78.useRef(0);
15471
15516
  const dropHandlers = isDropTarget ? {
15472
15517
  onDragEnter: (e) => {
15473
15518
  if (!hasInternalPayload(e)) return;
@@ -15515,8 +15560,8 @@ function RowShell({ icon, name, meta, onOpen, draggableId, isDropTarget, onDropP
15515
15560
  }
15516
15561
  function TreeNode({ folder, depth, folders, currentFolderId, onNavigate, onMoveInto, canMove }) {
15517
15562
  const kids = childrenOf(folders, folder.id);
15518
- const [expanded, setExpanded] = React77.useState(() => currentFolderId != null && isSelfOrDescendant(folders, folder.id, currentFolderId));
15519
- React77.useEffect(() => {
15563
+ const [expanded, setExpanded] = React78.useState(() => currentFolderId != null && isSelfOrDescendant(folders, folder.id, currentFolderId));
15564
+ React78.useEffect(() => {
15520
15565
  if (currentFolderId != null && isSelfOrDescendant(folders, folder.id, currentFolderId)) setExpanded(true);
15521
15566
  }, [currentFolderId, folder.id, folders]);
15522
15567
  const isCurrent = folder.id === currentFolderId;
@@ -15582,15 +15627,15 @@ function FileBrowser({
15582
15627
  const canUpload = perm.canUpload !== false && !!onUpload;
15583
15628
  const canRemoveFile = perm.canRemoveFile !== false && !!onRemoveFile;
15584
15629
  const canDeleteFolder = perm.canDeleteFolder !== false && !!onDeleteFolder;
15585
- const [createOpen, setCreateOpen] = React77.useState(false);
15586
- const [createName, setCreateName] = React77.useState("");
15587
- const [renameTarget, setRenameTarget] = React77.useState(null);
15588
- const [renameValue, setRenameValue] = React77.useState("");
15589
- const [deleteTarget, setDeleteTarget] = React77.useState(null);
15590
- const uploadInputRef = React77.useRef(null);
15591
- const crumbFolders = React77.useMemo(() => ancestorsOf(folders, currentFolderId), [folders, currentFolderId]);
15592
- const subfolders = React77.useMemo(() => childrenOf(folders, currentFolderId), [folders, currentFolderId]);
15593
- const currentFiles = React77.useMemo(
15630
+ const [createOpen, setCreateOpen] = React78.useState(false);
15631
+ const [createName, setCreateName] = React78.useState("");
15632
+ const [renameTarget, setRenameTarget] = React78.useState(null);
15633
+ const [renameValue, setRenameValue] = React78.useState("");
15634
+ const [deleteTarget, setDeleteTarget] = React78.useState(null);
15635
+ const uploadInputRef = React78.useRef(null);
15636
+ const crumbFolders = React78.useMemo(() => ancestorsOf(folders, currentFolderId), [folders, currentFolderId]);
15637
+ const subfolders = React78.useMemo(() => childrenOf(folders, currentFolderId), [folders, currentFolderId]);
15638
+ const currentFiles = React78.useMemo(
15594
15639
  () => files.filter((f) => f.folderId === currentFolderId).sort((a, b) => a.name.localeCompare(b.name)),
15595
15640
  [files, currentFolderId]
15596
15641
  );
@@ -15822,8 +15867,8 @@ function BreadcrumbCrumb({
15822
15867
  isDropTarget,
15823
15868
  onDropPayload
15824
15869
  }) {
15825
- const [over, setOver] = React77.useState(false);
15826
- const dragCounter = React77.useRef(0);
15870
+ const [over, setOver] = React78.useState(false);
15871
+ const dragCounter = React78.useRef(0);
15827
15872
  const dropHandlers = isDropTarget ? {
15828
15873
  onDragEnter: (e) => {
15829
15874
  if (!hasInternalPayload(e)) return;
@@ -15852,7 +15897,7 @@ function BreadcrumbCrumb({
15852
15897
  }
15853
15898
 
15854
15899
  // src/kits/query.ts
15855
- var React78 = __toESM(require("react"), 1);
15900
+ var React79 = __toESM(require("react"), 1);
15856
15901
 
15857
15902
  // src/kits/queryUrl.ts
15858
15903
  var historyUrlAdapter = {
@@ -15990,38 +16035,38 @@ function requestFor(params, query, paging, after) {
15990
16035
  }
15991
16036
  var toError = (e) => e instanceof Error ? e : new Error(String(e));
15992
16037
  function useServerTable({ endpoint, params, defaults, deps, prefsKey, paging = "page", url }) {
15993
- const [base] = React78.useState(() => {
16038
+ const [base] = React79.useState(() => {
15994
16039
  const store = PREFS || window.PlannerPrefs;
15995
16040
  const saved = prefsKey && store ? store.getTable(prefsKey) : {};
15996
16041
  return { ...DEFAULTS, ...defaults || {}, ...saved.pageSize ? { pageSize: saved.pageSize } : {}, ...saved.sort ? { sort: saved.sort, dir: saved.dir || "desc" } : {} };
15997
16042
  });
15998
- const [mountParams] = React78.useState(() => url ? (url.adapter ?? historyUrlAdapter).read() : null);
15999
- const address = React78.useRef(mountParams);
16000
- const [query, setQuery] = React78.useState(() => url && mountParams ? readQueryFromUrl(mountParams, url.scope, base, paging) : base);
16001
- const savePref = React78.useCallback((patch2) => {
16043
+ const [mountParams] = React79.useState(() => url ? (url.adapter ?? historyUrlAdapter).read() : null);
16044
+ const address = React79.useRef(mountParams);
16045
+ const [query, setQuery] = React79.useState(() => url && mountParams ? readQueryFromUrl(mountParams, url.scope, base, paging) : base);
16046
+ const savePref = React79.useCallback((patch2) => {
16002
16047
  const store = PREFS || window.PlannerPrefs;
16003
16048
  if (prefsKey && store) store.setTable(prefsKey, patch2);
16004
16049
  }, [prefsKey]);
16005
- const [res, setRes] = React78.useState(null);
16006
- const [loading, setLoading] = React78.useState(true);
16007
- const [loadingMore, setLoadingMore] = React78.useState(false);
16008
- const [failure, setFailure] = React78.useState(null);
16009
- const [reloadToken, setReloadToken] = React78.useState(0);
16010
- const moreController = React78.useRef(null);
16050
+ const [res, setRes] = React79.useState(null);
16051
+ const [loading, setLoading] = React79.useState(true);
16052
+ const [loadingMore, setLoadingMore] = React79.useState(false);
16053
+ const [failure, setFailure] = React79.useState(null);
16054
+ const [reloadToken, setReloadToken] = React79.useState(0);
16055
+ const moreController = React79.useRef(null);
16011
16056
  const depKey = (deps || []).join("|");
16012
16057
  const paramKey = JSON.stringify(params || {});
16013
16058
  const queryKey = JSON.stringify(query);
16014
- const lifetime = React78.useRef(null);
16015
- React78.useEffect(() => {
16059
+ const lifetime = React79.useRef(null);
16060
+ React79.useEffect(() => {
16016
16061
  const controller = new AbortController();
16017
16062
  lifetime.current = controller;
16018
16063
  return () => controller.abort();
16019
16064
  }, []);
16020
- const latest = React78.useRef({ res, loading, query, params, endpoint, url, base });
16021
- React78.useLayoutEffect(() => {
16065
+ const latest = React79.useRef({ res, loading, query, params, endpoint, url, base });
16066
+ React79.useLayoutEffect(() => {
16022
16067
  latest.current = { res, loading, query, params, endpoint, url, base };
16023
16068
  });
16024
- React78.useEffect(() => {
16069
+ React79.useEffect(() => {
16025
16070
  const controller = new AbortController();
16026
16071
  const { signal } = controller;
16027
16072
  setLoading(true);
@@ -16057,7 +16102,7 @@ function useServerTable({ endpoint, params, defaults, deps, prefsKey, paging = "
16057
16102
  };
16058
16103
  }, [endpoint, queryKey, paramKey, depKey, paging, reloadToken]);
16059
16104
  const adapter = url ? url.adapter ?? historyUrlAdapter : null;
16060
- React78.useEffect(() => {
16105
+ React79.useEffect(() => {
16061
16106
  if (!adapter) return;
16062
16107
  return adapter.subscribe((params2) => {
16063
16108
  const { url: u, base: b } = latest.current;
@@ -16407,12 +16452,12 @@ function createVersionStore(initialState, options) {
16407
16452
  }
16408
16453
 
16409
16454
  // src/kits/documentTitle.ts
16410
- var React79 = __toESM(require("react"), 1);
16455
+ var React80 = __toESM(require("react"), 1);
16411
16456
  function formatDocumentTitle(routeTitle, appName) {
16412
- return [routeTitle, appName, "Flytedesk"].filter((part) => !!part && part.length > 0).join(" \xB7 ");
16457
+ return [routeTitle, appName, "Flytedesk"].filter((part2) => !!part2 && part2.length > 0).join(" \xB7 ");
16413
16458
  }
16414
16459
  function useDocumentTitle(routeTitle, appName) {
16415
- React79.useEffect(() => {
16460
+ React80.useEffect(() => {
16416
16461
  if (typeof document === "undefined") return;
16417
16462
  document.title = formatDocumentTitle(routeTitle, appName);
16418
16463
  }, [routeTitle, appName]);
@@ -16523,6 +16568,7 @@ function useDocumentTitle(routeTitle, appName) {
16523
16568
  ModeSwitch,
16524
16569
  ModelControls,
16525
16570
  NumberInput,
16571
+ OVERLAY_BREAKPOINT,
16526
16572
  OVERLAY_CEILING,
16527
16573
  POPOVER_BODY_MIN,
16528
16574
  PacketCard,
@@ -16647,6 +16693,7 @@ function useDocumentTitle(routeTitle, appName) {
16647
16693
  useDocumentTitle,
16648
16694
  useFeatureStatus,
16649
16695
  useLayerZIndex,
16696
+ useOverlayLayout,
16650
16697
  usePopoverPosition,
16651
16698
  useResponsiveRail,
16652
16699
  useRuntimeMode,