@flytedan/flytebot-design-system 0.28.0 → 0.30.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 +910 -761
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +79 -51
- package/dist/index.d.ts +79 -51
- package/dist/index.js +910 -761
- package/dist/index.js.map +1 -1
- package/package.json +1 -1
- package/styles/components.css +50 -0
package/dist/index.cjs
CHANGED
|
@@ -438,6 +438,15 @@ var ROOT_LAYER = 0;
|
|
|
438
438
|
var LAYER_STEP = 10;
|
|
439
439
|
var ROOT_STEP = 100;
|
|
440
440
|
var OVERLAY_CEILING = 1e4;
|
|
441
|
+
var openEscapeIds = [];
|
|
442
|
+
var registerEscapeLayer = (id) => {
|
|
443
|
+
if (openEscapeIds.includes(id)) return;
|
|
444
|
+
openEscapeIds = [...openEscapeIds, id];
|
|
445
|
+
};
|
|
446
|
+
var unregisterEscapeLayer = (id) => {
|
|
447
|
+
if (!openEscapeIds.includes(id)) return;
|
|
448
|
+
openEscapeIds = openEscapeIds.filter((existing) => existing !== id);
|
|
449
|
+
};
|
|
441
450
|
var LayerContext = React2.createContext(ROOT_LAYER);
|
|
442
451
|
var openRootIds = [];
|
|
443
452
|
var rootListeners = /* @__PURE__ */ new Set();
|
|
@@ -515,6 +524,12 @@ function Popover({
|
|
|
515
524
|
});
|
|
516
525
|
const restore = React2.useRef(null);
|
|
517
526
|
const zIndex = useOverlayLayer(!!open);
|
|
527
|
+
const escapeId = React2.useId();
|
|
528
|
+
React2.useLayoutEffect(() => {
|
|
529
|
+
if (!open) return;
|
|
530
|
+
registerEscapeLayer(escapeId);
|
|
531
|
+
return () => unregisterEscapeLayer(escapeId);
|
|
532
|
+
}, [open, escapeId]);
|
|
518
533
|
React2.useEffect(() => {
|
|
519
534
|
if (!open) return;
|
|
520
535
|
restore.current = typeof document !== "undefined" ? document.activeElement : null;
|
|
@@ -539,10 +554,10 @@ function Popover({
|
|
|
539
554
|
onClose && onClose();
|
|
540
555
|
};
|
|
541
556
|
const key = (e) => {
|
|
542
|
-
if (closeOnEscape
|
|
543
|
-
|
|
544
|
-
|
|
545
|
-
|
|
557
|
+
if (!closeOnEscape || e.key !== "Escape") return;
|
|
558
|
+
if (openEscapeIds[openEscapeIds.length - 1] !== escapeId) return;
|
|
559
|
+
e.stopPropagation();
|
|
560
|
+
onClose && onClose();
|
|
546
561
|
};
|
|
547
562
|
document.addEventListener("pointerdown", away, true);
|
|
548
563
|
document.addEventListener("keydown", key);
|
|
@@ -550,7 +565,7 @@ function Popover({
|
|
|
550
565
|
document.removeEventListener("pointerdown", away, true);
|
|
551
566
|
document.removeEventListener("keydown", key);
|
|
552
567
|
};
|
|
553
|
-
}, [open, closeOnOutside, closeOnEscape, onClose, anchorRef, triggerRef]);
|
|
568
|
+
}, [open, closeOnOutside, closeOnEscape, onClose, anchorRef, triggerRef, escapeId]);
|
|
554
569
|
if (!open || !pos) return null;
|
|
555
570
|
return portal(
|
|
556
571
|
/* @__PURE__ */ (0, import_jsx_runtime3.jsx)(LayerProvider, { zIndex, children: /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)(
|
|
@@ -1739,11 +1754,13 @@ var BANNER_TONE_STYLE = {
|
|
|
1739
1754
|
text: "var(--danger-text)"
|
|
1740
1755
|
}
|
|
1741
1756
|
};
|
|
1742
|
-
function Banner({ tone = "info", title, detail, actions }) {
|
|
1757
|
+
function Banner({ tone = "info", title, detail, actions, role }) {
|
|
1743
1758
|
const t = BANNER_TONE_STYLE[tone];
|
|
1759
|
+
const liveRole = role || (tone === "danger" ? "alert" : "status");
|
|
1744
1760
|
return /* @__PURE__ */ (0, import_jsx_runtime23.jsxs)(
|
|
1745
1761
|
"div",
|
|
1746
1762
|
{
|
|
1763
|
+
role: liveRole,
|
|
1747
1764
|
style: {
|
|
1748
1765
|
display: "flex",
|
|
1749
1766
|
alignItems: "flex-start",
|
|
@@ -2953,7 +2970,7 @@ function DataTable({
|
|
|
2953
2970
|
}
|
|
2954
2971
|
|
|
2955
2972
|
// src/components/data/FilterBar.tsx
|
|
2956
|
-
var
|
|
2973
|
+
var React24 = __toESM(require("react"), 1);
|
|
2957
2974
|
|
|
2958
2975
|
// src/components/forms/NumberInput.tsx
|
|
2959
2976
|
var React21 = __toESM(require("react"), 1);
|
|
@@ -3001,21 +3018,36 @@ function NumberInput({
|
|
|
3001
3018
|
"aria-label": ariaLabel
|
|
3002
3019
|
}) {
|
|
3003
3020
|
const fieldId = useFieldId(id);
|
|
3021
|
+
const errorId = fieldId + "-error";
|
|
3004
3022
|
const num = (v) => {
|
|
3005
|
-
const
|
|
3023
|
+
const s = String(v == null ? "" : v).replace(/[^0-9.-]/g, "");
|
|
3024
|
+
if (s === "" || s === "-") return null;
|
|
3025
|
+
const n = Number(s);
|
|
3006
3026
|
return isNaN(n) ? null : n;
|
|
3007
3027
|
};
|
|
3028
|
+
const requiresInteger = Number.isInteger(step);
|
|
3029
|
+
const validationMessage = (n) => {
|
|
3030
|
+
if (requiresInteger && !Number.isInteger(n)) return "Enter a whole number";
|
|
3031
|
+
if (n < min) return "Must be \u2265 " + min;
|
|
3032
|
+
if (n > max) return "Must be \u2264 " + max;
|
|
3033
|
+
return null;
|
|
3034
|
+
};
|
|
3008
3035
|
const [text, setText] = React21.useState(value == null || value === "" ? "" : String(value));
|
|
3009
3036
|
const [editing, setEditing] = React21.useState(false);
|
|
3037
|
+
const [invalidMessage, setInvalidMessage] = React21.useState(null);
|
|
3010
3038
|
const timer = React21.useRef(null);
|
|
3011
3039
|
React21.useEffect(() => {
|
|
3012
|
-
if (!editing)
|
|
3040
|
+
if (!editing) {
|
|
3041
|
+
setText(value == null || value === "" ? "" : String(value));
|
|
3042
|
+
setInvalidMessage(null);
|
|
3043
|
+
}
|
|
3013
3044
|
}, [value, editing]);
|
|
3014
3045
|
const clamp = (n) => Math.min(max, Math.max(min, n));
|
|
3015
3046
|
const fire = (n) => onChange && onChange({ target: { value: n } });
|
|
3016
3047
|
const bump = (dir, mult = 1) => {
|
|
3017
3048
|
const cur = num(text) ?? num(value) ?? (min === -Infinity ? 0 : min);
|
|
3018
3049
|
const next = clamp(cur + dir * (bigStep && mult > 1 ? bigStep : step) * (bigStep ? 1 : mult));
|
|
3050
|
+
setInvalidMessage(null);
|
|
3019
3051
|
setText(String(next));
|
|
3020
3052
|
fire(next);
|
|
3021
3053
|
};
|
|
@@ -3039,7 +3071,8 @@ function NumberInput({
|
|
|
3039
3071
|
const n = num(text);
|
|
3040
3072
|
return n == null ? "" : format ? n.toLocaleString() : String(n);
|
|
3041
3073
|
})();
|
|
3042
|
-
const
|
|
3074
|
+
const shownError = error || invalidMessage || void 0;
|
|
3075
|
+
const box = ["fd-input", "fd-input-num", shownError ? "fd-input-error" : "", disabled ? "fd-input-disabled" : ""].filter(Boolean).join(" ");
|
|
3043
3076
|
const fieldName = label || ariaLabel;
|
|
3044
3077
|
const stepperName = (verb) => fieldName ? verb + " " + fieldName : verb;
|
|
3045
3078
|
return /* @__PURE__ */ (0, import_jsx_runtime42.jsxs)("div", { className: ["fd-field", className].filter(Boolean).join(" "), style, children: [
|
|
@@ -3055,20 +3088,29 @@ function NumberInput({
|
|
|
3055
3088
|
disabled,
|
|
3056
3089
|
placeholder,
|
|
3057
3090
|
value: shown,
|
|
3091
|
+
"aria-invalid": shownError ? "true" : void 0,
|
|
3092
|
+
"aria-describedby": shownError ? errorId : void 0,
|
|
3058
3093
|
onFocus: () => setEditing(true),
|
|
3059
3094
|
onBlur: () => {
|
|
3060
3095
|
setEditing(false);
|
|
3061
|
-
|
|
3062
|
-
if (n != null) {
|
|
3063
|
-
const c = clamp(n);
|
|
3064
|
-
setText(String(c));
|
|
3065
|
-
fire(c);
|
|
3066
|
-
}
|
|
3096
|
+
if (text.trim() === "") fire(void 0);
|
|
3067
3097
|
},
|
|
3068
3098
|
onChange: (e) => {
|
|
3069
|
-
|
|
3070
|
-
|
|
3071
|
-
if (
|
|
3099
|
+
const raw = e.target.value;
|
|
3100
|
+
setText(raw);
|
|
3101
|
+
if (raw.trim() === "") {
|
|
3102
|
+
setInvalidMessage(null);
|
|
3103
|
+
fire(void 0);
|
|
3104
|
+
return;
|
|
3105
|
+
}
|
|
3106
|
+
const n = num(raw);
|
|
3107
|
+
if (n == null) {
|
|
3108
|
+
setInvalidMessage("Enter a number");
|
|
3109
|
+
return;
|
|
3110
|
+
}
|
|
3111
|
+
const message = validationMessage(n);
|
|
3112
|
+
setInvalidMessage(message);
|
|
3113
|
+
if (!message) fire(n);
|
|
3072
3114
|
},
|
|
3073
3115
|
onKeyDown: (e) => {
|
|
3074
3116
|
if (e.key === "ArrowUp") {
|
|
@@ -3111,9 +3153,9 @@ function NumberInput({
|
|
|
3111
3153
|
)
|
|
3112
3154
|
] })
|
|
3113
3155
|
] }),
|
|
3114
|
-
|
|
3156
|
+
shownError ? /* @__PURE__ */ (0, import_jsx_runtime42.jsxs)("span", { id: errorId, className: "fd-field-error", children: [
|
|
3115
3157
|
/* @__PURE__ */ (0, import_jsx_runtime42.jsx)("i", { className: "ph ph-warning-circle", "aria-hidden": "true" }),
|
|
3116
|
-
|
|
3158
|
+
shownError
|
|
3117
3159
|
] }) : help ? /* @__PURE__ */ (0, import_jsx_runtime42.jsx)("span", { className: "fd-field-help", children: help }) : null
|
|
3118
3160
|
] });
|
|
3119
3161
|
}
|
|
@@ -3335,16 +3377,48 @@ function Textarea({ label, help, error, required = false, rows = 4, disabled = f
|
|
|
3335
3377
|
] });
|
|
3336
3378
|
}
|
|
3337
3379
|
|
|
3380
|
+
// src/components/forms/listbox.ts
|
|
3381
|
+
var React23 = __toESM(require("react"), 1);
|
|
3382
|
+
function useListboxNav({ count, onSelect }) {
|
|
3383
|
+
const [active, setActive] = React23.useState(-1);
|
|
3384
|
+
return {
|
|
3385
|
+
active,
|
|
3386
|
+
setActive,
|
|
3387
|
+
move: (dir) => setActive((a) => Math.min(count - 1, Math.max(0, a + dir))),
|
|
3388
|
+
first: () => setActive(0),
|
|
3389
|
+
last: () => setActive(count - 1),
|
|
3390
|
+
activate: () => {
|
|
3391
|
+
if (active >= 0 && active < count) onSelect(active);
|
|
3392
|
+
}
|
|
3393
|
+
};
|
|
3394
|
+
}
|
|
3395
|
+
function useListboxScrollIntoView(active, listRef, enabled) {
|
|
3396
|
+
React23.useEffect(() => {
|
|
3397
|
+
if (!enabled || active < 0 || !listRef.current) return;
|
|
3398
|
+
const list = listRef.current;
|
|
3399
|
+
const el = list.querySelector('[data-i="' + active + '"]');
|
|
3400
|
+
if (!el) return;
|
|
3401
|
+
const top = el.offsetTop - list.offsetTop;
|
|
3402
|
+
if (top < list.scrollTop) list.scrollTop = top - 4;
|
|
3403
|
+
else if (top + el.offsetHeight > list.scrollTop + list.clientHeight) {
|
|
3404
|
+
list.scrollTop = top + el.offsetHeight - list.clientHeight + 4;
|
|
3405
|
+
}
|
|
3406
|
+
}, [active, enabled]);
|
|
3407
|
+
}
|
|
3408
|
+
|
|
3338
3409
|
// src/components/data/FilterBar.tsx
|
|
3339
3410
|
var import_jsx_runtime45 = require("react/jsx-runtime");
|
|
3411
|
+
var PANEL_WIDTH = { multiSelect: 280, range: 240, date: 300 };
|
|
3340
3412
|
var isSet = (v) => !(v == null || v === "" || v === false);
|
|
3413
|
+
function operatorsFor(field) {
|
|
3414
|
+
return field.operators && field.operators.length ? field.operators : ["in", "notIn"];
|
|
3415
|
+
}
|
|
3341
3416
|
function isFieldSet(field, value) {
|
|
3342
3417
|
switch (field.type) {
|
|
3343
3418
|
case "text":
|
|
3344
3419
|
case "select":
|
|
3345
3420
|
return isSet(value);
|
|
3346
|
-
case "multiSelect":
|
|
3347
|
-
case "pasteList": {
|
|
3421
|
+
case "multiSelect": {
|
|
3348
3422
|
const v = value;
|
|
3349
3423
|
return !!v && Array.isArray(v.values) && v.values.length > 0;
|
|
3350
3424
|
}
|
|
@@ -3355,7 +3429,7 @@ function isFieldSet(field, value) {
|
|
|
3355
3429
|
case "date": {
|
|
3356
3430
|
const v = value;
|
|
3357
3431
|
if (!v) return false;
|
|
3358
|
-
return v.kind === "withinDays" ? v.days != null : !!(v.from
|
|
3432
|
+
return v.kind === "withinDays" ? v.days != null : !!(v.from && v.to);
|
|
3359
3433
|
}
|
|
3360
3434
|
}
|
|
3361
3435
|
}
|
|
@@ -3367,8 +3441,7 @@ function chipLabel(field, value) {
|
|
|
3367
3441
|
const chosen = field.options.find((o) => o.value === value);
|
|
3368
3442
|
return chosen ? chosen.label : String(value ?? "");
|
|
3369
3443
|
}
|
|
3370
|
-
case "multiSelect":
|
|
3371
|
-
case "pasteList": {
|
|
3444
|
+
case "multiSelect": {
|
|
3372
3445
|
const v = value;
|
|
3373
3446
|
if (!v || !v.values.length) return "";
|
|
3374
3447
|
const prefix = v.operator === "notIn" ? "Not " : "";
|
|
@@ -3386,7 +3459,7 @@ function chipLabel(field, value) {
|
|
|
3386
3459
|
const v = value;
|
|
3387
3460
|
if (!v) return "";
|
|
3388
3461
|
if (v.kind === "withinDays") return "Last " + v.days + " day" + (v.days === 1 ? "" : "s");
|
|
3389
|
-
return
|
|
3462
|
+
return v.from + " \u2192 " + v.to;
|
|
3390
3463
|
}
|
|
3391
3464
|
}
|
|
3392
3465
|
}
|
|
@@ -3408,338 +3481,395 @@ function OperatorToggle({
|
|
|
3408
3481
|
}
|
|
3409
3482
|
);
|
|
3410
3483
|
}
|
|
3411
|
-
function EditPopover({ zIndex, width, children }) {
|
|
3412
|
-
return /* @__PURE__ */ (0, import_jsx_runtime45.jsx)(LayerProvider, { zIndex, children: /* @__PURE__ */ (0, import_jsx_runtime45.jsx)(
|
|
3413
|
-
"span",
|
|
3414
|
-
{
|
|
3415
|
-
className: "fd-view-enter",
|
|
3416
|
-
style: {
|
|
3417
|
-
position: "absolute",
|
|
3418
|
-
top: "calc(100% + 6px)",
|
|
3419
|
-
left: 0,
|
|
3420
|
-
zIndex,
|
|
3421
|
-
width,
|
|
3422
|
-
maxWidth: "calc(100vw - 32px)",
|
|
3423
|
-
display: "block",
|
|
3424
|
-
background: "var(--surface)",
|
|
3425
|
-
border: "1px solid var(--border)",
|
|
3426
|
-
borderRadius: 10,
|
|
3427
|
-
boxShadow: "0 16px 44px rgba(11,13,17,.18)",
|
|
3428
|
-
padding: "var(--s-8)"
|
|
3429
|
-
},
|
|
3430
|
-
children
|
|
3431
|
-
}
|
|
3432
|
-
) });
|
|
3433
|
-
}
|
|
3434
3484
|
function MultiSelectPanel({
|
|
3435
3485
|
field,
|
|
3436
3486
|
value,
|
|
3487
|
+
anchorRef,
|
|
3437
3488
|
onChange,
|
|
3489
|
+
onRemove,
|
|
3438
3490
|
onClose
|
|
3439
3491
|
}) {
|
|
3440
|
-
const
|
|
3492
|
+
const allowedOps = operatorsFor(field);
|
|
3493
|
+
const [draftOperator, setDraftOperator] = React24.useState(value?.operator ?? allowedOps[0]);
|
|
3494
|
+
const operator = allowedOps.length === 1 ? allowedOps[0] : value?.operator ?? draftOperator;
|
|
3441
3495
|
const selected = value?.values ?? [];
|
|
3442
|
-
const
|
|
3443
|
-
|
|
3444
|
-
const
|
|
3445
|
-
|
|
3446
|
-
|
|
3447
|
-
|
|
3448
|
-
|
|
3496
|
+
const selectedRef = React24.useRef(selected);
|
|
3497
|
+
selectedRef.current = selected;
|
|
3498
|
+
const commit = (nextValues, nextOperator = operator) => {
|
|
3499
|
+
if (nextValues.length === 0) onRemove();
|
|
3500
|
+
else onChange({ operator: nextOperator, values: nextValues });
|
|
3501
|
+
};
|
|
3502
|
+
const setOperator = (op) => {
|
|
3503
|
+
setDraftOperator(op);
|
|
3504
|
+
if (selected.length > 0) commit(selected, op);
|
|
3505
|
+
};
|
|
3506
|
+
const [mode2, setMode] = React24.useState("search");
|
|
3507
|
+
const [query, setQuery] = React24.useState("");
|
|
3508
|
+
const [asyncState, setAsyncState] = React24.useState(
|
|
3509
|
+
{ options: null, loading: !!field.loadOptions, error: false }
|
|
3510
|
+
);
|
|
3511
|
+
const [retryTick, setRetryTick] = React24.useState(0);
|
|
3512
|
+
const inputRef = React24.useRef(null);
|
|
3513
|
+
const listRef = React24.useRef(null);
|
|
3514
|
+
const listId = React24.useId();
|
|
3515
|
+
const loadOptionsRef = React24.useRef(field.loadOptions);
|
|
3516
|
+
loadOptionsRef.current = field.loadOptions;
|
|
3517
|
+
React24.useEffect(() => {
|
|
3449
3518
|
inputRef.current?.focus();
|
|
3450
3519
|
}, []);
|
|
3451
|
-
|
|
3452
|
-
|
|
3453
|
-
|
|
3454
|
-
|
|
3455
|
-
|
|
3520
|
+
React24.useEffect(() => {
|
|
3521
|
+
const load = loadOptionsRef.current;
|
|
3522
|
+
if (!load) return;
|
|
3523
|
+
const controller = new AbortController();
|
|
3524
|
+
setAsyncState((s) => ({ options: s.options, loading: true, error: false }));
|
|
3456
3525
|
const t = setTimeout(() => {
|
|
3457
|
-
|
|
3458
|
-
if (
|
|
3459
|
-
|
|
3460
|
-
|
|
3461
|
-
|
|
3462
|
-
|
|
3463
|
-
if (!cancelled) {
|
|
3464
|
-
setAsyncOptions([]);
|
|
3465
|
-
setLoading(false);
|
|
3466
|
-
}
|
|
3526
|
+
load(query, controller.signal).then((opts) => {
|
|
3527
|
+
if (controller.signal.aborted) return;
|
|
3528
|
+
setAsyncState({ options: opts, loading: false, error: false });
|
|
3529
|
+
}).catch((err) => {
|
|
3530
|
+
if (controller.signal.aborted || err && err.name === "AbortError") return;
|
|
3531
|
+
setAsyncState({ options: null, loading: false, error: true });
|
|
3467
3532
|
});
|
|
3468
3533
|
}, 300);
|
|
3469
3534
|
return () => {
|
|
3470
|
-
cancelled = true;
|
|
3471
3535
|
clearTimeout(t);
|
|
3536
|
+
controller.abort();
|
|
3472
3537
|
};
|
|
3473
|
-
}, [query,
|
|
3474
|
-
const options = field.loadOptions ?
|
|
3475
|
-
|
|
3476
|
-
|
|
3477
|
-
|
|
3538
|
+
}, [query, retryTick]);
|
|
3539
|
+
const options = field.loadOptions ? asyncState.options ?? [] : (field.options ?? []).filter((o) => o.label.toLowerCase().includes(query.toLowerCase()));
|
|
3540
|
+
const showLoading = !!field.loadOptions && asyncState.loading;
|
|
3541
|
+
const showError = !!field.loadOptions && asyncState.error;
|
|
3542
|
+
const hasListbox = !showLoading && !showError && options.length > 0;
|
|
3478
3543
|
const isSelected = (o) => selected.some((s) => s.value === o.value);
|
|
3479
3544
|
const toggle = (o) => {
|
|
3480
3545
|
const next = isSelected(o) ? selected.filter((s) => s.value !== o.value) : [...selected, o];
|
|
3481
|
-
|
|
3546
|
+
commit(next);
|
|
3547
|
+
};
|
|
3548
|
+
const nav = useListboxNav({ count: options.length, onSelect: (i) => toggle(options[i]) });
|
|
3549
|
+
useListboxScrollIntoView(nav.active, listRef, hasListbox);
|
|
3550
|
+
React24.useEffect(() => {
|
|
3551
|
+
nav.setActive(0);
|
|
3552
|
+
}, [query, options.length]);
|
|
3553
|
+
const activeId = hasListbox && options[nav.active] ? listId + "-opt-" + nav.active : void 0;
|
|
3554
|
+
const liveRole = showError ? "alert" : "status";
|
|
3555
|
+
const liveMessage = showLoading ? "Loading\u2026" : showError ? "Couldn't load options." : options.length === 0 ? "No matches" : "";
|
|
3556
|
+
const [pasteText, setPasteText] = React24.useState("");
|
|
3557
|
+
const [pasteLoading, setPasteLoading] = React24.useState(false);
|
|
3558
|
+
const [unmatchedTokens, setUnmatchedTokens] = React24.useState([]);
|
|
3559
|
+
const [pasteError, setPasteError] = React24.useState(null);
|
|
3560
|
+
const pasteWrapRef = React24.useRef(null);
|
|
3561
|
+
React24.useEffect(() => {
|
|
3562
|
+
if (mode2 === "paste") pasteWrapRef.current?.querySelector("textarea")?.focus();
|
|
3563
|
+
}, [mode2]);
|
|
3564
|
+
const doResolve = () => {
|
|
3565
|
+
if (!field.resolve) return;
|
|
3566
|
+
const tokens = Array.from(new Set(pasteText.split(/[\n,]/).map((t) => t.trim()).filter(Boolean)));
|
|
3567
|
+
if (!tokens.length) return;
|
|
3568
|
+
setPasteLoading(true);
|
|
3569
|
+
setPasteError(null);
|
|
3570
|
+
field.resolve(tokens).then((result) => {
|
|
3571
|
+
setPasteLoading(false);
|
|
3572
|
+
setUnmatchedTokens(result.unmatched);
|
|
3573
|
+
const merged = new Map(selectedRef.current.map((s) => [s.value, s]));
|
|
3574
|
+
for (const m of result.matched) merged.set(m.value, { value: m.value, label: m.label });
|
|
3575
|
+
commit(Array.from(merged.values()));
|
|
3576
|
+
setPasteText("");
|
|
3577
|
+
}).catch((err) => {
|
|
3578
|
+
setPasteLoading(false);
|
|
3579
|
+
setPasteError(err instanceof Error ? err.message : "Could not resolve the pasted list.");
|
|
3580
|
+
});
|
|
3482
3581
|
};
|
|
3483
|
-
const
|
|
3484
|
-
|
|
3485
|
-
/* @__PURE__ */ (0, import_jsx_runtime45.jsx)(
|
|
3582
|
+
const header = /* @__PURE__ */ (0, import_jsx_runtime45.jsxs)("span", { className: "fd-stack fd-gap-sm", children: [
|
|
3583
|
+
allowedOps.length > 1 ? /* @__PURE__ */ (0, import_jsx_runtime45.jsx)(OperatorToggle, { operator, onChange: setOperator, label: field.label }) : null,
|
|
3584
|
+
field.resolve ? /* @__PURE__ */ (0, import_jsx_runtime45.jsx)(
|
|
3585
|
+
SegmentedControl,
|
|
3586
|
+
{
|
|
3587
|
+
"aria-label": field.label + " \u2014 search or paste a list",
|
|
3588
|
+
options: [{ value: "search", label: "Search" }, { value: "paste", label: "Paste a list" }],
|
|
3589
|
+
value: mode2,
|
|
3590
|
+
onChange: (m) => setMode(m)
|
|
3591
|
+
}
|
|
3592
|
+
) : null,
|
|
3593
|
+
mode2 === "search" ? /* @__PURE__ */ (0, import_jsx_runtime45.jsxs)("span", { className: "fd-pop-search", children: [
|
|
3594
|
+
/* @__PURE__ */ (0, import_jsx_runtime45.jsx)("i", { className: "ph ph-magnifying-glass", "aria-hidden": "true" }),
|
|
3595
|
+
/* @__PURE__ */ (0, import_jsx_runtime45.jsx)(
|
|
3596
|
+
"input",
|
|
3597
|
+
{
|
|
3598
|
+
ref: inputRef,
|
|
3599
|
+
role: "combobox",
|
|
3600
|
+
"aria-expanded": hasListbox,
|
|
3601
|
+
"aria-controls": hasListbox ? listId : void 0,
|
|
3602
|
+
"aria-autocomplete": "list",
|
|
3603
|
+
"aria-activedescendant": activeId,
|
|
3604
|
+
"aria-label": field.label,
|
|
3605
|
+
value: query,
|
|
3606
|
+
placeholder: field.placeholder || "Search\u2026",
|
|
3607
|
+
onChange: (e) => setQuery(e.target.value),
|
|
3608
|
+
onKeyDown: (e) => {
|
|
3609
|
+
if (e.key === "ArrowDown") {
|
|
3610
|
+
e.preventDefault();
|
|
3611
|
+
nav.move(1);
|
|
3612
|
+
} else if (e.key === "ArrowUp") {
|
|
3613
|
+
e.preventDefault();
|
|
3614
|
+
nav.move(-1);
|
|
3615
|
+
} else if (e.key === "Home") {
|
|
3616
|
+
e.preventDefault();
|
|
3617
|
+
nav.first();
|
|
3618
|
+
} else if (e.key === "End") {
|
|
3619
|
+
e.preventDefault();
|
|
3620
|
+
nav.last();
|
|
3621
|
+
} else if (e.key === "Enter") {
|
|
3622
|
+
e.preventDefault();
|
|
3623
|
+
nav.activate();
|
|
3624
|
+
}
|
|
3625
|
+
}
|
|
3626
|
+
}
|
|
3627
|
+
)
|
|
3628
|
+
] }) : null
|
|
3629
|
+
] });
|
|
3630
|
+
const body = mode2 === "paste" ? /* @__PURE__ */ (0, import_jsx_runtime45.jsxs)("span", { className: "fd-stack fd-gap-sm", ref: pasteWrapRef, children: [
|
|
3486
3631
|
/* @__PURE__ */ (0, import_jsx_runtime45.jsx)(
|
|
3487
|
-
|
|
3632
|
+
Textarea,
|
|
3488
3633
|
{
|
|
3489
|
-
|
|
3490
|
-
|
|
3491
|
-
|
|
3492
|
-
|
|
3493
|
-
|
|
3494
|
-
|
|
3495
|
-
"aria-label": field.label,
|
|
3496
|
-
className: "fd-input",
|
|
3497
|
-
style: { width: "100%", padding: "6px 10px" },
|
|
3498
|
-
value: query,
|
|
3499
|
-
placeholder: field.placeholder || "Search\u2026",
|
|
3500
|
-
onChange: (e) => setQuery(e.target.value),
|
|
3634
|
+
"aria-label": field.label + " \u2014 paste a list",
|
|
3635
|
+
rows: 4,
|
|
3636
|
+
placeholder: field.pastePlaceholder || field.placeholder || "Paste names, one per line or comma-separated",
|
|
3637
|
+
value: pasteText,
|
|
3638
|
+
disabled: pasteLoading,
|
|
3639
|
+
onChange: (e) => setPasteText(e.target.value),
|
|
3501
3640
|
onKeyDown: (e) => {
|
|
3502
|
-
if (e.key === "
|
|
3503
|
-
e.preventDefault();
|
|
3504
|
-
setActive((a) => Math.min(a + 1, options.length - 1));
|
|
3505
|
-
} else if (e.key === "ArrowUp") {
|
|
3506
|
-
e.preventDefault();
|
|
3507
|
-
setActive((a) => Math.max(a - 1, 0));
|
|
3508
|
-
} else if (e.key === "Enter") {
|
|
3641
|
+
if (e.key === "Enter" && (e.metaKey || e.ctrlKey)) {
|
|
3509
3642
|
e.preventDefault();
|
|
3510
|
-
|
|
3511
|
-
} else if (e.key === "Escape") {
|
|
3512
|
-
e.stopPropagation();
|
|
3513
|
-
onClose();
|
|
3643
|
+
doResolve();
|
|
3514
3644
|
}
|
|
3515
3645
|
}
|
|
3516
3646
|
}
|
|
3517
3647
|
),
|
|
3518
|
-
|
|
3519
|
-
|
|
3520
|
-
|
|
3521
|
-
|
|
3648
|
+
pasteError ? /* @__PURE__ */ (0, import_jsx_runtime45.jsx)(Banner, { tone: "danger", title: "Couldn't resolve the list", detail: pasteError }) : null,
|
|
3649
|
+
unmatchedTokens.length > 0 ? /* @__PURE__ */ (0, import_jsx_runtime45.jsx)(Banner, { tone: "warn", title: unmatchedTokens.length + " didn't match", detail: unmatchedTokens.join(", ") }) : null,
|
|
3650
|
+
selected.length > 0 ? /* @__PURE__ */ (0, import_jsx_runtime45.jsxs)("span", { className: "fd-stack fd-gap-xs", children: [
|
|
3651
|
+
/* @__PURE__ */ (0, import_jsx_runtime45.jsxs)("span", { className: "fd-body-sm fd-muted", children: [
|
|
3652
|
+
selected.length,
|
|
3653
|
+
" matched"
|
|
3654
|
+
] }),
|
|
3655
|
+
/* @__PURE__ */ (0, import_jsx_runtime45.jsx)("span", { className: "fd-row fd-wrap fd-gap-xs", children: selected.map((v) => /* @__PURE__ */ (0, import_jsx_runtime45.jsx)(Tag, { onRemove: () => commit(selected.filter((s) => s.value !== v.value)), children: v.label }, v.value)) })
|
|
3656
|
+
] }) : null
|
|
3657
|
+
] }) : /* @__PURE__ */ (0, import_jsx_runtime45.jsxs)("span", { className: "fd-stack fd-gap-sm", children: [
|
|
3658
|
+
/* @__PURE__ */ (0, import_jsx_runtime45.jsxs)(
|
|
3522
3659
|
"span",
|
|
3523
3660
|
{
|
|
3524
|
-
|
|
3525
|
-
role:
|
|
3526
|
-
|
|
3527
|
-
|
|
3528
|
-
|
|
3529
|
-
|
|
3530
|
-
children: options.map((o, i) => {
|
|
3531
|
-
const on = isSelected(o);
|
|
3532
|
-
return /* @__PURE__ */ (0, import_jsx_runtime45.jsxs)(
|
|
3533
|
-
"button",
|
|
3534
|
-
{
|
|
3535
|
-
type: "button",
|
|
3536
|
-
id: listId + "-opt-" + i,
|
|
3537
|
-
role: "option",
|
|
3538
|
-
"aria-selected": on,
|
|
3539
|
-
className: "fd-row",
|
|
3540
|
-
onMouseEnter: () => setActive(i),
|
|
3541
|
-
onClick: () => toggle(o),
|
|
3542
|
-
style: {
|
|
3543
|
-
gap: "var(--s-8)",
|
|
3544
|
-
padding: "4px 8px",
|
|
3545
|
-
borderRadius: 7,
|
|
3546
|
-
border: 0,
|
|
3547
|
-
width: "100%",
|
|
3548
|
-
textAlign: "left",
|
|
3549
|
-
cursor: "pointer",
|
|
3550
|
-
background: i === active ? "var(--surface-brand)" : "transparent"
|
|
3551
|
-
},
|
|
3552
|
-
children: [
|
|
3553
|
-
/* @__PURE__ */ (0, import_jsx_runtime45.jsx)("i", { className: on ? "ph ph-check-square" : "ph ph-square", "aria-hidden": "true" }),
|
|
3554
|
-
/* @__PURE__ */ (0, import_jsx_runtime45.jsx)("span", { className: "fd-body-sm", style: { flex: 1, color: "var(--text)" }, children: o.label })
|
|
3555
|
-
]
|
|
3556
|
-
},
|
|
3557
|
-
o.value
|
|
3558
|
-
);
|
|
3559
|
-
})
|
|
3661
|
+
className: "fd-row fd-gap-xs" + (liveMessage && !showError ? " fd-muted" : ""),
|
|
3662
|
+
role: liveRole,
|
|
3663
|
+
children: [
|
|
3664
|
+
showLoading ? /* @__PURE__ */ (0, import_jsx_runtime45.jsx)("span", { className: "fd-spinner", "aria-hidden": "true" }) : null,
|
|
3665
|
+
liveMessage ? /* @__PURE__ */ (0, import_jsx_runtime45.jsx)("span", { className: "fd-body-sm", children: liveMessage }) : null
|
|
3666
|
+
]
|
|
3560
3667
|
}
|
|
3561
3668
|
),
|
|
3562
|
-
|
|
3563
|
-
|
|
3564
|
-
|
|
3565
|
-
|
|
3669
|
+
showError ? /* @__PURE__ */ (0, import_jsx_runtime45.jsx)(Button, { size: "sm", variant: "secondary", onClick: () => setRetryTick((n) => n + 1), children: "Retry" }) : null,
|
|
3670
|
+
hasListbox ? /* @__PURE__ */ (0, import_jsx_runtime45.jsx)("span", { id: listId, role: "listbox", "aria-label": field.label, "aria-multiselectable": "true", ref: listRef, className: "fd-pop-list", children: options.map((o, i) => {
|
|
3671
|
+
const on = isSelected(o);
|
|
3672
|
+
return /* @__PURE__ */ (0, import_jsx_runtime45.jsxs)(
|
|
3673
|
+
"div",
|
|
3674
|
+
{
|
|
3675
|
+
id: listId + "-opt-" + i,
|
|
3676
|
+
"data-i": i,
|
|
3677
|
+
role: "option",
|
|
3678
|
+
tabIndex: -1,
|
|
3679
|
+
"aria-selected": on,
|
|
3680
|
+
className: ["fd-opt", i === nav.active ? "is-active" : "", on ? "is-selected" : ""].filter(Boolean).join(" "),
|
|
3681
|
+
onMouseEnter: () => nav.setActive(i),
|
|
3682
|
+
onClick: () => toggle(o),
|
|
3683
|
+
children: [
|
|
3684
|
+
/* @__PURE__ */ (0, import_jsx_runtime45.jsx)("i", { className: "fd-filterbar-opt-check ph " + (on ? "ph-check-square is-checked" : "ph-square"), "aria-hidden": "true" }),
|
|
3685
|
+
/* @__PURE__ */ (0, import_jsx_runtime45.jsx)("span", { className: "fd-opt-label", children: o.label })
|
|
3686
|
+
]
|
|
3687
|
+
},
|
|
3688
|
+
o.value
|
|
3689
|
+
);
|
|
3690
|
+
}) }) : null
|
|
3566
3691
|
] });
|
|
3692
|
+
const footer = mode2 === "paste" ? /* @__PURE__ */ (0, import_jsx_runtime45.jsx)(Button, { size: "sm", variant: "secondary", onClick: doResolve, disabled: pasteLoading || !pasteText.trim(), children: pasteLoading ? "Resolving\u2026" : "Resolve" }) : void 0;
|
|
3693
|
+
return /* @__PURE__ */ (0, import_jsx_runtime45.jsx)(
|
|
3694
|
+
Popover,
|
|
3695
|
+
{
|
|
3696
|
+
open: true,
|
|
3697
|
+
anchorRef,
|
|
3698
|
+
onClose,
|
|
3699
|
+
placement: "bottom-start",
|
|
3700
|
+
offset: 6,
|
|
3701
|
+
width: PANEL_WIDTH.multiSelect,
|
|
3702
|
+
label: field.label,
|
|
3703
|
+
header,
|
|
3704
|
+
footer,
|
|
3705
|
+
children: body
|
|
3706
|
+
}
|
|
3707
|
+
);
|
|
3567
3708
|
}
|
|
3568
3709
|
function RangePanel({
|
|
3569
3710
|
field,
|
|
3570
3711
|
value,
|
|
3712
|
+
anchorRef,
|
|
3571
3713
|
onChange,
|
|
3714
|
+
onRemove,
|
|
3572
3715
|
onClose
|
|
3573
3716
|
}) {
|
|
3574
|
-
const
|
|
3575
|
-
const
|
|
3576
|
-
const
|
|
3577
|
-
|
|
3578
|
-
|
|
3579
|
-
|
|
3580
|
-
|
|
3581
|
-
|
|
3582
|
-
|
|
3583
|
-
|
|
3584
|
-
|
|
3585
|
-
|
|
3586
|
-
|
|
3587
|
-
|
|
3588
|
-
|
|
3589
|
-
|
|
3590
|
-
|
|
3591
|
-
|
|
3592
|
-
|
|
3593
|
-
|
|
3594
|
-
|
|
3595
|
-
|
|
3596
|
-
|
|
3597
|
-
|
|
3598
|
-
|
|
3599
|
-
|
|
3600
|
-
|
|
3601
|
-
|
|
3602
|
-
|
|
3603
|
-
|
|
3604
|
-
|
|
3717
|
+
const [draftMin, setDraftMin] = React24.useState(value?.min);
|
|
3718
|
+
const [draftMax, setDraftMax] = React24.useState(value?.max);
|
|
3719
|
+
const invalid = draftMin != null && draftMax != null && draftMin > draftMax;
|
|
3720
|
+
const apply = (nextMin, nextMax) => {
|
|
3721
|
+
setDraftMin(nextMin);
|
|
3722
|
+
setDraftMax(nextMax);
|
|
3723
|
+
if (nextMin == null && nextMax == null) {
|
|
3724
|
+
onRemove();
|
|
3725
|
+
return;
|
|
3726
|
+
}
|
|
3727
|
+
if (nextMin != null && nextMax != null && nextMin > nextMax) return;
|
|
3728
|
+
onChange({ min: nextMin, max: nextMax });
|
|
3729
|
+
};
|
|
3730
|
+
return /* @__PURE__ */ (0, import_jsx_runtime45.jsx)(
|
|
3731
|
+
Popover,
|
|
3732
|
+
{
|
|
3733
|
+
open: true,
|
|
3734
|
+
anchorRef,
|
|
3735
|
+
onClose,
|
|
3736
|
+
placement: "bottom-start",
|
|
3737
|
+
offset: 6,
|
|
3738
|
+
width: PANEL_WIDTH.range,
|
|
3739
|
+
label: field.label,
|
|
3740
|
+
footer: /* @__PURE__ */ (0, import_jsx_runtime45.jsx)(Button, { size: "sm", variant: "secondary", onClick: onClose, disabled: invalid, children: "Done" }),
|
|
3741
|
+
children: /* @__PURE__ */ (0, import_jsx_runtime45.jsxs)("span", { className: "fd-stack fd-gap-sm", children: [
|
|
3742
|
+
/* @__PURE__ */ (0, import_jsx_runtime45.jsx)(
|
|
3743
|
+
NumberInput,
|
|
3744
|
+
{
|
|
3745
|
+
label: field.minLabel || "At least",
|
|
3746
|
+
value: draftMin ?? "",
|
|
3747
|
+
min: field.min,
|
|
3748
|
+
max: field.max,
|
|
3749
|
+
step: field.step,
|
|
3750
|
+
placeholder: field.minPlaceholder,
|
|
3751
|
+
onChange: (e) => apply(e.target.value, draftMax)
|
|
3752
|
+
}
|
|
3753
|
+
),
|
|
3754
|
+
/* @__PURE__ */ (0, import_jsx_runtime45.jsx)(
|
|
3755
|
+
NumberInput,
|
|
3756
|
+
{
|
|
3757
|
+
label: field.maxLabel || "At most",
|
|
3758
|
+
value: draftMax ?? "",
|
|
3759
|
+
min: field.min,
|
|
3760
|
+
max: field.max,
|
|
3761
|
+
step: field.step,
|
|
3762
|
+
error: invalid ? "Must be \u2265 " + draftMin : void 0,
|
|
3763
|
+
placeholder: field.maxPlaceholder,
|
|
3764
|
+
onChange: (e) => apply(draftMin, e.target.value)
|
|
3765
|
+
}
|
|
3766
|
+
)
|
|
3767
|
+
] })
|
|
3768
|
+
}
|
|
3769
|
+
);
|
|
3605
3770
|
}
|
|
3606
3771
|
function DatePanel({
|
|
3607
3772
|
field,
|
|
3608
3773
|
value,
|
|
3774
|
+
anchorRef,
|
|
3609
3775
|
onChange,
|
|
3776
|
+
onRemove,
|
|
3610
3777
|
onClose
|
|
3611
3778
|
}) {
|
|
3612
|
-
const
|
|
3613
|
-
|
|
3614
|
-
|
|
3615
|
-
|
|
3616
|
-
|
|
3617
|
-
|
|
3618
|
-
|
|
3619
|
-
|
|
3620
|
-
|
|
3621
|
-
|
|
3622
|
-
|
|
3623
|
-
|
|
3624
|
-
|
|
3625
|
-
|
|
3626
|
-
|
|
3627
|
-
|
|
3628
|
-
|
|
3629
|
-
|
|
3630
|
-
|
|
3631
|
-
|
|
3632
|
-
|
|
3633
|
-
|
|
3634
|
-
|
|
3635
|
-
|
|
3636
|
-
|
|
3637
|
-
|
|
3638
|
-
|
|
3639
|
-
|
|
3640
|
-
|
|
3641
|
-
|
|
3642
|
-
|
|
3643
|
-
|
|
3644
|
-
|
|
3645
|
-
|
|
3646
|
-
|
|
3779
|
+
const defaultDays = field.defaultDays ?? 30;
|
|
3780
|
+
const maxDays = field.maxDays ?? 3650;
|
|
3781
|
+
const [kind, setKind] = React24.useState(value?.kind ?? "withinDays");
|
|
3782
|
+
const [daysDraft, setDaysDraft] = React24.useState(
|
|
3783
|
+
value?.kind === "withinDays" ? value.days : defaultDays
|
|
3784
|
+
);
|
|
3785
|
+
const [between, setBetween] = React24.useState(
|
|
3786
|
+
value?.kind === "between" ? { from: value.from, to: value.to } : { from: "", to: "" }
|
|
3787
|
+
);
|
|
3788
|
+
const committedRef = React24.useRef(!!value);
|
|
3789
|
+
const applyWithinDays = (days) => {
|
|
3790
|
+
setDaysDraft(days);
|
|
3791
|
+
if (days != null) {
|
|
3792
|
+
committedRef.current = true;
|
|
3793
|
+
onChange({ kind: "withinDays", days });
|
|
3794
|
+
} else if (committedRef.current) {
|
|
3795
|
+
committedRef.current = false;
|
|
3796
|
+
onRemove();
|
|
3797
|
+
}
|
|
3798
|
+
};
|
|
3799
|
+
const applyBetween = (from, to) => {
|
|
3800
|
+
setBetween({ from, to });
|
|
3801
|
+
if (from && to) {
|
|
3802
|
+
committedRef.current = true;
|
|
3803
|
+
onChange({ kind: "between", from, to });
|
|
3804
|
+
} else if (committedRef.current) {
|
|
3805
|
+
committedRef.current = false;
|
|
3806
|
+
onRemove();
|
|
3807
|
+
}
|
|
3808
|
+
};
|
|
3809
|
+
const switchKind = (next) => {
|
|
3810
|
+
setKind(next);
|
|
3811
|
+
if (next === "between") {
|
|
3812
|
+
setBetween({ from: "", to: "" });
|
|
3813
|
+
if (committedRef.current) {
|
|
3814
|
+
committedRef.current = false;
|
|
3815
|
+
onRemove();
|
|
3647
3816
|
}
|
|
3648
|
-
|
|
3649
|
-
/* @__PURE__ */ (0, import_jsx_runtime45.jsx)(Button, { size: "sm", variant: "secondary", onClick: onClose, children: "Done" })
|
|
3650
|
-
] });
|
|
3651
|
-
}
|
|
3652
|
-
function PasteListPanel({
|
|
3653
|
-
field,
|
|
3654
|
-
value,
|
|
3655
|
-
onChange,
|
|
3656
|
-
onClose
|
|
3657
|
-
}) {
|
|
3658
|
-
const operator = value?.operator ?? "in";
|
|
3659
|
-
const selected = value?.values ?? [];
|
|
3660
|
-
const [text, setText] = React23.useState("");
|
|
3661
|
-
const [loading, setLoading] = React23.useState(false);
|
|
3662
|
-
const [unmatched, setUnmatched] = React23.useState([]);
|
|
3663
|
-
const [error, setError] = React23.useState(null);
|
|
3664
|
-
const wrapRef = React23.useRef(null);
|
|
3665
|
-
React23.useEffect(() => {
|
|
3666
|
-
wrapRef.current?.querySelector("textarea")?.focus();
|
|
3667
|
-
}, []);
|
|
3668
|
-
const doResolve = () => {
|
|
3669
|
-
const tokens = text.split(/[\n,]/).map((t) => t.trim()).filter(Boolean);
|
|
3670
|
-
if (!tokens.length) return;
|
|
3671
|
-
setLoading(true);
|
|
3672
|
-
setError(null);
|
|
3673
|
-
field.resolve(tokens).then((result) => {
|
|
3674
|
-
setLoading(false);
|
|
3675
|
-
setUnmatched(result.unmatched);
|
|
3676
|
-
const merged = new Map(selected.map((s) => [s.value, s]));
|
|
3677
|
-
for (const m of result.matched) merged.set(m.value, { value: m.value, label: m.label });
|
|
3678
|
-
onChange({ operator, values: Array.from(merged.values()) });
|
|
3679
|
-
setText("");
|
|
3680
|
-
}).catch((err) => {
|
|
3681
|
-
setLoading(false);
|
|
3682
|
-
setError(err instanceof Error ? err.message : "Could not resolve the pasted list.");
|
|
3683
|
-
});
|
|
3817
|
+
}
|
|
3684
3818
|
};
|
|
3685
|
-
|
|
3686
|
-
|
|
3687
|
-
|
|
3688
|
-
|
|
3689
|
-
|
|
3690
|
-
|
|
3691
|
-
|
|
3692
|
-
|
|
3693
|
-
|
|
3694
|
-
|
|
3695
|
-
|
|
3696
|
-
|
|
3697
|
-
|
|
3698
|
-
|
|
3699
|
-
|
|
3819
|
+
const confirm = () => {
|
|
3820
|
+
if (kind === "withinDays" && daysDraft != null) {
|
|
3821
|
+
committedRef.current = true;
|
|
3822
|
+
onChange({ kind: "withinDays", days: daysDraft });
|
|
3823
|
+
}
|
|
3824
|
+
onClose();
|
|
3825
|
+
};
|
|
3826
|
+
return /* @__PURE__ */ (0, import_jsx_runtime45.jsx)(
|
|
3827
|
+
Popover,
|
|
3828
|
+
{
|
|
3829
|
+
open: true,
|
|
3830
|
+
anchorRef,
|
|
3831
|
+
onClose,
|
|
3832
|
+
placement: "bottom-start",
|
|
3833
|
+
offset: 6,
|
|
3834
|
+
width: PANEL_WIDTH.date,
|
|
3835
|
+
label: field.label,
|
|
3836
|
+
footer: /* @__PURE__ */ (0, import_jsx_runtime45.jsx)(Button, { size: "sm", variant: "secondary", onClick: confirm, children: "Done" }),
|
|
3837
|
+
children: /* @__PURE__ */ (0, import_jsx_runtime45.jsxs)("span", { className: "fd-stack fd-gap-sm", children: [
|
|
3838
|
+
/* @__PURE__ */ (0, import_jsx_runtime45.jsx)(
|
|
3839
|
+
SegmentedControl,
|
|
3840
|
+
{
|
|
3841
|
+
"aria-label": field.label + " \u2014 relative or between dates",
|
|
3842
|
+
options: [
|
|
3843
|
+
{ value: "withinDays", label: "Within last N days" },
|
|
3844
|
+
{ value: "between", label: "Between dates" }
|
|
3845
|
+
],
|
|
3846
|
+
value: kind,
|
|
3847
|
+
onChange: (k) => switchKind(k)
|
|
3700
3848
|
}
|
|
3701
|
-
|
|
3702
|
-
|
|
3703
|
-
|
|
3704
|
-
|
|
3705
|
-
|
|
3706
|
-
|
|
3707
|
-
|
|
3708
|
-
|
|
3709
|
-
|
|
3710
|
-
|
|
3711
|
-
] })
|
|
3712
|
-
|
|
3713
|
-
|
|
3714
|
-
/* @__PURE__ */ (0, import_jsx_runtime45.jsx)(Button, { size: "sm", variant: "secondary", onClick: onClose, children: "Done" })
|
|
3715
|
-
] });
|
|
3849
|
+
),
|
|
3850
|
+
kind === "withinDays" ? /* @__PURE__ */ (0, import_jsx_runtime45.jsx)(NumberInput, { label: "Days", min: 1, max: maxDays, step: 1, value: daysDraft ?? "", onChange: (e) => applyWithinDays(e.target.value) }) : /* @__PURE__ */ (0, import_jsx_runtime45.jsx)(
|
|
3851
|
+
DatePicker,
|
|
3852
|
+
{
|
|
3853
|
+
range: true,
|
|
3854
|
+
label: "Date range",
|
|
3855
|
+
value: { start: between.from, end: between.to },
|
|
3856
|
+
onChange: (e) => applyBetween(e.target.value.start || "", e.target.value.end || "")
|
|
3857
|
+
}
|
|
3858
|
+
)
|
|
3859
|
+
] })
|
|
3860
|
+
}
|
|
3861
|
+
);
|
|
3716
3862
|
}
|
|
3717
3863
|
function FilterBar({ fields = [], filters, onFilterChange, onFilterRemove, align = "left", className = "", ...rest }) {
|
|
3718
|
-
const [panel, setPanel] =
|
|
3719
|
-
const
|
|
3720
|
-
const
|
|
3721
|
-
const textInputRef =
|
|
3722
|
-
const optionsRef =
|
|
3864
|
+
const [panel, setPanel] = React24.useState(null);
|
|
3865
|
+
const editAnchorRef = React24.useRef(null);
|
|
3866
|
+
const addAnchorRef = React24.useRef(null);
|
|
3867
|
+
const textInputRef = React24.useRef(null);
|
|
3868
|
+
const optionsRef = React24.useRef(null);
|
|
3723
3869
|
const editingField = panel && panel.kind === "edit" ? fields.find((f) => f.key === panel.key) : void 0;
|
|
3724
|
-
const
|
|
3725
|
-
|
|
3726
|
-
|
|
3727
|
-
const away = (e) => {
|
|
3728
|
-
const target = e.target;
|
|
3729
|
-
if (target.closest && target.closest(".fd-pop")) return;
|
|
3730
|
-
if (rootRef.current && !rootRef.current.contains(e.target)) setPanel(null);
|
|
3731
|
-
};
|
|
3732
|
-
const esc = (e) => {
|
|
3733
|
-
if (e.key === "Escape") setPanel(null);
|
|
3734
|
-
};
|
|
3735
|
-
document.addEventListener("pointerdown", away);
|
|
3736
|
-
document.addEventListener("keydown", esc);
|
|
3737
|
-
return () => {
|
|
3738
|
-
document.removeEventListener("pointerdown", away);
|
|
3739
|
-
document.removeEventListener("keydown", esc);
|
|
3740
|
-
};
|
|
3741
|
-
}, [dismissible]);
|
|
3742
|
-
React23.useEffect(() => {
|
|
3870
|
+
const startEditing = (key) => setPanel({ kind: "edit", key });
|
|
3871
|
+
const closeEditing = () => setPanel(null);
|
|
3872
|
+
React24.useEffect(() => {
|
|
3743
3873
|
if (!panel || panel.kind !== "edit") return;
|
|
3744
3874
|
if (editingField?.type === "text") {
|
|
3745
3875
|
textInputRef.current?.focus();
|
|
@@ -3749,72 +3879,77 @@ function FilterBar({ fields = [], filters, onFilterChange, onFilterRemove, align
|
|
|
3749
3879
|
}
|
|
3750
3880
|
}, [panel]);
|
|
3751
3881
|
const addableFields = fields.filter((f) => !isFieldSet(f, filters[f.key]));
|
|
3752
|
-
const
|
|
3753
|
-
|
|
3882
|
+
const addMenuItems = [
|
|
3883
|
+
{ kind: "section", label: "Add filter" },
|
|
3884
|
+
...addableFields.map((f) => ({ id: f.key, label: f.label, onSelect: () => startEditing(f.key) }))
|
|
3885
|
+
];
|
|
3886
|
+
return /* @__PURE__ */ (0, import_jsx_runtime45.jsxs)("span", { className: ["fd-filterbar", className].filter(Boolean).join(" "), ...rest, children: [
|
|
3754
3887
|
fields.map((field) => {
|
|
3755
3888
|
const value = filters[field.key];
|
|
3756
3889
|
const editing = panel?.kind === "edit" && panel.key === field.key;
|
|
3757
3890
|
if (editing && field.type === "text") {
|
|
3758
|
-
return /* @__PURE__ */ (0, import_jsx_runtime45.jsxs)(
|
|
3759
|
-
|
|
3760
|
-
|
|
3761
|
-
|
|
3762
|
-
|
|
3763
|
-
|
|
3764
|
-
|
|
3765
|
-
|
|
3766
|
-
|
|
3767
|
-
|
|
3768
|
-
|
|
3769
|
-
|
|
3770
|
-
|
|
3771
|
-
|
|
3772
|
-
|
|
3773
|
-
if (e.key === "Enter") setPanel(null);
|
|
3774
|
-
else if (e.key === "Escape") {
|
|
3775
|
-
e.stopPropagation();
|
|
3776
|
-
setPanel(null);
|
|
3777
|
-
}
|
|
3778
|
-
},
|
|
3779
|
-
onBlur: () => setPanel(null),
|
|
3780
|
-
style: { all: "unset", minWidth: 90, color: "var(--text-on-surface-brand)" }
|
|
3781
|
-
}
|
|
3782
|
-
),
|
|
3783
|
-
isSet(value) ? /* @__PURE__ */ (0, import_jsx_runtime45.jsx)(
|
|
3784
|
-
"span",
|
|
3785
|
-
{
|
|
3786
|
-
className: "fd-tag-remove",
|
|
3787
|
-
role: "button",
|
|
3788
|
-
"aria-label": "Remove " + field.label,
|
|
3789
|
-
onClick: (e) => {
|
|
3790
|
-
e.stopPropagation();
|
|
3791
|
-
onFilterRemove(field.key);
|
|
3792
|
-
setPanel(null);
|
|
3793
|
-
},
|
|
3794
|
-
children: /* @__PURE__ */ (0, import_jsx_runtime45.jsx)("i", { className: "ph ph-x", "aria-hidden": "true" })
|
|
3891
|
+
return /* @__PURE__ */ (0, import_jsx_runtime45.jsxs)("span", { className: ["fd-tag", "fd-filterbar-text"].join(" "), children: [
|
|
3892
|
+
/* @__PURE__ */ (0, import_jsx_runtime45.jsx)(
|
|
3893
|
+
"input",
|
|
3894
|
+
{
|
|
3895
|
+
ref: textInputRef,
|
|
3896
|
+
className: "fd-filterbar-text-input",
|
|
3897
|
+
value: value ?? "",
|
|
3898
|
+
placeholder: field.placeholder || field.label,
|
|
3899
|
+
"aria-label": field.label,
|
|
3900
|
+
onChange: (e) => onFilterChange(field.key, e.target.value),
|
|
3901
|
+
onKeyDown: (e) => {
|
|
3902
|
+
if (e.key === "Enter") setPanel(null);
|
|
3903
|
+
else if (e.key === "Escape") {
|
|
3904
|
+
e.stopPropagation();
|
|
3905
|
+
setPanel(null);
|
|
3795
3906
|
}
|
|
3796
|
-
|
|
3797
|
-
|
|
3798
|
-
|
|
3799
|
-
|
|
3800
|
-
|
|
3801
|
-
}
|
|
3802
|
-
if (editing && field.type === "select") {
|
|
3803
|
-
const chosen = field.options.find((o) => o.value === value);
|
|
3804
|
-
return /* @__PURE__ */ (0, import_jsx_runtime45.jsxs)("span", { style: { position: "relative", display: "inline-flex" }, children: [
|
|
3805
|
-
/* @__PURE__ */ (0, import_jsx_runtime45.jsxs)(Tag, { selected: true, onClick: () => setPanel(null), onRemove: () => {
|
|
3806
|
-
if (isSet(value)) onFilterRemove(field.key);
|
|
3807
|
-
setPanel(null);
|
|
3808
|
-
}, children: [
|
|
3809
|
-
field.label,
|
|
3810
|
-
chosen ? ": " + chosen.label : ""
|
|
3811
|
-
] }),
|
|
3812
|
-
/* @__PURE__ */ (0, import_jsx_runtime45.jsx)(LayerProvider, { zIndex, children: /* @__PURE__ */ (0, import_jsx_runtime45.jsx)(
|
|
3907
|
+
},
|
|
3908
|
+
onBlur: () => setPanel(null)
|
|
3909
|
+
}
|
|
3910
|
+
),
|
|
3911
|
+
isSet(value) ? /* @__PURE__ */ (0, import_jsx_runtime45.jsx)(
|
|
3813
3912
|
"span",
|
|
3814
3913
|
{
|
|
3815
|
-
className: "fd-
|
|
3816
|
-
|
|
3817
|
-
|
|
3914
|
+
className: "fd-tag-remove",
|
|
3915
|
+
role: "button",
|
|
3916
|
+
"aria-label": "Remove " + field.label,
|
|
3917
|
+
onClick: (e) => {
|
|
3918
|
+
e.stopPropagation();
|
|
3919
|
+
onFilterRemove(field.key);
|
|
3920
|
+
setPanel(null);
|
|
3921
|
+
},
|
|
3922
|
+
children: /* @__PURE__ */ (0, import_jsx_runtime45.jsx)("i", { className: "ph ph-x", "aria-hidden": "true" })
|
|
3923
|
+
}
|
|
3924
|
+
) : null
|
|
3925
|
+
] }, field.key);
|
|
3926
|
+
}
|
|
3927
|
+
const set = isFieldSet(field, value);
|
|
3928
|
+
if (!editing && !set) return null;
|
|
3929
|
+
const chipRef = editing ? editAnchorRef : void 0;
|
|
3930
|
+
const toggleOrClose = () => editing ? closeEditing() : startEditing(field.key);
|
|
3931
|
+
const remove = () => {
|
|
3932
|
+
if (set) onFilterRemove(field.key);
|
|
3933
|
+
closeEditing();
|
|
3934
|
+
};
|
|
3935
|
+
const chipText = field.label + (set ? ": " + chipLabel(field, value) : "");
|
|
3936
|
+
if (field.type === "text") {
|
|
3937
|
+
return /* @__PURE__ */ (0, import_jsx_runtime45.jsx)(Tag, { selected: true, onClick: toggleOrClose, onRemove: remove, children: chipText }, field.key);
|
|
3938
|
+
}
|
|
3939
|
+
if (field.type === "select") {
|
|
3940
|
+
return /* @__PURE__ */ (0, import_jsx_runtime45.jsxs)("span", { children: [
|
|
3941
|
+
/* @__PURE__ */ (0, import_jsx_runtime45.jsx)("span", { ref: chipRef, children: /* @__PURE__ */ (0, import_jsx_runtime45.jsx)(Tag, { selected: true, onClick: toggleOrClose, onRemove: remove, children: chipText }) }),
|
|
3942
|
+
editing ? /* @__PURE__ */ (0, import_jsx_runtime45.jsx)(
|
|
3943
|
+
Popover,
|
|
3944
|
+
{
|
|
3945
|
+
open: true,
|
|
3946
|
+
anchorRef: editAnchorRef,
|
|
3947
|
+
onClose: closeEditing,
|
|
3948
|
+
placement: align === "right" ? "bottom-end" : "bottom-start",
|
|
3949
|
+
offset: 6,
|
|
3950
|
+
minWidth: 200,
|
|
3951
|
+
label: field.label,
|
|
3952
|
+
children: /* @__PURE__ */ (0, import_jsx_runtime45.jsx)("span", { role: "listbox", "aria-label": field.label, ref: optionsRef, className: "fd-pop-list", children: field.options.map((o) => {
|
|
3818
3953
|
const on = o.value === value;
|
|
3819
3954
|
return /* @__PURE__ */ (0, import_jsx_runtime45.jsx)(
|
|
3820
3955
|
"button",
|
|
@@ -3822,84 +3957,72 @@ function FilterBar({ fields = [], filters, onFilterChange, onFilterRemove, align
|
|
|
3822
3957
|
type: "button",
|
|
3823
3958
|
role: "option",
|
|
3824
3959
|
"aria-selected": on,
|
|
3825
|
-
className: "fd-
|
|
3960
|
+
className: ["fd-opt", on ? "is-selected" : ""].filter(Boolean).join(" "),
|
|
3826
3961
|
onClick: () => {
|
|
3827
3962
|
onFilterChange(field.key, o.value);
|
|
3828
3963
|
setPanel(null);
|
|
3829
3964
|
},
|
|
3830
|
-
|
|
3831
|
-
children: /* @__PURE__ */ (0, import_jsx_runtime45.jsx)("span", { className: "fd-body-sm", style: { flex: 1, fontWeight: on ? 700 : 500, color: on ? "var(--text-on-surface-brand)" : "var(--text)" }, children: o.label })
|
|
3965
|
+
children: /* @__PURE__ */ (0, import_jsx_runtime45.jsx)("span", { className: "fd-opt-label", children: o.label })
|
|
3832
3966
|
},
|
|
3833
3967
|
o.value
|
|
3834
3968
|
);
|
|
3835
3969
|
}) })
|
|
3836
3970
|
}
|
|
3837
|
-
)
|
|
3838
|
-
] }, field.key);
|
|
3839
|
-
}
|
|
3840
|
-
if (editing && field.type === "multiSelect") {
|
|
3841
|
-
const mv = value;
|
|
3842
|
-
return /* @__PURE__ */ (0, import_jsx_runtime45.jsxs)("span", { style: { position: "relative", display: "inline-flex" }, children: [
|
|
3843
|
-
/* @__PURE__ */ (0, import_jsx_runtime45.jsxs)(Tag, { selected: true, onClick: () => setPanel(null), onRemove: () => {
|
|
3844
|
-
if (isFieldSet(field, value)) onFilterRemove(field.key);
|
|
3845
|
-
setPanel(null);
|
|
3846
|
-
}, children: [
|
|
3847
|
-
field.label,
|
|
3848
|
-
isFieldSet(field, value) ? ": " + chipLabel(field, value) : ""
|
|
3849
|
-
] }),
|
|
3850
|
-
/* @__PURE__ */ (0, import_jsx_runtime45.jsx)(EditPopover, { zIndex, width: 260, children: /* @__PURE__ */ (0, import_jsx_runtime45.jsx)(MultiSelectPanel, { field, value: mv, onChange: (v) => onFilterChange(field.key, v), onClose: () => setPanel(null) }) })
|
|
3851
|
-
] }, field.key);
|
|
3852
|
-
}
|
|
3853
|
-
if (editing && field.type === "range") {
|
|
3854
|
-
const rv = value;
|
|
3855
|
-
return /* @__PURE__ */ (0, import_jsx_runtime45.jsxs)("span", { style: { position: "relative", display: "inline-flex" }, children: [
|
|
3856
|
-
/* @__PURE__ */ (0, import_jsx_runtime45.jsxs)(Tag, { selected: true, onClick: () => setPanel(null), onRemove: () => {
|
|
3857
|
-
if (isFieldSet(field, value)) onFilterRemove(field.key);
|
|
3858
|
-
setPanel(null);
|
|
3859
|
-
}, children: [
|
|
3860
|
-
field.label,
|
|
3861
|
-
isFieldSet(field, value) ? ": " + chipLabel(field, value) : ""
|
|
3862
|
-
] }),
|
|
3863
|
-
/* @__PURE__ */ (0, import_jsx_runtime45.jsx)(EditPopover, { zIndex, width: 240, children: /* @__PURE__ */ (0, import_jsx_runtime45.jsx)(RangePanel, { field, value: rv, onChange: (v) => onFilterChange(field.key, v), onClose: () => setPanel(null) }) })
|
|
3971
|
+
) : null
|
|
3864
3972
|
] }, field.key);
|
|
3865
3973
|
}
|
|
3866
|
-
if (
|
|
3867
|
-
|
|
3868
|
-
|
|
3869
|
-
/* @__PURE__ */ (0, import_jsx_runtime45.
|
|
3870
|
-
|
|
3871
|
-
|
|
3872
|
-
|
|
3873
|
-
|
|
3874
|
-
|
|
3875
|
-
|
|
3876
|
-
|
|
3974
|
+
if (field.type === "multiSelect") {
|
|
3975
|
+
return /* @__PURE__ */ (0, import_jsx_runtime45.jsxs)("span", { children: [
|
|
3976
|
+
/* @__PURE__ */ (0, import_jsx_runtime45.jsx)("span", { ref: chipRef, children: /* @__PURE__ */ (0, import_jsx_runtime45.jsx)(Tag, { selected: true, onClick: toggleOrClose, onRemove: remove, children: chipText }) }),
|
|
3977
|
+
editing ? /* @__PURE__ */ (0, import_jsx_runtime45.jsx)(
|
|
3978
|
+
MultiSelectPanel,
|
|
3979
|
+
{
|
|
3980
|
+
field,
|
|
3981
|
+
value,
|
|
3982
|
+
anchorRef: editAnchorRef,
|
|
3983
|
+
onChange: (v) => onFilterChange(field.key, v),
|
|
3984
|
+
onRemove: () => onFilterRemove(field.key),
|
|
3985
|
+
onClose: closeEditing
|
|
3986
|
+
}
|
|
3987
|
+
) : null
|
|
3877
3988
|
] }, field.key);
|
|
3878
3989
|
}
|
|
3879
|
-
if (
|
|
3880
|
-
|
|
3881
|
-
|
|
3882
|
-
/* @__PURE__ */ (0, import_jsx_runtime45.
|
|
3883
|
-
|
|
3884
|
-
|
|
3885
|
-
|
|
3886
|
-
|
|
3887
|
-
|
|
3888
|
-
|
|
3889
|
-
|
|
3990
|
+
if (field.type === "range") {
|
|
3991
|
+
return /* @__PURE__ */ (0, import_jsx_runtime45.jsxs)("span", { children: [
|
|
3992
|
+
/* @__PURE__ */ (0, import_jsx_runtime45.jsx)("span", { ref: chipRef, children: /* @__PURE__ */ (0, import_jsx_runtime45.jsx)(Tag, { selected: true, onClick: toggleOrClose, onRemove: remove, children: chipText }) }),
|
|
3993
|
+
editing ? /* @__PURE__ */ (0, import_jsx_runtime45.jsx)(
|
|
3994
|
+
RangePanel,
|
|
3995
|
+
{
|
|
3996
|
+
field,
|
|
3997
|
+
value,
|
|
3998
|
+
anchorRef: editAnchorRef,
|
|
3999
|
+
onChange: (v) => onFilterChange(field.key, v),
|
|
4000
|
+
onRemove: () => onFilterRemove(field.key),
|
|
4001
|
+
onClose: closeEditing
|
|
4002
|
+
}
|
|
4003
|
+
) : null
|
|
3890
4004
|
] }, field.key);
|
|
3891
4005
|
}
|
|
3892
|
-
if (
|
|
3893
|
-
return /* @__PURE__ */ (0, import_jsx_runtime45.jsxs)(
|
|
3894
|
-
|
|
3895
|
-
|
|
3896
|
-
|
|
4006
|
+
if (field.type === "date") {
|
|
4007
|
+
return /* @__PURE__ */ (0, import_jsx_runtime45.jsxs)("span", { children: [
|
|
4008
|
+
/* @__PURE__ */ (0, import_jsx_runtime45.jsx)("span", { ref: chipRef, children: /* @__PURE__ */ (0, import_jsx_runtime45.jsx)(Tag, { selected: true, onClick: toggleOrClose, onRemove: remove, children: chipText }) }),
|
|
4009
|
+
editing ? /* @__PURE__ */ (0, import_jsx_runtime45.jsx)(
|
|
4010
|
+
DatePanel,
|
|
4011
|
+
{
|
|
4012
|
+
field,
|
|
4013
|
+
value,
|
|
4014
|
+
anchorRef: editAnchorRef,
|
|
4015
|
+
onChange: (v) => onFilterChange(field.key, v),
|
|
4016
|
+
onRemove: () => onFilterRemove(field.key),
|
|
4017
|
+
onClose: closeEditing
|
|
4018
|
+
}
|
|
4019
|
+
) : null
|
|
3897
4020
|
] }, field.key);
|
|
3898
4021
|
}
|
|
3899
4022
|
return null;
|
|
3900
4023
|
}),
|
|
3901
|
-
addableFields.length > 0 ? /* @__PURE__ */ (0, import_jsx_runtime45.jsxs)("span", {
|
|
3902
|
-
/* @__PURE__ */ (0, import_jsx_runtime45.jsx)(
|
|
4024
|
+
addableFields.length > 0 ? /* @__PURE__ */ (0, import_jsx_runtime45.jsxs)("span", { children: [
|
|
4025
|
+
/* @__PURE__ */ (0, import_jsx_runtime45.jsx)("span", { ref: addAnchorRef, children: /* @__PURE__ */ (0, import_jsx_runtime45.jsx)(
|
|
3903
4026
|
Button,
|
|
3904
4027
|
{
|
|
3905
4028
|
size: "sm",
|
|
@@ -3910,29 +4033,20 @@ function FilterBar({ fields = [], filters, onFilterChange, onFilterRemove, align
|
|
|
3910
4033
|
onClick: () => setPanel(panel?.kind === "add" ? null : { kind: "add" }),
|
|
3911
4034
|
children: "Filter"
|
|
3912
4035
|
}
|
|
3913
|
-
),
|
|
3914
|
-
|
|
3915
|
-
|
|
4036
|
+
) }),
|
|
4037
|
+
/* @__PURE__ */ (0, import_jsx_runtime45.jsx)(
|
|
4038
|
+
Popover,
|
|
3916
4039
|
{
|
|
3917
|
-
|
|
3918
|
-
|
|
3919
|
-
|
|
3920
|
-
|
|
3921
|
-
|
|
3922
|
-
|
|
3923
|
-
|
|
3924
|
-
|
|
3925
|
-
role: "menuitem",
|
|
3926
|
-
className: "fd-row",
|
|
3927
|
-
onClick: () => startEditing(f.key),
|
|
3928
|
-
style: { gap: 8, padding: "4px 8px", borderRadius: 7, border: 0, width: "100%", textAlign: "left", cursor: "pointer", background: "transparent" },
|
|
3929
|
-
children: /* @__PURE__ */ (0, import_jsx_runtime45.jsx)("span", { className: "fd-body-sm", style: { flex: 1, color: "var(--text)" }, children: f.label })
|
|
3930
|
-
},
|
|
3931
|
-
f.key
|
|
3932
|
-
))
|
|
3933
|
-
] })
|
|
4040
|
+
open: panel?.kind === "add",
|
|
4041
|
+
anchorRef: addAnchorRef,
|
|
4042
|
+
onClose: closeEditing,
|
|
4043
|
+
placement: align === "right" ? "bottom-end" : "bottom-start",
|
|
4044
|
+
minWidth: 200,
|
|
4045
|
+
role: "menu",
|
|
4046
|
+
label: "Add filter",
|
|
4047
|
+
children: /* @__PURE__ */ (0, import_jsx_runtime45.jsx)(Menu, { items: addMenuItems })
|
|
3934
4048
|
}
|
|
3935
|
-
)
|
|
4049
|
+
)
|
|
3936
4050
|
] }) : null
|
|
3937
4051
|
] });
|
|
3938
4052
|
}
|
|
@@ -3964,7 +4078,7 @@ function StatTile({ label, value, sub, delta, invert = false, loading = false, c
|
|
|
3964
4078
|
}
|
|
3965
4079
|
|
|
3966
4080
|
// src/components/data/CodeBlock.tsx
|
|
3967
|
-
var
|
|
4081
|
+
var React25 = __toESM(require("react"), 1);
|
|
3968
4082
|
var import_jsx_runtime47 = require("react/jsx-runtime");
|
|
3969
4083
|
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)$/;
|
|
3970
4084
|
var RULES = {
|
|
@@ -4120,13 +4234,13 @@ function tokenize(src, lang) {
|
|
|
4120
4234
|
return out;
|
|
4121
4235
|
}
|
|
4122
4236
|
function Highlighted({ code, lang }) {
|
|
4123
|
-
const toks =
|
|
4237
|
+
const toks = React25.useMemo(() => tokenize(code, lang), [code, lang]);
|
|
4124
4238
|
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) });
|
|
4125
4239
|
}
|
|
4126
4240
|
function useCopy() {
|
|
4127
|
-
const [done, setDone] =
|
|
4128
|
-
const timer =
|
|
4129
|
-
|
|
4241
|
+
const [done, setDone] = React25.useState(false);
|
|
4242
|
+
const timer = React25.useRef(null);
|
|
4243
|
+
React25.useEffect(() => () => {
|
|
4130
4244
|
if (timer.current) clearTimeout(timer.current);
|
|
4131
4245
|
}, []);
|
|
4132
4246
|
const copy = (text) => {
|
|
@@ -4162,8 +4276,8 @@ function CodeBlock({
|
|
|
4162
4276
|
actions,
|
|
4163
4277
|
className = ""
|
|
4164
4278
|
}) {
|
|
4165
|
-
const [wrap, setWrap] =
|
|
4166
|
-
const [open, setOpen] =
|
|
4279
|
+
const [wrap, setWrap] = React25.useState(!!wrapDefault);
|
|
4280
|
+
const [open, setOpen] = React25.useState(false);
|
|
4167
4281
|
const [copied, copy] = useCopy();
|
|
4168
4282
|
const body = String(code).replace(/\n$/, "");
|
|
4169
4283
|
const lines = body.split("\n");
|
|
@@ -4192,7 +4306,7 @@ function CodeBlock({
|
|
|
4192
4306
|
] });
|
|
4193
4307
|
}
|
|
4194
4308
|
function DiffBlock({ diff = "", filename, collapseAfter = 34, className = "" }) {
|
|
4195
|
-
const [open, setOpen] =
|
|
4309
|
+
const [open, setOpen] = React25.useState(false);
|
|
4196
4310
|
const [copied, copy] = useCopy();
|
|
4197
4311
|
const raw = String(diff).replace(/\n$/, "");
|
|
4198
4312
|
const all = raw.split("\n").map((line) => {
|
|
@@ -4238,7 +4352,7 @@ function DiffBlock({ diff = "", filename, collapseAfter = 34, className = "" })
|
|
|
4238
4352
|
}
|
|
4239
4353
|
|
|
4240
4354
|
// src/components/data/Markdown.tsx
|
|
4241
|
-
var
|
|
4355
|
+
var React26 = __toESM(require("react"), 1);
|
|
4242
4356
|
var import_jsx_runtime48 = require("react/jsx-runtime");
|
|
4243
4357
|
var SAFE = /^(?:https?:|mailto:|tel:|#|\/|\.{1,2}\/)/i;
|
|
4244
4358
|
var safeHref = (h) => SAFE.test(String(h || "").trim()) ? String(h).trim() : null;
|
|
@@ -4277,7 +4391,7 @@ function inlineNodes(src, ctx, keyBase) {
|
|
|
4277
4391
|
const href = safeHref(g(2));
|
|
4278
4392
|
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()));
|
|
4279
4393
|
} else if (kind === "cite") {
|
|
4280
|
-
out.push(ctx.renderCitation ? /* @__PURE__ */ (0, import_jsx_runtime48.jsx)(
|
|
4394
|
+
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()));
|
|
4281
4395
|
} 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()));
|
|
4282
4396
|
else if (kind === "strong") out.push(/* @__PURE__ */ (0, import_jsx_runtime48.jsx)("strong", { children: inlineNodes(g(1) || g(2), ctx, key()) }, key()));
|
|
4283
4397
|
else if (kind === "em") out.push(/* @__PURE__ */ (0, import_jsx_runtime48.jsx)("em", { children: inlineNodes(g(1) || g(2), ctx, key()) }, key()));
|
|
@@ -4442,7 +4556,7 @@ function Markdown({
|
|
|
4442
4556
|
onLinkClick
|
|
4443
4557
|
}) {
|
|
4444
4558
|
const ctx = { allowImages, headingOffset, renderCitation, onLinkClick, codeProps };
|
|
4445
|
-
const blocks =
|
|
4559
|
+
const blocks = React26.useMemo(() => parseBlocks(source), [source]);
|
|
4446
4560
|
return /* @__PURE__ */ (0, import_jsx_runtime48.jsx)("div", { className: ["fd-md", className].filter(Boolean).join(" "), children: renderBlocks(blocks, ctx, "b") });
|
|
4447
4561
|
}
|
|
4448
4562
|
function MarkdownInline({ source = "", className = "", onLinkClick }) {
|
|
@@ -4556,7 +4670,7 @@ function Pagination({
|
|
|
4556
4670
|
}
|
|
4557
4671
|
|
|
4558
4672
|
// src/components/data/RelativeTime.tsx
|
|
4559
|
-
var
|
|
4673
|
+
var React27 = __toESM(require("react"), 1);
|
|
4560
4674
|
var import_jsx_runtime51 = require("react/jsx-runtime");
|
|
4561
4675
|
var MIN = 6e4;
|
|
4562
4676
|
var HOUR = 36e5;
|
|
@@ -4608,9 +4722,9 @@ function formatDuration(ms) {
|
|
|
4608
4722
|
return h + "h" + (m % 60 ? " " + m % 60 + "m" : "");
|
|
4609
4723
|
}
|
|
4610
4724
|
function RelativeTime({ value, prefix, className = "", refresh: refresh2 = true, ...rest }) {
|
|
4611
|
-
const [, force] =
|
|
4725
|
+
const [, force] = React27.useState(0);
|
|
4612
4726
|
const t = value instanceof Date ? value.getTime() : Date.parse(value);
|
|
4613
|
-
|
|
4727
|
+
React27.useEffect(() => {
|
|
4614
4728
|
if (!refresh2 || !t || isNaN(t)) return;
|
|
4615
4729
|
const abs = Math.abs(t - Date.now());
|
|
4616
4730
|
if (abs > DAY) return;
|
|
@@ -4626,7 +4740,7 @@ function RelativeTime({ value, prefix, className = "", refresh: refresh2 = true,
|
|
|
4626
4740
|
}
|
|
4627
4741
|
|
|
4628
4742
|
// src/components/data/ScoreMeter.tsx
|
|
4629
|
-
var
|
|
4743
|
+
var React28 = __toESM(require("react"), 1);
|
|
4630
4744
|
var import_jsx_runtime52 = require("react/jsx-runtime");
|
|
4631
4745
|
function ScoreMeter({
|
|
4632
4746
|
score,
|
|
@@ -4641,10 +4755,10 @@ function ScoreMeter({
|
|
|
4641
4755
|
breakdownWidth = 280,
|
|
4642
4756
|
className = ""
|
|
4643
4757
|
}) {
|
|
4644
|
-
const [open, setOpen] =
|
|
4645
|
-
const ref =
|
|
4758
|
+
const [open, setOpen] = React28.useState(false);
|
|
4759
|
+
const ref = React28.useRef(null);
|
|
4646
4760
|
const value = Math.max(0, Math.min(100, Math.round(Number(score) || 0)));
|
|
4647
|
-
const body = /* @__PURE__ */ (0, import_jsx_runtime52.jsxs)(
|
|
4761
|
+
const body = /* @__PURE__ */ (0, import_jsx_runtime52.jsxs)(React28.Fragment, { children: [
|
|
4648
4762
|
/* @__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 }) }),
|
|
4649
4763
|
showScore ? /* @__PURE__ */ (0, import_jsx_runtime52.jsx)("span", { className: "fd-scoremeter-value fd-tabular", "aria-hidden": "true", children: value }) : null
|
|
4650
4764
|
] });
|
|
@@ -4663,7 +4777,7 @@ function ScoreMeter({
|
|
|
4663
4777
|
}
|
|
4664
4778
|
);
|
|
4665
4779
|
}
|
|
4666
|
-
return /* @__PURE__ */ (0, import_jsx_runtime52.jsxs)(
|
|
4780
|
+
return /* @__PURE__ */ (0, import_jsx_runtime52.jsxs)(React28.Fragment, { children: [
|
|
4667
4781
|
/* @__PURE__ */ (0, import_jsx_runtime52.jsx)(
|
|
4668
4782
|
"button",
|
|
4669
4783
|
{
|
|
@@ -4694,13 +4808,13 @@ function ScoreMeter({
|
|
|
4694
4808
|
}
|
|
4695
4809
|
|
|
4696
4810
|
// src/components/data/SortMenu.tsx
|
|
4697
|
-
var
|
|
4811
|
+
var React29 = __toESM(require("react"), 1);
|
|
4698
4812
|
var import_jsx_runtime53 = require("react/jsx-runtime");
|
|
4699
4813
|
function SortMenu({ fields = [], sort, onSort, align = "right", size = "md", className = "", ...rest }) {
|
|
4700
|
-
const [open, setOpen] =
|
|
4814
|
+
const [open, setOpen] = React29.useState(false);
|
|
4701
4815
|
const zIndex = useOverlayLayer(open);
|
|
4702
|
-
const ref =
|
|
4703
|
-
|
|
4816
|
+
const ref = React29.useRef(null);
|
|
4817
|
+
React29.useEffect(() => {
|
|
4704
4818
|
if (!open) return;
|
|
4705
4819
|
const away = (e) => {
|
|
4706
4820
|
if (ref.current && !ref.current.contains(e.target)) setOpen(false);
|
|
@@ -4762,7 +4876,7 @@ function SortMenu({ fields = [], sort, onSort, align = "right", size = "md", cla
|
|
|
4762
4876
|
}
|
|
4763
4877
|
|
|
4764
4878
|
// src/components/data/StepList.tsx
|
|
4765
|
-
var
|
|
4879
|
+
var React30 = __toESM(require("react"), 1);
|
|
4766
4880
|
var import_jsx_runtime54 = require("react/jsx-runtime");
|
|
4767
4881
|
var KIND_ICON = { tool: "wrench", search: "magnifying-glass", read: "file-text", write: "pencil-simple", reasoning: "brain", run: "terminal", fetch: "cloud-arrow-down" };
|
|
4768
4882
|
function StepList({
|
|
@@ -4775,9 +4889,9 @@ function StepList({
|
|
|
4775
4889
|
dense = false,
|
|
4776
4890
|
className = ""
|
|
4777
4891
|
}) {
|
|
4778
|
-
const [openState, setOpenState] =
|
|
4892
|
+
const [openState, setOpenState] = React30.useState(defaultOpen);
|
|
4779
4893
|
const open = openProp == null ? openState : openProp;
|
|
4780
|
-
const [expanded, setExpanded] =
|
|
4894
|
+
const [expanded, setExpanded] = React30.useState({});
|
|
4781
4895
|
if (!steps.length) return null;
|
|
4782
4896
|
const running = steps.some((s) => s.status === "running");
|
|
4783
4897
|
const failed = steps.filter((s) => s.status === "error").length;
|
|
@@ -4835,7 +4949,7 @@ function StepList({
|
|
|
4835
4949
|
}
|
|
4836
4950
|
|
|
4837
4951
|
// src/components/data/VirtualList.tsx
|
|
4838
|
-
var
|
|
4952
|
+
var React31 = __toESM(require("react"), 1);
|
|
4839
4953
|
var import_jsx_runtime55 = require("react/jsx-runtime");
|
|
4840
4954
|
var VIRTUAL_LIST_BUFFER_ROWS = 20;
|
|
4841
4955
|
var VIRTUAL_LIST_ROW_GAP = 6;
|
|
@@ -4887,35 +5001,35 @@ function VirtualList({
|
|
|
4887
5001
|
className = "",
|
|
4888
5002
|
style
|
|
4889
5003
|
}) {
|
|
4890
|
-
const [scrollTop, setScrollTop] =
|
|
4891
|
-
const loaded =
|
|
5004
|
+
const [scrollTop, setScrollTop] = React31.useState(0);
|
|
5005
|
+
const loaded = React31.useMemo(
|
|
4892
5006
|
() => ({ firstItemIndex, count: items.length }),
|
|
4893
5007
|
[firstItemIndex, items.length]
|
|
4894
5008
|
);
|
|
4895
5009
|
const total = Math.max(totalCount == null ? 0 : totalCount, firstItemIndex + items.length);
|
|
4896
5010
|
const bandKey = firstItemIndex + ":" + items.length;
|
|
4897
|
-
const win =
|
|
5011
|
+
const win = React31.useMemo(
|
|
4898
5012
|
() => computeVirtualWindow({ scrollTop, viewportHeight: height, itemHeight, itemCount: total, loaded }),
|
|
4899
5013
|
[scrollTop, height, itemHeight, total, loaded]
|
|
4900
5014
|
);
|
|
4901
|
-
const need =
|
|
5015
|
+
const need = React31.useMemo(() => computeNeedMore(win, loaded), [win, loaded]);
|
|
4902
5016
|
const wantStart = need.start && hasMore?.start !== false;
|
|
4903
5017
|
const wantEnd = need.end && hasMore?.end !== false;
|
|
4904
5018
|
const bucket2 = Math.floor(win.visibleStart / VIRTUAL_LIST_BUFFER_ROWS);
|
|
4905
5019
|
const askKey = bandKey + "@" + bucket2;
|
|
4906
|
-
const asked =
|
|
4907
|
-
|
|
5020
|
+
const asked = React31.useRef({ start: null, end: null });
|
|
5021
|
+
React31.useEffect(() => {
|
|
4908
5022
|
if (loading || !wantStart || asked.current.start === askKey) return;
|
|
4909
5023
|
asked.current.start = askKey;
|
|
4910
5024
|
onNeedMore("start", win);
|
|
4911
5025
|
}, [wantStart, loading, askKey, onNeedMore, win]);
|
|
4912
|
-
|
|
5026
|
+
React31.useEffect(() => {
|
|
4913
5027
|
if (loading || !wantEnd || asked.current.end === askKey) return;
|
|
4914
5028
|
asked.current.end = askKey;
|
|
4915
5029
|
onNeedMore("end", win);
|
|
4916
5030
|
}, [wantEnd, loading, askKey, onNeedMore, win]);
|
|
4917
|
-
const lastKeysRef =
|
|
4918
|
-
const newKeys =
|
|
5031
|
+
const lastKeysRef = React31.useRef(null);
|
|
5032
|
+
const newKeys = React31.useMemo(() => {
|
|
4919
5033
|
const prev = lastKeysRef.current;
|
|
4920
5034
|
if (!prev) return /* @__PURE__ */ new Set();
|
|
4921
5035
|
const fresh = /* @__PURE__ */ new Set();
|
|
@@ -4925,7 +5039,7 @@ function VirtualList({
|
|
|
4925
5039
|
}
|
|
4926
5040
|
return fresh;
|
|
4927
5041
|
}, [items]);
|
|
4928
|
-
|
|
5042
|
+
React31.useEffect(() => {
|
|
4929
5043
|
lastKeysRef.current = new Set(items.map(keyOf));
|
|
4930
5044
|
}, [items]);
|
|
4931
5045
|
const gapStyle = { "--fd-vlist-gap": rowGap + "px" };
|
|
@@ -4970,7 +5084,7 @@ function VirtualList({
|
|
|
4970
5084
|
}
|
|
4971
5085
|
|
|
4972
5086
|
// src/components/data/EntityRow.tsx
|
|
4973
|
-
var
|
|
5087
|
+
var React32 = __toESM(require("react"), 1);
|
|
4974
5088
|
var import_jsx_runtime56 = require("react/jsx-runtime");
|
|
4975
5089
|
var ENTITY_ROW_METRIC_WIDTH = 74;
|
|
4976
5090
|
var METRIC_TONE_COLOR = {
|
|
@@ -4983,7 +5097,7 @@ function EntityRowMetrics({ metrics, className = "", style }) {
|
|
|
4983
5097
|
const key = m.id || m.label || i;
|
|
4984
5098
|
const className2 = ["fd-erow-metric", m.tone && m.tone !== "default" ? "is-" + m.tone : "", m.tooltip != null ? "is-described" : ""].filter(Boolean).join(" ");
|
|
4985
5099
|
const tone = { color: METRIC_TONE_COLOR[m.tone || "default"] };
|
|
4986
|
-
const content = /* @__PURE__ */ (0, import_jsx_runtime56.jsxs)(
|
|
5100
|
+
const content = /* @__PURE__ */ (0, import_jsx_runtime56.jsxs)(React32.Fragment, { children: [
|
|
4987
5101
|
m.icon ? /* @__PURE__ */ (0, import_jsx_runtime56.jsx)("i", { className: "ph ph-" + m.icon, "aria-hidden": "true" }) : null,
|
|
4988
5102
|
/* @__PURE__ */ (0, import_jsx_runtime56.jsx)("span", { className: "fd-erow-metric-value fd-tabular", children: m.value }),
|
|
4989
5103
|
/* @__PURE__ */ (0, import_jsx_runtime56.jsx)("span", { className: "fd-sr", children: " " + m.label })
|
|
@@ -5075,7 +5189,7 @@ function EntityRow({
|
|
|
5075
5189
|
}
|
|
5076
5190
|
|
|
5077
5191
|
// src/components/data/TransferList.tsx
|
|
5078
|
-
var
|
|
5192
|
+
var React33 = __toESM(require("react"), 1);
|
|
5079
5193
|
var import_react_dom5 = require("react-dom");
|
|
5080
5194
|
|
|
5081
5195
|
// src/components/forms/Input.tsx
|
|
@@ -5181,12 +5295,12 @@ function TransferList({
|
|
|
5181
5295
|
listHeight = 440,
|
|
5182
5296
|
className = ""
|
|
5183
5297
|
}) {
|
|
5184
|
-
const [drag, setDrag] =
|
|
5185
|
-
const [dragOverSide, setDragOverSide] =
|
|
5186
|
-
const dragRef =
|
|
5187
|
-
const armedRef =
|
|
5188
|
-
const sideRefs =
|
|
5189
|
-
const hitTestSide =
|
|
5298
|
+
const [drag, setDrag] = React33.useState(null);
|
|
5299
|
+
const [dragOverSide, setDragOverSide] = React33.useState(null);
|
|
5300
|
+
const dragRef = React33.useRef(null);
|
|
5301
|
+
const armedRef = React33.useRef(null);
|
|
5302
|
+
const sideRefs = React33.useRef({ left: null, right: null });
|
|
5303
|
+
const hitTestSide = React33.useCallback((x, y) => {
|
|
5190
5304
|
for (const side of ["left", "right"]) {
|
|
5191
5305
|
const el = sideRefs.current[side];
|
|
5192
5306
|
if (!el) continue;
|
|
@@ -5195,7 +5309,7 @@ function TransferList({
|
|
|
5195
5309
|
}
|
|
5196
5310
|
return null;
|
|
5197
5311
|
}, []);
|
|
5198
|
-
const findItem =
|
|
5312
|
+
const findItem = React33.useCallback(
|
|
5199
5313
|
(side, key) => (side === "left" ? left.items : right.items).find((it) => keyOf(it) === key),
|
|
5200
5314
|
[left.items, right.items, keyOf]
|
|
5201
5315
|
);
|
|
@@ -5217,7 +5331,7 @@ function TransferList({
|
|
|
5217
5331
|
height: rect.height
|
|
5218
5332
|
};
|
|
5219
5333
|
};
|
|
5220
|
-
|
|
5334
|
+
React33.useEffect(() => {
|
|
5221
5335
|
const onMovePointer = (e) => {
|
|
5222
5336
|
const armed = armedRef.current;
|
|
5223
5337
|
if (!armed || e.pointerId !== armed.pointerId) return;
|
|
@@ -5270,7 +5384,7 @@ function TransferList({
|
|
|
5270
5384
|
window.removeEventListener("pointercancel", endDrag);
|
|
5271
5385
|
};
|
|
5272
5386
|
}, [hitTestSide, findItem, onMove]);
|
|
5273
|
-
|
|
5387
|
+
React33.useEffect(() => {
|
|
5274
5388
|
if (!drag || typeof document === "undefined") return;
|
|
5275
5389
|
const prev = document.body.style.userSelect;
|
|
5276
5390
|
document.body.style.userSelect = "none";
|
|
@@ -5378,11 +5492,11 @@ function TransferList({
|
|
|
5378
5492
|
}
|
|
5379
5493
|
|
|
5380
5494
|
// src/components/forms/Checkbox.tsx
|
|
5381
|
-
var
|
|
5495
|
+
var React34 = __toESM(require("react"), 1);
|
|
5382
5496
|
var import_jsx_runtime60 = require("react/jsx-runtime");
|
|
5383
5497
|
function Checkbox({ label, description, card = false, indeterminate = false, className = "", ...rest }) {
|
|
5384
|
-
const ref =
|
|
5385
|
-
|
|
5498
|
+
const ref = React34.useRef(null);
|
|
5499
|
+
React34.useEffect(() => {
|
|
5386
5500
|
if (ref.current) ref.current.indeterminate = indeterminate;
|
|
5387
5501
|
}, [indeterminate]);
|
|
5388
5502
|
return /* @__PURE__ */ (0, import_jsx_runtime60.jsxs)("label", { className: ["fd-choice", card ? "fd-choice-card" : "", className].filter(Boolean).join(" "), children: [
|
|
@@ -5426,7 +5540,7 @@ function Switch({ label, description, className = "", ...rest }) {
|
|
|
5426
5540
|
}
|
|
5427
5541
|
|
|
5428
5542
|
// src/components/forms/Select.tsx
|
|
5429
|
-
var
|
|
5543
|
+
var React35 = __toESM(require("react"), 1);
|
|
5430
5544
|
var import_jsx_runtime63 = require("react/jsx-runtime");
|
|
5431
5545
|
var norm = (o) => typeof o === "string" ? { value: o, label: o } : o;
|
|
5432
5546
|
function Select({
|
|
@@ -5453,13 +5567,12 @@ function Select({
|
|
|
5453
5567
|
const isOn = (v) => multiple ? vals.includes(v) : v === value;
|
|
5454
5568
|
const hasSearch = searchable === void 0 ? opts.length > 8 : searchable;
|
|
5455
5569
|
const { fieldId, labelId, ariaLabelledBy } = useTriggerLabelling(label, id);
|
|
5456
|
-
const [open, setOpen] =
|
|
5457
|
-
const [q, setQ] =
|
|
5458
|
-
const
|
|
5459
|
-
const
|
|
5460
|
-
const
|
|
5461
|
-
const
|
|
5462
|
-
const typeBuf = React34.useRef({ s: "", t: 0 });
|
|
5570
|
+
const [open, setOpen] = React35.useState(false);
|
|
5571
|
+
const [q, setQ] = React35.useState("");
|
|
5572
|
+
const rootRef = React35.useRef(null);
|
|
5573
|
+
const boxRef = React35.useRef(null);
|
|
5574
|
+
const listRef = React35.useRef(null);
|
|
5575
|
+
const typeBuf = React35.useRef({ s: "", t: 0 });
|
|
5463
5576
|
const selected = multiple ? null : opts.find((o) => o.value === value);
|
|
5464
5577
|
const chosen = multiple ? opts.filter((o) => vals.includes(o.value)) : [];
|
|
5465
5578
|
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;
|
|
@@ -5476,23 +5589,16 @@ function Select({
|
|
|
5476
5589
|
fire(o.value);
|
|
5477
5590
|
setOpen(false);
|
|
5478
5591
|
};
|
|
5592
|
+
const nav = useListboxNav({ count: visible.length, onSelect: (i) => pick(visible[i]) });
|
|
5593
|
+
useListboxScrollIntoView(nav.active, listRef, open);
|
|
5479
5594
|
const toggle = () => {
|
|
5480
5595
|
if (disabled || loading) return;
|
|
5481
5596
|
if (!open) {
|
|
5482
5597
|
setQ("");
|
|
5483
|
-
setActive(Math.max(0, opts.findIndex((o) => isOn(o.value))));
|
|
5598
|
+
nav.setActive(Math.max(0, opts.findIndex((o) => isOn(o.value))));
|
|
5484
5599
|
}
|
|
5485
5600
|
setOpen(!open);
|
|
5486
5601
|
};
|
|
5487
|
-
React34.useEffect(() => {
|
|
5488
|
-
if (!open || active < 0 || !listRef.current) return;
|
|
5489
|
-
const el = listRef.current.querySelector('[data-i="' + active + '"]');
|
|
5490
|
-
if (el) {
|
|
5491
|
-
const L = listRef.current, top = el.offsetTop - L.offsetTop;
|
|
5492
|
-
if (top < L.scrollTop) L.scrollTop = top - 4;
|
|
5493
|
-
else if (top + el.offsetHeight > L.scrollTop + L.clientHeight) L.scrollTop = top + el.offsetHeight - L.clientHeight + 4;
|
|
5494
|
-
}
|
|
5495
|
-
}, [active, open]);
|
|
5496
5602
|
const onKey = (e) => {
|
|
5497
5603
|
if (disabled) return;
|
|
5498
5604
|
if (!open && (e.key === "Enter" || e.key === " " || e.key === "ArrowDown" || e.key === "ArrowUp")) {
|
|
@@ -5514,19 +5620,19 @@ function Select({
|
|
|
5514
5620
|
setOpen(false);
|
|
5515
5621
|
} else if (e.key === "ArrowDown") {
|
|
5516
5622
|
e.preventDefault();
|
|
5517
|
-
|
|
5623
|
+
nav.move(1);
|
|
5518
5624
|
} else if (e.key === "ArrowUp") {
|
|
5519
5625
|
e.preventDefault();
|
|
5520
|
-
|
|
5626
|
+
nav.move(-1);
|
|
5521
5627
|
} else if (e.key === "Home") {
|
|
5522
5628
|
e.preventDefault();
|
|
5523
|
-
|
|
5629
|
+
nav.first();
|
|
5524
5630
|
} else if (e.key === "End") {
|
|
5525
5631
|
e.preventDefault();
|
|
5526
|
-
|
|
5632
|
+
nav.last();
|
|
5527
5633
|
} else if (e.key === "Enter") {
|
|
5528
5634
|
e.preventDefault();
|
|
5529
|
-
|
|
5635
|
+
nav.activate();
|
|
5530
5636
|
} else if (e.key === "Tab") setOpen(false);
|
|
5531
5637
|
};
|
|
5532
5638
|
const groups = [];
|
|
@@ -5599,13 +5705,13 @@ function Select({
|
|
|
5599
5705
|
onKeyDown: onKey,
|
|
5600
5706
|
onChange: (e) => {
|
|
5601
5707
|
setQ(e.target.value);
|
|
5602
|
-
setActive(0);
|
|
5708
|
+
nav.setActive(0);
|
|
5603
5709
|
}
|
|
5604
5710
|
}
|
|
5605
5711
|
),
|
|
5606
5712
|
q ? /* @__PURE__ */ (0, import_jsx_runtime63.jsx)("span", { className: "fd-body-sm fd-muted", children: visible.length }) : null
|
|
5607
5713
|
] }) : void 0,
|
|
5608
|
-
footer: multiple ? /* @__PURE__ */ (0, import_jsx_runtime63.jsxs)(
|
|
5714
|
+
footer: multiple ? /* @__PURE__ */ (0, import_jsx_runtime63.jsxs)(React35.Fragment, { children: [
|
|
5609
5715
|
/* @__PURE__ */ (0, import_jsx_runtime63.jsx)(
|
|
5610
5716
|
"button",
|
|
5611
5717
|
{
|
|
@@ -5636,7 +5742,7 @@ function Select({
|
|
|
5636
5742
|
'Nothing matches "',
|
|
5637
5743
|
q,
|
|
5638
5744
|
'".'
|
|
5639
|
-
] }) : groups.map((grp) => /* @__PURE__ */ (0, import_jsx_runtime63.jsxs)(
|
|
5745
|
+
] }) : groups.map((grp) => /* @__PURE__ */ (0, import_jsx_runtime63.jsxs)(React35.Fragment, { children: [
|
|
5640
5746
|
grp.g ? /* @__PURE__ */ (0, import_jsx_runtime63.jsx)("div", { className: "fd-pop-group", children: grp.g }) : null,
|
|
5641
5747
|
grp.items.map(({ o, i }) => /* @__PURE__ */ (0, import_jsx_runtime63.jsxs)(
|
|
5642
5748
|
"button",
|
|
@@ -5646,8 +5752,8 @@ function Select({
|
|
|
5646
5752
|
role: "option",
|
|
5647
5753
|
"aria-selected": isOn(o.value),
|
|
5648
5754
|
"aria-disabled": o.disabled || void 0,
|
|
5649
|
-
className: ["fd-opt", i === active ? "is-active" : "", isOn(o.value) ? "is-selected" : ""].filter(Boolean).join(" "),
|
|
5650
|
-
onMouseEnter: () => setActive(i),
|
|
5755
|
+
className: ["fd-opt", i === nav.active ? "is-active" : "", isOn(o.value) ? "is-selected" : ""].filter(Boolean).join(" "),
|
|
5756
|
+
onMouseEnter: () => nav.setActive(i),
|
|
5651
5757
|
onClick: () => pick(o),
|
|
5652
5758
|
children: [
|
|
5653
5759
|
multiple ? /* @__PURE__ */ (0, import_jsx_runtime63.jsx)("span", { "aria-hidden": "true", style: { flex: "none", display: "grid", placeItems: "center", width: 16, height: 16, borderRadius: 4, border: "1.5px solid " + (isOn(o.value) ? "var(--brand)" : "var(--border-strong, var(--border))"), background: isOn(o.value) ? "var(--brand)" : "var(--surface)", color: "#fff" }, children: isOn(o.value) ? /* @__PURE__ */ (0, import_jsx_runtime63.jsx)("i", { className: "ph ph-check", style: { fontSize: 11 } }) : null }) : null,
|
|
@@ -5673,7 +5779,7 @@ function Select({
|
|
|
5673
5779
|
}
|
|
5674
5780
|
|
|
5675
5781
|
// src/components/forms/TimePicker.tsx
|
|
5676
|
-
var
|
|
5782
|
+
var React36 = __toESM(require("react"), 1);
|
|
5677
5783
|
var import_jsx_runtime64 = require("react/jsx-runtime");
|
|
5678
5784
|
var pad = (n) => String(n).padStart(2, "0");
|
|
5679
5785
|
function ClockFace({ value = "09:00", onChange }) {
|
|
@@ -5682,9 +5788,9 @@ function ClockFace({ value = "09:00", onChange }) {
|
|
|
5682
5788
|
if (isNaN(m)) m = 0;
|
|
5683
5789
|
const pm = h24 >= 12;
|
|
5684
5790
|
const h12 = h24 % 12 === 0 ? 12 : h24 % 12;
|
|
5685
|
-
const [mode2, setMode] =
|
|
5686
|
-
const faceRef =
|
|
5687
|
-
const dragging =
|
|
5791
|
+
const [mode2, setMode] = React36.useState("h");
|
|
5792
|
+
const faceRef = React36.useRef(null);
|
|
5793
|
+
const dragging = React36.useRef(false);
|
|
5688
5794
|
const set = (h, mm, isPm) => onChange((isPm ? h % 12 + 12 : h % 12) + ":" + pad(mm));
|
|
5689
5795
|
const R = 108, NR = 80;
|
|
5690
5796
|
const nums = mode2 === "h" ? Array.from({ length: 12 }, (_, i) => i + 1) : Array.from({ length: 12 }, (_, i) => i * 5);
|
|
@@ -5757,9 +5863,9 @@ function ClockFace({ value = "09:00", onChange }) {
|
|
|
5757
5863
|
}
|
|
5758
5864
|
function TimePicker({ label, help, error, required = false, disabled = false, value = "", onChange, placeholder = "Pick a time", id, className = "", style }) {
|
|
5759
5865
|
const { fieldId, labelId, ariaLabelledBy } = useTriggerLabelling(label, id);
|
|
5760
|
-
const [open, setOpen] =
|
|
5761
|
-
const rootRef =
|
|
5762
|
-
const boxRef =
|
|
5866
|
+
const [open, setOpen] = React36.useState(false);
|
|
5867
|
+
const rootRef = React36.useRef(null);
|
|
5868
|
+
const boxRef = React36.useRef(null);
|
|
5763
5869
|
const disp = () => {
|
|
5764
5870
|
if (!value) return "";
|
|
5765
5871
|
const [h, m] = value.split(":").map(Number);
|
|
@@ -5802,7 +5908,7 @@ function TimePicker({ label, help, error, required = false, disabled = false, va
|
|
|
5802
5908
|
offset: 6,
|
|
5803
5909
|
width: 262,
|
|
5804
5910
|
role: "presentation",
|
|
5805
|
-
footer: /* @__PURE__ */ (0, import_jsx_runtime64.jsxs)(
|
|
5911
|
+
footer: /* @__PURE__ */ (0, import_jsx_runtime64.jsxs)(React36.Fragment, { children: [
|
|
5806
5912
|
/* @__PURE__ */ (0, import_jsx_runtime64.jsx)(
|
|
5807
5913
|
"button",
|
|
5808
5914
|
{
|
|
@@ -5830,7 +5936,7 @@ function TimePicker({ label, help, error, required = false, disabled = false, va
|
|
|
5830
5936
|
}
|
|
5831
5937
|
|
|
5832
5938
|
// src/components/forms/Slider.tsx
|
|
5833
|
-
var
|
|
5939
|
+
var React37 = __toESM(require("react"), 1);
|
|
5834
5940
|
var import_jsx_runtime65 = require("react/jsx-runtime");
|
|
5835
5941
|
function Slider({
|
|
5836
5942
|
label,
|
|
@@ -5848,7 +5954,7 @@ function Slider({
|
|
|
5848
5954
|
...rest
|
|
5849
5955
|
}) {
|
|
5850
5956
|
const fieldId = useFieldId(id);
|
|
5851
|
-
const [dragging, setDragging] =
|
|
5957
|
+
const [dragging, setDragging] = React37.useState(false);
|
|
5852
5958
|
const v = value === void 0 ? min : Number(value);
|
|
5853
5959
|
const pct = max === min ? 0 : (v - min) / (max - min) * 100;
|
|
5854
5960
|
return /* @__PURE__ */ (0, import_jsx_runtime65.jsxs)("div", { className: ["fd-field", className].filter(Boolean).join(" "), children: [
|
|
@@ -5882,7 +5988,7 @@ function Slider({
|
|
|
5882
5988
|
}
|
|
5883
5989
|
|
|
5884
5990
|
// src/components/forms/RangeSlider.tsx
|
|
5885
|
-
var
|
|
5991
|
+
var React38 = __toESM(require("react"), 1);
|
|
5886
5992
|
var import_jsx_runtime66 = require("react/jsx-runtime");
|
|
5887
5993
|
function RangeSlider({
|
|
5888
5994
|
label,
|
|
@@ -5902,9 +6008,9 @@ function RangeSlider({
|
|
|
5902
6008
|
}) {
|
|
5903
6009
|
const fmt2 = format || ((v) => String(v));
|
|
5904
6010
|
const [a, b] = value || [min, max];
|
|
5905
|
-
const [drag, setDrag] =
|
|
5906
|
-
const [focus, setFocus] =
|
|
5907
|
-
const railRef =
|
|
6011
|
+
const [drag, setDrag] = React38.useState(null);
|
|
6012
|
+
const [focus, setFocus] = React38.useState(null);
|
|
6013
|
+
const railRef = React38.useRef(null);
|
|
5908
6014
|
const pct = (v) => max === min ? 0 : (v - min) / (max - min) * 100;
|
|
5909
6015
|
const clampPair = (i, v) => {
|
|
5910
6016
|
v = Math.min(max, Math.max(min, Math.round(v / step) * step));
|
|
@@ -5919,7 +6025,7 @@ function RangeSlider({
|
|
|
5919
6025
|
const r = railRef.current.getBoundingClientRect();
|
|
5920
6026
|
return min + Math.min(1, Math.max(0, (e.clientX - r.left) / r.width)) * (max - min);
|
|
5921
6027
|
};
|
|
5922
|
-
|
|
6028
|
+
React38.useEffect(() => {
|
|
5923
6029
|
if (drag === null) return;
|
|
5924
6030
|
const mv = (e) => onChange && onChange(clampPair(drag, fromEvent(e)));
|
|
5925
6031
|
const upH = () => setDrag(null);
|
|
@@ -6000,7 +6106,7 @@ function RangeSlider({
|
|
|
6000
6106
|
/* @__PURE__ */ (0, import_jsx_runtime66.jsxs)("div", { className: "fd-range" + (hasLabels ? " has-labels" : ""), onPointerDown: onRailDown, children: [
|
|
6001
6107
|
/* @__PURE__ */ (0, import_jsx_runtime66.jsx)("span", { className: "fd-range-rail", ref: railRef }),
|
|
6002
6108
|
/* @__PURE__ */ (0, import_jsx_runtime66.jsx)("span", { className: "fd-range-fill", style: { left: pct(a) + "%", width: pct(b) - pct(a) + "%" } }),
|
|
6003
|
-
marks.map((m) => /* @__PURE__ */ (0, import_jsx_runtime66.jsxs)(
|
|
6109
|
+
marks.map((m) => /* @__PURE__ */ (0, import_jsx_runtime66.jsxs)(React38.Fragment, { children: [
|
|
6004
6110
|
/* @__PURE__ */ (0, import_jsx_runtime66.jsx)("span", { className: "fd-range-mark" + (m.value >= a && m.value <= b ? " is-in" : ""), style: { left: pct(m.value) + "%" } }),
|
|
6005
6111
|
m.label ? /* @__PURE__ */ (0, import_jsx_runtime66.jsx)("span", { className: "fd-range-mark-label", style: { left: pct(m.value) + "%" }, children: m.label }) : null
|
|
6006
6112
|
] }, m.value)),
|
|
@@ -6029,7 +6135,7 @@ function RangeSlider({
|
|
|
6029
6135
|
}
|
|
6030
6136
|
|
|
6031
6137
|
// src/components/forms/Dropzone.tsx
|
|
6032
|
-
var
|
|
6138
|
+
var React39 = __toESM(require("react"), 1);
|
|
6033
6139
|
var import_jsx_runtime67 = require("react/jsx-runtime");
|
|
6034
6140
|
function Dropzone({
|
|
6035
6141
|
onFiles,
|
|
@@ -6044,8 +6150,8 @@ function Dropzone({
|
|
|
6044
6150
|
className = "",
|
|
6045
6151
|
style
|
|
6046
6152
|
}) {
|
|
6047
|
-
const [over, setOver] =
|
|
6048
|
-
const depth =
|
|
6153
|
+
const [over, setOver] = React39.useState(false);
|
|
6154
|
+
const depth = React39.useRef(0);
|
|
6049
6155
|
const has = (e) => {
|
|
6050
6156
|
const dt = e.dataTransfer;
|
|
6051
6157
|
if (!dt) return false;
|
|
@@ -6107,8 +6213,8 @@ function FilePickButton({
|
|
|
6107
6213
|
className = "",
|
|
6108
6214
|
children
|
|
6109
6215
|
}) {
|
|
6110
|
-
const ref =
|
|
6111
|
-
return /* @__PURE__ */ (0, import_jsx_runtime67.jsxs)(
|
|
6216
|
+
const ref = React39.useRef(null);
|
|
6217
|
+
return /* @__PURE__ */ (0, import_jsx_runtime67.jsxs)(React39.Fragment, { children: [
|
|
6112
6218
|
/* @__PURE__ */ (0, import_jsx_runtime67.jsx)(
|
|
6113
6219
|
"button",
|
|
6114
6220
|
{
|
|
@@ -6141,10 +6247,10 @@ function FilePickButton({
|
|
|
6141
6247
|
}
|
|
6142
6248
|
function useStagedFiles(upload, opts) {
|
|
6143
6249
|
const o = opts || {};
|
|
6144
|
-
const [items, setItems] =
|
|
6145
|
-
const controllers =
|
|
6250
|
+
const [items, setItems] = React39.useState([]);
|
|
6251
|
+
const controllers = React39.useRef({});
|
|
6146
6252
|
const patch = (id, next) => setItems((list) => list.map((f) => f.id === id ? Object.assign({}, f, next) : f));
|
|
6147
|
-
const run =
|
|
6253
|
+
const run = React39.useCallback((att) => {
|
|
6148
6254
|
if (!upload) return;
|
|
6149
6255
|
const ac = typeof AbortController !== "undefined" ? new AbortController() : null;
|
|
6150
6256
|
controllers.current[att.id] = ac;
|
|
@@ -6161,14 +6267,14 @@ function useStagedFiles(upload, opts) {
|
|
|
6161
6267
|
delete controllers.current[att.id];
|
|
6162
6268
|
});
|
|
6163
6269
|
}, [upload]);
|
|
6164
|
-
const add =
|
|
6270
|
+
const add = React39.useCallback((files) => {
|
|
6165
6271
|
if (!upload) return [];
|
|
6166
6272
|
const atts = Array.from(files).map((f) => toAttachment(f));
|
|
6167
6273
|
setItems((list) => list.concat(atts));
|
|
6168
6274
|
atts.forEach(run);
|
|
6169
6275
|
return atts;
|
|
6170
6276
|
}, [upload, run]);
|
|
6171
|
-
const remove =
|
|
6277
|
+
const remove = React39.useCallback((att) => {
|
|
6172
6278
|
const ac = controllers.current[att.id];
|
|
6173
6279
|
if (ac) {
|
|
6174
6280
|
try {
|
|
@@ -6179,10 +6285,10 @@ function useStagedFiles(upload, opts) {
|
|
|
6179
6285
|
}
|
|
6180
6286
|
setItems((list) => list.filter((f) => f.id !== att.id));
|
|
6181
6287
|
}, []);
|
|
6182
|
-
const retry =
|
|
6288
|
+
const retry = React39.useCallback((att) => {
|
|
6183
6289
|
run(att);
|
|
6184
6290
|
}, [run]);
|
|
6185
|
-
const clear =
|
|
6291
|
+
const clear = React39.useCallback(() => {
|
|
6186
6292
|
Object.values(controllers.current).forEach((ac) => {
|
|
6187
6293
|
try {
|
|
6188
6294
|
ac && ac.abort();
|
|
@@ -6306,7 +6412,7 @@ function FileGrid({ files = [], onOpen, onRemove, onRetry, tiles = true, maxHeig
|
|
|
6306
6412
|
}
|
|
6307
6413
|
|
|
6308
6414
|
// src/components/forms/MarkdownEditor.tsx
|
|
6309
|
-
var
|
|
6415
|
+
var React40 = __toESM(require("react"), 1);
|
|
6310
6416
|
var import_jsx_runtime69 = require("react/jsx-runtime");
|
|
6311
6417
|
var isMac = typeof navigator !== "undefined" && /Mac|iPhone|iPad/.test(navigator.platform || navigator.userAgent || "");
|
|
6312
6418
|
var INLINE_RE = /(\*\*\*[^*\n]+\*\*\*|\*\*[^*\n]+\*\*|__[^_\n]+__|~~[^~\n]+~~|`[^`\n]+`|\*[^*\s][^*\n]*\*|(?<![A-Za-z0-9_])_[^_\s][^_\n]*_|\[[^\]\n]*\]\([^)\s\n]*\)|https?:\/\/\S+)/g;
|
|
@@ -6520,7 +6626,7 @@ function syncDom(root, value) {
|
|
|
6520
6626
|
while (root.children.length > lines.length) root.removeChild(root.lastChild);
|
|
6521
6627
|
}
|
|
6522
6628
|
var LIST_CONT = RE_LI;
|
|
6523
|
-
var MarkdownEditor =
|
|
6629
|
+
var MarkdownEditor = React40.forwardRef(function MarkdownEditor2({
|
|
6524
6630
|
value = "",
|
|
6525
6631
|
onChange,
|
|
6526
6632
|
onSubmit,
|
|
@@ -6539,10 +6645,10 @@ var MarkdownEditor = React39.forwardRef(function MarkdownEditor2({
|
|
|
6539
6645
|
className = "",
|
|
6540
6646
|
id
|
|
6541
6647
|
}, ref) {
|
|
6542
|
-
const boxRef =
|
|
6543
|
-
const composing =
|
|
6544
|
-
const pendingCaret =
|
|
6545
|
-
|
|
6648
|
+
const boxRef = React40.useRef(null);
|
|
6649
|
+
const composing = React40.useRef(false);
|
|
6650
|
+
const pendingCaret = React40.useRef(null);
|
|
6651
|
+
React40.useLayoutEffect(() => {
|
|
6546
6652
|
const root = boxRef.current;
|
|
6547
6653
|
if (!root || composing.current) return;
|
|
6548
6654
|
const active = document.activeElement === root || root.contains(document.activeElement);
|
|
@@ -6551,7 +6657,7 @@ var MarkdownEditor = React39.forwardRef(function MarkdownEditor2({
|
|
|
6551
6657
|
pendingCaret.current = null;
|
|
6552
6658
|
if (active && caret != null) placeCaret(root, caret);
|
|
6553
6659
|
}, [value]);
|
|
6554
|
-
|
|
6660
|
+
React40.useEffect(() => {
|
|
6555
6661
|
if (autoFocus && boxRef.current) boxRef.current.focus();
|
|
6556
6662
|
}, [autoFocus]);
|
|
6557
6663
|
const caretNow = () => {
|
|
@@ -6618,7 +6724,7 @@ var MarkdownEditor = React39.forwardRef(function MarkdownEditor2({
|
|
|
6618
6724
|
api.replaceRange(from, to, next, from + next.length);
|
|
6619
6725
|
}
|
|
6620
6726
|
};
|
|
6621
|
-
|
|
6727
|
+
React40.useImperativeHandle(ref, () => api);
|
|
6622
6728
|
function detect(text, caret) {
|
|
6623
6729
|
if (!onTrigger) return;
|
|
6624
6730
|
const upto = text.slice(0, caret);
|
|
@@ -6770,16 +6876,16 @@ var MarkdownEditor = React39.forwardRef(function MarkdownEditor2({
|
|
|
6770
6876
|
});
|
|
6771
6877
|
|
|
6772
6878
|
// src/components/platform/AccountMenu.tsx
|
|
6773
|
-
var
|
|
6879
|
+
var React42 = __toESM(require("react"), 1);
|
|
6774
6880
|
|
|
6775
6881
|
// src/kits/sessionContext.tsx
|
|
6776
|
-
var
|
|
6777
|
-
var SessionContext =
|
|
6882
|
+
var React41 = __toESM(require("react"), 1);
|
|
6883
|
+
var SessionContext = React41.createContext(null);
|
|
6778
6884
|
function SessionProvider({ value, children }) {
|
|
6779
|
-
return
|
|
6885
|
+
return React41.createElement(SessionContext.Provider, { value }, children);
|
|
6780
6886
|
}
|
|
6781
6887
|
function useSessionContext() {
|
|
6782
|
-
const ctx =
|
|
6888
|
+
const ctx = React41.useContext(SessionContext);
|
|
6783
6889
|
if (!ctx) {
|
|
6784
6890
|
throw new Error(
|
|
6785
6891
|
"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."
|
|
@@ -6819,11 +6925,11 @@ function AccountMenu({
|
|
|
6819
6925
|
...rest
|
|
6820
6926
|
}) {
|
|
6821
6927
|
const { user, roles, can: can2, signOut: ctxSignOut, demo } = useSessionContext();
|
|
6822
|
-
const [open, setOpen] =
|
|
6823
|
-
const [switching, setSwitching] =
|
|
6824
|
-
const [signingOut, setSigningOut] =
|
|
6825
|
-
const [signOutError, setSignOutError] =
|
|
6826
|
-
const ref =
|
|
6928
|
+
const [open, setOpen] = React42.useState(false);
|
|
6929
|
+
const [switching, setSwitching] = React42.useState(false);
|
|
6930
|
+
const [signingOut, setSigningOut] = React42.useState(false);
|
|
6931
|
+
const [signOutError, setSignOutError] = React42.useState(null);
|
|
6932
|
+
const ref = React42.useRef(null);
|
|
6827
6933
|
const visibleLinks = links.filter((l) => !l.perm || can2(l.perm));
|
|
6828
6934
|
const visibleGroups = groups.map((g) => ({ label: g.label, links: g.links.filter((l) => !l.perm || can2(l.perm)) })).filter((g) => g.links.length);
|
|
6829
6935
|
const closeMenu = () => {
|
|
@@ -6948,13 +7054,13 @@ function AccountMenu({
|
|
|
6948
7054
|
}
|
|
6949
7055
|
|
|
6950
7056
|
// src/components/platform/AppSwitcher.tsx
|
|
6951
|
-
var
|
|
7057
|
+
var React43 = __toESM(require("react"), 1);
|
|
6952
7058
|
var import_jsx_runtime71 = require("react/jsx-runtime");
|
|
6953
7059
|
function AppSwitcher({ apps: appsProp, onNavigate, className = "" }) {
|
|
6954
7060
|
const { apps: contextApps } = useSessionContext();
|
|
6955
7061
|
const apps = appsProp ?? contextApps ?? [];
|
|
6956
|
-
const [open, setOpen] =
|
|
6957
|
-
const anchorRef =
|
|
7062
|
+
const [open, setOpen] = React43.useState(false);
|
|
7063
|
+
const anchorRef = React43.useRef(null);
|
|
6958
7064
|
if (!apps.length) return null;
|
|
6959
7065
|
const items = apps.map((app) => ({
|
|
6960
7066
|
id: app.key,
|
|
@@ -6968,7 +7074,7 @@ function AppSwitcher({ apps: appsProp, onNavigate, className = "" }) {
|
|
|
6968
7074
|
window.location.href = app.url;
|
|
6969
7075
|
}
|
|
6970
7076
|
}));
|
|
6971
|
-
return /* @__PURE__ */ (0, import_jsx_runtime71.jsxs)(
|
|
7077
|
+
return /* @__PURE__ */ (0, import_jsx_runtime71.jsxs)(React43.Fragment, { children: [
|
|
6972
7078
|
/* @__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)(
|
|
6973
7079
|
IconButton,
|
|
6974
7080
|
{
|
|
@@ -6997,10 +7103,10 @@ function AppSwitcher({ apps: appsProp, onNavigate, className = "" }) {
|
|
|
6997
7103
|
}
|
|
6998
7104
|
|
|
6999
7105
|
// src/components/platform/AppearanceMenu.tsx
|
|
7000
|
-
var
|
|
7106
|
+
var React45 = __toESM(require("react"), 1);
|
|
7001
7107
|
|
|
7002
7108
|
// src/kits/appearance.ts
|
|
7003
|
-
var
|
|
7109
|
+
var React44 = __toESM(require("react"), 1);
|
|
7004
7110
|
var DEFAULT_STORAGE_KEY = "fd-appearance";
|
|
7005
7111
|
var DEFAULT_PREFS = {
|
|
7006
7112
|
theme: "system",
|
|
@@ -7095,11 +7201,11 @@ function applyPrefs(prefs, root = document.documentElement) {
|
|
|
7095
7201
|
else root.removeAttribute("data-motion");
|
|
7096
7202
|
}
|
|
7097
7203
|
function useAppearancePrefs(store) {
|
|
7098
|
-
const prefs =
|
|
7099
|
-
|
|
7204
|
+
const prefs = React44.useSyncExternalStore(store.subscribe, store.getSnapshot);
|
|
7205
|
+
React44.useEffect(() => {
|
|
7100
7206
|
applyPrefs(prefs);
|
|
7101
7207
|
}, [prefs]);
|
|
7102
|
-
|
|
7208
|
+
React44.useEffect(() => {
|
|
7103
7209
|
if (prefs.theme !== "system" || typeof window === "undefined" || typeof window.matchMedia !== "function") {
|
|
7104
7210
|
return;
|
|
7105
7211
|
}
|
|
@@ -7108,7 +7214,7 @@ function useAppearancePrefs(store) {
|
|
|
7108
7214
|
mq.addEventListener("change", onChange);
|
|
7109
7215
|
return () => mq.removeEventListener("change", onChange);
|
|
7110
7216
|
}, [prefs]);
|
|
7111
|
-
const update =
|
|
7217
|
+
const update = React44.useCallback(
|
|
7112
7218
|
(patch) => {
|
|
7113
7219
|
store.write({ ...store.getSnapshot(), ...patch });
|
|
7114
7220
|
},
|
|
@@ -7131,15 +7237,15 @@ var TEXT_SCALE_OPTIONS = [
|
|
|
7131
7237
|
{ value: "xl", label: "XL" }
|
|
7132
7238
|
];
|
|
7133
7239
|
function AppearanceMenu({ className = "", store: storeProp, storageKey, storage, defaults }) {
|
|
7134
|
-
const store =
|
|
7240
|
+
const store = React45.useMemo(
|
|
7135
7241
|
() => storeProp ?? createLocalStorageAppearanceStore({ storageKey, storage, defaults }),
|
|
7136
7242
|
[storeProp, storageKey, storage, defaults]
|
|
7137
7243
|
);
|
|
7138
7244
|
const [prefs, update] = useAppearancePrefs(store);
|
|
7139
|
-
const [open, setOpen] =
|
|
7140
|
-
const anchorRef =
|
|
7245
|
+
const [open, setOpen] = React45.useState(false);
|
|
7246
|
+
const anchorRef = React45.useRef(null);
|
|
7141
7247
|
const patch = (p) => update(p);
|
|
7142
|
-
return /* @__PURE__ */ (0, import_jsx_runtime72.jsxs)(
|
|
7248
|
+
return /* @__PURE__ */ (0, import_jsx_runtime72.jsxs)(React45.Fragment, { children: [
|
|
7143
7249
|
/* @__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)(
|
|
7144
7250
|
IconButton,
|
|
7145
7251
|
{
|
|
@@ -7208,14 +7314,14 @@ function AppearanceMenu({ className = "", store: storeProp, storageKey, storage,
|
|
|
7208
7314
|
}
|
|
7209
7315
|
|
|
7210
7316
|
// src/components/platform/ApiSpecBrowser.tsx
|
|
7211
|
-
var
|
|
7317
|
+
var React46 = __toESM(require("react"), 1);
|
|
7212
7318
|
var import_jsx_runtime73 = require("react/jsx-runtime");
|
|
7213
7319
|
var METHOD_TONE = { GET: "success", POST: "info", PATCH: "warning", PUT: "warning", DELETE: "danger" };
|
|
7214
7320
|
function Json({ obj }) {
|
|
7215
7321
|
return /* @__PURE__ */ (0, import_jsx_runtime73.jsx)("pre", { className: "fd-json", children: JSON.stringify(obj, null, 2) });
|
|
7216
7322
|
}
|
|
7217
7323
|
function Endpoint({ s, onRequest }) {
|
|
7218
|
-
const [tried, setTried] =
|
|
7324
|
+
const [tried, setTried] = React46.useState(null);
|
|
7219
7325
|
const run = async () => {
|
|
7220
7326
|
setTried("busy");
|
|
7221
7327
|
const t0 = (window.performance || Date).now();
|
|
@@ -7288,10 +7394,10 @@ function ApiSpecBrowser({
|
|
|
7288
7394
|
className = "",
|
|
7289
7395
|
...rest
|
|
7290
7396
|
}) {
|
|
7291
|
-
const [q, setQ] =
|
|
7292
|
-
const [method, setMethod] =
|
|
7293
|
-
const [mod, setMod] =
|
|
7294
|
-
const [listOnly, setListOnly] =
|
|
7397
|
+
const [q, setQ] = React46.useState("");
|
|
7398
|
+
const [method, setMethod] = React46.useState(null);
|
|
7399
|
+
const [mod, setMod] = React46.useState(null);
|
|
7400
|
+
const [listOnly, setListOnly] = React46.useState(false);
|
|
7295
7401
|
const activeModule = modules && modules.find((m) => m.id === mod);
|
|
7296
7402
|
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())));
|
|
7297
7403
|
const effGroups = groups && groups.length ? groups : [["All endpoints", spec.map((s) => s.id)]];
|
|
@@ -7370,7 +7476,7 @@ function ApiSpecBrowser({
|
|
|
7370
7476
|
}
|
|
7371
7477
|
|
|
7372
7478
|
// src/components/platform/ProfilePage.tsx
|
|
7373
|
-
var
|
|
7479
|
+
var React47 = __toESM(require("react"), 1);
|
|
7374
7480
|
var import_jsx_runtime74 = require("react/jsx-runtime");
|
|
7375
7481
|
function fieldInitialValue(field, user) {
|
|
7376
7482
|
if (field.value) return field.value(user);
|
|
@@ -7406,21 +7512,21 @@ function ProfilePage({
|
|
|
7406
7512
|
}) {
|
|
7407
7513
|
const { user: sessionUser, roles, permissions, saveProfile: saveProfile2 } = useSessionContext();
|
|
7408
7514
|
const user = userProp || sessionUser;
|
|
7409
|
-
const initialFieldValues =
|
|
7515
|
+
const initialFieldValues = React47.useMemo(() => {
|
|
7410
7516
|
const values2 = {};
|
|
7411
7517
|
for (const field of fields) values2[field.key] = fieldInitialValue(field, user);
|
|
7412
7518
|
return values2;
|
|
7413
7519
|
}, [user.id, fields]);
|
|
7414
|
-
const initialNotify =
|
|
7520
|
+
const initialNotify = React47.useMemo(() => {
|
|
7415
7521
|
const values2 = {};
|
|
7416
7522
|
for (const n of notifications) values2[n.key] = !!user.notify?.[n.key];
|
|
7417
7523
|
return values2;
|
|
7418
7524
|
}, [user.id, notifications]);
|
|
7419
|
-
const [values, setValues] =
|
|
7420
|
-
const [notify, setNotify] =
|
|
7421
|
-
const [saving, setSaving] =
|
|
7422
|
-
const [saved, setSaved] =
|
|
7423
|
-
const [prevUserId, setPrevUserId] =
|
|
7525
|
+
const [values, setValues] = React47.useState(initialFieldValues);
|
|
7526
|
+
const [notify, setNotify] = React47.useState(initialNotify);
|
|
7527
|
+
const [saving, setSaving] = React47.useState(false);
|
|
7528
|
+
const [saved, setSaved] = React47.useState(false);
|
|
7529
|
+
const [prevUserId, setPrevUserId] = React47.useState(user.id);
|
|
7424
7530
|
if (user.id !== prevUserId) {
|
|
7425
7531
|
setPrevUserId(user.id);
|
|
7426
7532
|
setValues(initialFieldValues);
|
|
@@ -7608,11 +7714,11 @@ function ProfilePage({
|
|
|
7608
7714
|
}
|
|
7609
7715
|
|
|
7610
7716
|
// src/components/platform/SignInPage.tsx
|
|
7611
|
-
var
|
|
7717
|
+
var React48 = __toESM(require("react"), 1);
|
|
7612
7718
|
var import_jsx_runtime75 = require("react/jsx-runtime");
|
|
7613
7719
|
function SignInPage({ productName, onSignIn, continueAs, error }) {
|
|
7614
|
-
const [signingIn, setSigningIn] =
|
|
7615
|
-
const [resuming, setResuming] =
|
|
7720
|
+
const [signingIn, setSigningIn] = React48.useState(false);
|
|
7721
|
+
const [resuming, setResuming] = React48.useState(false);
|
|
7616
7722
|
function handleSignIn() {
|
|
7617
7723
|
setSigningIn(true);
|
|
7618
7724
|
onSignIn();
|
|
@@ -7801,10 +7907,10 @@ function GoogleGlyph() {
|
|
|
7801
7907
|
}
|
|
7802
7908
|
|
|
7803
7909
|
// src/components/platform/RoadmapTimeline.tsx
|
|
7804
|
-
var
|
|
7910
|
+
var React51 = __toESM(require("react"), 1);
|
|
7805
7911
|
|
|
7806
7912
|
// src/kits/session.ts
|
|
7807
|
-
var
|
|
7913
|
+
var React49 = __toESM(require("react"), 1);
|
|
7808
7914
|
var PERMISSION_CATALOG = [
|
|
7809
7915
|
{ group: "Plans", items: [
|
|
7810
7916
|
{ key: "plan.view", label: "View plans", detail: "Read any plan in the workspace." },
|
|
@@ -9371,8 +9477,8 @@ function roadmap(overrides) {
|
|
|
9371
9477
|
};
|
|
9372
9478
|
}
|
|
9373
9479
|
function useSession() {
|
|
9374
|
-
const [s, setS] =
|
|
9375
|
-
|
|
9480
|
+
const [s, setS] = React49.useState(getSession);
|
|
9481
|
+
React49.useEffect(() => subscribe(setS), []);
|
|
9376
9482
|
return s;
|
|
9377
9483
|
}
|
|
9378
9484
|
var SessionKit = {
|
|
@@ -9405,7 +9511,7 @@ var SessionKit = {
|
|
|
9405
9511
|
};
|
|
9406
9512
|
function DemoSessionProvider({ children }) {
|
|
9407
9513
|
const session = useSession();
|
|
9408
|
-
const value =
|
|
9514
|
+
const value = React49.useMemo(
|
|
9409
9515
|
() => ({
|
|
9410
9516
|
user: session.user,
|
|
9411
9517
|
roles: session.roles,
|
|
@@ -9421,11 +9527,11 @@ function DemoSessionProvider({ children }) {
|
|
|
9421
9527
|
}),
|
|
9422
9528
|
[session]
|
|
9423
9529
|
);
|
|
9424
|
-
return
|
|
9530
|
+
return React49.createElement(SessionProvider, { value }, children);
|
|
9425
9531
|
}
|
|
9426
9532
|
|
|
9427
9533
|
// src/kits/runtime.ts
|
|
9428
|
-
var
|
|
9534
|
+
var React50 = __toESM(require("react"), 1);
|
|
9429
9535
|
var WIRED_ENDPOINTS = [
|
|
9430
9536
|
// Nothing yet. Every id below would come from a real service:
|
|
9431
9537
|
// "plan.get", "placements.list", …
|
|
@@ -9596,8 +9702,8 @@ var RuntimeKit = {
|
|
|
9596
9702
|
};
|
|
9597
9703
|
RuntimeKit.declare(FEATURE_NEEDS);
|
|
9598
9704
|
function useRuntimeMode() {
|
|
9599
|
-
const [m, setM] =
|
|
9600
|
-
|
|
9705
|
+
const [m, setM] = React50.useState(RuntimeKit.getMode());
|
|
9706
|
+
React50.useEffect(() => RuntimeKit.subscribe(setM), []);
|
|
9601
9707
|
return m;
|
|
9602
9708
|
}
|
|
9603
9709
|
function useFeatureStatus(key) {
|
|
@@ -9680,12 +9786,12 @@ function RoadmapCard({ item, byKey, onOpenFlag }) {
|
|
|
9680
9786
|
}
|
|
9681
9787
|
function RoadmapTimeline({ onOpenFlag, title = "Roadmap", lede }) {
|
|
9682
9788
|
const session = SessionKit.useSession();
|
|
9683
|
-
const [project, setProject] =
|
|
9684
|
-
const [q, setQ] =
|
|
9685
|
-
const scrollRef =
|
|
9686
|
-
const nowRef =
|
|
9687
|
-
const rm =
|
|
9688
|
-
const byKey =
|
|
9789
|
+
const [project, setProject] = React51.useState("");
|
|
9790
|
+
const [q, setQ] = React51.useState("");
|
|
9791
|
+
const scrollRef = React51.useRef(null);
|
|
9792
|
+
const nowRef = React51.useRef(null);
|
|
9793
|
+
const rm = React51.useMemo(() => SessionKit.roadmap({ isComplete: RuntimeKit.isComplete }), [session]);
|
|
9794
|
+
const byKey = React51.useMemo(() => {
|
|
9689
9795
|
const m = {};
|
|
9690
9796
|
rm.items.forEach((i) => {
|
|
9691
9797
|
m[i.key] = i;
|
|
@@ -9694,7 +9800,7 @@ function RoadmapTimeline({ onOpenFlag, title = "Roadmap", lede }) {
|
|
|
9694
9800
|
}, [rm]);
|
|
9695
9801
|
const items = rm.items.filter((i) => (!project || i.project === project) && (!q || (i.label + " " + i.description + " " + (i.backend || "") + " " + i.key).toLowerCase().includes(q.toLowerCase())));
|
|
9696
9802
|
const projects = [...new Set(rm.items.map((i) => i.project))];
|
|
9697
|
-
|
|
9803
|
+
React51.useEffect(() => {
|
|
9698
9804
|
let raf1 = 0, raf2 = 0;
|
|
9699
9805
|
const place = () => {
|
|
9700
9806
|
const box = scrollRef.current, mark = nowRef.current;
|
|
@@ -9768,7 +9874,7 @@ function RoadmapTimeline({ onOpenFlag, title = "Roadmap", lede }) {
|
|
|
9768
9874
|
lastPhase = item.phase;
|
|
9769
9875
|
const inPhase = items.filter((i) => i.phase === item.phase).length;
|
|
9770
9876
|
const isBoundary = n === firstPending;
|
|
9771
|
-
return /* @__PURE__ */ (0, import_jsx_runtime76.jsxs)(
|
|
9877
|
+
return /* @__PURE__ */ (0, import_jsx_runtime76.jsxs)(React51.Fragment, { children: [
|
|
9772
9878
|
showPhase ? /* @__PURE__ */ (0, import_jsx_runtime76.jsxs)("div", { className: "fd-rm-era", children: [
|
|
9773
9879
|
/* @__PURE__ */ (0, import_jsx_runtime76.jsxs)("span", { className: "fd-row", style: { gap: 8, flexWrap: "wrap", alignItems: "baseline" }, children: [
|
|
9774
9880
|
/* @__PURE__ */ (0, import_jsx_runtime76.jsx)("span", { style: { fontWeight: 700 }, children: item.phase === 0 ? "Shipped" : "Phase " + item.phase + " \u2014 " + item.phaseName }),
|
|
@@ -9812,7 +9918,7 @@ function RoadmapTimeline({ onOpenFlag, title = "Roadmap", lede }) {
|
|
|
9812
9918
|
}
|
|
9813
9919
|
|
|
9814
9920
|
// src/components/platform/ComingSoon.tsx
|
|
9815
|
-
var
|
|
9921
|
+
var React52 = __toESM(require("react"), 1);
|
|
9816
9922
|
var import_react_dom6 = require("react-dom");
|
|
9817
9923
|
var import_jsx_runtime77 = require("react/jsx-runtime");
|
|
9818
9924
|
var BYPASS_STORE = "fd.soon.bypass.v1";
|
|
@@ -9830,8 +9936,8 @@ function writeBypassed(list) {
|
|
|
9830
9936
|
}
|
|
9831
9937
|
}
|
|
9832
9938
|
function useBypass(key) {
|
|
9833
|
-
const [on, setOn] =
|
|
9834
|
-
|
|
9939
|
+
const [on, setOn] = React52.useState(() => !!key && readBypassed().indexOf(key) >= 0);
|
|
9940
|
+
React52.useEffect(() => {
|
|
9835
9941
|
setOn(!!key && readBypassed().indexOf(key) >= 0);
|
|
9836
9942
|
}, [key]);
|
|
9837
9943
|
const set = (next) => {
|
|
@@ -9878,9 +9984,9 @@ function SoonCard({ label, detail, backend, eta, effort, onRoadmap, allowed, onB
|
|
|
9878
9984
|
] });
|
|
9879
9985
|
}
|
|
9880
9986
|
function useHoverCard(open) {
|
|
9881
|
-
const anchor =
|
|
9882
|
-
const [pos, setPos] =
|
|
9883
|
-
|
|
9987
|
+
const anchor = React52.useRef(null);
|
|
9988
|
+
const [pos, setPos] = React52.useState(null);
|
|
9989
|
+
React52.useLayoutEffect(() => {
|
|
9884
9990
|
if (!open || !anchor.current) {
|
|
9885
9991
|
setPos(null);
|
|
9886
9992
|
return;
|
|
@@ -10007,10 +10113,10 @@ function ComingSoon({
|
|
|
10007
10113
|
] });
|
|
10008
10114
|
}
|
|
10009
10115
|
function InlineSoon({ label, detail, backend, eta, effort, onRoadmap, allowed, onBypass, blur, tip, className, rest, children }) {
|
|
10010
|
-
const [open, setOpen] =
|
|
10116
|
+
const [open, setOpen] = React52.useState(false);
|
|
10011
10117
|
const [anchor, pos] = useHoverCard(open);
|
|
10012
10118
|
const zIndex = useOverlayLayer(open);
|
|
10013
|
-
const close =
|
|
10119
|
+
const close = React52.useRef(null);
|
|
10014
10120
|
const show = () => {
|
|
10015
10121
|
if (close.current) {
|
|
10016
10122
|
clearTimeout(close.current);
|
|
@@ -10026,7 +10132,7 @@ function InlineSoon({ label, detail, backend, eta, effort, onRoadmap, allowed, o
|
|
|
10026
10132
|
setOpen(false);
|
|
10027
10133
|
}, 140);
|
|
10028
10134
|
};
|
|
10029
|
-
|
|
10135
|
+
React52.useEffect(() => () => {
|
|
10030
10136
|
if (close.current) clearTimeout(close.current);
|
|
10031
10137
|
}, []);
|
|
10032
10138
|
return /* @__PURE__ */ (0, import_jsx_runtime77.jsxs)(
|
|
@@ -10197,14 +10303,14 @@ function PermissionHint({ perm, children }) {
|
|
|
10197
10303
|
}
|
|
10198
10304
|
|
|
10199
10305
|
// src/components/platform/ModeSwitch.tsx
|
|
10200
|
-
var
|
|
10306
|
+
var React53 = __toESM(require("react"), 1);
|
|
10201
10307
|
var import_jsx_runtime79 = require("react/jsx-runtime");
|
|
10202
10308
|
function ModeSwitch({ canToggle = false, requestCount = 0, onClearLog, renderLog, onOpenSpec, summary }) {
|
|
10203
10309
|
const mode2 = useRuntimeMode();
|
|
10204
|
-
const [open, setOpen] =
|
|
10310
|
+
const [open, setOpen] = React53.useState(false);
|
|
10205
10311
|
const zIndex = useOverlayLayer(open);
|
|
10206
|
-
const ref =
|
|
10207
|
-
|
|
10312
|
+
const ref = React53.useRef(null);
|
|
10313
|
+
React53.useEffect(() => {
|
|
10208
10314
|
if (!open) return;
|
|
10209
10315
|
const away = (e) => {
|
|
10210
10316
|
if (ref.current && !ref.current.contains(e.target)) setOpen(false);
|
|
@@ -10460,7 +10566,7 @@ function SaturationDistribution({ campuses = [], floorBand, floorScore, onSelect
|
|
|
10460
10566
|
}
|
|
10461
10567
|
|
|
10462
10568
|
// src/components/planner/MixGap.tsx
|
|
10463
|
-
var
|
|
10569
|
+
var React54 = __toESM(require("react"), 1);
|
|
10464
10570
|
var import_jsx_runtime82 = require("react/jsx-runtime");
|
|
10465
10571
|
var MIX_GAP_LAYOUT = {
|
|
10466
10572
|
trackHeight: 30,
|
|
@@ -10475,7 +10581,7 @@ function mixGapOffset(value, max) {
|
|
|
10475
10581
|
}
|
|
10476
10582
|
function MixGap({ rows = [], loading = false, className = "" }) {
|
|
10477
10583
|
const max = Math.max(1, ...rows.flatMap((r) => [r.target, r.realized]));
|
|
10478
|
-
const [hover, setHover] =
|
|
10584
|
+
const [hover, setHover] = React54.useState(null);
|
|
10479
10585
|
const toneOf = (gap) => gap >= -1 ? "ok" : gap >= -4 ? "warn" : "danger";
|
|
10480
10586
|
const TONE = { ok: "var(--ok-solid)", warn: "var(--warn-solid)", danger: "var(--danger-solid)" };
|
|
10481
10587
|
const { trackHeight, barHeight, targetWidth, labelGap } = MIX_GAP_LAYOUT;
|
|
@@ -10618,7 +10724,7 @@ function ChannelContribution({
|
|
|
10618
10724
|
}
|
|
10619
10725
|
|
|
10620
10726
|
// src/components/planner/BudgetReallocator.tsx
|
|
10621
|
-
var
|
|
10727
|
+
var React55 = __toESM(require("react"), 1);
|
|
10622
10728
|
var import_jsx_runtime84 = require("react/jsx-runtime");
|
|
10623
10729
|
var bandFor = (crp) => crp >= 200 ? "dominant" : crp >= 100 ? "strong" : crp >= 50 ? "adequate" : "weak";
|
|
10624
10730
|
function BudgetReallocator({
|
|
@@ -10634,8 +10740,8 @@ function BudgetReallocator({
|
|
|
10634
10740
|
onCancel,
|
|
10635
10741
|
className = ""
|
|
10636
10742
|
}) {
|
|
10637
|
-
const [draft, setDraft] =
|
|
10638
|
-
|
|
10743
|
+
const [draft, setDraft] = React55.useState(spend);
|
|
10744
|
+
React55.useEffect(() => setDraft(spend), [spend]);
|
|
10639
10745
|
const dirty = draft !== spend;
|
|
10640
10746
|
const nextCrp = scoreFor ? scoreFor(draft) : crp;
|
|
10641
10747
|
const nextBand = bandFor(nextCrp);
|
|
@@ -10650,10 +10756,10 @@ function BudgetReallocator({
|
|
|
10650
10756
|
setDraft(spend);
|
|
10651
10757
|
if (onCancel) onCancel();
|
|
10652
10758
|
};
|
|
10653
|
-
const trackRef =
|
|
10654
|
-
const chipRef =
|
|
10655
|
-
const [chipLeft, setChipLeft] =
|
|
10656
|
-
|
|
10759
|
+
const trackRef = React55.useRef(null);
|
|
10760
|
+
const chipRef = React55.useRef(null);
|
|
10761
|
+
const [chipLeft, setChipLeft] = React55.useState(null);
|
|
10762
|
+
React55.useLayoutEffect(() => {
|
|
10657
10763
|
const track = trackRef.current;
|
|
10658
10764
|
if (!dirty || !track) {
|
|
10659
10765
|
setChipLeft(null);
|
|
@@ -10840,7 +10946,7 @@ function ImportanceTag({ level, showLabel = true, size = "sm", className = "" })
|
|
|
10840
10946
|
}
|
|
10841
10947
|
|
|
10842
10948
|
// src/components/planner/PreferenceMeter.tsx
|
|
10843
|
-
var
|
|
10949
|
+
var React56 = __toESM(require("react"), 1);
|
|
10844
10950
|
var import_jsx_runtime87 = require("react/jsx-runtime");
|
|
10845
10951
|
function preferenceScore(criteria) {
|
|
10846
10952
|
const earned = criteria.reduce((n, c) => n + (Number(c.earned) || 0), 0);
|
|
@@ -10870,7 +10976,7 @@ function PreferenceMeter({
|
|
|
10870
10976
|
className = ""
|
|
10871
10977
|
}) {
|
|
10872
10978
|
const value = score == null ? preferenceScore(criteria) : score;
|
|
10873
|
-
const segments =
|
|
10979
|
+
const segments = React56.useMemo(() => preferenceSegments(criteria), [criteria]);
|
|
10874
10980
|
return /* @__PURE__ */ (0, import_jsx_runtime87.jsx)(
|
|
10875
10981
|
ScoreMeter,
|
|
10876
10982
|
{
|
|
@@ -10909,10 +11015,10 @@ function PreferenceMeter({
|
|
|
10909
11015
|
}
|
|
10910
11016
|
|
|
10911
11017
|
// src/components/chat/AgentChatPanel.tsx
|
|
10912
|
-
var
|
|
11018
|
+
var React62 = __toESM(require("react"), 1);
|
|
10913
11019
|
|
|
10914
11020
|
// src/components/chat/chatEngine.ts
|
|
10915
|
-
var
|
|
11021
|
+
var React57 = __toESM(require("react"), 1);
|
|
10916
11022
|
var CHAT_UNAVAILABLE = "chat_unavailable";
|
|
10917
11023
|
var JOB_PENDING = ["queued", "running"];
|
|
10918
11024
|
var JOB_SUCCESS = ["completed", "recovered"];
|
|
@@ -10966,22 +11072,22 @@ function useChatEngine(opts) {
|
|
|
10966
11072
|
onClear,
|
|
10967
11073
|
onFeedback
|
|
10968
11074
|
} = opts || {};
|
|
10969
|
-
const [status, setStatus] =
|
|
10970
|
-
const [threadId, setThreadId] =
|
|
10971
|
-
const [messages, setMessages] =
|
|
10972
|
-
const [queue, setQueue] =
|
|
10973
|
-
const [fatal, setFatal] =
|
|
10974
|
-
const [busy, setBusy] =
|
|
10975
|
-
const [turnStartedAt, setTurnStartedAt] =
|
|
10976
|
-
const listRef =
|
|
10977
|
-
const queueRef =
|
|
10978
|
-
const busyRef =
|
|
10979
|
-
const stoppedRef =
|
|
10980
|
-
const abortRef =
|
|
10981
|
-
const serverCount =
|
|
10982
|
-
const threadRef =
|
|
10983
|
-
const mounted =
|
|
10984
|
-
|
|
11075
|
+
const [status, setStatus] = React57.useState("idle");
|
|
11076
|
+
const [threadId, setThreadId] = React57.useState(null);
|
|
11077
|
+
const [messages, setMessages] = React57.useState([]);
|
|
11078
|
+
const [queue, setQueue] = React57.useState([]);
|
|
11079
|
+
const [fatal, setFatal] = React57.useState(null);
|
|
11080
|
+
const [busy, setBusy] = React57.useState(false);
|
|
11081
|
+
const [turnStartedAt, setTurnStartedAt] = React57.useState(null);
|
|
11082
|
+
const listRef = React57.useRef([]);
|
|
11083
|
+
const queueRef = React57.useRef([]);
|
|
11084
|
+
const busyRef = React57.useRef(false);
|
|
11085
|
+
const stoppedRef = React57.useRef(false);
|
|
11086
|
+
const abortRef = React57.useRef(null);
|
|
11087
|
+
const serverCount = React57.useRef(0);
|
|
11088
|
+
const threadRef = React57.useRef(null);
|
|
11089
|
+
const mounted = React57.useRef(true);
|
|
11090
|
+
React57.useEffect(() => {
|
|
10985
11091
|
mounted.current = true;
|
|
10986
11092
|
return () => {
|
|
10987
11093
|
mounted.current = false;
|
|
@@ -11003,14 +11109,14 @@ function useChatEngine(opts) {
|
|
|
11003
11109
|
}
|
|
11004
11110
|
return false;
|
|
11005
11111
|
};
|
|
11006
|
-
const loadThread =
|
|
11112
|
+
const loadThread = React57.useCallback(async (id) => {
|
|
11007
11113
|
const data = await apiAdapter.getThread(id);
|
|
11008
11114
|
const list = [...data && data.messages || []];
|
|
11009
11115
|
serverCount.current = list.length;
|
|
11010
11116
|
commit(list);
|
|
11011
11117
|
return list;
|
|
11012
11118
|
}, [apiAdapter]);
|
|
11013
|
-
|
|
11119
|
+
React57.useEffect(() => {
|
|
11014
11120
|
if (!apiAdapter) {
|
|
11015
11121
|
setStatus("idle");
|
|
11016
11122
|
setFatal(null);
|
|
@@ -11223,7 +11329,7 @@ function useChatEngine(opts) {
|
|
|
11223
11329
|
await dispatchTurn(turn);
|
|
11224
11330
|
}
|
|
11225
11331
|
}
|
|
11226
|
-
const send =
|
|
11332
|
+
const send = React57.useCallback((text, attachments) => {
|
|
11227
11333
|
const body = (text || "").trim();
|
|
11228
11334
|
if (!body && !(attachments && attachments.length)) return;
|
|
11229
11335
|
if (status === "disconnected") return;
|
|
@@ -11233,7 +11339,7 @@ function useChatEngine(opts) {
|
|
|
11233
11339
|
stoppedRef.current = false;
|
|
11234
11340
|
drain();
|
|
11235
11341
|
}, [status]);
|
|
11236
|
-
const stop =
|
|
11342
|
+
const stop = React57.useCallback(() => {
|
|
11237
11343
|
stoppedRef.current = true;
|
|
11238
11344
|
const ac = abortRef.current;
|
|
11239
11345
|
if (ac) {
|
|
@@ -11252,11 +11358,11 @@ function useChatEngine(opts) {
|
|
|
11252
11358
|
store.del(STORAGE_PREFIX + threadRef.current);
|
|
11253
11359
|
}
|
|
11254
11360
|
}, [apiAdapter]);
|
|
11255
|
-
const removeQueued =
|
|
11361
|
+
const removeQueued = React57.useCallback((id) => {
|
|
11256
11362
|
queueRef.current = queueRef.current.filter((t) => t.id !== id);
|
|
11257
11363
|
setQueue(queueRef.current.slice());
|
|
11258
11364
|
}, []);
|
|
11259
|
-
const retry =
|
|
11365
|
+
const retry = React57.useCallback(() => {
|
|
11260
11366
|
const list = listRef.current;
|
|
11261
11367
|
let at = -1;
|
|
11262
11368
|
for (let i = list.length - 1; i >= 0; i--) if (list[i].role === "user") {
|
|
@@ -11272,19 +11378,19 @@ function useChatEngine(opts) {
|
|
|
11272
11378
|
setQueue(queueRef.current.slice());
|
|
11273
11379
|
drain();
|
|
11274
11380
|
}, []);
|
|
11275
|
-
const clear =
|
|
11381
|
+
const clear = React57.useCallback(() => {
|
|
11276
11382
|
commit([]);
|
|
11277
11383
|
serverCount.current = 0;
|
|
11278
11384
|
queueRef.current = [];
|
|
11279
11385
|
setQueue([]);
|
|
11280
11386
|
onClear && onClear();
|
|
11281
11387
|
}, [onClear]);
|
|
11282
|
-
const setFeedback =
|
|
11388
|
+
const setFeedback = React57.useCallback((id, value) => {
|
|
11283
11389
|
patch(id, (m) => ({ feedback: m.feedback === value ? null : value }));
|
|
11284
11390
|
const msg = listRef.current.find((m) => m.id === id);
|
|
11285
11391
|
onFeedback && onFeedback({ message: msg, feedback: msg ? msg.feedback : value });
|
|
11286
11392
|
}, [onFeedback]);
|
|
11287
|
-
const reload =
|
|
11393
|
+
const reload = React57.useCallback(async () => {
|
|
11288
11394
|
if (!threadRef.current) return;
|
|
11289
11395
|
setStatus("loading");
|
|
11290
11396
|
try {
|
|
@@ -11322,10 +11428,10 @@ var ChatKit = {
|
|
|
11322
11428
|
};
|
|
11323
11429
|
|
|
11324
11430
|
// src/components/chat/ChatTranscript.tsx
|
|
11325
|
-
var
|
|
11431
|
+
var React59 = __toESM(require("react"), 1);
|
|
11326
11432
|
|
|
11327
11433
|
// src/components/chat/ChatTurn.tsx
|
|
11328
|
-
var
|
|
11434
|
+
var React58 = __toESM(require("react"), 1);
|
|
11329
11435
|
var import_jsx_runtime88 = require("react/jsx-runtime");
|
|
11330
11436
|
function JsonView({ value }) {
|
|
11331
11437
|
let text;
|
|
@@ -11362,7 +11468,7 @@ function PacketCard({ packet, schema, render, onApply, applied }) {
|
|
|
11362
11468
|
] });
|
|
11363
11469
|
}
|
|
11364
11470
|
function ThinkingBlock({ text, durationMs, streaming, defaultOpen = false }) {
|
|
11365
|
-
const [open, setOpen] =
|
|
11471
|
+
const [open, setOpen] = React58.useState(defaultOpen);
|
|
11366
11472
|
if (!text) return null;
|
|
11367
11473
|
return /* @__PURE__ */ (0, import_jsx_runtime88.jsxs)("div", { className: "fdc-think" + (open ? " is-open" : ""), children: [
|
|
11368
11474
|
/* @__PURE__ */ (0, import_jsx_runtime88.jsxs)("button", { type: "button", className: "fdc-think-head", onClick: () => setOpen((v) => !v), "aria-expanded": open, children: [
|
|
@@ -11379,7 +11485,7 @@ function ThinkingBlock({ text, durationMs, streaming, defaultOpen = false }) {
|
|
|
11379
11485
|
] });
|
|
11380
11486
|
}
|
|
11381
11487
|
function Citations({ items = [], onOpen }) {
|
|
11382
|
-
const [open, setOpen] =
|
|
11488
|
+
const [open, setOpen] = React58.useState(false);
|
|
11383
11489
|
if (!items.length) return null;
|
|
11384
11490
|
return /* @__PURE__ */ (0, import_jsx_runtime88.jsxs)("div", { className: "fdc-cites", children: [
|
|
11385
11491
|
/* @__PURE__ */ (0, import_jsx_runtime88.jsxs)("button", { type: "button", className: "fdc-cites-head", onClick: () => setOpen((v) => !v), "aria-expanded": open, children: [
|
|
@@ -11405,7 +11511,7 @@ function clampText(text, max) {
|
|
|
11405
11511
|
return (at > max * 0.6 ? cut.slice(0, at) : cut).trimEnd() + "\u2026";
|
|
11406
11512
|
}
|
|
11407
11513
|
function MessageBody({ message: m, ctx }) {
|
|
11408
|
-
const [expanded, setExpanded] =
|
|
11514
|
+
const [expanded, setExpanded] = React58.useState(false);
|
|
11409
11515
|
const isUser = m.role === "user";
|
|
11410
11516
|
const raw = m.text || "";
|
|
11411
11517
|
const clamped = !expanded && !m.streaming ? clampText(raw, ctx.maxVisibleChars) : null;
|
|
@@ -11472,9 +11578,9 @@ function MessageBody({ message: m, ctx }) {
|
|
|
11472
11578
|
] });
|
|
11473
11579
|
}
|
|
11474
11580
|
function useCopyRun() {
|
|
11475
|
-
const [done, setDone] =
|
|
11476
|
-
const t =
|
|
11477
|
-
|
|
11581
|
+
const [done, setDone] = React58.useState(false);
|
|
11582
|
+
const t = React58.useRef(null);
|
|
11583
|
+
React58.useEffect(() => () => {
|
|
11478
11584
|
if (t.current) clearTimeout(t.current);
|
|
11479
11585
|
}, []);
|
|
11480
11586
|
return [done, (text) => {
|
|
@@ -11501,7 +11607,7 @@ function RunActions({ group, ctx }) {
|
|
|
11501
11607
|
] }),
|
|
11502
11608
|
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,
|
|
11503
11609
|
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,
|
|
11504
|
-
isAssistant && ctx.onFeedback ? /* @__PURE__ */ (0, import_jsx_runtime88.jsxs)(
|
|
11610
|
+
isAssistant && ctx.onFeedback ? /* @__PURE__ */ (0, import_jsx_runtime88.jsxs)(React58.Fragment, { children: [
|
|
11505
11611
|
/* @__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" }) }),
|
|
11506
11612
|
/* @__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" }) })
|
|
11507
11613
|
] }) : null,
|
|
@@ -11596,10 +11702,10 @@ function ChatTranscript({
|
|
|
11596
11702
|
renderEmpty,
|
|
11597
11703
|
className = ""
|
|
11598
11704
|
}) {
|
|
11599
|
-
const scroller =
|
|
11600
|
-
const stick =
|
|
11601
|
-
const [pill, setPill] =
|
|
11602
|
-
const seen =
|
|
11705
|
+
const scroller = React59.useRef(null);
|
|
11706
|
+
const stick = React59.useRef(true);
|
|
11707
|
+
const [pill, setPill] = React59.useState(0);
|
|
11708
|
+
const seen = React59.useRef(0);
|
|
11603
11709
|
const toBottom = (smooth) => {
|
|
11604
11710
|
const el = scroller.current;
|
|
11605
11711
|
if (!el) return;
|
|
@@ -11618,7 +11724,7 @@ function ChatTranscript({
|
|
|
11618
11724
|
seen.current = messages.length;
|
|
11619
11725
|
}
|
|
11620
11726
|
};
|
|
11621
|
-
|
|
11727
|
+
React59.useLayoutEffect(() => {
|
|
11622
11728
|
const el = scroller.current;
|
|
11623
11729
|
if (!el) return;
|
|
11624
11730
|
if (stick.current) {
|
|
@@ -11626,7 +11732,7 @@ function ChatTranscript({
|
|
|
11626
11732
|
seen.current = messages.length;
|
|
11627
11733
|
} else setPill(Math.max(0, messages.length - seen.current));
|
|
11628
11734
|
}, [messages]);
|
|
11629
|
-
|
|
11735
|
+
React59.useEffect(() => {
|
|
11630
11736
|
const el = scroller.current;
|
|
11631
11737
|
const inner = el && el.firstChild;
|
|
11632
11738
|
if (!el || !inner || typeof ResizeObserver === "undefined") return;
|
|
@@ -11636,7 +11742,7 @@ function ChatTranscript({
|
|
|
11636
11742
|
ro.observe(inner);
|
|
11637
11743
|
return () => ro.disconnect();
|
|
11638
11744
|
}, []);
|
|
11639
|
-
const groups =
|
|
11745
|
+
const groups = React59.useMemo(() => groupMessages(messages), [messages]);
|
|
11640
11746
|
const empty = !messages.length && status === "ready";
|
|
11641
11747
|
return /* @__PURE__ */ (0, import_jsx_runtime89.jsxs)("div", { className: ["fdc-scroll", className].filter(Boolean).join(" "), ref: scroller, onScroll, children: [
|
|
11642
11748
|
/* @__PURE__ */ (0, import_jsx_runtime89.jsxs)("div", { className: "fdc-log", role: "log", "aria-label": "Conversation", children: [
|
|
@@ -11660,7 +11766,7 @@ function ChatTranscript({
|
|
|
11660
11766
|
const prev = groups[i - 1];
|
|
11661
11767
|
const k = dayKey(g.messages[0].timestamp);
|
|
11662
11768
|
const showDay = !!k && (!prev || dayKey(prev.messages[0].timestamp) !== k);
|
|
11663
|
-
return /* @__PURE__ */ (0, import_jsx_runtime89.jsxs)(
|
|
11769
|
+
return /* @__PURE__ */ (0, import_jsx_runtime89.jsxs)(React59.Fragment, { children: [
|
|
11664
11770
|
showDay ? /* @__PURE__ */ (0, import_jsx_runtime89.jsx)("div", { className: "fdc-day", children: /* @__PURE__ */ (0, import_jsx_runtime89.jsx)("span", { children: dayLabel(k) }) }) : null,
|
|
11665
11771
|
/* @__PURE__ */ (0, import_jsx_runtime89.jsx)(ChatTurn, { group: g, ctx })
|
|
11666
11772
|
] }, g.key || i);
|
|
@@ -11677,7 +11783,7 @@ function ChatTranscript({
|
|
|
11677
11783
|
var TranscriptKit = { groupMessages };
|
|
11678
11784
|
|
|
11679
11785
|
// src/components/chat/ChatComposer.tsx
|
|
11680
|
-
var
|
|
11786
|
+
var React60 = __toESM(require("react"), 1);
|
|
11681
11787
|
var import_jsx_runtime90 = require("react/jsx-runtime");
|
|
11682
11788
|
function ChatComposer({
|
|
11683
11789
|
onSubmit,
|
|
@@ -11705,17 +11811,17 @@ function ChatComposer({
|
|
|
11705
11811
|
onReject,
|
|
11706
11812
|
onOpenAttachment
|
|
11707
11813
|
}) {
|
|
11708
|
-
const [text, setText] =
|
|
11709
|
-
const [trigger, setTrigger] =
|
|
11710
|
-
const [mentionItems, setMentionItems] =
|
|
11711
|
-
const [listening, setListening] =
|
|
11712
|
-
const [notice, setNotice] =
|
|
11713
|
-
const editor =
|
|
11714
|
-
const wrap =
|
|
11715
|
-
const stopVoice =
|
|
11814
|
+
const [text, setText] = React60.useState(draft || "");
|
|
11815
|
+
const [trigger, setTrigger] = React60.useState(null);
|
|
11816
|
+
const [mentionItems, setMentionItems] = React60.useState([]);
|
|
11817
|
+
const [listening, setListening] = React60.useState(false);
|
|
11818
|
+
const [notice, setNotice] = React60.useState(null);
|
|
11819
|
+
const editor = React60.useRef(null);
|
|
11820
|
+
const wrap = React60.useRef(null);
|
|
11821
|
+
const stopVoice = React60.useRef(null);
|
|
11716
11822
|
const staged = useStagedFiles(fileUploadHandler, { onError: () => {
|
|
11717
11823
|
} });
|
|
11718
|
-
|
|
11824
|
+
React60.useEffect(() => {
|
|
11719
11825
|
if (draft != null && draft !== text) setText(draft);
|
|
11720
11826
|
}, [draft]);
|
|
11721
11827
|
const change = (v) => {
|
|
@@ -11751,7 +11857,7 @@ function ChatComposer({
|
|
|
11751
11857
|
e.preventDefault();
|
|
11752
11858
|
staged.add(found.files);
|
|
11753
11859
|
};
|
|
11754
|
-
|
|
11860
|
+
React60.useEffect(() => {
|
|
11755
11861
|
if (!trigger || trigger.type !== "mention" || !mentionSources) {
|
|
11756
11862
|
setMentionItems([]);
|
|
11757
11863
|
return;
|
|
@@ -11769,7 +11875,7 @@ function ChatComposer({
|
|
|
11769
11875
|
const q = (trigger.query || "").toLowerCase();
|
|
11770
11876
|
setMentionItems(mentionSources.filter((m) => !q || (m.label + " " + (m.description || "")).toLowerCase().includes(q)));
|
|
11771
11877
|
}, [trigger, mentionSources]);
|
|
11772
|
-
const slashItems =
|
|
11878
|
+
const slashItems = React60.useMemo(() => {
|
|
11773
11879
|
if (!trigger || trigger.type !== "slash" || !slashCommands) return [];
|
|
11774
11880
|
const q = (trigger.query || "").toLowerCase();
|
|
11775
11881
|
return slashCommands.filter((c) => !q || (c.id + " " + c.label + " " + (c.description || "")).toLowerCase().includes(q));
|
|
@@ -11943,12 +12049,12 @@ function ChatComposer({
|
|
|
11943
12049
|
}
|
|
11944
12050
|
|
|
11945
12051
|
// src/components/chat/ChatSessionBar.tsx
|
|
11946
|
-
var
|
|
12052
|
+
var React61 = __toESM(require("react"), 1);
|
|
11947
12053
|
var import_jsx_runtime91 = require("react/jsx-runtime");
|
|
11948
12054
|
var compact2 = meterFormats.compact;
|
|
11949
12055
|
function ChatSessionBar({ sessionStats, contextUsage, usageLimits, onClear, extras }) {
|
|
11950
|
-
const [open, setOpen] =
|
|
11951
|
-
const anchor =
|
|
12056
|
+
const [open, setOpen] = React61.useState(false);
|
|
12057
|
+
const anchor = React61.useRef(null);
|
|
11952
12058
|
const stats = sessionStats || null;
|
|
11953
12059
|
const cu = contextUsage || null;
|
|
11954
12060
|
const limits = usageLimits || null;
|
|
@@ -11963,7 +12069,7 @@ function ChatSessionBar({ sessionStats, contextUsage, usageLimits, onClear, extr
|
|
|
11963
12069
|
if (stats && stats.runningTasks) bits.push(stats.runningTasks + " running task" + (stats.runningTasks === 1 ? "" : "s"));
|
|
11964
12070
|
if (cu) bits.push(pct + "% context");
|
|
11965
12071
|
const expandable = !!(cu || limits);
|
|
11966
|
-
return /* @__PURE__ */ (0, import_jsx_runtime91.jsxs)(
|
|
12072
|
+
return /* @__PURE__ */ (0, import_jsx_runtime91.jsxs)(React61.Fragment, { children: [
|
|
11967
12073
|
/* @__PURE__ */ (0, import_jsx_runtime91.jsxs)("div", { className: "fdc-bar", children: [
|
|
11968
12074
|
/* @__PURE__ */ (0, import_jsx_runtime91.jsxs)(
|
|
11969
12075
|
"button",
|
|
@@ -12104,7 +12210,7 @@ function ModelControls({
|
|
|
12104
12210
|
] })
|
|
12105
12211
|
});
|
|
12106
12212
|
}
|
|
12107
|
-
return /* @__PURE__ */ (0, import_jsx_runtime91.jsxs)(
|
|
12213
|
+
return /* @__PURE__ */ (0, import_jsx_runtime91.jsxs)(React61.Fragment, { children: [
|
|
12108
12214
|
/* @__PURE__ */ (0, import_jsx_runtime91.jsx)(
|
|
12109
12215
|
MenuButton,
|
|
12110
12216
|
{
|
|
@@ -12221,11 +12327,11 @@ function AgentChatPanel({
|
|
|
12221
12327
|
onFeedback,
|
|
12222
12328
|
onEditMessage
|
|
12223
12329
|
}) {
|
|
12224
|
-
const [panelWidth, setPanelWidth] =
|
|
12225
|
-
const [applied, setApplied] =
|
|
12226
|
-
const [draft, setDraft] =
|
|
12227
|
-
const dragging =
|
|
12228
|
-
|
|
12330
|
+
const [panelWidth, setPanelWidth] = React62.useState(width);
|
|
12331
|
+
const [applied, setApplied] = React62.useState({});
|
|
12332
|
+
const [draft, setDraft] = React62.useState("");
|
|
12333
|
+
const dragging = React62.useRef(null);
|
|
12334
|
+
React62.useEffect(() => setPanelWidth(width), [width]);
|
|
12229
12335
|
const engine = useChatEngine({
|
|
12230
12336
|
contextType,
|
|
12231
12337
|
contextId,
|
|
@@ -12429,7 +12535,7 @@ function AgentChatPanel({
|
|
|
12429
12535
|
}
|
|
12430
12536
|
|
|
12431
12537
|
// src/components/files/FileViewer.tsx
|
|
12432
|
-
var
|
|
12538
|
+
var React63 = __toESM(require("react"), 1);
|
|
12433
12539
|
var import_jsx_runtime93 = require("react/jsx-runtime");
|
|
12434
12540
|
function previewKindOf(file) {
|
|
12435
12541
|
const mime = (file.mime || "").toLowerCase();
|
|
@@ -12486,13 +12592,13 @@ function parseDelimited(text, delimiter) {
|
|
|
12486
12592
|
return rows;
|
|
12487
12593
|
}
|
|
12488
12594
|
function usePreview(file, kind, resolveUrl) {
|
|
12489
|
-
const [state, setState] =
|
|
12490
|
-
const [attempt, setAttempt] =
|
|
12491
|
-
const resolveRef =
|
|
12492
|
-
|
|
12595
|
+
const [state, setState] = React63.useState({ status: "loading" });
|
|
12596
|
+
const [attempt, setAttempt] = React63.useState(0);
|
|
12597
|
+
const resolveRef = React63.useRef(resolveUrl);
|
|
12598
|
+
React63.useEffect(() => {
|
|
12493
12599
|
resolveRef.current = resolveUrl;
|
|
12494
12600
|
}, [resolveUrl]);
|
|
12495
|
-
|
|
12601
|
+
React63.useEffect(() => {
|
|
12496
12602
|
if (kind === "none") {
|
|
12497
12603
|
setState({ status: "ready" });
|
|
12498
12604
|
return;
|
|
@@ -12522,7 +12628,7 @@ function usePreview(file, kind, resolveUrl) {
|
|
|
12522
12628
|
if (ac) ac.abort();
|
|
12523
12629
|
};
|
|
12524
12630
|
}, [file.id, kind, attempt]);
|
|
12525
|
-
return { ...state, retry:
|
|
12631
|
+
return { ...state, retry: React63.useCallback(() => setAttempt((a) => a + 1), []) };
|
|
12526
12632
|
}
|
|
12527
12633
|
function PreviewBody({ file, kind, state }) {
|
|
12528
12634
|
if (kind === "image") return /* @__PURE__ */ (0, import_jsx_runtime93.jsx)("img", { className: "fd-fv-image", src: state.url, alt: file.name || "Preview" });
|
|
@@ -12567,13 +12673,13 @@ function PreviewBody({ file, kind, state }) {
|
|
|
12567
12673
|
] });
|
|
12568
12674
|
}
|
|
12569
12675
|
function FileViewer({ file, resolveUrl, sidePanel, sidePanelLabel = "Details", onClose, actions, className = "" }) {
|
|
12570
|
-
const kind =
|
|
12676
|
+
const kind = React63.useMemo(() => previewKindOf(file), [file]);
|
|
12571
12677
|
const preview = usePreview(file, kind, resolveUrl);
|
|
12572
|
-
const [tab, setTab] =
|
|
12573
|
-
const [downloading, setDownloading] =
|
|
12574
|
-
const [downloadError, setDownloadError] =
|
|
12678
|
+
const [tab, setTab] = React63.useState("preview");
|
|
12679
|
+
const [downloading, setDownloading] = React63.useState(false);
|
|
12680
|
+
const [downloadError, setDownloadError] = React63.useState(null);
|
|
12575
12681
|
const hasSide = sidePanel != null;
|
|
12576
|
-
|
|
12682
|
+
React63.useEffect(() => {
|
|
12577
12683
|
setTab("preview");
|
|
12578
12684
|
}, [file.id]);
|
|
12579
12685
|
const download = () => {
|
|
@@ -12640,7 +12746,7 @@ function FileViewer({ file, resolveUrl, sidePanel, sidePanelLabel = "Details", o
|
|
|
12640
12746
|
}
|
|
12641
12747
|
|
|
12642
12748
|
// src/components/files/FileBrowser.tsx
|
|
12643
|
-
var
|
|
12749
|
+
var React64 = __toESM(require("react"), 1);
|
|
12644
12750
|
var import_jsx_runtime94 = require("react/jsx-runtime");
|
|
12645
12751
|
function childrenOf(folders, parentId) {
|
|
12646
12752
|
return folders.filter((f) => f.parentId === parentId).sort((a, b) => a.name.localeCompare(b.name));
|
|
@@ -12711,10 +12817,10 @@ function FolderPickerMenu({
|
|
|
12711
12817
|
destinations,
|
|
12712
12818
|
onPick
|
|
12713
12819
|
}) {
|
|
12714
|
-
const [open, setOpen] =
|
|
12820
|
+
const [open, setOpen] = React64.useState(false);
|
|
12715
12821
|
const zIndex = useOverlayLayer(open);
|
|
12716
|
-
const ref =
|
|
12717
|
-
|
|
12822
|
+
const ref = React64.useRef(null);
|
|
12823
|
+
React64.useEffect(() => {
|
|
12718
12824
|
if (!open) return;
|
|
12719
12825
|
const away = (e) => {
|
|
12720
12826
|
if (ref.current && !ref.current.contains(e.target)) setOpen(false);
|
|
@@ -12766,8 +12872,8 @@ function FolderPickerMenu({
|
|
|
12766
12872
|
] });
|
|
12767
12873
|
}
|
|
12768
12874
|
function RowShell({ icon, name, meta, onOpen, draggableId, isDropTarget, onDropPayload, actions, className = "" }) {
|
|
12769
|
-
const [over, setOver] =
|
|
12770
|
-
const dragCounter =
|
|
12875
|
+
const [over, setOver] = React64.useState(false);
|
|
12876
|
+
const dragCounter = React64.useRef(0);
|
|
12771
12877
|
const dropHandlers = isDropTarget ? {
|
|
12772
12878
|
onDragEnter: (e) => {
|
|
12773
12879
|
if (!hasInternalPayload(e)) return;
|
|
@@ -12815,8 +12921,8 @@ function RowShell({ icon, name, meta, onOpen, draggableId, isDropTarget, onDropP
|
|
|
12815
12921
|
}
|
|
12816
12922
|
function TreeNode({ folder, depth, folders, currentFolderId, onNavigate, onMoveInto, canMove }) {
|
|
12817
12923
|
const kids = childrenOf(folders, folder.id);
|
|
12818
|
-
const [expanded, setExpanded] =
|
|
12819
|
-
|
|
12924
|
+
const [expanded, setExpanded] = React64.useState(() => currentFolderId != null && isSelfOrDescendant(folders, folder.id, currentFolderId));
|
|
12925
|
+
React64.useEffect(() => {
|
|
12820
12926
|
if (currentFolderId != null && isSelfOrDescendant(folders, folder.id, currentFolderId)) setExpanded(true);
|
|
12821
12927
|
}, [currentFolderId, folder.id, folders]);
|
|
12822
12928
|
const isCurrent = folder.id === currentFolderId;
|
|
@@ -12882,15 +12988,15 @@ function FileBrowser({
|
|
|
12882
12988
|
const canUpload = perm.canUpload !== false && !!onUpload;
|
|
12883
12989
|
const canRemoveFile = perm.canRemoveFile !== false && !!onRemoveFile;
|
|
12884
12990
|
const canDeleteFolder = perm.canDeleteFolder !== false && !!onDeleteFolder;
|
|
12885
|
-
const [createOpen, setCreateOpen] =
|
|
12886
|
-
const [createName, setCreateName] =
|
|
12887
|
-
const [renameTarget, setRenameTarget] =
|
|
12888
|
-
const [renameValue, setRenameValue] =
|
|
12889
|
-
const [deleteTarget, setDeleteTarget] =
|
|
12890
|
-
const uploadInputRef =
|
|
12891
|
-
const crumbFolders =
|
|
12892
|
-
const subfolders =
|
|
12893
|
-
const currentFiles =
|
|
12991
|
+
const [createOpen, setCreateOpen] = React64.useState(false);
|
|
12992
|
+
const [createName, setCreateName] = React64.useState("");
|
|
12993
|
+
const [renameTarget, setRenameTarget] = React64.useState(null);
|
|
12994
|
+
const [renameValue, setRenameValue] = React64.useState("");
|
|
12995
|
+
const [deleteTarget, setDeleteTarget] = React64.useState(null);
|
|
12996
|
+
const uploadInputRef = React64.useRef(null);
|
|
12997
|
+
const crumbFolders = React64.useMemo(() => ancestorsOf(folders, currentFolderId), [folders, currentFolderId]);
|
|
12998
|
+
const subfolders = React64.useMemo(() => childrenOf(folders, currentFolderId), [folders, currentFolderId]);
|
|
12999
|
+
const currentFiles = React64.useMemo(
|
|
12894
13000
|
() => files.filter((f) => f.folderId === currentFolderId).sort((a, b) => a.name.localeCompare(b.name)),
|
|
12895
13001
|
[files, currentFolderId]
|
|
12896
13002
|
);
|
|
@@ -13122,8 +13228,8 @@ function BreadcrumbCrumb({
|
|
|
13122
13228
|
isDropTarget,
|
|
13123
13229
|
onDropPayload
|
|
13124
13230
|
}) {
|
|
13125
|
-
const [over, setOver] =
|
|
13126
|
-
const dragCounter =
|
|
13231
|
+
const [over, setOver] = React64.useState(false);
|
|
13232
|
+
const dragCounter = React64.useRef(0);
|
|
13127
13233
|
const dropHandlers = isDropTarget ? {
|
|
13128
13234
|
onDragEnter: (e) => {
|
|
13129
13235
|
if (!hasInternalPayload(e)) return;
|
|
@@ -13152,9 +13258,27 @@ function BreadcrumbCrumb({
|
|
|
13152
13258
|
}
|
|
13153
13259
|
|
|
13154
13260
|
// src/kits/query.ts
|
|
13155
|
-
var
|
|
13261
|
+
var React65 = __toESM(require("react"), 1);
|
|
13262
|
+
var isMultiSelectShaped = (v) => !!v && typeof v === "object" && Array.isArray(v.values);
|
|
13263
|
+
var isRangeShaped = (v) => !!v && typeof v === "object" && ("min" in v || "max" in v);
|
|
13264
|
+
var isDateShaped = (v) => !!v && typeof v === "object" && "kind" in v;
|
|
13265
|
+
function isActiveFilterValue(v) {
|
|
13266
|
+
if (v == null || v === "" || v === false) return false;
|
|
13267
|
+
if (Array.isArray(v)) return v.length > 0;
|
|
13268
|
+
if (isMultiSelectShaped(v)) return v.values.length > 0;
|
|
13269
|
+
if (isRangeShaped(v)) return v.min != null || v.max != null;
|
|
13270
|
+
if (isDateShaped(v)) return v.kind === "withinDays" ? v.days != null : !!(v.from && v.to);
|
|
13271
|
+
return true;
|
|
13272
|
+
}
|
|
13156
13273
|
function eqFilter(get2) {
|
|
13157
|
-
return (row, value) =>
|
|
13274
|
+
return (row, value) => {
|
|
13275
|
+
if (Array.isArray(value)) return value.includes(get2(row));
|
|
13276
|
+
if (isMultiSelectShaped(value)) {
|
|
13277
|
+
const hit = value.values.some((o) => o.value === get2(row));
|
|
13278
|
+
return value.operator === "notIn" ? !hit : hit;
|
|
13279
|
+
}
|
|
13280
|
+
return get2(row) === value;
|
|
13281
|
+
};
|
|
13158
13282
|
}
|
|
13159
13283
|
function anyOfFilter(get2) {
|
|
13160
13284
|
return (row, value) => {
|
|
@@ -13165,10 +13289,15 @@ function anyOfFilter(get2) {
|
|
|
13165
13289
|
function rangeFilter(get2) {
|
|
13166
13290
|
return (row, value) => {
|
|
13167
13291
|
const n = get2(row);
|
|
13168
|
-
|
|
13169
|
-
|
|
13170
|
-
|
|
13171
|
-
|
|
13292
|
+
let lo = 0;
|
|
13293
|
+
let hi = Number.POSITIVE_INFINITY;
|
|
13294
|
+
if (Array.isArray(value)) {
|
|
13295
|
+
lo = Number(value[0] ?? 0);
|
|
13296
|
+
hi = value[1] == null ? Number.POSITIVE_INFINITY : Number(value[1]);
|
|
13297
|
+
} else if (isRangeShaped(value)) {
|
|
13298
|
+
lo = value.min ?? 0;
|
|
13299
|
+
hi = value.max ?? Number.POSITIVE_INFINITY;
|
|
13300
|
+
}
|
|
13172
13301
|
return n >= lo && (hi === Number.POSITIVE_INFINITY || n <= hi);
|
|
13173
13302
|
};
|
|
13174
13303
|
}
|
|
@@ -13184,22 +13313,22 @@ function compare(a, b, dir) {
|
|
|
13184
13313
|
var API = null;
|
|
13185
13314
|
var PREFS = null;
|
|
13186
13315
|
function useServerTable({ endpoint, params, defaults, deps, prefsKey }) {
|
|
13187
|
-
const [query, setQuery] =
|
|
13316
|
+
const [query, setQuery] = React65.useState(() => {
|
|
13188
13317
|
const store = PREFS || window.PlannerPrefs;
|
|
13189
13318
|
const saved = prefsKey && store ? store.getTable(prefsKey) : {};
|
|
13190
13319
|
return { ...DEFAULTS, ...defaults || {}, ...saved.pageSize ? { pageSize: saved.pageSize } : {}, ...saved.sort ? { sort: saved.sort, dir: saved.dir || "desc" } : {} };
|
|
13191
13320
|
});
|
|
13192
|
-
const savePref =
|
|
13321
|
+
const savePref = React65.useCallback((patch2) => {
|
|
13193
13322
|
const store = PREFS || window.PlannerPrefs;
|
|
13194
13323
|
if (prefsKey && store) store.setTable(prefsKey, patch2);
|
|
13195
13324
|
}, [prefsKey]);
|
|
13196
|
-
const [res, setRes] =
|
|
13197
|
-
const [loading, setLoading] =
|
|
13198
|
-
const seq2 =
|
|
13325
|
+
const [res, setRes] = React65.useState(null);
|
|
13326
|
+
const [loading, setLoading] = React65.useState(true);
|
|
13327
|
+
const seq2 = React65.useRef(0);
|
|
13199
13328
|
const depKey = (deps || []).join("|");
|
|
13200
13329
|
const paramKey = JSON.stringify(params || {});
|
|
13201
13330
|
const queryKey = JSON.stringify(query);
|
|
13202
|
-
|
|
13331
|
+
React65.useEffect(() => {
|
|
13203
13332
|
const id = ++seq2.current;
|
|
13204
13333
|
setLoading(true);
|
|
13205
13334
|
const t = setTimeout(() => {
|
|
@@ -13235,7 +13364,7 @@ function useServerTable({ endpoint, params, defaults, deps, prefsKey }) {
|
|
|
13235
13364
|
loading,
|
|
13236
13365
|
/** True only on the very first load — later loads keep showing stale rows. */
|
|
13237
13366
|
initialLoading: loading && !res,
|
|
13238
|
-
activeFilterCount: Object.values(query.filters).filter(
|
|
13367
|
+
activeFilterCount: Object.values(query.filters).filter(isActiveFilterValue).length,
|
|
13239
13368
|
setPage: (page) => patch({ page }, false),
|
|
13240
13369
|
setPageSize: (pageSize) => {
|
|
13241
13370
|
savePref({ pageSize });
|
|
@@ -13298,7 +13427,6 @@ var QueryKit = {
|
|
|
13298
13427
|
const Q = { ...DEFAULTS, ...query || {} };
|
|
13299
13428
|
const c = cfg;
|
|
13300
13429
|
const filters = Q.filters || {};
|
|
13301
|
-
const active = (v) => !(v == null || v === "" || v === false || Array.isArray(v) && !v.length);
|
|
13302
13430
|
let out = rows;
|
|
13303
13431
|
const term = (Q.q || "").trim().toLowerCase();
|
|
13304
13432
|
if (term && c.searchKeys) {
|
|
@@ -13308,7 +13436,7 @@ var QueryKit = {
|
|
|
13308
13436
|
const searched = out;
|
|
13309
13437
|
Object.entries(filters).forEach(([id, val]) => {
|
|
13310
13438
|
const fn = c.filters && c.filters[id];
|
|
13311
|
-
if (!
|
|
13439
|
+
if (!isActiveFilterValue(val) || !fn) return;
|
|
13312
13440
|
out = out.filter((r) => fn(r, val));
|
|
13313
13441
|
});
|
|
13314
13442
|
const matched = out;
|
|
@@ -13355,9 +13483,30 @@ var QueryKit = {
|
|
|
13355
13483
|
if (Q.sort) parts.push("sort=" + Q.sort + "&dir=" + Q.dir);
|
|
13356
13484
|
if (Q.q) parts.push("q=" + encodeURIComponent(Q.q));
|
|
13357
13485
|
Object.entries(Q.filters || {}).forEach(([k, v]) => {
|
|
13358
|
-
if (
|
|
13359
|
-
if (Array.isArray(v))
|
|
13360
|
-
|
|
13486
|
+
if (!isActiveFilterValue(v)) return;
|
|
13487
|
+
if (Array.isArray(v)) {
|
|
13488
|
+
v.forEach((x) => parts.push(k + "=" + encodeURIComponent(x === Infinity ? "*" : x)));
|
|
13489
|
+
return;
|
|
13490
|
+
}
|
|
13491
|
+
if (isMultiSelectShaped(v)) {
|
|
13492
|
+
const prefix = v.operator === "notIn" ? "notIn:" : "";
|
|
13493
|
+
v.values.forEach((o) => parts.push(k + "=" + encodeURIComponent(prefix + String(o.value))));
|
|
13494
|
+
return;
|
|
13495
|
+
}
|
|
13496
|
+
if (isRangeShaped(v)) {
|
|
13497
|
+
if (v.min != null) parts.push(k + ".min=" + encodeURIComponent(String(v.min)));
|
|
13498
|
+
if (v.max != null) parts.push(k + ".max=" + encodeURIComponent(String(v.max)));
|
|
13499
|
+
return;
|
|
13500
|
+
}
|
|
13501
|
+
if (isDateShaped(v)) {
|
|
13502
|
+
if (v.kind === "withinDays") parts.push(k + "=withinDays:" + encodeURIComponent(String(v.days)));
|
|
13503
|
+
else {
|
|
13504
|
+
parts.push(k + ".from=" + encodeURIComponent(String(v.from)));
|
|
13505
|
+
parts.push(k + ".to=" + encodeURIComponent(String(v.to)));
|
|
13506
|
+
}
|
|
13507
|
+
return;
|
|
13508
|
+
}
|
|
13509
|
+
parts.push(k + "=" + encodeURIComponent(v));
|
|
13361
13510
|
});
|
|
13362
13511
|
return parts.join("&");
|
|
13363
13512
|
},
|
|
@@ -13498,12 +13647,12 @@ function createVersionStore(initialState, options) {
|
|
|
13498
13647
|
}
|
|
13499
13648
|
|
|
13500
13649
|
// src/kits/documentTitle.ts
|
|
13501
|
-
var
|
|
13650
|
+
var React66 = __toESM(require("react"), 1);
|
|
13502
13651
|
function formatDocumentTitle(routeTitle, appName) {
|
|
13503
13652
|
return [routeTitle, appName, "Flytedesk"].filter((part) => !!part && part.length > 0).join(" \xB7 ");
|
|
13504
13653
|
}
|
|
13505
13654
|
function useDocumentTitle(routeTitle, appName) {
|
|
13506
|
-
|
|
13655
|
+
React66.useEffect(() => {
|
|
13507
13656
|
if (typeof document === "undefined") return;
|
|
13508
13657
|
document.title = formatDocumentTitle(routeTitle, appName);
|
|
13509
13658
|
}, [routeTitle, appName]);
|