@flytedan/flytebot-design-system 0.33.0 → 0.35.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
@@ -2971,10 +2971,10 @@ function DataTable({
2971
2971
  }
2972
2972
 
2973
2973
  // src/components/data/FilterBar.tsx
2974
- var React24 = __toESM(require("react"), 1);
2974
+ var React25 = __toESM(require("react"), 1);
2975
2975
 
2976
2976
  // src/components/forms/NumberInput.tsx
2977
- var React21 = __toESM(require("react"), 1);
2977
+ var React22 = __toESM(require("react"), 1);
2978
2978
 
2979
2979
  // src/components/forms/field.tsx
2980
2980
  var React20 = __toESM(require("react"), 1);
@@ -2995,6 +2995,16 @@ function useTriggerLabelling(label, id) {
2995
2995
  return { fieldId, labelId, ariaLabelledBy: label ? labelId + " " + fieldId : void 0 };
2996
2996
  }
2997
2997
 
2998
+ // src/components/useLatest.ts
2999
+ var React21 = __toESM(require("react"), 1);
3000
+ function useLatest(value) {
3001
+ const ref = React21.useRef(value);
3002
+ React21.useInsertionEffect(() => {
3003
+ ref.current = value;
3004
+ });
3005
+ return ref;
3006
+ }
3007
+
2998
3008
  // src/components/forms/NumberInput.tsx
2999
3009
  var import_jsx_runtime42 = require("react/jsx-runtime");
3000
3010
  var HOLD_DELAY_MS = 400;
@@ -3072,24 +3082,22 @@ function NumberInput({
3072
3082
  const n = typeof v === "number" ? v : parseNumberText(v);
3073
3083
  return n == null || Number.isNaN(n) ? null : n;
3074
3084
  };
3075
- const [text, setText] = React21.useState(() => toText(value));
3076
- const [editing, setEditing] = React21.useState(false);
3085
+ const [text, setText] = React22.useState(() => toText(value));
3086
+ const [editing, setEditing] = React22.useState(false);
3077
3087
  const parsed = parseNumberText(text);
3078
3088
  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;
3079
3089
  const valid = invalidMessage == null;
3080
- const committedRef = React21.useRef(toNumber(value));
3081
- const onChangeRef = React21.useRef(onChange);
3082
- onChangeRef.current = onChange;
3083
- const onValidityChangeRef = React21.useRef(onValidityChange);
3084
- onValidityChangeRef.current = onValidityChange;
3085
- const focusedRef = React21.useRef(false);
3086
- React21.useEffect(() => {
3090
+ const committedRef = React22.useRef(toNumber(value));
3091
+ const onChangeRef = useLatest(onChange);
3092
+ const onValidityChangeRef = useLatest(onValidityChange);
3093
+ const focusedRef = React22.useRef(false);
3094
+ React22.useEffect(() => {
3087
3095
  committedRef.current = toNumber(value);
3088
3096
  if (!focusedRef.current) setText(toText(value));
3089
3097
  }, [value]);
3090
- React21.useLayoutEffect(() => {
3098
+ React22.useLayoutEffect(() => {
3091
3099
  onValidityChangeRef.current?.(valid);
3092
- }, [valid]);
3100
+ }, [valid, onValidityChangeRef]);
3093
3101
  const fire = (n) => {
3094
3102
  committedRef.current = n ?? null;
3095
3103
  onChangeRef.current?.({ target: { value: n } });
@@ -3102,9 +3110,8 @@ function NumberInput({
3102
3110
  fire(next);
3103
3111
  return true;
3104
3112
  };
3105
- const bumpRef = React21.useRef(bump);
3106
- bumpRef.current = bump;
3107
- const holdTimer = React21.useRef(null);
3113
+ const bumpRef = useLatest(bump);
3114
+ const holdTimer = React22.useRef(null);
3108
3115
  const release = () => {
3109
3116
  if (holdTimer.current) clearTimeout(holdTimer.current);
3110
3117
  holdTimer.current = null;
@@ -3123,7 +3130,7 @@ function NumberInput({
3123
3130
  };
3124
3131
  holdTimer.current = setTimeout(tick, HOLD_DELAY_MS);
3125
3132
  };
3126
- React21.useEffect(() => () => {
3133
+ React22.useEffect(() => () => {
3127
3134
  if (holdTimer.current) clearTimeout(holdTimer.current);
3128
3135
  }, []);
3129
3136
  const current2 = committedRef.current;
@@ -3226,7 +3233,7 @@ function NumberInput({
3226
3233
  }
3227
3234
 
3228
3235
  // src/components/forms/DatePicker.tsx
3229
- var React22 = __toESM(require("react"), 1);
3236
+ var React23 = __toESM(require("react"), 1);
3230
3237
  var import_jsx_runtime43 = require("react/jsx-runtime");
3231
3238
  var MONTHS = ["January", "February", "March", "April", "May", "June", "July", "August", "September", "October", "November", "December"];
3232
3239
  var DOW = ["Su", "Mo", "Tu", "We", "Th", "Fr", "Sa"];
@@ -3244,10 +3251,10 @@ function Calendar({ value, range = false, onPick, initialMonth, months = 1 }) {
3244
3251
  const today = /* @__PURE__ */ new Date();
3245
3252
  const sel = range ? value || {} : { start: value, end: value };
3246
3253
  const anchor = parse(sel.start) || parse(initialMonth) || today;
3247
- const [vy, setVy] = React22.useState(anchor.getFullYear());
3248
- const [vm, setVm] = React22.useState(anchor.getMonth());
3249
- const [mode2, setMode] = React22.useState("days");
3250
- const [hover, setHover] = React22.useState(null);
3254
+ const [vy, setVy] = React23.useState(anchor.getFullYear());
3255
+ const [vm, setVm] = React23.useState(anchor.getMonth());
3256
+ const [mode2, setMode] = React23.useState("days");
3257
+ const [hover, setHover] = React23.useState(null);
3251
3258
  const s = parse(sel.start), e = parse(sel.end);
3252
3259
  const hoverEnd = range && s && !e && hover ? parse(hover) : null;
3253
3260
  const inRange = (d) => {
@@ -3363,9 +3370,9 @@ function Calendar({ value, range = false, onPick, initialMonth, months = 1 }) {
3363
3370
  }
3364
3371
  function DatePicker({ label, help, error, required = false, disabled = false, range = false, value, onChange, placeholder, id, className = "", style, ...rest }) {
3365
3372
  const { fieldId, labelId, ariaLabelledBy } = useTriggerLabelling(label, id);
3366
- const [open, setOpen] = React22.useState(false);
3367
- const rootRef = React22.useRef(null);
3368
- const boxRef = React22.useRef(null);
3373
+ const [open, setOpen] = React23.useState(false);
3374
+ const rootRef = React23.useRef(null);
3375
+ const boxRef = React23.useRef(null);
3369
3376
  const display = range ? value && value.start ? fmt(value.start) + (value.end ? " \u2192 " + fmt(value.end) : " \u2192 \u2026") : "" : fmt(value);
3370
3377
  const toggle = () => {
3371
3378
  if (!disabled) setOpen(!open);
@@ -3443,9 +3450,9 @@ function Textarea({ label, help, error, required = false, rows = 4, disabled = f
3443
3450
  }
3444
3451
 
3445
3452
  // src/components/forms/listbox.ts
3446
- var React23 = __toESM(require("react"), 1);
3453
+ var React24 = __toESM(require("react"), 1);
3447
3454
  function useListboxNav({ count, onSelect }) {
3448
- const [active, setActive] = React23.useState(-1);
3455
+ const [active, setActive] = React24.useState(-1);
3449
3456
  return {
3450
3457
  active,
3451
3458
  setActive,
@@ -3458,7 +3465,7 @@ function useListboxNav({ count, onSelect }) {
3458
3465
  };
3459
3466
  }
3460
3467
  function useListboxScrollIntoView(active, listRef, enabled) {
3461
- React23.useEffect(() => {
3468
+ React24.useEffect(() => {
3462
3469
  if (!enabled || active < 0 || !listRef.current) return;
3463
3470
  const list = listRef.current;
3464
3471
  const el = list.querySelector('[data-i="' + active + '"]');
@@ -3645,40 +3652,40 @@ function MultiSelectPanel({
3645
3652
  onClose
3646
3653
  }) {
3647
3654
  const allowedOps = operatorsFor(field);
3648
- const [draftOperator, setDraftOperator] = React24.useState(value?.operator ?? allowedOps[0]);
3655
+ const [draftOperator, setDraftOperator] = React25.useState(value?.operator ?? allowedOps[0]);
3649
3656
  const operator = allowedOps.length === 1 ? allowedOps[0] : value?.operator ?? draftOperator;
3650
3657
  const selected = value?.values ?? [];
3651
- const selectedRef = React24.useRef(selected);
3652
- selectedRef.current = selected;
3653
- const operatorRef = React24.useRef(operator);
3654
- operatorRef.current = operator;
3655
- const mountedRef = React24.useRef(true);
3656
- React24.useEffect(() => {
3658
+ const selectedRef = useLatest(selected);
3659
+ const operatorRef = useLatest(operator);
3660
+ const mountedRef = React25.useRef(true);
3661
+ React25.useEffect(() => {
3657
3662
  mountedRef.current = true;
3658
3663
  return () => {
3659
3664
  mountedRef.current = false;
3660
3665
  };
3661
3666
  }, []);
3662
- const commit = (nextValues, nextOperator = operator) => onCommit({ operator: nextOperator, values: nextValues });
3667
+ const commit = (nextValues, nextOperator = operatorRef.current) => {
3668
+ setDraftOperator(nextOperator);
3669
+ return onCommit({ operator: nextOperator, values: nextValues });
3670
+ };
3663
3671
  const setOperator = (op) => {
3664
- setDraftOperator(op);
3665
3672
  if (selectedRef.current.length > 0) commit(selectedRef.current, op);
3673
+ else setDraftOperator(op);
3666
3674
  };
3667
- const [mode2, setMode] = React24.useState("search");
3668
- const [query, setQuery] = React24.useState("");
3669
- const [asyncState, setAsyncState] = React24.useState(
3675
+ const [mode2, setMode] = React25.useState("search");
3676
+ const [query, setQuery] = React25.useState("");
3677
+ const [asyncState, setAsyncState] = React25.useState(
3670
3678
  { options: null, loading: !!field.loadOptions, error: false }
3671
3679
  );
3672
- const [retryTick, setRetryTick] = React24.useState(0);
3673
- const inputRef = React24.useRef(null);
3674
- const listRef = React24.useRef(null);
3675
- const listId = React24.useId();
3676
- const loadOptionsRef = React24.useRef(field.loadOptions);
3677
- loadOptionsRef.current = field.loadOptions;
3678
- React24.useEffect(() => {
3680
+ const [retryTick, setRetryTick] = React25.useState(0);
3681
+ const inputRef = React25.useRef(null);
3682
+ const listRef = React25.useRef(null);
3683
+ const listId = React25.useId();
3684
+ const loadOptionsRef = useLatest(field.loadOptions);
3685
+ React25.useEffect(() => {
3679
3686
  inputRef.current?.focus();
3680
3687
  }, []);
3681
- React24.useEffect(() => {
3688
+ React25.useEffect(() => {
3682
3689
  const load = loadOptionsRef.current;
3683
3690
  if (!load) return;
3684
3691
  const controller = new AbortController();
@@ -3696,7 +3703,7 @@ function MultiSelectPanel({
3696
3703
  clearTimeout(t);
3697
3704
  controller.abort();
3698
3705
  };
3699
- }, [query, retryTick]);
3706
+ }, [query, retryTick, loadOptionsRef]);
3700
3707
  const options = field.loadOptions ? asyncState.options ?? [] : (field.options ?? []).filter((o) => o.label.toLowerCase().includes(query.toLowerCase()));
3701
3708
  const showLoading = !!field.loadOptions && asyncState.loading;
3702
3709
  const showError = !!field.loadOptions && asyncState.error;
@@ -3711,19 +3718,24 @@ function MultiSelectPanel({
3711
3718
  };
3712
3719
  const nav = useListboxNav({ count: options.length, onSelect: (i) => toggle(options[i]) });
3713
3720
  useListboxScrollIntoView(nav.active, listRef, hasListbox);
3714
- React24.useEffect(() => {
3721
+ React25.useEffect(() => {
3715
3722
  nav.setActive(0);
3716
3723
  }, [query, options.length]);
3717
3724
  const activeId = hasListbox && options[nav.active] ? listId + "-opt-" + nav.active : void 0;
3718
3725
  const liveMessage = showLoading ? "Loading\u2026" : showError ? "Couldn't load options." : options.length === 0 ? "No matches" : atLimit ? "Limit reached: at most " + field.maxValues + " values" : "";
3719
- const [pasteText, setPasteText] = React24.useState("");
3720
- const [pasteLoading, setPasteLoading] = React24.useState(false);
3721
- const [unmatchedTokens, setUnmatchedTokens] = React24.useState([]);
3722
- const [pasteError, setPasteError] = React24.useState(null);
3723
- const pasteWrapRef = React24.useRef(null);
3724
- React24.useEffect(() => {
3726
+ const [pasteText, setPasteText] = React25.useState("");
3727
+ const [pasteLoading, setPasteLoading] = React25.useState(false);
3728
+ const [unmatchedTokens, setUnmatchedTokens] = React25.useState([]);
3729
+ const [pasteError, setPasteError] = React25.useState(null);
3730
+ const pasteWrapRef = React25.useRef(null);
3731
+ const [resolvedAt, setResolvedAt] = React25.useState(0);
3732
+ React25.useEffect(() => {
3725
3733
  if (mode2 === "paste") pasteWrapRef.current?.querySelector("textarea")?.focus();
3726
3734
  }, [mode2]);
3735
+ React25.useLayoutEffect(() => {
3736
+ if (resolvedAt === 0) return;
3737
+ pasteWrapRef.current?.querySelector("textarea")?.focus();
3738
+ }, [resolvedAt]);
3727
3739
  const doResolve = () => {
3728
3740
  if (!field.resolve) return;
3729
3741
  const tokens = Array.from(new Set(pasteText.split(/[\n,]/).map((t) => t.trim()).filter(Boolean)));
@@ -3740,12 +3752,13 @@ function MultiSelectPanel({
3740
3752
  setPasteError("This filter allows at most " + field.maxValues + " values; adding this list would make " + merged.size + ".");
3741
3753
  return;
3742
3754
  }
3743
- const applied = commit(Array.from(merged.values()), operatorRef.current);
3755
+ const applied = commit(Array.from(merged.values()));
3744
3756
  if (!applied.ok) {
3745
3757
  setPasteError(applied.reason);
3746
3758
  return;
3747
3759
  }
3748
3760
  setPasteText("");
3761
+ setResolvedAt((n) => n + 1);
3749
3762
  }, (err) => {
3750
3763
  if (!mountedRef.current) return;
3751
3764
  setPasteLoading(false);
@@ -3882,10 +3895,9 @@ function MultiSelectPanel({
3882
3895
  );
3883
3896
  }
3884
3897
  function useTextValidity(onFlip) {
3885
- const invalidRef = React24.useRef(/* @__PURE__ */ new Set());
3886
- const [, rerender] = React24.useReducer((n) => n + 1, 0);
3887
- const onFlipRef = React24.useRef(onFlip);
3888
- onFlipRef.current = onFlip;
3898
+ const invalidRef = React25.useRef(/* @__PURE__ */ new Set());
3899
+ const [, rerender] = React25.useReducer((n) => n + 1, 0);
3900
+ const onFlipRef = useLatest(onFlip);
3889
3901
  const record = (name, valid) => {
3890
3902
  const invalid = invalidRef.current;
3891
3903
  if (valid !== invalid.has(name)) return false;
@@ -3902,6 +3914,12 @@ function useTextValidity(onFlip) {
3902
3914
  /** For an input that is about to unmount: it has nothing left to show. */
3903
3915
  forget: (name) => {
3904
3916
  record(name, true);
3917
+ },
3918
+ /** For a panel that is about to remount every input: each reports afresh on mount. */
3919
+ reset: () => {
3920
+ if (invalidRef.current.size === 0) return;
3921
+ invalidRef.current.clear();
3922
+ rerender();
3905
3923
  }
3906
3924
  };
3907
3925
  }
@@ -3909,6 +3927,40 @@ function applicable(field, candidate, textValid) {
3909
3927
  if (!textValid || candidate === void 0) return void 0;
3910
3928
  return validateFilterValue(field, candidate).ok ? candidate : void 0;
3911
3929
  }
3930
+ function sameValue(a, b) {
3931
+ if (a === b) return true;
3932
+ if (typeof a !== "object" || typeof b !== "object" || a === null || b === null) return false;
3933
+ if (Array.isArray(a) !== Array.isArray(b)) return false;
3934
+ const left = a;
3935
+ const right = b;
3936
+ for (const key of /* @__PURE__ */ new Set([...Object.keys(left), ...Object.keys(right)])) {
3937
+ if (!sameValue(left[key], right[key])) return false;
3938
+ }
3939
+ return true;
3940
+ }
3941
+ function useReseedFromProps(value, applies, reseed) {
3942
+ const seen = React25.useRef(value);
3943
+ React25.useLayoutEffect(() => {
3944
+ if (seen.current === value) return;
3945
+ seen.current = value;
3946
+ if (!sameValue(value, applies())) reseed(value);
3947
+ }, [value, applies, reseed]);
3948
+ }
3949
+ function usePreserveFocusAcrossRemount(seed) {
3950
+ const pendingId = React25.useRef(null);
3951
+ const capture = (ids) => {
3952
+ const active = document.activeElement;
3953
+ pendingId.current = active instanceof HTMLElement && ids.includes(active.id) ? active.id : null;
3954
+ };
3955
+ React25.useLayoutEffect(() => {
3956
+ const id = pendingId.current;
3957
+ if (!id) return;
3958
+ pendingId.current = null;
3959
+ document.getElementById(id)?.focus();
3960
+ }, [seed]);
3961
+ return capture;
3962
+ }
3963
+ var rangeDraft = (value) => ({ min: value?.min, max: value?.max });
3912
3964
  function RangePanel({
3913
3965
  field,
3914
3966
  value,
@@ -3916,13 +3968,27 @@ function RangePanel({
3916
3968
  onCommit,
3917
3969
  onClose
3918
3970
  }) {
3919
- const [draft, setDraft] = React24.useState({ min: value?.min, max: value?.max });
3920
- const draftRef = React24.useRef(draft);
3921
- const publish = () => {
3971
+ const [draft, setDraft] = React25.useState(() => rangeDraft(value));
3972
+ const [seed, setSeed] = React25.useState(0);
3973
+ const preserveFocus = usePreserveFocusAcrossRemount(seed);
3974
+ const minId = field.key + "-min";
3975
+ const maxId = field.key + "-max";
3976
+ const draftRef = React25.useRef(draft);
3977
+ const shown = () => {
3922
3978
  const { min, max } = draftRef.current;
3923
- onCommit(applicable(field, min == null && max == null ? void 0 : { min, max }, validity.allValid()));
3979
+ return applicable(field, min == null && max == null ? void 0 : { min, max }, validity.allValid());
3980
+ };
3981
+ const publish = () => {
3982
+ onCommit(shown());
3924
3983
  };
3925
3984
  const validity = useTextValidity(publish);
3985
+ useReseedFromProps(value, shown, (next) => {
3986
+ preserveFocus([minId, maxId]);
3987
+ draftRef.current = rangeDraft(next);
3988
+ setDraft(draftRef.current);
3989
+ validity.reset();
3990
+ setSeed((n) => n + 1);
3991
+ });
3926
3992
  const draftMin = draft.min;
3927
3993
  const draftMax = draft.max;
3928
3994
  const isEmpty = draftMin == null && draftMax == null;
@@ -3950,6 +4016,7 @@ function RangePanel({
3950
4016
  /* @__PURE__ */ (0, import_jsx_runtime45.jsx)(
3951
4017
  NumberInput,
3952
4018
  {
4019
+ id: minId,
3953
4020
  label: field.minLabel || "At least",
3954
4021
  value: draftMin ?? "",
3955
4022
  min: field.min,
@@ -3959,11 +4026,13 @@ function RangePanel({
3959
4026
  placeholder: field.minPlaceholder,
3960
4027
  onChange: (e) => apply({ min: e.target.value }),
3961
4028
  onValidityChange: validity.report("min")
3962
- }
4029
+ },
4030
+ "min-" + seed
3963
4031
  ),
3964
4032
  /* @__PURE__ */ (0, import_jsx_runtime45.jsx)(
3965
4033
  NumberInput,
3966
4034
  {
4035
+ id: maxId,
3967
4036
  label: field.maxLabel || "At most",
3968
4037
  value: draftMax ?? "",
3969
4038
  min: field.min,
@@ -3974,12 +4043,20 @@ function RangePanel({
3974
4043
  placeholder: field.maxPlaceholder,
3975
4044
  onChange: (e) => apply({ max: e.target.value }),
3976
4045
  onValidityChange: validity.report("max")
3977
- }
4046
+ },
4047
+ "max-" + seed
3978
4048
  )
3979
4049
  ] })
3980
4050
  }
3981
4051
  );
3982
4052
  }
4053
+ function dateDraft(field, value) {
4054
+ return {
4055
+ kind: value?.kind ?? "withinDays",
4056
+ days: value?.kind === "withinDays" ? value.days : field.defaultDays ?? 30,
4057
+ between: value?.kind === "between" ? { from: value.from, to: value.to } : { from: "", to: "" }
4058
+ };
4059
+ }
3983
4060
  function DatePanel({
3984
4061
  field,
3985
4062
  value,
@@ -3987,23 +4064,44 @@ function DatePanel({
3987
4064
  onCommit,
3988
4065
  onClose
3989
4066
  }) {
3990
- const defaultDays = field.defaultDays ?? 30;
3991
4067
  const maxDays = effectiveMaxDays(field);
3992
- const [kind, setKind] = React24.useState(value?.kind ?? "withinDays");
3993
- const [daysDraft, setDaysDraft] = React24.useState(
3994
- value?.kind === "withinDays" ? value.days : defaultDays
3995
- );
3996
- const daysRef = React24.useRef(daysDraft);
3997
- const [between, setBetween] = React24.useState(
3998
- value?.kind === "between" ? { from: value.from, to: value.to } : { from: "", to: "" }
3999
- );
4068
+ const [initial] = React25.useState(() => dateDraft(field, value));
4069
+ const [kind, setKind] = React25.useState(initial.kind);
4070
+ const [daysDraft, setDaysDraft] = React25.useState(initial.days);
4071
+ const daysRef = React25.useRef(daysDraft);
4072
+ const daysConfirmed = React25.useRef(value?.kind === "withinDays");
4073
+ const [between, setBetween] = React25.useState(initial.between);
4074
+ const [seed, setSeed] = React25.useState(0);
4075
+ const preserveFocus = usePreserveFocusAcrossRemount(seed);
4076
+ const daysId = field.key + "-days";
4000
4077
  const shownWithinDays = () => {
4001
4078
  const days = daysRef.current;
4002
4079
  return applicable(field, days == null ? void 0 : { kind: "withinDays", days }, validity.allValid());
4003
4080
  };
4004
- const validity = useTextValidity(() => onCommit(shownWithinDays()));
4081
+ const validity = useTextValidity(() => {
4082
+ daysConfirmed.current = true;
4083
+ onCommit(shownWithinDays());
4084
+ });
4085
+ const applies = () => {
4086
+ if (kind === "between") {
4087
+ return applicable(field, between.from && between.to ? { kind: "between", ...between } : void 0, true);
4088
+ }
4089
+ return daysConfirmed.current ? shownWithinDays() : void 0;
4090
+ };
4091
+ useReseedFromProps(value, applies, (next) => {
4092
+ preserveFocus([daysId]);
4093
+ const d = dateDraft(field, next);
4094
+ setKind(d.kind);
4095
+ daysRef.current = d.days;
4096
+ daysConfirmed.current = next?.kind === "withinDays";
4097
+ setDaysDraft(d.days);
4098
+ setBetween(d.between);
4099
+ validity.reset();
4100
+ setSeed((n) => n + 1);
4101
+ });
4005
4102
  const applyWithinDays = (days) => {
4006
4103
  daysRef.current = days;
4104
+ daysConfirmed.current = true;
4007
4105
  setDaysDraft(days);
4008
4106
  onCommit(shownWithinDays());
4009
4107
  };
@@ -4018,8 +4116,10 @@ function DatePanel({
4018
4116
  setBetween({ from: "", to: "" });
4019
4117
  validity.forget("days");
4020
4118
  } else {
4021
- daysRef.current = defaultDays;
4022
- setDaysDraft(defaultDays);
4119
+ const { days } = dateDraft(field, void 0);
4120
+ daysRef.current = days;
4121
+ daysConfirmed.current = false;
4122
+ setDaysDraft(days);
4023
4123
  }
4024
4124
  onCommit(void 0);
4025
4125
  };
@@ -4059,6 +4159,7 @@ function DatePanel({
4059
4159
  kind === "withinDays" ? /* @__PURE__ */ (0, import_jsx_runtime45.jsx)(
4060
4160
  NumberInput,
4061
4161
  {
4162
+ id: daysId,
4062
4163
  label: "Days",
4063
4164
  min: 1,
4064
4165
  max: maxDays,
@@ -4067,7 +4168,8 @@ function DatePanel({
4067
4168
  value: daysDraft ?? "",
4068
4169
  onChange: (e) => applyWithinDays(e.target.value),
4069
4170
  onValidityChange: validity.report("days")
4070
- }
4171
+ },
4172
+ "days-" + seed
4071
4173
  ) : /* @__PURE__ */ (0, import_jsx_runtime45.jsx)(
4072
4174
  DatePicker,
4073
4175
  {
@@ -4075,30 +4177,23 @@ function DatePanel({
4075
4177
  label: "Date range",
4076
4178
  value: { start: between.from, end: between.to },
4077
4179
  onChange: (e) => applyBetween(e.target.value.start || "", e.target.value.end || "")
4078
- }
4180
+ },
4181
+ "between-" + seed
4079
4182
  )
4080
4183
  ] })
4081
4184
  }
4082
4185
  );
4083
4186
  }
4084
4187
  function FilterBar({ fields = [], filters, onFilterChange, onFilterRemove, align = "left", className = "", ...rest }) {
4085
- const [panel, setPanel] = React24.useState(null);
4086
- const editAnchorRef = React24.useRef(null);
4087
- const addAnchorRef = React24.useRef(null);
4088
- const textInputRef = React24.useRef(null);
4089
- const optionsRef = React24.useRef(null);
4188
+ const [panel, setPanel] = React25.useState(null);
4189
+ const editAnchorRef = React25.useRef(null);
4190
+ const addAnchorRef = React25.useRef(null);
4191
+ const textInputRef = React25.useRef(null);
4192
+ const optionsRef = React25.useRef(null);
4090
4193
  if (process.env.NODE_ENV !== "production") {
4091
4194
  for (const f of fields) assertValidFieldDefinition(f);
4092
4195
  }
4093
- const latest = React24.useRef({ fields, filters, onFilterChange, onFilterRemove });
4094
- const filtersProp = React24.useRef(filters);
4095
- if (filters !== filtersProp.current) {
4096
- filtersProp.current = filters;
4097
- latest.current.filters = filters;
4098
- }
4099
- latest.current.fields = fields;
4100
- latest.current.onFilterChange = onFilterChange;
4101
- latest.current.onFilterRemove = onFilterRemove;
4196
+ const latest = useLatest({ fields, filters, onFilterChange, onFilterRemove });
4102
4197
  const commit = (field, candidate) => {
4103
4198
  const current2 = latest.current.fields.find((f) => f.key === field.key);
4104
4199
  if (!current2) return { ok: false, reason: "This filter is no longer available" };
@@ -4107,24 +4202,17 @@ function FilterBar({ fields = [], filters, onFilterChange, onFilterRemove, align
4107
4202
  return { ok: true };
4108
4203
  }
4109
4204
  const result = validateFilterValue(current2, candidate);
4110
- if (result.ok) {
4111
- latest.current.filters = { ...latest.current.filters, [current2.key]: candidate };
4112
- latest.current.onFilterChange(current2.key, candidate);
4113
- }
4205
+ if (result.ok) latest.current.onFilterChange(current2.key, candidate);
4114
4206
  return result;
4115
4207
  };
4116
4208
  const removeField = (field) => {
4117
4209
  const { filters: now, onFilterRemove: remove } = latest.current;
4118
- if (!isFieldSet(field, now[field.key])) return;
4119
- const next = { ...now };
4120
- delete next[field.key];
4121
- latest.current.filters = next;
4122
- remove(field.key);
4210
+ if (isFieldSet(field, now[field.key])) remove(field.key);
4123
4211
  };
4124
4212
  const editingField = panel && panel.kind === "edit" ? fields.find((f) => f.key === panel.key) : void 0;
4125
4213
  const startEditing = (key) => setPanel({ kind: "edit", key });
4126
4214
  const closeEditing = () => setPanel(null);
4127
- React24.useEffect(() => {
4215
+ React25.useEffect(() => {
4128
4216
  if (!panel || panel.kind !== "edit") return;
4129
4217
  if (editingField?.type === "text") {
4130
4218
  textInputRef.current?.focus();
@@ -4330,7 +4418,7 @@ function StatTile({ label, value, sub, delta, invert = false, loading = false, c
4330
4418
  }
4331
4419
 
4332
4420
  // src/components/data/CodeBlock.tsx
4333
- var React25 = __toESM(require("react"), 1);
4421
+ var React26 = __toESM(require("react"), 1);
4334
4422
  var import_jsx_runtime47 = require("react/jsx-runtime");
4335
4423
  var JS_KW = /^(?:const|let|var|function|return|if|else|for|while|do|new|class|extends|import|from|export|default|await|async|try|catch|finally|throw|typeof|instanceof|of|in|switch|case|break|continue|delete|void|yield|static|get|set|this|super|interface|type|enum|implements|public|private|protected|readonly|abstract|as|satisfies|declare|namespace)$/;
4336
4424
  var RULES = {
@@ -4486,13 +4574,13 @@ function tokenize(src, lang) {
4486
4574
  return out;
4487
4575
  }
4488
4576
  function Highlighted({ code, lang }) {
4489
- const toks = React25.useMemo(() => tokenize(code, lang), [code, lang]);
4577
+ const toks = React26.useMemo(() => tokenize(code, lang), [code, lang]);
4490
4578
  return /* @__PURE__ */ (0, import_jsx_runtime47.jsx)(import_jsx_runtime47.Fragment, { children: toks.map((tk, i) => tk.c ? /* @__PURE__ */ (0, import_jsx_runtime47.jsx)("span", { className: "tok-" + tk.c, children: tk.t }, i) : tk.t) });
4491
4579
  }
4492
4580
  function useCopy() {
4493
- const [done, setDone] = React25.useState(false);
4494
- const timer = React25.useRef(null);
4495
- React25.useEffect(() => () => {
4581
+ const [done, setDone] = React26.useState(false);
4582
+ const timer = React26.useRef(null);
4583
+ React26.useEffect(() => () => {
4496
4584
  if (timer.current) clearTimeout(timer.current);
4497
4585
  }, []);
4498
4586
  const copy = (text) => {
@@ -4528,8 +4616,8 @@ function CodeBlock({
4528
4616
  actions,
4529
4617
  className = ""
4530
4618
  }) {
4531
- const [wrap, setWrap] = React25.useState(!!wrapDefault);
4532
- const [open, setOpen] = React25.useState(false);
4619
+ const [wrap, setWrap] = React26.useState(!!wrapDefault);
4620
+ const [open, setOpen] = React26.useState(false);
4533
4621
  const [copied, copy] = useCopy();
4534
4622
  const body = String(code).replace(/\n$/, "");
4535
4623
  const lines = body.split("\n");
@@ -4558,7 +4646,7 @@ function CodeBlock({
4558
4646
  ] });
4559
4647
  }
4560
4648
  function DiffBlock({ diff = "", filename, collapseAfter = 34, className = "" }) {
4561
- const [open, setOpen] = React25.useState(false);
4649
+ const [open, setOpen] = React26.useState(false);
4562
4650
  const [copied, copy] = useCopy();
4563
4651
  const raw = String(diff).replace(/\n$/, "");
4564
4652
  const all = raw.split("\n").map((line) => {
@@ -4604,7 +4692,7 @@ function DiffBlock({ diff = "", filename, collapseAfter = 34, className = "" })
4604
4692
  }
4605
4693
 
4606
4694
  // src/components/data/Markdown.tsx
4607
- var React26 = __toESM(require("react"), 1);
4695
+ var React27 = __toESM(require("react"), 1);
4608
4696
  var import_jsx_runtime48 = require("react/jsx-runtime");
4609
4697
  var SAFE = /^(?:https?:|mailto:|tel:|#|\/|\.{1,2}\/)/i;
4610
4698
  var safeHref = (h) => SAFE.test(String(h || "").trim()) ? String(h).trim() : null;
@@ -4643,7 +4731,7 @@ function inlineNodes(src, ctx, keyBase) {
4643
4731
  const href = safeHref(g(2));
4644
4732
  out.push(href ? /* @__PURE__ */ (0, import_jsx_runtime48.jsx)("a", { href, title: g(3) || void 0, target: /^https?:/i.test(href) ? "_blank" : void 0, rel: "noopener noreferrer", onClick: ctx.onLinkClick, children: inlineNodes(g(1), ctx, key()) }, key()) : /* @__PURE__ */ (0, import_jsx_runtime48.jsx)("span", { children: g(1) }, key()));
4645
4733
  } else if (kind === "cite") {
4646
- out.push(ctx.renderCitation ? /* @__PURE__ */ (0, import_jsx_runtime48.jsx)(React26.Fragment, { children: ctx.renderCitation(g(1)) }, key()) : /* @__PURE__ */ (0, import_jsx_runtime48.jsx)("sup", { className: "fd-md-cite", children: g(1) }, key()));
4734
+ out.push(ctx.renderCitation ? /* @__PURE__ */ (0, import_jsx_runtime48.jsx)(React27.Fragment, { children: ctx.renderCitation(g(1)) }, key()) : /* @__PURE__ */ (0, import_jsx_runtime48.jsx)("sup", { className: "fd-md-cite", children: g(1) }, key()));
4647
4735
  } else if (kind === "strongem") out.push(/* @__PURE__ */ (0, import_jsx_runtime48.jsx)("strong", { children: /* @__PURE__ */ (0, import_jsx_runtime48.jsx)("em", { children: inlineNodes(g(1), ctx, key()) }) }, key()));
4648
4736
  else if (kind === "strong") out.push(/* @__PURE__ */ (0, import_jsx_runtime48.jsx)("strong", { children: inlineNodes(g(1) || g(2), ctx, key()) }, key()));
4649
4737
  else if (kind === "em") out.push(/* @__PURE__ */ (0, import_jsx_runtime48.jsx)("em", { children: inlineNodes(g(1) || g(2), ctx, key()) }, key()));
@@ -4808,7 +4896,7 @@ function Markdown({
4808
4896
  onLinkClick
4809
4897
  }) {
4810
4898
  const ctx = { allowImages, headingOffset, renderCitation, onLinkClick, codeProps };
4811
- const blocks = React26.useMemo(() => parseBlocks(source), [source]);
4899
+ const blocks = React27.useMemo(() => parseBlocks(source), [source]);
4812
4900
  return /* @__PURE__ */ (0, import_jsx_runtime48.jsx)("div", { className: ["fd-md", className].filter(Boolean).join(" "), children: renderBlocks(blocks, ctx, "b") });
4813
4901
  }
4814
4902
  function MarkdownInline({ source = "", className = "", onLinkClick }) {
@@ -4922,7 +5010,7 @@ function Pagination({
4922
5010
  }
4923
5011
 
4924
5012
  // src/components/data/RelativeTime.tsx
4925
- var React27 = __toESM(require("react"), 1);
5013
+ var React28 = __toESM(require("react"), 1);
4926
5014
  var import_jsx_runtime51 = require("react/jsx-runtime");
4927
5015
  var MIN = 6e4;
4928
5016
  var HOUR = 36e5;
@@ -4974,9 +5062,9 @@ function formatDuration(ms) {
4974
5062
  return h + "h" + (m % 60 ? " " + m % 60 + "m" : "");
4975
5063
  }
4976
5064
  function RelativeTime({ value, prefix, className = "", refresh: refresh2 = true, ...rest }) {
4977
- const [, force] = React27.useState(0);
5065
+ const [, force] = React28.useState(0);
4978
5066
  const t = value instanceof Date ? value.getTime() : Date.parse(value);
4979
- React27.useEffect(() => {
5067
+ React28.useEffect(() => {
4980
5068
  if (!refresh2 || !t || isNaN(t)) return;
4981
5069
  const abs = Math.abs(t - Date.now());
4982
5070
  if (abs > DAY) return;
@@ -4992,7 +5080,7 @@ function RelativeTime({ value, prefix, className = "", refresh: refresh2 = true,
4992
5080
  }
4993
5081
 
4994
5082
  // src/components/data/ScoreMeter.tsx
4995
- var React28 = __toESM(require("react"), 1);
5083
+ var React29 = __toESM(require("react"), 1);
4996
5084
  var import_jsx_runtime52 = require("react/jsx-runtime");
4997
5085
  function ScoreMeter({
4998
5086
  score,
@@ -5007,10 +5095,10 @@ function ScoreMeter({
5007
5095
  breakdownWidth = 280,
5008
5096
  className = ""
5009
5097
  }) {
5010
- const [open, setOpen] = React28.useState(false);
5011
- const ref = React28.useRef(null);
5098
+ const [open, setOpen] = React29.useState(false);
5099
+ const ref = React29.useRef(null);
5012
5100
  const value = Math.max(0, Math.min(100, Math.round(Number(score) || 0)));
5013
- const body = /* @__PURE__ */ (0, import_jsx_runtime52.jsxs)(React28.Fragment, { children: [
5101
+ const body = /* @__PURE__ */ (0, import_jsx_runtime52.jsxs)(React29.Fragment, { children: [
5014
5102
  /* @__PURE__ */ (0, import_jsx_runtime52.jsx)("span", { className: "fd-scoremeter-rail", style: { width }, "aria-hidden": "true", children: /* @__PURE__ */ (0, import_jsx_runtime52.jsx)(SegmentedMeter, { total: 100, segments, height, showTotal: false, showPercent: false, legend: false }) }),
5015
5103
  showScore ? /* @__PURE__ */ (0, import_jsx_runtime52.jsx)("span", { className: "fd-scoremeter-value fd-tabular", "aria-hidden": "true", children: value }) : null
5016
5104
  ] });
@@ -5029,7 +5117,7 @@ function ScoreMeter({
5029
5117
  }
5030
5118
  );
5031
5119
  }
5032
- return /* @__PURE__ */ (0, import_jsx_runtime52.jsxs)(React28.Fragment, { children: [
5120
+ return /* @__PURE__ */ (0, import_jsx_runtime52.jsxs)(React29.Fragment, { children: [
5033
5121
  /* @__PURE__ */ (0, import_jsx_runtime52.jsx)(
5034
5122
  "button",
5035
5123
  {
@@ -5060,13 +5148,13 @@ function ScoreMeter({
5060
5148
  }
5061
5149
 
5062
5150
  // src/components/data/SortMenu.tsx
5063
- var React29 = __toESM(require("react"), 1);
5151
+ var React30 = __toESM(require("react"), 1);
5064
5152
  var import_jsx_runtime53 = require("react/jsx-runtime");
5065
5153
  function SortMenu({ fields = [], sort, onSort, align = "right", size = "md", className = "", ...rest }) {
5066
- const [open, setOpen] = React29.useState(false);
5154
+ const [open, setOpen] = React30.useState(false);
5067
5155
  const zIndex = useOverlayLayer(open);
5068
- const ref = React29.useRef(null);
5069
- React29.useEffect(() => {
5156
+ const ref = React30.useRef(null);
5157
+ React30.useEffect(() => {
5070
5158
  if (!open) return;
5071
5159
  const away = (e) => {
5072
5160
  if (ref.current && !ref.current.contains(e.target)) setOpen(false);
@@ -5128,7 +5216,7 @@ function SortMenu({ fields = [], sort, onSort, align = "right", size = "md", cla
5128
5216
  }
5129
5217
 
5130
5218
  // src/components/data/StepList.tsx
5131
- var React30 = __toESM(require("react"), 1);
5219
+ var React31 = __toESM(require("react"), 1);
5132
5220
  var import_jsx_runtime54 = require("react/jsx-runtime");
5133
5221
  var KIND_ICON = { tool: "wrench", search: "magnifying-glass", read: "file-text", write: "pencil-simple", reasoning: "brain", run: "terminal", fetch: "cloud-arrow-down" };
5134
5222
  function StepList({
@@ -5141,9 +5229,9 @@ function StepList({
5141
5229
  dense = false,
5142
5230
  className = ""
5143
5231
  }) {
5144
- const [openState, setOpenState] = React30.useState(defaultOpen);
5232
+ const [openState, setOpenState] = React31.useState(defaultOpen);
5145
5233
  const open = openProp == null ? openState : openProp;
5146
- const [expanded, setExpanded] = React30.useState({});
5234
+ const [expanded, setExpanded] = React31.useState({});
5147
5235
  if (!steps.length) return null;
5148
5236
  const running = steps.some((s) => s.status === "running");
5149
5237
  const failed = steps.filter((s) => s.status === "error").length;
@@ -5201,7 +5289,7 @@ function StepList({
5201
5289
  }
5202
5290
 
5203
5291
  // src/components/data/VirtualList.tsx
5204
- var React31 = __toESM(require("react"), 1);
5292
+ var React32 = __toESM(require("react"), 1);
5205
5293
  var import_jsx_runtime55 = require("react/jsx-runtime");
5206
5294
  var VIRTUAL_LIST_BUFFER_ROWS = 20;
5207
5295
  var VIRTUAL_LIST_ROW_GAP = 6;
@@ -5253,35 +5341,35 @@ function VirtualList({
5253
5341
  className = "",
5254
5342
  style
5255
5343
  }) {
5256
- const [scrollTop, setScrollTop] = React31.useState(0);
5257
- const loaded = React31.useMemo(
5344
+ const [scrollTop, setScrollTop] = React32.useState(0);
5345
+ const loaded = React32.useMemo(
5258
5346
  () => ({ firstItemIndex, count: items.length }),
5259
5347
  [firstItemIndex, items.length]
5260
5348
  );
5261
5349
  const total = Math.max(totalCount == null ? 0 : totalCount, firstItemIndex + items.length);
5262
5350
  const bandKey = firstItemIndex + ":" + items.length;
5263
- const win = React31.useMemo(
5351
+ const win = React32.useMemo(
5264
5352
  () => computeVirtualWindow({ scrollTop, viewportHeight: height, itemHeight, itemCount: total, loaded }),
5265
5353
  [scrollTop, height, itemHeight, total, loaded]
5266
5354
  );
5267
- const need = React31.useMemo(() => computeNeedMore(win, loaded), [win, loaded]);
5355
+ const need = React32.useMemo(() => computeNeedMore(win, loaded), [win, loaded]);
5268
5356
  const wantStart = need.start && hasMore?.start !== false;
5269
5357
  const wantEnd = need.end && hasMore?.end !== false;
5270
5358
  const bucket2 = Math.floor(win.visibleStart / VIRTUAL_LIST_BUFFER_ROWS);
5271
5359
  const askKey = bandKey + "@" + bucket2;
5272
- const asked = React31.useRef({ start: null, end: null });
5273
- React31.useEffect(() => {
5360
+ const asked = React32.useRef({ start: null, end: null });
5361
+ React32.useEffect(() => {
5274
5362
  if (loading || !wantStart || asked.current.start === askKey) return;
5275
5363
  asked.current.start = askKey;
5276
5364
  onNeedMore("start", win);
5277
5365
  }, [wantStart, loading, askKey, onNeedMore, win]);
5278
- React31.useEffect(() => {
5366
+ React32.useEffect(() => {
5279
5367
  if (loading || !wantEnd || asked.current.end === askKey) return;
5280
5368
  asked.current.end = askKey;
5281
5369
  onNeedMore("end", win);
5282
5370
  }, [wantEnd, loading, askKey, onNeedMore, win]);
5283
- const lastKeysRef = React31.useRef(null);
5284
- const newKeys = React31.useMemo(() => {
5371
+ const lastKeysRef = React32.useRef(null);
5372
+ const newKeys = React32.useMemo(() => {
5285
5373
  const prev = lastKeysRef.current;
5286
5374
  if (!prev) return /* @__PURE__ */ new Set();
5287
5375
  const fresh = /* @__PURE__ */ new Set();
@@ -5291,7 +5379,7 @@ function VirtualList({
5291
5379
  }
5292
5380
  return fresh;
5293
5381
  }, [items]);
5294
- React31.useEffect(() => {
5382
+ React32.useEffect(() => {
5295
5383
  lastKeysRef.current = new Set(items.map(keyOf));
5296
5384
  }, [items]);
5297
5385
  const gapStyle = { "--fd-vlist-gap": rowGap + "px" };
@@ -5336,7 +5424,7 @@ function VirtualList({
5336
5424
  }
5337
5425
 
5338
5426
  // src/components/data/EntityRow.tsx
5339
- var React32 = __toESM(require("react"), 1);
5427
+ var React33 = __toESM(require("react"), 1);
5340
5428
  var import_jsx_runtime56 = require("react/jsx-runtime");
5341
5429
  var ENTITY_ROW_METRIC_WIDTH = 74;
5342
5430
  var METRIC_TONE_COLOR = {
@@ -5349,7 +5437,7 @@ function EntityRowMetrics({ metrics, className = "", style }) {
5349
5437
  const key = m.id || m.label || i;
5350
5438
  const className2 = ["fd-erow-metric", m.tone && m.tone !== "default" ? "is-" + m.tone : "", m.tooltip != null ? "is-described" : ""].filter(Boolean).join(" ");
5351
5439
  const tone = { color: METRIC_TONE_COLOR[m.tone || "default"] };
5352
- const content = /* @__PURE__ */ (0, import_jsx_runtime56.jsxs)(React32.Fragment, { children: [
5440
+ const content = /* @__PURE__ */ (0, import_jsx_runtime56.jsxs)(React33.Fragment, { children: [
5353
5441
  m.icon ? /* @__PURE__ */ (0, import_jsx_runtime56.jsx)("i", { className: "ph ph-" + m.icon, "aria-hidden": "true" }) : null,
5354
5442
  /* @__PURE__ */ (0, import_jsx_runtime56.jsx)("span", { className: "fd-erow-metric-value fd-tabular", children: m.value }),
5355
5443
  /* @__PURE__ */ (0, import_jsx_runtime56.jsx)("span", { className: "fd-sr", children: " " + m.label })
@@ -5441,7 +5529,7 @@ function EntityRow({
5441
5529
  }
5442
5530
 
5443
5531
  // src/components/data/TransferList.tsx
5444
- var React33 = __toESM(require("react"), 1);
5532
+ var React34 = __toESM(require("react"), 1);
5445
5533
  var import_react_dom5 = require("react-dom");
5446
5534
 
5447
5535
  // src/components/forms/Input.tsx
@@ -5547,12 +5635,12 @@ function TransferList({
5547
5635
  listHeight = 440,
5548
5636
  className = ""
5549
5637
  }) {
5550
- const [drag, setDrag] = React33.useState(null);
5551
- const [dragOverSide, setDragOverSide] = React33.useState(null);
5552
- const dragRef = React33.useRef(null);
5553
- const armedRef = React33.useRef(null);
5554
- const sideRefs = React33.useRef({ left: null, right: null });
5555
- const hitTestSide = React33.useCallback((x, y) => {
5638
+ const [drag, setDrag] = React34.useState(null);
5639
+ const [dragOverSide, setDragOverSide] = React34.useState(null);
5640
+ const dragRef = React34.useRef(null);
5641
+ const armedRef = React34.useRef(null);
5642
+ const sideRefs = React34.useRef({ left: null, right: null });
5643
+ const hitTestSide = React34.useCallback((x, y) => {
5556
5644
  for (const side of ["left", "right"]) {
5557
5645
  const el = sideRefs.current[side];
5558
5646
  if (!el) continue;
@@ -5561,7 +5649,7 @@ function TransferList({
5561
5649
  }
5562
5650
  return null;
5563
5651
  }, []);
5564
- const findItem = React33.useCallback(
5652
+ const findItem = React34.useCallback(
5565
5653
  (side, key) => (side === "left" ? left.items : right.items).find((it) => keyOf(it) === key),
5566
5654
  [left.items, right.items, keyOf]
5567
5655
  );
@@ -5583,7 +5671,7 @@ function TransferList({
5583
5671
  height: rect.height
5584
5672
  };
5585
5673
  };
5586
- React33.useEffect(() => {
5674
+ React34.useEffect(() => {
5587
5675
  const onMovePointer = (e) => {
5588
5676
  const armed = armedRef.current;
5589
5677
  if (!armed || e.pointerId !== armed.pointerId) return;
@@ -5636,7 +5724,7 @@ function TransferList({
5636
5724
  window.removeEventListener("pointercancel", endDrag);
5637
5725
  };
5638
5726
  }, [hitTestSide, findItem, onMove]);
5639
- React33.useEffect(() => {
5727
+ React34.useEffect(() => {
5640
5728
  if (!drag || typeof document === "undefined") return;
5641
5729
  const prev = document.body.style.userSelect;
5642
5730
  document.body.style.userSelect = "none";
@@ -5744,11 +5832,11 @@ function TransferList({
5744
5832
  }
5745
5833
 
5746
5834
  // src/components/forms/Checkbox.tsx
5747
- var React34 = __toESM(require("react"), 1);
5835
+ var React35 = __toESM(require("react"), 1);
5748
5836
  var import_jsx_runtime60 = require("react/jsx-runtime");
5749
5837
  function Checkbox({ label, description, card = false, indeterminate = false, className = "", ...rest }) {
5750
- const ref = React34.useRef(null);
5751
- React34.useEffect(() => {
5838
+ const ref = React35.useRef(null);
5839
+ React35.useEffect(() => {
5752
5840
  if (ref.current) ref.current.indeterminate = indeterminate;
5753
5841
  }, [indeterminate]);
5754
5842
  return /* @__PURE__ */ (0, import_jsx_runtime60.jsxs)("label", { className: ["fd-choice", card ? "fd-choice-card" : "", className].filter(Boolean).join(" "), children: [
@@ -5792,7 +5880,7 @@ function Switch({ label, description, className = "", ...rest }) {
5792
5880
  }
5793
5881
 
5794
5882
  // src/components/forms/Select.tsx
5795
- var React35 = __toESM(require("react"), 1);
5883
+ var React36 = __toESM(require("react"), 1);
5796
5884
  var import_jsx_runtime63 = require("react/jsx-runtime");
5797
5885
  var norm = (o) => typeof o === "string" ? { value: o, label: o } : o;
5798
5886
  function Select({
@@ -5819,12 +5907,12 @@ function Select({
5819
5907
  const isOn = (v) => multiple ? vals.includes(v) : v === value;
5820
5908
  const hasSearch = searchable === void 0 ? opts.length > 8 : searchable;
5821
5909
  const { fieldId, labelId, ariaLabelledBy } = useTriggerLabelling(label, id);
5822
- const [open, setOpen] = React35.useState(false);
5823
- const [q, setQ] = React35.useState("");
5824
- const rootRef = React35.useRef(null);
5825
- const boxRef = React35.useRef(null);
5826
- const listRef = React35.useRef(null);
5827
- const typeBuf = React35.useRef({ s: "", t: 0 });
5910
+ const [open, setOpen] = React36.useState(false);
5911
+ const [q, setQ] = React36.useState("");
5912
+ const rootRef = React36.useRef(null);
5913
+ const boxRef = React36.useRef(null);
5914
+ const listRef = React36.useRef(null);
5915
+ const typeBuf = React36.useRef({ s: "", t: 0 });
5828
5916
  const selected = multiple ? null : opts.find((o) => o.value === value);
5829
5917
  const chosen = multiple ? opts.filter((o) => vals.includes(o.value)) : [];
5830
5918
  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;
@@ -5963,7 +6051,7 @@ function Select({
5963
6051
  ),
5964
6052
  q ? /* @__PURE__ */ (0, import_jsx_runtime63.jsx)("span", { className: "fd-body-sm fd-muted", children: visible.length }) : null
5965
6053
  ] }) : void 0,
5966
- footer: multiple ? /* @__PURE__ */ (0, import_jsx_runtime63.jsxs)(React35.Fragment, { children: [
6054
+ footer: multiple ? /* @__PURE__ */ (0, import_jsx_runtime63.jsxs)(React36.Fragment, { children: [
5967
6055
  /* @__PURE__ */ (0, import_jsx_runtime63.jsx)(
5968
6056
  "button",
5969
6057
  {
@@ -5994,7 +6082,7 @@ function Select({
5994
6082
  'Nothing matches "',
5995
6083
  q,
5996
6084
  '".'
5997
- ] }) : groups.map((grp) => /* @__PURE__ */ (0, import_jsx_runtime63.jsxs)(React35.Fragment, { children: [
6085
+ ] }) : groups.map((grp) => /* @__PURE__ */ (0, import_jsx_runtime63.jsxs)(React36.Fragment, { children: [
5998
6086
  grp.g ? /* @__PURE__ */ (0, import_jsx_runtime63.jsx)("div", { className: "fd-pop-group", children: grp.g }) : null,
5999
6087
  grp.items.map(({ o, i }) => /* @__PURE__ */ (0, import_jsx_runtime63.jsxs)(
6000
6088
  "button",
@@ -6031,7 +6119,7 @@ function Select({
6031
6119
  }
6032
6120
 
6033
6121
  // src/components/forms/TimePicker.tsx
6034
- var React36 = __toESM(require("react"), 1);
6122
+ var React37 = __toESM(require("react"), 1);
6035
6123
  var import_jsx_runtime64 = require("react/jsx-runtime");
6036
6124
  var pad = (n) => String(n).padStart(2, "0");
6037
6125
  function ClockFace({ value = "09:00", onChange }) {
@@ -6040,9 +6128,9 @@ function ClockFace({ value = "09:00", onChange }) {
6040
6128
  if (isNaN(m)) m = 0;
6041
6129
  const pm = h24 >= 12;
6042
6130
  const h12 = h24 % 12 === 0 ? 12 : h24 % 12;
6043
- const [mode2, setMode] = React36.useState("h");
6044
- const faceRef = React36.useRef(null);
6045
- const dragging = React36.useRef(false);
6131
+ const [mode2, setMode] = React37.useState("h");
6132
+ const faceRef = React37.useRef(null);
6133
+ const dragging = React37.useRef(false);
6046
6134
  const set = (h, mm, isPm) => onChange((isPm ? h % 12 + 12 : h % 12) + ":" + pad(mm));
6047
6135
  const R = 108, NR = 80;
6048
6136
  const nums = mode2 === "h" ? Array.from({ length: 12 }, (_, i) => i + 1) : Array.from({ length: 12 }, (_, i) => i * 5);
@@ -6115,9 +6203,9 @@ function ClockFace({ value = "09:00", onChange }) {
6115
6203
  }
6116
6204
  function TimePicker({ label, help, error, required = false, disabled = false, value = "", onChange, placeholder = "Pick a time", id, className = "", style }) {
6117
6205
  const { fieldId, labelId, ariaLabelledBy } = useTriggerLabelling(label, id);
6118
- const [open, setOpen] = React36.useState(false);
6119
- const rootRef = React36.useRef(null);
6120
- const boxRef = React36.useRef(null);
6206
+ const [open, setOpen] = React37.useState(false);
6207
+ const rootRef = React37.useRef(null);
6208
+ const boxRef = React37.useRef(null);
6121
6209
  const disp = () => {
6122
6210
  if (!value) return "";
6123
6211
  const [h, m] = value.split(":").map(Number);
@@ -6160,7 +6248,7 @@ function TimePicker({ label, help, error, required = false, disabled = false, va
6160
6248
  offset: 6,
6161
6249
  width: 262,
6162
6250
  role: "presentation",
6163
- footer: /* @__PURE__ */ (0, import_jsx_runtime64.jsxs)(React36.Fragment, { children: [
6251
+ footer: /* @__PURE__ */ (0, import_jsx_runtime64.jsxs)(React37.Fragment, { children: [
6164
6252
  /* @__PURE__ */ (0, import_jsx_runtime64.jsx)(
6165
6253
  "button",
6166
6254
  {
@@ -6188,7 +6276,7 @@ function TimePicker({ label, help, error, required = false, disabled = false, va
6188
6276
  }
6189
6277
 
6190
6278
  // src/components/forms/Slider.tsx
6191
- var React37 = __toESM(require("react"), 1);
6279
+ var React38 = __toESM(require("react"), 1);
6192
6280
  var import_jsx_runtime65 = require("react/jsx-runtime");
6193
6281
  function Slider({
6194
6282
  label,
@@ -6206,7 +6294,7 @@ function Slider({
6206
6294
  ...rest
6207
6295
  }) {
6208
6296
  const fieldId = useFieldId(id);
6209
- const [dragging, setDragging] = React37.useState(false);
6297
+ const [dragging, setDragging] = React38.useState(false);
6210
6298
  const v = value === void 0 ? min : Number(value);
6211
6299
  const pct = max === min ? 0 : (v - min) / (max - min) * 100;
6212
6300
  return /* @__PURE__ */ (0, import_jsx_runtime65.jsxs)("div", { className: ["fd-field", className].filter(Boolean).join(" "), children: [
@@ -6240,7 +6328,7 @@ function Slider({
6240
6328
  }
6241
6329
 
6242
6330
  // src/components/forms/RangeSlider.tsx
6243
- var React38 = __toESM(require("react"), 1);
6331
+ var React39 = __toESM(require("react"), 1);
6244
6332
  var import_jsx_runtime66 = require("react/jsx-runtime");
6245
6333
  function RangeSlider({
6246
6334
  label,
@@ -6260,9 +6348,9 @@ function RangeSlider({
6260
6348
  }) {
6261
6349
  const fmt2 = format || ((v) => String(v));
6262
6350
  const [a, b] = value || [min, max];
6263
- const [drag, setDrag] = React38.useState(null);
6264
- const [focus, setFocus] = React38.useState(null);
6265
- const railRef = React38.useRef(null);
6351
+ const [drag, setDrag] = React39.useState(null);
6352
+ const [focus, setFocus] = React39.useState(null);
6353
+ const railRef = React39.useRef(null);
6266
6354
  const pct = (v) => max === min ? 0 : (v - min) / (max - min) * 100;
6267
6355
  const clampPair = (i, v) => {
6268
6356
  v = Math.min(max, Math.max(min, Math.round(v / step) * step));
@@ -6277,7 +6365,7 @@ function RangeSlider({
6277
6365
  const r = railRef.current.getBoundingClientRect();
6278
6366
  return min + Math.min(1, Math.max(0, (e.clientX - r.left) / r.width)) * (max - min);
6279
6367
  };
6280
- React38.useEffect(() => {
6368
+ React39.useEffect(() => {
6281
6369
  if (drag === null) return;
6282
6370
  const mv = (e) => onChange && onChange(clampPair(drag, fromEvent(e)));
6283
6371
  const upH = () => setDrag(null);
@@ -6358,7 +6446,7 @@ function RangeSlider({
6358
6446
  /* @__PURE__ */ (0, import_jsx_runtime66.jsxs)("div", { className: "fd-range" + (hasLabels ? " has-labels" : ""), onPointerDown: onRailDown, children: [
6359
6447
  /* @__PURE__ */ (0, import_jsx_runtime66.jsx)("span", { className: "fd-range-rail", ref: railRef }),
6360
6448
  /* @__PURE__ */ (0, import_jsx_runtime66.jsx)("span", { className: "fd-range-fill", style: { left: pct(a) + "%", width: pct(b) - pct(a) + "%" } }),
6361
- marks.map((m) => /* @__PURE__ */ (0, import_jsx_runtime66.jsxs)(React38.Fragment, { children: [
6449
+ marks.map((m) => /* @__PURE__ */ (0, import_jsx_runtime66.jsxs)(React39.Fragment, { children: [
6362
6450
  /* @__PURE__ */ (0, import_jsx_runtime66.jsx)("span", { className: "fd-range-mark" + (m.value >= a && m.value <= b ? " is-in" : ""), style: { left: pct(m.value) + "%" } }),
6363
6451
  m.label ? /* @__PURE__ */ (0, import_jsx_runtime66.jsx)("span", { className: "fd-range-mark-label", style: { left: pct(m.value) + "%" }, children: m.label }) : null
6364
6452
  ] }, m.value)),
@@ -6387,7 +6475,7 @@ function RangeSlider({
6387
6475
  }
6388
6476
 
6389
6477
  // src/components/forms/Dropzone.tsx
6390
- var React39 = __toESM(require("react"), 1);
6478
+ var React40 = __toESM(require("react"), 1);
6391
6479
  var import_jsx_runtime67 = require("react/jsx-runtime");
6392
6480
  function Dropzone({
6393
6481
  onFiles,
@@ -6402,8 +6490,8 @@ function Dropzone({
6402
6490
  className = "",
6403
6491
  style
6404
6492
  }) {
6405
- const [over, setOver] = React39.useState(false);
6406
- const depth = React39.useRef(0);
6493
+ const [over, setOver] = React40.useState(false);
6494
+ const depth = React40.useRef(0);
6407
6495
  const has = (e) => {
6408
6496
  const dt = e.dataTransfer;
6409
6497
  if (!dt) return false;
@@ -6465,8 +6553,8 @@ function FilePickButton({
6465
6553
  className = "",
6466
6554
  children
6467
6555
  }) {
6468
- const ref = React39.useRef(null);
6469
- return /* @__PURE__ */ (0, import_jsx_runtime67.jsxs)(React39.Fragment, { children: [
6556
+ const ref = React40.useRef(null);
6557
+ return /* @__PURE__ */ (0, import_jsx_runtime67.jsxs)(React40.Fragment, { children: [
6470
6558
  /* @__PURE__ */ (0, import_jsx_runtime67.jsx)(
6471
6559
  "button",
6472
6560
  {
@@ -6499,10 +6587,10 @@ function FilePickButton({
6499
6587
  }
6500
6588
  function useStagedFiles(upload, opts) {
6501
6589
  const o = opts || {};
6502
- const [items, setItems] = React39.useState([]);
6503
- const controllers = React39.useRef({});
6590
+ const [items, setItems] = React40.useState([]);
6591
+ const controllers = React40.useRef({});
6504
6592
  const patch = (id, next) => setItems((list) => list.map((f) => f.id === id ? Object.assign({}, f, next) : f));
6505
- const run = React39.useCallback((att) => {
6593
+ const run = React40.useCallback((att) => {
6506
6594
  if (!upload) return;
6507
6595
  const ac = typeof AbortController !== "undefined" ? new AbortController() : null;
6508
6596
  controllers.current[att.id] = ac;
@@ -6519,14 +6607,14 @@ function useStagedFiles(upload, opts) {
6519
6607
  delete controllers.current[att.id];
6520
6608
  });
6521
6609
  }, [upload]);
6522
- const add = React39.useCallback((files) => {
6610
+ const add = React40.useCallback((files) => {
6523
6611
  if (!upload) return [];
6524
6612
  const atts = Array.from(files).map((f) => toAttachment(f));
6525
6613
  setItems((list) => list.concat(atts));
6526
6614
  atts.forEach(run);
6527
6615
  return atts;
6528
6616
  }, [upload, run]);
6529
- const remove = React39.useCallback((att) => {
6617
+ const remove = React40.useCallback((att) => {
6530
6618
  const ac = controllers.current[att.id];
6531
6619
  if (ac) {
6532
6620
  try {
@@ -6537,10 +6625,10 @@ function useStagedFiles(upload, opts) {
6537
6625
  }
6538
6626
  setItems((list) => list.filter((f) => f.id !== att.id));
6539
6627
  }, []);
6540
- const retry = React39.useCallback((att) => {
6628
+ const retry = React40.useCallback((att) => {
6541
6629
  run(att);
6542
6630
  }, [run]);
6543
- const clear = React39.useCallback(() => {
6631
+ const clear = React40.useCallback(() => {
6544
6632
  Object.values(controllers.current).forEach((ac) => {
6545
6633
  try {
6546
6634
  ac && ac.abort();
@@ -6664,7 +6752,7 @@ function FileGrid({ files = [], onOpen, onRemove, onRetry, tiles = true, maxHeig
6664
6752
  }
6665
6753
 
6666
6754
  // src/components/forms/MarkdownEditor.tsx
6667
- var React40 = __toESM(require("react"), 1);
6755
+ var React41 = __toESM(require("react"), 1);
6668
6756
  var import_jsx_runtime69 = require("react/jsx-runtime");
6669
6757
  var isMac = typeof navigator !== "undefined" && /Mac|iPhone|iPad/.test(navigator.platform || navigator.userAgent || "");
6670
6758
  var INLINE_RE = /(\*\*\*[^*\n]+\*\*\*|\*\*[^*\n]+\*\*|__[^_\n]+__|~~[^~\n]+~~|`[^`\n]+`|\*[^*\s][^*\n]*\*|(?<![A-Za-z0-9_])_[^_\s][^_\n]*_|\[[^\]\n]*\]\([^)\s\n]*\)|https?:\/\/\S+)/g;
@@ -6878,7 +6966,7 @@ function syncDom(root, value) {
6878
6966
  while (root.children.length > lines.length) root.removeChild(root.lastChild);
6879
6967
  }
6880
6968
  var LIST_CONT = RE_LI;
6881
- var MarkdownEditor = React40.forwardRef(function MarkdownEditor2({
6969
+ var MarkdownEditor = React41.forwardRef(function MarkdownEditor2({
6882
6970
  value = "",
6883
6971
  onChange,
6884
6972
  onSubmit,
@@ -6897,10 +6985,10 @@ var MarkdownEditor = React40.forwardRef(function MarkdownEditor2({
6897
6985
  className = "",
6898
6986
  id
6899
6987
  }, ref) {
6900
- const boxRef = React40.useRef(null);
6901
- const composing = React40.useRef(false);
6902
- const pendingCaret = React40.useRef(null);
6903
- React40.useLayoutEffect(() => {
6988
+ const boxRef = React41.useRef(null);
6989
+ const composing = React41.useRef(false);
6990
+ const pendingCaret = React41.useRef(null);
6991
+ React41.useLayoutEffect(() => {
6904
6992
  const root = boxRef.current;
6905
6993
  if (!root || composing.current) return;
6906
6994
  const active = document.activeElement === root || root.contains(document.activeElement);
@@ -6909,7 +6997,7 @@ var MarkdownEditor = React40.forwardRef(function MarkdownEditor2({
6909
6997
  pendingCaret.current = null;
6910
6998
  if (active && caret != null) placeCaret(root, caret);
6911
6999
  }, [value]);
6912
- React40.useEffect(() => {
7000
+ React41.useEffect(() => {
6913
7001
  if (autoFocus && boxRef.current) boxRef.current.focus();
6914
7002
  }, [autoFocus]);
6915
7003
  const caretNow = () => {
@@ -6976,7 +7064,7 @@ var MarkdownEditor = React40.forwardRef(function MarkdownEditor2({
6976
7064
  api.replaceRange(from, to, next, from + next.length);
6977
7065
  }
6978
7066
  };
6979
- React40.useImperativeHandle(ref, () => api);
7067
+ React41.useImperativeHandle(ref, () => api);
6980
7068
  function detect(text, caret) {
6981
7069
  if (!onTrigger) return;
6982
7070
  const upto = text.slice(0, caret);
@@ -7128,16 +7216,16 @@ var MarkdownEditor = React40.forwardRef(function MarkdownEditor2({
7128
7216
  });
7129
7217
 
7130
7218
  // src/components/platform/AccountMenu.tsx
7131
- var React42 = __toESM(require("react"), 1);
7219
+ var React43 = __toESM(require("react"), 1);
7132
7220
 
7133
7221
  // src/kits/sessionContext.tsx
7134
- var React41 = __toESM(require("react"), 1);
7135
- var SessionContext = React41.createContext(null);
7222
+ var React42 = __toESM(require("react"), 1);
7223
+ var SessionContext = React42.createContext(null);
7136
7224
  function SessionProvider({ value, children }) {
7137
- return React41.createElement(SessionContext.Provider, { value }, children);
7225
+ return React42.createElement(SessionContext.Provider, { value }, children);
7138
7226
  }
7139
7227
  function useSessionContext() {
7140
- const ctx = React41.useContext(SessionContext);
7228
+ const ctx = React42.useContext(SessionContext);
7141
7229
  if (!ctx) {
7142
7230
  throw new Error(
7143
7231
  "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."
@@ -7177,11 +7265,11 @@ function AccountMenu({
7177
7265
  ...rest
7178
7266
  }) {
7179
7267
  const { user, roles, can: can2, signOut: ctxSignOut, demo } = useSessionContext();
7180
- const [open, setOpen] = React42.useState(false);
7181
- const [switching, setSwitching] = React42.useState(false);
7182
- const [signingOut, setSigningOut] = React42.useState(false);
7183
- const [signOutError, setSignOutError] = React42.useState(null);
7184
- const ref = React42.useRef(null);
7268
+ const [open, setOpen] = React43.useState(false);
7269
+ const [switching, setSwitching] = React43.useState(false);
7270
+ const [signingOut, setSigningOut] = React43.useState(false);
7271
+ const [signOutError, setSignOutError] = React43.useState(null);
7272
+ const ref = React43.useRef(null);
7185
7273
  const visibleLinks = links.filter((l) => !l.perm || can2(l.perm));
7186
7274
  const visibleGroups = groups.map((g) => ({ label: g.label, links: g.links.filter((l) => !l.perm || can2(l.perm)) })).filter((g) => g.links.length);
7187
7275
  const closeMenu = () => {
@@ -7306,13 +7394,13 @@ function AccountMenu({
7306
7394
  }
7307
7395
 
7308
7396
  // src/components/platform/AppSwitcher.tsx
7309
- var React43 = __toESM(require("react"), 1);
7397
+ var React44 = __toESM(require("react"), 1);
7310
7398
  var import_jsx_runtime71 = require("react/jsx-runtime");
7311
7399
  function AppSwitcher({ apps: appsProp, onNavigate, className = "" }) {
7312
7400
  const { apps: contextApps } = useSessionContext();
7313
7401
  const apps = appsProp ?? contextApps ?? [];
7314
- const [open, setOpen] = React43.useState(false);
7315
- const anchorRef = React43.useRef(null);
7402
+ const [open, setOpen] = React44.useState(false);
7403
+ const anchorRef = React44.useRef(null);
7316
7404
  if (!apps.length) return null;
7317
7405
  const items = apps.map((app) => ({
7318
7406
  id: app.key,
@@ -7326,7 +7414,7 @@ function AppSwitcher({ apps: appsProp, onNavigate, className = "" }) {
7326
7414
  window.location.href = app.url;
7327
7415
  }
7328
7416
  }));
7329
- return /* @__PURE__ */ (0, import_jsx_runtime71.jsxs)(React43.Fragment, { children: [
7417
+ return /* @__PURE__ */ (0, import_jsx_runtime71.jsxs)(React44.Fragment, { children: [
7330
7418
  /* @__PURE__ */ (0, import_jsx_runtime71.jsx)("span", { ref: anchorRef, className: ["fd-appswitch-anchor", className].filter(Boolean).join(" "), style: { display: "inline-flex" }, children: /* @__PURE__ */ (0, import_jsx_runtime71.jsx)(
7331
7419
  IconButton,
7332
7420
  {
@@ -7355,10 +7443,10 @@ function AppSwitcher({ apps: appsProp, onNavigate, className = "" }) {
7355
7443
  }
7356
7444
 
7357
7445
  // src/components/platform/AppearanceMenu.tsx
7358
- var React45 = __toESM(require("react"), 1);
7446
+ var React46 = __toESM(require("react"), 1);
7359
7447
 
7360
7448
  // src/kits/appearance.ts
7361
- var React44 = __toESM(require("react"), 1);
7449
+ var React45 = __toESM(require("react"), 1);
7362
7450
  var DEFAULT_STORAGE_KEY = "fd-appearance";
7363
7451
  var DEFAULT_PREFS = {
7364
7452
  theme: "system",
@@ -7453,11 +7541,11 @@ function applyPrefs(prefs, root = document.documentElement) {
7453
7541
  else root.removeAttribute("data-motion");
7454
7542
  }
7455
7543
  function useAppearancePrefs(store) {
7456
- const prefs = React44.useSyncExternalStore(store.subscribe, store.getSnapshot);
7457
- React44.useEffect(() => {
7544
+ const prefs = React45.useSyncExternalStore(store.subscribe, store.getSnapshot);
7545
+ React45.useEffect(() => {
7458
7546
  applyPrefs(prefs);
7459
7547
  }, [prefs]);
7460
- React44.useEffect(() => {
7548
+ React45.useEffect(() => {
7461
7549
  if (prefs.theme !== "system" || typeof window === "undefined" || typeof window.matchMedia !== "function") {
7462
7550
  return;
7463
7551
  }
@@ -7466,7 +7554,7 @@ function useAppearancePrefs(store) {
7466
7554
  mq.addEventListener("change", onChange);
7467
7555
  return () => mq.removeEventListener("change", onChange);
7468
7556
  }, [prefs]);
7469
- const update = React44.useCallback(
7557
+ const update = React45.useCallback(
7470
7558
  (patch) => {
7471
7559
  store.write({ ...store.getSnapshot(), ...patch });
7472
7560
  },
@@ -7489,15 +7577,15 @@ var TEXT_SCALE_OPTIONS = [
7489
7577
  { value: "xl", label: "XL" }
7490
7578
  ];
7491
7579
  function AppearanceMenu({ className = "", store: storeProp, storageKey, storage, defaults }) {
7492
- const store = React45.useMemo(
7580
+ const store = React46.useMemo(
7493
7581
  () => storeProp ?? createLocalStorageAppearanceStore({ storageKey, storage, defaults }),
7494
7582
  [storeProp, storageKey, storage, defaults]
7495
7583
  );
7496
7584
  const [prefs, update] = useAppearancePrefs(store);
7497
- const [open, setOpen] = React45.useState(false);
7498
- const anchorRef = React45.useRef(null);
7585
+ const [open, setOpen] = React46.useState(false);
7586
+ const anchorRef = React46.useRef(null);
7499
7587
  const patch = (p) => update(p);
7500
- return /* @__PURE__ */ (0, import_jsx_runtime72.jsxs)(React45.Fragment, { children: [
7588
+ return /* @__PURE__ */ (0, import_jsx_runtime72.jsxs)(React46.Fragment, { children: [
7501
7589
  /* @__PURE__ */ (0, import_jsx_runtime72.jsx)("span", { ref: anchorRef, className: ["fd-appearance-anchor", className].filter(Boolean).join(" "), style: { display: "inline-flex" }, children: /* @__PURE__ */ (0, import_jsx_runtime72.jsx)(
7502
7590
  IconButton,
7503
7591
  {
@@ -7566,14 +7654,14 @@ function AppearanceMenu({ className = "", store: storeProp, storageKey, storage,
7566
7654
  }
7567
7655
 
7568
7656
  // src/components/platform/ApiSpecBrowser.tsx
7569
- var React46 = __toESM(require("react"), 1);
7657
+ var React47 = __toESM(require("react"), 1);
7570
7658
  var import_jsx_runtime73 = require("react/jsx-runtime");
7571
7659
  var METHOD_TONE = { GET: "success", POST: "info", PATCH: "warning", PUT: "warning", DELETE: "danger" };
7572
7660
  function Json({ obj }) {
7573
7661
  return /* @__PURE__ */ (0, import_jsx_runtime73.jsx)("pre", { className: "fd-json", children: JSON.stringify(obj, null, 2) });
7574
7662
  }
7575
7663
  function Endpoint({ s, onRequest }) {
7576
- const [tried, setTried] = React46.useState(null);
7664
+ const [tried, setTried] = React47.useState(null);
7577
7665
  const run = async () => {
7578
7666
  setTried("busy");
7579
7667
  const t0 = (window.performance || Date).now();
@@ -7646,10 +7734,10 @@ function ApiSpecBrowser({
7646
7734
  className = "",
7647
7735
  ...rest
7648
7736
  }) {
7649
- const [q, setQ] = React46.useState("");
7650
- const [method, setMethod] = React46.useState(null);
7651
- const [mod, setMod] = React46.useState(null);
7652
- const [listOnly, setListOnly] = React46.useState(false);
7737
+ const [q, setQ] = React47.useState("");
7738
+ const [method, setMethod] = React47.useState(null);
7739
+ const [mod, setMod] = React47.useState(null);
7740
+ const [listOnly, setListOnly] = React47.useState(false);
7653
7741
  const activeModule = modules && modules.find((m) => m.id === mod);
7654
7742
  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())));
7655
7743
  const effGroups = groups && groups.length ? groups : [["All endpoints", spec.map((s) => s.id)]];
@@ -7728,7 +7816,7 @@ function ApiSpecBrowser({
7728
7816
  }
7729
7817
 
7730
7818
  // src/components/platform/ProfilePage.tsx
7731
- var React47 = __toESM(require("react"), 1);
7819
+ var React48 = __toESM(require("react"), 1);
7732
7820
  var import_jsx_runtime74 = require("react/jsx-runtime");
7733
7821
  function fieldInitialValue(field, user) {
7734
7822
  if (field.value) return field.value(user);
@@ -7764,21 +7852,21 @@ function ProfilePage({
7764
7852
  }) {
7765
7853
  const { user: sessionUser, roles, permissions, saveProfile: saveProfile2 } = useSessionContext();
7766
7854
  const user = userProp || sessionUser;
7767
- const initialFieldValues = React47.useMemo(() => {
7855
+ const initialFieldValues = React48.useMemo(() => {
7768
7856
  const values2 = {};
7769
7857
  for (const field of fields) values2[field.key] = fieldInitialValue(field, user);
7770
7858
  return values2;
7771
7859
  }, [user.id, fields]);
7772
- const initialNotify = React47.useMemo(() => {
7860
+ const initialNotify = React48.useMemo(() => {
7773
7861
  const values2 = {};
7774
7862
  for (const n of notifications) values2[n.key] = !!user.notify?.[n.key];
7775
7863
  return values2;
7776
7864
  }, [user.id, notifications]);
7777
- const [values, setValues] = React47.useState(initialFieldValues);
7778
- const [notify, setNotify] = React47.useState(initialNotify);
7779
- const [saving, setSaving] = React47.useState(false);
7780
- const [saved, setSaved] = React47.useState(false);
7781
- const [prevUserId, setPrevUserId] = React47.useState(user.id);
7865
+ const [values, setValues] = React48.useState(initialFieldValues);
7866
+ const [notify, setNotify] = React48.useState(initialNotify);
7867
+ const [saving, setSaving] = React48.useState(false);
7868
+ const [saved, setSaved] = React48.useState(false);
7869
+ const [prevUserId, setPrevUserId] = React48.useState(user.id);
7782
7870
  if (user.id !== prevUserId) {
7783
7871
  setPrevUserId(user.id);
7784
7872
  setValues(initialFieldValues);
@@ -7966,11 +8054,11 @@ function ProfilePage({
7966
8054
  }
7967
8055
 
7968
8056
  // src/components/platform/SignInPage.tsx
7969
- var React48 = __toESM(require("react"), 1);
8057
+ var React49 = __toESM(require("react"), 1);
7970
8058
  var import_jsx_runtime75 = require("react/jsx-runtime");
7971
8059
  function SignInPage({ productName, onSignIn, continueAs, error }) {
7972
- const [signingIn, setSigningIn] = React48.useState(false);
7973
- const [resuming, setResuming] = React48.useState(false);
8060
+ const [signingIn, setSigningIn] = React49.useState(false);
8061
+ const [resuming, setResuming] = React49.useState(false);
7974
8062
  function handleSignIn() {
7975
8063
  setSigningIn(true);
7976
8064
  onSignIn();
@@ -8159,10 +8247,10 @@ function GoogleGlyph() {
8159
8247
  }
8160
8248
 
8161
8249
  // src/components/platform/RoadmapTimeline.tsx
8162
- var React51 = __toESM(require("react"), 1);
8250
+ var React52 = __toESM(require("react"), 1);
8163
8251
 
8164
8252
  // src/kits/session.ts
8165
- var React49 = __toESM(require("react"), 1);
8253
+ var React50 = __toESM(require("react"), 1);
8166
8254
  var PERMISSION_CATALOG = [
8167
8255
  { group: "Plans", items: [
8168
8256
  { key: "plan.view", label: "View plans", detail: "Read any plan in the workspace." },
@@ -9729,8 +9817,8 @@ function roadmap(overrides) {
9729
9817
  };
9730
9818
  }
9731
9819
  function useSession() {
9732
- const [s, setS] = React49.useState(getSession);
9733
- React49.useEffect(() => subscribe(setS), []);
9820
+ const [s, setS] = React50.useState(getSession);
9821
+ React50.useEffect(() => subscribe(setS), []);
9734
9822
  return s;
9735
9823
  }
9736
9824
  var SessionKit = {
@@ -9763,7 +9851,7 @@ var SessionKit = {
9763
9851
  };
9764
9852
  function DemoSessionProvider({ children }) {
9765
9853
  const session = useSession();
9766
- const value = React49.useMemo(
9854
+ const value = React50.useMemo(
9767
9855
  () => ({
9768
9856
  user: session.user,
9769
9857
  roles: session.roles,
@@ -9779,11 +9867,11 @@ function DemoSessionProvider({ children }) {
9779
9867
  }),
9780
9868
  [session]
9781
9869
  );
9782
- return React49.createElement(SessionProvider, { value }, children);
9870
+ return React50.createElement(SessionProvider, { value }, children);
9783
9871
  }
9784
9872
 
9785
9873
  // src/kits/runtime.ts
9786
- var React50 = __toESM(require("react"), 1);
9874
+ var React51 = __toESM(require("react"), 1);
9787
9875
  var WIRED_ENDPOINTS = [
9788
9876
  // Nothing yet. Every id below would come from a real service:
9789
9877
  // "plan.get", "placements.list", …
@@ -9954,8 +10042,8 @@ var RuntimeKit = {
9954
10042
  };
9955
10043
  RuntimeKit.declare(FEATURE_NEEDS);
9956
10044
  function useRuntimeMode() {
9957
- const [m, setM] = React50.useState(RuntimeKit.getMode());
9958
- React50.useEffect(() => RuntimeKit.subscribe(setM), []);
10045
+ const [m, setM] = React51.useState(RuntimeKit.getMode());
10046
+ React51.useEffect(() => RuntimeKit.subscribe(setM), []);
9959
10047
  return m;
9960
10048
  }
9961
10049
  function useFeatureStatus(key) {
@@ -10038,12 +10126,12 @@ function RoadmapCard({ item, byKey, onOpenFlag }) {
10038
10126
  }
10039
10127
  function RoadmapTimeline({ onOpenFlag, title = "Roadmap", lede }) {
10040
10128
  const session = SessionKit.useSession();
10041
- const [project, setProject] = React51.useState("");
10042
- const [q, setQ] = React51.useState("");
10043
- const scrollRef = React51.useRef(null);
10044
- const nowRef = React51.useRef(null);
10045
- const rm = React51.useMemo(() => SessionKit.roadmap({ isComplete: RuntimeKit.isComplete }), [session]);
10046
- const byKey = React51.useMemo(() => {
10129
+ const [project, setProject] = React52.useState("");
10130
+ const [q, setQ] = React52.useState("");
10131
+ const scrollRef = React52.useRef(null);
10132
+ const nowRef = React52.useRef(null);
10133
+ const rm = React52.useMemo(() => SessionKit.roadmap({ isComplete: RuntimeKit.isComplete }), [session]);
10134
+ const byKey = React52.useMemo(() => {
10047
10135
  const m = {};
10048
10136
  rm.items.forEach((i) => {
10049
10137
  m[i.key] = i;
@@ -10052,7 +10140,7 @@ function RoadmapTimeline({ onOpenFlag, title = "Roadmap", lede }) {
10052
10140
  }, [rm]);
10053
10141
  const items = rm.items.filter((i) => (!project || i.project === project) && (!q || (i.label + " " + i.description + " " + (i.backend || "") + " " + i.key).toLowerCase().includes(q.toLowerCase())));
10054
10142
  const projects = [...new Set(rm.items.map((i) => i.project))];
10055
- React51.useEffect(() => {
10143
+ React52.useEffect(() => {
10056
10144
  let raf1 = 0, raf2 = 0;
10057
10145
  const place = () => {
10058
10146
  const box = scrollRef.current, mark = nowRef.current;
@@ -10126,7 +10214,7 @@ function RoadmapTimeline({ onOpenFlag, title = "Roadmap", lede }) {
10126
10214
  lastPhase = item.phase;
10127
10215
  const inPhase = items.filter((i) => i.phase === item.phase).length;
10128
10216
  const isBoundary = n === firstPending;
10129
- return /* @__PURE__ */ (0, import_jsx_runtime76.jsxs)(React51.Fragment, { children: [
10217
+ return /* @__PURE__ */ (0, import_jsx_runtime76.jsxs)(React52.Fragment, { children: [
10130
10218
  showPhase ? /* @__PURE__ */ (0, import_jsx_runtime76.jsxs)("div", { className: "fd-rm-era", children: [
10131
10219
  /* @__PURE__ */ (0, import_jsx_runtime76.jsxs)("span", { className: "fd-row", style: { gap: 8, flexWrap: "wrap", alignItems: "baseline" }, children: [
10132
10220
  /* @__PURE__ */ (0, import_jsx_runtime76.jsx)("span", { style: { fontWeight: 700 }, children: item.phase === 0 ? "Shipped" : "Phase " + item.phase + " \u2014 " + item.phaseName }),
@@ -10170,7 +10258,7 @@ function RoadmapTimeline({ onOpenFlag, title = "Roadmap", lede }) {
10170
10258
  }
10171
10259
 
10172
10260
  // src/components/platform/ComingSoon.tsx
10173
- var React52 = __toESM(require("react"), 1);
10261
+ var React53 = __toESM(require("react"), 1);
10174
10262
  var import_react_dom6 = require("react-dom");
10175
10263
  var import_jsx_runtime77 = require("react/jsx-runtime");
10176
10264
  var BYPASS_STORE = "fd.soon.bypass.v1";
@@ -10188,8 +10276,8 @@ function writeBypassed(list) {
10188
10276
  }
10189
10277
  }
10190
10278
  function useBypass(key) {
10191
- const [on, setOn] = React52.useState(() => !!key && readBypassed().indexOf(key) >= 0);
10192
- React52.useEffect(() => {
10279
+ const [on, setOn] = React53.useState(() => !!key && readBypassed().indexOf(key) >= 0);
10280
+ React53.useEffect(() => {
10193
10281
  setOn(!!key && readBypassed().indexOf(key) >= 0);
10194
10282
  }, [key]);
10195
10283
  const set = (next) => {
@@ -10236,9 +10324,9 @@ function SoonCard({ label, detail, backend, eta, effort, onRoadmap, allowed, onB
10236
10324
  ] });
10237
10325
  }
10238
10326
  function useHoverCard(open) {
10239
- const anchor = React52.useRef(null);
10240
- const [pos, setPos] = React52.useState(null);
10241
- React52.useLayoutEffect(() => {
10327
+ const anchor = React53.useRef(null);
10328
+ const [pos, setPos] = React53.useState(null);
10329
+ React53.useLayoutEffect(() => {
10242
10330
  if (!open || !anchor.current) {
10243
10331
  setPos(null);
10244
10332
  return;
@@ -10365,10 +10453,10 @@ function ComingSoon({
10365
10453
  ] });
10366
10454
  }
10367
10455
  function InlineSoon({ label, detail, backend, eta, effort, onRoadmap, allowed, onBypass, blur, tip, className, rest, children }) {
10368
- const [open, setOpen] = React52.useState(false);
10456
+ const [open, setOpen] = React53.useState(false);
10369
10457
  const [anchor, pos] = useHoverCard(open);
10370
10458
  const zIndex = useOverlayLayer(open);
10371
- const close = React52.useRef(null);
10459
+ const close = React53.useRef(null);
10372
10460
  const show = () => {
10373
10461
  if (close.current) {
10374
10462
  clearTimeout(close.current);
@@ -10384,7 +10472,7 @@ function InlineSoon({ label, detail, backend, eta, effort, onRoadmap, allowed, o
10384
10472
  setOpen(false);
10385
10473
  }, 140);
10386
10474
  };
10387
- React52.useEffect(() => () => {
10475
+ React53.useEffect(() => () => {
10388
10476
  if (close.current) clearTimeout(close.current);
10389
10477
  }, []);
10390
10478
  return /* @__PURE__ */ (0, import_jsx_runtime77.jsxs)(
@@ -10555,14 +10643,14 @@ function PermissionHint({ perm, children }) {
10555
10643
  }
10556
10644
 
10557
10645
  // src/components/platform/ModeSwitch.tsx
10558
- var React53 = __toESM(require("react"), 1);
10646
+ var React54 = __toESM(require("react"), 1);
10559
10647
  var import_jsx_runtime79 = require("react/jsx-runtime");
10560
10648
  function ModeSwitch({ canToggle = false, requestCount = 0, onClearLog, renderLog, onOpenSpec, summary }) {
10561
10649
  const mode2 = useRuntimeMode();
10562
- const [open, setOpen] = React53.useState(false);
10650
+ const [open, setOpen] = React54.useState(false);
10563
10651
  const zIndex = useOverlayLayer(open);
10564
- const ref = React53.useRef(null);
10565
- React53.useEffect(() => {
10652
+ const ref = React54.useRef(null);
10653
+ React54.useEffect(() => {
10566
10654
  if (!open) return;
10567
10655
  const away = (e) => {
10568
10656
  if (ref.current && !ref.current.contains(e.target)) setOpen(false);
@@ -10818,7 +10906,7 @@ function SaturationDistribution({ campuses = [], floorBand, floorScore, onSelect
10818
10906
  }
10819
10907
 
10820
10908
  // src/components/planner/MixGap.tsx
10821
- var React54 = __toESM(require("react"), 1);
10909
+ var React55 = __toESM(require("react"), 1);
10822
10910
  var import_jsx_runtime82 = require("react/jsx-runtime");
10823
10911
  var MIX_GAP_LAYOUT = {
10824
10912
  trackHeight: 30,
@@ -10833,7 +10921,7 @@ function mixGapOffset(value, max) {
10833
10921
  }
10834
10922
  function MixGap({ rows = [], loading = false, className = "" }) {
10835
10923
  const max = Math.max(1, ...rows.flatMap((r) => [r.target, r.realized]));
10836
- const [hover, setHover] = React54.useState(null);
10924
+ const [hover, setHover] = React55.useState(null);
10837
10925
  const toneOf = (gap) => gap >= -1 ? "ok" : gap >= -4 ? "warn" : "danger";
10838
10926
  const TONE = { ok: "var(--ok-solid)", warn: "var(--warn-solid)", danger: "var(--danger-solid)" };
10839
10927
  const { trackHeight, barHeight, targetWidth, labelGap } = MIX_GAP_LAYOUT;
@@ -10976,7 +11064,7 @@ function ChannelContribution({
10976
11064
  }
10977
11065
 
10978
11066
  // src/components/planner/BudgetReallocator.tsx
10979
- var React55 = __toESM(require("react"), 1);
11067
+ var React56 = __toESM(require("react"), 1);
10980
11068
  var import_jsx_runtime84 = require("react/jsx-runtime");
10981
11069
  var bandFor = (crp) => crp >= 200 ? "dominant" : crp >= 100 ? "strong" : crp >= 50 ? "adequate" : "weak";
10982
11070
  function BudgetReallocator({
@@ -10992,8 +11080,8 @@ function BudgetReallocator({
10992
11080
  onCancel,
10993
11081
  className = ""
10994
11082
  }) {
10995
- const [draft, setDraft] = React55.useState(spend);
10996
- React55.useEffect(() => setDraft(spend), [spend]);
11083
+ const [draft, setDraft] = React56.useState(spend);
11084
+ React56.useEffect(() => setDraft(spend), [spend]);
10997
11085
  const dirty = draft !== spend;
10998
11086
  const nextCrp = scoreFor ? scoreFor(draft) : crp;
10999
11087
  const nextBand = bandFor(nextCrp);
@@ -11008,10 +11096,10 @@ function BudgetReallocator({
11008
11096
  setDraft(spend);
11009
11097
  if (onCancel) onCancel();
11010
11098
  };
11011
- const trackRef = React55.useRef(null);
11012
- const chipRef = React55.useRef(null);
11013
- const [chipLeft, setChipLeft] = React55.useState(null);
11014
- React55.useLayoutEffect(() => {
11099
+ const trackRef = React56.useRef(null);
11100
+ const chipRef = React56.useRef(null);
11101
+ const [chipLeft, setChipLeft] = React56.useState(null);
11102
+ React56.useLayoutEffect(() => {
11015
11103
  const track = trackRef.current;
11016
11104
  if (!dirty || !track) {
11017
11105
  setChipLeft(null);
@@ -11198,7 +11286,7 @@ function ImportanceTag({ level, showLabel = true, size = "sm", className = "" })
11198
11286
  }
11199
11287
 
11200
11288
  // src/components/planner/PreferenceMeter.tsx
11201
- var React56 = __toESM(require("react"), 1);
11289
+ var React57 = __toESM(require("react"), 1);
11202
11290
  var import_jsx_runtime87 = require("react/jsx-runtime");
11203
11291
  function preferenceScore(criteria) {
11204
11292
  const earned = criteria.reduce((n, c) => n + (Number(c.earned) || 0), 0);
@@ -11228,7 +11316,7 @@ function PreferenceMeter({
11228
11316
  className = ""
11229
11317
  }) {
11230
11318
  const value = score == null ? preferenceScore(criteria) : score;
11231
- const segments = React56.useMemo(() => preferenceSegments(criteria), [criteria]);
11319
+ const segments = React57.useMemo(() => preferenceSegments(criteria), [criteria]);
11232
11320
  return /* @__PURE__ */ (0, import_jsx_runtime87.jsx)(
11233
11321
  ScoreMeter,
11234
11322
  {
@@ -11267,10 +11355,10 @@ function PreferenceMeter({
11267
11355
  }
11268
11356
 
11269
11357
  // src/components/chat/AgentChatPanel.tsx
11270
- var React62 = __toESM(require("react"), 1);
11358
+ var React63 = __toESM(require("react"), 1);
11271
11359
 
11272
11360
  // src/components/chat/chatEngine.ts
11273
- var React57 = __toESM(require("react"), 1);
11361
+ var React58 = __toESM(require("react"), 1);
11274
11362
  var CHAT_UNAVAILABLE = "chat_unavailable";
11275
11363
  var JOB_PENDING = ["queued", "running"];
11276
11364
  var JOB_SUCCESS = ["completed", "recovered"];
@@ -11324,22 +11412,22 @@ function useChatEngine(opts) {
11324
11412
  onClear,
11325
11413
  onFeedback
11326
11414
  } = opts || {};
11327
- const [status, setStatus] = React57.useState("idle");
11328
- const [threadId, setThreadId] = React57.useState(null);
11329
- const [messages, setMessages] = React57.useState([]);
11330
- const [queue, setQueue] = React57.useState([]);
11331
- const [fatal, setFatal] = React57.useState(null);
11332
- const [busy, setBusy] = React57.useState(false);
11333
- const [turnStartedAt, setTurnStartedAt] = React57.useState(null);
11334
- const listRef = React57.useRef([]);
11335
- const queueRef = React57.useRef([]);
11336
- const busyRef = React57.useRef(false);
11337
- const stoppedRef = React57.useRef(false);
11338
- const abortRef = React57.useRef(null);
11339
- const serverCount = React57.useRef(0);
11340
- const threadRef = React57.useRef(null);
11341
- const mounted = React57.useRef(true);
11342
- React57.useEffect(() => {
11415
+ const [status, setStatus] = React58.useState("idle");
11416
+ const [threadId, setThreadId] = React58.useState(null);
11417
+ const [messages, setMessages] = React58.useState([]);
11418
+ const [queue, setQueue] = React58.useState([]);
11419
+ const [fatal, setFatal] = React58.useState(null);
11420
+ const [busy, setBusy] = React58.useState(false);
11421
+ const [turnStartedAt, setTurnStartedAt] = React58.useState(null);
11422
+ const listRef = React58.useRef([]);
11423
+ const queueRef = React58.useRef([]);
11424
+ const busyRef = React58.useRef(false);
11425
+ const stoppedRef = React58.useRef(false);
11426
+ const abortRef = React58.useRef(null);
11427
+ const serverCount = React58.useRef(0);
11428
+ const threadRef = React58.useRef(null);
11429
+ const mounted = React58.useRef(true);
11430
+ React58.useEffect(() => {
11343
11431
  mounted.current = true;
11344
11432
  return () => {
11345
11433
  mounted.current = false;
@@ -11361,14 +11449,14 @@ function useChatEngine(opts) {
11361
11449
  }
11362
11450
  return false;
11363
11451
  };
11364
- const loadThread = React57.useCallback(async (id) => {
11452
+ const loadThread = React58.useCallback(async (id) => {
11365
11453
  const data = await apiAdapter.getThread(id);
11366
11454
  const list = [...data && data.messages || []];
11367
11455
  serverCount.current = list.length;
11368
11456
  commit(list);
11369
11457
  return list;
11370
11458
  }, [apiAdapter]);
11371
- React57.useEffect(() => {
11459
+ React58.useEffect(() => {
11372
11460
  if (!apiAdapter) {
11373
11461
  setStatus("idle");
11374
11462
  setFatal(null);
@@ -11581,7 +11669,7 @@ function useChatEngine(opts) {
11581
11669
  await dispatchTurn(turn);
11582
11670
  }
11583
11671
  }
11584
- const send = React57.useCallback((text, attachments) => {
11672
+ const send = React58.useCallback((text, attachments) => {
11585
11673
  const body = (text || "").trim();
11586
11674
  if (!body && !(attachments && attachments.length)) return;
11587
11675
  if (status === "disconnected") return;
@@ -11591,7 +11679,7 @@ function useChatEngine(opts) {
11591
11679
  stoppedRef.current = false;
11592
11680
  drain();
11593
11681
  }, [status]);
11594
- const stop = React57.useCallback(() => {
11682
+ const stop = React58.useCallback(() => {
11595
11683
  stoppedRef.current = true;
11596
11684
  const ac = abortRef.current;
11597
11685
  if (ac) {
@@ -11610,11 +11698,11 @@ function useChatEngine(opts) {
11610
11698
  store.del(STORAGE_PREFIX + threadRef.current);
11611
11699
  }
11612
11700
  }, [apiAdapter]);
11613
- const removeQueued = React57.useCallback((id) => {
11701
+ const removeQueued = React58.useCallback((id) => {
11614
11702
  queueRef.current = queueRef.current.filter((t) => t.id !== id);
11615
11703
  setQueue(queueRef.current.slice());
11616
11704
  }, []);
11617
- const retry = React57.useCallback(() => {
11705
+ const retry = React58.useCallback(() => {
11618
11706
  const list = listRef.current;
11619
11707
  let at = -1;
11620
11708
  for (let i = list.length - 1; i >= 0; i--) if (list[i].role === "user") {
@@ -11630,19 +11718,19 @@ function useChatEngine(opts) {
11630
11718
  setQueue(queueRef.current.slice());
11631
11719
  drain();
11632
11720
  }, []);
11633
- const clear = React57.useCallback(() => {
11721
+ const clear = React58.useCallback(() => {
11634
11722
  commit([]);
11635
11723
  serverCount.current = 0;
11636
11724
  queueRef.current = [];
11637
11725
  setQueue([]);
11638
11726
  onClear && onClear();
11639
11727
  }, [onClear]);
11640
- const setFeedback = React57.useCallback((id, value) => {
11728
+ const setFeedback = React58.useCallback((id, value) => {
11641
11729
  patch(id, (m) => ({ feedback: m.feedback === value ? null : value }));
11642
11730
  const msg = listRef.current.find((m) => m.id === id);
11643
11731
  onFeedback && onFeedback({ message: msg, feedback: msg ? msg.feedback : value });
11644
11732
  }, [onFeedback]);
11645
- const reload = React57.useCallback(async () => {
11733
+ const reload = React58.useCallback(async () => {
11646
11734
  if (!threadRef.current) return;
11647
11735
  setStatus("loading");
11648
11736
  try {
@@ -11680,10 +11768,10 @@ var ChatKit = {
11680
11768
  };
11681
11769
 
11682
11770
  // src/components/chat/ChatTranscript.tsx
11683
- var React59 = __toESM(require("react"), 1);
11771
+ var React60 = __toESM(require("react"), 1);
11684
11772
 
11685
11773
  // src/components/chat/ChatTurn.tsx
11686
- var React58 = __toESM(require("react"), 1);
11774
+ var React59 = __toESM(require("react"), 1);
11687
11775
  var import_jsx_runtime88 = require("react/jsx-runtime");
11688
11776
  function JsonView({ value }) {
11689
11777
  let text;
@@ -11720,7 +11808,7 @@ function PacketCard({ packet, schema, render, onApply, applied }) {
11720
11808
  ] });
11721
11809
  }
11722
11810
  function ThinkingBlock({ text, durationMs, streaming, defaultOpen = false }) {
11723
- const [open, setOpen] = React58.useState(defaultOpen);
11811
+ const [open, setOpen] = React59.useState(defaultOpen);
11724
11812
  if (!text) return null;
11725
11813
  return /* @__PURE__ */ (0, import_jsx_runtime88.jsxs)("div", { className: "fdc-think" + (open ? " is-open" : ""), children: [
11726
11814
  /* @__PURE__ */ (0, import_jsx_runtime88.jsxs)("button", { type: "button", className: "fdc-think-head", onClick: () => setOpen((v) => !v), "aria-expanded": open, children: [
@@ -11737,7 +11825,7 @@ function ThinkingBlock({ text, durationMs, streaming, defaultOpen = false }) {
11737
11825
  ] });
11738
11826
  }
11739
11827
  function Citations({ items = [], onOpen }) {
11740
- const [open, setOpen] = React58.useState(false);
11828
+ const [open, setOpen] = React59.useState(false);
11741
11829
  if (!items.length) return null;
11742
11830
  return /* @__PURE__ */ (0, import_jsx_runtime88.jsxs)("div", { className: "fdc-cites", children: [
11743
11831
  /* @__PURE__ */ (0, import_jsx_runtime88.jsxs)("button", { type: "button", className: "fdc-cites-head", onClick: () => setOpen((v) => !v), "aria-expanded": open, children: [
@@ -11763,7 +11851,7 @@ function clampText(text, max) {
11763
11851
  return (at > max * 0.6 ? cut.slice(0, at) : cut).trimEnd() + "\u2026";
11764
11852
  }
11765
11853
  function MessageBody({ message: m, ctx }) {
11766
- const [expanded, setExpanded] = React58.useState(false);
11854
+ const [expanded, setExpanded] = React59.useState(false);
11767
11855
  const isUser = m.role === "user";
11768
11856
  const raw = m.text || "";
11769
11857
  const clamped = !expanded && !m.streaming ? clampText(raw, ctx.maxVisibleChars) : null;
@@ -11830,9 +11918,9 @@ function MessageBody({ message: m, ctx }) {
11830
11918
  ] });
11831
11919
  }
11832
11920
  function useCopyRun() {
11833
- const [done, setDone] = React58.useState(false);
11834
- const t = React58.useRef(null);
11835
- React58.useEffect(() => () => {
11921
+ const [done, setDone] = React59.useState(false);
11922
+ const t = React59.useRef(null);
11923
+ React59.useEffect(() => () => {
11836
11924
  if (t.current) clearTimeout(t.current);
11837
11925
  }, []);
11838
11926
  return [done, (text) => {
@@ -11859,7 +11947,7 @@ function RunActions({ group, ctx }) {
11859
11947
  ] }),
11860
11948
  isAssistant && ctx.onRetry ? /* @__PURE__ */ (0, import_jsx_runtime88.jsx)("button", { type: "button", className: "fdc-act", onClick: ctx.onRetry, "aria-label": "Retry this turn", children: /* @__PURE__ */ (0, import_jsx_runtime88.jsx)("i", { className: "ph ph-arrow-clockwise", "aria-hidden": "true" }) }) : null,
11861
11949
  group.role === "user" && ctx.onEdit ? /* @__PURE__ */ (0, import_jsx_runtime88.jsx)("button", { type: "button", className: "fdc-act", onClick: () => ctx.onEdit(last), "aria-label": "Edit and resend", children: /* @__PURE__ */ (0, import_jsx_runtime88.jsx)("i", { className: "ph ph-pencil-simple", "aria-hidden": "true" }) }) : null,
11862
- isAssistant && ctx.onFeedback ? /* @__PURE__ */ (0, import_jsx_runtime88.jsxs)(React58.Fragment, { children: [
11950
+ isAssistant && ctx.onFeedback ? /* @__PURE__ */ (0, import_jsx_runtime88.jsxs)(React59.Fragment, { children: [
11863
11951
  /* @__PURE__ */ (0, import_jsx_runtime88.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_runtime88.jsx)("i", { className: "ph ph-thumbs-up", "aria-hidden": "true" }) }),
11864
11952
  /* @__PURE__ */ (0, import_jsx_runtime88.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_runtime88.jsx)("i", { className: "ph ph-thumbs-down", "aria-hidden": "true" }) })
11865
11953
  ] }) : null,
@@ -11954,10 +12042,10 @@ function ChatTranscript({
11954
12042
  renderEmpty,
11955
12043
  className = ""
11956
12044
  }) {
11957
- const scroller = React59.useRef(null);
11958
- const stick = React59.useRef(true);
11959
- const [pill, setPill] = React59.useState(0);
11960
- const seen = React59.useRef(0);
12045
+ const scroller = React60.useRef(null);
12046
+ const stick = React60.useRef(true);
12047
+ const [pill, setPill] = React60.useState(0);
12048
+ const seen = React60.useRef(0);
11961
12049
  const toBottom = (smooth) => {
11962
12050
  const el = scroller.current;
11963
12051
  if (!el) return;
@@ -11976,7 +12064,7 @@ function ChatTranscript({
11976
12064
  seen.current = messages.length;
11977
12065
  }
11978
12066
  };
11979
- React59.useLayoutEffect(() => {
12067
+ React60.useLayoutEffect(() => {
11980
12068
  const el = scroller.current;
11981
12069
  if (!el) return;
11982
12070
  if (stick.current) {
@@ -11984,7 +12072,7 @@ function ChatTranscript({
11984
12072
  seen.current = messages.length;
11985
12073
  } else setPill(Math.max(0, messages.length - seen.current));
11986
12074
  }, [messages]);
11987
- React59.useEffect(() => {
12075
+ React60.useEffect(() => {
11988
12076
  const el = scroller.current;
11989
12077
  const inner = el && el.firstChild;
11990
12078
  if (!el || !inner || typeof ResizeObserver === "undefined") return;
@@ -11994,7 +12082,7 @@ function ChatTranscript({
11994
12082
  ro.observe(inner);
11995
12083
  return () => ro.disconnect();
11996
12084
  }, []);
11997
- const groups = React59.useMemo(() => groupMessages(messages), [messages]);
12085
+ const groups = React60.useMemo(() => groupMessages(messages), [messages]);
11998
12086
  const empty = !messages.length && status === "ready";
11999
12087
  return /* @__PURE__ */ (0, import_jsx_runtime89.jsxs)("div", { className: ["fdc-scroll", className].filter(Boolean).join(" "), ref: scroller, onScroll, children: [
12000
12088
  /* @__PURE__ */ (0, import_jsx_runtime89.jsxs)("div", { className: "fdc-log", role: "log", "aria-label": "Conversation", children: [
@@ -12018,7 +12106,7 @@ function ChatTranscript({
12018
12106
  const prev = groups[i - 1];
12019
12107
  const k = dayKey(g.messages[0].timestamp);
12020
12108
  const showDay = !!k && (!prev || dayKey(prev.messages[0].timestamp) !== k);
12021
- return /* @__PURE__ */ (0, import_jsx_runtime89.jsxs)(React59.Fragment, { children: [
12109
+ return /* @__PURE__ */ (0, import_jsx_runtime89.jsxs)(React60.Fragment, { children: [
12022
12110
  showDay ? /* @__PURE__ */ (0, import_jsx_runtime89.jsx)("div", { className: "fdc-day", children: /* @__PURE__ */ (0, import_jsx_runtime89.jsx)("span", { children: dayLabel(k) }) }) : null,
12023
12111
  /* @__PURE__ */ (0, import_jsx_runtime89.jsx)(ChatTurn, { group: g, ctx })
12024
12112
  ] }, g.key || i);
@@ -12035,7 +12123,7 @@ function ChatTranscript({
12035
12123
  var TranscriptKit = { groupMessages };
12036
12124
 
12037
12125
  // src/components/chat/ChatComposer.tsx
12038
- var React60 = __toESM(require("react"), 1);
12126
+ var React61 = __toESM(require("react"), 1);
12039
12127
  var import_jsx_runtime90 = require("react/jsx-runtime");
12040
12128
  function ChatComposer({
12041
12129
  onSubmit,
@@ -12063,17 +12151,17 @@ function ChatComposer({
12063
12151
  onReject,
12064
12152
  onOpenAttachment
12065
12153
  }) {
12066
- const [text, setText] = React60.useState(draft || "");
12067
- const [trigger, setTrigger] = React60.useState(null);
12068
- const [mentionItems, setMentionItems] = React60.useState([]);
12069
- const [listening, setListening] = React60.useState(false);
12070
- const [notice, setNotice] = React60.useState(null);
12071
- const editor = React60.useRef(null);
12072
- const wrap = React60.useRef(null);
12073
- const stopVoice = React60.useRef(null);
12154
+ const [text, setText] = React61.useState(draft || "");
12155
+ const [trigger, setTrigger] = React61.useState(null);
12156
+ const [mentionItems, setMentionItems] = React61.useState([]);
12157
+ const [listening, setListening] = React61.useState(false);
12158
+ const [notice, setNotice] = React61.useState(null);
12159
+ const editor = React61.useRef(null);
12160
+ const wrap = React61.useRef(null);
12161
+ const stopVoice = React61.useRef(null);
12074
12162
  const staged = useStagedFiles(fileUploadHandler, { onError: () => {
12075
12163
  } });
12076
- React60.useEffect(() => {
12164
+ React61.useEffect(() => {
12077
12165
  if (draft != null && draft !== text) setText(draft);
12078
12166
  }, [draft]);
12079
12167
  const change = (v) => {
@@ -12109,7 +12197,7 @@ function ChatComposer({
12109
12197
  e.preventDefault();
12110
12198
  staged.add(found.files);
12111
12199
  };
12112
- React60.useEffect(() => {
12200
+ React61.useEffect(() => {
12113
12201
  if (!trigger || trigger.type !== "mention" || !mentionSources) {
12114
12202
  setMentionItems([]);
12115
12203
  return;
@@ -12127,7 +12215,7 @@ function ChatComposer({
12127
12215
  const q = (trigger.query || "").toLowerCase();
12128
12216
  setMentionItems(mentionSources.filter((m) => !q || (m.label + " " + (m.description || "")).toLowerCase().includes(q)));
12129
12217
  }, [trigger, mentionSources]);
12130
- const slashItems = React60.useMemo(() => {
12218
+ const slashItems = React61.useMemo(() => {
12131
12219
  if (!trigger || trigger.type !== "slash" || !slashCommands) return [];
12132
12220
  const q = (trigger.query || "").toLowerCase();
12133
12221
  return slashCommands.filter((c) => !q || (c.id + " " + c.label + " " + (c.description || "")).toLowerCase().includes(q));
@@ -12301,12 +12389,12 @@ function ChatComposer({
12301
12389
  }
12302
12390
 
12303
12391
  // src/components/chat/ChatSessionBar.tsx
12304
- var React61 = __toESM(require("react"), 1);
12392
+ var React62 = __toESM(require("react"), 1);
12305
12393
  var import_jsx_runtime91 = require("react/jsx-runtime");
12306
12394
  var compact2 = meterFormats.compact;
12307
12395
  function ChatSessionBar({ sessionStats, contextUsage, usageLimits, onClear, extras }) {
12308
- const [open, setOpen] = React61.useState(false);
12309
- const anchor = React61.useRef(null);
12396
+ const [open, setOpen] = React62.useState(false);
12397
+ const anchor = React62.useRef(null);
12310
12398
  const stats = sessionStats || null;
12311
12399
  const cu = contextUsage || null;
12312
12400
  const limits = usageLimits || null;
@@ -12321,7 +12409,7 @@ function ChatSessionBar({ sessionStats, contextUsage, usageLimits, onClear, extr
12321
12409
  if (stats && stats.runningTasks) bits.push(stats.runningTasks + " running task" + (stats.runningTasks === 1 ? "" : "s"));
12322
12410
  if (cu) bits.push(pct + "% context");
12323
12411
  const expandable = !!(cu || limits);
12324
- return /* @__PURE__ */ (0, import_jsx_runtime91.jsxs)(React61.Fragment, { children: [
12412
+ return /* @__PURE__ */ (0, import_jsx_runtime91.jsxs)(React62.Fragment, { children: [
12325
12413
  /* @__PURE__ */ (0, import_jsx_runtime91.jsxs)("div", { className: "fdc-bar", children: [
12326
12414
  /* @__PURE__ */ (0, import_jsx_runtime91.jsxs)(
12327
12415
  "button",
@@ -12462,7 +12550,7 @@ function ModelControls({
12462
12550
  ] })
12463
12551
  });
12464
12552
  }
12465
- return /* @__PURE__ */ (0, import_jsx_runtime91.jsxs)(React61.Fragment, { children: [
12553
+ return /* @__PURE__ */ (0, import_jsx_runtime91.jsxs)(React62.Fragment, { children: [
12466
12554
  /* @__PURE__ */ (0, import_jsx_runtime91.jsx)(
12467
12555
  MenuButton,
12468
12556
  {
@@ -12579,11 +12667,11 @@ function AgentChatPanel({
12579
12667
  onFeedback,
12580
12668
  onEditMessage
12581
12669
  }) {
12582
- const [panelWidth, setPanelWidth] = React62.useState(width);
12583
- const [applied, setApplied] = React62.useState({});
12584
- const [draft, setDraft] = React62.useState("");
12585
- const dragging = React62.useRef(null);
12586
- React62.useEffect(() => setPanelWidth(width), [width]);
12670
+ const [panelWidth, setPanelWidth] = React63.useState(width);
12671
+ const [applied, setApplied] = React63.useState({});
12672
+ const [draft, setDraft] = React63.useState("");
12673
+ const dragging = React63.useRef(null);
12674
+ React63.useEffect(() => setPanelWidth(width), [width]);
12587
12675
  const engine = useChatEngine({
12588
12676
  contextType,
12589
12677
  contextId,
@@ -12787,7 +12875,7 @@ function AgentChatPanel({
12787
12875
  }
12788
12876
 
12789
12877
  // src/components/files/FileViewer.tsx
12790
- var React63 = __toESM(require("react"), 1);
12878
+ var React64 = __toESM(require("react"), 1);
12791
12879
  var import_jsx_runtime93 = require("react/jsx-runtime");
12792
12880
  function previewKindOf(file) {
12793
12881
  const mime = (file.mime || "").toLowerCase();
@@ -12844,13 +12932,13 @@ function parseDelimited(text, delimiter) {
12844
12932
  return rows;
12845
12933
  }
12846
12934
  function usePreview(file, kind, resolveUrl) {
12847
- const [state, setState] = React63.useState({ status: "loading" });
12848
- const [attempt, setAttempt] = React63.useState(0);
12849
- const resolveRef = React63.useRef(resolveUrl);
12850
- React63.useEffect(() => {
12935
+ const [state, setState] = React64.useState({ status: "loading" });
12936
+ const [attempt, setAttempt] = React64.useState(0);
12937
+ const resolveRef = React64.useRef(resolveUrl);
12938
+ React64.useEffect(() => {
12851
12939
  resolveRef.current = resolveUrl;
12852
12940
  }, [resolveUrl]);
12853
- React63.useEffect(() => {
12941
+ React64.useEffect(() => {
12854
12942
  if (kind === "none") {
12855
12943
  setState({ status: "ready" });
12856
12944
  return;
@@ -12880,7 +12968,7 @@ function usePreview(file, kind, resolveUrl) {
12880
12968
  if (ac) ac.abort();
12881
12969
  };
12882
12970
  }, [file.id, kind, attempt]);
12883
- return { ...state, retry: React63.useCallback(() => setAttempt((a) => a + 1), []) };
12971
+ return { ...state, retry: React64.useCallback(() => setAttempt((a) => a + 1), []) };
12884
12972
  }
12885
12973
  function PreviewBody({ file, kind, state }) {
12886
12974
  if (kind === "image") return /* @__PURE__ */ (0, import_jsx_runtime93.jsx)("img", { className: "fd-fv-image", src: state.url, alt: file.name || "Preview" });
@@ -12925,13 +13013,13 @@ function PreviewBody({ file, kind, state }) {
12925
13013
  ] });
12926
13014
  }
12927
13015
  function FileViewer({ file, resolveUrl, sidePanel, sidePanelLabel = "Details", onClose, actions, className = "" }) {
12928
- const kind = React63.useMemo(() => previewKindOf(file), [file]);
13016
+ const kind = React64.useMemo(() => previewKindOf(file), [file]);
12929
13017
  const preview = usePreview(file, kind, resolveUrl);
12930
- const [tab, setTab] = React63.useState("preview");
12931
- const [downloading, setDownloading] = React63.useState(false);
12932
- const [downloadError, setDownloadError] = React63.useState(null);
13018
+ const [tab, setTab] = React64.useState("preview");
13019
+ const [downloading, setDownloading] = React64.useState(false);
13020
+ const [downloadError, setDownloadError] = React64.useState(null);
12933
13021
  const hasSide = sidePanel != null;
12934
- React63.useEffect(() => {
13022
+ React64.useEffect(() => {
12935
13023
  setTab("preview");
12936
13024
  }, [file.id]);
12937
13025
  const download = () => {
@@ -12998,7 +13086,7 @@ function FileViewer({ file, resolveUrl, sidePanel, sidePanelLabel = "Details", o
12998
13086
  }
12999
13087
 
13000
13088
  // src/components/files/FileBrowser.tsx
13001
- var React64 = __toESM(require("react"), 1);
13089
+ var React65 = __toESM(require("react"), 1);
13002
13090
  var import_jsx_runtime94 = require("react/jsx-runtime");
13003
13091
  function childrenOf(folders, parentId) {
13004
13092
  return folders.filter((f) => f.parentId === parentId).sort((a, b) => a.name.localeCompare(b.name));
@@ -13069,10 +13157,10 @@ function FolderPickerMenu({
13069
13157
  destinations,
13070
13158
  onPick
13071
13159
  }) {
13072
- const [open, setOpen] = React64.useState(false);
13160
+ const [open, setOpen] = React65.useState(false);
13073
13161
  const zIndex = useOverlayLayer(open);
13074
- const ref = React64.useRef(null);
13075
- React64.useEffect(() => {
13162
+ const ref = React65.useRef(null);
13163
+ React65.useEffect(() => {
13076
13164
  if (!open) return;
13077
13165
  const away = (e) => {
13078
13166
  if (ref.current && !ref.current.contains(e.target)) setOpen(false);
@@ -13124,8 +13212,8 @@ function FolderPickerMenu({
13124
13212
  ] });
13125
13213
  }
13126
13214
  function RowShell({ icon, name, meta, onOpen, draggableId, isDropTarget, onDropPayload, actions, className = "" }) {
13127
- const [over, setOver] = React64.useState(false);
13128
- const dragCounter = React64.useRef(0);
13215
+ const [over, setOver] = React65.useState(false);
13216
+ const dragCounter = React65.useRef(0);
13129
13217
  const dropHandlers = isDropTarget ? {
13130
13218
  onDragEnter: (e) => {
13131
13219
  if (!hasInternalPayload(e)) return;
@@ -13173,8 +13261,8 @@ function RowShell({ icon, name, meta, onOpen, draggableId, isDropTarget, onDropP
13173
13261
  }
13174
13262
  function TreeNode({ folder, depth, folders, currentFolderId, onNavigate, onMoveInto, canMove }) {
13175
13263
  const kids = childrenOf(folders, folder.id);
13176
- const [expanded, setExpanded] = React64.useState(() => currentFolderId != null && isSelfOrDescendant(folders, folder.id, currentFolderId));
13177
- React64.useEffect(() => {
13264
+ const [expanded, setExpanded] = React65.useState(() => currentFolderId != null && isSelfOrDescendant(folders, folder.id, currentFolderId));
13265
+ React65.useEffect(() => {
13178
13266
  if (currentFolderId != null && isSelfOrDescendant(folders, folder.id, currentFolderId)) setExpanded(true);
13179
13267
  }, [currentFolderId, folder.id, folders]);
13180
13268
  const isCurrent = folder.id === currentFolderId;
@@ -13240,15 +13328,15 @@ function FileBrowser({
13240
13328
  const canUpload = perm.canUpload !== false && !!onUpload;
13241
13329
  const canRemoveFile = perm.canRemoveFile !== false && !!onRemoveFile;
13242
13330
  const canDeleteFolder = perm.canDeleteFolder !== false && !!onDeleteFolder;
13243
- const [createOpen, setCreateOpen] = React64.useState(false);
13244
- const [createName, setCreateName] = React64.useState("");
13245
- const [renameTarget, setRenameTarget] = React64.useState(null);
13246
- const [renameValue, setRenameValue] = React64.useState("");
13247
- const [deleteTarget, setDeleteTarget] = React64.useState(null);
13248
- const uploadInputRef = React64.useRef(null);
13249
- const crumbFolders = React64.useMemo(() => ancestorsOf(folders, currentFolderId), [folders, currentFolderId]);
13250
- const subfolders = React64.useMemo(() => childrenOf(folders, currentFolderId), [folders, currentFolderId]);
13251
- const currentFiles = React64.useMemo(
13331
+ const [createOpen, setCreateOpen] = React65.useState(false);
13332
+ const [createName, setCreateName] = React65.useState("");
13333
+ const [renameTarget, setRenameTarget] = React65.useState(null);
13334
+ const [renameValue, setRenameValue] = React65.useState("");
13335
+ const [deleteTarget, setDeleteTarget] = React65.useState(null);
13336
+ const uploadInputRef = React65.useRef(null);
13337
+ const crumbFolders = React65.useMemo(() => ancestorsOf(folders, currentFolderId), [folders, currentFolderId]);
13338
+ const subfolders = React65.useMemo(() => childrenOf(folders, currentFolderId), [folders, currentFolderId]);
13339
+ const currentFiles = React65.useMemo(
13252
13340
  () => files.filter((f) => f.folderId === currentFolderId).sort((a, b) => a.name.localeCompare(b.name)),
13253
13341
  [files, currentFolderId]
13254
13342
  );
@@ -13480,8 +13568,8 @@ function BreadcrumbCrumb({
13480
13568
  isDropTarget,
13481
13569
  onDropPayload
13482
13570
  }) {
13483
- const [over, setOver] = React64.useState(false);
13484
- const dragCounter = React64.useRef(0);
13571
+ const [over, setOver] = React65.useState(false);
13572
+ const dragCounter = React65.useRef(0);
13485
13573
  const dropHandlers = isDropTarget ? {
13486
13574
  onDragEnter: (e) => {
13487
13575
  if (!hasInternalPayload(e)) return;
@@ -13510,7 +13598,7 @@ function BreadcrumbCrumb({
13510
13598
  }
13511
13599
 
13512
13600
  // src/kits/query.ts
13513
- var React65 = __toESM(require("react"), 1);
13601
+ var React66 = __toESM(require("react"), 1);
13514
13602
  var isMultiSelectShaped = (v) => !!v && typeof v === "object" && Array.isArray(v.values);
13515
13603
  var isRangeShaped = (v) => !!v && typeof v === "object" && ("min" in v || "max" in v);
13516
13604
  var isDateShaped = (v) => !!v && typeof v === "object" && "kind" in v;
@@ -13565,22 +13653,22 @@ function compare(a, b, dir) {
13565
13653
  var API = null;
13566
13654
  var PREFS = null;
13567
13655
  function useServerTable({ endpoint, params, defaults, deps, prefsKey }) {
13568
- const [query, setQuery] = React65.useState(() => {
13656
+ const [query, setQuery] = React66.useState(() => {
13569
13657
  const store = PREFS || window.PlannerPrefs;
13570
13658
  const saved = prefsKey && store ? store.getTable(prefsKey) : {};
13571
13659
  return { ...DEFAULTS, ...defaults || {}, ...saved.pageSize ? { pageSize: saved.pageSize } : {}, ...saved.sort ? { sort: saved.sort, dir: saved.dir || "desc" } : {} };
13572
13660
  });
13573
- const savePref = React65.useCallback((patch2) => {
13661
+ const savePref = React66.useCallback((patch2) => {
13574
13662
  const store = PREFS || window.PlannerPrefs;
13575
13663
  if (prefsKey && store) store.setTable(prefsKey, patch2);
13576
13664
  }, [prefsKey]);
13577
- const [res, setRes] = React65.useState(null);
13578
- const [loading, setLoading] = React65.useState(true);
13579
- const seq2 = React65.useRef(0);
13665
+ const [res, setRes] = React66.useState(null);
13666
+ const [loading, setLoading] = React66.useState(true);
13667
+ const seq2 = React66.useRef(0);
13580
13668
  const depKey = (deps || []).join("|");
13581
13669
  const paramKey = JSON.stringify(params || {});
13582
13670
  const queryKey = JSON.stringify(query);
13583
- React65.useEffect(() => {
13671
+ React66.useEffect(() => {
13584
13672
  const id = ++seq2.current;
13585
13673
  setLoading(true);
13586
13674
  const t = setTimeout(() => {
@@ -13899,12 +13987,12 @@ function createVersionStore(initialState, options) {
13899
13987
  }
13900
13988
 
13901
13989
  // src/kits/documentTitle.ts
13902
- var React66 = __toESM(require("react"), 1);
13990
+ var React67 = __toESM(require("react"), 1);
13903
13991
  function formatDocumentTitle(routeTitle, appName) {
13904
13992
  return [routeTitle, appName, "Flytedesk"].filter((part) => !!part && part.length > 0).join(" \xB7 ");
13905
13993
  }
13906
13994
  function useDocumentTitle(routeTitle, appName) {
13907
- React66.useEffect(() => {
13995
+ React67.useEffect(() => {
13908
13996
  if (typeof document === "undefined") return;
13909
13997
  document.title = formatDocumentTitle(routeTitle, appName);
13910
13998
  }, [routeTitle, appName]);