@flytedan/flytebot-design-system 0.33.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;
@@ -3226,7 +3233,7 @@ function NumberInput({
3226
3233
  }
3227
3234
 
3228
3235
  // src/components/forms/DatePicker.tsx
3229
- var React22 = __toESM(require("react"), 1);
3236
+ var React23 = __toESM(require("react"), 1);
3230
3237
  var import_jsx_runtime43 = require("react/jsx-runtime");
3231
3238
  var MONTHS = ["January", "February", "March", "April", "May", "June", "July", "August", "September", "October", "November", "December"];
3232
3239
  var DOW = ["Su", "Mo", "Tu", "We", "Th", "Fr", "Sa"];
@@ -3244,10 +3251,10 @@ function Calendar({ value, range = false, onPick, initialMonth, months = 1 }) {
3244
3251
  const today = /* @__PURE__ */ new Date();
3245
3252
  const sel = range ? value || {} : { start: value, end: value };
3246
3253
  const anchor = parse(sel.start) || parse(initialMonth) || today;
3247
- const [vy, setVy] = React22.useState(anchor.getFullYear());
3248
- const [vm, setVm] = React22.useState(anchor.getMonth());
3249
- const [mode2, setMode] = React22.useState("days");
3250
- const [hover, setHover] = React22.useState(null);
3254
+ const [vy, setVy] = React23.useState(anchor.getFullYear());
3255
+ const [vm, setVm] = React23.useState(anchor.getMonth());
3256
+ const [mode2, setMode] = React23.useState("days");
3257
+ const [hover, setHover] = React23.useState(null);
3251
3258
  const s = parse(sel.start), e = parse(sel.end);
3252
3259
  const hoverEnd = range && s && !e && hover ? parse(hover) : null;
3253
3260
  const inRange = (d) => {
@@ -3363,9 +3370,9 @@ function Calendar({ value, range = false, onPick, initialMonth, months = 1 }) {
3363
3370
  }
3364
3371
  function DatePicker({ label, help, error, required = false, disabled = false, range = false, value, onChange, placeholder, id, className = "", style, ...rest }) {
3365
3372
  const { fieldId, labelId, ariaLabelledBy } = useTriggerLabelling(label, id);
3366
- const [open, setOpen] = React22.useState(false);
3367
- const rootRef = React22.useRef(null);
3368
- const boxRef = React22.useRef(null);
3373
+ const [open, setOpen] = React23.useState(false);
3374
+ const rootRef = React23.useRef(null);
3375
+ const boxRef = React23.useRef(null);
3369
3376
  const display = range ? value && value.start ? fmt(value.start) + (value.end ? " \u2192 " + fmt(value.end) : " \u2192 \u2026") : "" : fmt(value);
3370
3377
  const toggle = () => {
3371
3378
  if (!disabled) setOpen(!open);
@@ -3443,9 +3450,9 @@ function Textarea({ label, help, error, required = false, rows = 4, disabled = f
3443
3450
  }
3444
3451
 
3445
3452
  // src/components/forms/listbox.ts
3446
- var React23 = __toESM(require("react"), 1);
3453
+ var React24 = __toESM(require("react"), 1);
3447
3454
  function useListboxNav({ count, onSelect }) {
3448
- const [active, setActive] = React23.useState(-1);
3455
+ const [active, setActive] = React24.useState(-1);
3449
3456
  return {
3450
3457
  active,
3451
3458
  setActive,
@@ -3458,7 +3465,7 @@ function useListboxNav({ count, onSelect }) {
3458
3465
  };
3459
3466
  }
3460
3467
  function useListboxScrollIntoView(active, listRef, enabled) {
3461
- React23.useEffect(() => {
3468
+ React24.useEffect(() => {
3462
3469
  if (!enabled || active < 0 || !listRef.current) return;
3463
3470
  const list = listRef.current;
3464
3471
  const el = list.querySelector('[data-i="' + active + '"]');
@@ -3645,40 +3652,40 @@ function MultiSelectPanel({
3645
3652
  onClose
3646
3653
  }) {
3647
3654
  const allowedOps = operatorsFor(field);
3648
- const [draftOperator, setDraftOperator] = React24.useState(value?.operator ?? allowedOps[0]);
3655
+ const [draftOperator, setDraftOperator] = React25.useState(value?.operator ?? allowedOps[0]);
3649
3656
  const operator = allowedOps.length === 1 ? allowedOps[0] : value?.operator ?? draftOperator;
3650
3657
  const selected = value?.values ?? [];
3651
- const selectedRef = React24.useRef(selected);
3652
- selectedRef.current = selected;
3653
- const operatorRef = React24.useRef(operator);
3654
- operatorRef.current = operator;
3655
- const mountedRef = React24.useRef(true);
3656
- React24.useEffect(() => {
3658
+ const selectedRef = useLatest(selected);
3659
+ const operatorRef = useLatest(operator);
3660
+ const mountedRef = React25.useRef(true);
3661
+ React25.useEffect(() => {
3657
3662
  mountedRef.current = true;
3658
3663
  return () => {
3659
3664
  mountedRef.current = false;
3660
3665
  };
3661
3666
  }, []);
3662
- const commit = (nextValues, nextOperator = operator) => onCommit({ operator: nextOperator, values: nextValues });
3667
+ const commit = (nextValues, nextOperator = operatorRef.current) => {
3668
+ setDraftOperator(nextOperator);
3669
+ return onCommit({ operator: nextOperator, values: nextValues });
3670
+ };
3663
3671
  const setOperator = (op) => {
3664
- setDraftOperator(op);
3665
3672
  if (selectedRef.current.length > 0) commit(selectedRef.current, op);
3673
+ else setDraftOperator(op);
3666
3674
  };
3667
- const [mode2, setMode] = React24.useState("search");
3668
- const [query, setQuery] = React24.useState("");
3669
- const [asyncState, setAsyncState] = React24.useState(
3675
+ const [mode2, setMode] = React25.useState("search");
3676
+ const [query, setQuery] = React25.useState("");
3677
+ const [asyncState, setAsyncState] = React25.useState(
3670
3678
  { options: null, loading: !!field.loadOptions, error: false }
3671
3679
  );
3672
- const [retryTick, setRetryTick] = React24.useState(0);
3673
- const inputRef = React24.useRef(null);
3674
- const listRef = React24.useRef(null);
3675
- const listId = React24.useId();
3676
- const loadOptionsRef = React24.useRef(field.loadOptions);
3677
- loadOptionsRef.current = field.loadOptions;
3678
- React24.useEffect(() => {
3680
+ const [retryTick, setRetryTick] = React25.useState(0);
3681
+ const inputRef = React25.useRef(null);
3682
+ const listRef = React25.useRef(null);
3683
+ const listId = React25.useId();
3684
+ const loadOptionsRef = useLatest(field.loadOptions);
3685
+ React25.useEffect(() => {
3679
3686
  inputRef.current?.focus();
3680
3687
  }, []);
3681
- React24.useEffect(() => {
3688
+ React25.useEffect(() => {
3682
3689
  const load = loadOptionsRef.current;
3683
3690
  if (!load) return;
3684
3691
  const controller = new AbortController();
@@ -3696,7 +3703,7 @@ function MultiSelectPanel({
3696
3703
  clearTimeout(t);
3697
3704
  controller.abort();
3698
3705
  };
3699
- }, [query, retryTick]);
3706
+ }, [query, retryTick, loadOptionsRef]);
3700
3707
  const options = field.loadOptions ? asyncState.options ?? [] : (field.options ?? []).filter((o) => o.label.toLowerCase().includes(query.toLowerCase()));
3701
3708
  const showLoading = !!field.loadOptions && asyncState.loading;
3702
3709
  const showError = !!field.loadOptions && asyncState.error;
@@ -3711,17 +3718,17 @@ function MultiSelectPanel({
3711
3718
  };
3712
3719
  const nav = useListboxNav({ count: options.length, onSelect: (i) => toggle(options[i]) });
3713
3720
  useListboxScrollIntoView(nav.active, listRef, hasListbox);
3714
- React24.useEffect(() => {
3721
+ React25.useEffect(() => {
3715
3722
  nav.setActive(0);
3716
3723
  }, [query, options.length]);
3717
3724
  const activeId = hasListbox && options[nav.active] ? listId + "-opt-" + nav.active : void 0;
3718
3725
  const liveMessage = showLoading ? "Loading\u2026" : showError ? "Couldn't load options." : options.length === 0 ? "No matches" : atLimit ? "Limit reached: at most " + field.maxValues + " values" : "";
3719
- const [pasteText, setPasteText] = React24.useState("");
3720
- const [pasteLoading, setPasteLoading] = React24.useState(false);
3721
- const [unmatchedTokens, setUnmatchedTokens] = React24.useState([]);
3722
- const [pasteError, setPasteError] = React24.useState(null);
3723
- const pasteWrapRef = React24.useRef(null);
3724
- React24.useEffect(() => {
3726
+ const [pasteText, setPasteText] = React25.useState("");
3727
+ const [pasteLoading, setPasteLoading] = React25.useState(false);
3728
+ const [unmatchedTokens, setUnmatchedTokens] = React25.useState([]);
3729
+ const [pasteError, setPasteError] = React25.useState(null);
3730
+ const pasteWrapRef = React25.useRef(null);
3731
+ React25.useEffect(() => {
3725
3732
  if (mode2 === "paste") pasteWrapRef.current?.querySelector("textarea")?.focus();
3726
3733
  }, [mode2]);
3727
3734
  const doResolve = () => {
@@ -3740,7 +3747,7 @@ function MultiSelectPanel({
3740
3747
  setPasteError("This filter allows at most " + field.maxValues + " values; adding this list would make " + merged.size + ".");
3741
3748
  return;
3742
3749
  }
3743
- const applied = commit(Array.from(merged.values()), operatorRef.current);
3750
+ const applied = commit(Array.from(merged.values()));
3744
3751
  if (!applied.ok) {
3745
3752
  setPasteError(applied.reason);
3746
3753
  return;
@@ -3882,10 +3889,9 @@ function MultiSelectPanel({
3882
3889
  );
3883
3890
  }
3884
3891
  function useTextValidity(onFlip) {
3885
- const invalidRef = React24.useRef(/* @__PURE__ */ new Set());
3886
- const [, rerender] = React24.useReducer((n) => n + 1, 0);
3887
- const onFlipRef = React24.useRef(onFlip);
3888
- onFlipRef.current = onFlip;
3892
+ const invalidRef = React25.useRef(/* @__PURE__ */ new Set());
3893
+ const [, rerender] = React25.useReducer((n) => n + 1, 0);
3894
+ const onFlipRef = useLatest(onFlip);
3889
3895
  const record = (name, valid) => {
3890
3896
  const invalid = invalidRef.current;
3891
3897
  if (valid !== invalid.has(name)) return false;
@@ -3902,6 +3908,12 @@ function useTextValidity(onFlip) {
3902
3908
  /** For an input that is about to unmount: it has nothing left to show. */
3903
3909
  forget: (name) => {
3904
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();
3905
3917
  }
3906
3918
  };
3907
3919
  }
@@ -3909,6 +3921,26 @@ function applicable(field, candidate, textValid) {
3909
3921
  if (!textValid || candidate === void 0) return void 0;
3910
3922
  return validateFilterValue(field, candidate).ok ? candidate : void 0;
3911
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 });
3912
3944
  function RangePanel({
3913
3945
  field,
3914
3946
  value,
@@ -3916,13 +3948,23 @@ function RangePanel({
3916
3948
  onCommit,
3917
3949
  onClose
3918
3950
  }) {
3919
- const [draft, setDraft] = React24.useState({ min: value?.min, max: value?.max });
3920
- const draftRef = React24.useRef(draft);
3921
- const publish = () => {
3951
+ const [draft, setDraft] = React25.useState(() => rangeDraft(value));
3952
+ const [seed, setSeed] = React25.useState(0);
3953
+ const draftRef = React25.useRef(draft);
3954
+ const shown = () => {
3922
3955
  const { min, max } = draftRef.current;
3923
- onCommit(applicable(field, min == null && max == null ? void 0 : { min, max }, validity.allValid()));
3956
+ return applicable(field, min == null && max == null ? void 0 : { min, max }, validity.allValid());
3957
+ };
3958
+ const publish = () => {
3959
+ onCommit(shown());
3924
3960
  };
3925
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
+ });
3926
3968
  const draftMin = draft.min;
3927
3969
  const draftMax = draft.max;
3928
3970
  const isEmpty = draftMin == null && draftMax == null;
@@ -3959,7 +4001,8 @@ function RangePanel({
3959
4001
  placeholder: field.minPlaceholder,
3960
4002
  onChange: (e) => apply({ min: e.target.value }),
3961
4003
  onValidityChange: validity.report("min")
3962
- }
4004
+ },
4005
+ "min-" + seed
3963
4006
  ),
3964
4007
  /* @__PURE__ */ (0, import_jsx_runtime45.jsx)(
3965
4008
  NumberInput,
@@ -3974,12 +4017,20 @@ function RangePanel({
3974
4017
  placeholder: field.maxPlaceholder,
3975
4018
  onChange: (e) => apply({ max: e.target.value }),
3976
4019
  onValidityChange: validity.report("max")
3977
- }
4020
+ },
4021
+ "max-" + seed
3978
4022
  )
3979
4023
  ] })
3980
4024
  }
3981
4025
  );
3982
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
+ }
3983
4034
  function DatePanel({
3984
4035
  field,
3985
4036
  value,
@@ -3987,23 +4038,41 @@ function DatePanel({
3987
4038
  onCommit,
3988
4039
  onClose
3989
4040
  }) {
3990
- const defaultDays = field.defaultDays ?? 30;
3991
4041
  const maxDays = effectiveMaxDays(field);
3992
- const [kind, setKind] = React24.useState(value?.kind ?? "withinDays");
3993
- const [daysDraft, setDaysDraft] = React24.useState(
3994
- value?.kind === "withinDays" ? value.days : defaultDays
3995
- );
3996
- const daysRef = React24.useRef(daysDraft);
3997
- const [between, setBetween] = React24.useState(
3998
- value?.kind === "between" ? { from: value.from, to: value.to } : { from: "", to: "" }
3999
- );
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);
4000
4049
  const shownWithinDays = () => {
4001
4050
  const days = daysRef.current;
4002
4051
  return applicable(field, days == null ? void 0 : { kind: "withinDays", days }, validity.allValid());
4003
4052
  };
4004
- const validity = useTextValidity(() => onCommit(shownWithinDays()));
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
+ });
4005
4073
  const applyWithinDays = (days) => {
4006
4074
  daysRef.current = days;
4075
+ daysConfirmed.current = true;
4007
4076
  setDaysDraft(days);
4008
4077
  onCommit(shownWithinDays());
4009
4078
  };
@@ -4018,8 +4087,10 @@ function DatePanel({
4018
4087
  setBetween({ from: "", to: "" });
4019
4088
  validity.forget("days");
4020
4089
  } else {
4021
- daysRef.current = defaultDays;
4022
- setDaysDraft(defaultDays);
4090
+ const { days } = dateDraft(field, void 0);
4091
+ daysRef.current = days;
4092
+ daysConfirmed.current = false;
4093
+ setDaysDraft(days);
4023
4094
  }
4024
4095
  onCommit(void 0);
4025
4096
  };
@@ -4067,7 +4138,8 @@ function DatePanel({
4067
4138
  value: daysDraft ?? "",
4068
4139
  onChange: (e) => applyWithinDays(e.target.value),
4069
4140
  onValidityChange: validity.report("days")
4070
- }
4141
+ },
4142
+ "days-" + seed
4071
4143
  ) : /* @__PURE__ */ (0, import_jsx_runtime45.jsx)(
4072
4144
  DatePicker,
4073
4145
  {
@@ -4075,30 +4147,23 @@ function DatePanel({
4075
4147
  label: "Date range",
4076
4148
  value: { start: between.from, end: between.to },
4077
4149
  onChange: (e) => applyBetween(e.target.value.start || "", e.target.value.end || "")
4078
- }
4150
+ },
4151
+ "between-" + seed
4079
4152
  )
4080
4153
  ] })
4081
4154
  }
4082
4155
  );
4083
4156
  }
4084
4157
  function FilterBar({ fields = [], filters, onFilterChange, onFilterRemove, align = "left", className = "", ...rest }) {
4085
- const [panel, setPanel] = React24.useState(null);
4086
- const editAnchorRef = React24.useRef(null);
4087
- const addAnchorRef = React24.useRef(null);
4088
- const textInputRef = React24.useRef(null);
4089
- const optionsRef = React24.useRef(null);
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);
4090
4163
  if (process.env.NODE_ENV !== "production") {
4091
4164
  for (const f of fields) assertValidFieldDefinition(f);
4092
4165
  }
4093
- const latest = React24.useRef({ fields, filters, onFilterChange, onFilterRemove });
4094
- const filtersProp = React24.useRef(filters);
4095
- if (filters !== filtersProp.current) {
4096
- filtersProp.current = filters;
4097
- latest.current.filters = filters;
4098
- }
4099
- latest.current.fields = fields;
4100
- latest.current.onFilterChange = onFilterChange;
4101
- latest.current.onFilterRemove = onFilterRemove;
4166
+ const latest = useLatest({ fields, filters, onFilterChange, onFilterRemove });
4102
4167
  const commit = (field, candidate) => {
4103
4168
  const current2 = latest.current.fields.find((f) => f.key === field.key);
4104
4169
  if (!current2) return { ok: false, reason: "This filter is no longer available" };
@@ -4107,24 +4172,17 @@ function FilterBar({ fields = [], filters, onFilterChange, onFilterRemove, align
4107
4172
  return { ok: true };
4108
4173
  }
4109
4174
  const result = validateFilterValue(current2, candidate);
4110
- if (result.ok) {
4111
- latest.current.filters = { ...latest.current.filters, [current2.key]: candidate };
4112
- latest.current.onFilterChange(current2.key, candidate);
4113
- }
4175
+ if (result.ok) latest.current.onFilterChange(current2.key, candidate);
4114
4176
  return result;
4115
4177
  };
4116
4178
  const removeField = (field) => {
4117
4179
  const { filters: now, onFilterRemove: remove } = latest.current;
4118
- if (!isFieldSet(field, now[field.key])) return;
4119
- const next = { ...now };
4120
- delete next[field.key];
4121
- latest.current.filters = next;
4122
- remove(field.key);
4180
+ if (isFieldSet(field, now[field.key])) remove(field.key);
4123
4181
  };
4124
4182
  const editingField = panel && panel.kind === "edit" ? fields.find((f) => f.key === panel.key) : void 0;
4125
4183
  const startEditing = (key) => setPanel({ kind: "edit", key });
4126
4184
  const closeEditing = () => setPanel(null);
4127
- React24.useEffect(() => {
4185
+ React25.useEffect(() => {
4128
4186
  if (!panel || panel.kind !== "edit") return;
4129
4187
  if (editingField?.type === "text") {
4130
4188
  textInputRef.current?.focus();
@@ -4330,7 +4388,7 @@ function StatTile({ label, value, sub, delta, invert = false, loading = false, c
4330
4388
  }
4331
4389
 
4332
4390
  // src/components/data/CodeBlock.tsx
4333
- var React25 = __toESM(require("react"), 1);
4391
+ var React26 = __toESM(require("react"), 1);
4334
4392
  var import_jsx_runtime47 = require("react/jsx-runtime");
4335
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)$/;
4336
4394
  var RULES = {
@@ -4486,13 +4544,13 @@ function tokenize(src, lang) {
4486
4544
  return out;
4487
4545
  }
4488
4546
  function Highlighted({ code, lang }) {
4489
- const toks = React25.useMemo(() => tokenize(code, lang), [code, lang]);
4547
+ const toks = React26.useMemo(() => tokenize(code, lang), [code, lang]);
4490
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) });
4491
4549
  }
4492
4550
  function useCopy() {
4493
- const [done, setDone] = React25.useState(false);
4494
- const timer = React25.useRef(null);
4495
- React25.useEffect(() => () => {
4551
+ const [done, setDone] = React26.useState(false);
4552
+ const timer = React26.useRef(null);
4553
+ React26.useEffect(() => () => {
4496
4554
  if (timer.current) clearTimeout(timer.current);
4497
4555
  }, []);
4498
4556
  const copy = (text) => {
@@ -4528,8 +4586,8 @@ function CodeBlock({
4528
4586
  actions,
4529
4587
  className = ""
4530
4588
  }) {
4531
- const [wrap, setWrap] = React25.useState(!!wrapDefault);
4532
- const [open, setOpen] = React25.useState(false);
4589
+ const [wrap, setWrap] = React26.useState(!!wrapDefault);
4590
+ const [open, setOpen] = React26.useState(false);
4533
4591
  const [copied, copy] = useCopy();
4534
4592
  const body = String(code).replace(/\n$/, "");
4535
4593
  const lines = body.split("\n");
@@ -4558,7 +4616,7 @@ function CodeBlock({
4558
4616
  ] });
4559
4617
  }
4560
4618
  function DiffBlock({ diff = "", filename, collapseAfter = 34, className = "" }) {
4561
- const [open, setOpen] = React25.useState(false);
4619
+ const [open, setOpen] = React26.useState(false);
4562
4620
  const [copied, copy] = useCopy();
4563
4621
  const raw = String(diff).replace(/\n$/, "");
4564
4622
  const all = raw.split("\n").map((line) => {
@@ -4604,7 +4662,7 @@ function DiffBlock({ diff = "", filename, collapseAfter = 34, className = "" })
4604
4662
  }
4605
4663
 
4606
4664
  // src/components/data/Markdown.tsx
4607
- var React26 = __toESM(require("react"), 1);
4665
+ var React27 = __toESM(require("react"), 1);
4608
4666
  var import_jsx_runtime48 = require("react/jsx-runtime");
4609
4667
  var SAFE = /^(?:https?:|mailto:|tel:|#|\/|\.{1,2}\/)/i;
4610
4668
  var safeHref = (h) => SAFE.test(String(h || "").trim()) ? String(h).trim() : null;
@@ -4643,7 +4701,7 @@ function inlineNodes(src, ctx, keyBase) {
4643
4701
  const href = safeHref(g(2));
4644
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()));
4645
4703
  } else if (kind === "cite") {
4646
- out.push(ctx.renderCitation ? /* @__PURE__ */ (0, import_jsx_runtime48.jsx)(React26.Fragment, { children: ctx.renderCitation(g(1)) }, key()) : /* @__PURE__ */ (0, import_jsx_runtime48.jsx)("sup", { className: "fd-md-cite", children: g(1) }, key()));
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()));
4647
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()));
4648
4706
  else if (kind === "strong") out.push(/* @__PURE__ */ (0, import_jsx_runtime48.jsx)("strong", { children: inlineNodes(g(1) || g(2), ctx, key()) }, key()));
4649
4707
  else if (kind === "em") out.push(/* @__PURE__ */ (0, import_jsx_runtime48.jsx)("em", { children: inlineNodes(g(1) || g(2), ctx, key()) }, key()));
@@ -4808,7 +4866,7 @@ function Markdown({
4808
4866
  onLinkClick
4809
4867
  }) {
4810
4868
  const ctx = { allowImages, headingOffset, renderCitation, onLinkClick, codeProps };
4811
- const blocks = React26.useMemo(() => parseBlocks(source), [source]);
4869
+ const blocks = React27.useMemo(() => parseBlocks(source), [source]);
4812
4870
  return /* @__PURE__ */ (0, import_jsx_runtime48.jsx)("div", { className: ["fd-md", className].filter(Boolean).join(" "), children: renderBlocks(blocks, ctx, "b") });
4813
4871
  }
4814
4872
  function MarkdownInline({ source = "", className = "", onLinkClick }) {
@@ -4922,7 +4980,7 @@ function Pagination({
4922
4980
  }
4923
4981
 
4924
4982
  // src/components/data/RelativeTime.tsx
4925
- var React27 = __toESM(require("react"), 1);
4983
+ var React28 = __toESM(require("react"), 1);
4926
4984
  var import_jsx_runtime51 = require("react/jsx-runtime");
4927
4985
  var MIN = 6e4;
4928
4986
  var HOUR = 36e5;
@@ -4974,9 +5032,9 @@ function formatDuration(ms) {
4974
5032
  return h + "h" + (m % 60 ? " " + m % 60 + "m" : "");
4975
5033
  }
4976
5034
  function RelativeTime({ value, prefix, className = "", refresh: refresh2 = true, ...rest }) {
4977
- const [, force] = React27.useState(0);
5035
+ const [, force] = React28.useState(0);
4978
5036
  const t = value instanceof Date ? value.getTime() : Date.parse(value);
4979
- React27.useEffect(() => {
5037
+ React28.useEffect(() => {
4980
5038
  if (!refresh2 || !t || isNaN(t)) return;
4981
5039
  const abs = Math.abs(t - Date.now());
4982
5040
  if (abs > DAY) return;
@@ -4992,7 +5050,7 @@ function RelativeTime({ value, prefix, className = "", refresh: refresh2 = true,
4992
5050
  }
4993
5051
 
4994
5052
  // src/components/data/ScoreMeter.tsx
4995
- var React28 = __toESM(require("react"), 1);
5053
+ var React29 = __toESM(require("react"), 1);
4996
5054
  var import_jsx_runtime52 = require("react/jsx-runtime");
4997
5055
  function ScoreMeter({
4998
5056
  score,
@@ -5007,10 +5065,10 @@ function ScoreMeter({
5007
5065
  breakdownWidth = 280,
5008
5066
  className = ""
5009
5067
  }) {
5010
- const [open, setOpen] = React28.useState(false);
5011
- const ref = React28.useRef(null);
5068
+ const [open, setOpen] = React29.useState(false);
5069
+ const ref = React29.useRef(null);
5012
5070
  const value = Math.max(0, Math.min(100, Math.round(Number(score) || 0)));
5013
- const body = /* @__PURE__ */ (0, import_jsx_runtime52.jsxs)(React28.Fragment, { children: [
5071
+ const body = /* @__PURE__ */ (0, import_jsx_runtime52.jsxs)(React29.Fragment, { children: [
5014
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 }) }),
5015
5073
  showScore ? /* @__PURE__ */ (0, import_jsx_runtime52.jsx)("span", { className: "fd-scoremeter-value fd-tabular", "aria-hidden": "true", children: value }) : null
5016
5074
  ] });
@@ -5029,7 +5087,7 @@ function ScoreMeter({
5029
5087
  }
5030
5088
  );
5031
5089
  }
5032
- return /* @__PURE__ */ (0, import_jsx_runtime52.jsxs)(React28.Fragment, { children: [
5090
+ return /* @__PURE__ */ (0, import_jsx_runtime52.jsxs)(React29.Fragment, { children: [
5033
5091
  /* @__PURE__ */ (0, import_jsx_runtime52.jsx)(
5034
5092
  "button",
5035
5093
  {
@@ -5060,13 +5118,13 @@ function ScoreMeter({
5060
5118
  }
5061
5119
 
5062
5120
  // src/components/data/SortMenu.tsx
5063
- var React29 = __toESM(require("react"), 1);
5121
+ var React30 = __toESM(require("react"), 1);
5064
5122
  var import_jsx_runtime53 = require("react/jsx-runtime");
5065
5123
  function SortMenu({ fields = [], sort, onSort, align = "right", size = "md", className = "", ...rest }) {
5066
- const [open, setOpen] = React29.useState(false);
5124
+ const [open, setOpen] = React30.useState(false);
5067
5125
  const zIndex = useOverlayLayer(open);
5068
- const ref = React29.useRef(null);
5069
- React29.useEffect(() => {
5126
+ const ref = React30.useRef(null);
5127
+ React30.useEffect(() => {
5070
5128
  if (!open) return;
5071
5129
  const away = (e) => {
5072
5130
  if (ref.current && !ref.current.contains(e.target)) setOpen(false);
@@ -5128,7 +5186,7 @@ function SortMenu({ fields = [], sort, onSort, align = "right", size = "md", cla
5128
5186
  }
5129
5187
 
5130
5188
  // src/components/data/StepList.tsx
5131
- var React30 = __toESM(require("react"), 1);
5189
+ var React31 = __toESM(require("react"), 1);
5132
5190
  var import_jsx_runtime54 = require("react/jsx-runtime");
5133
5191
  var KIND_ICON = { tool: "wrench", search: "magnifying-glass", read: "file-text", write: "pencil-simple", reasoning: "brain", run: "terminal", fetch: "cloud-arrow-down" };
5134
5192
  function StepList({
@@ -5141,9 +5199,9 @@ function StepList({
5141
5199
  dense = false,
5142
5200
  className = ""
5143
5201
  }) {
5144
- const [openState, setOpenState] = React30.useState(defaultOpen);
5202
+ const [openState, setOpenState] = React31.useState(defaultOpen);
5145
5203
  const open = openProp == null ? openState : openProp;
5146
- const [expanded, setExpanded] = React30.useState({});
5204
+ const [expanded, setExpanded] = React31.useState({});
5147
5205
  if (!steps.length) return null;
5148
5206
  const running = steps.some((s) => s.status === "running");
5149
5207
  const failed = steps.filter((s) => s.status === "error").length;
@@ -5201,7 +5259,7 @@ function StepList({
5201
5259
  }
5202
5260
 
5203
5261
  // src/components/data/VirtualList.tsx
5204
- var React31 = __toESM(require("react"), 1);
5262
+ var React32 = __toESM(require("react"), 1);
5205
5263
  var import_jsx_runtime55 = require("react/jsx-runtime");
5206
5264
  var VIRTUAL_LIST_BUFFER_ROWS = 20;
5207
5265
  var VIRTUAL_LIST_ROW_GAP = 6;
@@ -5253,35 +5311,35 @@ function VirtualList({
5253
5311
  className = "",
5254
5312
  style
5255
5313
  }) {
5256
- const [scrollTop, setScrollTop] = React31.useState(0);
5257
- const loaded = React31.useMemo(
5314
+ const [scrollTop, setScrollTop] = React32.useState(0);
5315
+ const loaded = React32.useMemo(
5258
5316
  () => ({ firstItemIndex, count: items.length }),
5259
5317
  [firstItemIndex, items.length]
5260
5318
  );
5261
5319
  const total = Math.max(totalCount == null ? 0 : totalCount, firstItemIndex + items.length);
5262
5320
  const bandKey = firstItemIndex + ":" + items.length;
5263
- const win = React31.useMemo(
5321
+ const win = React32.useMemo(
5264
5322
  () => computeVirtualWindow({ scrollTop, viewportHeight: height, itemHeight, itemCount: total, loaded }),
5265
5323
  [scrollTop, height, itemHeight, total, loaded]
5266
5324
  );
5267
- const need = React31.useMemo(() => computeNeedMore(win, loaded), [win, loaded]);
5325
+ const need = React32.useMemo(() => computeNeedMore(win, loaded), [win, loaded]);
5268
5326
  const wantStart = need.start && hasMore?.start !== false;
5269
5327
  const wantEnd = need.end && hasMore?.end !== false;
5270
5328
  const bucket2 = Math.floor(win.visibleStart / VIRTUAL_LIST_BUFFER_ROWS);
5271
5329
  const askKey = bandKey + "@" + bucket2;
5272
- const asked = React31.useRef({ start: null, end: null });
5273
- React31.useEffect(() => {
5330
+ const asked = React32.useRef({ start: null, end: null });
5331
+ React32.useEffect(() => {
5274
5332
  if (loading || !wantStart || asked.current.start === askKey) return;
5275
5333
  asked.current.start = askKey;
5276
5334
  onNeedMore("start", win);
5277
5335
  }, [wantStart, loading, askKey, onNeedMore, win]);
5278
- React31.useEffect(() => {
5336
+ React32.useEffect(() => {
5279
5337
  if (loading || !wantEnd || asked.current.end === askKey) return;
5280
5338
  asked.current.end = askKey;
5281
5339
  onNeedMore("end", win);
5282
5340
  }, [wantEnd, loading, askKey, onNeedMore, win]);
5283
- const lastKeysRef = React31.useRef(null);
5284
- const newKeys = React31.useMemo(() => {
5341
+ const lastKeysRef = React32.useRef(null);
5342
+ const newKeys = React32.useMemo(() => {
5285
5343
  const prev = lastKeysRef.current;
5286
5344
  if (!prev) return /* @__PURE__ */ new Set();
5287
5345
  const fresh = /* @__PURE__ */ new Set();
@@ -5291,7 +5349,7 @@ function VirtualList({
5291
5349
  }
5292
5350
  return fresh;
5293
5351
  }, [items]);
5294
- React31.useEffect(() => {
5352
+ React32.useEffect(() => {
5295
5353
  lastKeysRef.current = new Set(items.map(keyOf));
5296
5354
  }, [items]);
5297
5355
  const gapStyle = { "--fd-vlist-gap": rowGap + "px" };
@@ -5336,7 +5394,7 @@ function VirtualList({
5336
5394
  }
5337
5395
 
5338
5396
  // src/components/data/EntityRow.tsx
5339
- var React32 = __toESM(require("react"), 1);
5397
+ var React33 = __toESM(require("react"), 1);
5340
5398
  var import_jsx_runtime56 = require("react/jsx-runtime");
5341
5399
  var ENTITY_ROW_METRIC_WIDTH = 74;
5342
5400
  var METRIC_TONE_COLOR = {
@@ -5349,7 +5407,7 @@ function EntityRowMetrics({ metrics, className = "", style }) {
5349
5407
  const key = m.id || m.label || i;
5350
5408
  const className2 = ["fd-erow-metric", m.tone && m.tone !== "default" ? "is-" + m.tone : "", m.tooltip != null ? "is-described" : ""].filter(Boolean).join(" ");
5351
5409
  const tone = { color: METRIC_TONE_COLOR[m.tone || "default"] };
5352
- const content = /* @__PURE__ */ (0, import_jsx_runtime56.jsxs)(React32.Fragment, { children: [
5410
+ const content = /* @__PURE__ */ (0, import_jsx_runtime56.jsxs)(React33.Fragment, { children: [
5353
5411
  m.icon ? /* @__PURE__ */ (0, import_jsx_runtime56.jsx)("i", { className: "ph ph-" + m.icon, "aria-hidden": "true" }) : null,
5354
5412
  /* @__PURE__ */ (0, import_jsx_runtime56.jsx)("span", { className: "fd-erow-metric-value fd-tabular", children: m.value }),
5355
5413
  /* @__PURE__ */ (0, import_jsx_runtime56.jsx)("span", { className: "fd-sr", children: " " + m.label })
@@ -5441,7 +5499,7 @@ function EntityRow({
5441
5499
  }
5442
5500
 
5443
5501
  // src/components/data/TransferList.tsx
5444
- var React33 = __toESM(require("react"), 1);
5502
+ var React34 = __toESM(require("react"), 1);
5445
5503
  var import_react_dom5 = require("react-dom");
5446
5504
 
5447
5505
  // src/components/forms/Input.tsx
@@ -5547,12 +5605,12 @@ function TransferList({
5547
5605
  listHeight = 440,
5548
5606
  className = ""
5549
5607
  }) {
5550
- const [drag, setDrag] = React33.useState(null);
5551
- const [dragOverSide, setDragOverSide] = React33.useState(null);
5552
- const dragRef = React33.useRef(null);
5553
- const armedRef = React33.useRef(null);
5554
- const sideRefs = React33.useRef({ left: null, right: null });
5555
- const hitTestSide = React33.useCallback((x, y) => {
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) => {
5556
5614
  for (const side of ["left", "right"]) {
5557
5615
  const el = sideRefs.current[side];
5558
5616
  if (!el) continue;
@@ -5561,7 +5619,7 @@ function TransferList({
5561
5619
  }
5562
5620
  return null;
5563
5621
  }, []);
5564
- const findItem = React33.useCallback(
5622
+ const findItem = React34.useCallback(
5565
5623
  (side, key) => (side === "left" ? left.items : right.items).find((it) => keyOf(it) === key),
5566
5624
  [left.items, right.items, keyOf]
5567
5625
  );
@@ -5583,7 +5641,7 @@ function TransferList({
5583
5641
  height: rect.height
5584
5642
  };
5585
5643
  };
5586
- React33.useEffect(() => {
5644
+ React34.useEffect(() => {
5587
5645
  const onMovePointer = (e) => {
5588
5646
  const armed = armedRef.current;
5589
5647
  if (!armed || e.pointerId !== armed.pointerId) return;
@@ -5636,7 +5694,7 @@ function TransferList({
5636
5694
  window.removeEventListener("pointercancel", endDrag);
5637
5695
  };
5638
5696
  }, [hitTestSide, findItem, onMove]);
5639
- React33.useEffect(() => {
5697
+ React34.useEffect(() => {
5640
5698
  if (!drag || typeof document === "undefined") return;
5641
5699
  const prev = document.body.style.userSelect;
5642
5700
  document.body.style.userSelect = "none";
@@ -5744,11 +5802,11 @@ function TransferList({
5744
5802
  }
5745
5803
 
5746
5804
  // src/components/forms/Checkbox.tsx
5747
- var React34 = __toESM(require("react"), 1);
5805
+ var React35 = __toESM(require("react"), 1);
5748
5806
  var import_jsx_runtime60 = require("react/jsx-runtime");
5749
5807
  function Checkbox({ label, description, card = false, indeterminate = false, className = "", ...rest }) {
5750
- const ref = React34.useRef(null);
5751
- React34.useEffect(() => {
5808
+ const ref = React35.useRef(null);
5809
+ React35.useEffect(() => {
5752
5810
  if (ref.current) ref.current.indeterminate = indeterminate;
5753
5811
  }, [indeterminate]);
5754
5812
  return /* @__PURE__ */ (0, import_jsx_runtime60.jsxs)("label", { className: ["fd-choice", card ? "fd-choice-card" : "", className].filter(Boolean).join(" "), children: [
@@ -5792,7 +5850,7 @@ function Switch({ label, description, className = "", ...rest }) {
5792
5850
  }
5793
5851
 
5794
5852
  // src/components/forms/Select.tsx
5795
- var React35 = __toESM(require("react"), 1);
5853
+ var React36 = __toESM(require("react"), 1);
5796
5854
  var import_jsx_runtime63 = require("react/jsx-runtime");
5797
5855
  var norm = (o) => typeof o === "string" ? { value: o, label: o } : o;
5798
5856
  function Select({
@@ -5819,12 +5877,12 @@ function Select({
5819
5877
  const isOn = (v) => multiple ? vals.includes(v) : v === value;
5820
5878
  const hasSearch = searchable === void 0 ? opts.length > 8 : searchable;
5821
5879
  const { fieldId, labelId, ariaLabelledBy } = useTriggerLabelling(label, id);
5822
- const [open, setOpen] = React35.useState(false);
5823
- const [q, setQ] = React35.useState("");
5824
- const rootRef = React35.useRef(null);
5825
- const boxRef = React35.useRef(null);
5826
- const listRef = React35.useRef(null);
5827
- const typeBuf = React35.useRef({ s: "", t: 0 });
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 });
5828
5886
  const selected = multiple ? null : opts.find((o) => o.value === value);
5829
5887
  const chosen = multiple ? opts.filter((o) => vals.includes(o.value)) : [];
5830
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;
@@ -5963,7 +6021,7 @@ function Select({
5963
6021
  ),
5964
6022
  q ? /* @__PURE__ */ (0, import_jsx_runtime63.jsx)("span", { className: "fd-body-sm fd-muted", children: visible.length }) : null
5965
6023
  ] }) : void 0,
5966
- footer: multiple ? /* @__PURE__ */ (0, import_jsx_runtime63.jsxs)(React35.Fragment, { children: [
6024
+ footer: multiple ? /* @__PURE__ */ (0, import_jsx_runtime63.jsxs)(React36.Fragment, { children: [
5967
6025
  /* @__PURE__ */ (0, import_jsx_runtime63.jsx)(
5968
6026
  "button",
5969
6027
  {
@@ -5994,7 +6052,7 @@ function Select({
5994
6052
  'Nothing matches "',
5995
6053
  q,
5996
6054
  '".'
5997
- ] }) : 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: [
5998
6056
  grp.g ? /* @__PURE__ */ (0, import_jsx_runtime63.jsx)("div", { className: "fd-pop-group", children: grp.g }) : null,
5999
6057
  grp.items.map(({ o, i }) => /* @__PURE__ */ (0, import_jsx_runtime63.jsxs)(
6000
6058
  "button",
@@ -6031,7 +6089,7 @@ function Select({
6031
6089
  }
6032
6090
 
6033
6091
  // src/components/forms/TimePicker.tsx
6034
- var React36 = __toESM(require("react"), 1);
6092
+ var React37 = __toESM(require("react"), 1);
6035
6093
  var import_jsx_runtime64 = require("react/jsx-runtime");
6036
6094
  var pad = (n) => String(n).padStart(2, "0");
6037
6095
  function ClockFace({ value = "09:00", onChange }) {
@@ -6040,9 +6098,9 @@ function ClockFace({ value = "09:00", onChange }) {
6040
6098
  if (isNaN(m)) m = 0;
6041
6099
  const pm = h24 >= 12;
6042
6100
  const h12 = h24 % 12 === 0 ? 12 : h24 % 12;
6043
- const [mode2, setMode] = React36.useState("h");
6044
- const faceRef = React36.useRef(null);
6045
- const dragging = React36.useRef(false);
6101
+ const [mode2, setMode] = React37.useState("h");
6102
+ const faceRef = React37.useRef(null);
6103
+ const dragging = React37.useRef(false);
6046
6104
  const set = (h, mm, isPm) => onChange((isPm ? h % 12 + 12 : h % 12) + ":" + pad(mm));
6047
6105
  const R = 108, NR = 80;
6048
6106
  const nums = mode2 === "h" ? Array.from({ length: 12 }, (_, i) => i + 1) : Array.from({ length: 12 }, (_, i) => i * 5);
@@ -6115,9 +6173,9 @@ function ClockFace({ value = "09:00", onChange }) {
6115
6173
  }
6116
6174
  function TimePicker({ label, help, error, required = false, disabled = false, value = "", onChange, placeholder = "Pick a time", id, className = "", style }) {
6117
6175
  const { fieldId, labelId, ariaLabelledBy } = useTriggerLabelling(label, id);
6118
- const [open, setOpen] = React36.useState(false);
6119
- const rootRef = React36.useRef(null);
6120
- const boxRef = React36.useRef(null);
6176
+ const [open, setOpen] = React37.useState(false);
6177
+ const rootRef = React37.useRef(null);
6178
+ const boxRef = React37.useRef(null);
6121
6179
  const disp = () => {
6122
6180
  if (!value) return "";
6123
6181
  const [h, m] = value.split(":").map(Number);
@@ -6160,7 +6218,7 @@ function TimePicker({ label, help, error, required = false, disabled = false, va
6160
6218
  offset: 6,
6161
6219
  width: 262,
6162
6220
  role: "presentation",
6163
- footer: /* @__PURE__ */ (0, import_jsx_runtime64.jsxs)(React36.Fragment, { children: [
6221
+ footer: /* @__PURE__ */ (0, import_jsx_runtime64.jsxs)(React37.Fragment, { children: [
6164
6222
  /* @__PURE__ */ (0, import_jsx_runtime64.jsx)(
6165
6223
  "button",
6166
6224
  {
@@ -6188,7 +6246,7 @@ function TimePicker({ label, help, error, required = false, disabled = false, va
6188
6246
  }
6189
6247
 
6190
6248
  // src/components/forms/Slider.tsx
6191
- var React37 = __toESM(require("react"), 1);
6249
+ var React38 = __toESM(require("react"), 1);
6192
6250
  var import_jsx_runtime65 = require("react/jsx-runtime");
6193
6251
  function Slider({
6194
6252
  label,
@@ -6206,7 +6264,7 @@ function Slider({
6206
6264
  ...rest
6207
6265
  }) {
6208
6266
  const fieldId = useFieldId(id);
6209
- const [dragging, setDragging] = React37.useState(false);
6267
+ const [dragging, setDragging] = React38.useState(false);
6210
6268
  const v = value === void 0 ? min : Number(value);
6211
6269
  const pct = max === min ? 0 : (v - min) / (max - min) * 100;
6212
6270
  return /* @__PURE__ */ (0, import_jsx_runtime65.jsxs)("div", { className: ["fd-field", className].filter(Boolean).join(" "), children: [
@@ -6240,7 +6298,7 @@ function Slider({
6240
6298
  }
6241
6299
 
6242
6300
  // src/components/forms/RangeSlider.tsx
6243
- var React38 = __toESM(require("react"), 1);
6301
+ var React39 = __toESM(require("react"), 1);
6244
6302
  var import_jsx_runtime66 = require("react/jsx-runtime");
6245
6303
  function RangeSlider({
6246
6304
  label,
@@ -6260,9 +6318,9 @@ function RangeSlider({
6260
6318
  }) {
6261
6319
  const fmt2 = format || ((v) => String(v));
6262
6320
  const [a, b] = value || [min, max];
6263
- const [drag, setDrag] = React38.useState(null);
6264
- const [focus, setFocus] = React38.useState(null);
6265
- const railRef = React38.useRef(null);
6321
+ const [drag, setDrag] = React39.useState(null);
6322
+ const [focus, setFocus] = React39.useState(null);
6323
+ const railRef = React39.useRef(null);
6266
6324
  const pct = (v) => max === min ? 0 : (v - min) / (max - min) * 100;
6267
6325
  const clampPair = (i, v) => {
6268
6326
  v = Math.min(max, Math.max(min, Math.round(v / step) * step));
@@ -6277,7 +6335,7 @@ function RangeSlider({
6277
6335
  const r = railRef.current.getBoundingClientRect();
6278
6336
  return min + Math.min(1, Math.max(0, (e.clientX - r.left) / r.width)) * (max - min);
6279
6337
  };
6280
- React38.useEffect(() => {
6338
+ React39.useEffect(() => {
6281
6339
  if (drag === null) return;
6282
6340
  const mv = (e) => onChange && onChange(clampPair(drag, fromEvent(e)));
6283
6341
  const upH = () => setDrag(null);
@@ -6358,7 +6416,7 @@ function RangeSlider({
6358
6416
  /* @__PURE__ */ (0, import_jsx_runtime66.jsxs)("div", { className: "fd-range" + (hasLabels ? " has-labels" : ""), onPointerDown: onRailDown, children: [
6359
6417
  /* @__PURE__ */ (0, import_jsx_runtime66.jsx)("span", { className: "fd-range-rail", ref: railRef }),
6360
6418
  /* @__PURE__ */ (0, import_jsx_runtime66.jsx)("span", { className: "fd-range-fill", style: { left: pct(a) + "%", width: pct(b) - pct(a) + "%" } }),
6361
- marks.map((m) => /* @__PURE__ */ (0, import_jsx_runtime66.jsxs)(React38.Fragment, { children: [
6419
+ marks.map((m) => /* @__PURE__ */ (0, import_jsx_runtime66.jsxs)(React39.Fragment, { children: [
6362
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) + "%" } }),
6363
6421
  m.label ? /* @__PURE__ */ (0, import_jsx_runtime66.jsx)("span", { className: "fd-range-mark-label", style: { left: pct(m.value) + "%" }, children: m.label }) : null
6364
6422
  ] }, m.value)),
@@ -6387,7 +6445,7 @@ function RangeSlider({
6387
6445
  }
6388
6446
 
6389
6447
  // src/components/forms/Dropzone.tsx
6390
- var React39 = __toESM(require("react"), 1);
6448
+ var React40 = __toESM(require("react"), 1);
6391
6449
  var import_jsx_runtime67 = require("react/jsx-runtime");
6392
6450
  function Dropzone({
6393
6451
  onFiles,
@@ -6402,8 +6460,8 @@ function Dropzone({
6402
6460
  className = "",
6403
6461
  style
6404
6462
  }) {
6405
- const [over, setOver] = React39.useState(false);
6406
- const depth = React39.useRef(0);
6463
+ const [over, setOver] = React40.useState(false);
6464
+ const depth = React40.useRef(0);
6407
6465
  const has = (e) => {
6408
6466
  const dt = e.dataTransfer;
6409
6467
  if (!dt) return false;
@@ -6465,8 +6523,8 @@ function FilePickButton({
6465
6523
  className = "",
6466
6524
  children
6467
6525
  }) {
6468
- const ref = React39.useRef(null);
6469
- 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: [
6470
6528
  /* @__PURE__ */ (0, import_jsx_runtime67.jsx)(
6471
6529
  "button",
6472
6530
  {
@@ -6499,10 +6557,10 @@ function FilePickButton({
6499
6557
  }
6500
6558
  function useStagedFiles(upload, opts) {
6501
6559
  const o = opts || {};
6502
- const [items, setItems] = React39.useState([]);
6503
- const controllers = React39.useRef({});
6560
+ const [items, setItems] = React40.useState([]);
6561
+ const controllers = React40.useRef({});
6504
6562
  const patch = (id, next) => setItems((list) => list.map((f) => f.id === id ? Object.assign({}, f, next) : f));
6505
- const run = React39.useCallback((att) => {
6563
+ const run = React40.useCallback((att) => {
6506
6564
  if (!upload) return;
6507
6565
  const ac = typeof AbortController !== "undefined" ? new AbortController() : null;
6508
6566
  controllers.current[att.id] = ac;
@@ -6519,14 +6577,14 @@ function useStagedFiles(upload, opts) {
6519
6577
  delete controllers.current[att.id];
6520
6578
  });
6521
6579
  }, [upload]);
6522
- const add = React39.useCallback((files) => {
6580
+ const add = React40.useCallback((files) => {
6523
6581
  if (!upload) return [];
6524
6582
  const atts = Array.from(files).map((f) => toAttachment(f));
6525
6583
  setItems((list) => list.concat(atts));
6526
6584
  atts.forEach(run);
6527
6585
  return atts;
6528
6586
  }, [upload, run]);
6529
- const remove = React39.useCallback((att) => {
6587
+ const remove = React40.useCallback((att) => {
6530
6588
  const ac = controllers.current[att.id];
6531
6589
  if (ac) {
6532
6590
  try {
@@ -6537,10 +6595,10 @@ function useStagedFiles(upload, opts) {
6537
6595
  }
6538
6596
  setItems((list) => list.filter((f) => f.id !== att.id));
6539
6597
  }, []);
6540
- const retry = React39.useCallback((att) => {
6598
+ const retry = React40.useCallback((att) => {
6541
6599
  run(att);
6542
6600
  }, [run]);
6543
- const clear = React39.useCallback(() => {
6601
+ const clear = React40.useCallback(() => {
6544
6602
  Object.values(controllers.current).forEach((ac) => {
6545
6603
  try {
6546
6604
  ac && ac.abort();
@@ -6664,7 +6722,7 @@ function FileGrid({ files = [], onOpen, onRemove, onRetry, tiles = true, maxHeig
6664
6722
  }
6665
6723
 
6666
6724
  // src/components/forms/MarkdownEditor.tsx
6667
- var React40 = __toESM(require("react"), 1);
6725
+ var React41 = __toESM(require("react"), 1);
6668
6726
  var import_jsx_runtime69 = require("react/jsx-runtime");
6669
6727
  var isMac = typeof navigator !== "undefined" && /Mac|iPhone|iPad/.test(navigator.platform || navigator.userAgent || "");
6670
6728
  var INLINE_RE = /(\*\*\*[^*\n]+\*\*\*|\*\*[^*\n]+\*\*|__[^_\n]+__|~~[^~\n]+~~|`[^`\n]+`|\*[^*\s][^*\n]*\*|(?<![A-Za-z0-9_])_[^_\s][^_\n]*_|\[[^\]\n]*\]\([^)\s\n]*\)|https?:\/\/\S+)/g;
@@ -6878,7 +6936,7 @@ function syncDom(root, value) {
6878
6936
  while (root.children.length > lines.length) root.removeChild(root.lastChild);
6879
6937
  }
6880
6938
  var LIST_CONT = RE_LI;
6881
- var MarkdownEditor = React40.forwardRef(function MarkdownEditor2({
6939
+ var MarkdownEditor = React41.forwardRef(function MarkdownEditor2({
6882
6940
  value = "",
6883
6941
  onChange,
6884
6942
  onSubmit,
@@ -6897,10 +6955,10 @@ var MarkdownEditor = React40.forwardRef(function MarkdownEditor2({
6897
6955
  className = "",
6898
6956
  id
6899
6957
  }, ref) {
6900
- const boxRef = React40.useRef(null);
6901
- const composing = React40.useRef(false);
6902
- const pendingCaret = React40.useRef(null);
6903
- React40.useLayoutEffect(() => {
6958
+ const boxRef = React41.useRef(null);
6959
+ const composing = React41.useRef(false);
6960
+ const pendingCaret = React41.useRef(null);
6961
+ React41.useLayoutEffect(() => {
6904
6962
  const root = boxRef.current;
6905
6963
  if (!root || composing.current) return;
6906
6964
  const active = document.activeElement === root || root.contains(document.activeElement);
@@ -6909,7 +6967,7 @@ var MarkdownEditor = React40.forwardRef(function MarkdownEditor2({
6909
6967
  pendingCaret.current = null;
6910
6968
  if (active && caret != null) placeCaret(root, caret);
6911
6969
  }, [value]);
6912
- React40.useEffect(() => {
6970
+ React41.useEffect(() => {
6913
6971
  if (autoFocus && boxRef.current) boxRef.current.focus();
6914
6972
  }, [autoFocus]);
6915
6973
  const caretNow = () => {
@@ -6976,7 +7034,7 @@ var MarkdownEditor = React40.forwardRef(function MarkdownEditor2({
6976
7034
  api.replaceRange(from, to, next, from + next.length);
6977
7035
  }
6978
7036
  };
6979
- React40.useImperativeHandle(ref, () => api);
7037
+ React41.useImperativeHandle(ref, () => api);
6980
7038
  function detect(text, caret) {
6981
7039
  if (!onTrigger) return;
6982
7040
  const upto = text.slice(0, caret);
@@ -7128,16 +7186,16 @@ var MarkdownEditor = React40.forwardRef(function MarkdownEditor2({
7128
7186
  });
7129
7187
 
7130
7188
  // src/components/platform/AccountMenu.tsx
7131
- var React42 = __toESM(require("react"), 1);
7189
+ var React43 = __toESM(require("react"), 1);
7132
7190
 
7133
7191
  // src/kits/sessionContext.tsx
7134
- var React41 = __toESM(require("react"), 1);
7135
- var SessionContext = React41.createContext(null);
7192
+ var React42 = __toESM(require("react"), 1);
7193
+ var SessionContext = React42.createContext(null);
7136
7194
  function SessionProvider({ value, children }) {
7137
- return React41.createElement(SessionContext.Provider, { value }, children);
7195
+ return React42.createElement(SessionContext.Provider, { value }, children);
7138
7196
  }
7139
7197
  function useSessionContext() {
7140
- const ctx = React41.useContext(SessionContext);
7198
+ const ctx = React42.useContext(SessionContext);
7141
7199
  if (!ctx) {
7142
7200
  throw new Error(
7143
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."
@@ -7177,11 +7235,11 @@ function AccountMenu({
7177
7235
  ...rest
7178
7236
  }) {
7179
7237
  const { user, roles, can: can2, signOut: ctxSignOut, demo } = useSessionContext();
7180
- const [open, setOpen] = React42.useState(false);
7181
- const [switching, setSwitching] = React42.useState(false);
7182
- const [signingOut, setSigningOut] = React42.useState(false);
7183
- const [signOutError, setSignOutError] = React42.useState(null);
7184
- const ref = React42.useRef(null);
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);
7185
7243
  const visibleLinks = links.filter((l) => !l.perm || can2(l.perm));
7186
7244
  const visibleGroups = groups.map((g) => ({ label: g.label, links: g.links.filter((l) => !l.perm || can2(l.perm)) })).filter((g) => g.links.length);
7187
7245
  const closeMenu = () => {
@@ -7306,13 +7364,13 @@ function AccountMenu({
7306
7364
  }
7307
7365
 
7308
7366
  // src/components/platform/AppSwitcher.tsx
7309
- var React43 = __toESM(require("react"), 1);
7367
+ var React44 = __toESM(require("react"), 1);
7310
7368
  var import_jsx_runtime71 = require("react/jsx-runtime");
7311
7369
  function AppSwitcher({ apps: appsProp, onNavigate, className = "" }) {
7312
7370
  const { apps: contextApps } = useSessionContext();
7313
7371
  const apps = appsProp ?? contextApps ?? [];
7314
- const [open, setOpen] = React43.useState(false);
7315
- const anchorRef = React43.useRef(null);
7372
+ const [open, setOpen] = React44.useState(false);
7373
+ const anchorRef = React44.useRef(null);
7316
7374
  if (!apps.length) return null;
7317
7375
  const items = apps.map((app) => ({
7318
7376
  id: app.key,
@@ -7326,7 +7384,7 @@ function AppSwitcher({ apps: appsProp, onNavigate, className = "" }) {
7326
7384
  window.location.href = app.url;
7327
7385
  }
7328
7386
  }));
7329
- return /* @__PURE__ */ (0, import_jsx_runtime71.jsxs)(React43.Fragment, { children: [
7387
+ return /* @__PURE__ */ (0, import_jsx_runtime71.jsxs)(React44.Fragment, { children: [
7330
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)(
7331
7389
  IconButton,
7332
7390
  {
@@ -7355,10 +7413,10 @@ function AppSwitcher({ apps: appsProp, onNavigate, className = "" }) {
7355
7413
  }
7356
7414
 
7357
7415
  // src/components/platform/AppearanceMenu.tsx
7358
- var React45 = __toESM(require("react"), 1);
7416
+ var React46 = __toESM(require("react"), 1);
7359
7417
 
7360
7418
  // src/kits/appearance.ts
7361
- var React44 = __toESM(require("react"), 1);
7419
+ var React45 = __toESM(require("react"), 1);
7362
7420
  var DEFAULT_STORAGE_KEY = "fd-appearance";
7363
7421
  var DEFAULT_PREFS = {
7364
7422
  theme: "system",
@@ -7453,11 +7511,11 @@ function applyPrefs(prefs, root = document.documentElement) {
7453
7511
  else root.removeAttribute("data-motion");
7454
7512
  }
7455
7513
  function useAppearancePrefs(store) {
7456
- const prefs = React44.useSyncExternalStore(store.subscribe, store.getSnapshot);
7457
- React44.useEffect(() => {
7514
+ const prefs = React45.useSyncExternalStore(store.subscribe, store.getSnapshot);
7515
+ React45.useEffect(() => {
7458
7516
  applyPrefs(prefs);
7459
7517
  }, [prefs]);
7460
- React44.useEffect(() => {
7518
+ React45.useEffect(() => {
7461
7519
  if (prefs.theme !== "system" || typeof window === "undefined" || typeof window.matchMedia !== "function") {
7462
7520
  return;
7463
7521
  }
@@ -7466,7 +7524,7 @@ function useAppearancePrefs(store) {
7466
7524
  mq.addEventListener("change", onChange);
7467
7525
  return () => mq.removeEventListener("change", onChange);
7468
7526
  }, [prefs]);
7469
- const update = React44.useCallback(
7527
+ const update = React45.useCallback(
7470
7528
  (patch) => {
7471
7529
  store.write({ ...store.getSnapshot(), ...patch });
7472
7530
  },
@@ -7489,15 +7547,15 @@ var TEXT_SCALE_OPTIONS = [
7489
7547
  { value: "xl", label: "XL" }
7490
7548
  ];
7491
7549
  function AppearanceMenu({ className = "", store: storeProp, storageKey, storage, defaults }) {
7492
- const store = React45.useMemo(
7550
+ const store = React46.useMemo(
7493
7551
  () => storeProp ?? createLocalStorageAppearanceStore({ storageKey, storage, defaults }),
7494
7552
  [storeProp, storageKey, storage, defaults]
7495
7553
  );
7496
7554
  const [prefs, update] = useAppearancePrefs(store);
7497
- const [open, setOpen] = React45.useState(false);
7498
- const anchorRef = React45.useRef(null);
7555
+ const [open, setOpen] = React46.useState(false);
7556
+ const anchorRef = React46.useRef(null);
7499
7557
  const patch = (p) => update(p);
7500
- return /* @__PURE__ */ (0, import_jsx_runtime72.jsxs)(React45.Fragment, { children: [
7558
+ return /* @__PURE__ */ (0, import_jsx_runtime72.jsxs)(React46.Fragment, { children: [
7501
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)(
7502
7560
  IconButton,
7503
7561
  {
@@ -7566,14 +7624,14 @@ function AppearanceMenu({ className = "", store: storeProp, storageKey, storage,
7566
7624
  }
7567
7625
 
7568
7626
  // src/components/platform/ApiSpecBrowser.tsx
7569
- var React46 = __toESM(require("react"), 1);
7627
+ var React47 = __toESM(require("react"), 1);
7570
7628
  var import_jsx_runtime73 = require("react/jsx-runtime");
7571
7629
  var METHOD_TONE = { GET: "success", POST: "info", PATCH: "warning", PUT: "warning", DELETE: "danger" };
7572
7630
  function Json({ obj }) {
7573
7631
  return /* @__PURE__ */ (0, import_jsx_runtime73.jsx)("pre", { className: "fd-json", children: JSON.stringify(obj, null, 2) });
7574
7632
  }
7575
7633
  function Endpoint({ s, onRequest }) {
7576
- const [tried, setTried] = React46.useState(null);
7634
+ const [tried, setTried] = React47.useState(null);
7577
7635
  const run = async () => {
7578
7636
  setTried("busy");
7579
7637
  const t0 = (window.performance || Date).now();
@@ -7646,10 +7704,10 @@ function ApiSpecBrowser({
7646
7704
  className = "",
7647
7705
  ...rest
7648
7706
  }) {
7649
- const [q, setQ] = React46.useState("");
7650
- const [method, setMethod] = React46.useState(null);
7651
- const [mod, setMod] = React46.useState(null);
7652
- const [listOnly, setListOnly] = React46.useState(false);
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);
7653
7711
  const activeModule = modules && modules.find((m) => m.id === mod);
7654
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())));
7655
7713
  const effGroups = groups && groups.length ? groups : [["All endpoints", spec.map((s) => s.id)]];
@@ -7728,7 +7786,7 @@ function ApiSpecBrowser({
7728
7786
  }
7729
7787
 
7730
7788
  // src/components/platform/ProfilePage.tsx
7731
- var React47 = __toESM(require("react"), 1);
7789
+ var React48 = __toESM(require("react"), 1);
7732
7790
  var import_jsx_runtime74 = require("react/jsx-runtime");
7733
7791
  function fieldInitialValue(field, user) {
7734
7792
  if (field.value) return field.value(user);
@@ -7764,21 +7822,21 @@ function ProfilePage({
7764
7822
  }) {
7765
7823
  const { user: sessionUser, roles, permissions, saveProfile: saveProfile2 } = useSessionContext();
7766
7824
  const user = userProp || sessionUser;
7767
- const initialFieldValues = React47.useMemo(() => {
7825
+ const initialFieldValues = React48.useMemo(() => {
7768
7826
  const values2 = {};
7769
7827
  for (const field of fields) values2[field.key] = fieldInitialValue(field, user);
7770
7828
  return values2;
7771
7829
  }, [user.id, fields]);
7772
- const initialNotify = React47.useMemo(() => {
7830
+ const initialNotify = React48.useMemo(() => {
7773
7831
  const values2 = {};
7774
7832
  for (const n of notifications) values2[n.key] = !!user.notify?.[n.key];
7775
7833
  return values2;
7776
7834
  }, [user.id, notifications]);
7777
- const [values, setValues] = React47.useState(initialFieldValues);
7778
- const [notify, setNotify] = React47.useState(initialNotify);
7779
- const [saving, setSaving] = React47.useState(false);
7780
- const [saved, setSaved] = React47.useState(false);
7781
- const [prevUserId, setPrevUserId] = React47.useState(user.id);
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);
7782
7840
  if (user.id !== prevUserId) {
7783
7841
  setPrevUserId(user.id);
7784
7842
  setValues(initialFieldValues);
@@ -7966,11 +8024,11 @@ function ProfilePage({
7966
8024
  }
7967
8025
 
7968
8026
  // src/components/platform/SignInPage.tsx
7969
- var React48 = __toESM(require("react"), 1);
8027
+ var React49 = __toESM(require("react"), 1);
7970
8028
  var import_jsx_runtime75 = require("react/jsx-runtime");
7971
8029
  function SignInPage({ productName, onSignIn, continueAs, error }) {
7972
- const [signingIn, setSigningIn] = React48.useState(false);
7973
- const [resuming, setResuming] = React48.useState(false);
8030
+ const [signingIn, setSigningIn] = React49.useState(false);
8031
+ const [resuming, setResuming] = React49.useState(false);
7974
8032
  function handleSignIn() {
7975
8033
  setSigningIn(true);
7976
8034
  onSignIn();
@@ -8159,10 +8217,10 @@ function GoogleGlyph() {
8159
8217
  }
8160
8218
 
8161
8219
  // src/components/platform/RoadmapTimeline.tsx
8162
- var React51 = __toESM(require("react"), 1);
8220
+ var React52 = __toESM(require("react"), 1);
8163
8221
 
8164
8222
  // src/kits/session.ts
8165
- var React49 = __toESM(require("react"), 1);
8223
+ var React50 = __toESM(require("react"), 1);
8166
8224
  var PERMISSION_CATALOG = [
8167
8225
  { group: "Plans", items: [
8168
8226
  { key: "plan.view", label: "View plans", detail: "Read any plan in the workspace." },
@@ -9729,8 +9787,8 @@ function roadmap(overrides) {
9729
9787
  };
9730
9788
  }
9731
9789
  function useSession() {
9732
- const [s, setS] = React49.useState(getSession);
9733
- React49.useEffect(() => subscribe(setS), []);
9790
+ const [s, setS] = React50.useState(getSession);
9791
+ React50.useEffect(() => subscribe(setS), []);
9734
9792
  return s;
9735
9793
  }
9736
9794
  var SessionKit = {
@@ -9763,7 +9821,7 @@ var SessionKit = {
9763
9821
  };
9764
9822
  function DemoSessionProvider({ children }) {
9765
9823
  const session = useSession();
9766
- const value = React49.useMemo(
9824
+ const value = React50.useMemo(
9767
9825
  () => ({
9768
9826
  user: session.user,
9769
9827
  roles: session.roles,
@@ -9779,11 +9837,11 @@ function DemoSessionProvider({ children }) {
9779
9837
  }),
9780
9838
  [session]
9781
9839
  );
9782
- return React49.createElement(SessionProvider, { value }, children);
9840
+ return React50.createElement(SessionProvider, { value }, children);
9783
9841
  }
9784
9842
 
9785
9843
  // src/kits/runtime.ts
9786
- var React50 = __toESM(require("react"), 1);
9844
+ var React51 = __toESM(require("react"), 1);
9787
9845
  var WIRED_ENDPOINTS = [
9788
9846
  // Nothing yet. Every id below would come from a real service:
9789
9847
  // "plan.get", "placements.list", …
@@ -9954,8 +10012,8 @@ var RuntimeKit = {
9954
10012
  };
9955
10013
  RuntimeKit.declare(FEATURE_NEEDS);
9956
10014
  function useRuntimeMode() {
9957
- const [m, setM] = React50.useState(RuntimeKit.getMode());
9958
- React50.useEffect(() => RuntimeKit.subscribe(setM), []);
10015
+ const [m, setM] = React51.useState(RuntimeKit.getMode());
10016
+ React51.useEffect(() => RuntimeKit.subscribe(setM), []);
9959
10017
  return m;
9960
10018
  }
9961
10019
  function useFeatureStatus(key) {
@@ -10038,12 +10096,12 @@ function RoadmapCard({ item, byKey, onOpenFlag }) {
10038
10096
  }
10039
10097
  function RoadmapTimeline({ onOpenFlag, title = "Roadmap", lede }) {
10040
10098
  const session = SessionKit.useSession();
10041
- const [project, setProject] = React51.useState("");
10042
- const [q, setQ] = React51.useState("");
10043
- const scrollRef = React51.useRef(null);
10044
- const nowRef = React51.useRef(null);
10045
- const rm = React51.useMemo(() => SessionKit.roadmap({ isComplete: RuntimeKit.isComplete }), [session]);
10046
- const byKey = React51.useMemo(() => {
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(() => {
10047
10105
  const m = {};
10048
10106
  rm.items.forEach((i) => {
10049
10107
  m[i.key] = i;
@@ -10052,7 +10110,7 @@ function RoadmapTimeline({ onOpenFlag, title = "Roadmap", lede }) {
10052
10110
  }, [rm]);
10053
10111
  const items = rm.items.filter((i) => (!project || i.project === project) && (!q || (i.label + " " + i.description + " " + (i.backend || "") + " " + i.key).toLowerCase().includes(q.toLowerCase())));
10054
10112
  const projects = [...new Set(rm.items.map((i) => i.project))];
10055
- React51.useEffect(() => {
10113
+ React52.useEffect(() => {
10056
10114
  let raf1 = 0, raf2 = 0;
10057
10115
  const place = () => {
10058
10116
  const box = scrollRef.current, mark = nowRef.current;
@@ -10126,7 +10184,7 @@ function RoadmapTimeline({ onOpenFlag, title = "Roadmap", lede }) {
10126
10184
  lastPhase = item.phase;
10127
10185
  const inPhase = items.filter((i) => i.phase === item.phase).length;
10128
10186
  const isBoundary = n === firstPending;
10129
- return /* @__PURE__ */ (0, import_jsx_runtime76.jsxs)(React51.Fragment, { children: [
10187
+ return /* @__PURE__ */ (0, import_jsx_runtime76.jsxs)(React52.Fragment, { children: [
10130
10188
  showPhase ? /* @__PURE__ */ (0, import_jsx_runtime76.jsxs)("div", { className: "fd-rm-era", children: [
10131
10189
  /* @__PURE__ */ (0, import_jsx_runtime76.jsxs)("span", { className: "fd-row", style: { gap: 8, flexWrap: "wrap", alignItems: "baseline" }, children: [
10132
10190
  /* @__PURE__ */ (0, import_jsx_runtime76.jsx)("span", { style: { fontWeight: 700 }, children: item.phase === 0 ? "Shipped" : "Phase " + item.phase + " \u2014 " + item.phaseName }),
@@ -10170,7 +10228,7 @@ function RoadmapTimeline({ onOpenFlag, title = "Roadmap", lede }) {
10170
10228
  }
10171
10229
 
10172
10230
  // src/components/platform/ComingSoon.tsx
10173
- var React52 = __toESM(require("react"), 1);
10231
+ var React53 = __toESM(require("react"), 1);
10174
10232
  var import_react_dom6 = require("react-dom");
10175
10233
  var import_jsx_runtime77 = require("react/jsx-runtime");
10176
10234
  var BYPASS_STORE = "fd.soon.bypass.v1";
@@ -10188,8 +10246,8 @@ function writeBypassed(list) {
10188
10246
  }
10189
10247
  }
10190
10248
  function useBypass(key) {
10191
- const [on, setOn] = React52.useState(() => !!key && readBypassed().indexOf(key) >= 0);
10192
- React52.useEffect(() => {
10249
+ const [on, setOn] = React53.useState(() => !!key && readBypassed().indexOf(key) >= 0);
10250
+ React53.useEffect(() => {
10193
10251
  setOn(!!key && readBypassed().indexOf(key) >= 0);
10194
10252
  }, [key]);
10195
10253
  const set = (next) => {
@@ -10236,9 +10294,9 @@ function SoonCard({ label, detail, backend, eta, effort, onRoadmap, allowed, onB
10236
10294
  ] });
10237
10295
  }
10238
10296
  function useHoverCard(open) {
10239
- const anchor = React52.useRef(null);
10240
- const [pos, setPos] = React52.useState(null);
10241
- React52.useLayoutEffect(() => {
10297
+ const anchor = React53.useRef(null);
10298
+ const [pos, setPos] = React53.useState(null);
10299
+ React53.useLayoutEffect(() => {
10242
10300
  if (!open || !anchor.current) {
10243
10301
  setPos(null);
10244
10302
  return;
@@ -10365,10 +10423,10 @@ function ComingSoon({
10365
10423
  ] });
10366
10424
  }
10367
10425
  function InlineSoon({ label, detail, backend, eta, effort, onRoadmap, allowed, onBypass, blur, tip, className, rest, children }) {
10368
- const [open, setOpen] = React52.useState(false);
10426
+ const [open, setOpen] = React53.useState(false);
10369
10427
  const [anchor, pos] = useHoverCard(open);
10370
10428
  const zIndex = useOverlayLayer(open);
10371
- const close = React52.useRef(null);
10429
+ const close = React53.useRef(null);
10372
10430
  const show = () => {
10373
10431
  if (close.current) {
10374
10432
  clearTimeout(close.current);
@@ -10384,7 +10442,7 @@ function InlineSoon({ label, detail, backend, eta, effort, onRoadmap, allowed, o
10384
10442
  setOpen(false);
10385
10443
  }, 140);
10386
10444
  };
10387
- React52.useEffect(() => () => {
10445
+ React53.useEffect(() => () => {
10388
10446
  if (close.current) clearTimeout(close.current);
10389
10447
  }, []);
10390
10448
  return /* @__PURE__ */ (0, import_jsx_runtime77.jsxs)(
@@ -10555,14 +10613,14 @@ function PermissionHint({ perm, children }) {
10555
10613
  }
10556
10614
 
10557
10615
  // src/components/platform/ModeSwitch.tsx
10558
- var React53 = __toESM(require("react"), 1);
10616
+ var React54 = __toESM(require("react"), 1);
10559
10617
  var import_jsx_runtime79 = require("react/jsx-runtime");
10560
10618
  function ModeSwitch({ canToggle = false, requestCount = 0, onClearLog, renderLog, onOpenSpec, summary }) {
10561
10619
  const mode2 = useRuntimeMode();
10562
- const [open, setOpen] = React53.useState(false);
10620
+ const [open, setOpen] = React54.useState(false);
10563
10621
  const zIndex = useOverlayLayer(open);
10564
- const ref = React53.useRef(null);
10565
- React53.useEffect(() => {
10622
+ const ref = React54.useRef(null);
10623
+ React54.useEffect(() => {
10566
10624
  if (!open) return;
10567
10625
  const away = (e) => {
10568
10626
  if (ref.current && !ref.current.contains(e.target)) setOpen(false);
@@ -10818,7 +10876,7 @@ function SaturationDistribution({ campuses = [], floorBand, floorScore, onSelect
10818
10876
  }
10819
10877
 
10820
10878
  // src/components/planner/MixGap.tsx
10821
- var React54 = __toESM(require("react"), 1);
10879
+ var React55 = __toESM(require("react"), 1);
10822
10880
  var import_jsx_runtime82 = require("react/jsx-runtime");
10823
10881
  var MIX_GAP_LAYOUT = {
10824
10882
  trackHeight: 30,
@@ -10833,7 +10891,7 @@ function mixGapOffset(value, max) {
10833
10891
  }
10834
10892
  function MixGap({ rows = [], loading = false, className = "" }) {
10835
10893
  const max = Math.max(1, ...rows.flatMap((r) => [r.target, r.realized]));
10836
- const [hover, setHover] = React54.useState(null);
10894
+ const [hover, setHover] = React55.useState(null);
10837
10895
  const toneOf = (gap) => gap >= -1 ? "ok" : gap >= -4 ? "warn" : "danger";
10838
10896
  const TONE = { ok: "var(--ok-solid)", warn: "var(--warn-solid)", danger: "var(--danger-solid)" };
10839
10897
  const { trackHeight, barHeight, targetWidth, labelGap } = MIX_GAP_LAYOUT;
@@ -10976,7 +11034,7 @@ function ChannelContribution({
10976
11034
  }
10977
11035
 
10978
11036
  // src/components/planner/BudgetReallocator.tsx
10979
- var React55 = __toESM(require("react"), 1);
11037
+ var React56 = __toESM(require("react"), 1);
10980
11038
  var import_jsx_runtime84 = require("react/jsx-runtime");
10981
11039
  var bandFor = (crp) => crp >= 200 ? "dominant" : crp >= 100 ? "strong" : crp >= 50 ? "adequate" : "weak";
10982
11040
  function BudgetReallocator({
@@ -10992,8 +11050,8 @@ function BudgetReallocator({
10992
11050
  onCancel,
10993
11051
  className = ""
10994
11052
  }) {
10995
- const [draft, setDraft] = React55.useState(spend);
10996
- React55.useEffect(() => setDraft(spend), [spend]);
11053
+ const [draft, setDraft] = React56.useState(spend);
11054
+ React56.useEffect(() => setDraft(spend), [spend]);
10997
11055
  const dirty = draft !== spend;
10998
11056
  const nextCrp = scoreFor ? scoreFor(draft) : crp;
10999
11057
  const nextBand = bandFor(nextCrp);
@@ -11008,10 +11066,10 @@ function BudgetReallocator({
11008
11066
  setDraft(spend);
11009
11067
  if (onCancel) onCancel();
11010
11068
  };
11011
- const trackRef = React55.useRef(null);
11012
- const chipRef = React55.useRef(null);
11013
- const [chipLeft, setChipLeft] = React55.useState(null);
11014
- React55.useLayoutEffect(() => {
11069
+ const trackRef = React56.useRef(null);
11070
+ const chipRef = React56.useRef(null);
11071
+ const [chipLeft, setChipLeft] = React56.useState(null);
11072
+ React56.useLayoutEffect(() => {
11015
11073
  const track = trackRef.current;
11016
11074
  if (!dirty || !track) {
11017
11075
  setChipLeft(null);
@@ -11198,7 +11256,7 @@ function ImportanceTag({ level, showLabel = true, size = "sm", className = "" })
11198
11256
  }
11199
11257
 
11200
11258
  // src/components/planner/PreferenceMeter.tsx
11201
- var React56 = __toESM(require("react"), 1);
11259
+ var React57 = __toESM(require("react"), 1);
11202
11260
  var import_jsx_runtime87 = require("react/jsx-runtime");
11203
11261
  function preferenceScore(criteria) {
11204
11262
  const earned = criteria.reduce((n, c) => n + (Number(c.earned) || 0), 0);
@@ -11228,7 +11286,7 @@ function PreferenceMeter({
11228
11286
  className = ""
11229
11287
  }) {
11230
11288
  const value = score == null ? preferenceScore(criteria) : score;
11231
- const segments = React56.useMemo(() => preferenceSegments(criteria), [criteria]);
11289
+ const segments = React57.useMemo(() => preferenceSegments(criteria), [criteria]);
11232
11290
  return /* @__PURE__ */ (0, import_jsx_runtime87.jsx)(
11233
11291
  ScoreMeter,
11234
11292
  {
@@ -11267,10 +11325,10 @@ function PreferenceMeter({
11267
11325
  }
11268
11326
 
11269
11327
  // src/components/chat/AgentChatPanel.tsx
11270
- var React62 = __toESM(require("react"), 1);
11328
+ var React63 = __toESM(require("react"), 1);
11271
11329
 
11272
11330
  // src/components/chat/chatEngine.ts
11273
- var React57 = __toESM(require("react"), 1);
11331
+ var React58 = __toESM(require("react"), 1);
11274
11332
  var CHAT_UNAVAILABLE = "chat_unavailable";
11275
11333
  var JOB_PENDING = ["queued", "running"];
11276
11334
  var JOB_SUCCESS = ["completed", "recovered"];
@@ -11324,22 +11382,22 @@ function useChatEngine(opts) {
11324
11382
  onClear,
11325
11383
  onFeedback
11326
11384
  } = opts || {};
11327
- const [status, setStatus] = React57.useState("idle");
11328
- const [threadId, setThreadId] = React57.useState(null);
11329
- const [messages, setMessages] = React57.useState([]);
11330
- const [queue, setQueue] = React57.useState([]);
11331
- const [fatal, setFatal] = React57.useState(null);
11332
- const [busy, setBusy] = React57.useState(false);
11333
- const [turnStartedAt, setTurnStartedAt] = React57.useState(null);
11334
- const listRef = React57.useRef([]);
11335
- const queueRef = React57.useRef([]);
11336
- const busyRef = React57.useRef(false);
11337
- const stoppedRef = React57.useRef(false);
11338
- const abortRef = React57.useRef(null);
11339
- const serverCount = React57.useRef(0);
11340
- const threadRef = React57.useRef(null);
11341
- const mounted = React57.useRef(true);
11342
- React57.useEffect(() => {
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(() => {
11343
11401
  mounted.current = true;
11344
11402
  return () => {
11345
11403
  mounted.current = false;
@@ -11361,14 +11419,14 @@ function useChatEngine(opts) {
11361
11419
  }
11362
11420
  return false;
11363
11421
  };
11364
- const loadThread = React57.useCallback(async (id) => {
11422
+ const loadThread = React58.useCallback(async (id) => {
11365
11423
  const data = await apiAdapter.getThread(id);
11366
11424
  const list = [...data && data.messages || []];
11367
11425
  serverCount.current = list.length;
11368
11426
  commit(list);
11369
11427
  return list;
11370
11428
  }, [apiAdapter]);
11371
- React57.useEffect(() => {
11429
+ React58.useEffect(() => {
11372
11430
  if (!apiAdapter) {
11373
11431
  setStatus("idle");
11374
11432
  setFatal(null);
@@ -11581,7 +11639,7 @@ function useChatEngine(opts) {
11581
11639
  await dispatchTurn(turn);
11582
11640
  }
11583
11641
  }
11584
- const send = React57.useCallback((text, attachments) => {
11642
+ const send = React58.useCallback((text, attachments) => {
11585
11643
  const body = (text || "").trim();
11586
11644
  if (!body && !(attachments && attachments.length)) return;
11587
11645
  if (status === "disconnected") return;
@@ -11591,7 +11649,7 @@ function useChatEngine(opts) {
11591
11649
  stoppedRef.current = false;
11592
11650
  drain();
11593
11651
  }, [status]);
11594
- const stop = React57.useCallback(() => {
11652
+ const stop = React58.useCallback(() => {
11595
11653
  stoppedRef.current = true;
11596
11654
  const ac = abortRef.current;
11597
11655
  if (ac) {
@@ -11610,11 +11668,11 @@ function useChatEngine(opts) {
11610
11668
  store.del(STORAGE_PREFIX + threadRef.current);
11611
11669
  }
11612
11670
  }, [apiAdapter]);
11613
- const removeQueued = React57.useCallback((id) => {
11671
+ const removeQueued = React58.useCallback((id) => {
11614
11672
  queueRef.current = queueRef.current.filter((t) => t.id !== id);
11615
11673
  setQueue(queueRef.current.slice());
11616
11674
  }, []);
11617
- const retry = React57.useCallback(() => {
11675
+ const retry = React58.useCallback(() => {
11618
11676
  const list = listRef.current;
11619
11677
  let at = -1;
11620
11678
  for (let i = list.length - 1; i >= 0; i--) if (list[i].role === "user") {
@@ -11630,19 +11688,19 @@ function useChatEngine(opts) {
11630
11688
  setQueue(queueRef.current.slice());
11631
11689
  drain();
11632
11690
  }, []);
11633
- const clear = React57.useCallback(() => {
11691
+ const clear = React58.useCallback(() => {
11634
11692
  commit([]);
11635
11693
  serverCount.current = 0;
11636
11694
  queueRef.current = [];
11637
11695
  setQueue([]);
11638
11696
  onClear && onClear();
11639
11697
  }, [onClear]);
11640
- const setFeedback = React57.useCallback((id, value) => {
11698
+ const setFeedback = React58.useCallback((id, value) => {
11641
11699
  patch(id, (m) => ({ feedback: m.feedback === value ? null : value }));
11642
11700
  const msg = listRef.current.find((m) => m.id === id);
11643
11701
  onFeedback && onFeedback({ message: msg, feedback: msg ? msg.feedback : value });
11644
11702
  }, [onFeedback]);
11645
- const reload = React57.useCallback(async () => {
11703
+ const reload = React58.useCallback(async () => {
11646
11704
  if (!threadRef.current) return;
11647
11705
  setStatus("loading");
11648
11706
  try {
@@ -11680,10 +11738,10 @@ var ChatKit = {
11680
11738
  };
11681
11739
 
11682
11740
  // src/components/chat/ChatTranscript.tsx
11683
- var React59 = __toESM(require("react"), 1);
11741
+ var React60 = __toESM(require("react"), 1);
11684
11742
 
11685
11743
  // src/components/chat/ChatTurn.tsx
11686
- var React58 = __toESM(require("react"), 1);
11744
+ var React59 = __toESM(require("react"), 1);
11687
11745
  var import_jsx_runtime88 = require("react/jsx-runtime");
11688
11746
  function JsonView({ value }) {
11689
11747
  let text;
@@ -11720,7 +11778,7 @@ function PacketCard({ packet, schema, render, onApply, applied }) {
11720
11778
  ] });
11721
11779
  }
11722
11780
  function ThinkingBlock({ text, durationMs, streaming, defaultOpen = false }) {
11723
- const [open, setOpen] = React58.useState(defaultOpen);
11781
+ const [open, setOpen] = React59.useState(defaultOpen);
11724
11782
  if (!text) return null;
11725
11783
  return /* @__PURE__ */ (0, import_jsx_runtime88.jsxs)("div", { className: "fdc-think" + (open ? " is-open" : ""), children: [
11726
11784
  /* @__PURE__ */ (0, import_jsx_runtime88.jsxs)("button", { type: "button", className: "fdc-think-head", onClick: () => setOpen((v) => !v), "aria-expanded": open, children: [
@@ -11737,7 +11795,7 @@ function ThinkingBlock({ text, durationMs, streaming, defaultOpen = false }) {
11737
11795
  ] });
11738
11796
  }
11739
11797
  function Citations({ items = [], onOpen }) {
11740
- const [open, setOpen] = React58.useState(false);
11798
+ const [open, setOpen] = React59.useState(false);
11741
11799
  if (!items.length) return null;
11742
11800
  return /* @__PURE__ */ (0, import_jsx_runtime88.jsxs)("div", { className: "fdc-cites", children: [
11743
11801
  /* @__PURE__ */ (0, import_jsx_runtime88.jsxs)("button", { type: "button", className: "fdc-cites-head", onClick: () => setOpen((v) => !v), "aria-expanded": open, children: [
@@ -11763,7 +11821,7 @@ function clampText(text, max) {
11763
11821
  return (at > max * 0.6 ? cut.slice(0, at) : cut).trimEnd() + "\u2026";
11764
11822
  }
11765
11823
  function MessageBody({ message: m, ctx }) {
11766
- const [expanded, setExpanded] = React58.useState(false);
11824
+ const [expanded, setExpanded] = React59.useState(false);
11767
11825
  const isUser = m.role === "user";
11768
11826
  const raw = m.text || "";
11769
11827
  const clamped = !expanded && !m.streaming ? clampText(raw, ctx.maxVisibleChars) : null;
@@ -11830,9 +11888,9 @@ function MessageBody({ message: m, ctx }) {
11830
11888
  ] });
11831
11889
  }
11832
11890
  function useCopyRun() {
11833
- const [done, setDone] = React58.useState(false);
11834
- const t = React58.useRef(null);
11835
- React58.useEffect(() => () => {
11891
+ const [done, setDone] = React59.useState(false);
11892
+ const t = React59.useRef(null);
11893
+ React59.useEffect(() => () => {
11836
11894
  if (t.current) clearTimeout(t.current);
11837
11895
  }, []);
11838
11896
  return [done, (text) => {
@@ -11859,7 +11917,7 @@ function RunActions({ group, ctx }) {
11859
11917
  ] }),
11860
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,
11861
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,
11862
- 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: [
11863
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" }) }),
11864
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" }) })
11865
11923
  ] }) : null,
@@ -11954,10 +12012,10 @@ function ChatTranscript({
11954
12012
  renderEmpty,
11955
12013
  className = ""
11956
12014
  }) {
11957
- const scroller = React59.useRef(null);
11958
- const stick = React59.useRef(true);
11959
- const [pill, setPill] = React59.useState(0);
11960
- const seen = React59.useRef(0);
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);
11961
12019
  const toBottom = (smooth) => {
11962
12020
  const el = scroller.current;
11963
12021
  if (!el) return;
@@ -11976,7 +12034,7 @@ function ChatTranscript({
11976
12034
  seen.current = messages.length;
11977
12035
  }
11978
12036
  };
11979
- React59.useLayoutEffect(() => {
12037
+ React60.useLayoutEffect(() => {
11980
12038
  const el = scroller.current;
11981
12039
  if (!el) return;
11982
12040
  if (stick.current) {
@@ -11984,7 +12042,7 @@ function ChatTranscript({
11984
12042
  seen.current = messages.length;
11985
12043
  } else setPill(Math.max(0, messages.length - seen.current));
11986
12044
  }, [messages]);
11987
- React59.useEffect(() => {
12045
+ React60.useEffect(() => {
11988
12046
  const el = scroller.current;
11989
12047
  const inner = el && el.firstChild;
11990
12048
  if (!el || !inner || typeof ResizeObserver === "undefined") return;
@@ -11994,7 +12052,7 @@ function ChatTranscript({
11994
12052
  ro.observe(inner);
11995
12053
  return () => ro.disconnect();
11996
12054
  }, []);
11997
- const groups = React59.useMemo(() => groupMessages(messages), [messages]);
12055
+ const groups = React60.useMemo(() => groupMessages(messages), [messages]);
11998
12056
  const empty = !messages.length && status === "ready";
11999
12057
  return /* @__PURE__ */ (0, import_jsx_runtime89.jsxs)("div", { className: ["fdc-scroll", className].filter(Boolean).join(" "), ref: scroller, onScroll, children: [
12000
12058
  /* @__PURE__ */ (0, import_jsx_runtime89.jsxs)("div", { className: "fdc-log", role: "log", "aria-label": "Conversation", children: [
@@ -12018,7 +12076,7 @@ function ChatTranscript({
12018
12076
  const prev = groups[i - 1];
12019
12077
  const k = dayKey(g.messages[0].timestamp);
12020
12078
  const showDay = !!k && (!prev || dayKey(prev.messages[0].timestamp) !== k);
12021
- return /* @__PURE__ */ (0, import_jsx_runtime89.jsxs)(React59.Fragment, { children: [
12079
+ return /* @__PURE__ */ (0, import_jsx_runtime89.jsxs)(React60.Fragment, { children: [
12022
12080
  showDay ? /* @__PURE__ */ (0, import_jsx_runtime89.jsx)("div", { className: "fdc-day", children: /* @__PURE__ */ (0, import_jsx_runtime89.jsx)("span", { children: dayLabel(k) }) }) : null,
12023
12081
  /* @__PURE__ */ (0, import_jsx_runtime89.jsx)(ChatTurn, { group: g, ctx })
12024
12082
  ] }, g.key || i);
@@ -12035,7 +12093,7 @@ function ChatTranscript({
12035
12093
  var TranscriptKit = { groupMessages };
12036
12094
 
12037
12095
  // src/components/chat/ChatComposer.tsx
12038
- var React60 = __toESM(require("react"), 1);
12096
+ var React61 = __toESM(require("react"), 1);
12039
12097
  var import_jsx_runtime90 = require("react/jsx-runtime");
12040
12098
  function ChatComposer({
12041
12099
  onSubmit,
@@ -12063,17 +12121,17 @@ function ChatComposer({
12063
12121
  onReject,
12064
12122
  onOpenAttachment
12065
12123
  }) {
12066
- const [text, setText] = React60.useState(draft || "");
12067
- const [trigger, setTrigger] = React60.useState(null);
12068
- const [mentionItems, setMentionItems] = React60.useState([]);
12069
- const [listening, setListening] = React60.useState(false);
12070
- const [notice, setNotice] = React60.useState(null);
12071
- const editor = React60.useRef(null);
12072
- const wrap = React60.useRef(null);
12073
- const stopVoice = React60.useRef(null);
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);
12074
12132
  const staged = useStagedFiles(fileUploadHandler, { onError: () => {
12075
12133
  } });
12076
- React60.useEffect(() => {
12134
+ React61.useEffect(() => {
12077
12135
  if (draft != null && draft !== text) setText(draft);
12078
12136
  }, [draft]);
12079
12137
  const change = (v) => {
@@ -12109,7 +12167,7 @@ function ChatComposer({
12109
12167
  e.preventDefault();
12110
12168
  staged.add(found.files);
12111
12169
  };
12112
- React60.useEffect(() => {
12170
+ React61.useEffect(() => {
12113
12171
  if (!trigger || trigger.type !== "mention" || !mentionSources) {
12114
12172
  setMentionItems([]);
12115
12173
  return;
@@ -12127,7 +12185,7 @@ function ChatComposer({
12127
12185
  const q = (trigger.query || "").toLowerCase();
12128
12186
  setMentionItems(mentionSources.filter((m) => !q || (m.label + " " + (m.description || "")).toLowerCase().includes(q)));
12129
12187
  }, [trigger, mentionSources]);
12130
- const slashItems = React60.useMemo(() => {
12188
+ const slashItems = React61.useMemo(() => {
12131
12189
  if (!trigger || trigger.type !== "slash" || !slashCommands) return [];
12132
12190
  const q = (trigger.query || "").toLowerCase();
12133
12191
  return slashCommands.filter((c) => !q || (c.id + " " + c.label + " " + (c.description || "")).toLowerCase().includes(q));
@@ -12301,12 +12359,12 @@ function ChatComposer({
12301
12359
  }
12302
12360
 
12303
12361
  // src/components/chat/ChatSessionBar.tsx
12304
- var React61 = __toESM(require("react"), 1);
12362
+ var React62 = __toESM(require("react"), 1);
12305
12363
  var import_jsx_runtime91 = require("react/jsx-runtime");
12306
12364
  var compact2 = meterFormats.compact;
12307
12365
  function ChatSessionBar({ sessionStats, contextUsage, usageLimits, onClear, extras }) {
12308
- const [open, setOpen] = React61.useState(false);
12309
- const anchor = React61.useRef(null);
12366
+ const [open, setOpen] = React62.useState(false);
12367
+ const anchor = React62.useRef(null);
12310
12368
  const stats = sessionStats || null;
12311
12369
  const cu = contextUsage || null;
12312
12370
  const limits = usageLimits || null;
@@ -12321,7 +12379,7 @@ function ChatSessionBar({ sessionStats, contextUsage, usageLimits, onClear, extr
12321
12379
  if (stats && stats.runningTasks) bits.push(stats.runningTasks + " running task" + (stats.runningTasks === 1 ? "" : "s"));
12322
12380
  if (cu) bits.push(pct + "% context");
12323
12381
  const expandable = !!(cu || limits);
12324
- return /* @__PURE__ */ (0, import_jsx_runtime91.jsxs)(React61.Fragment, { children: [
12382
+ return /* @__PURE__ */ (0, import_jsx_runtime91.jsxs)(React62.Fragment, { children: [
12325
12383
  /* @__PURE__ */ (0, import_jsx_runtime91.jsxs)("div", { className: "fdc-bar", children: [
12326
12384
  /* @__PURE__ */ (0, import_jsx_runtime91.jsxs)(
12327
12385
  "button",
@@ -12462,7 +12520,7 @@ function ModelControls({
12462
12520
  ] })
12463
12521
  });
12464
12522
  }
12465
- return /* @__PURE__ */ (0, import_jsx_runtime91.jsxs)(React61.Fragment, { children: [
12523
+ return /* @__PURE__ */ (0, import_jsx_runtime91.jsxs)(React62.Fragment, { children: [
12466
12524
  /* @__PURE__ */ (0, import_jsx_runtime91.jsx)(
12467
12525
  MenuButton,
12468
12526
  {
@@ -12579,11 +12637,11 @@ function AgentChatPanel({
12579
12637
  onFeedback,
12580
12638
  onEditMessage
12581
12639
  }) {
12582
- const [panelWidth, setPanelWidth] = React62.useState(width);
12583
- const [applied, setApplied] = React62.useState({});
12584
- const [draft, setDraft] = React62.useState("");
12585
- const dragging = React62.useRef(null);
12586
- React62.useEffect(() => setPanelWidth(width), [width]);
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]);
12587
12645
  const engine = useChatEngine({
12588
12646
  contextType,
12589
12647
  contextId,
@@ -12787,7 +12845,7 @@ function AgentChatPanel({
12787
12845
  }
12788
12846
 
12789
12847
  // src/components/files/FileViewer.tsx
12790
- var React63 = __toESM(require("react"), 1);
12848
+ var React64 = __toESM(require("react"), 1);
12791
12849
  var import_jsx_runtime93 = require("react/jsx-runtime");
12792
12850
  function previewKindOf(file) {
12793
12851
  const mime = (file.mime || "").toLowerCase();
@@ -12844,13 +12902,13 @@ function parseDelimited(text, delimiter) {
12844
12902
  return rows;
12845
12903
  }
12846
12904
  function usePreview(file, kind, resolveUrl) {
12847
- const [state, setState] = React63.useState({ status: "loading" });
12848
- const [attempt, setAttempt] = React63.useState(0);
12849
- const resolveRef = React63.useRef(resolveUrl);
12850
- React63.useEffect(() => {
12905
+ const [state, setState] = React64.useState({ status: "loading" });
12906
+ const [attempt, setAttempt] = React64.useState(0);
12907
+ const resolveRef = React64.useRef(resolveUrl);
12908
+ React64.useEffect(() => {
12851
12909
  resolveRef.current = resolveUrl;
12852
12910
  }, [resolveUrl]);
12853
- React63.useEffect(() => {
12911
+ React64.useEffect(() => {
12854
12912
  if (kind === "none") {
12855
12913
  setState({ status: "ready" });
12856
12914
  return;
@@ -12880,7 +12938,7 @@ function usePreview(file, kind, resolveUrl) {
12880
12938
  if (ac) ac.abort();
12881
12939
  };
12882
12940
  }, [file.id, kind, attempt]);
12883
- return { ...state, retry: React63.useCallback(() => setAttempt((a) => a + 1), []) };
12941
+ return { ...state, retry: React64.useCallback(() => setAttempt((a) => a + 1), []) };
12884
12942
  }
12885
12943
  function PreviewBody({ file, kind, state }) {
12886
12944
  if (kind === "image") return /* @__PURE__ */ (0, import_jsx_runtime93.jsx)("img", { className: "fd-fv-image", src: state.url, alt: file.name || "Preview" });
@@ -12925,13 +12983,13 @@ function PreviewBody({ file, kind, state }) {
12925
12983
  ] });
12926
12984
  }
12927
12985
  function FileViewer({ file, resolveUrl, sidePanel, sidePanelLabel = "Details", onClose, actions, className = "" }) {
12928
- const kind = React63.useMemo(() => previewKindOf(file), [file]);
12986
+ const kind = React64.useMemo(() => previewKindOf(file), [file]);
12929
12987
  const preview = usePreview(file, kind, resolveUrl);
12930
- const [tab, setTab] = React63.useState("preview");
12931
- const [downloading, setDownloading] = React63.useState(false);
12932
- const [downloadError, setDownloadError] = React63.useState(null);
12988
+ const [tab, setTab] = React64.useState("preview");
12989
+ const [downloading, setDownloading] = React64.useState(false);
12990
+ const [downloadError, setDownloadError] = React64.useState(null);
12933
12991
  const hasSide = sidePanel != null;
12934
- React63.useEffect(() => {
12992
+ React64.useEffect(() => {
12935
12993
  setTab("preview");
12936
12994
  }, [file.id]);
12937
12995
  const download = () => {
@@ -12998,7 +13056,7 @@ function FileViewer({ file, resolveUrl, sidePanel, sidePanelLabel = "Details", o
12998
13056
  }
12999
13057
 
13000
13058
  // src/components/files/FileBrowser.tsx
13001
- var React64 = __toESM(require("react"), 1);
13059
+ var React65 = __toESM(require("react"), 1);
13002
13060
  var import_jsx_runtime94 = require("react/jsx-runtime");
13003
13061
  function childrenOf(folders, parentId) {
13004
13062
  return folders.filter((f) => f.parentId === parentId).sort((a, b) => a.name.localeCompare(b.name));
@@ -13069,10 +13127,10 @@ function FolderPickerMenu({
13069
13127
  destinations,
13070
13128
  onPick
13071
13129
  }) {
13072
- const [open, setOpen] = React64.useState(false);
13130
+ const [open, setOpen] = React65.useState(false);
13073
13131
  const zIndex = useOverlayLayer(open);
13074
- const ref = React64.useRef(null);
13075
- React64.useEffect(() => {
13132
+ const ref = React65.useRef(null);
13133
+ React65.useEffect(() => {
13076
13134
  if (!open) return;
13077
13135
  const away = (e) => {
13078
13136
  if (ref.current && !ref.current.contains(e.target)) setOpen(false);
@@ -13124,8 +13182,8 @@ function FolderPickerMenu({
13124
13182
  ] });
13125
13183
  }
13126
13184
  function RowShell({ icon, name, meta, onOpen, draggableId, isDropTarget, onDropPayload, actions, className = "" }) {
13127
- const [over, setOver] = React64.useState(false);
13128
- const dragCounter = React64.useRef(0);
13185
+ const [over, setOver] = React65.useState(false);
13186
+ const dragCounter = React65.useRef(0);
13129
13187
  const dropHandlers = isDropTarget ? {
13130
13188
  onDragEnter: (e) => {
13131
13189
  if (!hasInternalPayload(e)) return;
@@ -13173,8 +13231,8 @@ function RowShell({ icon, name, meta, onOpen, draggableId, isDropTarget, onDropP
13173
13231
  }
13174
13232
  function TreeNode({ folder, depth, folders, currentFolderId, onNavigate, onMoveInto, canMove }) {
13175
13233
  const kids = childrenOf(folders, folder.id);
13176
- const [expanded, setExpanded] = React64.useState(() => currentFolderId != null && isSelfOrDescendant(folders, folder.id, currentFolderId));
13177
- React64.useEffect(() => {
13234
+ const [expanded, setExpanded] = React65.useState(() => currentFolderId != null && isSelfOrDescendant(folders, folder.id, currentFolderId));
13235
+ React65.useEffect(() => {
13178
13236
  if (currentFolderId != null && isSelfOrDescendant(folders, folder.id, currentFolderId)) setExpanded(true);
13179
13237
  }, [currentFolderId, folder.id, folders]);
13180
13238
  const isCurrent = folder.id === currentFolderId;
@@ -13240,15 +13298,15 @@ function FileBrowser({
13240
13298
  const canUpload = perm.canUpload !== false && !!onUpload;
13241
13299
  const canRemoveFile = perm.canRemoveFile !== false && !!onRemoveFile;
13242
13300
  const canDeleteFolder = perm.canDeleteFolder !== false && !!onDeleteFolder;
13243
- const [createOpen, setCreateOpen] = React64.useState(false);
13244
- const [createName, setCreateName] = React64.useState("");
13245
- const [renameTarget, setRenameTarget] = React64.useState(null);
13246
- const [renameValue, setRenameValue] = React64.useState("");
13247
- const [deleteTarget, setDeleteTarget] = React64.useState(null);
13248
- const uploadInputRef = React64.useRef(null);
13249
- const crumbFolders = React64.useMemo(() => ancestorsOf(folders, currentFolderId), [folders, currentFolderId]);
13250
- const subfolders = React64.useMemo(() => childrenOf(folders, currentFolderId), [folders, currentFolderId]);
13251
- const currentFiles = React64.useMemo(
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(
13252
13310
  () => files.filter((f) => f.folderId === currentFolderId).sort((a, b) => a.name.localeCompare(b.name)),
13253
13311
  [files, currentFolderId]
13254
13312
  );
@@ -13480,8 +13538,8 @@ function BreadcrumbCrumb({
13480
13538
  isDropTarget,
13481
13539
  onDropPayload
13482
13540
  }) {
13483
- const [over, setOver] = React64.useState(false);
13484
- const dragCounter = React64.useRef(0);
13541
+ const [over, setOver] = React65.useState(false);
13542
+ const dragCounter = React65.useRef(0);
13485
13543
  const dropHandlers = isDropTarget ? {
13486
13544
  onDragEnter: (e) => {
13487
13545
  if (!hasInternalPayload(e)) return;
@@ -13510,7 +13568,7 @@ function BreadcrumbCrumb({
13510
13568
  }
13511
13569
 
13512
13570
  // src/kits/query.ts
13513
- var React65 = __toESM(require("react"), 1);
13571
+ var React66 = __toESM(require("react"), 1);
13514
13572
  var isMultiSelectShaped = (v) => !!v && typeof v === "object" && Array.isArray(v.values);
13515
13573
  var isRangeShaped = (v) => !!v && typeof v === "object" && ("min" in v || "max" in v);
13516
13574
  var isDateShaped = (v) => !!v && typeof v === "object" && "kind" in v;
@@ -13565,22 +13623,22 @@ function compare(a, b, dir) {
13565
13623
  var API = null;
13566
13624
  var PREFS = null;
13567
13625
  function useServerTable({ endpoint, params, defaults, deps, prefsKey }) {
13568
- const [query, setQuery] = React65.useState(() => {
13626
+ const [query, setQuery] = React66.useState(() => {
13569
13627
  const store = PREFS || window.PlannerPrefs;
13570
13628
  const saved = prefsKey && store ? store.getTable(prefsKey) : {};
13571
13629
  return { ...DEFAULTS, ...defaults || {}, ...saved.pageSize ? { pageSize: saved.pageSize } : {}, ...saved.sort ? { sort: saved.sort, dir: saved.dir || "desc" } : {} };
13572
13630
  });
13573
- const savePref = React65.useCallback((patch2) => {
13631
+ const savePref = React66.useCallback((patch2) => {
13574
13632
  const store = PREFS || window.PlannerPrefs;
13575
13633
  if (prefsKey && store) store.setTable(prefsKey, patch2);
13576
13634
  }, [prefsKey]);
13577
- const [res, setRes] = React65.useState(null);
13578
- const [loading, setLoading] = React65.useState(true);
13579
- 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);
13580
13638
  const depKey = (deps || []).join("|");
13581
13639
  const paramKey = JSON.stringify(params || {});
13582
13640
  const queryKey = JSON.stringify(query);
13583
- React65.useEffect(() => {
13641
+ React66.useEffect(() => {
13584
13642
  const id = ++seq2.current;
13585
13643
  setLoading(true);
13586
13644
  const t = setTimeout(() => {
@@ -13899,12 +13957,12 @@ function createVersionStore(initialState, options) {
13899
13957
  }
13900
13958
 
13901
13959
  // src/kits/documentTitle.ts
13902
- var React66 = __toESM(require("react"), 1);
13960
+ var React67 = __toESM(require("react"), 1);
13903
13961
  function formatDocumentTitle(routeTitle, appName) {
13904
13962
  return [routeTitle, appName, "Flytedesk"].filter((part) => !!part && part.length > 0).join(" \xB7 ");
13905
13963
  }
13906
13964
  function useDocumentTitle(routeTitle, appName) {
13907
- React66.useEffect(() => {
13965
+ React67.useEffect(() => {
13908
13966
  if (typeof document === "undefined") return;
13909
13967
  document.title = formatDocumentTitle(routeTitle, appName);
13910
13968
  }, [routeTitle, appName]);