@flytedan/flytebot-design-system 0.32.0 → 0.34.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;
@@ -3217,7 +3224,8 @@ function NumberInput({
3217
3224
  )
3218
3225
  ] })
3219
3226
  ] }),
3220
- shownError ? /* @__PURE__ */ (0, import_jsx_runtime42.jsxs)("span", { id: errorId, className: "fd-field-error", children: [
3227
+ /* @__PURE__ */ (0, import_jsx_runtime42.jsx)("span", { id: errorId, className: "fd-sr", role: "status", children: shownError ?? "" }),
3228
+ shownError ? /* @__PURE__ */ (0, import_jsx_runtime42.jsxs)("span", { className: "fd-field-error", "aria-hidden": "true", children: [
3221
3229
  /* @__PURE__ */ (0, import_jsx_runtime42.jsx)("i", { className: "ph ph-warning-circle", "aria-hidden": "true" }),
3222
3230
  shownError
3223
3231
  ] }) : help ? /* @__PURE__ */ (0, import_jsx_runtime42.jsx)("span", { className: "fd-field-help", children: help }) : null
@@ -3225,7 +3233,7 @@ function NumberInput({
3225
3233
  }
3226
3234
 
3227
3235
  // src/components/forms/DatePicker.tsx
3228
- var React22 = __toESM(require("react"), 1);
3236
+ var React23 = __toESM(require("react"), 1);
3229
3237
  var import_jsx_runtime43 = require("react/jsx-runtime");
3230
3238
  var MONTHS = ["January", "February", "March", "April", "May", "June", "July", "August", "September", "October", "November", "December"];
3231
3239
  var DOW = ["Su", "Mo", "Tu", "We", "Th", "Fr", "Sa"];
@@ -3243,10 +3251,10 @@ function Calendar({ value, range = false, onPick, initialMonth, months = 1 }) {
3243
3251
  const today = /* @__PURE__ */ new Date();
3244
3252
  const sel = range ? value || {} : { start: value, end: value };
3245
3253
  const anchor = parse(sel.start) || parse(initialMonth) || today;
3246
- const [vy, setVy] = React22.useState(anchor.getFullYear());
3247
- const [vm, setVm] = React22.useState(anchor.getMonth());
3248
- const [mode2, setMode] = React22.useState("days");
3249
- 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);
3250
3258
  const s = parse(sel.start), e = parse(sel.end);
3251
3259
  const hoverEnd = range && s && !e && hover ? parse(hover) : null;
3252
3260
  const inRange = (d) => {
@@ -3362,9 +3370,9 @@ function Calendar({ value, range = false, onPick, initialMonth, months = 1 }) {
3362
3370
  }
3363
3371
  function DatePicker({ label, help, error, required = false, disabled = false, range = false, value, onChange, placeholder, id, className = "", style, ...rest }) {
3364
3372
  const { fieldId, labelId, ariaLabelledBy } = useTriggerLabelling(label, id);
3365
- const [open, setOpen] = React22.useState(false);
3366
- const rootRef = React22.useRef(null);
3367
- const boxRef = React22.useRef(null);
3373
+ const [open, setOpen] = React23.useState(false);
3374
+ const rootRef = React23.useRef(null);
3375
+ const boxRef = React23.useRef(null);
3368
3376
  const display = range ? value && value.start ? fmt(value.start) + (value.end ? " \u2192 " + fmt(value.end) : " \u2192 \u2026") : "" : fmt(value);
3369
3377
  const toggle = () => {
3370
3378
  if (!disabled) setOpen(!open);
@@ -3442,9 +3450,9 @@ function Textarea({ label, help, error, required = false, rows = 4, disabled = f
3442
3450
  }
3443
3451
 
3444
3452
  // src/components/forms/listbox.ts
3445
- var React23 = __toESM(require("react"), 1);
3453
+ var React24 = __toESM(require("react"), 1);
3446
3454
  function useListboxNav({ count, onSelect }) {
3447
- const [active, setActive] = React23.useState(-1);
3455
+ const [active, setActive] = React24.useState(-1);
3448
3456
  return {
3449
3457
  active,
3450
3458
  setActive,
@@ -3457,7 +3465,7 @@ function useListboxNav({ count, onSelect }) {
3457
3465
  };
3458
3466
  }
3459
3467
  function useListboxScrollIntoView(active, listRef, enabled) {
3460
- React23.useEffect(() => {
3468
+ React24.useEffect(() => {
3461
3469
  if (!enabled || active < 0 || !listRef.current) return;
3462
3470
  const list = listRef.current;
3463
3471
  const el = list.querySelector('[data-i="' + active + '"]');
@@ -3644,42 +3652,40 @@ function MultiSelectPanel({
3644
3652
  onClose
3645
3653
  }) {
3646
3654
  const allowedOps = operatorsFor(field);
3647
- const [draftOperator, setDraftOperator] = React24.useState(value?.operator ?? allowedOps[0]);
3655
+ const [draftOperator, setDraftOperator] = React25.useState(value?.operator ?? allowedOps[0]);
3648
3656
  const operator = allowedOps.length === 1 ? allowedOps[0] : value?.operator ?? draftOperator;
3649
3657
  const selected = value?.values ?? [];
3650
- const selectedRef = React24.useRef(selected);
3651
- selectedRef.current = selected;
3652
- const operatorRef = React24.useRef(operator);
3653
- operatorRef.current = operator;
3654
- const mountedRef = React24.useRef(true);
3655
- React24.useEffect(() => {
3658
+ const selectedRef = useLatest(selected);
3659
+ const operatorRef = useLatest(operator);
3660
+ const mountedRef = React25.useRef(true);
3661
+ React25.useEffect(() => {
3656
3662
  mountedRef.current = true;
3657
3663
  return () => {
3658
3664
  mountedRef.current = false;
3659
3665
  };
3660
3666
  }, []);
3661
- const commit = (nextValues, nextOperator = operator) => {
3662
- onCommit({ operator: nextOperator, values: nextValues });
3667
+ const commit = (nextValues, nextOperator = operatorRef.current) => {
3668
+ setDraftOperator(nextOperator);
3669
+ return onCommit({ operator: nextOperator, values: nextValues });
3663
3670
  };
3664
3671
  const setOperator = (op) => {
3665
- setDraftOperator(op);
3666
3672
  if (selectedRef.current.length > 0) commit(selectedRef.current, op);
3673
+ else setDraftOperator(op);
3667
3674
  };
3668
- const [mode2, setMode] = React24.useState("search");
3669
- const [query, setQuery] = React24.useState("");
3670
- const [asyncState, setAsyncState] = React24.useState(
3675
+ const [mode2, setMode] = React25.useState("search");
3676
+ const [query, setQuery] = React25.useState("");
3677
+ const [asyncState, setAsyncState] = React25.useState(
3671
3678
  { options: null, loading: !!field.loadOptions, error: false }
3672
3679
  );
3673
- const [retryTick, setRetryTick] = React24.useState(0);
3674
- const inputRef = React24.useRef(null);
3675
- const listRef = React24.useRef(null);
3676
- const listId = React24.useId();
3677
- const loadOptionsRef = React24.useRef(field.loadOptions);
3678
- loadOptionsRef.current = field.loadOptions;
3679
- 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(() => {
3680
3686
  inputRef.current?.focus();
3681
3687
  }, []);
3682
- React24.useEffect(() => {
3688
+ React25.useEffect(() => {
3683
3689
  const load = loadOptionsRef.current;
3684
3690
  if (!load) return;
3685
3691
  const controller = new AbortController();
@@ -3697,7 +3703,7 @@ function MultiSelectPanel({
3697
3703
  clearTimeout(t);
3698
3704
  controller.abort();
3699
3705
  };
3700
- }, [query, retryTick]);
3706
+ }, [query, retryTick, loadOptionsRef]);
3701
3707
  const options = field.loadOptions ? asyncState.options ?? [] : (field.options ?? []).filter((o) => o.label.toLowerCase().includes(query.toLowerCase()));
3702
3708
  const showLoading = !!field.loadOptions && asyncState.loading;
3703
3709
  const showError = !!field.loadOptions && asyncState.error;
@@ -3712,17 +3718,17 @@ function MultiSelectPanel({
3712
3718
  };
3713
3719
  const nav = useListboxNav({ count: options.length, onSelect: (i) => toggle(options[i]) });
3714
3720
  useListboxScrollIntoView(nav.active, listRef, hasListbox);
3715
- React24.useEffect(() => {
3721
+ React25.useEffect(() => {
3716
3722
  nav.setActive(0);
3717
3723
  }, [query, options.length]);
3718
3724
  const activeId = hasListbox && options[nav.active] ? listId + "-opt-" + nav.active : void 0;
3719
3725
  const liveMessage = showLoading ? "Loading\u2026" : showError ? "Couldn't load options." : options.length === 0 ? "No matches" : atLimit ? "Limit reached: at most " + field.maxValues + " values" : "";
3720
- const [pasteText, setPasteText] = React24.useState("");
3721
- const [pasteLoading, setPasteLoading] = React24.useState(false);
3722
- const [unmatchedTokens, setUnmatchedTokens] = React24.useState([]);
3723
- const [pasteError, setPasteError] = React24.useState(null);
3724
- const pasteWrapRef = React24.useRef(null);
3725
- 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
+ React25.useEffect(() => {
3726
3732
  if (mode2 === "paste") pasteWrapRef.current?.querySelector("textarea")?.focus();
3727
3733
  }, [mode2]);
3728
3734
  const doResolve = () => {
@@ -3741,7 +3747,11 @@ function MultiSelectPanel({
3741
3747
  setPasteError("This filter allows at most " + field.maxValues + " values; adding this list would make " + merged.size + ".");
3742
3748
  return;
3743
3749
  }
3744
- commit(Array.from(merged.values()), operatorRef.current);
3750
+ const applied = commit(Array.from(merged.values()));
3751
+ if (!applied.ok) {
3752
+ setPasteError(applied.reason);
3753
+ return;
3754
+ }
3745
3755
  setPasteText("");
3746
3756
  }, (err) => {
3747
3757
  if (!mountedRef.current) return;
@@ -3878,6 +3888,59 @@ function MultiSelectPanel({
3878
3888
  }
3879
3889
  );
3880
3890
  }
3891
+ function useTextValidity(onFlip) {
3892
+ const invalidRef = React25.useRef(/* @__PURE__ */ new Set());
3893
+ const [, rerender] = React25.useReducer((n) => n + 1, 0);
3894
+ const onFlipRef = useLatest(onFlip);
3895
+ const record = (name, valid) => {
3896
+ const invalid = invalidRef.current;
3897
+ if (valid !== invalid.has(name)) return false;
3898
+ if (valid) invalid.delete(name);
3899
+ else invalid.add(name);
3900
+ rerender();
3901
+ return true;
3902
+ };
3903
+ return {
3904
+ allValid: () => invalidRef.current.size === 0,
3905
+ report: (name) => (valid) => {
3906
+ if (record(name, valid)) onFlipRef.current();
3907
+ },
3908
+ /** For an input that is about to unmount: it has nothing left to show. */
3909
+ forget: (name) => {
3910
+ record(name, true);
3911
+ },
3912
+ /** For a panel that is about to remount every input: each reports afresh on mount. */
3913
+ reset: () => {
3914
+ if (invalidRef.current.size === 0) return;
3915
+ invalidRef.current.clear();
3916
+ rerender();
3917
+ }
3918
+ };
3919
+ }
3920
+ function applicable(field, candidate, textValid) {
3921
+ if (!textValid || candidate === void 0) return void 0;
3922
+ return validateFilterValue(field, candidate).ok ? candidate : void 0;
3923
+ }
3924
+ function sameValue(a, b) {
3925
+ if (a === b) return true;
3926
+ if (typeof a !== "object" || typeof b !== "object" || a === null || b === null) return false;
3927
+ if (Array.isArray(a) !== Array.isArray(b)) return false;
3928
+ const left = a;
3929
+ const right = b;
3930
+ for (const key of /* @__PURE__ */ new Set([...Object.keys(left), ...Object.keys(right)])) {
3931
+ if (!sameValue(left[key], right[key])) return false;
3932
+ }
3933
+ return true;
3934
+ }
3935
+ function useReseedFromProps(value, applies, reseed) {
3936
+ const seen = React25.useRef(value);
3937
+ React25.useLayoutEffect(() => {
3938
+ if (seen.current === value) return;
3939
+ seen.current = value;
3940
+ if (!sameValue(value, applies())) reseed(value);
3941
+ }, [value, applies, reseed]);
3942
+ }
3943
+ var rangeDraft = (value) => ({ min: value?.min, max: value?.max });
3881
3944
  function RangePanel({
3882
3945
  field,
3883
3946
  value,
@@ -3885,21 +3948,34 @@ function RangePanel({
3885
3948
  onCommit,
3886
3949
  onClose
3887
3950
  }) {
3888
- const [draft, setDraft] = React24.useState({ min: value?.min, max: value?.max });
3889
- const draftRef = React24.useRef(draft);
3890
- const [minTextValid, setMinTextValid] = React24.useState(true);
3891
- const [maxTextValid, setMaxTextValid] = React24.useState(true);
3951
+ const [draft, setDraft] = React25.useState(() => rangeDraft(value));
3952
+ const [seed, setSeed] = React25.useState(0);
3953
+ const draftRef = React25.useRef(draft);
3954
+ const shown = () => {
3955
+ const { min, max } = draftRef.current;
3956
+ return applicable(field, min == null && max == null ? void 0 : { min, max }, validity.allValid());
3957
+ };
3958
+ const publish = () => {
3959
+ onCommit(shown());
3960
+ };
3961
+ const validity = useTextValidity(publish);
3962
+ useReseedFromProps(value, shown, (next) => {
3963
+ draftRef.current = rangeDraft(next);
3964
+ setDraft(draftRef.current);
3965
+ validity.reset();
3966
+ setSeed((n) => n + 1);
3967
+ });
3892
3968
  const draftMin = draft.min;
3893
3969
  const draftMax = draft.max;
3894
3970
  const isEmpty = draftMin == null && draftMax == null;
3895
3971
  const validation = isEmpty ? { ok: true } : validateFilterValue(field, { min: draftMin, max: draftMax });
3896
3972
  const comboError = !isEmpty && !validation.ok ? validation.reason : void 0;
3897
- const doneDisabled = !minTextValid || !maxTextValid || !!comboError;
3973
+ const doneDisabled = !validity.allValid() || !!comboError;
3898
3974
  const apply = (patch) => {
3899
3975
  const next = { ...draftRef.current, ...patch };
3900
3976
  draftRef.current = next;
3901
3977
  setDraft(next);
3902
- onCommit(next.min == null && next.max == null ? void 0 : next);
3978
+ publish();
3903
3979
  };
3904
3980
  return /* @__PURE__ */ (0, import_jsx_runtime45.jsx)(
3905
3981
  Popover,
@@ -3924,8 +4000,9 @@ function RangePanel({
3924
4000
  integer: field.integer,
3925
4001
  placeholder: field.minPlaceholder,
3926
4002
  onChange: (e) => apply({ min: e.target.value }),
3927
- onValidityChange: setMinTextValid
3928
- }
4003
+ onValidityChange: validity.report("min")
4004
+ },
4005
+ "min-" + seed
3929
4006
  ),
3930
4007
  /* @__PURE__ */ (0, import_jsx_runtime45.jsx)(
3931
4008
  NumberInput,
@@ -3939,13 +4016,21 @@ function RangePanel({
3939
4016
  error: comboError,
3940
4017
  placeholder: field.maxPlaceholder,
3941
4018
  onChange: (e) => apply({ max: e.target.value }),
3942
- onValidityChange: setMaxTextValid
3943
- }
4019
+ onValidityChange: validity.report("max")
4020
+ },
4021
+ "max-" + seed
3944
4022
  )
3945
4023
  ] })
3946
4024
  }
3947
4025
  );
3948
4026
  }
4027
+ function dateDraft(field, value) {
4028
+ return {
4029
+ kind: value?.kind ?? "withinDays",
4030
+ days: value?.kind === "withinDays" ? value.days : field.defaultDays ?? 30,
4031
+ between: value?.kind === "between" ? { from: value.from, to: value.to } : { from: "", to: "" }
4032
+ };
4033
+ }
3949
4034
  function DatePanel({
3950
4035
  field,
3951
4036
  value,
@@ -3953,36 +4038,69 @@ function DatePanel({
3953
4038
  onCommit,
3954
4039
  onClose
3955
4040
  }) {
3956
- const defaultDays = field.defaultDays ?? 30;
3957
4041
  const maxDays = effectiveMaxDays(field);
3958
- const [daysTextValid, setDaysTextValid] = React24.useState(true);
3959
- const [kind, setKind] = React24.useState(value?.kind ?? "withinDays");
3960
- const [daysDraft, setDaysDraft] = React24.useState(
3961
- value?.kind === "withinDays" ? value.days : defaultDays
3962
- );
3963
- const [between, setBetween] = React24.useState(
3964
- value?.kind === "between" ? { from: value.from, to: value.to } : { from: "", to: "" }
3965
- );
4042
+ const [initial] = React25.useState(() => dateDraft(field, value));
4043
+ const [kind, setKind] = React25.useState(initial.kind);
4044
+ const [daysDraft, setDaysDraft] = React25.useState(initial.days);
4045
+ const daysRef = React25.useRef(daysDraft);
4046
+ const daysConfirmed = React25.useRef(value?.kind === "withinDays");
4047
+ const [between, setBetween] = React25.useState(initial.between);
4048
+ const [seed, setSeed] = React25.useState(0);
4049
+ const shownWithinDays = () => {
4050
+ const days = daysRef.current;
4051
+ return applicable(field, days == null ? void 0 : { kind: "withinDays", days }, validity.allValid());
4052
+ };
4053
+ const validity = useTextValidity(() => {
4054
+ daysConfirmed.current = true;
4055
+ onCommit(shownWithinDays());
4056
+ });
4057
+ const applies = () => {
4058
+ if (kind === "between") {
4059
+ return applicable(field, between.from && between.to ? { kind: "between", ...between } : void 0, true);
4060
+ }
4061
+ return daysConfirmed.current ? shownWithinDays() : void 0;
4062
+ };
4063
+ useReseedFromProps(value, applies, (next) => {
4064
+ const d = dateDraft(field, next);
4065
+ setKind(d.kind);
4066
+ daysRef.current = d.days;
4067
+ daysConfirmed.current = next?.kind === "withinDays";
4068
+ setDaysDraft(d.days);
4069
+ setBetween(d.between);
4070
+ validity.reset();
4071
+ setSeed((n) => n + 1);
4072
+ });
3966
4073
  const applyWithinDays = (days) => {
4074
+ daysRef.current = days;
4075
+ daysConfirmed.current = true;
3967
4076
  setDaysDraft(days);
3968
- onCommit(days == null ? void 0 : { kind: "withinDays", days });
4077
+ onCommit(shownWithinDays());
3969
4078
  };
3970
4079
  const applyBetween = (from, to) => {
3971
4080
  setBetween({ from, to });
3972
- onCommit(from && to ? { kind: "between", from, to } : void 0);
4081
+ onCommit(applicable(field, from && to ? { kind: "between", from, to } : void 0, true));
3973
4082
  };
3974
4083
  const switchKind = (next) => {
3975
4084
  if (next === kind) return;
3976
4085
  setKind(next);
3977
- if (next === "between") setBetween({ from: "", to: "" });
3978
- else setDaysDraft(defaultDays);
3979
- setDaysTextValid(true);
4086
+ if (next === "between") {
4087
+ setBetween({ from: "", to: "" });
4088
+ validity.forget("days");
4089
+ } else {
4090
+ const { days } = dateDraft(field, void 0);
4091
+ daysRef.current = days;
4092
+ daysConfirmed.current = false;
4093
+ setDaysDraft(days);
4094
+ }
3980
4095
  onCommit(void 0);
3981
4096
  };
3982
- const doneDisabled = kind === "withinDays" && !daysTextValid;
4097
+ const doneDisabled = kind === "withinDays" && !validity.allValid();
3983
4098
  const confirm = () => {
3984
4099
  if (doneDisabled) return;
3985
- if (kind === "withinDays" && daysDraft != null) onCommit({ kind: "withinDays", days: daysDraft });
4100
+ if (kind === "withinDays") {
4101
+ const shown = shownWithinDays();
4102
+ if (shown) onCommit(shown);
4103
+ }
3986
4104
  onClose();
3987
4105
  };
3988
4106
  return /* @__PURE__ */ (0, import_jsx_runtime45.jsx)(
@@ -4019,8 +4137,9 @@ function DatePanel({
4019
4137
  integer: true,
4020
4138
  value: daysDraft ?? "",
4021
4139
  onChange: (e) => applyWithinDays(e.target.value),
4022
- onValidityChange: setDaysTextValid
4023
- }
4140
+ onValidityChange: validity.report("days")
4141
+ },
4142
+ "days-" + seed
4024
4143
  ) : /* @__PURE__ */ (0, import_jsx_runtime45.jsx)(
4025
4144
  DatePicker,
4026
4145
  {
@@ -4028,23 +4147,23 @@ function DatePanel({
4028
4147
  label: "Date range",
4029
4148
  value: { start: between.from, end: between.to },
4030
4149
  onChange: (e) => applyBetween(e.target.value.start || "", e.target.value.end || "")
4031
- }
4150
+ },
4151
+ "between-" + seed
4032
4152
  )
4033
4153
  ] })
4034
4154
  }
4035
4155
  );
4036
4156
  }
4037
4157
  function FilterBar({ fields = [], filters, onFilterChange, onFilterRemove, align = "left", className = "", ...rest }) {
4038
- const [panel, setPanel] = React24.useState(null);
4039
- const editAnchorRef = React24.useRef(null);
4040
- const addAnchorRef = React24.useRef(null);
4041
- const textInputRef = React24.useRef(null);
4042
- const optionsRef = React24.useRef(null);
4158
+ const [panel, setPanel] = React25.useState(null);
4159
+ const editAnchorRef = React25.useRef(null);
4160
+ const addAnchorRef = React25.useRef(null);
4161
+ const textInputRef = React25.useRef(null);
4162
+ const optionsRef = React25.useRef(null);
4043
4163
  if (process.env.NODE_ENV !== "production") {
4044
4164
  for (const f of fields) assertValidFieldDefinition(f);
4045
4165
  }
4046
- const latest = React24.useRef({ fields, filters, onFilterChange, onFilterRemove });
4047
- latest.current = { fields, filters, onFilterChange, onFilterRemove };
4166
+ const latest = useLatest({ fields, filters, onFilterChange, onFilterRemove });
4048
4167
  const commit = (field, candidate) => {
4049
4168
  const current2 = latest.current.fields.find((f) => f.key === field.key);
4050
4169
  if (!current2) return { ok: false, reason: "This filter is no longer available" };
@@ -4053,24 +4172,17 @@ function FilterBar({ fields = [], filters, onFilterChange, onFilterRemove, align
4053
4172
  return { ok: true };
4054
4173
  }
4055
4174
  const result = validateFilterValue(current2, candidate);
4056
- if (result.ok) {
4057
- latest.current.filters = { ...latest.current.filters, [current2.key]: candidate };
4058
- latest.current.onFilterChange(current2.key, candidate);
4059
- }
4175
+ if (result.ok) latest.current.onFilterChange(current2.key, candidate);
4060
4176
  return result;
4061
4177
  };
4062
4178
  const removeField = (field) => {
4063
4179
  const { filters: now, onFilterRemove: remove } = latest.current;
4064
- if (!isFieldSet(field, now[field.key])) return;
4065
- const next = { ...now };
4066
- delete next[field.key];
4067
- latest.current.filters = next;
4068
- remove(field.key);
4180
+ if (isFieldSet(field, now[field.key])) remove(field.key);
4069
4181
  };
4070
4182
  const editingField = panel && panel.kind === "edit" ? fields.find((f) => f.key === panel.key) : void 0;
4071
4183
  const startEditing = (key) => setPanel({ kind: "edit", key });
4072
4184
  const closeEditing = () => setPanel(null);
4073
- React24.useEffect(() => {
4185
+ React25.useEffect(() => {
4074
4186
  if (!panel || panel.kind !== "edit") return;
4075
4187
  if (editingField?.type === "text") {
4076
4188
  textInputRef.current?.focus();
@@ -4276,7 +4388,7 @@ function StatTile({ label, value, sub, delta, invert = false, loading = false, c
4276
4388
  }
4277
4389
 
4278
4390
  // src/components/data/CodeBlock.tsx
4279
- var React25 = __toESM(require("react"), 1);
4391
+ var React26 = __toESM(require("react"), 1);
4280
4392
  var import_jsx_runtime47 = require("react/jsx-runtime");
4281
4393
  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)$/;
4282
4394
  var RULES = {
@@ -4432,13 +4544,13 @@ function tokenize(src, lang) {
4432
4544
  return out;
4433
4545
  }
4434
4546
  function Highlighted({ code, lang }) {
4435
- const toks = React25.useMemo(() => tokenize(code, lang), [code, lang]);
4547
+ const toks = React26.useMemo(() => tokenize(code, lang), [code, lang]);
4436
4548
  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) });
4437
4549
  }
4438
4550
  function useCopy() {
4439
- const [done, setDone] = React25.useState(false);
4440
- const timer = React25.useRef(null);
4441
- React25.useEffect(() => () => {
4551
+ const [done, setDone] = React26.useState(false);
4552
+ const timer = React26.useRef(null);
4553
+ React26.useEffect(() => () => {
4442
4554
  if (timer.current) clearTimeout(timer.current);
4443
4555
  }, []);
4444
4556
  const copy = (text) => {
@@ -4474,8 +4586,8 @@ function CodeBlock({
4474
4586
  actions,
4475
4587
  className = ""
4476
4588
  }) {
4477
- const [wrap, setWrap] = React25.useState(!!wrapDefault);
4478
- const [open, setOpen] = React25.useState(false);
4589
+ const [wrap, setWrap] = React26.useState(!!wrapDefault);
4590
+ const [open, setOpen] = React26.useState(false);
4479
4591
  const [copied, copy] = useCopy();
4480
4592
  const body = String(code).replace(/\n$/, "");
4481
4593
  const lines = body.split("\n");
@@ -4504,7 +4616,7 @@ function CodeBlock({
4504
4616
  ] });
4505
4617
  }
4506
4618
  function DiffBlock({ diff = "", filename, collapseAfter = 34, className = "" }) {
4507
- const [open, setOpen] = React25.useState(false);
4619
+ const [open, setOpen] = React26.useState(false);
4508
4620
  const [copied, copy] = useCopy();
4509
4621
  const raw = String(diff).replace(/\n$/, "");
4510
4622
  const all = raw.split("\n").map((line) => {
@@ -4550,7 +4662,7 @@ function DiffBlock({ diff = "", filename, collapseAfter = 34, className = "" })
4550
4662
  }
4551
4663
 
4552
4664
  // src/components/data/Markdown.tsx
4553
- var React26 = __toESM(require("react"), 1);
4665
+ var React27 = __toESM(require("react"), 1);
4554
4666
  var import_jsx_runtime48 = require("react/jsx-runtime");
4555
4667
  var SAFE = /^(?:https?:|mailto:|tel:|#|\/|\.{1,2}\/)/i;
4556
4668
  var safeHref = (h) => SAFE.test(String(h || "").trim()) ? String(h).trim() : null;
@@ -4589,7 +4701,7 @@ function inlineNodes(src, ctx, keyBase) {
4589
4701
  const href = safeHref(g(2));
4590
4702
  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()));
4591
4703
  } else if (kind === "cite") {
4592
- 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()));
4704
+ 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()));
4593
4705
  } 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()));
4594
4706
  else if (kind === "strong") out.push(/* @__PURE__ */ (0, import_jsx_runtime48.jsx)("strong", { children: inlineNodes(g(1) || g(2), ctx, key()) }, key()));
4595
4707
  else if (kind === "em") out.push(/* @__PURE__ */ (0, import_jsx_runtime48.jsx)("em", { children: inlineNodes(g(1) || g(2), ctx, key()) }, key()));
@@ -4754,7 +4866,7 @@ function Markdown({
4754
4866
  onLinkClick
4755
4867
  }) {
4756
4868
  const ctx = { allowImages, headingOffset, renderCitation, onLinkClick, codeProps };
4757
- const blocks = React26.useMemo(() => parseBlocks(source), [source]);
4869
+ const blocks = React27.useMemo(() => parseBlocks(source), [source]);
4758
4870
  return /* @__PURE__ */ (0, import_jsx_runtime48.jsx)("div", { className: ["fd-md", className].filter(Boolean).join(" "), children: renderBlocks(blocks, ctx, "b") });
4759
4871
  }
4760
4872
  function MarkdownInline({ source = "", className = "", onLinkClick }) {
@@ -4868,7 +4980,7 @@ function Pagination({
4868
4980
  }
4869
4981
 
4870
4982
  // src/components/data/RelativeTime.tsx
4871
- var React27 = __toESM(require("react"), 1);
4983
+ var React28 = __toESM(require("react"), 1);
4872
4984
  var import_jsx_runtime51 = require("react/jsx-runtime");
4873
4985
  var MIN = 6e4;
4874
4986
  var HOUR = 36e5;
@@ -4920,9 +5032,9 @@ function formatDuration(ms) {
4920
5032
  return h + "h" + (m % 60 ? " " + m % 60 + "m" : "");
4921
5033
  }
4922
5034
  function RelativeTime({ value, prefix, className = "", refresh: refresh2 = true, ...rest }) {
4923
- const [, force] = React27.useState(0);
5035
+ const [, force] = React28.useState(0);
4924
5036
  const t = value instanceof Date ? value.getTime() : Date.parse(value);
4925
- React27.useEffect(() => {
5037
+ React28.useEffect(() => {
4926
5038
  if (!refresh2 || !t || isNaN(t)) return;
4927
5039
  const abs = Math.abs(t - Date.now());
4928
5040
  if (abs > DAY) return;
@@ -4938,7 +5050,7 @@ function RelativeTime({ value, prefix, className = "", refresh: refresh2 = true,
4938
5050
  }
4939
5051
 
4940
5052
  // src/components/data/ScoreMeter.tsx
4941
- var React28 = __toESM(require("react"), 1);
5053
+ var React29 = __toESM(require("react"), 1);
4942
5054
  var import_jsx_runtime52 = require("react/jsx-runtime");
4943
5055
  function ScoreMeter({
4944
5056
  score,
@@ -4953,10 +5065,10 @@ function ScoreMeter({
4953
5065
  breakdownWidth = 280,
4954
5066
  className = ""
4955
5067
  }) {
4956
- const [open, setOpen] = React28.useState(false);
4957
- const ref = React28.useRef(null);
5068
+ const [open, setOpen] = React29.useState(false);
5069
+ const ref = React29.useRef(null);
4958
5070
  const value = Math.max(0, Math.min(100, Math.round(Number(score) || 0)));
4959
- const body = /* @__PURE__ */ (0, import_jsx_runtime52.jsxs)(React28.Fragment, { children: [
5071
+ const body = /* @__PURE__ */ (0, import_jsx_runtime52.jsxs)(React29.Fragment, { children: [
4960
5072
  /* @__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 }) }),
4961
5073
  showScore ? /* @__PURE__ */ (0, import_jsx_runtime52.jsx)("span", { className: "fd-scoremeter-value fd-tabular", "aria-hidden": "true", children: value }) : null
4962
5074
  ] });
@@ -4975,7 +5087,7 @@ function ScoreMeter({
4975
5087
  }
4976
5088
  );
4977
5089
  }
4978
- return /* @__PURE__ */ (0, import_jsx_runtime52.jsxs)(React28.Fragment, { children: [
5090
+ return /* @__PURE__ */ (0, import_jsx_runtime52.jsxs)(React29.Fragment, { children: [
4979
5091
  /* @__PURE__ */ (0, import_jsx_runtime52.jsx)(
4980
5092
  "button",
4981
5093
  {
@@ -5006,13 +5118,13 @@ function ScoreMeter({
5006
5118
  }
5007
5119
 
5008
5120
  // src/components/data/SortMenu.tsx
5009
- var React29 = __toESM(require("react"), 1);
5121
+ var React30 = __toESM(require("react"), 1);
5010
5122
  var import_jsx_runtime53 = require("react/jsx-runtime");
5011
5123
  function SortMenu({ fields = [], sort, onSort, align = "right", size = "md", className = "", ...rest }) {
5012
- const [open, setOpen] = React29.useState(false);
5124
+ const [open, setOpen] = React30.useState(false);
5013
5125
  const zIndex = useOverlayLayer(open);
5014
- const ref = React29.useRef(null);
5015
- React29.useEffect(() => {
5126
+ const ref = React30.useRef(null);
5127
+ React30.useEffect(() => {
5016
5128
  if (!open) return;
5017
5129
  const away = (e) => {
5018
5130
  if (ref.current && !ref.current.contains(e.target)) setOpen(false);
@@ -5074,7 +5186,7 @@ function SortMenu({ fields = [], sort, onSort, align = "right", size = "md", cla
5074
5186
  }
5075
5187
 
5076
5188
  // src/components/data/StepList.tsx
5077
- var React30 = __toESM(require("react"), 1);
5189
+ var React31 = __toESM(require("react"), 1);
5078
5190
  var import_jsx_runtime54 = require("react/jsx-runtime");
5079
5191
  var KIND_ICON = { tool: "wrench", search: "magnifying-glass", read: "file-text", write: "pencil-simple", reasoning: "brain", run: "terminal", fetch: "cloud-arrow-down" };
5080
5192
  function StepList({
@@ -5087,9 +5199,9 @@ function StepList({
5087
5199
  dense = false,
5088
5200
  className = ""
5089
5201
  }) {
5090
- const [openState, setOpenState] = React30.useState(defaultOpen);
5202
+ const [openState, setOpenState] = React31.useState(defaultOpen);
5091
5203
  const open = openProp == null ? openState : openProp;
5092
- const [expanded, setExpanded] = React30.useState({});
5204
+ const [expanded, setExpanded] = React31.useState({});
5093
5205
  if (!steps.length) return null;
5094
5206
  const running = steps.some((s) => s.status === "running");
5095
5207
  const failed = steps.filter((s) => s.status === "error").length;
@@ -5147,7 +5259,7 @@ function StepList({
5147
5259
  }
5148
5260
 
5149
5261
  // src/components/data/VirtualList.tsx
5150
- var React31 = __toESM(require("react"), 1);
5262
+ var React32 = __toESM(require("react"), 1);
5151
5263
  var import_jsx_runtime55 = require("react/jsx-runtime");
5152
5264
  var VIRTUAL_LIST_BUFFER_ROWS = 20;
5153
5265
  var VIRTUAL_LIST_ROW_GAP = 6;
@@ -5199,35 +5311,35 @@ function VirtualList({
5199
5311
  className = "",
5200
5312
  style
5201
5313
  }) {
5202
- const [scrollTop, setScrollTop] = React31.useState(0);
5203
- const loaded = React31.useMemo(
5314
+ const [scrollTop, setScrollTop] = React32.useState(0);
5315
+ const loaded = React32.useMemo(
5204
5316
  () => ({ firstItemIndex, count: items.length }),
5205
5317
  [firstItemIndex, items.length]
5206
5318
  );
5207
5319
  const total = Math.max(totalCount == null ? 0 : totalCount, firstItemIndex + items.length);
5208
5320
  const bandKey = firstItemIndex + ":" + items.length;
5209
- const win = React31.useMemo(
5321
+ const win = React32.useMemo(
5210
5322
  () => computeVirtualWindow({ scrollTop, viewportHeight: height, itemHeight, itemCount: total, loaded }),
5211
5323
  [scrollTop, height, itemHeight, total, loaded]
5212
5324
  );
5213
- const need = React31.useMemo(() => computeNeedMore(win, loaded), [win, loaded]);
5325
+ const need = React32.useMemo(() => computeNeedMore(win, loaded), [win, loaded]);
5214
5326
  const wantStart = need.start && hasMore?.start !== false;
5215
5327
  const wantEnd = need.end && hasMore?.end !== false;
5216
5328
  const bucket2 = Math.floor(win.visibleStart / VIRTUAL_LIST_BUFFER_ROWS);
5217
5329
  const askKey = bandKey + "@" + bucket2;
5218
- const asked = React31.useRef({ start: null, end: null });
5219
- React31.useEffect(() => {
5330
+ const asked = React32.useRef({ start: null, end: null });
5331
+ React32.useEffect(() => {
5220
5332
  if (loading || !wantStart || asked.current.start === askKey) return;
5221
5333
  asked.current.start = askKey;
5222
5334
  onNeedMore("start", win);
5223
5335
  }, [wantStart, loading, askKey, onNeedMore, win]);
5224
- React31.useEffect(() => {
5336
+ React32.useEffect(() => {
5225
5337
  if (loading || !wantEnd || asked.current.end === askKey) return;
5226
5338
  asked.current.end = askKey;
5227
5339
  onNeedMore("end", win);
5228
5340
  }, [wantEnd, loading, askKey, onNeedMore, win]);
5229
- const lastKeysRef = React31.useRef(null);
5230
- const newKeys = React31.useMemo(() => {
5341
+ const lastKeysRef = React32.useRef(null);
5342
+ const newKeys = React32.useMemo(() => {
5231
5343
  const prev = lastKeysRef.current;
5232
5344
  if (!prev) return /* @__PURE__ */ new Set();
5233
5345
  const fresh = /* @__PURE__ */ new Set();
@@ -5237,7 +5349,7 @@ function VirtualList({
5237
5349
  }
5238
5350
  return fresh;
5239
5351
  }, [items]);
5240
- React31.useEffect(() => {
5352
+ React32.useEffect(() => {
5241
5353
  lastKeysRef.current = new Set(items.map(keyOf));
5242
5354
  }, [items]);
5243
5355
  const gapStyle = { "--fd-vlist-gap": rowGap + "px" };
@@ -5282,7 +5394,7 @@ function VirtualList({
5282
5394
  }
5283
5395
 
5284
5396
  // src/components/data/EntityRow.tsx
5285
- var React32 = __toESM(require("react"), 1);
5397
+ var React33 = __toESM(require("react"), 1);
5286
5398
  var import_jsx_runtime56 = require("react/jsx-runtime");
5287
5399
  var ENTITY_ROW_METRIC_WIDTH = 74;
5288
5400
  var METRIC_TONE_COLOR = {
@@ -5295,7 +5407,7 @@ function EntityRowMetrics({ metrics, className = "", style }) {
5295
5407
  const key = m.id || m.label || i;
5296
5408
  const className2 = ["fd-erow-metric", m.tone && m.tone !== "default" ? "is-" + m.tone : "", m.tooltip != null ? "is-described" : ""].filter(Boolean).join(" ");
5297
5409
  const tone = { color: METRIC_TONE_COLOR[m.tone || "default"] };
5298
- const content = /* @__PURE__ */ (0, import_jsx_runtime56.jsxs)(React32.Fragment, { children: [
5410
+ const content = /* @__PURE__ */ (0, import_jsx_runtime56.jsxs)(React33.Fragment, { children: [
5299
5411
  m.icon ? /* @__PURE__ */ (0, import_jsx_runtime56.jsx)("i", { className: "ph ph-" + m.icon, "aria-hidden": "true" }) : null,
5300
5412
  /* @__PURE__ */ (0, import_jsx_runtime56.jsx)("span", { className: "fd-erow-metric-value fd-tabular", children: m.value }),
5301
5413
  /* @__PURE__ */ (0, import_jsx_runtime56.jsx)("span", { className: "fd-sr", children: " " + m.label })
@@ -5387,7 +5499,7 @@ function EntityRow({
5387
5499
  }
5388
5500
 
5389
5501
  // src/components/data/TransferList.tsx
5390
- var React33 = __toESM(require("react"), 1);
5502
+ var React34 = __toESM(require("react"), 1);
5391
5503
  var import_react_dom5 = require("react-dom");
5392
5504
 
5393
5505
  // src/components/forms/Input.tsx
@@ -5493,12 +5605,12 @@ function TransferList({
5493
5605
  listHeight = 440,
5494
5606
  className = ""
5495
5607
  }) {
5496
- const [drag, setDrag] = React33.useState(null);
5497
- const [dragOverSide, setDragOverSide] = React33.useState(null);
5498
- const dragRef = React33.useRef(null);
5499
- const armedRef = React33.useRef(null);
5500
- const sideRefs = React33.useRef({ left: null, right: null });
5501
- const hitTestSide = React33.useCallback((x, y) => {
5608
+ const [drag, setDrag] = React34.useState(null);
5609
+ const [dragOverSide, setDragOverSide] = React34.useState(null);
5610
+ const dragRef = React34.useRef(null);
5611
+ const armedRef = React34.useRef(null);
5612
+ const sideRefs = React34.useRef({ left: null, right: null });
5613
+ const hitTestSide = React34.useCallback((x, y) => {
5502
5614
  for (const side of ["left", "right"]) {
5503
5615
  const el = sideRefs.current[side];
5504
5616
  if (!el) continue;
@@ -5507,7 +5619,7 @@ function TransferList({
5507
5619
  }
5508
5620
  return null;
5509
5621
  }, []);
5510
- const findItem = React33.useCallback(
5622
+ const findItem = React34.useCallback(
5511
5623
  (side, key) => (side === "left" ? left.items : right.items).find((it) => keyOf(it) === key),
5512
5624
  [left.items, right.items, keyOf]
5513
5625
  );
@@ -5529,7 +5641,7 @@ function TransferList({
5529
5641
  height: rect.height
5530
5642
  };
5531
5643
  };
5532
- React33.useEffect(() => {
5644
+ React34.useEffect(() => {
5533
5645
  const onMovePointer = (e) => {
5534
5646
  const armed = armedRef.current;
5535
5647
  if (!armed || e.pointerId !== armed.pointerId) return;
@@ -5582,7 +5694,7 @@ function TransferList({
5582
5694
  window.removeEventListener("pointercancel", endDrag);
5583
5695
  };
5584
5696
  }, [hitTestSide, findItem, onMove]);
5585
- React33.useEffect(() => {
5697
+ React34.useEffect(() => {
5586
5698
  if (!drag || typeof document === "undefined") return;
5587
5699
  const prev = document.body.style.userSelect;
5588
5700
  document.body.style.userSelect = "none";
@@ -5690,11 +5802,11 @@ function TransferList({
5690
5802
  }
5691
5803
 
5692
5804
  // src/components/forms/Checkbox.tsx
5693
- var React34 = __toESM(require("react"), 1);
5805
+ var React35 = __toESM(require("react"), 1);
5694
5806
  var import_jsx_runtime60 = require("react/jsx-runtime");
5695
5807
  function Checkbox({ label, description, card = false, indeterminate = false, className = "", ...rest }) {
5696
- const ref = React34.useRef(null);
5697
- React34.useEffect(() => {
5808
+ const ref = React35.useRef(null);
5809
+ React35.useEffect(() => {
5698
5810
  if (ref.current) ref.current.indeterminate = indeterminate;
5699
5811
  }, [indeterminate]);
5700
5812
  return /* @__PURE__ */ (0, import_jsx_runtime60.jsxs)("label", { className: ["fd-choice", card ? "fd-choice-card" : "", className].filter(Boolean).join(" "), children: [
@@ -5738,7 +5850,7 @@ function Switch({ label, description, className = "", ...rest }) {
5738
5850
  }
5739
5851
 
5740
5852
  // src/components/forms/Select.tsx
5741
- var React35 = __toESM(require("react"), 1);
5853
+ var React36 = __toESM(require("react"), 1);
5742
5854
  var import_jsx_runtime63 = require("react/jsx-runtime");
5743
5855
  var norm = (o) => typeof o === "string" ? { value: o, label: o } : o;
5744
5856
  function Select({
@@ -5765,12 +5877,12 @@ function Select({
5765
5877
  const isOn = (v) => multiple ? vals.includes(v) : v === value;
5766
5878
  const hasSearch = searchable === void 0 ? opts.length > 8 : searchable;
5767
5879
  const { fieldId, labelId, ariaLabelledBy } = useTriggerLabelling(label, id);
5768
- const [open, setOpen] = React35.useState(false);
5769
- const [q, setQ] = React35.useState("");
5770
- const rootRef = React35.useRef(null);
5771
- const boxRef = React35.useRef(null);
5772
- const listRef = React35.useRef(null);
5773
- const typeBuf = React35.useRef({ s: "", t: 0 });
5880
+ const [open, setOpen] = React36.useState(false);
5881
+ const [q, setQ] = React36.useState("");
5882
+ const rootRef = React36.useRef(null);
5883
+ const boxRef = React36.useRef(null);
5884
+ const listRef = React36.useRef(null);
5885
+ const typeBuf = React36.useRef({ s: "", t: 0 });
5774
5886
  const selected = multiple ? null : opts.find((o) => o.value === value);
5775
5887
  const chosen = multiple ? opts.filter((o) => vals.includes(o.value)) : [];
5776
5888
  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;
@@ -5909,7 +6021,7 @@ function Select({
5909
6021
  ),
5910
6022
  q ? /* @__PURE__ */ (0, import_jsx_runtime63.jsx)("span", { className: "fd-body-sm fd-muted", children: visible.length }) : null
5911
6023
  ] }) : void 0,
5912
- footer: multiple ? /* @__PURE__ */ (0, import_jsx_runtime63.jsxs)(React35.Fragment, { children: [
6024
+ footer: multiple ? /* @__PURE__ */ (0, import_jsx_runtime63.jsxs)(React36.Fragment, { children: [
5913
6025
  /* @__PURE__ */ (0, import_jsx_runtime63.jsx)(
5914
6026
  "button",
5915
6027
  {
@@ -5940,7 +6052,7 @@ function Select({
5940
6052
  'Nothing matches "',
5941
6053
  q,
5942
6054
  '".'
5943
- ] }) : groups.map((grp) => /* @__PURE__ */ (0, import_jsx_runtime63.jsxs)(React35.Fragment, { children: [
6055
+ ] }) : groups.map((grp) => /* @__PURE__ */ (0, import_jsx_runtime63.jsxs)(React36.Fragment, { children: [
5944
6056
  grp.g ? /* @__PURE__ */ (0, import_jsx_runtime63.jsx)("div", { className: "fd-pop-group", children: grp.g }) : null,
5945
6057
  grp.items.map(({ o, i }) => /* @__PURE__ */ (0, import_jsx_runtime63.jsxs)(
5946
6058
  "button",
@@ -5977,7 +6089,7 @@ function Select({
5977
6089
  }
5978
6090
 
5979
6091
  // src/components/forms/TimePicker.tsx
5980
- var React36 = __toESM(require("react"), 1);
6092
+ var React37 = __toESM(require("react"), 1);
5981
6093
  var import_jsx_runtime64 = require("react/jsx-runtime");
5982
6094
  var pad = (n) => String(n).padStart(2, "0");
5983
6095
  function ClockFace({ value = "09:00", onChange }) {
@@ -5986,9 +6098,9 @@ function ClockFace({ value = "09:00", onChange }) {
5986
6098
  if (isNaN(m)) m = 0;
5987
6099
  const pm = h24 >= 12;
5988
6100
  const h12 = h24 % 12 === 0 ? 12 : h24 % 12;
5989
- const [mode2, setMode] = React36.useState("h");
5990
- const faceRef = React36.useRef(null);
5991
- const dragging = React36.useRef(false);
6101
+ const [mode2, setMode] = React37.useState("h");
6102
+ const faceRef = React37.useRef(null);
6103
+ const dragging = React37.useRef(false);
5992
6104
  const set = (h, mm, isPm) => onChange((isPm ? h % 12 + 12 : h % 12) + ":" + pad(mm));
5993
6105
  const R = 108, NR = 80;
5994
6106
  const nums = mode2 === "h" ? Array.from({ length: 12 }, (_, i) => i + 1) : Array.from({ length: 12 }, (_, i) => i * 5);
@@ -6061,9 +6173,9 @@ function ClockFace({ value = "09:00", onChange }) {
6061
6173
  }
6062
6174
  function TimePicker({ label, help, error, required = false, disabled = false, value = "", onChange, placeholder = "Pick a time", id, className = "", style }) {
6063
6175
  const { fieldId, labelId, ariaLabelledBy } = useTriggerLabelling(label, id);
6064
- const [open, setOpen] = React36.useState(false);
6065
- const rootRef = React36.useRef(null);
6066
- const boxRef = React36.useRef(null);
6176
+ const [open, setOpen] = React37.useState(false);
6177
+ const rootRef = React37.useRef(null);
6178
+ const boxRef = React37.useRef(null);
6067
6179
  const disp = () => {
6068
6180
  if (!value) return "";
6069
6181
  const [h, m] = value.split(":").map(Number);
@@ -6106,7 +6218,7 @@ function TimePicker({ label, help, error, required = false, disabled = false, va
6106
6218
  offset: 6,
6107
6219
  width: 262,
6108
6220
  role: "presentation",
6109
- footer: /* @__PURE__ */ (0, import_jsx_runtime64.jsxs)(React36.Fragment, { children: [
6221
+ footer: /* @__PURE__ */ (0, import_jsx_runtime64.jsxs)(React37.Fragment, { children: [
6110
6222
  /* @__PURE__ */ (0, import_jsx_runtime64.jsx)(
6111
6223
  "button",
6112
6224
  {
@@ -6134,7 +6246,7 @@ function TimePicker({ label, help, error, required = false, disabled = false, va
6134
6246
  }
6135
6247
 
6136
6248
  // src/components/forms/Slider.tsx
6137
- var React37 = __toESM(require("react"), 1);
6249
+ var React38 = __toESM(require("react"), 1);
6138
6250
  var import_jsx_runtime65 = require("react/jsx-runtime");
6139
6251
  function Slider({
6140
6252
  label,
@@ -6152,7 +6264,7 @@ function Slider({
6152
6264
  ...rest
6153
6265
  }) {
6154
6266
  const fieldId = useFieldId(id);
6155
- const [dragging, setDragging] = React37.useState(false);
6267
+ const [dragging, setDragging] = React38.useState(false);
6156
6268
  const v = value === void 0 ? min : Number(value);
6157
6269
  const pct = max === min ? 0 : (v - min) / (max - min) * 100;
6158
6270
  return /* @__PURE__ */ (0, import_jsx_runtime65.jsxs)("div", { className: ["fd-field", className].filter(Boolean).join(" "), children: [
@@ -6186,7 +6298,7 @@ function Slider({
6186
6298
  }
6187
6299
 
6188
6300
  // src/components/forms/RangeSlider.tsx
6189
- var React38 = __toESM(require("react"), 1);
6301
+ var React39 = __toESM(require("react"), 1);
6190
6302
  var import_jsx_runtime66 = require("react/jsx-runtime");
6191
6303
  function RangeSlider({
6192
6304
  label,
@@ -6206,9 +6318,9 @@ function RangeSlider({
6206
6318
  }) {
6207
6319
  const fmt2 = format || ((v) => String(v));
6208
6320
  const [a, b] = value || [min, max];
6209
- const [drag, setDrag] = React38.useState(null);
6210
- const [focus, setFocus] = React38.useState(null);
6211
- const railRef = React38.useRef(null);
6321
+ const [drag, setDrag] = React39.useState(null);
6322
+ const [focus, setFocus] = React39.useState(null);
6323
+ const railRef = React39.useRef(null);
6212
6324
  const pct = (v) => max === min ? 0 : (v - min) / (max - min) * 100;
6213
6325
  const clampPair = (i, v) => {
6214
6326
  v = Math.min(max, Math.max(min, Math.round(v / step) * step));
@@ -6223,7 +6335,7 @@ function RangeSlider({
6223
6335
  const r = railRef.current.getBoundingClientRect();
6224
6336
  return min + Math.min(1, Math.max(0, (e.clientX - r.left) / r.width)) * (max - min);
6225
6337
  };
6226
- React38.useEffect(() => {
6338
+ React39.useEffect(() => {
6227
6339
  if (drag === null) return;
6228
6340
  const mv = (e) => onChange && onChange(clampPair(drag, fromEvent(e)));
6229
6341
  const upH = () => setDrag(null);
@@ -6304,7 +6416,7 @@ function RangeSlider({
6304
6416
  /* @__PURE__ */ (0, import_jsx_runtime66.jsxs)("div", { className: "fd-range" + (hasLabels ? " has-labels" : ""), onPointerDown: onRailDown, children: [
6305
6417
  /* @__PURE__ */ (0, import_jsx_runtime66.jsx)("span", { className: "fd-range-rail", ref: railRef }),
6306
6418
  /* @__PURE__ */ (0, import_jsx_runtime66.jsx)("span", { className: "fd-range-fill", style: { left: pct(a) + "%", width: pct(b) - pct(a) + "%" } }),
6307
- marks.map((m) => /* @__PURE__ */ (0, import_jsx_runtime66.jsxs)(React38.Fragment, { children: [
6419
+ marks.map((m) => /* @__PURE__ */ (0, import_jsx_runtime66.jsxs)(React39.Fragment, { children: [
6308
6420
  /* @__PURE__ */ (0, import_jsx_runtime66.jsx)("span", { className: "fd-range-mark" + (m.value >= a && m.value <= b ? " is-in" : ""), style: { left: pct(m.value) + "%" } }),
6309
6421
  m.label ? /* @__PURE__ */ (0, import_jsx_runtime66.jsx)("span", { className: "fd-range-mark-label", style: { left: pct(m.value) + "%" }, children: m.label }) : null
6310
6422
  ] }, m.value)),
@@ -6333,7 +6445,7 @@ function RangeSlider({
6333
6445
  }
6334
6446
 
6335
6447
  // src/components/forms/Dropzone.tsx
6336
- var React39 = __toESM(require("react"), 1);
6448
+ var React40 = __toESM(require("react"), 1);
6337
6449
  var import_jsx_runtime67 = require("react/jsx-runtime");
6338
6450
  function Dropzone({
6339
6451
  onFiles,
@@ -6348,8 +6460,8 @@ function Dropzone({
6348
6460
  className = "",
6349
6461
  style
6350
6462
  }) {
6351
- const [over, setOver] = React39.useState(false);
6352
- const depth = React39.useRef(0);
6463
+ const [over, setOver] = React40.useState(false);
6464
+ const depth = React40.useRef(0);
6353
6465
  const has = (e) => {
6354
6466
  const dt = e.dataTransfer;
6355
6467
  if (!dt) return false;
@@ -6411,8 +6523,8 @@ function FilePickButton({
6411
6523
  className = "",
6412
6524
  children
6413
6525
  }) {
6414
- const ref = React39.useRef(null);
6415
- return /* @__PURE__ */ (0, import_jsx_runtime67.jsxs)(React39.Fragment, { children: [
6526
+ const ref = React40.useRef(null);
6527
+ return /* @__PURE__ */ (0, import_jsx_runtime67.jsxs)(React40.Fragment, { children: [
6416
6528
  /* @__PURE__ */ (0, import_jsx_runtime67.jsx)(
6417
6529
  "button",
6418
6530
  {
@@ -6445,10 +6557,10 @@ function FilePickButton({
6445
6557
  }
6446
6558
  function useStagedFiles(upload, opts) {
6447
6559
  const o = opts || {};
6448
- const [items, setItems] = React39.useState([]);
6449
- const controllers = React39.useRef({});
6560
+ const [items, setItems] = React40.useState([]);
6561
+ const controllers = React40.useRef({});
6450
6562
  const patch = (id, next) => setItems((list) => list.map((f) => f.id === id ? Object.assign({}, f, next) : f));
6451
- const run = React39.useCallback((att) => {
6563
+ const run = React40.useCallback((att) => {
6452
6564
  if (!upload) return;
6453
6565
  const ac = typeof AbortController !== "undefined" ? new AbortController() : null;
6454
6566
  controllers.current[att.id] = ac;
@@ -6465,14 +6577,14 @@ function useStagedFiles(upload, opts) {
6465
6577
  delete controllers.current[att.id];
6466
6578
  });
6467
6579
  }, [upload]);
6468
- const add = React39.useCallback((files) => {
6580
+ const add = React40.useCallback((files) => {
6469
6581
  if (!upload) return [];
6470
6582
  const atts = Array.from(files).map((f) => toAttachment(f));
6471
6583
  setItems((list) => list.concat(atts));
6472
6584
  atts.forEach(run);
6473
6585
  return atts;
6474
6586
  }, [upload, run]);
6475
- const remove = React39.useCallback((att) => {
6587
+ const remove = React40.useCallback((att) => {
6476
6588
  const ac = controllers.current[att.id];
6477
6589
  if (ac) {
6478
6590
  try {
@@ -6483,10 +6595,10 @@ function useStagedFiles(upload, opts) {
6483
6595
  }
6484
6596
  setItems((list) => list.filter((f) => f.id !== att.id));
6485
6597
  }, []);
6486
- const retry = React39.useCallback((att) => {
6598
+ const retry = React40.useCallback((att) => {
6487
6599
  run(att);
6488
6600
  }, [run]);
6489
- const clear = React39.useCallback(() => {
6601
+ const clear = React40.useCallback(() => {
6490
6602
  Object.values(controllers.current).forEach((ac) => {
6491
6603
  try {
6492
6604
  ac && ac.abort();
@@ -6610,7 +6722,7 @@ function FileGrid({ files = [], onOpen, onRemove, onRetry, tiles = true, maxHeig
6610
6722
  }
6611
6723
 
6612
6724
  // src/components/forms/MarkdownEditor.tsx
6613
- var React40 = __toESM(require("react"), 1);
6725
+ var React41 = __toESM(require("react"), 1);
6614
6726
  var import_jsx_runtime69 = require("react/jsx-runtime");
6615
6727
  var isMac = typeof navigator !== "undefined" && /Mac|iPhone|iPad/.test(navigator.platform || navigator.userAgent || "");
6616
6728
  var INLINE_RE = /(\*\*\*[^*\n]+\*\*\*|\*\*[^*\n]+\*\*|__[^_\n]+__|~~[^~\n]+~~|`[^`\n]+`|\*[^*\s][^*\n]*\*|(?<![A-Za-z0-9_])_[^_\s][^_\n]*_|\[[^\]\n]*\]\([^)\s\n]*\)|https?:\/\/\S+)/g;
@@ -6824,7 +6936,7 @@ function syncDom(root, value) {
6824
6936
  while (root.children.length > lines.length) root.removeChild(root.lastChild);
6825
6937
  }
6826
6938
  var LIST_CONT = RE_LI;
6827
- var MarkdownEditor = React40.forwardRef(function MarkdownEditor2({
6939
+ var MarkdownEditor = React41.forwardRef(function MarkdownEditor2({
6828
6940
  value = "",
6829
6941
  onChange,
6830
6942
  onSubmit,
@@ -6843,10 +6955,10 @@ var MarkdownEditor = React40.forwardRef(function MarkdownEditor2({
6843
6955
  className = "",
6844
6956
  id
6845
6957
  }, ref) {
6846
- const boxRef = React40.useRef(null);
6847
- const composing = React40.useRef(false);
6848
- const pendingCaret = React40.useRef(null);
6849
- React40.useLayoutEffect(() => {
6958
+ const boxRef = React41.useRef(null);
6959
+ const composing = React41.useRef(false);
6960
+ const pendingCaret = React41.useRef(null);
6961
+ React41.useLayoutEffect(() => {
6850
6962
  const root = boxRef.current;
6851
6963
  if (!root || composing.current) return;
6852
6964
  const active = document.activeElement === root || root.contains(document.activeElement);
@@ -6855,7 +6967,7 @@ var MarkdownEditor = React40.forwardRef(function MarkdownEditor2({
6855
6967
  pendingCaret.current = null;
6856
6968
  if (active && caret != null) placeCaret(root, caret);
6857
6969
  }, [value]);
6858
- React40.useEffect(() => {
6970
+ React41.useEffect(() => {
6859
6971
  if (autoFocus && boxRef.current) boxRef.current.focus();
6860
6972
  }, [autoFocus]);
6861
6973
  const caretNow = () => {
@@ -6922,7 +7034,7 @@ var MarkdownEditor = React40.forwardRef(function MarkdownEditor2({
6922
7034
  api.replaceRange(from, to, next, from + next.length);
6923
7035
  }
6924
7036
  };
6925
- React40.useImperativeHandle(ref, () => api);
7037
+ React41.useImperativeHandle(ref, () => api);
6926
7038
  function detect(text, caret) {
6927
7039
  if (!onTrigger) return;
6928
7040
  const upto = text.slice(0, caret);
@@ -7074,16 +7186,16 @@ var MarkdownEditor = React40.forwardRef(function MarkdownEditor2({
7074
7186
  });
7075
7187
 
7076
7188
  // src/components/platform/AccountMenu.tsx
7077
- var React42 = __toESM(require("react"), 1);
7189
+ var React43 = __toESM(require("react"), 1);
7078
7190
 
7079
7191
  // src/kits/sessionContext.tsx
7080
- var React41 = __toESM(require("react"), 1);
7081
- var SessionContext = React41.createContext(null);
7192
+ var React42 = __toESM(require("react"), 1);
7193
+ var SessionContext = React42.createContext(null);
7082
7194
  function SessionProvider({ value, children }) {
7083
- return React41.createElement(SessionContext.Provider, { value }, children);
7195
+ return React42.createElement(SessionContext.Provider, { value }, children);
7084
7196
  }
7085
7197
  function useSessionContext() {
7086
- const ctx = React41.useContext(SessionContext);
7198
+ const ctx = React42.useContext(SessionContext);
7087
7199
  if (!ctx) {
7088
7200
  throw new Error(
7089
7201
  "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."
@@ -7123,11 +7235,11 @@ function AccountMenu({
7123
7235
  ...rest
7124
7236
  }) {
7125
7237
  const { user, roles, can: can2, signOut: ctxSignOut, demo } = useSessionContext();
7126
- const [open, setOpen] = React42.useState(false);
7127
- const [switching, setSwitching] = React42.useState(false);
7128
- const [signingOut, setSigningOut] = React42.useState(false);
7129
- const [signOutError, setSignOutError] = React42.useState(null);
7130
- const ref = React42.useRef(null);
7238
+ const [open, setOpen] = React43.useState(false);
7239
+ const [switching, setSwitching] = React43.useState(false);
7240
+ const [signingOut, setSigningOut] = React43.useState(false);
7241
+ const [signOutError, setSignOutError] = React43.useState(null);
7242
+ const ref = React43.useRef(null);
7131
7243
  const visibleLinks = links.filter((l) => !l.perm || can2(l.perm));
7132
7244
  const visibleGroups = groups.map((g) => ({ label: g.label, links: g.links.filter((l) => !l.perm || can2(l.perm)) })).filter((g) => g.links.length);
7133
7245
  const closeMenu = () => {
@@ -7252,13 +7364,13 @@ function AccountMenu({
7252
7364
  }
7253
7365
 
7254
7366
  // src/components/platform/AppSwitcher.tsx
7255
- var React43 = __toESM(require("react"), 1);
7367
+ var React44 = __toESM(require("react"), 1);
7256
7368
  var import_jsx_runtime71 = require("react/jsx-runtime");
7257
7369
  function AppSwitcher({ apps: appsProp, onNavigate, className = "" }) {
7258
7370
  const { apps: contextApps } = useSessionContext();
7259
7371
  const apps = appsProp ?? contextApps ?? [];
7260
- const [open, setOpen] = React43.useState(false);
7261
- const anchorRef = React43.useRef(null);
7372
+ const [open, setOpen] = React44.useState(false);
7373
+ const anchorRef = React44.useRef(null);
7262
7374
  if (!apps.length) return null;
7263
7375
  const items = apps.map((app) => ({
7264
7376
  id: app.key,
@@ -7272,7 +7384,7 @@ function AppSwitcher({ apps: appsProp, onNavigate, className = "" }) {
7272
7384
  window.location.href = app.url;
7273
7385
  }
7274
7386
  }));
7275
- return /* @__PURE__ */ (0, import_jsx_runtime71.jsxs)(React43.Fragment, { children: [
7387
+ return /* @__PURE__ */ (0, import_jsx_runtime71.jsxs)(React44.Fragment, { children: [
7276
7388
  /* @__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)(
7277
7389
  IconButton,
7278
7390
  {
@@ -7301,10 +7413,10 @@ function AppSwitcher({ apps: appsProp, onNavigate, className = "" }) {
7301
7413
  }
7302
7414
 
7303
7415
  // src/components/platform/AppearanceMenu.tsx
7304
- var React45 = __toESM(require("react"), 1);
7416
+ var React46 = __toESM(require("react"), 1);
7305
7417
 
7306
7418
  // src/kits/appearance.ts
7307
- var React44 = __toESM(require("react"), 1);
7419
+ var React45 = __toESM(require("react"), 1);
7308
7420
  var DEFAULT_STORAGE_KEY = "fd-appearance";
7309
7421
  var DEFAULT_PREFS = {
7310
7422
  theme: "system",
@@ -7399,11 +7511,11 @@ function applyPrefs(prefs, root = document.documentElement) {
7399
7511
  else root.removeAttribute("data-motion");
7400
7512
  }
7401
7513
  function useAppearancePrefs(store) {
7402
- const prefs = React44.useSyncExternalStore(store.subscribe, store.getSnapshot);
7403
- React44.useEffect(() => {
7514
+ const prefs = React45.useSyncExternalStore(store.subscribe, store.getSnapshot);
7515
+ React45.useEffect(() => {
7404
7516
  applyPrefs(prefs);
7405
7517
  }, [prefs]);
7406
- React44.useEffect(() => {
7518
+ React45.useEffect(() => {
7407
7519
  if (prefs.theme !== "system" || typeof window === "undefined" || typeof window.matchMedia !== "function") {
7408
7520
  return;
7409
7521
  }
@@ -7412,7 +7524,7 @@ function useAppearancePrefs(store) {
7412
7524
  mq.addEventListener("change", onChange);
7413
7525
  return () => mq.removeEventListener("change", onChange);
7414
7526
  }, [prefs]);
7415
- const update = React44.useCallback(
7527
+ const update = React45.useCallback(
7416
7528
  (patch) => {
7417
7529
  store.write({ ...store.getSnapshot(), ...patch });
7418
7530
  },
@@ -7435,15 +7547,15 @@ var TEXT_SCALE_OPTIONS = [
7435
7547
  { value: "xl", label: "XL" }
7436
7548
  ];
7437
7549
  function AppearanceMenu({ className = "", store: storeProp, storageKey, storage, defaults }) {
7438
- const store = React45.useMemo(
7550
+ const store = React46.useMemo(
7439
7551
  () => storeProp ?? createLocalStorageAppearanceStore({ storageKey, storage, defaults }),
7440
7552
  [storeProp, storageKey, storage, defaults]
7441
7553
  );
7442
7554
  const [prefs, update] = useAppearancePrefs(store);
7443
- const [open, setOpen] = React45.useState(false);
7444
- const anchorRef = React45.useRef(null);
7555
+ const [open, setOpen] = React46.useState(false);
7556
+ const anchorRef = React46.useRef(null);
7445
7557
  const patch = (p) => update(p);
7446
- return /* @__PURE__ */ (0, import_jsx_runtime72.jsxs)(React45.Fragment, { children: [
7558
+ return /* @__PURE__ */ (0, import_jsx_runtime72.jsxs)(React46.Fragment, { children: [
7447
7559
  /* @__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)(
7448
7560
  IconButton,
7449
7561
  {
@@ -7512,14 +7624,14 @@ function AppearanceMenu({ className = "", store: storeProp, storageKey, storage,
7512
7624
  }
7513
7625
 
7514
7626
  // src/components/platform/ApiSpecBrowser.tsx
7515
- var React46 = __toESM(require("react"), 1);
7627
+ var React47 = __toESM(require("react"), 1);
7516
7628
  var import_jsx_runtime73 = require("react/jsx-runtime");
7517
7629
  var METHOD_TONE = { GET: "success", POST: "info", PATCH: "warning", PUT: "warning", DELETE: "danger" };
7518
7630
  function Json({ obj }) {
7519
7631
  return /* @__PURE__ */ (0, import_jsx_runtime73.jsx)("pre", { className: "fd-json", children: JSON.stringify(obj, null, 2) });
7520
7632
  }
7521
7633
  function Endpoint({ s, onRequest }) {
7522
- const [tried, setTried] = React46.useState(null);
7634
+ const [tried, setTried] = React47.useState(null);
7523
7635
  const run = async () => {
7524
7636
  setTried("busy");
7525
7637
  const t0 = (window.performance || Date).now();
@@ -7592,10 +7704,10 @@ function ApiSpecBrowser({
7592
7704
  className = "",
7593
7705
  ...rest
7594
7706
  }) {
7595
- const [q, setQ] = React46.useState("");
7596
- const [method, setMethod] = React46.useState(null);
7597
- const [mod, setMod] = React46.useState(null);
7598
- const [listOnly, setListOnly] = React46.useState(false);
7707
+ const [q, setQ] = React47.useState("");
7708
+ const [method, setMethod] = React47.useState(null);
7709
+ const [mod, setMod] = React47.useState(null);
7710
+ const [listOnly, setListOnly] = React47.useState(false);
7599
7711
  const activeModule = modules && modules.find((m) => m.id === mod);
7600
7712
  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())));
7601
7713
  const effGroups = groups && groups.length ? groups : [["All endpoints", spec.map((s) => s.id)]];
@@ -7674,7 +7786,7 @@ function ApiSpecBrowser({
7674
7786
  }
7675
7787
 
7676
7788
  // src/components/platform/ProfilePage.tsx
7677
- var React47 = __toESM(require("react"), 1);
7789
+ var React48 = __toESM(require("react"), 1);
7678
7790
  var import_jsx_runtime74 = require("react/jsx-runtime");
7679
7791
  function fieldInitialValue(field, user) {
7680
7792
  if (field.value) return field.value(user);
@@ -7710,21 +7822,21 @@ function ProfilePage({
7710
7822
  }) {
7711
7823
  const { user: sessionUser, roles, permissions, saveProfile: saveProfile2 } = useSessionContext();
7712
7824
  const user = userProp || sessionUser;
7713
- const initialFieldValues = React47.useMemo(() => {
7825
+ const initialFieldValues = React48.useMemo(() => {
7714
7826
  const values2 = {};
7715
7827
  for (const field of fields) values2[field.key] = fieldInitialValue(field, user);
7716
7828
  return values2;
7717
7829
  }, [user.id, fields]);
7718
- const initialNotify = React47.useMemo(() => {
7830
+ const initialNotify = React48.useMemo(() => {
7719
7831
  const values2 = {};
7720
7832
  for (const n of notifications) values2[n.key] = !!user.notify?.[n.key];
7721
7833
  return values2;
7722
7834
  }, [user.id, notifications]);
7723
- const [values, setValues] = React47.useState(initialFieldValues);
7724
- const [notify, setNotify] = React47.useState(initialNotify);
7725
- const [saving, setSaving] = React47.useState(false);
7726
- const [saved, setSaved] = React47.useState(false);
7727
- const [prevUserId, setPrevUserId] = React47.useState(user.id);
7835
+ const [values, setValues] = React48.useState(initialFieldValues);
7836
+ const [notify, setNotify] = React48.useState(initialNotify);
7837
+ const [saving, setSaving] = React48.useState(false);
7838
+ const [saved, setSaved] = React48.useState(false);
7839
+ const [prevUserId, setPrevUserId] = React48.useState(user.id);
7728
7840
  if (user.id !== prevUserId) {
7729
7841
  setPrevUserId(user.id);
7730
7842
  setValues(initialFieldValues);
@@ -7912,11 +8024,11 @@ function ProfilePage({
7912
8024
  }
7913
8025
 
7914
8026
  // src/components/platform/SignInPage.tsx
7915
- var React48 = __toESM(require("react"), 1);
8027
+ var React49 = __toESM(require("react"), 1);
7916
8028
  var import_jsx_runtime75 = require("react/jsx-runtime");
7917
8029
  function SignInPage({ productName, onSignIn, continueAs, error }) {
7918
- const [signingIn, setSigningIn] = React48.useState(false);
7919
- const [resuming, setResuming] = React48.useState(false);
8030
+ const [signingIn, setSigningIn] = React49.useState(false);
8031
+ const [resuming, setResuming] = React49.useState(false);
7920
8032
  function handleSignIn() {
7921
8033
  setSigningIn(true);
7922
8034
  onSignIn();
@@ -8105,10 +8217,10 @@ function GoogleGlyph() {
8105
8217
  }
8106
8218
 
8107
8219
  // src/components/platform/RoadmapTimeline.tsx
8108
- var React51 = __toESM(require("react"), 1);
8220
+ var React52 = __toESM(require("react"), 1);
8109
8221
 
8110
8222
  // src/kits/session.ts
8111
- var React49 = __toESM(require("react"), 1);
8223
+ var React50 = __toESM(require("react"), 1);
8112
8224
  var PERMISSION_CATALOG = [
8113
8225
  { group: "Plans", items: [
8114
8226
  { key: "plan.view", label: "View plans", detail: "Read any plan in the workspace." },
@@ -9675,8 +9787,8 @@ function roadmap(overrides) {
9675
9787
  };
9676
9788
  }
9677
9789
  function useSession() {
9678
- const [s, setS] = React49.useState(getSession);
9679
- React49.useEffect(() => subscribe(setS), []);
9790
+ const [s, setS] = React50.useState(getSession);
9791
+ React50.useEffect(() => subscribe(setS), []);
9680
9792
  return s;
9681
9793
  }
9682
9794
  var SessionKit = {
@@ -9709,7 +9821,7 @@ var SessionKit = {
9709
9821
  };
9710
9822
  function DemoSessionProvider({ children }) {
9711
9823
  const session = useSession();
9712
- const value = React49.useMemo(
9824
+ const value = React50.useMemo(
9713
9825
  () => ({
9714
9826
  user: session.user,
9715
9827
  roles: session.roles,
@@ -9725,11 +9837,11 @@ function DemoSessionProvider({ children }) {
9725
9837
  }),
9726
9838
  [session]
9727
9839
  );
9728
- return React49.createElement(SessionProvider, { value }, children);
9840
+ return React50.createElement(SessionProvider, { value }, children);
9729
9841
  }
9730
9842
 
9731
9843
  // src/kits/runtime.ts
9732
- var React50 = __toESM(require("react"), 1);
9844
+ var React51 = __toESM(require("react"), 1);
9733
9845
  var WIRED_ENDPOINTS = [
9734
9846
  // Nothing yet. Every id below would come from a real service:
9735
9847
  // "plan.get", "placements.list", …
@@ -9900,8 +10012,8 @@ var RuntimeKit = {
9900
10012
  };
9901
10013
  RuntimeKit.declare(FEATURE_NEEDS);
9902
10014
  function useRuntimeMode() {
9903
- const [m, setM] = React50.useState(RuntimeKit.getMode());
9904
- React50.useEffect(() => RuntimeKit.subscribe(setM), []);
10015
+ const [m, setM] = React51.useState(RuntimeKit.getMode());
10016
+ React51.useEffect(() => RuntimeKit.subscribe(setM), []);
9905
10017
  return m;
9906
10018
  }
9907
10019
  function useFeatureStatus(key) {
@@ -9984,12 +10096,12 @@ function RoadmapCard({ item, byKey, onOpenFlag }) {
9984
10096
  }
9985
10097
  function RoadmapTimeline({ onOpenFlag, title = "Roadmap", lede }) {
9986
10098
  const session = SessionKit.useSession();
9987
- const [project, setProject] = React51.useState("");
9988
- const [q, setQ] = React51.useState("");
9989
- const scrollRef = React51.useRef(null);
9990
- const nowRef = React51.useRef(null);
9991
- const rm = React51.useMemo(() => SessionKit.roadmap({ isComplete: RuntimeKit.isComplete }), [session]);
9992
- const byKey = React51.useMemo(() => {
10099
+ const [project, setProject] = React52.useState("");
10100
+ const [q, setQ] = React52.useState("");
10101
+ const scrollRef = React52.useRef(null);
10102
+ const nowRef = React52.useRef(null);
10103
+ const rm = React52.useMemo(() => SessionKit.roadmap({ isComplete: RuntimeKit.isComplete }), [session]);
10104
+ const byKey = React52.useMemo(() => {
9993
10105
  const m = {};
9994
10106
  rm.items.forEach((i) => {
9995
10107
  m[i.key] = i;
@@ -9998,7 +10110,7 @@ function RoadmapTimeline({ onOpenFlag, title = "Roadmap", lede }) {
9998
10110
  }, [rm]);
9999
10111
  const items = rm.items.filter((i) => (!project || i.project === project) && (!q || (i.label + " " + i.description + " " + (i.backend || "") + " " + i.key).toLowerCase().includes(q.toLowerCase())));
10000
10112
  const projects = [...new Set(rm.items.map((i) => i.project))];
10001
- React51.useEffect(() => {
10113
+ React52.useEffect(() => {
10002
10114
  let raf1 = 0, raf2 = 0;
10003
10115
  const place = () => {
10004
10116
  const box = scrollRef.current, mark = nowRef.current;
@@ -10072,7 +10184,7 @@ function RoadmapTimeline({ onOpenFlag, title = "Roadmap", lede }) {
10072
10184
  lastPhase = item.phase;
10073
10185
  const inPhase = items.filter((i) => i.phase === item.phase).length;
10074
10186
  const isBoundary = n === firstPending;
10075
- return /* @__PURE__ */ (0, import_jsx_runtime76.jsxs)(React51.Fragment, { children: [
10187
+ return /* @__PURE__ */ (0, import_jsx_runtime76.jsxs)(React52.Fragment, { children: [
10076
10188
  showPhase ? /* @__PURE__ */ (0, import_jsx_runtime76.jsxs)("div", { className: "fd-rm-era", children: [
10077
10189
  /* @__PURE__ */ (0, import_jsx_runtime76.jsxs)("span", { className: "fd-row", style: { gap: 8, flexWrap: "wrap", alignItems: "baseline" }, children: [
10078
10190
  /* @__PURE__ */ (0, import_jsx_runtime76.jsx)("span", { style: { fontWeight: 700 }, children: item.phase === 0 ? "Shipped" : "Phase " + item.phase + " \u2014 " + item.phaseName }),
@@ -10116,7 +10228,7 @@ function RoadmapTimeline({ onOpenFlag, title = "Roadmap", lede }) {
10116
10228
  }
10117
10229
 
10118
10230
  // src/components/platform/ComingSoon.tsx
10119
- var React52 = __toESM(require("react"), 1);
10231
+ var React53 = __toESM(require("react"), 1);
10120
10232
  var import_react_dom6 = require("react-dom");
10121
10233
  var import_jsx_runtime77 = require("react/jsx-runtime");
10122
10234
  var BYPASS_STORE = "fd.soon.bypass.v1";
@@ -10134,8 +10246,8 @@ function writeBypassed(list) {
10134
10246
  }
10135
10247
  }
10136
10248
  function useBypass(key) {
10137
- const [on, setOn] = React52.useState(() => !!key && readBypassed().indexOf(key) >= 0);
10138
- React52.useEffect(() => {
10249
+ const [on, setOn] = React53.useState(() => !!key && readBypassed().indexOf(key) >= 0);
10250
+ React53.useEffect(() => {
10139
10251
  setOn(!!key && readBypassed().indexOf(key) >= 0);
10140
10252
  }, [key]);
10141
10253
  const set = (next) => {
@@ -10182,9 +10294,9 @@ function SoonCard({ label, detail, backend, eta, effort, onRoadmap, allowed, onB
10182
10294
  ] });
10183
10295
  }
10184
10296
  function useHoverCard(open) {
10185
- const anchor = React52.useRef(null);
10186
- const [pos, setPos] = React52.useState(null);
10187
- React52.useLayoutEffect(() => {
10297
+ const anchor = React53.useRef(null);
10298
+ const [pos, setPos] = React53.useState(null);
10299
+ React53.useLayoutEffect(() => {
10188
10300
  if (!open || !anchor.current) {
10189
10301
  setPos(null);
10190
10302
  return;
@@ -10311,10 +10423,10 @@ function ComingSoon({
10311
10423
  ] });
10312
10424
  }
10313
10425
  function InlineSoon({ label, detail, backend, eta, effort, onRoadmap, allowed, onBypass, blur, tip, className, rest, children }) {
10314
- const [open, setOpen] = React52.useState(false);
10426
+ const [open, setOpen] = React53.useState(false);
10315
10427
  const [anchor, pos] = useHoverCard(open);
10316
10428
  const zIndex = useOverlayLayer(open);
10317
- const close = React52.useRef(null);
10429
+ const close = React53.useRef(null);
10318
10430
  const show = () => {
10319
10431
  if (close.current) {
10320
10432
  clearTimeout(close.current);
@@ -10330,7 +10442,7 @@ function InlineSoon({ label, detail, backend, eta, effort, onRoadmap, allowed, o
10330
10442
  setOpen(false);
10331
10443
  }, 140);
10332
10444
  };
10333
- React52.useEffect(() => () => {
10445
+ React53.useEffect(() => () => {
10334
10446
  if (close.current) clearTimeout(close.current);
10335
10447
  }, []);
10336
10448
  return /* @__PURE__ */ (0, import_jsx_runtime77.jsxs)(
@@ -10501,14 +10613,14 @@ function PermissionHint({ perm, children }) {
10501
10613
  }
10502
10614
 
10503
10615
  // src/components/platform/ModeSwitch.tsx
10504
- var React53 = __toESM(require("react"), 1);
10616
+ var React54 = __toESM(require("react"), 1);
10505
10617
  var import_jsx_runtime79 = require("react/jsx-runtime");
10506
10618
  function ModeSwitch({ canToggle = false, requestCount = 0, onClearLog, renderLog, onOpenSpec, summary }) {
10507
10619
  const mode2 = useRuntimeMode();
10508
- const [open, setOpen] = React53.useState(false);
10620
+ const [open, setOpen] = React54.useState(false);
10509
10621
  const zIndex = useOverlayLayer(open);
10510
- const ref = React53.useRef(null);
10511
- React53.useEffect(() => {
10622
+ const ref = React54.useRef(null);
10623
+ React54.useEffect(() => {
10512
10624
  if (!open) return;
10513
10625
  const away = (e) => {
10514
10626
  if (ref.current && !ref.current.contains(e.target)) setOpen(false);
@@ -10764,7 +10876,7 @@ function SaturationDistribution({ campuses = [], floorBand, floorScore, onSelect
10764
10876
  }
10765
10877
 
10766
10878
  // src/components/planner/MixGap.tsx
10767
- var React54 = __toESM(require("react"), 1);
10879
+ var React55 = __toESM(require("react"), 1);
10768
10880
  var import_jsx_runtime82 = require("react/jsx-runtime");
10769
10881
  var MIX_GAP_LAYOUT = {
10770
10882
  trackHeight: 30,
@@ -10779,7 +10891,7 @@ function mixGapOffset(value, max) {
10779
10891
  }
10780
10892
  function MixGap({ rows = [], loading = false, className = "" }) {
10781
10893
  const max = Math.max(1, ...rows.flatMap((r) => [r.target, r.realized]));
10782
- const [hover, setHover] = React54.useState(null);
10894
+ const [hover, setHover] = React55.useState(null);
10783
10895
  const toneOf = (gap) => gap >= -1 ? "ok" : gap >= -4 ? "warn" : "danger";
10784
10896
  const TONE = { ok: "var(--ok-solid)", warn: "var(--warn-solid)", danger: "var(--danger-solid)" };
10785
10897
  const { trackHeight, barHeight, targetWidth, labelGap } = MIX_GAP_LAYOUT;
@@ -10922,7 +11034,7 @@ function ChannelContribution({
10922
11034
  }
10923
11035
 
10924
11036
  // src/components/planner/BudgetReallocator.tsx
10925
- var React55 = __toESM(require("react"), 1);
11037
+ var React56 = __toESM(require("react"), 1);
10926
11038
  var import_jsx_runtime84 = require("react/jsx-runtime");
10927
11039
  var bandFor = (crp) => crp >= 200 ? "dominant" : crp >= 100 ? "strong" : crp >= 50 ? "adequate" : "weak";
10928
11040
  function BudgetReallocator({
@@ -10938,8 +11050,8 @@ function BudgetReallocator({
10938
11050
  onCancel,
10939
11051
  className = ""
10940
11052
  }) {
10941
- const [draft, setDraft] = React55.useState(spend);
10942
- React55.useEffect(() => setDraft(spend), [spend]);
11053
+ const [draft, setDraft] = React56.useState(spend);
11054
+ React56.useEffect(() => setDraft(spend), [spend]);
10943
11055
  const dirty = draft !== spend;
10944
11056
  const nextCrp = scoreFor ? scoreFor(draft) : crp;
10945
11057
  const nextBand = bandFor(nextCrp);
@@ -10954,10 +11066,10 @@ function BudgetReallocator({
10954
11066
  setDraft(spend);
10955
11067
  if (onCancel) onCancel();
10956
11068
  };
10957
- const trackRef = React55.useRef(null);
10958
- const chipRef = React55.useRef(null);
10959
- const [chipLeft, setChipLeft] = React55.useState(null);
10960
- React55.useLayoutEffect(() => {
11069
+ const trackRef = React56.useRef(null);
11070
+ const chipRef = React56.useRef(null);
11071
+ const [chipLeft, setChipLeft] = React56.useState(null);
11072
+ React56.useLayoutEffect(() => {
10961
11073
  const track = trackRef.current;
10962
11074
  if (!dirty || !track) {
10963
11075
  setChipLeft(null);
@@ -11144,7 +11256,7 @@ function ImportanceTag({ level, showLabel = true, size = "sm", className = "" })
11144
11256
  }
11145
11257
 
11146
11258
  // src/components/planner/PreferenceMeter.tsx
11147
- var React56 = __toESM(require("react"), 1);
11259
+ var React57 = __toESM(require("react"), 1);
11148
11260
  var import_jsx_runtime87 = require("react/jsx-runtime");
11149
11261
  function preferenceScore(criteria) {
11150
11262
  const earned = criteria.reduce((n, c) => n + (Number(c.earned) || 0), 0);
@@ -11174,7 +11286,7 @@ function PreferenceMeter({
11174
11286
  className = ""
11175
11287
  }) {
11176
11288
  const value = score == null ? preferenceScore(criteria) : score;
11177
- const segments = React56.useMemo(() => preferenceSegments(criteria), [criteria]);
11289
+ const segments = React57.useMemo(() => preferenceSegments(criteria), [criteria]);
11178
11290
  return /* @__PURE__ */ (0, import_jsx_runtime87.jsx)(
11179
11291
  ScoreMeter,
11180
11292
  {
@@ -11213,10 +11325,10 @@ function PreferenceMeter({
11213
11325
  }
11214
11326
 
11215
11327
  // src/components/chat/AgentChatPanel.tsx
11216
- var React62 = __toESM(require("react"), 1);
11328
+ var React63 = __toESM(require("react"), 1);
11217
11329
 
11218
11330
  // src/components/chat/chatEngine.ts
11219
- var React57 = __toESM(require("react"), 1);
11331
+ var React58 = __toESM(require("react"), 1);
11220
11332
  var CHAT_UNAVAILABLE = "chat_unavailable";
11221
11333
  var JOB_PENDING = ["queued", "running"];
11222
11334
  var JOB_SUCCESS = ["completed", "recovered"];
@@ -11270,22 +11382,22 @@ function useChatEngine(opts) {
11270
11382
  onClear,
11271
11383
  onFeedback
11272
11384
  } = opts || {};
11273
- const [status, setStatus] = React57.useState("idle");
11274
- const [threadId, setThreadId] = React57.useState(null);
11275
- const [messages, setMessages] = React57.useState([]);
11276
- const [queue, setQueue] = React57.useState([]);
11277
- const [fatal, setFatal] = React57.useState(null);
11278
- const [busy, setBusy] = React57.useState(false);
11279
- const [turnStartedAt, setTurnStartedAt] = React57.useState(null);
11280
- const listRef = React57.useRef([]);
11281
- const queueRef = React57.useRef([]);
11282
- const busyRef = React57.useRef(false);
11283
- const stoppedRef = React57.useRef(false);
11284
- const abortRef = React57.useRef(null);
11285
- const serverCount = React57.useRef(0);
11286
- const threadRef = React57.useRef(null);
11287
- const mounted = React57.useRef(true);
11288
- React57.useEffect(() => {
11385
+ const [status, setStatus] = React58.useState("idle");
11386
+ const [threadId, setThreadId] = React58.useState(null);
11387
+ const [messages, setMessages] = React58.useState([]);
11388
+ const [queue, setQueue] = React58.useState([]);
11389
+ const [fatal, setFatal] = React58.useState(null);
11390
+ const [busy, setBusy] = React58.useState(false);
11391
+ const [turnStartedAt, setTurnStartedAt] = React58.useState(null);
11392
+ const listRef = React58.useRef([]);
11393
+ const queueRef = React58.useRef([]);
11394
+ const busyRef = React58.useRef(false);
11395
+ const stoppedRef = React58.useRef(false);
11396
+ const abortRef = React58.useRef(null);
11397
+ const serverCount = React58.useRef(0);
11398
+ const threadRef = React58.useRef(null);
11399
+ const mounted = React58.useRef(true);
11400
+ React58.useEffect(() => {
11289
11401
  mounted.current = true;
11290
11402
  return () => {
11291
11403
  mounted.current = false;
@@ -11307,14 +11419,14 @@ function useChatEngine(opts) {
11307
11419
  }
11308
11420
  return false;
11309
11421
  };
11310
- const loadThread = React57.useCallback(async (id) => {
11422
+ const loadThread = React58.useCallback(async (id) => {
11311
11423
  const data = await apiAdapter.getThread(id);
11312
11424
  const list = [...data && data.messages || []];
11313
11425
  serverCount.current = list.length;
11314
11426
  commit(list);
11315
11427
  return list;
11316
11428
  }, [apiAdapter]);
11317
- React57.useEffect(() => {
11429
+ React58.useEffect(() => {
11318
11430
  if (!apiAdapter) {
11319
11431
  setStatus("idle");
11320
11432
  setFatal(null);
@@ -11527,7 +11639,7 @@ function useChatEngine(opts) {
11527
11639
  await dispatchTurn(turn);
11528
11640
  }
11529
11641
  }
11530
- const send = React57.useCallback((text, attachments) => {
11642
+ const send = React58.useCallback((text, attachments) => {
11531
11643
  const body = (text || "").trim();
11532
11644
  if (!body && !(attachments && attachments.length)) return;
11533
11645
  if (status === "disconnected") return;
@@ -11537,7 +11649,7 @@ function useChatEngine(opts) {
11537
11649
  stoppedRef.current = false;
11538
11650
  drain();
11539
11651
  }, [status]);
11540
- const stop = React57.useCallback(() => {
11652
+ const stop = React58.useCallback(() => {
11541
11653
  stoppedRef.current = true;
11542
11654
  const ac = abortRef.current;
11543
11655
  if (ac) {
@@ -11556,11 +11668,11 @@ function useChatEngine(opts) {
11556
11668
  store.del(STORAGE_PREFIX + threadRef.current);
11557
11669
  }
11558
11670
  }, [apiAdapter]);
11559
- const removeQueued = React57.useCallback((id) => {
11671
+ const removeQueued = React58.useCallback((id) => {
11560
11672
  queueRef.current = queueRef.current.filter((t) => t.id !== id);
11561
11673
  setQueue(queueRef.current.slice());
11562
11674
  }, []);
11563
- const retry = React57.useCallback(() => {
11675
+ const retry = React58.useCallback(() => {
11564
11676
  const list = listRef.current;
11565
11677
  let at = -1;
11566
11678
  for (let i = list.length - 1; i >= 0; i--) if (list[i].role === "user") {
@@ -11576,19 +11688,19 @@ function useChatEngine(opts) {
11576
11688
  setQueue(queueRef.current.slice());
11577
11689
  drain();
11578
11690
  }, []);
11579
- const clear = React57.useCallback(() => {
11691
+ const clear = React58.useCallback(() => {
11580
11692
  commit([]);
11581
11693
  serverCount.current = 0;
11582
11694
  queueRef.current = [];
11583
11695
  setQueue([]);
11584
11696
  onClear && onClear();
11585
11697
  }, [onClear]);
11586
- const setFeedback = React57.useCallback((id, value) => {
11698
+ const setFeedback = React58.useCallback((id, value) => {
11587
11699
  patch(id, (m) => ({ feedback: m.feedback === value ? null : value }));
11588
11700
  const msg = listRef.current.find((m) => m.id === id);
11589
11701
  onFeedback && onFeedback({ message: msg, feedback: msg ? msg.feedback : value });
11590
11702
  }, [onFeedback]);
11591
- const reload = React57.useCallback(async () => {
11703
+ const reload = React58.useCallback(async () => {
11592
11704
  if (!threadRef.current) return;
11593
11705
  setStatus("loading");
11594
11706
  try {
@@ -11626,10 +11738,10 @@ var ChatKit = {
11626
11738
  };
11627
11739
 
11628
11740
  // src/components/chat/ChatTranscript.tsx
11629
- var React59 = __toESM(require("react"), 1);
11741
+ var React60 = __toESM(require("react"), 1);
11630
11742
 
11631
11743
  // src/components/chat/ChatTurn.tsx
11632
- var React58 = __toESM(require("react"), 1);
11744
+ var React59 = __toESM(require("react"), 1);
11633
11745
  var import_jsx_runtime88 = require("react/jsx-runtime");
11634
11746
  function JsonView({ value }) {
11635
11747
  let text;
@@ -11666,7 +11778,7 @@ function PacketCard({ packet, schema, render, onApply, applied }) {
11666
11778
  ] });
11667
11779
  }
11668
11780
  function ThinkingBlock({ text, durationMs, streaming, defaultOpen = false }) {
11669
- const [open, setOpen] = React58.useState(defaultOpen);
11781
+ const [open, setOpen] = React59.useState(defaultOpen);
11670
11782
  if (!text) return null;
11671
11783
  return /* @__PURE__ */ (0, import_jsx_runtime88.jsxs)("div", { className: "fdc-think" + (open ? " is-open" : ""), children: [
11672
11784
  /* @__PURE__ */ (0, import_jsx_runtime88.jsxs)("button", { type: "button", className: "fdc-think-head", onClick: () => setOpen((v) => !v), "aria-expanded": open, children: [
@@ -11683,7 +11795,7 @@ function ThinkingBlock({ text, durationMs, streaming, defaultOpen = false }) {
11683
11795
  ] });
11684
11796
  }
11685
11797
  function Citations({ items = [], onOpen }) {
11686
- const [open, setOpen] = React58.useState(false);
11798
+ const [open, setOpen] = React59.useState(false);
11687
11799
  if (!items.length) return null;
11688
11800
  return /* @__PURE__ */ (0, import_jsx_runtime88.jsxs)("div", { className: "fdc-cites", children: [
11689
11801
  /* @__PURE__ */ (0, import_jsx_runtime88.jsxs)("button", { type: "button", className: "fdc-cites-head", onClick: () => setOpen((v) => !v), "aria-expanded": open, children: [
@@ -11709,7 +11821,7 @@ function clampText(text, max) {
11709
11821
  return (at > max * 0.6 ? cut.slice(0, at) : cut).trimEnd() + "\u2026";
11710
11822
  }
11711
11823
  function MessageBody({ message: m, ctx }) {
11712
- const [expanded, setExpanded] = React58.useState(false);
11824
+ const [expanded, setExpanded] = React59.useState(false);
11713
11825
  const isUser = m.role === "user";
11714
11826
  const raw = m.text || "";
11715
11827
  const clamped = !expanded && !m.streaming ? clampText(raw, ctx.maxVisibleChars) : null;
@@ -11776,9 +11888,9 @@ function MessageBody({ message: m, ctx }) {
11776
11888
  ] });
11777
11889
  }
11778
11890
  function useCopyRun() {
11779
- const [done, setDone] = React58.useState(false);
11780
- const t = React58.useRef(null);
11781
- React58.useEffect(() => () => {
11891
+ const [done, setDone] = React59.useState(false);
11892
+ const t = React59.useRef(null);
11893
+ React59.useEffect(() => () => {
11782
11894
  if (t.current) clearTimeout(t.current);
11783
11895
  }, []);
11784
11896
  return [done, (text) => {
@@ -11805,7 +11917,7 @@ function RunActions({ group, ctx }) {
11805
11917
  ] }),
11806
11918
  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,
11807
11919
  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,
11808
- isAssistant && ctx.onFeedback ? /* @__PURE__ */ (0, import_jsx_runtime88.jsxs)(React58.Fragment, { children: [
11920
+ isAssistant && ctx.onFeedback ? /* @__PURE__ */ (0, import_jsx_runtime88.jsxs)(React59.Fragment, { children: [
11809
11921
  /* @__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" }) }),
11810
11922
  /* @__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" }) })
11811
11923
  ] }) : null,
@@ -11900,10 +12012,10 @@ function ChatTranscript({
11900
12012
  renderEmpty,
11901
12013
  className = ""
11902
12014
  }) {
11903
- const scroller = React59.useRef(null);
11904
- const stick = React59.useRef(true);
11905
- const [pill, setPill] = React59.useState(0);
11906
- const seen = React59.useRef(0);
12015
+ const scroller = React60.useRef(null);
12016
+ const stick = React60.useRef(true);
12017
+ const [pill, setPill] = React60.useState(0);
12018
+ const seen = React60.useRef(0);
11907
12019
  const toBottom = (smooth) => {
11908
12020
  const el = scroller.current;
11909
12021
  if (!el) return;
@@ -11922,7 +12034,7 @@ function ChatTranscript({
11922
12034
  seen.current = messages.length;
11923
12035
  }
11924
12036
  };
11925
- React59.useLayoutEffect(() => {
12037
+ React60.useLayoutEffect(() => {
11926
12038
  const el = scroller.current;
11927
12039
  if (!el) return;
11928
12040
  if (stick.current) {
@@ -11930,7 +12042,7 @@ function ChatTranscript({
11930
12042
  seen.current = messages.length;
11931
12043
  } else setPill(Math.max(0, messages.length - seen.current));
11932
12044
  }, [messages]);
11933
- React59.useEffect(() => {
12045
+ React60.useEffect(() => {
11934
12046
  const el = scroller.current;
11935
12047
  const inner = el && el.firstChild;
11936
12048
  if (!el || !inner || typeof ResizeObserver === "undefined") return;
@@ -11940,7 +12052,7 @@ function ChatTranscript({
11940
12052
  ro.observe(inner);
11941
12053
  return () => ro.disconnect();
11942
12054
  }, []);
11943
- const groups = React59.useMemo(() => groupMessages(messages), [messages]);
12055
+ const groups = React60.useMemo(() => groupMessages(messages), [messages]);
11944
12056
  const empty = !messages.length && status === "ready";
11945
12057
  return /* @__PURE__ */ (0, import_jsx_runtime89.jsxs)("div", { className: ["fdc-scroll", className].filter(Boolean).join(" "), ref: scroller, onScroll, children: [
11946
12058
  /* @__PURE__ */ (0, import_jsx_runtime89.jsxs)("div", { className: "fdc-log", role: "log", "aria-label": "Conversation", children: [
@@ -11964,7 +12076,7 @@ function ChatTranscript({
11964
12076
  const prev = groups[i - 1];
11965
12077
  const k = dayKey(g.messages[0].timestamp);
11966
12078
  const showDay = !!k && (!prev || dayKey(prev.messages[0].timestamp) !== k);
11967
- return /* @__PURE__ */ (0, import_jsx_runtime89.jsxs)(React59.Fragment, { children: [
12079
+ return /* @__PURE__ */ (0, import_jsx_runtime89.jsxs)(React60.Fragment, { children: [
11968
12080
  showDay ? /* @__PURE__ */ (0, import_jsx_runtime89.jsx)("div", { className: "fdc-day", children: /* @__PURE__ */ (0, import_jsx_runtime89.jsx)("span", { children: dayLabel(k) }) }) : null,
11969
12081
  /* @__PURE__ */ (0, import_jsx_runtime89.jsx)(ChatTurn, { group: g, ctx })
11970
12082
  ] }, g.key || i);
@@ -11981,7 +12093,7 @@ function ChatTranscript({
11981
12093
  var TranscriptKit = { groupMessages };
11982
12094
 
11983
12095
  // src/components/chat/ChatComposer.tsx
11984
- var React60 = __toESM(require("react"), 1);
12096
+ var React61 = __toESM(require("react"), 1);
11985
12097
  var import_jsx_runtime90 = require("react/jsx-runtime");
11986
12098
  function ChatComposer({
11987
12099
  onSubmit,
@@ -12009,17 +12121,17 @@ function ChatComposer({
12009
12121
  onReject,
12010
12122
  onOpenAttachment
12011
12123
  }) {
12012
- const [text, setText] = React60.useState(draft || "");
12013
- const [trigger, setTrigger] = React60.useState(null);
12014
- const [mentionItems, setMentionItems] = React60.useState([]);
12015
- const [listening, setListening] = React60.useState(false);
12016
- const [notice, setNotice] = React60.useState(null);
12017
- const editor = React60.useRef(null);
12018
- const wrap = React60.useRef(null);
12019
- const stopVoice = React60.useRef(null);
12124
+ const [text, setText] = React61.useState(draft || "");
12125
+ const [trigger, setTrigger] = React61.useState(null);
12126
+ const [mentionItems, setMentionItems] = React61.useState([]);
12127
+ const [listening, setListening] = React61.useState(false);
12128
+ const [notice, setNotice] = React61.useState(null);
12129
+ const editor = React61.useRef(null);
12130
+ const wrap = React61.useRef(null);
12131
+ const stopVoice = React61.useRef(null);
12020
12132
  const staged = useStagedFiles(fileUploadHandler, { onError: () => {
12021
12133
  } });
12022
- React60.useEffect(() => {
12134
+ React61.useEffect(() => {
12023
12135
  if (draft != null && draft !== text) setText(draft);
12024
12136
  }, [draft]);
12025
12137
  const change = (v) => {
@@ -12055,7 +12167,7 @@ function ChatComposer({
12055
12167
  e.preventDefault();
12056
12168
  staged.add(found.files);
12057
12169
  };
12058
- React60.useEffect(() => {
12170
+ React61.useEffect(() => {
12059
12171
  if (!trigger || trigger.type !== "mention" || !mentionSources) {
12060
12172
  setMentionItems([]);
12061
12173
  return;
@@ -12073,7 +12185,7 @@ function ChatComposer({
12073
12185
  const q = (trigger.query || "").toLowerCase();
12074
12186
  setMentionItems(mentionSources.filter((m) => !q || (m.label + " " + (m.description || "")).toLowerCase().includes(q)));
12075
12187
  }, [trigger, mentionSources]);
12076
- const slashItems = React60.useMemo(() => {
12188
+ const slashItems = React61.useMemo(() => {
12077
12189
  if (!trigger || trigger.type !== "slash" || !slashCommands) return [];
12078
12190
  const q = (trigger.query || "").toLowerCase();
12079
12191
  return slashCommands.filter((c) => !q || (c.id + " " + c.label + " " + (c.description || "")).toLowerCase().includes(q));
@@ -12247,12 +12359,12 @@ function ChatComposer({
12247
12359
  }
12248
12360
 
12249
12361
  // src/components/chat/ChatSessionBar.tsx
12250
- var React61 = __toESM(require("react"), 1);
12362
+ var React62 = __toESM(require("react"), 1);
12251
12363
  var import_jsx_runtime91 = require("react/jsx-runtime");
12252
12364
  var compact2 = meterFormats.compact;
12253
12365
  function ChatSessionBar({ sessionStats, contextUsage, usageLimits, onClear, extras }) {
12254
- const [open, setOpen] = React61.useState(false);
12255
- const anchor = React61.useRef(null);
12366
+ const [open, setOpen] = React62.useState(false);
12367
+ const anchor = React62.useRef(null);
12256
12368
  const stats = sessionStats || null;
12257
12369
  const cu = contextUsage || null;
12258
12370
  const limits = usageLimits || null;
@@ -12267,7 +12379,7 @@ function ChatSessionBar({ sessionStats, contextUsage, usageLimits, onClear, extr
12267
12379
  if (stats && stats.runningTasks) bits.push(stats.runningTasks + " running task" + (stats.runningTasks === 1 ? "" : "s"));
12268
12380
  if (cu) bits.push(pct + "% context");
12269
12381
  const expandable = !!(cu || limits);
12270
- return /* @__PURE__ */ (0, import_jsx_runtime91.jsxs)(React61.Fragment, { children: [
12382
+ return /* @__PURE__ */ (0, import_jsx_runtime91.jsxs)(React62.Fragment, { children: [
12271
12383
  /* @__PURE__ */ (0, import_jsx_runtime91.jsxs)("div", { className: "fdc-bar", children: [
12272
12384
  /* @__PURE__ */ (0, import_jsx_runtime91.jsxs)(
12273
12385
  "button",
@@ -12408,7 +12520,7 @@ function ModelControls({
12408
12520
  ] })
12409
12521
  });
12410
12522
  }
12411
- return /* @__PURE__ */ (0, import_jsx_runtime91.jsxs)(React61.Fragment, { children: [
12523
+ return /* @__PURE__ */ (0, import_jsx_runtime91.jsxs)(React62.Fragment, { children: [
12412
12524
  /* @__PURE__ */ (0, import_jsx_runtime91.jsx)(
12413
12525
  MenuButton,
12414
12526
  {
@@ -12525,11 +12637,11 @@ function AgentChatPanel({
12525
12637
  onFeedback,
12526
12638
  onEditMessage
12527
12639
  }) {
12528
- const [panelWidth, setPanelWidth] = React62.useState(width);
12529
- const [applied, setApplied] = React62.useState({});
12530
- const [draft, setDraft] = React62.useState("");
12531
- const dragging = React62.useRef(null);
12532
- React62.useEffect(() => setPanelWidth(width), [width]);
12640
+ const [panelWidth, setPanelWidth] = React63.useState(width);
12641
+ const [applied, setApplied] = React63.useState({});
12642
+ const [draft, setDraft] = React63.useState("");
12643
+ const dragging = React63.useRef(null);
12644
+ React63.useEffect(() => setPanelWidth(width), [width]);
12533
12645
  const engine = useChatEngine({
12534
12646
  contextType,
12535
12647
  contextId,
@@ -12733,7 +12845,7 @@ function AgentChatPanel({
12733
12845
  }
12734
12846
 
12735
12847
  // src/components/files/FileViewer.tsx
12736
- var React63 = __toESM(require("react"), 1);
12848
+ var React64 = __toESM(require("react"), 1);
12737
12849
  var import_jsx_runtime93 = require("react/jsx-runtime");
12738
12850
  function previewKindOf(file) {
12739
12851
  const mime = (file.mime || "").toLowerCase();
@@ -12790,13 +12902,13 @@ function parseDelimited(text, delimiter) {
12790
12902
  return rows;
12791
12903
  }
12792
12904
  function usePreview(file, kind, resolveUrl) {
12793
- const [state, setState] = React63.useState({ status: "loading" });
12794
- const [attempt, setAttempt] = React63.useState(0);
12795
- const resolveRef = React63.useRef(resolveUrl);
12796
- React63.useEffect(() => {
12905
+ const [state, setState] = React64.useState({ status: "loading" });
12906
+ const [attempt, setAttempt] = React64.useState(0);
12907
+ const resolveRef = React64.useRef(resolveUrl);
12908
+ React64.useEffect(() => {
12797
12909
  resolveRef.current = resolveUrl;
12798
12910
  }, [resolveUrl]);
12799
- React63.useEffect(() => {
12911
+ React64.useEffect(() => {
12800
12912
  if (kind === "none") {
12801
12913
  setState({ status: "ready" });
12802
12914
  return;
@@ -12826,7 +12938,7 @@ function usePreview(file, kind, resolveUrl) {
12826
12938
  if (ac) ac.abort();
12827
12939
  };
12828
12940
  }, [file.id, kind, attempt]);
12829
- return { ...state, retry: React63.useCallback(() => setAttempt((a) => a + 1), []) };
12941
+ return { ...state, retry: React64.useCallback(() => setAttempt((a) => a + 1), []) };
12830
12942
  }
12831
12943
  function PreviewBody({ file, kind, state }) {
12832
12944
  if (kind === "image") return /* @__PURE__ */ (0, import_jsx_runtime93.jsx)("img", { className: "fd-fv-image", src: state.url, alt: file.name || "Preview" });
@@ -12871,13 +12983,13 @@ function PreviewBody({ file, kind, state }) {
12871
12983
  ] });
12872
12984
  }
12873
12985
  function FileViewer({ file, resolveUrl, sidePanel, sidePanelLabel = "Details", onClose, actions, className = "" }) {
12874
- const kind = React63.useMemo(() => previewKindOf(file), [file]);
12986
+ const kind = React64.useMemo(() => previewKindOf(file), [file]);
12875
12987
  const preview = usePreview(file, kind, resolveUrl);
12876
- const [tab, setTab] = React63.useState("preview");
12877
- const [downloading, setDownloading] = React63.useState(false);
12878
- const [downloadError, setDownloadError] = React63.useState(null);
12988
+ const [tab, setTab] = React64.useState("preview");
12989
+ const [downloading, setDownloading] = React64.useState(false);
12990
+ const [downloadError, setDownloadError] = React64.useState(null);
12879
12991
  const hasSide = sidePanel != null;
12880
- React63.useEffect(() => {
12992
+ React64.useEffect(() => {
12881
12993
  setTab("preview");
12882
12994
  }, [file.id]);
12883
12995
  const download = () => {
@@ -12944,7 +13056,7 @@ function FileViewer({ file, resolveUrl, sidePanel, sidePanelLabel = "Details", o
12944
13056
  }
12945
13057
 
12946
13058
  // src/components/files/FileBrowser.tsx
12947
- var React64 = __toESM(require("react"), 1);
13059
+ var React65 = __toESM(require("react"), 1);
12948
13060
  var import_jsx_runtime94 = require("react/jsx-runtime");
12949
13061
  function childrenOf(folders, parentId) {
12950
13062
  return folders.filter((f) => f.parentId === parentId).sort((a, b) => a.name.localeCompare(b.name));
@@ -13015,10 +13127,10 @@ function FolderPickerMenu({
13015
13127
  destinations,
13016
13128
  onPick
13017
13129
  }) {
13018
- const [open, setOpen] = React64.useState(false);
13130
+ const [open, setOpen] = React65.useState(false);
13019
13131
  const zIndex = useOverlayLayer(open);
13020
- const ref = React64.useRef(null);
13021
- React64.useEffect(() => {
13132
+ const ref = React65.useRef(null);
13133
+ React65.useEffect(() => {
13022
13134
  if (!open) return;
13023
13135
  const away = (e) => {
13024
13136
  if (ref.current && !ref.current.contains(e.target)) setOpen(false);
@@ -13070,8 +13182,8 @@ function FolderPickerMenu({
13070
13182
  ] });
13071
13183
  }
13072
13184
  function RowShell({ icon, name, meta, onOpen, draggableId, isDropTarget, onDropPayload, actions, className = "" }) {
13073
- const [over, setOver] = React64.useState(false);
13074
- const dragCounter = React64.useRef(0);
13185
+ const [over, setOver] = React65.useState(false);
13186
+ const dragCounter = React65.useRef(0);
13075
13187
  const dropHandlers = isDropTarget ? {
13076
13188
  onDragEnter: (e) => {
13077
13189
  if (!hasInternalPayload(e)) return;
@@ -13119,8 +13231,8 @@ function RowShell({ icon, name, meta, onOpen, draggableId, isDropTarget, onDropP
13119
13231
  }
13120
13232
  function TreeNode({ folder, depth, folders, currentFolderId, onNavigate, onMoveInto, canMove }) {
13121
13233
  const kids = childrenOf(folders, folder.id);
13122
- const [expanded, setExpanded] = React64.useState(() => currentFolderId != null && isSelfOrDescendant(folders, folder.id, currentFolderId));
13123
- React64.useEffect(() => {
13234
+ const [expanded, setExpanded] = React65.useState(() => currentFolderId != null && isSelfOrDescendant(folders, folder.id, currentFolderId));
13235
+ React65.useEffect(() => {
13124
13236
  if (currentFolderId != null && isSelfOrDescendant(folders, folder.id, currentFolderId)) setExpanded(true);
13125
13237
  }, [currentFolderId, folder.id, folders]);
13126
13238
  const isCurrent = folder.id === currentFolderId;
@@ -13186,15 +13298,15 @@ function FileBrowser({
13186
13298
  const canUpload = perm.canUpload !== false && !!onUpload;
13187
13299
  const canRemoveFile = perm.canRemoveFile !== false && !!onRemoveFile;
13188
13300
  const canDeleteFolder = perm.canDeleteFolder !== false && !!onDeleteFolder;
13189
- const [createOpen, setCreateOpen] = React64.useState(false);
13190
- const [createName, setCreateName] = React64.useState("");
13191
- const [renameTarget, setRenameTarget] = React64.useState(null);
13192
- const [renameValue, setRenameValue] = React64.useState("");
13193
- const [deleteTarget, setDeleteTarget] = React64.useState(null);
13194
- const uploadInputRef = React64.useRef(null);
13195
- const crumbFolders = React64.useMemo(() => ancestorsOf(folders, currentFolderId), [folders, currentFolderId]);
13196
- const subfolders = React64.useMemo(() => childrenOf(folders, currentFolderId), [folders, currentFolderId]);
13197
- const currentFiles = React64.useMemo(
13301
+ const [createOpen, setCreateOpen] = React65.useState(false);
13302
+ const [createName, setCreateName] = React65.useState("");
13303
+ const [renameTarget, setRenameTarget] = React65.useState(null);
13304
+ const [renameValue, setRenameValue] = React65.useState("");
13305
+ const [deleteTarget, setDeleteTarget] = React65.useState(null);
13306
+ const uploadInputRef = React65.useRef(null);
13307
+ const crumbFolders = React65.useMemo(() => ancestorsOf(folders, currentFolderId), [folders, currentFolderId]);
13308
+ const subfolders = React65.useMemo(() => childrenOf(folders, currentFolderId), [folders, currentFolderId]);
13309
+ const currentFiles = React65.useMemo(
13198
13310
  () => files.filter((f) => f.folderId === currentFolderId).sort((a, b) => a.name.localeCompare(b.name)),
13199
13311
  [files, currentFolderId]
13200
13312
  );
@@ -13426,8 +13538,8 @@ function BreadcrumbCrumb({
13426
13538
  isDropTarget,
13427
13539
  onDropPayload
13428
13540
  }) {
13429
- const [over, setOver] = React64.useState(false);
13430
- const dragCounter = React64.useRef(0);
13541
+ const [over, setOver] = React65.useState(false);
13542
+ const dragCounter = React65.useRef(0);
13431
13543
  const dropHandlers = isDropTarget ? {
13432
13544
  onDragEnter: (e) => {
13433
13545
  if (!hasInternalPayload(e)) return;
@@ -13456,7 +13568,7 @@ function BreadcrumbCrumb({
13456
13568
  }
13457
13569
 
13458
13570
  // src/kits/query.ts
13459
- var React65 = __toESM(require("react"), 1);
13571
+ var React66 = __toESM(require("react"), 1);
13460
13572
  var isMultiSelectShaped = (v) => !!v && typeof v === "object" && Array.isArray(v.values);
13461
13573
  var isRangeShaped = (v) => !!v && typeof v === "object" && ("min" in v || "max" in v);
13462
13574
  var isDateShaped = (v) => !!v && typeof v === "object" && "kind" in v;
@@ -13511,22 +13623,22 @@ function compare(a, b, dir) {
13511
13623
  var API = null;
13512
13624
  var PREFS = null;
13513
13625
  function useServerTable({ endpoint, params, defaults, deps, prefsKey }) {
13514
- const [query, setQuery] = React65.useState(() => {
13626
+ const [query, setQuery] = React66.useState(() => {
13515
13627
  const store = PREFS || window.PlannerPrefs;
13516
13628
  const saved = prefsKey && store ? store.getTable(prefsKey) : {};
13517
13629
  return { ...DEFAULTS, ...defaults || {}, ...saved.pageSize ? { pageSize: saved.pageSize } : {}, ...saved.sort ? { sort: saved.sort, dir: saved.dir || "desc" } : {} };
13518
13630
  });
13519
- const savePref = React65.useCallback((patch2) => {
13631
+ const savePref = React66.useCallback((patch2) => {
13520
13632
  const store = PREFS || window.PlannerPrefs;
13521
13633
  if (prefsKey && store) store.setTable(prefsKey, patch2);
13522
13634
  }, [prefsKey]);
13523
- const [res, setRes] = React65.useState(null);
13524
- const [loading, setLoading] = React65.useState(true);
13525
- const seq2 = React65.useRef(0);
13635
+ const [res, setRes] = React66.useState(null);
13636
+ const [loading, setLoading] = React66.useState(true);
13637
+ const seq2 = React66.useRef(0);
13526
13638
  const depKey = (deps || []).join("|");
13527
13639
  const paramKey = JSON.stringify(params || {});
13528
13640
  const queryKey = JSON.stringify(query);
13529
- React65.useEffect(() => {
13641
+ React66.useEffect(() => {
13530
13642
  const id = ++seq2.current;
13531
13643
  setLoading(true);
13532
13644
  const t = setTimeout(() => {
@@ -13845,12 +13957,12 @@ function createVersionStore(initialState, options) {
13845
13957
  }
13846
13958
 
13847
13959
  // src/kits/documentTitle.ts
13848
- var React66 = __toESM(require("react"), 1);
13960
+ var React67 = __toESM(require("react"), 1);
13849
13961
  function formatDocumentTitle(routeTitle, appName) {
13850
13962
  return [routeTitle, appName, "Flytedesk"].filter((part) => !!part && part.length > 0).join(" \xB7 ");
13851
13963
  }
13852
13964
  function useDocumentTitle(routeTitle, appName) {
13853
- React66.useEffect(() => {
13965
+ React67.useEffect(() => {
13854
13966
  if (typeof document === "undefined") return;
13855
13967
  document.title = formatDocumentTitle(routeTitle, appName);
13856
13968
  }, [routeTitle, appName]);