@flytedan/flytebot-design-system 0.28.0 → 0.29.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 +869 -753
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +74 -50
- package/dist/index.d.ts +74 -50
- package/dist/index.js +869 -753
- 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" || tone === "warn" ? "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,8 +3018,11 @@ 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
|
};
|
|
3008
3028
|
const [text, setText] = React21.useState(value == null || value === "" ? "" : String(value));
|
|
@@ -3055,9 +3075,15 @@ function NumberInput({
|
|
|
3055
3075
|
disabled,
|
|
3056
3076
|
placeholder,
|
|
3057
3077
|
value: shown,
|
|
3078
|
+
"aria-invalid": error ? "true" : void 0,
|
|
3079
|
+
"aria-describedby": error ? errorId : void 0,
|
|
3058
3080
|
onFocus: () => setEditing(true),
|
|
3059
3081
|
onBlur: () => {
|
|
3060
3082
|
setEditing(false);
|
|
3083
|
+
if (text.trim() === "") {
|
|
3084
|
+
fire(void 0);
|
|
3085
|
+
return;
|
|
3086
|
+
}
|
|
3061
3087
|
const n = num(text);
|
|
3062
3088
|
if (n != null) {
|
|
3063
3089
|
const c = clamp(n);
|
|
@@ -3067,6 +3093,10 @@ function NumberInput({
|
|
|
3067
3093
|
},
|
|
3068
3094
|
onChange: (e) => {
|
|
3069
3095
|
setText(e.target.value);
|
|
3096
|
+
if (e.target.value.trim() === "") {
|
|
3097
|
+
fire(void 0);
|
|
3098
|
+
return;
|
|
3099
|
+
}
|
|
3070
3100
|
const n = num(e.target.value);
|
|
3071
3101
|
if (n != null) fire(n);
|
|
3072
3102
|
},
|
|
@@ -3111,7 +3141,7 @@ function NumberInput({
|
|
|
3111
3141
|
)
|
|
3112
3142
|
] })
|
|
3113
3143
|
] }),
|
|
3114
|
-
error ? /* @__PURE__ */ (0, import_jsx_runtime42.jsxs)("span", { className: "fd-field-error", children: [
|
|
3144
|
+
error ? /* @__PURE__ */ (0, import_jsx_runtime42.jsxs)("span", { id: errorId, className: "fd-field-error", children: [
|
|
3115
3145
|
/* @__PURE__ */ (0, import_jsx_runtime42.jsx)("i", { className: "ph ph-warning-circle", "aria-hidden": "true" }),
|
|
3116
3146
|
error
|
|
3117
3147
|
] }) : help ? /* @__PURE__ */ (0, import_jsx_runtime42.jsx)("span", { className: "fd-field-help", children: help }) : null
|
|
@@ -3335,16 +3365,48 @@ function Textarea({ label, help, error, required = false, rows = 4, disabled = f
|
|
|
3335
3365
|
] });
|
|
3336
3366
|
}
|
|
3337
3367
|
|
|
3368
|
+
// src/components/forms/listbox.ts
|
|
3369
|
+
var React23 = __toESM(require("react"), 1);
|
|
3370
|
+
function useListboxNav({ count, onSelect }) {
|
|
3371
|
+
const [active, setActive] = React23.useState(-1);
|
|
3372
|
+
return {
|
|
3373
|
+
active,
|
|
3374
|
+
setActive,
|
|
3375
|
+
move: (dir) => setActive((a) => Math.min(count - 1, Math.max(0, a + dir))),
|
|
3376
|
+
first: () => setActive(0),
|
|
3377
|
+
last: () => setActive(count - 1),
|
|
3378
|
+
activate: () => {
|
|
3379
|
+
if (active >= 0 && active < count) onSelect(active);
|
|
3380
|
+
}
|
|
3381
|
+
};
|
|
3382
|
+
}
|
|
3383
|
+
function useListboxScrollIntoView(active, listRef, enabled) {
|
|
3384
|
+
React23.useEffect(() => {
|
|
3385
|
+
if (!enabled || active < 0 || !listRef.current) return;
|
|
3386
|
+
const list = listRef.current;
|
|
3387
|
+
const el = list.querySelector('[data-i="' + active + '"]');
|
|
3388
|
+
if (!el) return;
|
|
3389
|
+
const top = el.offsetTop - list.offsetTop;
|
|
3390
|
+
if (top < list.scrollTop) list.scrollTop = top - 4;
|
|
3391
|
+
else if (top + el.offsetHeight > list.scrollTop + list.clientHeight) {
|
|
3392
|
+
list.scrollTop = top + el.offsetHeight - list.clientHeight + 4;
|
|
3393
|
+
}
|
|
3394
|
+
}, [active, enabled]);
|
|
3395
|
+
}
|
|
3396
|
+
|
|
3338
3397
|
// src/components/data/FilterBar.tsx
|
|
3339
3398
|
var import_jsx_runtime45 = require("react/jsx-runtime");
|
|
3399
|
+
var PANEL_WIDTH = { multiSelect: 280, range: 240, date: 300 };
|
|
3340
3400
|
var isSet = (v) => !(v == null || v === "" || v === false);
|
|
3401
|
+
function operatorsFor(field) {
|
|
3402
|
+
return field.operators && field.operators.length ? field.operators : ["in", "notIn"];
|
|
3403
|
+
}
|
|
3341
3404
|
function isFieldSet(field, value) {
|
|
3342
3405
|
switch (field.type) {
|
|
3343
3406
|
case "text":
|
|
3344
3407
|
case "select":
|
|
3345
3408
|
return isSet(value);
|
|
3346
|
-
case "multiSelect":
|
|
3347
|
-
case "pasteList": {
|
|
3409
|
+
case "multiSelect": {
|
|
3348
3410
|
const v = value;
|
|
3349
3411
|
return !!v && Array.isArray(v.values) && v.values.length > 0;
|
|
3350
3412
|
}
|
|
@@ -3355,7 +3417,7 @@ function isFieldSet(field, value) {
|
|
|
3355
3417
|
case "date": {
|
|
3356
3418
|
const v = value;
|
|
3357
3419
|
if (!v) return false;
|
|
3358
|
-
return v.kind === "withinDays" ? v.days != null : !!(v.from
|
|
3420
|
+
return v.kind === "withinDays" ? v.days != null : !!(v.from && v.to);
|
|
3359
3421
|
}
|
|
3360
3422
|
}
|
|
3361
3423
|
}
|
|
@@ -3367,8 +3429,7 @@ function chipLabel(field, value) {
|
|
|
3367
3429
|
const chosen = field.options.find((o) => o.value === value);
|
|
3368
3430
|
return chosen ? chosen.label : String(value ?? "");
|
|
3369
3431
|
}
|
|
3370
|
-
case "multiSelect":
|
|
3371
|
-
case "pasteList": {
|
|
3432
|
+
case "multiSelect": {
|
|
3372
3433
|
const v = value;
|
|
3373
3434
|
if (!v || !v.values.length) return "";
|
|
3374
3435
|
const prefix = v.operator === "notIn" ? "Not " : "";
|
|
@@ -3386,7 +3447,7 @@ function chipLabel(field, value) {
|
|
|
3386
3447
|
const v = value;
|
|
3387
3448
|
if (!v) return "";
|
|
3388
3449
|
if (v.kind === "withinDays") return "Last " + v.days + " day" + (v.days === 1 ? "" : "s");
|
|
3389
|
-
return
|
|
3450
|
+
return v.from + " \u2192 " + v.to;
|
|
3390
3451
|
}
|
|
3391
3452
|
}
|
|
3392
3453
|
}
|
|
@@ -3408,338 +3469,374 @@ function OperatorToggle({
|
|
|
3408
3469
|
}
|
|
3409
3470
|
);
|
|
3410
3471
|
}
|
|
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
3472
|
function MultiSelectPanel({
|
|
3435
3473
|
field,
|
|
3436
3474
|
value,
|
|
3475
|
+
anchorRef,
|
|
3437
3476
|
onChange,
|
|
3477
|
+
onRemove,
|
|
3438
3478
|
onClose
|
|
3439
3479
|
}) {
|
|
3440
|
-
const
|
|
3480
|
+
const allowedOps = operatorsFor(field);
|
|
3481
|
+
const operator = allowedOps.length === 1 ? allowedOps[0] : value?.operator ?? allowedOps[0];
|
|
3441
3482
|
const selected = value?.values ?? [];
|
|
3442
|
-
const
|
|
3443
|
-
|
|
3444
|
-
const
|
|
3445
|
-
|
|
3446
|
-
|
|
3447
|
-
|
|
3448
|
-
|
|
3483
|
+
const selectedRef = React24.useRef(selected);
|
|
3484
|
+
selectedRef.current = selected;
|
|
3485
|
+
const commit = (nextValues, nextOperator = operator) => {
|
|
3486
|
+
if (nextValues.length === 0) onRemove();
|
|
3487
|
+
else onChange({ operator: nextOperator, values: nextValues });
|
|
3488
|
+
};
|
|
3489
|
+
const [mode2, setMode] = React24.useState("search");
|
|
3490
|
+
const [query, setQuery] = React24.useState("");
|
|
3491
|
+
const [asyncState, setAsyncState] = React24.useState(
|
|
3492
|
+
{ options: null, loading: !!field.loadOptions, error: false }
|
|
3493
|
+
);
|
|
3494
|
+
const [retryTick, setRetryTick] = React24.useState(0);
|
|
3495
|
+
const inputRef = React24.useRef(null);
|
|
3496
|
+
const listRef = React24.useRef(null);
|
|
3497
|
+
const listId = React24.useId();
|
|
3498
|
+
const loadOptionsRef = React24.useRef(field.loadOptions);
|
|
3499
|
+
loadOptionsRef.current = field.loadOptions;
|
|
3500
|
+
React24.useEffect(() => {
|
|
3449
3501
|
inputRef.current?.focus();
|
|
3450
3502
|
}, []);
|
|
3451
|
-
|
|
3452
|
-
|
|
3453
|
-
|
|
3454
|
-
|
|
3455
|
-
|
|
3503
|
+
React24.useEffect(() => {
|
|
3504
|
+
const load = loadOptionsRef.current;
|
|
3505
|
+
if (!load) return;
|
|
3506
|
+
const controller = new AbortController();
|
|
3507
|
+
setAsyncState((s) => ({ options: s.options, loading: true, error: false }));
|
|
3456
3508
|
const t = setTimeout(() => {
|
|
3457
|
-
|
|
3458
|
-
if (
|
|
3459
|
-
|
|
3460
|
-
|
|
3461
|
-
|
|
3462
|
-
|
|
3463
|
-
if (!cancelled) {
|
|
3464
|
-
setAsyncOptions([]);
|
|
3465
|
-
setLoading(false);
|
|
3466
|
-
}
|
|
3509
|
+
load(query, controller.signal).then((opts) => {
|
|
3510
|
+
if (controller.signal.aborted) return;
|
|
3511
|
+
setAsyncState({ options: opts, loading: false, error: false });
|
|
3512
|
+
}).catch((err) => {
|
|
3513
|
+
if (controller.signal.aborted || err && err.name === "AbortError") return;
|
|
3514
|
+
setAsyncState({ options: null, loading: false, error: true });
|
|
3467
3515
|
});
|
|
3468
3516
|
}, 300);
|
|
3469
3517
|
return () => {
|
|
3470
|
-
cancelled = true;
|
|
3471
3518
|
clearTimeout(t);
|
|
3519
|
+
controller.abort();
|
|
3472
3520
|
};
|
|
3473
|
-
}, [query,
|
|
3474
|
-
const options = field.loadOptions ?
|
|
3475
|
-
|
|
3476
|
-
|
|
3477
|
-
|
|
3521
|
+
}, [query, retryTick]);
|
|
3522
|
+
const options = field.loadOptions ? asyncState.options ?? [] : (field.options ?? []).filter((o) => o.label.toLowerCase().includes(query.toLowerCase()));
|
|
3523
|
+
const showLoading = !!field.loadOptions && asyncState.loading;
|
|
3524
|
+
const showError = !!field.loadOptions && asyncState.error;
|
|
3525
|
+
const showListbox = !showLoading && !showError;
|
|
3478
3526
|
const isSelected = (o) => selected.some((s) => s.value === o.value);
|
|
3479
3527
|
const toggle = (o) => {
|
|
3480
3528
|
const next = isSelected(o) ? selected.filter((s) => s.value !== o.value) : [...selected, o];
|
|
3481
|
-
|
|
3529
|
+
commit(next);
|
|
3530
|
+
};
|
|
3531
|
+
const nav = useListboxNav({ count: options.length, onSelect: (i) => toggle(options[i]) });
|
|
3532
|
+
useListboxScrollIntoView(nav.active, listRef, showListbox);
|
|
3533
|
+
React24.useEffect(() => {
|
|
3534
|
+
nav.setActive(0);
|
|
3535
|
+
}, [query, options.length]);
|
|
3536
|
+
const activeId = showListbox && options[nav.active] ? listId + "-opt-" + nav.active : void 0;
|
|
3537
|
+
const [pasteText, setPasteText] = React24.useState("");
|
|
3538
|
+
const [pasteLoading, setPasteLoading] = React24.useState(false);
|
|
3539
|
+
const [unmatchedTokens, setUnmatchedTokens] = React24.useState([]);
|
|
3540
|
+
const [pasteError, setPasteError] = React24.useState(null);
|
|
3541
|
+
const pasteWrapRef = React24.useRef(null);
|
|
3542
|
+
React24.useEffect(() => {
|
|
3543
|
+
if (mode2 === "paste") pasteWrapRef.current?.querySelector("textarea")?.focus();
|
|
3544
|
+
}, [mode2]);
|
|
3545
|
+
const doResolve = () => {
|
|
3546
|
+
if (!field.resolve) return;
|
|
3547
|
+
const tokens = Array.from(new Set(pasteText.split(/[\n,]/).map((t) => t.trim()).filter(Boolean)));
|
|
3548
|
+
if (!tokens.length) return;
|
|
3549
|
+
setPasteLoading(true);
|
|
3550
|
+
setPasteError(null);
|
|
3551
|
+
field.resolve(tokens).then((result) => {
|
|
3552
|
+
setPasteLoading(false);
|
|
3553
|
+
setUnmatchedTokens(result.unmatched);
|
|
3554
|
+
const merged = new Map(selectedRef.current.map((s) => [s.value, s]));
|
|
3555
|
+
for (const m of result.matched) merged.set(m.value, { value: m.value, label: m.label });
|
|
3556
|
+
commit(Array.from(merged.values()));
|
|
3557
|
+
setPasteText("");
|
|
3558
|
+
}).catch((err) => {
|
|
3559
|
+
setPasteLoading(false);
|
|
3560
|
+
setPasteError(err instanceof Error ? err.message : "Could not resolve the pasted list.");
|
|
3561
|
+
});
|
|
3482
3562
|
};
|
|
3483
|
-
const
|
|
3484
|
-
|
|
3485
|
-
/* @__PURE__ */ (0, import_jsx_runtime45.jsx)(
|
|
3563
|
+
const header = /* @__PURE__ */ (0, import_jsx_runtime45.jsxs)("span", { className: "fd-stack fd-gap-sm", children: [
|
|
3564
|
+
allowedOps.length > 1 ? /* @__PURE__ */ (0, import_jsx_runtime45.jsx)(OperatorToggle, { operator, onChange: (op) => commit(selected, op), label: field.label }) : null,
|
|
3565
|
+
field.resolve ? /* @__PURE__ */ (0, import_jsx_runtime45.jsx)(
|
|
3566
|
+
SegmentedControl,
|
|
3567
|
+
{
|
|
3568
|
+
"aria-label": field.label + " \u2014 search or paste a list",
|
|
3569
|
+
options: [{ value: "search", label: "Search" }, { value: "paste", label: "Paste a list" }],
|
|
3570
|
+
value: mode2,
|
|
3571
|
+
onChange: (m) => setMode(m)
|
|
3572
|
+
}
|
|
3573
|
+
) : null,
|
|
3574
|
+
mode2 === "search" ? /* @__PURE__ */ (0, import_jsx_runtime45.jsxs)("span", { className: "fd-pop-search", children: [
|
|
3575
|
+
/* @__PURE__ */ (0, import_jsx_runtime45.jsx)("i", { className: "ph ph-magnifying-glass", "aria-hidden": "true" }),
|
|
3576
|
+
/* @__PURE__ */ (0, import_jsx_runtime45.jsx)(
|
|
3577
|
+
"input",
|
|
3578
|
+
{
|
|
3579
|
+
ref: inputRef,
|
|
3580
|
+
role: "combobox",
|
|
3581
|
+
"aria-expanded": showListbox,
|
|
3582
|
+
"aria-controls": showListbox ? listId : void 0,
|
|
3583
|
+
"aria-autocomplete": "list",
|
|
3584
|
+
"aria-activedescendant": activeId,
|
|
3585
|
+
"aria-label": field.label,
|
|
3586
|
+
value: query,
|
|
3587
|
+
placeholder: field.placeholder || "Search\u2026",
|
|
3588
|
+
onChange: (e) => setQuery(e.target.value),
|
|
3589
|
+
onKeyDown: (e) => {
|
|
3590
|
+
if (e.key === "ArrowDown") {
|
|
3591
|
+
e.preventDefault();
|
|
3592
|
+
nav.move(1);
|
|
3593
|
+
} else if (e.key === "ArrowUp") {
|
|
3594
|
+
e.preventDefault();
|
|
3595
|
+
nav.move(-1);
|
|
3596
|
+
} else if (e.key === "Home") {
|
|
3597
|
+
e.preventDefault();
|
|
3598
|
+
nav.first();
|
|
3599
|
+
} else if (e.key === "End") {
|
|
3600
|
+
e.preventDefault();
|
|
3601
|
+
nav.last();
|
|
3602
|
+
} else if (e.key === "Enter") {
|
|
3603
|
+
e.preventDefault();
|
|
3604
|
+
nav.activate();
|
|
3605
|
+
}
|
|
3606
|
+
}
|
|
3607
|
+
}
|
|
3608
|
+
)
|
|
3609
|
+
] }) : null
|
|
3610
|
+
] });
|
|
3611
|
+
const body = mode2 === "paste" ? /* @__PURE__ */ (0, import_jsx_runtime45.jsxs)("span", { className: "fd-stack fd-gap-sm", ref: pasteWrapRef, children: [
|
|
3486
3612
|
/* @__PURE__ */ (0, import_jsx_runtime45.jsx)(
|
|
3487
|
-
|
|
3613
|
+
Textarea,
|
|
3488
3614
|
{
|
|
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),
|
|
3615
|
+
"aria-label": field.label + " \u2014 paste a list",
|
|
3616
|
+
rows: 4,
|
|
3617
|
+
placeholder: field.pastePlaceholder || field.placeholder || "Paste names, one per line or comma-separated",
|
|
3618
|
+
value: pasteText,
|
|
3619
|
+
disabled: pasteLoading,
|
|
3620
|
+
onChange: (e) => setPasteText(e.target.value),
|
|
3501
3621
|
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") {
|
|
3622
|
+
if (e.key === "Enter" && (e.metaKey || e.ctrlKey)) {
|
|
3509
3623
|
e.preventDefault();
|
|
3510
|
-
|
|
3511
|
-
} else if (e.key === "Escape") {
|
|
3512
|
-
e.stopPropagation();
|
|
3513
|
-
onClose();
|
|
3624
|
+
doResolve();
|
|
3514
3625
|
}
|
|
3515
3626
|
}
|
|
3516
3627
|
}
|
|
3517
3628
|
),
|
|
3518
|
-
|
|
3519
|
-
|
|
3520
|
-
|
|
3521
|
-
|
|
3522
|
-
|
|
3523
|
-
|
|
3524
|
-
|
|
3525
|
-
|
|
3526
|
-
"aria-label": field.label,
|
|
3527
|
-
"aria-multiselectable": "true",
|
|
3528
|
-
className: "fd-stack",
|
|
3529
|
-
style: { gap: 2, maxHeight: 220, overflowY: "auto" },
|
|
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
|
-
})
|
|
3560
|
-
}
|
|
3561
|
-
),
|
|
3562
|
-
selected.length > 0 ? /* @__PURE__ */ (0, import_jsx_runtime45.jsxs)("span", { className: "fd-body-sm fd-muted", children: [
|
|
3563
|
-
selected.length,
|
|
3564
|
-
" selected"
|
|
3629
|
+
pasteError ? /* @__PURE__ */ (0, import_jsx_runtime45.jsx)(Banner, { tone: "danger", title: "Couldn't resolve the list", detail: pasteError }) : null,
|
|
3630
|
+
unmatchedTokens.length > 0 ? /* @__PURE__ */ (0, import_jsx_runtime45.jsx)(Banner, { tone: "warn", title: unmatchedTokens.length + " didn't match", detail: unmatchedTokens.join(", ") }) : null,
|
|
3631
|
+
selected.length > 0 ? /* @__PURE__ */ (0, import_jsx_runtime45.jsxs)("span", { className: "fd-stack fd-gap-xs", children: [
|
|
3632
|
+
/* @__PURE__ */ (0, import_jsx_runtime45.jsxs)("span", { className: "fd-body-sm fd-muted", children: [
|
|
3633
|
+
selected.length,
|
|
3634
|
+
" matched"
|
|
3635
|
+
] }),
|
|
3636
|
+
/* @__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)) })
|
|
3565
3637
|
] }) : null
|
|
3566
|
-
] })
|
|
3638
|
+
] }) : showLoading ? /* @__PURE__ */ (0, import_jsx_runtime45.jsxs)("span", { className: "fd-row fd-gap-xs", role: "status", children: [
|
|
3639
|
+
/* @__PURE__ */ (0, import_jsx_runtime45.jsx)("span", { className: "fd-spinner", "aria-hidden": "true" }),
|
|
3640
|
+
" Loading\u2026"
|
|
3641
|
+
] }) : showError ? /* @__PURE__ */ (0, import_jsx_runtime45.jsxs)("span", { className: "fd-stack fd-gap-sm", children: [
|
|
3642
|
+
/* @__PURE__ */ (0, import_jsx_runtime45.jsx)("span", { className: "fd-body-sm", role: "alert", children: "Couldn't load options." }),
|
|
3643
|
+
/* @__PURE__ */ (0, import_jsx_runtime45.jsx)(Button, { size: "sm", variant: "secondary", onClick: () => setRetryTick((n) => n + 1), children: "Retry" })
|
|
3644
|
+
] }) : options.length === 0 ? /* @__PURE__ */ (0, import_jsx_runtime45.jsx)("span", { className: "fd-body-sm fd-muted", role: "status", children: "No matches" }) : /* @__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) => {
|
|
3645
|
+
const on = isSelected(o);
|
|
3646
|
+
return /* @__PURE__ */ (0, import_jsx_runtime45.jsxs)(
|
|
3647
|
+
"div",
|
|
3648
|
+
{
|
|
3649
|
+
id: listId + "-opt-" + i,
|
|
3650
|
+
"data-i": i,
|
|
3651
|
+
role: "option",
|
|
3652
|
+
tabIndex: -1,
|
|
3653
|
+
"aria-selected": on,
|
|
3654
|
+
className: ["fd-opt", i === nav.active ? "is-active" : "", on ? "is-selected" : ""].filter(Boolean).join(" "),
|
|
3655
|
+
onMouseEnter: () => nav.setActive(i),
|
|
3656
|
+
onClick: () => toggle(o),
|
|
3657
|
+
children: [
|
|
3658
|
+
/* @__PURE__ */ (0, import_jsx_runtime45.jsx)("i", { className: "fd-filterbar-opt-check ph " + (on ? "ph-check-square is-checked" : "ph-square"), "aria-hidden": "true" }),
|
|
3659
|
+
/* @__PURE__ */ (0, import_jsx_runtime45.jsx)("span", { className: "fd-opt-label", children: o.label })
|
|
3660
|
+
]
|
|
3661
|
+
},
|
|
3662
|
+
o.value
|
|
3663
|
+
);
|
|
3664
|
+
}) });
|
|
3665
|
+
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;
|
|
3666
|
+
return /* @__PURE__ */ (0, import_jsx_runtime45.jsx)(
|
|
3667
|
+
Popover,
|
|
3668
|
+
{
|
|
3669
|
+
open: true,
|
|
3670
|
+
anchorRef,
|
|
3671
|
+
onClose,
|
|
3672
|
+
placement: "bottom-start",
|
|
3673
|
+
offset: 6,
|
|
3674
|
+
width: PANEL_WIDTH.multiSelect,
|
|
3675
|
+
label: field.label,
|
|
3676
|
+
header,
|
|
3677
|
+
footer,
|
|
3678
|
+
children: body
|
|
3679
|
+
}
|
|
3680
|
+
);
|
|
3567
3681
|
}
|
|
3568
3682
|
function RangePanel({
|
|
3569
3683
|
field,
|
|
3570
3684
|
value,
|
|
3685
|
+
anchorRef,
|
|
3571
3686
|
onChange,
|
|
3687
|
+
onRemove,
|
|
3572
3688
|
onClose
|
|
3573
3689
|
}) {
|
|
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
|
-
|
|
3690
|
+
const [draftMin, setDraftMin] = React24.useState(value?.min);
|
|
3691
|
+
const [draftMax, setDraftMax] = React24.useState(value?.max);
|
|
3692
|
+
const invalid = draftMin != null && draftMax != null && draftMin > draftMax;
|
|
3693
|
+
const apply = (nextMin, nextMax) => {
|
|
3694
|
+
setDraftMin(nextMin);
|
|
3695
|
+
setDraftMax(nextMax);
|
|
3696
|
+
if (nextMin == null && nextMax == null) {
|
|
3697
|
+
onRemove();
|
|
3698
|
+
return;
|
|
3699
|
+
}
|
|
3700
|
+
if (nextMin != null && nextMax != null && nextMin > nextMax) return;
|
|
3701
|
+
onChange({ min: nextMin, max: nextMax });
|
|
3702
|
+
};
|
|
3703
|
+
return /* @__PURE__ */ (0, import_jsx_runtime45.jsx)(
|
|
3704
|
+
Popover,
|
|
3705
|
+
{
|
|
3706
|
+
open: true,
|
|
3707
|
+
anchorRef,
|
|
3708
|
+
onClose,
|
|
3709
|
+
placement: "bottom-start",
|
|
3710
|
+
offset: 6,
|
|
3711
|
+
width: PANEL_WIDTH.range,
|
|
3712
|
+
label: field.label,
|
|
3713
|
+
footer: /* @__PURE__ */ (0, import_jsx_runtime45.jsx)(Button, { size: "sm", variant: "secondary", onClick: onClose, children: "Done" }),
|
|
3714
|
+
children: /* @__PURE__ */ (0, import_jsx_runtime45.jsxs)("span", { className: "fd-stack fd-gap-sm", children: [
|
|
3715
|
+
/* @__PURE__ */ (0, import_jsx_runtime45.jsx)(
|
|
3716
|
+
NumberInput,
|
|
3717
|
+
{
|
|
3718
|
+
label: field.minLabel || "At least",
|
|
3719
|
+
value: draftMin ?? "",
|
|
3720
|
+
min: field.min,
|
|
3721
|
+
max: field.max,
|
|
3722
|
+
step: field.step,
|
|
3723
|
+
placeholder: field.minPlaceholder,
|
|
3724
|
+
onChange: (e) => apply(e.target.value, draftMax)
|
|
3725
|
+
}
|
|
3726
|
+
),
|
|
3727
|
+
/* @__PURE__ */ (0, import_jsx_runtime45.jsx)(
|
|
3728
|
+
NumberInput,
|
|
3729
|
+
{
|
|
3730
|
+
label: field.maxLabel || "At most",
|
|
3731
|
+
value: draftMax ?? "",
|
|
3732
|
+
min: field.min,
|
|
3733
|
+
max: field.max,
|
|
3734
|
+
step: field.step,
|
|
3735
|
+
error: invalid ? "Must be \u2265 " + draftMin : void 0,
|
|
3736
|
+
placeholder: field.maxPlaceholder,
|
|
3737
|
+
onChange: (e) => apply(draftMin, e.target.value)
|
|
3738
|
+
}
|
|
3739
|
+
)
|
|
3740
|
+
] })
|
|
3741
|
+
}
|
|
3742
|
+
);
|
|
3605
3743
|
}
|
|
3606
3744
|
function DatePanel({
|
|
3607
3745
|
field,
|
|
3608
3746
|
value,
|
|
3747
|
+
anchorRef,
|
|
3609
3748
|
onChange,
|
|
3749
|
+
onRemove,
|
|
3610
3750
|
onClose
|
|
3611
3751
|
}) {
|
|
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
|
-
range: true,
|
|
3644
|
-
label: "Date range",
|
|
3645
|
-
value: value?.kind === "between" ? { start: value.from, end: value.to } : void 0,
|
|
3646
|
-
onChange: (e) => onChange({ kind: "between", from: e.target.value.start || "", to: e.target.value.end || "" })
|
|
3752
|
+
const defaultDays = field.defaultDays ?? 30;
|
|
3753
|
+
const [draft, setDraft] = React24.useState(value ?? { kind: "withinDays", days: defaultDays });
|
|
3754
|
+
const committedRef = React24.useRef(!!value);
|
|
3755
|
+
const applyWithinDays = (days) => {
|
|
3756
|
+
const next = { kind: "withinDays", days: days ?? defaultDays };
|
|
3757
|
+
setDraft(next);
|
|
3758
|
+
if (days != null) {
|
|
3759
|
+
committedRef.current = true;
|
|
3760
|
+
onChange(next);
|
|
3761
|
+
}
|
|
3762
|
+
};
|
|
3763
|
+
const applyBetween = (from, to) => {
|
|
3764
|
+
const next = { kind: "between", from, to };
|
|
3765
|
+
setDraft(next);
|
|
3766
|
+
if (from && to) {
|
|
3767
|
+
committedRef.current = true;
|
|
3768
|
+
onChange(next);
|
|
3769
|
+
} else if (committedRef.current) {
|
|
3770
|
+
committedRef.current = false;
|
|
3771
|
+
onRemove();
|
|
3772
|
+
}
|
|
3773
|
+
};
|
|
3774
|
+
const switchKind = (kind) => {
|
|
3775
|
+
if (kind === "withinDays") {
|
|
3776
|
+
const days = draft.kind === "withinDays" ? draft.days : defaultDays;
|
|
3777
|
+
setDraft({ kind: "withinDays", days });
|
|
3778
|
+
} else {
|
|
3779
|
+
setDraft({ kind: "between", from: "", to: "" });
|
|
3780
|
+
if (committedRef.current) {
|
|
3781
|
+
committedRef.current = false;
|
|
3782
|
+
onRemove();
|
|
3647
3783
|
}
|
|
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
|
-
});
|
|
3784
|
+
}
|
|
3684
3785
|
};
|
|
3685
|
-
|
|
3686
|
-
|
|
3687
|
-
|
|
3688
|
-
|
|
3689
|
-
|
|
3690
|
-
|
|
3691
|
-
|
|
3692
|
-
|
|
3693
|
-
|
|
3694
|
-
|
|
3695
|
-
|
|
3696
|
-
|
|
3697
|
-
|
|
3698
|
-
|
|
3699
|
-
|
|
3786
|
+
const confirm = () => {
|
|
3787
|
+
if (draft.kind === "withinDays") {
|
|
3788
|
+
committedRef.current = true;
|
|
3789
|
+
onChange(draft);
|
|
3790
|
+
}
|
|
3791
|
+
onClose();
|
|
3792
|
+
};
|
|
3793
|
+
return /* @__PURE__ */ (0, import_jsx_runtime45.jsx)(
|
|
3794
|
+
Popover,
|
|
3795
|
+
{
|
|
3796
|
+
open: true,
|
|
3797
|
+
anchorRef,
|
|
3798
|
+
onClose,
|
|
3799
|
+
placement: "bottom-start",
|
|
3800
|
+
offset: 6,
|
|
3801
|
+
width: PANEL_WIDTH.date,
|
|
3802
|
+
label: field.label,
|
|
3803
|
+
footer: /* @__PURE__ */ (0, import_jsx_runtime45.jsx)(Button, { size: "sm", variant: "secondary", onClick: confirm, children: "Done" }),
|
|
3804
|
+
children: /* @__PURE__ */ (0, import_jsx_runtime45.jsxs)("span", { className: "fd-stack fd-gap-sm", children: [
|
|
3805
|
+
/* @__PURE__ */ (0, import_jsx_runtime45.jsx)(
|
|
3806
|
+
SegmentedControl,
|
|
3807
|
+
{
|
|
3808
|
+
"aria-label": field.label + " \u2014 relative or between dates",
|
|
3809
|
+
options: [
|
|
3810
|
+
{ value: "withinDays", label: "Within last N days" },
|
|
3811
|
+
{ value: "between", label: "Between dates" }
|
|
3812
|
+
],
|
|
3813
|
+
value: draft.kind,
|
|
3814
|
+
onChange: (k) => switchKind(k)
|
|
3700
3815
|
}
|
|
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
|
-
] });
|
|
3816
|
+
),
|
|
3817
|
+
draft.kind === "withinDays" ? /* @__PURE__ */ (0, import_jsx_runtime45.jsx)(NumberInput, { label: "Days", min: 1, value: draft.days, onChange: (e) => applyWithinDays(e.target.value) }) : /* @__PURE__ */ (0, import_jsx_runtime45.jsx)(
|
|
3818
|
+
DatePicker,
|
|
3819
|
+
{
|
|
3820
|
+
range: true,
|
|
3821
|
+
label: "Date range",
|
|
3822
|
+
value: { start: draft.from, end: draft.to },
|
|
3823
|
+
onChange: (e) => applyBetween(e.target.value.start || "", e.target.value.end || "")
|
|
3824
|
+
}
|
|
3825
|
+
)
|
|
3826
|
+
] })
|
|
3827
|
+
}
|
|
3828
|
+
);
|
|
3716
3829
|
}
|
|
3717
3830
|
function FilterBar({ fields = [], filters, onFilterChange, onFilterRemove, align = "left", className = "", ...rest }) {
|
|
3718
|
-
const [panel, setPanel] =
|
|
3719
|
-
const
|
|
3720
|
-
const
|
|
3721
|
-
const textInputRef =
|
|
3722
|
-
const optionsRef =
|
|
3831
|
+
const [panel, setPanel] = React24.useState(null);
|
|
3832
|
+
const editAnchorRef = React24.useRef(null);
|
|
3833
|
+
const addAnchorRef = React24.useRef(null);
|
|
3834
|
+
const textInputRef = React24.useRef(null);
|
|
3835
|
+
const optionsRef = React24.useRef(null);
|
|
3723
3836
|
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(() => {
|
|
3837
|
+
const startEditing = (key) => setPanel({ kind: "edit", key });
|
|
3838
|
+
const closeEditing = () => setPanel(null);
|
|
3839
|
+
React24.useEffect(() => {
|
|
3743
3840
|
if (!panel || panel.kind !== "edit") return;
|
|
3744
3841
|
if (editingField?.type === "text") {
|
|
3745
3842
|
textInputRef.current?.focus();
|
|
@@ -3749,72 +3846,77 @@ function FilterBar({ fields = [], filters, onFilterChange, onFilterRemove, align
|
|
|
3749
3846
|
}
|
|
3750
3847
|
}, [panel]);
|
|
3751
3848
|
const addableFields = fields.filter((f) => !isFieldSet(f, filters[f.key]));
|
|
3752
|
-
const
|
|
3753
|
-
|
|
3849
|
+
const addMenuItems = [
|
|
3850
|
+
{ kind: "section", label: "Add filter" },
|
|
3851
|
+
...addableFields.map((f) => ({ id: f.key, label: f.label, onSelect: () => startEditing(f.key) }))
|
|
3852
|
+
];
|
|
3853
|
+
return /* @__PURE__ */ (0, import_jsx_runtime45.jsxs)("span", { className: ["fd-filterbar", className].filter(Boolean).join(" "), ...rest, children: [
|
|
3754
3854
|
fields.map((field) => {
|
|
3755
3855
|
const value = filters[field.key];
|
|
3756
3856
|
const editing = panel?.kind === "edit" && panel.key === field.key;
|
|
3757
3857
|
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" })
|
|
3858
|
+
return /* @__PURE__ */ (0, import_jsx_runtime45.jsxs)("span", { className: ["fd-tag", "fd-filterbar-text"].join(" "), children: [
|
|
3859
|
+
/* @__PURE__ */ (0, import_jsx_runtime45.jsx)(
|
|
3860
|
+
"input",
|
|
3861
|
+
{
|
|
3862
|
+
ref: textInputRef,
|
|
3863
|
+
className: "fd-filterbar-text-input",
|
|
3864
|
+
value: value ?? "",
|
|
3865
|
+
placeholder: field.placeholder || field.label,
|
|
3866
|
+
"aria-label": field.label,
|
|
3867
|
+
onChange: (e) => onFilterChange(field.key, e.target.value),
|
|
3868
|
+
onKeyDown: (e) => {
|
|
3869
|
+
if (e.key === "Enter") setPanel(null);
|
|
3870
|
+
else if (e.key === "Escape") {
|
|
3871
|
+
e.stopPropagation();
|
|
3872
|
+
setPanel(null);
|
|
3795
3873
|
}
|
|
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)(
|
|
3874
|
+
},
|
|
3875
|
+
onBlur: () => setPanel(null)
|
|
3876
|
+
}
|
|
3877
|
+
),
|
|
3878
|
+
isSet(value) ? /* @__PURE__ */ (0, import_jsx_runtime45.jsx)(
|
|
3813
3879
|
"span",
|
|
3814
3880
|
{
|
|
3815
|
-
className: "fd-
|
|
3816
|
-
|
|
3817
|
-
|
|
3881
|
+
className: "fd-tag-remove",
|
|
3882
|
+
role: "button",
|
|
3883
|
+
"aria-label": "Remove " + field.label,
|
|
3884
|
+
onClick: (e) => {
|
|
3885
|
+
e.stopPropagation();
|
|
3886
|
+
onFilterRemove(field.key);
|
|
3887
|
+
setPanel(null);
|
|
3888
|
+
},
|
|
3889
|
+
children: /* @__PURE__ */ (0, import_jsx_runtime45.jsx)("i", { className: "ph ph-x", "aria-hidden": "true" })
|
|
3890
|
+
}
|
|
3891
|
+
) : null
|
|
3892
|
+
] }, field.key);
|
|
3893
|
+
}
|
|
3894
|
+
const set = isFieldSet(field, value);
|
|
3895
|
+
if (!editing && !set) return null;
|
|
3896
|
+
const chipRef = editing ? editAnchorRef : void 0;
|
|
3897
|
+
const toggleOrClose = () => editing ? closeEditing() : startEditing(field.key);
|
|
3898
|
+
const remove = () => {
|
|
3899
|
+
if (set) onFilterRemove(field.key);
|
|
3900
|
+
closeEditing();
|
|
3901
|
+
};
|
|
3902
|
+
const chipText = field.label + (set ? ": " + chipLabel(field, value) : "");
|
|
3903
|
+
if (field.type === "text") {
|
|
3904
|
+
return /* @__PURE__ */ (0, import_jsx_runtime45.jsx)(Tag, { selected: true, onClick: toggleOrClose, onRemove: remove, children: chipText }, field.key);
|
|
3905
|
+
}
|
|
3906
|
+
if (field.type === "select") {
|
|
3907
|
+
return /* @__PURE__ */ (0, import_jsx_runtime45.jsxs)("span", { children: [
|
|
3908
|
+
/* @__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 }) }),
|
|
3909
|
+
editing ? /* @__PURE__ */ (0, import_jsx_runtime45.jsx)(
|
|
3910
|
+
Popover,
|
|
3911
|
+
{
|
|
3912
|
+
open: true,
|
|
3913
|
+
anchorRef: editAnchorRef,
|
|
3914
|
+
onClose: closeEditing,
|
|
3915
|
+
placement: align === "right" ? "bottom-end" : "bottom-start",
|
|
3916
|
+
offset: 6,
|
|
3917
|
+
minWidth: 200,
|
|
3918
|
+
label: field.label,
|
|
3919
|
+
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
3920
|
const on = o.value === value;
|
|
3819
3921
|
return /* @__PURE__ */ (0, import_jsx_runtime45.jsx)(
|
|
3820
3922
|
"button",
|
|
@@ -3822,84 +3924,72 @@ function FilterBar({ fields = [], filters, onFilterChange, onFilterRemove, align
|
|
|
3822
3924
|
type: "button",
|
|
3823
3925
|
role: "option",
|
|
3824
3926
|
"aria-selected": on,
|
|
3825
|
-
className: "fd-
|
|
3927
|
+
className: ["fd-opt", on ? "is-selected" : ""].filter(Boolean).join(" "),
|
|
3826
3928
|
onClick: () => {
|
|
3827
3929
|
onFilterChange(field.key, o.value);
|
|
3828
3930
|
setPanel(null);
|
|
3829
3931
|
},
|
|
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 })
|
|
3932
|
+
children: /* @__PURE__ */ (0, import_jsx_runtime45.jsx)("span", { className: "fd-opt-label", children: o.label })
|
|
3832
3933
|
},
|
|
3833
3934
|
o.value
|
|
3834
3935
|
);
|
|
3835
3936
|
}) })
|
|
3836
3937
|
}
|
|
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) }) })
|
|
3938
|
+
) : null
|
|
3851
3939
|
] }, field.key);
|
|
3852
3940
|
}
|
|
3853
|
-
if (
|
|
3854
|
-
|
|
3855
|
-
|
|
3856
|
-
/* @__PURE__ */ (0, import_jsx_runtime45.
|
|
3857
|
-
|
|
3858
|
-
|
|
3859
|
-
|
|
3860
|
-
|
|
3861
|
-
|
|
3862
|
-
|
|
3863
|
-
|
|
3864
|
-
|
|
3865
|
-
|
|
3866
|
-
|
|
3867
|
-
const dv = value;
|
|
3868
|
-
return /* @__PURE__ */ (0, import_jsx_runtime45.jsxs)("span", { style: { position: "relative", display: "inline-flex" }, children: [
|
|
3869
|
-
/* @__PURE__ */ (0, import_jsx_runtime45.jsxs)(Tag, { selected: true, onClick: () => setPanel(null), onRemove: () => {
|
|
3870
|
-
if (isFieldSet(field, value)) onFilterRemove(field.key);
|
|
3871
|
-
setPanel(null);
|
|
3872
|
-
}, children: [
|
|
3873
|
-
field.label,
|
|
3874
|
-
isFieldSet(field, value) ? ": " + chipLabel(field, value) : ""
|
|
3875
|
-
] }),
|
|
3876
|
-
/* @__PURE__ */ (0, import_jsx_runtime45.jsx)(EditPopover, { zIndex, width: 300, children: /* @__PURE__ */ (0, import_jsx_runtime45.jsx)(DatePanel, { field, value: dv, onChange: (v) => onFilterChange(field.key, v), onClose: () => setPanel(null) }) })
|
|
3941
|
+
if (field.type === "multiSelect") {
|
|
3942
|
+
return /* @__PURE__ */ (0, import_jsx_runtime45.jsxs)("span", { children: [
|
|
3943
|
+
/* @__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 }) }),
|
|
3944
|
+
editing ? /* @__PURE__ */ (0, import_jsx_runtime45.jsx)(
|
|
3945
|
+
MultiSelectPanel,
|
|
3946
|
+
{
|
|
3947
|
+
field,
|
|
3948
|
+
value,
|
|
3949
|
+
anchorRef: editAnchorRef,
|
|
3950
|
+
onChange: (v) => onFilterChange(field.key, v),
|
|
3951
|
+
onRemove: () => onFilterRemove(field.key),
|
|
3952
|
+
onClose: closeEditing
|
|
3953
|
+
}
|
|
3954
|
+
) : null
|
|
3877
3955
|
] }, field.key);
|
|
3878
3956
|
}
|
|
3879
|
-
if (
|
|
3880
|
-
|
|
3881
|
-
|
|
3882
|
-
/* @__PURE__ */ (0, import_jsx_runtime45.
|
|
3883
|
-
|
|
3884
|
-
|
|
3885
|
-
|
|
3886
|
-
|
|
3887
|
-
|
|
3888
|
-
|
|
3889
|
-
|
|
3957
|
+
if (field.type === "range") {
|
|
3958
|
+
return /* @__PURE__ */ (0, import_jsx_runtime45.jsxs)("span", { children: [
|
|
3959
|
+
/* @__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 }) }),
|
|
3960
|
+
editing ? /* @__PURE__ */ (0, import_jsx_runtime45.jsx)(
|
|
3961
|
+
RangePanel,
|
|
3962
|
+
{
|
|
3963
|
+
field,
|
|
3964
|
+
value,
|
|
3965
|
+
anchorRef: editAnchorRef,
|
|
3966
|
+
onChange: (v) => onFilterChange(field.key, v),
|
|
3967
|
+
onRemove: () => onFilterRemove(field.key),
|
|
3968
|
+
onClose: closeEditing
|
|
3969
|
+
}
|
|
3970
|
+
) : null
|
|
3890
3971
|
] }, field.key);
|
|
3891
3972
|
}
|
|
3892
|
-
if (
|
|
3893
|
-
return /* @__PURE__ */ (0, import_jsx_runtime45.jsxs)(
|
|
3894
|
-
|
|
3895
|
-
|
|
3896
|
-
|
|
3973
|
+
if (field.type === "date") {
|
|
3974
|
+
return /* @__PURE__ */ (0, import_jsx_runtime45.jsxs)("span", { children: [
|
|
3975
|
+
/* @__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 }) }),
|
|
3976
|
+
editing ? /* @__PURE__ */ (0, import_jsx_runtime45.jsx)(
|
|
3977
|
+
DatePanel,
|
|
3978
|
+
{
|
|
3979
|
+
field,
|
|
3980
|
+
value,
|
|
3981
|
+
anchorRef: editAnchorRef,
|
|
3982
|
+
onChange: (v) => onFilterChange(field.key, v),
|
|
3983
|
+
onRemove: () => onFilterRemove(field.key),
|
|
3984
|
+
onClose: closeEditing
|
|
3985
|
+
}
|
|
3986
|
+
) : null
|
|
3897
3987
|
] }, field.key);
|
|
3898
3988
|
}
|
|
3899
3989
|
return null;
|
|
3900
3990
|
}),
|
|
3901
|
-
addableFields.length > 0 ? /* @__PURE__ */ (0, import_jsx_runtime45.jsxs)("span", {
|
|
3902
|
-
/* @__PURE__ */ (0, import_jsx_runtime45.jsx)(
|
|
3991
|
+
addableFields.length > 0 ? /* @__PURE__ */ (0, import_jsx_runtime45.jsxs)("span", { children: [
|
|
3992
|
+
/* @__PURE__ */ (0, import_jsx_runtime45.jsx)("span", { ref: addAnchorRef, children: /* @__PURE__ */ (0, import_jsx_runtime45.jsx)(
|
|
3903
3993
|
Button,
|
|
3904
3994
|
{
|
|
3905
3995
|
size: "sm",
|
|
@@ -3910,29 +4000,20 @@ function FilterBar({ fields = [], filters, onFilterChange, onFilterRemove, align
|
|
|
3910
4000
|
onClick: () => setPanel(panel?.kind === "add" ? null : { kind: "add" }),
|
|
3911
4001
|
children: "Filter"
|
|
3912
4002
|
}
|
|
3913
|
-
),
|
|
3914
|
-
|
|
3915
|
-
|
|
4003
|
+
) }),
|
|
4004
|
+
/* @__PURE__ */ (0, import_jsx_runtime45.jsx)(
|
|
4005
|
+
Popover,
|
|
3916
4006
|
{
|
|
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
|
-
] })
|
|
4007
|
+
open: panel?.kind === "add",
|
|
4008
|
+
anchorRef: addAnchorRef,
|
|
4009
|
+
onClose: closeEditing,
|
|
4010
|
+
placement: align === "right" ? "bottom-end" : "bottom-start",
|
|
4011
|
+
minWidth: 200,
|
|
4012
|
+
role: "menu",
|
|
4013
|
+
label: "Add filter",
|
|
4014
|
+
children: /* @__PURE__ */ (0, import_jsx_runtime45.jsx)(Menu, { items: addMenuItems })
|
|
3934
4015
|
}
|
|
3935
|
-
)
|
|
4016
|
+
)
|
|
3936
4017
|
] }) : null
|
|
3937
4018
|
] });
|
|
3938
4019
|
}
|
|
@@ -3964,7 +4045,7 @@ function StatTile({ label, value, sub, delta, invert = false, loading = false, c
|
|
|
3964
4045
|
}
|
|
3965
4046
|
|
|
3966
4047
|
// src/components/data/CodeBlock.tsx
|
|
3967
|
-
var
|
|
4048
|
+
var React25 = __toESM(require("react"), 1);
|
|
3968
4049
|
var import_jsx_runtime47 = require("react/jsx-runtime");
|
|
3969
4050
|
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
4051
|
var RULES = {
|
|
@@ -4120,13 +4201,13 @@ function tokenize(src, lang) {
|
|
|
4120
4201
|
return out;
|
|
4121
4202
|
}
|
|
4122
4203
|
function Highlighted({ code, lang }) {
|
|
4123
|
-
const toks =
|
|
4204
|
+
const toks = React25.useMemo(() => tokenize(code, lang), [code, lang]);
|
|
4124
4205
|
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
4206
|
}
|
|
4126
4207
|
function useCopy() {
|
|
4127
|
-
const [done, setDone] =
|
|
4128
|
-
const timer =
|
|
4129
|
-
|
|
4208
|
+
const [done, setDone] = React25.useState(false);
|
|
4209
|
+
const timer = React25.useRef(null);
|
|
4210
|
+
React25.useEffect(() => () => {
|
|
4130
4211
|
if (timer.current) clearTimeout(timer.current);
|
|
4131
4212
|
}, []);
|
|
4132
4213
|
const copy = (text) => {
|
|
@@ -4162,8 +4243,8 @@ function CodeBlock({
|
|
|
4162
4243
|
actions,
|
|
4163
4244
|
className = ""
|
|
4164
4245
|
}) {
|
|
4165
|
-
const [wrap, setWrap] =
|
|
4166
|
-
const [open, setOpen] =
|
|
4246
|
+
const [wrap, setWrap] = React25.useState(!!wrapDefault);
|
|
4247
|
+
const [open, setOpen] = React25.useState(false);
|
|
4167
4248
|
const [copied, copy] = useCopy();
|
|
4168
4249
|
const body = String(code).replace(/\n$/, "");
|
|
4169
4250
|
const lines = body.split("\n");
|
|
@@ -4192,7 +4273,7 @@ function CodeBlock({
|
|
|
4192
4273
|
] });
|
|
4193
4274
|
}
|
|
4194
4275
|
function DiffBlock({ diff = "", filename, collapseAfter = 34, className = "" }) {
|
|
4195
|
-
const [open, setOpen] =
|
|
4276
|
+
const [open, setOpen] = React25.useState(false);
|
|
4196
4277
|
const [copied, copy] = useCopy();
|
|
4197
4278
|
const raw = String(diff).replace(/\n$/, "");
|
|
4198
4279
|
const all = raw.split("\n").map((line) => {
|
|
@@ -4238,7 +4319,7 @@ function DiffBlock({ diff = "", filename, collapseAfter = 34, className = "" })
|
|
|
4238
4319
|
}
|
|
4239
4320
|
|
|
4240
4321
|
// src/components/data/Markdown.tsx
|
|
4241
|
-
var
|
|
4322
|
+
var React26 = __toESM(require("react"), 1);
|
|
4242
4323
|
var import_jsx_runtime48 = require("react/jsx-runtime");
|
|
4243
4324
|
var SAFE = /^(?:https?:|mailto:|tel:|#|\/|\.{1,2}\/)/i;
|
|
4244
4325
|
var safeHref = (h) => SAFE.test(String(h || "").trim()) ? String(h).trim() : null;
|
|
@@ -4277,7 +4358,7 @@ function inlineNodes(src, ctx, keyBase) {
|
|
|
4277
4358
|
const href = safeHref(g(2));
|
|
4278
4359
|
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
4360
|
} else if (kind === "cite") {
|
|
4280
|
-
out.push(ctx.renderCitation ? /* @__PURE__ */ (0, import_jsx_runtime48.jsx)(
|
|
4361
|
+
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
4362
|
} 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
4363
|
else if (kind === "strong") out.push(/* @__PURE__ */ (0, import_jsx_runtime48.jsx)("strong", { children: inlineNodes(g(1) || g(2), ctx, key()) }, key()));
|
|
4283
4364
|
else if (kind === "em") out.push(/* @__PURE__ */ (0, import_jsx_runtime48.jsx)("em", { children: inlineNodes(g(1) || g(2), ctx, key()) }, key()));
|
|
@@ -4442,7 +4523,7 @@ function Markdown({
|
|
|
4442
4523
|
onLinkClick
|
|
4443
4524
|
}) {
|
|
4444
4525
|
const ctx = { allowImages, headingOffset, renderCitation, onLinkClick, codeProps };
|
|
4445
|
-
const blocks =
|
|
4526
|
+
const blocks = React26.useMemo(() => parseBlocks(source), [source]);
|
|
4446
4527
|
return /* @__PURE__ */ (0, import_jsx_runtime48.jsx)("div", { className: ["fd-md", className].filter(Boolean).join(" "), children: renderBlocks(blocks, ctx, "b") });
|
|
4447
4528
|
}
|
|
4448
4529
|
function MarkdownInline({ source = "", className = "", onLinkClick }) {
|
|
@@ -4556,7 +4637,7 @@ function Pagination({
|
|
|
4556
4637
|
}
|
|
4557
4638
|
|
|
4558
4639
|
// src/components/data/RelativeTime.tsx
|
|
4559
|
-
var
|
|
4640
|
+
var React27 = __toESM(require("react"), 1);
|
|
4560
4641
|
var import_jsx_runtime51 = require("react/jsx-runtime");
|
|
4561
4642
|
var MIN = 6e4;
|
|
4562
4643
|
var HOUR = 36e5;
|
|
@@ -4608,9 +4689,9 @@ function formatDuration(ms) {
|
|
|
4608
4689
|
return h + "h" + (m % 60 ? " " + m % 60 + "m" : "");
|
|
4609
4690
|
}
|
|
4610
4691
|
function RelativeTime({ value, prefix, className = "", refresh: refresh2 = true, ...rest }) {
|
|
4611
|
-
const [, force] =
|
|
4692
|
+
const [, force] = React27.useState(0);
|
|
4612
4693
|
const t = value instanceof Date ? value.getTime() : Date.parse(value);
|
|
4613
|
-
|
|
4694
|
+
React27.useEffect(() => {
|
|
4614
4695
|
if (!refresh2 || !t || isNaN(t)) return;
|
|
4615
4696
|
const abs = Math.abs(t - Date.now());
|
|
4616
4697
|
if (abs > DAY) return;
|
|
@@ -4626,7 +4707,7 @@ function RelativeTime({ value, prefix, className = "", refresh: refresh2 = true,
|
|
|
4626
4707
|
}
|
|
4627
4708
|
|
|
4628
4709
|
// src/components/data/ScoreMeter.tsx
|
|
4629
|
-
var
|
|
4710
|
+
var React28 = __toESM(require("react"), 1);
|
|
4630
4711
|
var import_jsx_runtime52 = require("react/jsx-runtime");
|
|
4631
4712
|
function ScoreMeter({
|
|
4632
4713
|
score,
|
|
@@ -4641,10 +4722,10 @@ function ScoreMeter({
|
|
|
4641
4722
|
breakdownWidth = 280,
|
|
4642
4723
|
className = ""
|
|
4643
4724
|
}) {
|
|
4644
|
-
const [open, setOpen] =
|
|
4645
|
-
const ref =
|
|
4725
|
+
const [open, setOpen] = React28.useState(false);
|
|
4726
|
+
const ref = React28.useRef(null);
|
|
4646
4727
|
const value = Math.max(0, Math.min(100, Math.round(Number(score) || 0)));
|
|
4647
|
-
const body = /* @__PURE__ */ (0, import_jsx_runtime52.jsxs)(
|
|
4728
|
+
const body = /* @__PURE__ */ (0, import_jsx_runtime52.jsxs)(React28.Fragment, { children: [
|
|
4648
4729
|
/* @__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
4730
|
showScore ? /* @__PURE__ */ (0, import_jsx_runtime52.jsx)("span", { className: "fd-scoremeter-value fd-tabular", "aria-hidden": "true", children: value }) : null
|
|
4650
4731
|
] });
|
|
@@ -4663,7 +4744,7 @@ function ScoreMeter({
|
|
|
4663
4744
|
}
|
|
4664
4745
|
);
|
|
4665
4746
|
}
|
|
4666
|
-
return /* @__PURE__ */ (0, import_jsx_runtime52.jsxs)(
|
|
4747
|
+
return /* @__PURE__ */ (0, import_jsx_runtime52.jsxs)(React28.Fragment, { children: [
|
|
4667
4748
|
/* @__PURE__ */ (0, import_jsx_runtime52.jsx)(
|
|
4668
4749
|
"button",
|
|
4669
4750
|
{
|
|
@@ -4694,13 +4775,13 @@ function ScoreMeter({
|
|
|
4694
4775
|
}
|
|
4695
4776
|
|
|
4696
4777
|
// src/components/data/SortMenu.tsx
|
|
4697
|
-
var
|
|
4778
|
+
var React29 = __toESM(require("react"), 1);
|
|
4698
4779
|
var import_jsx_runtime53 = require("react/jsx-runtime");
|
|
4699
4780
|
function SortMenu({ fields = [], sort, onSort, align = "right", size = "md", className = "", ...rest }) {
|
|
4700
|
-
const [open, setOpen] =
|
|
4781
|
+
const [open, setOpen] = React29.useState(false);
|
|
4701
4782
|
const zIndex = useOverlayLayer(open);
|
|
4702
|
-
const ref =
|
|
4703
|
-
|
|
4783
|
+
const ref = React29.useRef(null);
|
|
4784
|
+
React29.useEffect(() => {
|
|
4704
4785
|
if (!open) return;
|
|
4705
4786
|
const away = (e) => {
|
|
4706
4787
|
if (ref.current && !ref.current.contains(e.target)) setOpen(false);
|
|
@@ -4762,7 +4843,7 @@ function SortMenu({ fields = [], sort, onSort, align = "right", size = "md", cla
|
|
|
4762
4843
|
}
|
|
4763
4844
|
|
|
4764
4845
|
// src/components/data/StepList.tsx
|
|
4765
|
-
var
|
|
4846
|
+
var React30 = __toESM(require("react"), 1);
|
|
4766
4847
|
var import_jsx_runtime54 = require("react/jsx-runtime");
|
|
4767
4848
|
var KIND_ICON = { tool: "wrench", search: "magnifying-glass", read: "file-text", write: "pencil-simple", reasoning: "brain", run: "terminal", fetch: "cloud-arrow-down" };
|
|
4768
4849
|
function StepList({
|
|
@@ -4775,9 +4856,9 @@ function StepList({
|
|
|
4775
4856
|
dense = false,
|
|
4776
4857
|
className = ""
|
|
4777
4858
|
}) {
|
|
4778
|
-
const [openState, setOpenState] =
|
|
4859
|
+
const [openState, setOpenState] = React30.useState(defaultOpen);
|
|
4779
4860
|
const open = openProp == null ? openState : openProp;
|
|
4780
|
-
const [expanded, setExpanded] =
|
|
4861
|
+
const [expanded, setExpanded] = React30.useState({});
|
|
4781
4862
|
if (!steps.length) return null;
|
|
4782
4863
|
const running = steps.some((s) => s.status === "running");
|
|
4783
4864
|
const failed = steps.filter((s) => s.status === "error").length;
|
|
@@ -4835,7 +4916,7 @@ function StepList({
|
|
|
4835
4916
|
}
|
|
4836
4917
|
|
|
4837
4918
|
// src/components/data/VirtualList.tsx
|
|
4838
|
-
var
|
|
4919
|
+
var React31 = __toESM(require("react"), 1);
|
|
4839
4920
|
var import_jsx_runtime55 = require("react/jsx-runtime");
|
|
4840
4921
|
var VIRTUAL_LIST_BUFFER_ROWS = 20;
|
|
4841
4922
|
var VIRTUAL_LIST_ROW_GAP = 6;
|
|
@@ -4887,35 +4968,35 @@ function VirtualList({
|
|
|
4887
4968
|
className = "",
|
|
4888
4969
|
style
|
|
4889
4970
|
}) {
|
|
4890
|
-
const [scrollTop, setScrollTop] =
|
|
4891
|
-
const loaded =
|
|
4971
|
+
const [scrollTop, setScrollTop] = React31.useState(0);
|
|
4972
|
+
const loaded = React31.useMemo(
|
|
4892
4973
|
() => ({ firstItemIndex, count: items.length }),
|
|
4893
4974
|
[firstItemIndex, items.length]
|
|
4894
4975
|
);
|
|
4895
4976
|
const total = Math.max(totalCount == null ? 0 : totalCount, firstItemIndex + items.length);
|
|
4896
4977
|
const bandKey = firstItemIndex + ":" + items.length;
|
|
4897
|
-
const win =
|
|
4978
|
+
const win = React31.useMemo(
|
|
4898
4979
|
() => computeVirtualWindow({ scrollTop, viewportHeight: height, itemHeight, itemCount: total, loaded }),
|
|
4899
4980
|
[scrollTop, height, itemHeight, total, loaded]
|
|
4900
4981
|
);
|
|
4901
|
-
const need =
|
|
4982
|
+
const need = React31.useMemo(() => computeNeedMore(win, loaded), [win, loaded]);
|
|
4902
4983
|
const wantStart = need.start && hasMore?.start !== false;
|
|
4903
4984
|
const wantEnd = need.end && hasMore?.end !== false;
|
|
4904
4985
|
const bucket2 = Math.floor(win.visibleStart / VIRTUAL_LIST_BUFFER_ROWS);
|
|
4905
4986
|
const askKey = bandKey + "@" + bucket2;
|
|
4906
|
-
const asked =
|
|
4907
|
-
|
|
4987
|
+
const asked = React31.useRef({ start: null, end: null });
|
|
4988
|
+
React31.useEffect(() => {
|
|
4908
4989
|
if (loading || !wantStart || asked.current.start === askKey) return;
|
|
4909
4990
|
asked.current.start = askKey;
|
|
4910
4991
|
onNeedMore("start", win);
|
|
4911
4992
|
}, [wantStart, loading, askKey, onNeedMore, win]);
|
|
4912
|
-
|
|
4993
|
+
React31.useEffect(() => {
|
|
4913
4994
|
if (loading || !wantEnd || asked.current.end === askKey) return;
|
|
4914
4995
|
asked.current.end = askKey;
|
|
4915
4996
|
onNeedMore("end", win);
|
|
4916
4997
|
}, [wantEnd, loading, askKey, onNeedMore, win]);
|
|
4917
|
-
const lastKeysRef =
|
|
4918
|
-
const newKeys =
|
|
4998
|
+
const lastKeysRef = React31.useRef(null);
|
|
4999
|
+
const newKeys = React31.useMemo(() => {
|
|
4919
5000
|
const prev = lastKeysRef.current;
|
|
4920
5001
|
if (!prev) return /* @__PURE__ */ new Set();
|
|
4921
5002
|
const fresh = /* @__PURE__ */ new Set();
|
|
@@ -4925,7 +5006,7 @@ function VirtualList({
|
|
|
4925
5006
|
}
|
|
4926
5007
|
return fresh;
|
|
4927
5008
|
}, [items]);
|
|
4928
|
-
|
|
5009
|
+
React31.useEffect(() => {
|
|
4929
5010
|
lastKeysRef.current = new Set(items.map(keyOf));
|
|
4930
5011
|
}, [items]);
|
|
4931
5012
|
const gapStyle = { "--fd-vlist-gap": rowGap + "px" };
|
|
@@ -4970,7 +5051,7 @@ function VirtualList({
|
|
|
4970
5051
|
}
|
|
4971
5052
|
|
|
4972
5053
|
// src/components/data/EntityRow.tsx
|
|
4973
|
-
var
|
|
5054
|
+
var React32 = __toESM(require("react"), 1);
|
|
4974
5055
|
var import_jsx_runtime56 = require("react/jsx-runtime");
|
|
4975
5056
|
var ENTITY_ROW_METRIC_WIDTH = 74;
|
|
4976
5057
|
var METRIC_TONE_COLOR = {
|
|
@@ -4983,7 +5064,7 @@ function EntityRowMetrics({ metrics, className = "", style }) {
|
|
|
4983
5064
|
const key = m.id || m.label || i;
|
|
4984
5065
|
const className2 = ["fd-erow-metric", m.tone && m.tone !== "default" ? "is-" + m.tone : "", m.tooltip != null ? "is-described" : ""].filter(Boolean).join(" ");
|
|
4985
5066
|
const tone = { color: METRIC_TONE_COLOR[m.tone || "default"] };
|
|
4986
|
-
const content = /* @__PURE__ */ (0, import_jsx_runtime56.jsxs)(
|
|
5067
|
+
const content = /* @__PURE__ */ (0, import_jsx_runtime56.jsxs)(React32.Fragment, { children: [
|
|
4987
5068
|
m.icon ? /* @__PURE__ */ (0, import_jsx_runtime56.jsx)("i", { className: "ph ph-" + m.icon, "aria-hidden": "true" }) : null,
|
|
4988
5069
|
/* @__PURE__ */ (0, import_jsx_runtime56.jsx)("span", { className: "fd-erow-metric-value fd-tabular", children: m.value }),
|
|
4989
5070
|
/* @__PURE__ */ (0, import_jsx_runtime56.jsx)("span", { className: "fd-sr", children: " " + m.label })
|
|
@@ -5075,7 +5156,7 @@ function EntityRow({
|
|
|
5075
5156
|
}
|
|
5076
5157
|
|
|
5077
5158
|
// src/components/data/TransferList.tsx
|
|
5078
|
-
var
|
|
5159
|
+
var React33 = __toESM(require("react"), 1);
|
|
5079
5160
|
var import_react_dom5 = require("react-dom");
|
|
5080
5161
|
|
|
5081
5162
|
// src/components/forms/Input.tsx
|
|
@@ -5181,12 +5262,12 @@ function TransferList({
|
|
|
5181
5262
|
listHeight = 440,
|
|
5182
5263
|
className = ""
|
|
5183
5264
|
}) {
|
|
5184
|
-
const [drag, setDrag] =
|
|
5185
|
-
const [dragOverSide, setDragOverSide] =
|
|
5186
|
-
const dragRef =
|
|
5187
|
-
const armedRef =
|
|
5188
|
-
const sideRefs =
|
|
5189
|
-
const hitTestSide =
|
|
5265
|
+
const [drag, setDrag] = React33.useState(null);
|
|
5266
|
+
const [dragOverSide, setDragOverSide] = React33.useState(null);
|
|
5267
|
+
const dragRef = React33.useRef(null);
|
|
5268
|
+
const armedRef = React33.useRef(null);
|
|
5269
|
+
const sideRefs = React33.useRef({ left: null, right: null });
|
|
5270
|
+
const hitTestSide = React33.useCallback((x, y) => {
|
|
5190
5271
|
for (const side of ["left", "right"]) {
|
|
5191
5272
|
const el = sideRefs.current[side];
|
|
5192
5273
|
if (!el) continue;
|
|
@@ -5195,7 +5276,7 @@ function TransferList({
|
|
|
5195
5276
|
}
|
|
5196
5277
|
return null;
|
|
5197
5278
|
}, []);
|
|
5198
|
-
const findItem =
|
|
5279
|
+
const findItem = React33.useCallback(
|
|
5199
5280
|
(side, key) => (side === "left" ? left.items : right.items).find((it) => keyOf(it) === key),
|
|
5200
5281
|
[left.items, right.items, keyOf]
|
|
5201
5282
|
);
|
|
@@ -5217,7 +5298,7 @@ function TransferList({
|
|
|
5217
5298
|
height: rect.height
|
|
5218
5299
|
};
|
|
5219
5300
|
};
|
|
5220
|
-
|
|
5301
|
+
React33.useEffect(() => {
|
|
5221
5302
|
const onMovePointer = (e) => {
|
|
5222
5303
|
const armed = armedRef.current;
|
|
5223
5304
|
if (!armed || e.pointerId !== armed.pointerId) return;
|
|
@@ -5270,7 +5351,7 @@ function TransferList({
|
|
|
5270
5351
|
window.removeEventListener("pointercancel", endDrag);
|
|
5271
5352
|
};
|
|
5272
5353
|
}, [hitTestSide, findItem, onMove]);
|
|
5273
|
-
|
|
5354
|
+
React33.useEffect(() => {
|
|
5274
5355
|
if (!drag || typeof document === "undefined") return;
|
|
5275
5356
|
const prev = document.body.style.userSelect;
|
|
5276
5357
|
document.body.style.userSelect = "none";
|
|
@@ -5378,11 +5459,11 @@ function TransferList({
|
|
|
5378
5459
|
}
|
|
5379
5460
|
|
|
5380
5461
|
// src/components/forms/Checkbox.tsx
|
|
5381
|
-
var
|
|
5462
|
+
var React34 = __toESM(require("react"), 1);
|
|
5382
5463
|
var import_jsx_runtime60 = require("react/jsx-runtime");
|
|
5383
5464
|
function Checkbox({ label, description, card = false, indeterminate = false, className = "", ...rest }) {
|
|
5384
|
-
const ref =
|
|
5385
|
-
|
|
5465
|
+
const ref = React34.useRef(null);
|
|
5466
|
+
React34.useEffect(() => {
|
|
5386
5467
|
if (ref.current) ref.current.indeterminate = indeterminate;
|
|
5387
5468
|
}, [indeterminate]);
|
|
5388
5469
|
return /* @__PURE__ */ (0, import_jsx_runtime60.jsxs)("label", { className: ["fd-choice", card ? "fd-choice-card" : "", className].filter(Boolean).join(" "), children: [
|
|
@@ -5426,7 +5507,7 @@ function Switch({ label, description, className = "", ...rest }) {
|
|
|
5426
5507
|
}
|
|
5427
5508
|
|
|
5428
5509
|
// src/components/forms/Select.tsx
|
|
5429
|
-
var
|
|
5510
|
+
var React35 = __toESM(require("react"), 1);
|
|
5430
5511
|
var import_jsx_runtime63 = require("react/jsx-runtime");
|
|
5431
5512
|
var norm = (o) => typeof o === "string" ? { value: o, label: o } : o;
|
|
5432
5513
|
function Select({
|
|
@@ -5453,13 +5534,12 @@ function Select({
|
|
|
5453
5534
|
const isOn = (v) => multiple ? vals.includes(v) : v === value;
|
|
5454
5535
|
const hasSearch = searchable === void 0 ? opts.length > 8 : searchable;
|
|
5455
5536
|
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 });
|
|
5537
|
+
const [open, setOpen] = React35.useState(false);
|
|
5538
|
+
const [q, setQ] = React35.useState("");
|
|
5539
|
+
const rootRef = React35.useRef(null);
|
|
5540
|
+
const boxRef = React35.useRef(null);
|
|
5541
|
+
const listRef = React35.useRef(null);
|
|
5542
|
+
const typeBuf = React35.useRef({ s: "", t: 0 });
|
|
5463
5543
|
const selected = multiple ? null : opts.find((o) => o.value === value);
|
|
5464
5544
|
const chosen = multiple ? opts.filter((o) => vals.includes(o.value)) : [];
|
|
5465
5545
|
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 +5556,16 @@ function Select({
|
|
|
5476
5556
|
fire(o.value);
|
|
5477
5557
|
setOpen(false);
|
|
5478
5558
|
};
|
|
5559
|
+
const nav = useListboxNav({ count: visible.length, onSelect: (i) => pick(visible[i]) });
|
|
5560
|
+
useListboxScrollIntoView(nav.active, listRef, open);
|
|
5479
5561
|
const toggle = () => {
|
|
5480
5562
|
if (disabled || loading) return;
|
|
5481
5563
|
if (!open) {
|
|
5482
5564
|
setQ("");
|
|
5483
|
-
setActive(Math.max(0, opts.findIndex((o) => isOn(o.value))));
|
|
5565
|
+
nav.setActive(Math.max(0, opts.findIndex((o) => isOn(o.value))));
|
|
5484
5566
|
}
|
|
5485
5567
|
setOpen(!open);
|
|
5486
5568
|
};
|
|
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
5569
|
const onKey = (e) => {
|
|
5497
5570
|
if (disabled) return;
|
|
5498
5571
|
if (!open && (e.key === "Enter" || e.key === " " || e.key === "ArrowDown" || e.key === "ArrowUp")) {
|
|
@@ -5514,19 +5587,19 @@ function Select({
|
|
|
5514
5587
|
setOpen(false);
|
|
5515
5588
|
} else if (e.key === "ArrowDown") {
|
|
5516
5589
|
e.preventDefault();
|
|
5517
|
-
|
|
5590
|
+
nav.move(1);
|
|
5518
5591
|
} else if (e.key === "ArrowUp") {
|
|
5519
5592
|
e.preventDefault();
|
|
5520
|
-
|
|
5593
|
+
nav.move(-1);
|
|
5521
5594
|
} else if (e.key === "Home") {
|
|
5522
5595
|
e.preventDefault();
|
|
5523
|
-
|
|
5596
|
+
nav.first();
|
|
5524
5597
|
} else if (e.key === "End") {
|
|
5525
5598
|
e.preventDefault();
|
|
5526
|
-
|
|
5599
|
+
nav.last();
|
|
5527
5600
|
} else if (e.key === "Enter") {
|
|
5528
5601
|
e.preventDefault();
|
|
5529
|
-
|
|
5602
|
+
nav.activate();
|
|
5530
5603
|
} else if (e.key === "Tab") setOpen(false);
|
|
5531
5604
|
};
|
|
5532
5605
|
const groups = [];
|
|
@@ -5599,13 +5672,13 @@ function Select({
|
|
|
5599
5672
|
onKeyDown: onKey,
|
|
5600
5673
|
onChange: (e) => {
|
|
5601
5674
|
setQ(e.target.value);
|
|
5602
|
-
setActive(0);
|
|
5675
|
+
nav.setActive(0);
|
|
5603
5676
|
}
|
|
5604
5677
|
}
|
|
5605
5678
|
),
|
|
5606
5679
|
q ? /* @__PURE__ */ (0, import_jsx_runtime63.jsx)("span", { className: "fd-body-sm fd-muted", children: visible.length }) : null
|
|
5607
5680
|
] }) : void 0,
|
|
5608
|
-
footer: multiple ? /* @__PURE__ */ (0, import_jsx_runtime63.jsxs)(
|
|
5681
|
+
footer: multiple ? /* @__PURE__ */ (0, import_jsx_runtime63.jsxs)(React35.Fragment, { children: [
|
|
5609
5682
|
/* @__PURE__ */ (0, import_jsx_runtime63.jsx)(
|
|
5610
5683
|
"button",
|
|
5611
5684
|
{
|
|
@@ -5636,7 +5709,7 @@ function Select({
|
|
|
5636
5709
|
'Nothing matches "',
|
|
5637
5710
|
q,
|
|
5638
5711
|
'".'
|
|
5639
|
-
] }) : groups.map((grp) => /* @__PURE__ */ (0, import_jsx_runtime63.jsxs)(
|
|
5712
|
+
] }) : groups.map((grp) => /* @__PURE__ */ (0, import_jsx_runtime63.jsxs)(React35.Fragment, { children: [
|
|
5640
5713
|
grp.g ? /* @__PURE__ */ (0, import_jsx_runtime63.jsx)("div", { className: "fd-pop-group", children: grp.g }) : null,
|
|
5641
5714
|
grp.items.map(({ o, i }) => /* @__PURE__ */ (0, import_jsx_runtime63.jsxs)(
|
|
5642
5715
|
"button",
|
|
@@ -5646,8 +5719,8 @@ function Select({
|
|
|
5646
5719
|
role: "option",
|
|
5647
5720
|
"aria-selected": isOn(o.value),
|
|
5648
5721
|
"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),
|
|
5722
|
+
className: ["fd-opt", i === nav.active ? "is-active" : "", isOn(o.value) ? "is-selected" : ""].filter(Boolean).join(" "),
|
|
5723
|
+
onMouseEnter: () => nav.setActive(i),
|
|
5651
5724
|
onClick: () => pick(o),
|
|
5652
5725
|
children: [
|
|
5653
5726
|
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 +5746,7 @@ function Select({
|
|
|
5673
5746
|
}
|
|
5674
5747
|
|
|
5675
5748
|
// src/components/forms/TimePicker.tsx
|
|
5676
|
-
var
|
|
5749
|
+
var React36 = __toESM(require("react"), 1);
|
|
5677
5750
|
var import_jsx_runtime64 = require("react/jsx-runtime");
|
|
5678
5751
|
var pad = (n) => String(n).padStart(2, "0");
|
|
5679
5752
|
function ClockFace({ value = "09:00", onChange }) {
|
|
@@ -5682,9 +5755,9 @@ function ClockFace({ value = "09:00", onChange }) {
|
|
|
5682
5755
|
if (isNaN(m)) m = 0;
|
|
5683
5756
|
const pm = h24 >= 12;
|
|
5684
5757
|
const h12 = h24 % 12 === 0 ? 12 : h24 % 12;
|
|
5685
|
-
const [mode2, setMode] =
|
|
5686
|
-
const faceRef =
|
|
5687
|
-
const dragging =
|
|
5758
|
+
const [mode2, setMode] = React36.useState("h");
|
|
5759
|
+
const faceRef = React36.useRef(null);
|
|
5760
|
+
const dragging = React36.useRef(false);
|
|
5688
5761
|
const set = (h, mm, isPm) => onChange((isPm ? h % 12 + 12 : h % 12) + ":" + pad(mm));
|
|
5689
5762
|
const R = 108, NR = 80;
|
|
5690
5763
|
const nums = mode2 === "h" ? Array.from({ length: 12 }, (_, i) => i + 1) : Array.from({ length: 12 }, (_, i) => i * 5);
|
|
@@ -5757,9 +5830,9 @@ function ClockFace({ value = "09:00", onChange }) {
|
|
|
5757
5830
|
}
|
|
5758
5831
|
function TimePicker({ label, help, error, required = false, disabled = false, value = "", onChange, placeholder = "Pick a time", id, className = "", style }) {
|
|
5759
5832
|
const { fieldId, labelId, ariaLabelledBy } = useTriggerLabelling(label, id);
|
|
5760
|
-
const [open, setOpen] =
|
|
5761
|
-
const rootRef =
|
|
5762
|
-
const boxRef =
|
|
5833
|
+
const [open, setOpen] = React36.useState(false);
|
|
5834
|
+
const rootRef = React36.useRef(null);
|
|
5835
|
+
const boxRef = React36.useRef(null);
|
|
5763
5836
|
const disp = () => {
|
|
5764
5837
|
if (!value) return "";
|
|
5765
5838
|
const [h, m] = value.split(":").map(Number);
|
|
@@ -5802,7 +5875,7 @@ function TimePicker({ label, help, error, required = false, disabled = false, va
|
|
|
5802
5875
|
offset: 6,
|
|
5803
5876
|
width: 262,
|
|
5804
5877
|
role: "presentation",
|
|
5805
|
-
footer: /* @__PURE__ */ (0, import_jsx_runtime64.jsxs)(
|
|
5878
|
+
footer: /* @__PURE__ */ (0, import_jsx_runtime64.jsxs)(React36.Fragment, { children: [
|
|
5806
5879
|
/* @__PURE__ */ (0, import_jsx_runtime64.jsx)(
|
|
5807
5880
|
"button",
|
|
5808
5881
|
{
|
|
@@ -5830,7 +5903,7 @@ function TimePicker({ label, help, error, required = false, disabled = false, va
|
|
|
5830
5903
|
}
|
|
5831
5904
|
|
|
5832
5905
|
// src/components/forms/Slider.tsx
|
|
5833
|
-
var
|
|
5906
|
+
var React37 = __toESM(require("react"), 1);
|
|
5834
5907
|
var import_jsx_runtime65 = require("react/jsx-runtime");
|
|
5835
5908
|
function Slider({
|
|
5836
5909
|
label,
|
|
@@ -5848,7 +5921,7 @@ function Slider({
|
|
|
5848
5921
|
...rest
|
|
5849
5922
|
}) {
|
|
5850
5923
|
const fieldId = useFieldId(id);
|
|
5851
|
-
const [dragging, setDragging] =
|
|
5924
|
+
const [dragging, setDragging] = React37.useState(false);
|
|
5852
5925
|
const v = value === void 0 ? min : Number(value);
|
|
5853
5926
|
const pct = max === min ? 0 : (v - min) / (max - min) * 100;
|
|
5854
5927
|
return /* @__PURE__ */ (0, import_jsx_runtime65.jsxs)("div", { className: ["fd-field", className].filter(Boolean).join(" "), children: [
|
|
@@ -5882,7 +5955,7 @@ function Slider({
|
|
|
5882
5955
|
}
|
|
5883
5956
|
|
|
5884
5957
|
// src/components/forms/RangeSlider.tsx
|
|
5885
|
-
var
|
|
5958
|
+
var React38 = __toESM(require("react"), 1);
|
|
5886
5959
|
var import_jsx_runtime66 = require("react/jsx-runtime");
|
|
5887
5960
|
function RangeSlider({
|
|
5888
5961
|
label,
|
|
@@ -5902,9 +5975,9 @@ function RangeSlider({
|
|
|
5902
5975
|
}) {
|
|
5903
5976
|
const fmt2 = format || ((v) => String(v));
|
|
5904
5977
|
const [a, b] = value || [min, max];
|
|
5905
|
-
const [drag, setDrag] =
|
|
5906
|
-
const [focus, setFocus] =
|
|
5907
|
-
const railRef =
|
|
5978
|
+
const [drag, setDrag] = React38.useState(null);
|
|
5979
|
+
const [focus, setFocus] = React38.useState(null);
|
|
5980
|
+
const railRef = React38.useRef(null);
|
|
5908
5981
|
const pct = (v) => max === min ? 0 : (v - min) / (max - min) * 100;
|
|
5909
5982
|
const clampPair = (i, v) => {
|
|
5910
5983
|
v = Math.min(max, Math.max(min, Math.round(v / step) * step));
|
|
@@ -5919,7 +5992,7 @@ function RangeSlider({
|
|
|
5919
5992
|
const r = railRef.current.getBoundingClientRect();
|
|
5920
5993
|
return min + Math.min(1, Math.max(0, (e.clientX - r.left) / r.width)) * (max - min);
|
|
5921
5994
|
};
|
|
5922
|
-
|
|
5995
|
+
React38.useEffect(() => {
|
|
5923
5996
|
if (drag === null) return;
|
|
5924
5997
|
const mv = (e) => onChange && onChange(clampPair(drag, fromEvent(e)));
|
|
5925
5998
|
const upH = () => setDrag(null);
|
|
@@ -6000,7 +6073,7 @@ function RangeSlider({
|
|
|
6000
6073
|
/* @__PURE__ */ (0, import_jsx_runtime66.jsxs)("div", { className: "fd-range" + (hasLabels ? " has-labels" : ""), onPointerDown: onRailDown, children: [
|
|
6001
6074
|
/* @__PURE__ */ (0, import_jsx_runtime66.jsx)("span", { className: "fd-range-rail", ref: railRef }),
|
|
6002
6075
|
/* @__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)(
|
|
6076
|
+
marks.map((m) => /* @__PURE__ */ (0, import_jsx_runtime66.jsxs)(React38.Fragment, { children: [
|
|
6004
6077
|
/* @__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
6078
|
m.label ? /* @__PURE__ */ (0, import_jsx_runtime66.jsx)("span", { className: "fd-range-mark-label", style: { left: pct(m.value) + "%" }, children: m.label }) : null
|
|
6006
6079
|
] }, m.value)),
|
|
@@ -6029,7 +6102,7 @@ function RangeSlider({
|
|
|
6029
6102
|
}
|
|
6030
6103
|
|
|
6031
6104
|
// src/components/forms/Dropzone.tsx
|
|
6032
|
-
var
|
|
6105
|
+
var React39 = __toESM(require("react"), 1);
|
|
6033
6106
|
var import_jsx_runtime67 = require("react/jsx-runtime");
|
|
6034
6107
|
function Dropzone({
|
|
6035
6108
|
onFiles,
|
|
@@ -6044,8 +6117,8 @@ function Dropzone({
|
|
|
6044
6117
|
className = "",
|
|
6045
6118
|
style
|
|
6046
6119
|
}) {
|
|
6047
|
-
const [over, setOver] =
|
|
6048
|
-
const depth =
|
|
6120
|
+
const [over, setOver] = React39.useState(false);
|
|
6121
|
+
const depth = React39.useRef(0);
|
|
6049
6122
|
const has = (e) => {
|
|
6050
6123
|
const dt = e.dataTransfer;
|
|
6051
6124
|
if (!dt) return false;
|
|
@@ -6107,8 +6180,8 @@ function FilePickButton({
|
|
|
6107
6180
|
className = "",
|
|
6108
6181
|
children
|
|
6109
6182
|
}) {
|
|
6110
|
-
const ref =
|
|
6111
|
-
return /* @__PURE__ */ (0, import_jsx_runtime67.jsxs)(
|
|
6183
|
+
const ref = React39.useRef(null);
|
|
6184
|
+
return /* @__PURE__ */ (0, import_jsx_runtime67.jsxs)(React39.Fragment, { children: [
|
|
6112
6185
|
/* @__PURE__ */ (0, import_jsx_runtime67.jsx)(
|
|
6113
6186
|
"button",
|
|
6114
6187
|
{
|
|
@@ -6141,10 +6214,10 @@ function FilePickButton({
|
|
|
6141
6214
|
}
|
|
6142
6215
|
function useStagedFiles(upload, opts) {
|
|
6143
6216
|
const o = opts || {};
|
|
6144
|
-
const [items, setItems] =
|
|
6145
|
-
const controllers =
|
|
6217
|
+
const [items, setItems] = React39.useState([]);
|
|
6218
|
+
const controllers = React39.useRef({});
|
|
6146
6219
|
const patch = (id, next) => setItems((list) => list.map((f) => f.id === id ? Object.assign({}, f, next) : f));
|
|
6147
|
-
const run =
|
|
6220
|
+
const run = React39.useCallback((att) => {
|
|
6148
6221
|
if (!upload) return;
|
|
6149
6222
|
const ac = typeof AbortController !== "undefined" ? new AbortController() : null;
|
|
6150
6223
|
controllers.current[att.id] = ac;
|
|
@@ -6161,14 +6234,14 @@ function useStagedFiles(upload, opts) {
|
|
|
6161
6234
|
delete controllers.current[att.id];
|
|
6162
6235
|
});
|
|
6163
6236
|
}, [upload]);
|
|
6164
|
-
const add =
|
|
6237
|
+
const add = React39.useCallback((files) => {
|
|
6165
6238
|
if (!upload) return [];
|
|
6166
6239
|
const atts = Array.from(files).map((f) => toAttachment(f));
|
|
6167
6240
|
setItems((list) => list.concat(atts));
|
|
6168
6241
|
atts.forEach(run);
|
|
6169
6242
|
return atts;
|
|
6170
6243
|
}, [upload, run]);
|
|
6171
|
-
const remove =
|
|
6244
|
+
const remove = React39.useCallback((att) => {
|
|
6172
6245
|
const ac = controllers.current[att.id];
|
|
6173
6246
|
if (ac) {
|
|
6174
6247
|
try {
|
|
@@ -6179,10 +6252,10 @@ function useStagedFiles(upload, opts) {
|
|
|
6179
6252
|
}
|
|
6180
6253
|
setItems((list) => list.filter((f) => f.id !== att.id));
|
|
6181
6254
|
}, []);
|
|
6182
|
-
const retry =
|
|
6255
|
+
const retry = React39.useCallback((att) => {
|
|
6183
6256
|
run(att);
|
|
6184
6257
|
}, [run]);
|
|
6185
|
-
const clear =
|
|
6258
|
+
const clear = React39.useCallback(() => {
|
|
6186
6259
|
Object.values(controllers.current).forEach((ac) => {
|
|
6187
6260
|
try {
|
|
6188
6261
|
ac && ac.abort();
|
|
@@ -6306,7 +6379,7 @@ function FileGrid({ files = [], onOpen, onRemove, onRetry, tiles = true, maxHeig
|
|
|
6306
6379
|
}
|
|
6307
6380
|
|
|
6308
6381
|
// src/components/forms/MarkdownEditor.tsx
|
|
6309
|
-
var
|
|
6382
|
+
var React40 = __toESM(require("react"), 1);
|
|
6310
6383
|
var import_jsx_runtime69 = require("react/jsx-runtime");
|
|
6311
6384
|
var isMac = typeof navigator !== "undefined" && /Mac|iPhone|iPad/.test(navigator.platform || navigator.userAgent || "");
|
|
6312
6385
|
var INLINE_RE = /(\*\*\*[^*\n]+\*\*\*|\*\*[^*\n]+\*\*|__[^_\n]+__|~~[^~\n]+~~|`[^`\n]+`|\*[^*\s][^*\n]*\*|(?<![A-Za-z0-9_])_[^_\s][^_\n]*_|\[[^\]\n]*\]\([^)\s\n]*\)|https?:\/\/\S+)/g;
|
|
@@ -6520,7 +6593,7 @@ function syncDom(root, value) {
|
|
|
6520
6593
|
while (root.children.length > lines.length) root.removeChild(root.lastChild);
|
|
6521
6594
|
}
|
|
6522
6595
|
var LIST_CONT = RE_LI;
|
|
6523
|
-
var MarkdownEditor =
|
|
6596
|
+
var MarkdownEditor = React40.forwardRef(function MarkdownEditor2({
|
|
6524
6597
|
value = "",
|
|
6525
6598
|
onChange,
|
|
6526
6599
|
onSubmit,
|
|
@@ -6539,10 +6612,10 @@ var MarkdownEditor = React39.forwardRef(function MarkdownEditor2({
|
|
|
6539
6612
|
className = "",
|
|
6540
6613
|
id
|
|
6541
6614
|
}, ref) {
|
|
6542
|
-
const boxRef =
|
|
6543
|
-
const composing =
|
|
6544
|
-
const pendingCaret =
|
|
6545
|
-
|
|
6615
|
+
const boxRef = React40.useRef(null);
|
|
6616
|
+
const composing = React40.useRef(false);
|
|
6617
|
+
const pendingCaret = React40.useRef(null);
|
|
6618
|
+
React40.useLayoutEffect(() => {
|
|
6546
6619
|
const root = boxRef.current;
|
|
6547
6620
|
if (!root || composing.current) return;
|
|
6548
6621
|
const active = document.activeElement === root || root.contains(document.activeElement);
|
|
@@ -6551,7 +6624,7 @@ var MarkdownEditor = React39.forwardRef(function MarkdownEditor2({
|
|
|
6551
6624
|
pendingCaret.current = null;
|
|
6552
6625
|
if (active && caret != null) placeCaret(root, caret);
|
|
6553
6626
|
}, [value]);
|
|
6554
|
-
|
|
6627
|
+
React40.useEffect(() => {
|
|
6555
6628
|
if (autoFocus && boxRef.current) boxRef.current.focus();
|
|
6556
6629
|
}, [autoFocus]);
|
|
6557
6630
|
const caretNow = () => {
|
|
@@ -6618,7 +6691,7 @@ var MarkdownEditor = React39.forwardRef(function MarkdownEditor2({
|
|
|
6618
6691
|
api.replaceRange(from, to, next, from + next.length);
|
|
6619
6692
|
}
|
|
6620
6693
|
};
|
|
6621
|
-
|
|
6694
|
+
React40.useImperativeHandle(ref, () => api);
|
|
6622
6695
|
function detect(text, caret) {
|
|
6623
6696
|
if (!onTrigger) return;
|
|
6624
6697
|
const upto = text.slice(0, caret);
|
|
@@ -6770,16 +6843,16 @@ var MarkdownEditor = React39.forwardRef(function MarkdownEditor2({
|
|
|
6770
6843
|
});
|
|
6771
6844
|
|
|
6772
6845
|
// src/components/platform/AccountMenu.tsx
|
|
6773
|
-
var
|
|
6846
|
+
var React42 = __toESM(require("react"), 1);
|
|
6774
6847
|
|
|
6775
6848
|
// src/kits/sessionContext.tsx
|
|
6776
|
-
var
|
|
6777
|
-
var SessionContext =
|
|
6849
|
+
var React41 = __toESM(require("react"), 1);
|
|
6850
|
+
var SessionContext = React41.createContext(null);
|
|
6778
6851
|
function SessionProvider({ value, children }) {
|
|
6779
|
-
return
|
|
6852
|
+
return React41.createElement(SessionContext.Provider, { value }, children);
|
|
6780
6853
|
}
|
|
6781
6854
|
function useSessionContext() {
|
|
6782
|
-
const ctx =
|
|
6855
|
+
const ctx = React41.useContext(SessionContext);
|
|
6783
6856
|
if (!ctx) {
|
|
6784
6857
|
throw new Error(
|
|
6785
6858
|
"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 +6892,11 @@ function AccountMenu({
|
|
|
6819
6892
|
...rest
|
|
6820
6893
|
}) {
|
|
6821
6894
|
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 =
|
|
6895
|
+
const [open, setOpen] = React42.useState(false);
|
|
6896
|
+
const [switching, setSwitching] = React42.useState(false);
|
|
6897
|
+
const [signingOut, setSigningOut] = React42.useState(false);
|
|
6898
|
+
const [signOutError, setSignOutError] = React42.useState(null);
|
|
6899
|
+
const ref = React42.useRef(null);
|
|
6827
6900
|
const visibleLinks = links.filter((l) => !l.perm || can2(l.perm));
|
|
6828
6901
|
const visibleGroups = groups.map((g) => ({ label: g.label, links: g.links.filter((l) => !l.perm || can2(l.perm)) })).filter((g) => g.links.length);
|
|
6829
6902
|
const closeMenu = () => {
|
|
@@ -6948,13 +7021,13 @@ function AccountMenu({
|
|
|
6948
7021
|
}
|
|
6949
7022
|
|
|
6950
7023
|
// src/components/platform/AppSwitcher.tsx
|
|
6951
|
-
var
|
|
7024
|
+
var React43 = __toESM(require("react"), 1);
|
|
6952
7025
|
var import_jsx_runtime71 = require("react/jsx-runtime");
|
|
6953
7026
|
function AppSwitcher({ apps: appsProp, onNavigate, className = "" }) {
|
|
6954
7027
|
const { apps: contextApps } = useSessionContext();
|
|
6955
7028
|
const apps = appsProp ?? contextApps ?? [];
|
|
6956
|
-
const [open, setOpen] =
|
|
6957
|
-
const anchorRef =
|
|
7029
|
+
const [open, setOpen] = React43.useState(false);
|
|
7030
|
+
const anchorRef = React43.useRef(null);
|
|
6958
7031
|
if (!apps.length) return null;
|
|
6959
7032
|
const items = apps.map((app) => ({
|
|
6960
7033
|
id: app.key,
|
|
@@ -6968,7 +7041,7 @@ function AppSwitcher({ apps: appsProp, onNavigate, className = "" }) {
|
|
|
6968
7041
|
window.location.href = app.url;
|
|
6969
7042
|
}
|
|
6970
7043
|
}));
|
|
6971
|
-
return /* @__PURE__ */ (0, import_jsx_runtime71.jsxs)(
|
|
7044
|
+
return /* @__PURE__ */ (0, import_jsx_runtime71.jsxs)(React43.Fragment, { children: [
|
|
6972
7045
|
/* @__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
7046
|
IconButton,
|
|
6974
7047
|
{
|
|
@@ -6997,10 +7070,10 @@ function AppSwitcher({ apps: appsProp, onNavigate, className = "" }) {
|
|
|
6997
7070
|
}
|
|
6998
7071
|
|
|
6999
7072
|
// src/components/platform/AppearanceMenu.tsx
|
|
7000
|
-
var
|
|
7073
|
+
var React45 = __toESM(require("react"), 1);
|
|
7001
7074
|
|
|
7002
7075
|
// src/kits/appearance.ts
|
|
7003
|
-
var
|
|
7076
|
+
var React44 = __toESM(require("react"), 1);
|
|
7004
7077
|
var DEFAULT_STORAGE_KEY = "fd-appearance";
|
|
7005
7078
|
var DEFAULT_PREFS = {
|
|
7006
7079
|
theme: "system",
|
|
@@ -7095,11 +7168,11 @@ function applyPrefs(prefs, root = document.documentElement) {
|
|
|
7095
7168
|
else root.removeAttribute("data-motion");
|
|
7096
7169
|
}
|
|
7097
7170
|
function useAppearancePrefs(store) {
|
|
7098
|
-
const prefs =
|
|
7099
|
-
|
|
7171
|
+
const prefs = React44.useSyncExternalStore(store.subscribe, store.getSnapshot);
|
|
7172
|
+
React44.useEffect(() => {
|
|
7100
7173
|
applyPrefs(prefs);
|
|
7101
7174
|
}, [prefs]);
|
|
7102
|
-
|
|
7175
|
+
React44.useEffect(() => {
|
|
7103
7176
|
if (prefs.theme !== "system" || typeof window === "undefined" || typeof window.matchMedia !== "function") {
|
|
7104
7177
|
return;
|
|
7105
7178
|
}
|
|
@@ -7108,7 +7181,7 @@ function useAppearancePrefs(store) {
|
|
|
7108
7181
|
mq.addEventListener("change", onChange);
|
|
7109
7182
|
return () => mq.removeEventListener("change", onChange);
|
|
7110
7183
|
}, [prefs]);
|
|
7111
|
-
const update =
|
|
7184
|
+
const update = React44.useCallback(
|
|
7112
7185
|
(patch) => {
|
|
7113
7186
|
store.write({ ...store.getSnapshot(), ...patch });
|
|
7114
7187
|
},
|
|
@@ -7131,15 +7204,15 @@ var TEXT_SCALE_OPTIONS = [
|
|
|
7131
7204
|
{ value: "xl", label: "XL" }
|
|
7132
7205
|
];
|
|
7133
7206
|
function AppearanceMenu({ className = "", store: storeProp, storageKey, storage, defaults }) {
|
|
7134
|
-
const store =
|
|
7207
|
+
const store = React45.useMemo(
|
|
7135
7208
|
() => storeProp ?? createLocalStorageAppearanceStore({ storageKey, storage, defaults }),
|
|
7136
7209
|
[storeProp, storageKey, storage, defaults]
|
|
7137
7210
|
);
|
|
7138
7211
|
const [prefs, update] = useAppearancePrefs(store);
|
|
7139
|
-
const [open, setOpen] =
|
|
7140
|
-
const anchorRef =
|
|
7212
|
+
const [open, setOpen] = React45.useState(false);
|
|
7213
|
+
const anchorRef = React45.useRef(null);
|
|
7141
7214
|
const patch = (p) => update(p);
|
|
7142
|
-
return /* @__PURE__ */ (0, import_jsx_runtime72.jsxs)(
|
|
7215
|
+
return /* @__PURE__ */ (0, import_jsx_runtime72.jsxs)(React45.Fragment, { children: [
|
|
7143
7216
|
/* @__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
7217
|
IconButton,
|
|
7145
7218
|
{
|
|
@@ -7208,14 +7281,14 @@ function AppearanceMenu({ className = "", store: storeProp, storageKey, storage,
|
|
|
7208
7281
|
}
|
|
7209
7282
|
|
|
7210
7283
|
// src/components/platform/ApiSpecBrowser.tsx
|
|
7211
|
-
var
|
|
7284
|
+
var React46 = __toESM(require("react"), 1);
|
|
7212
7285
|
var import_jsx_runtime73 = require("react/jsx-runtime");
|
|
7213
7286
|
var METHOD_TONE = { GET: "success", POST: "info", PATCH: "warning", PUT: "warning", DELETE: "danger" };
|
|
7214
7287
|
function Json({ obj }) {
|
|
7215
7288
|
return /* @__PURE__ */ (0, import_jsx_runtime73.jsx)("pre", { className: "fd-json", children: JSON.stringify(obj, null, 2) });
|
|
7216
7289
|
}
|
|
7217
7290
|
function Endpoint({ s, onRequest }) {
|
|
7218
|
-
const [tried, setTried] =
|
|
7291
|
+
const [tried, setTried] = React46.useState(null);
|
|
7219
7292
|
const run = async () => {
|
|
7220
7293
|
setTried("busy");
|
|
7221
7294
|
const t0 = (window.performance || Date).now();
|
|
@@ -7288,10 +7361,10 @@ function ApiSpecBrowser({
|
|
|
7288
7361
|
className = "",
|
|
7289
7362
|
...rest
|
|
7290
7363
|
}) {
|
|
7291
|
-
const [q, setQ] =
|
|
7292
|
-
const [method, setMethod] =
|
|
7293
|
-
const [mod, setMod] =
|
|
7294
|
-
const [listOnly, setListOnly] =
|
|
7364
|
+
const [q, setQ] = React46.useState("");
|
|
7365
|
+
const [method, setMethod] = React46.useState(null);
|
|
7366
|
+
const [mod, setMod] = React46.useState(null);
|
|
7367
|
+
const [listOnly, setListOnly] = React46.useState(false);
|
|
7295
7368
|
const activeModule = modules && modules.find((m) => m.id === mod);
|
|
7296
7369
|
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
7370
|
const effGroups = groups && groups.length ? groups : [["All endpoints", spec.map((s) => s.id)]];
|
|
@@ -7370,7 +7443,7 @@ function ApiSpecBrowser({
|
|
|
7370
7443
|
}
|
|
7371
7444
|
|
|
7372
7445
|
// src/components/platform/ProfilePage.tsx
|
|
7373
|
-
var
|
|
7446
|
+
var React47 = __toESM(require("react"), 1);
|
|
7374
7447
|
var import_jsx_runtime74 = require("react/jsx-runtime");
|
|
7375
7448
|
function fieldInitialValue(field, user) {
|
|
7376
7449
|
if (field.value) return field.value(user);
|
|
@@ -7406,21 +7479,21 @@ function ProfilePage({
|
|
|
7406
7479
|
}) {
|
|
7407
7480
|
const { user: sessionUser, roles, permissions, saveProfile: saveProfile2 } = useSessionContext();
|
|
7408
7481
|
const user = userProp || sessionUser;
|
|
7409
|
-
const initialFieldValues =
|
|
7482
|
+
const initialFieldValues = React47.useMemo(() => {
|
|
7410
7483
|
const values2 = {};
|
|
7411
7484
|
for (const field of fields) values2[field.key] = fieldInitialValue(field, user);
|
|
7412
7485
|
return values2;
|
|
7413
7486
|
}, [user.id, fields]);
|
|
7414
|
-
const initialNotify =
|
|
7487
|
+
const initialNotify = React47.useMemo(() => {
|
|
7415
7488
|
const values2 = {};
|
|
7416
7489
|
for (const n of notifications) values2[n.key] = !!user.notify?.[n.key];
|
|
7417
7490
|
return values2;
|
|
7418
7491
|
}, [user.id, notifications]);
|
|
7419
|
-
const [values, setValues] =
|
|
7420
|
-
const [notify, setNotify] =
|
|
7421
|
-
const [saving, setSaving] =
|
|
7422
|
-
const [saved, setSaved] =
|
|
7423
|
-
const [prevUserId, setPrevUserId] =
|
|
7492
|
+
const [values, setValues] = React47.useState(initialFieldValues);
|
|
7493
|
+
const [notify, setNotify] = React47.useState(initialNotify);
|
|
7494
|
+
const [saving, setSaving] = React47.useState(false);
|
|
7495
|
+
const [saved, setSaved] = React47.useState(false);
|
|
7496
|
+
const [prevUserId, setPrevUserId] = React47.useState(user.id);
|
|
7424
7497
|
if (user.id !== prevUserId) {
|
|
7425
7498
|
setPrevUserId(user.id);
|
|
7426
7499
|
setValues(initialFieldValues);
|
|
@@ -7608,11 +7681,11 @@ function ProfilePage({
|
|
|
7608
7681
|
}
|
|
7609
7682
|
|
|
7610
7683
|
// src/components/platform/SignInPage.tsx
|
|
7611
|
-
var
|
|
7684
|
+
var React48 = __toESM(require("react"), 1);
|
|
7612
7685
|
var import_jsx_runtime75 = require("react/jsx-runtime");
|
|
7613
7686
|
function SignInPage({ productName, onSignIn, continueAs, error }) {
|
|
7614
|
-
const [signingIn, setSigningIn] =
|
|
7615
|
-
const [resuming, setResuming] =
|
|
7687
|
+
const [signingIn, setSigningIn] = React48.useState(false);
|
|
7688
|
+
const [resuming, setResuming] = React48.useState(false);
|
|
7616
7689
|
function handleSignIn() {
|
|
7617
7690
|
setSigningIn(true);
|
|
7618
7691
|
onSignIn();
|
|
@@ -7801,10 +7874,10 @@ function GoogleGlyph() {
|
|
|
7801
7874
|
}
|
|
7802
7875
|
|
|
7803
7876
|
// src/components/platform/RoadmapTimeline.tsx
|
|
7804
|
-
var
|
|
7877
|
+
var React51 = __toESM(require("react"), 1);
|
|
7805
7878
|
|
|
7806
7879
|
// src/kits/session.ts
|
|
7807
|
-
var
|
|
7880
|
+
var React49 = __toESM(require("react"), 1);
|
|
7808
7881
|
var PERMISSION_CATALOG = [
|
|
7809
7882
|
{ group: "Plans", items: [
|
|
7810
7883
|
{ key: "plan.view", label: "View plans", detail: "Read any plan in the workspace." },
|
|
@@ -9371,8 +9444,8 @@ function roadmap(overrides) {
|
|
|
9371
9444
|
};
|
|
9372
9445
|
}
|
|
9373
9446
|
function useSession() {
|
|
9374
|
-
const [s, setS] =
|
|
9375
|
-
|
|
9447
|
+
const [s, setS] = React49.useState(getSession);
|
|
9448
|
+
React49.useEffect(() => subscribe(setS), []);
|
|
9376
9449
|
return s;
|
|
9377
9450
|
}
|
|
9378
9451
|
var SessionKit = {
|
|
@@ -9405,7 +9478,7 @@ var SessionKit = {
|
|
|
9405
9478
|
};
|
|
9406
9479
|
function DemoSessionProvider({ children }) {
|
|
9407
9480
|
const session = useSession();
|
|
9408
|
-
const value =
|
|
9481
|
+
const value = React49.useMemo(
|
|
9409
9482
|
() => ({
|
|
9410
9483
|
user: session.user,
|
|
9411
9484
|
roles: session.roles,
|
|
@@ -9421,11 +9494,11 @@ function DemoSessionProvider({ children }) {
|
|
|
9421
9494
|
}),
|
|
9422
9495
|
[session]
|
|
9423
9496
|
);
|
|
9424
|
-
return
|
|
9497
|
+
return React49.createElement(SessionProvider, { value }, children);
|
|
9425
9498
|
}
|
|
9426
9499
|
|
|
9427
9500
|
// src/kits/runtime.ts
|
|
9428
|
-
var
|
|
9501
|
+
var React50 = __toESM(require("react"), 1);
|
|
9429
9502
|
var WIRED_ENDPOINTS = [
|
|
9430
9503
|
// Nothing yet. Every id below would come from a real service:
|
|
9431
9504
|
// "plan.get", "placements.list", …
|
|
@@ -9596,8 +9669,8 @@ var RuntimeKit = {
|
|
|
9596
9669
|
};
|
|
9597
9670
|
RuntimeKit.declare(FEATURE_NEEDS);
|
|
9598
9671
|
function useRuntimeMode() {
|
|
9599
|
-
const [m, setM] =
|
|
9600
|
-
|
|
9672
|
+
const [m, setM] = React50.useState(RuntimeKit.getMode());
|
|
9673
|
+
React50.useEffect(() => RuntimeKit.subscribe(setM), []);
|
|
9601
9674
|
return m;
|
|
9602
9675
|
}
|
|
9603
9676
|
function useFeatureStatus(key) {
|
|
@@ -9680,12 +9753,12 @@ function RoadmapCard({ item, byKey, onOpenFlag }) {
|
|
|
9680
9753
|
}
|
|
9681
9754
|
function RoadmapTimeline({ onOpenFlag, title = "Roadmap", lede }) {
|
|
9682
9755
|
const session = SessionKit.useSession();
|
|
9683
|
-
const [project, setProject] =
|
|
9684
|
-
const [q, setQ] =
|
|
9685
|
-
const scrollRef =
|
|
9686
|
-
const nowRef =
|
|
9687
|
-
const rm =
|
|
9688
|
-
const byKey =
|
|
9756
|
+
const [project, setProject] = React51.useState("");
|
|
9757
|
+
const [q, setQ] = React51.useState("");
|
|
9758
|
+
const scrollRef = React51.useRef(null);
|
|
9759
|
+
const nowRef = React51.useRef(null);
|
|
9760
|
+
const rm = React51.useMemo(() => SessionKit.roadmap({ isComplete: RuntimeKit.isComplete }), [session]);
|
|
9761
|
+
const byKey = React51.useMemo(() => {
|
|
9689
9762
|
const m = {};
|
|
9690
9763
|
rm.items.forEach((i) => {
|
|
9691
9764
|
m[i.key] = i;
|
|
@@ -9694,7 +9767,7 @@ function RoadmapTimeline({ onOpenFlag, title = "Roadmap", lede }) {
|
|
|
9694
9767
|
}, [rm]);
|
|
9695
9768
|
const items = rm.items.filter((i) => (!project || i.project === project) && (!q || (i.label + " " + i.description + " " + (i.backend || "") + " " + i.key).toLowerCase().includes(q.toLowerCase())));
|
|
9696
9769
|
const projects = [...new Set(rm.items.map((i) => i.project))];
|
|
9697
|
-
|
|
9770
|
+
React51.useEffect(() => {
|
|
9698
9771
|
let raf1 = 0, raf2 = 0;
|
|
9699
9772
|
const place = () => {
|
|
9700
9773
|
const box = scrollRef.current, mark = nowRef.current;
|
|
@@ -9768,7 +9841,7 @@ function RoadmapTimeline({ onOpenFlag, title = "Roadmap", lede }) {
|
|
|
9768
9841
|
lastPhase = item.phase;
|
|
9769
9842
|
const inPhase = items.filter((i) => i.phase === item.phase).length;
|
|
9770
9843
|
const isBoundary = n === firstPending;
|
|
9771
|
-
return /* @__PURE__ */ (0, import_jsx_runtime76.jsxs)(
|
|
9844
|
+
return /* @__PURE__ */ (0, import_jsx_runtime76.jsxs)(React51.Fragment, { children: [
|
|
9772
9845
|
showPhase ? /* @__PURE__ */ (0, import_jsx_runtime76.jsxs)("div", { className: "fd-rm-era", children: [
|
|
9773
9846
|
/* @__PURE__ */ (0, import_jsx_runtime76.jsxs)("span", { className: "fd-row", style: { gap: 8, flexWrap: "wrap", alignItems: "baseline" }, children: [
|
|
9774
9847
|
/* @__PURE__ */ (0, import_jsx_runtime76.jsx)("span", { style: { fontWeight: 700 }, children: item.phase === 0 ? "Shipped" : "Phase " + item.phase + " \u2014 " + item.phaseName }),
|
|
@@ -9812,7 +9885,7 @@ function RoadmapTimeline({ onOpenFlag, title = "Roadmap", lede }) {
|
|
|
9812
9885
|
}
|
|
9813
9886
|
|
|
9814
9887
|
// src/components/platform/ComingSoon.tsx
|
|
9815
|
-
var
|
|
9888
|
+
var React52 = __toESM(require("react"), 1);
|
|
9816
9889
|
var import_react_dom6 = require("react-dom");
|
|
9817
9890
|
var import_jsx_runtime77 = require("react/jsx-runtime");
|
|
9818
9891
|
var BYPASS_STORE = "fd.soon.bypass.v1";
|
|
@@ -9830,8 +9903,8 @@ function writeBypassed(list) {
|
|
|
9830
9903
|
}
|
|
9831
9904
|
}
|
|
9832
9905
|
function useBypass(key) {
|
|
9833
|
-
const [on, setOn] =
|
|
9834
|
-
|
|
9906
|
+
const [on, setOn] = React52.useState(() => !!key && readBypassed().indexOf(key) >= 0);
|
|
9907
|
+
React52.useEffect(() => {
|
|
9835
9908
|
setOn(!!key && readBypassed().indexOf(key) >= 0);
|
|
9836
9909
|
}, [key]);
|
|
9837
9910
|
const set = (next) => {
|
|
@@ -9878,9 +9951,9 @@ function SoonCard({ label, detail, backend, eta, effort, onRoadmap, allowed, onB
|
|
|
9878
9951
|
] });
|
|
9879
9952
|
}
|
|
9880
9953
|
function useHoverCard(open) {
|
|
9881
|
-
const anchor =
|
|
9882
|
-
const [pos, setPos] =
|
|
9883
|
-
|
|
9954
|
+
const anchor = React52.useRef(null);
|
|
9955
|
+
const [pos, setPos] = React52.useState(null);
|
|
9956
|
+
React52.useLayoutEffect(() => {
|
|
9884
9957
|
if (!open || !anchor.current) {
|
|
9885
9958
|
setPos(null);
|
|
9886
9959
|
return;
|
|
@@ -10007,10 +10080,10 @@ function ComingSoon({
|
|
|
10007
10080
|
] });
|
|
10008
10081
|
}
|
|
10009
10082
|
function InlineSoon({ label, detail, backend, eta, effort, onRoadmap, allowed, onBypass, blur, tip, className, rest, children }) {
|
|
10010
|
-
const [open, setOpen] =
|
|
10083
|
+
const [open, setOpen] = React52.useState(false);
|
|
10011
10084
|
const [anchor, pos] = useHoverCard(open);
|
|
10012
10085
|
const zIndex = useOverlayLayer(open);
|
|
10013
|
-
const close =
|
|
10086
|
+
const close = React52.useRef(null);
|
|
10014
10087
|
const show = () => {
|
|
10015
10088
|
if (close.current) {
|
|
10016
10089
|
clearTimeout(close.current);
|
|
@@ -10026,7 +10099,7 @@ function InlineSoon({ label, detail, backend, eta, effort, onRoadmap, allowed, o
|
|
|
10026
10099
|
setOpen(false);
|
|
10027
10100
|
}, 140);
|
|
10028
10101
|
};
|
|
10029
|
-
|
|
10102
|
+
React52.useEffect(() => () => {
|
|
10030
10103
|
if (close.current) clearTimeout(close.current);
|
|
10031
10104
|
}, []);
|
|
10032
10105
|
return /* @__PURE__ */ (0, import_jsx_runtime77.jsxs)(
|
|
@@ -10197,14 +10270,14 @@ function PermissionHint({ perm, children }) {
|
|
|
10197
10270
|
}
|
|
10198
10271
|
|
|
10199
10272
|
// src/components/platform/ModeSwitch.tsx
|
|
10200
|
-
var
|
|
10273
|
+
var React53 = __toESM(require("react"), 1);
|
|
10201
10274
|
var import_jsx_runtime79 = require("react/jsx-runtime");
|
|
10202
10275
|
function ModeSwitch({ canToggle = false, requestCount = 0, onClearLog, renderLog, onOpenSpec, summary }) {
|
|
10203
10276
|
const mode2 = useRuntimeMode();
|
|
10204
|
-
const [open, setOpen] =
|
|
10277
|
+
const [open, setOpen] = React53.useState(false);
|
|
10205
10278
|
const zIndex = useOverlayLayer(open);
|
|
10206
|
-
const ref =
|
|
10207
|
-
|
|
10279
|
+
const ref = React53.useRef(null);
|
|
10280
|
+
React53.useEffect(() => {
|
|
10208
10281
|
if (!open) return;
|
|
10209
10282
|
const away = (e) => {
|
|
10210
10283
|
if (ref.current && !ref.current.contains(e.target)) setOpen(false);
|
|
@@ -10460,7 +10533,7 @@ function SaturationDistribution({ campuses = [], floorBand, floorScore, onSelect
|
|
|
10460
10533
|
}
|
|
10461
10534
|
|
|
10462
10535
|
// src/components/planner/MixGap.tsx
|
|
10463
|
-
var
|
|
10536
|
+
var React54 = __toESM(require("react"), 1);
|
|
10464
10537
|
var import_jsx_runtime82 = require("react/jsx-runtime");
|
|
10465
10538
|
var MIX_GAP_LAYOUT = {
|
|
10466
10539
|
trackHeight: 30,
|
|
@@ -10475,7 +10548,7 @@ function mixGapOffset(value, max) {
|
|
|
10475
10548
|
}
|
|
10476
10549
|
function MixGap({ rows = [], loading = false, className = "" }) {
|
|
10477
10550
|
const max = Math.max(1, ...rows.flatMap((r) => [r.target, r.realized]));
|
|
10478
|
-
const [hover, setHover] =
|
|
10551
|
+
const [hover, setHover] = React54.useState(null);
|
|
10479
10552
|
const toneOf = (gap) => gap >= -1 ? "ok" : gap >= -4 ? "warn" : "danger";
|
|
10480
10553
|
const TONE = { ok: "var(--ok-solid)", warn: "var(--warn-solid)", danger: "var(--danger-solid)" };
|
|
10481
10554
|
const { trackHeight, barHeight, targetWidth, labelGap } = MIX_GAP_LAYOUT;
|
|
@@ -10618,7 +10691,7 @@ function ChannelContribution({
|
|
|
10618
10691
|
}
|
|
10619
10692
|
|
|
10620
10693
|
// src/components/planner/BudgetReallocator.tsx
|
|
10621
|
-
var
|
|
10694
|
+
var React55 = __toESM(require("react"), 1);
|
|
10622
10695
|
var import_jsx_runtime84 = require("react/jsx-runtime");
|
|
10623
10696
|
var bandFor = (crp) => crp >= 200 ? "dominant" : crp >= 100 ? "strong" : crp >= 50 ? "adequate" : "weak";
|
|
10624
10697
|
function BudgetReallocator({
|
|
@@ -10634,8 +10707,8 @@ function BudgetReallocator({
|
|
|
10634
10707
|
onCancel,
|
|
10635
10708
|
className = ""
|
|
10636
10709
|
}) {
|
|
10637
|
-
const [draft, setDraft] =
|
|
10638
|
-
|
|
10710
|
+
const [draft, setDraft] = React55.useState(spend);
|
|
10711
|
+
React55.useEffect(() => setDraft(spend), [spend]);
|
|
10639
10712
|
const dirty = draft !== spend;
|
|
10640
10713
|
const nextCrp = scoreFor ? scoreFor(draft) : crp;
|
|
10641
10714
|
const nextBand = bandFor(nextCrp);
|
|
@@ -10650,10 +10723,10 @@ function BudgetReallocator({
|
|
|
10650
10723
|
setDraft(spend);
|
|
10651
10724
|
if (onCancel) onCancel();
|
|
10652
10725
|
};
|
|
10653
|
-
const trackRef =
|
|
10654
|
-
const chipRef =
|
|
10655
|
-
const [chipLeft, setChipLeft] =
|
|
10656
|
-
|
|
10726
|
+
const trackRef = React55.useRef(null);
|
|
10727
|
+
const chipRef = React55.useRef(null);
|
|
10728
|
+
const [chipLeft, setChipLeft] = React55.useState(null);
|
|
10729
|
+
React55.useLayoutEffect(() => {
|
|
10657
10730
|
const track = trackRef.current;
|
|
10658
10731
|
if (!dirty || !track) {
|
|
10659
10732
|
setChipLeft(null);
|
|
@@ -10840,7 +10913,7 @@ function ImportanceTag({ level, showLabel = true, size = "sm", className = "" })
|
|
|
10840
10913
|
}
|
|
10841
10914
|
|
|
10842
10915
|
// src/components/planner/PreferenceMeter.tsx
|
|
10843
|
-
var
|
|
10916
|
+
var React56 = __toESM(require("react"), 1);
|
|
10844
10917
|
var import_jsx_runtime87 = require("react/jsx-runtime");
|
|
10845
10918
|
function preferenceScore(criteria) {
|
|
10846
10919
|
const earned = criteria.reduce((n, c) => n + (Number(c.earned) || 0), 0);
|
|
@@ -10870,7 +10943,7 @@ function PreferenceMeter({
|
|
|
10870
10943
|
className = ""
|
|
10871
10944
|
}) {
|
|
10872
10945
|
const value = score == null ? preferenceScore(criteria) : score;
|
|
10873
|
-
const segments =
|
|
10946
|
+
const segments = React56.useMemo(() => preferenceSegments(criteria), [criteria]);
|
|
10874
10947
|
return /* @__PURE__ */ (0, import_jsx_runtime87.jsx)(
|
|
10875
10948
|
ScoreMeter,
|
|
10876
10949
|
{
|
|
@@ -10909,10 +10982,10 @@ function PreferenceMeter({
|
|
|
10909
10982
|
}
|
|
10910
10983
|
|
|
10911
10984
|
// src/components/chat/AgentChatPanel.tsx
|
|
10912
|
-
var
|
|
10985
|
+
var React62 = __toESM(require("react"), 1);
|
|
10913
10986
|
|
|
10914
10987
|
// src/components/chat/chatEngine.ts
|
|
10915
|
-
var
|
|
10988
|
+
var React57 = __toESM(require("react"), 1);
|
|
10916
10989
|
var CHAT_UNAVAILABLE = "chat_unavailable";
|
|
10917
10990
|
var JOB_PENDING = ["queued", "running"];
|
|
10918
10991
|
var JOB_SUCCESS = ["completed", "recovered"];
|
|
@@ -10966,22 +11039,22 @@ function useChatEngine(opts) {
|
|
|
10966
11039
|
onClear,
|
|
10967
11040
|
onFeedback
|
|
10968
11041
|
} = 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
|
-
|
|
11042
|
+
const [status, setStatus] = React57.useState("idle");
|
|
11043
|
+
const [threadId, setThreadId] = React57.useState(null);
|
|
11044
|
+
const [messages, setMessages] = React57.useState([]);
|
|
11045
|
+
const [queue, setQueue] = React57.useState([]);
|
|
11046
|
+
const [fatal, setFatal] = React57.useState(null);
|
|
11047
|
+
const [busy, setBusy] = React57.useState(false);
|
|
11048
|
+
const [turnStartedAt, setTurnStartedAt] = React57.useState(null);
|
|
11049
|
+
const listRef = React57.useRef([]);
|
|
11050
|
+
const queueRef = React57.useRef([]);
|
|
11051
|
+
const busyRef = React57.useRef(false);
|
|
11052
|
+
const stoppedRef = React57.useRef(false);
|
|
11053
|
+
const abortRef = React57.useRef(null);
|
|
11054
|
+
const serverCount = React57.useRef(0);
|
|
11055
|
+
const threadRef = React57.useRef(null);
|
|
11056
|
+
const mounted = React57.useRef(true);
|
|
11057
|
+
React57.useEffect(() => {
|
|
10985
11058
|
mounted.current = true;
|
|
10986
11059
|
return () => {
|
|
10987
11060
|
mounted.current = false;
|
|
@@ -11003,14 +11076,14 @@ function useChatEngine(opts) {
|
|
|
11003
11076
|
}
|
|
11004
11077
|
return false;
|
|
11005
11078
|
};
|
|
11006
|
-
const loadThread =
|
|
11079
|
+
const loadThread = React57.useCallback(async (id) => {
|
|
11007
11080
|
const data = await apiAdapter.getThread(id);
|
|
11008
11081
|
const list = [...data && data.messages || []];
|
|
11009
11082
|
serverCount.current = list.length;
|
|
11010
11083
|
commit(list);
|
|
11011
11084
|
return list;
|
|
11012
11085
|
}, [apiAdapter]);
|
|
11013
|
-
|
|
11086
|
+
React57.useEffect(() => {
|
|
11014
11087
|
if (!apiAdapter) {
|
|
11015
11088
|
setStatus("idle");
|
|
11016
11089
|
setFatal(null);
|
|
@@ -11223,7 +11296,7 @@ function useChatEngine(opts) {
|
|
|
11223
11296
|
await dispatchTurn(turn);
|
|
11224
11297
|
}
|
|
11225
11298
|
}
|
|
11226
|
-
const send =
|
|
11299
|
+
const send = React57.useCallback((text, attachments) => {
|
|
11227
11300
|
const body = (text || "").trim();
|
|
11228
11301
|
if (!body && !(attachments && attachments.length)) return;
|
|
11229
11302
|
if (status === "disconnected") return;
|
|
@@ -11233,7 +11306,7 @@ function useChatEngine(opts) {
|
|
|
11233
11306
|
stoppedRef.current = false;
|
|
11234
11307
|
drain();
|
|
11235
11308
|
}, [status]);
|
|
11236
|
-
const stop =
|
|
11309
|
+
const stop = React57.useCallback(() => {
|
|
11237
11310
|
stoppedRef.current = true;
|
|
11238
11311
|
const ac = abortRef.current;
|
|
11239
11312
|
if (ac) {
|
|
@@ -11252,11 +11325,11 @@ function useChatEngine(opts) {
|
|
|
11252
11325
|
store.del(STORAGE_PREFIX + threadRef.current);
|
|
11253
11326
|
}
|
|
11254
11327
|
}, [apiAdapter]);
|
|
11255
|
-
const removeQueued =
|
|
11328
|
+
const removeQueued = React57.useCallback((id) => {
|
|
11256
11329
|
queueRef.current = queueRef.current.filter((t) => t.id !== id);
|
|
11257
11330
|
setQueue(queueRef.current.slice());
|
|
11258
11331
|
}, []);
|
|
11259
|
-
const retry =
|
|
11332
|
+
const retry = React57.useCallback(() => {
|
|
11260
11333
|
const list = listRef.current;
|
|
11261
11334
|
let at = -1;
|
|
11262
11335
|
for (let i = list.length - 1; i >= 0; i--) if (list[i].role === "user") {
|
|
@@ -11272,19 +11345,19 @@ function useChatEngine(opts) {
|
|
|
11272
11345
|
setQueue(queueRef.current.slice());
|
|
11273
11346
|
drain();
|
|
11274
11347
|
}, []);
|
|
11275
|
-
const clear =
|
|
11348
|
+
const clear = React57.useCallback(() => {
|
|
11276
11349
|
commit([]);
|
|
11277
11350
|
serverCount.current = 0;
|
|
11278
11351
|
queueRef.current = [];
|
|
11279
11352
|
setQueue([]);
|
|
11280
11353
|
onClear && onClear();
|
|
11281
11354
|
}, [onClear]);
|
|
11282
|
-
const setFeedback =
|
|
11355
|
+
const setFeedback = React57.useCallback((id, value) => {
|
|
11283
11356
|
patch(id, (m) => ({ feedback: m.feedback === value ? null : value }));
|
|
11284
11357
|
const msg = listRef.current.find((m) => m.id === id);
|
|
11285
11358
|
onFeedback && onFeedback({ message: msg, feedback: msg ? msg.feedback : value });
|
|
11286
11359
|
}, [onFeedback]);
|
|
11287
|
-
const reload =
|
|
11360
|
+
const reload = React57.useCallback(async () => {
|
|
11288
11361
|
if (!threadRef.current) return;
|
|
11289
11362
|
setStatus("loading");
|
|
11290
11363
|
try {
|
|
@@ -11322,10 +11395,10 @@ var ChatKit = {
|
|
|
11322
11395
|
};
|
|
11323
11396
|
|
|
11324
11397
|
// src/components/chat/ChatTranscript.tsx
|
|
11325
|
-
var
|
|
11398
|
+
var React59 = __toESM(require("react"), 1);
|
|
11326
11399
|
|
|
11327
11400
|
// src/components/chat/ChatTurn.tsx
|
|
11328
|
-
var
|
|
11401
|
+
var React58 = __toESM(require("react"), 1);
|
|
11329
11402
|
var import_jsx_runtime88 = require("react/jsx-runtime");
|
|
11330
11403
|
function JsonView({ value }) {
|
|
11331
11404
|
let text;
|
|
@@ -11362,7 +11435,7 @@ function PacketCard({ packet, schema, render, onApply, applied }) {
|
|
|
11362
11435
|
] });
|
|
11363
11436
|
}
|
|
11364
11437
|
function ThinkingBlock({ text, durationMs, streaming, defaultOpen = false }) {
|
|
11365
|
-
const [open, setOpen] =
|
|
11438
|
+
const [open, setOpen] = React58.useState(defaultOpen);
|
|
11366
11439
|
if (!text) return null;
|
|
11367
11440
|
return /* @__PURE__ */ (0, import_jsx_runtime88.jsxs)("div", { className: "fdc-think" + (open ? " is-open" : ""), children: [
|
|
11368
11441
|
/* @__PURE__ */ (0, import_jsx_runtime88.jsxs)("button", { type: "button", className: "fdc-think-head", onClick: () => setOpen((v) => !v), "aria-expanded": open, children: [
|
|
@@ -11379,7 +11452,7 @@ function ThinkingBlock({ text, durationMs, streaming, defaultOpen = false }) {
|
|
|
11379
11452
|
] });
|
|
11380
11453
|
}
|
|
11381
11454
|
function Citations({ items = [], onOpen }) {
|
|
11382
|
-
const [open, setOpen] =
|
|
11455
|
+
const [open, setOpen] = React58.useState(false);
|
|
11383
11456
|
if (!items.length) return null;
|
|
11384
11457
|
return /* @__PURE__ */ (0, import_jsx_runtime88.jsxs)("div", { className: "fdc-cites", children: [
|
|
11385
11458
|
/* @__PURE__ */ (0, import_jsx_runtime88.jsxs)("button", { type: "button", className: "fdc-cites-head", onClick: () => setOpen((v) => !v), "aria-expanded": open, children: [
|
|
@@ -11405,7 +11478,7 @@ function clampText(text, max) {
|
|
|
11405
11478
|
return (at > max * 0.6 ? cut.slice(0, at) : cut).trimEnd() + "\u2026";
|
|
11406
11479
|
}
|
|
11407
11480
|
function MessageBody({ message: m, ctx }) {
|
|
11408
|
-
const [expanded, setExpanded] =
|
|
11481
|
+
const [expanded, setExpanded] = React58.useState(false);
|
|
11409
11482
|
const isUser = m.role === "user";
|
|
11410
11483
|
const raw = m.text || "";
|
|
11411
11484
|
const clamped = !expanded && !m.streaming ? clampText(raw, ctx.maxVisibleChars) : null;
|
|
@@ -11472,9 +11545,9 @@ function MessageBody({ message: m, ctx }) {
|
|
|
11472
11545
|
] });
|
|
11473
11546
|
}
|
|
11474
11547
|
function useCopyRun() {
|
|
11475
|
-
const [done, setDone] =
|
|
11476
|
-
const t =
|
|
11477
|
-
|
|
11548
|
+
const [done, setDone] = React58.useState(false);
|
|
11549
|
+
const t = React58.useRef(null);
|
|
11550
|
+
React58.useEffect(() => () => {
|
|
11478
11551
|
if (t.current) clearTimeout(t.current);
|
|
11479
11552
|
}, []);
|
|
11480
11553
|
return [done, (text) => {
|
|
@@ -11501,7 +11574,7 @@ function RunActions({ group, ctx }) {
|
|
|
11501
11574
|
] }),
|
|
11502
11575
|
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
11576
|
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)(
|
|
11577
|
+
isAssistant && ctx.onFeedback ? /* @__PURE__ */ (0, import_jsx_runtime88.jsxs)(React58.Fragment, { children: [
|
|
11505
11578
|
/* @__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
11579
|
/* @__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
11580
|
] }) : null,
|
|
@@ -11596,10 +11669,10 @@ function ChatTranscript({
|
|
|
11596
11669
|
renderEmpty,
|
|
11597
11670
|
className = ""
|
|
11598
11671
|
}) {
|
|
11599
|
-
const scroller =
|
|
11600
|
-
const stick =
|
|
11601
|
-
const [pill, setPill] =
|
|
11602
|
-
const seen =
|
|
11672
|
+
const scroller = React59.useRef(null);
|
|
11673
|
+
const stick = React59.useRef(true);
|
|
11674
|
+
const [pill, setPill] = React59.useState(0);
|
|
11675
|
+
const seen = React59.useRef(0);
|
|
11603
11676
|
const toBottom = (smooth) => {
|
|
11604
11677
|
const el = scroller.current;
|
|
11605
11678
|
if (!el) return;
|
|
@@ -11618,7 +11691,7 @@ function ChatTranscript({
|
|
|
11618
11691
|
seen.current = messages.length;
|
|
11619
11692
|
}
|
|
11620
11693
|
};
|
|
11621
|
-
|
|
11694
|
+
React59.useLayoutEffect(() => {
|
|
11622
11695
|
const el = scroller.current;
|
|
11623
11696
|
if (!el) return;
|
|
11624
11697
|
if (stick.current) {
|
|
@@ -11626,7 +11699,7 @@ function ChatTranscript({
|
|
|
11626
11699
|
seen.current = messages.length;
|
|
11627
11700
|
} else setPill(Math.max(0, messages.length - seen.current));
|
|
11628
11701
|
}, [messages]);
|
|
11629
|
-
|
|
11702
|
+
React59.useEffect(() => {
|
|
11630
11703
|
const el = scroller.current;
|
|
11631
11704
|
const inner = el && el.firstChild;
|
|
11632
11705
|
if (!el || !inner || typeof ResizeObserver === "undefined") return;
|
|
@@ -11636,7 +11709,7 @@ function ChatTranscript({
|
|
|
11636
11709
|
ro.observe(inner);
|
|
11637
11710
|
return () => ro.disconnect();
|
|
11638
11711
|
}, []);
|
|
11639
|
-
const groups =
|
|
11712
|
+
const groups = React59.useMemo(() => groupMessages(messages), [messages]);
|
|
11640
11713
|
const empty = !messages.length && status === "ready";
|
|
11641
11714
|
return /* @__PURE__ */ (0, import_jsx_runtime89.jsxs)("div", { className: ["fdc-scroll", className].filter(Boolean).join(" "), ref: scroller, onScroll, children: [
|
|
11642
11715
|
/* @__PURE__ */ (0, import_jsx_runtime89.jsxs)("div", { className: "fdc-log", role: "log", "aria-label": "Conversation", children: [
|
|
@@ -11660,7 +11733,7 @@ function ChatTranscript({
|
|
|
11660
11733
|
const prev = groups[i - 1];
|
|
11661
11734
|
const k = dayKey(g.messages[0].timestamp);
|
|
11662
11735
|
const showDay = !!k && (!prev || dayKey(prev.messages[0].timestamp) !== k);
|
|
11663
|
-
return /* @__PURE__ */ (0, import_jsx_runtime89.jsxs)(
|
|
11736
|
+
return /* @__PURE__ */ (0, import_jsx_runtime89.jsxs)(React59.Fragment, { children: [
|
|
11664
11737
|
showDay ? /* @__PURE__ */ (0, import_jsx_runtime89.jsx)("div", { className: "fdc-day", children: /* @__PURE__ */ (0, import_jsx_runtime89.jsx)("span", { children: dayLabel(k) }) }) : null,
|
|
11665
11738
|
/* @__PURE__ */ (0, import_jsx_runtime89.jsx)(ChatTurn, { group: g, ctx })
|
|
11666
11739
|
] }, g.key || i);
|
|
@@ -11677,7 +11750,7 @@ function ChatTranscript({
|
|
|
11677
11750
|
var TranscriptKit = { groupMessages };
|
|
11678
11751
|
|
|
11679
11752
|
// src/components/chat/ChatComposer.tsx
|
|
11680
|
-
var
|
|
11753
|
+
var React60 = __toESM(require("react"), 1);
|
|
11681
11754
|
var import_jsx_runtime90 = require("react/jsx-runtime");
|
|
11682
11755
|
function ChatComposer({
|
|
11683
11756
|
onSubmit,
|
|
@@ -11705,17 +11778,17 @@ function ChatComposer({
|
|
|
11705
11778
|
onReject,
|
|
11706
11779
|
onOpenAttachment
|
|
11707
11780
|
}) {
|
|
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 =
|
|
11781
|
+
const [text, setText] = React60.useState(draft || "");
|
|
11782
|
+
const [trigger, setTrigger] = React60.useState(null);
|
|
11783
|
+
const [mentionItems, setMentionItems] = React60.useState([]);
|
|
11784
|
+
const [listening, setListening] = React60.useState(false);
|
|
11785
|
+
const [notice, setNotice] = React60.useState(null);
|
|
11786
|
+
const editor = React60.useRef(null);
|
|
11787
|
+
const wrap = React60.useRef(null);
|
|
11788
|
+
const stopVoice = React60.useRef(null);
|
|
11716
11789
|
const staged = useStagedFiles(fileUploadHandler, { onError: () => {
|
|
11717
11790
|
} });
|
|
11718
|
-
|
|
11791
|
+
React60.useEffect(() => {
|
|
11719
11792
|
if (draft != null && draft !== text) setText(draft);
|
|
11720
11793
|
}, [draft]);
|
|
11721
11794
|
const change = (v) => {
|
|
@@ -11751,7 +11824,7 @@ function ChatComposer({
|
|
|
11751
11824
|
e.preventDefault();
|
|
11752
11825
|
staged.add(found.files);
|
|
11753
11826
|
};
|
|
11754
|
-
|
|
11827
|
+
React60.useEffect(() => {
|
|
11755
11828
|
if (!trigger || trigger.type !== "mention" || !mentionSources) {
|
|
11756
11829
|
setMentionItems([]);
|
|
11757
11830
|
return;
|
|
@@ -11769,7 +11842,7 @@ function ChatComposer({
|
|
|
11769
11842
|
const q = (trigger.query || "").toLowerCase();
|
|
11770
11843
|
setMentionItems(mentionSources.filter((m) => !q || (m.label + " " + (m.description || "")).toLowerCase().includes(q)));
|
|
11771
11844
|
}, [trigger, mentionSources]);
|
|
11772
|
-
const slashItems =
|
|
11845
|
+
const slashItems = React60.useMemo(() => {
|
|
11773
11846
|
if (!trigger || trigger.type !== "slash" || !slashCommands) return [];
|
|
11774
11847
|
const q = (trigger.query || "").toLowerCase();
|
|
11775
11848
|
return slashCommands.filter((c) => !q || (c.id + " " + c.label + " " + (c.description || "")).toLowerCase().includes(q));
|
|
@@ -11943,12 +12016,12 @@ function ChatComposer({
|
|
|
11943
12016
|
}
|
|
11944
12017
|
|
|
11945
12018
|
// src/components/chat/ChatSessionBar.tsx
|
|
11946
|
-
var
|
|
12019
|
+
var React61 = __toESM(require("react"), 1);
|
|
11947
12020
|
var import_jsx_runtime91 = require("react/jsx-runtime");
|
|
11948
12021
|
var compact2 = meterFormats.compact;
|
|
11949
12022
|
function ChatSessionBar({ sessionStats, contextUsage, usageLimits, onClear, extras }) {
|
|
11950
|
-
const [open, setOpen] =
|
|
11951
|
-
const anchor =
|
|
12023
|
+
const [open, setOpen] = React61.useState(false);
|
|
12024
|
+
const anchor = React61.useRef(null);
|
|
11952
12025
|
const stats = sessionStats || null;
|
|
11953
12026
|
const cu = contextUsage || null;
|
|
11954
12027
|
const limits = usageLimits || null;
|
|
@@ -11963,7 +12036,7 @@ function ChatSessionBar({ sessionStats, contextUsage, usageLimits, onClear, extr
|
|
|
11963
12036
|
if (stats && stats.runningTasks) bits.push(stats.runningTasks + " running task" + (stats.runningTasks === 1 ? "" : "s"));
|
|
11964
12037
|
if (cu) bits.push(pct + "% context");
|
|
11965
12038
|
const expandable = !!(cu || limits);
|
|
11966
|
-
return /* @__PURE__ */ (0, import_jsx_runtime91.jsxs)(
|
|
12039
|
+
return /* @__PURE__ */ (0, import_jsx_runtime91.jsxs)(React61.Fragment, { children: [
|
|
11967
12040
|
/* @__PURE__ */ (0, import_jsx_runtime91.jsxs)("div", { className: "fdc-bar", children: [
|
|
11968
12041
|
/* @__PURE__ */ (0, import_jsx_runtime91.jsxs)(
|
|
11969
12042
|
"button",
|
|
@@ -12104,7 +12177,7 @@ function ModelControls({
|
|
|
12104
12177
|
] })
|
|
12105
12178
|
});
|
|
12106
12179
|
}
|
|
12107
|
-
return /* @__PURE__ */ (0, import_jsx_runtime91.jsxs)(
|
|
12180
|
+
return /* @__PURE__ */ (0, import_jsx_runtime91.jsxs)(React61.Fragment, { children: [
|
|
12108
12181
|
/* @__PURE__ */ (0, import_jsx_runtime91.jsx)(
|
|
12109
12182
|
MenuButton,
|
|
12110
12183
|
{
|
|
@@ -12221,11 +12294,11 @@ function AgentChatPanel({
|
|
|
12221
12294
|
onFeedback,
|
|
12222
12295
|
onEditMessage
|
|
12223
12296
|
}) {
|
|
12224
|
-
const [panelWidth, setPanelWidth] =
|
|
12225
|
-
const [applied, setApplied] =
|
|
12226
|
-
const [draft, setDraft] =
|
|
12227
|
-
const dragging =
|
|
12228
|
-
|
|
12297
|
+
const [panelWidth, setPanelWidth] = React62.useState(width);
|
|
12298
|
+
const [applied, setApplied] = React62.useState({});
|
|
12299
|
+
const [draft, setDraft] = React62.useState("");
|
|
12300
|
+
const dragging = React62.useRef(null);
|
|
12301
|
+
React62.useEffect(() => setPanelWidth(width), [width]);
|
|
12229
12302
|
const engine = useChatEngine({
|
|
12230
12303
|
contextType,
|
|
12231
12304
|
contextId,
|
|
@@ -12429,7 +12502,7 @@ function AgentChatPanel({
|
|
|
12429
12502
|
}
|
|
12430
12503
|
|
|
12431
12504
|
// src/components/files/FileViewer.tsx
|
|
12432
|
-
var
|
|
12505
|
+
var React63 = __toESM(require("react"), 1);
|
|
12433
12506
|
var import_jsx_runtime93 = require("react/jsx-runtime");
|
|
12434
12507
|
function previewKindOf(file) {
|
|
12435
12508
|
const mime = (file.mime || "").toLowerCase();
|
|
@@ -12486,13 +12559,13 @@ function parseDelimited(text, delimiter) {
|
|
|
12486
12559
|
return rows;
|
|
12487
12560
|
}
|
|
12488
12561
|
function usePreview(file, kind, resolveUrl) {
|
|
12489
|
-
const [state, setState] =
|
|
12490
|
-
const [attempt, setAttempt] =
|
|
12491
|
-
const resolveRef =
|
|
12492
|
-
|
|
12562
|
+
const [state, setState] = React63.useState({ status: "loading" });
|
|
12563
|
+
const [attempt, setAttempt] = React63.useState(0);
|
|
12564
|
+
const resolveRef = React63.useRef(resolveUrl);
|
|
12565
|
+
React63.useEffect(() => {
|
|
12493
12566
|
resolveRef.current = resolveUrl;
|
|
12494
12567
|
}, [resolveUrl]);
|
|
12495
|
-
|
|
12568
|
+
React63.useEffect(() => {
|
|
12496
12569
|
if (kind === "none") {
|
|
12497
12570
|
setState({ status: "ready" });
|
|
12498
12571
|
return;
|
|
@@ -12522,7 +12595,7 @@ function usePreview(file, kind, resolveUrl) {
|
|
|
12522
12595
|
if (ac) ac.abort();
|
|
12523
12596
|
};
|
|
12524
12597
|
}, [file.id, kind, attempt]);
|
|
12525
|
-
return { ...state, retry:
|
|
12598
|
+
return { ...state, retry: React63.useCallback(() => setAttempt((a) => a + 1), []) };
|
|
12526
12599
|
}
|
|
12527
12600
|
function PreviewBody({ file, kind, state }) {
|
|
12528
12601
|
if (kind === "image") return /* @__PURE__ */ (0, import_jsx_runtime93.jsx)("img", { className: "fd-fv-image", src: state.url, alt: file.name || "Preview" });
|
|
@@ -12567,13 +12640,13 @@ function PreviewBody({ file, kind, state }) {
|
|
|
12567
12640
|
] });
|
|
12568
12641
|
}
|
|
12569
12642
|
function FileViewer({ file, resolveUrl, sidePanel, sidePanelLabel = "Details", onClose, actions, className = "" }) {
|
|
12570
|
-
const kind =
|
|
12643
|
+
const kind = React63.useMemo(() => previewKindOf(file), [file]);
|
|
12571
12644
|
const preview = usePreview(file, kind, resolveUrl);
|
|
12572
|
-
const [tab, setTab] =
|
|
12573
|
-
const [downloading, setDownloading] =
|
|
12574
|
-
const [downloadError, setDownloadError] =
|
|
12645
|
+
const [tab, setTab] = React63.useState("preview");
|
|
12646
|
+
const [downloading, setDownloading] = React63.useState(false);
|
|
12647
|
+
const [downloadError, setDownloadError] = React63.useState(null);
|
|
12575
12648
|
const hasSide = sidePanel != null;
|
|
12576
|
-
|
|
12649
|
+
React63.useEffect(() => {
|
|
12577
12650
|
setTab("preview");
|
|
12578
12651
|
}, [file.id]);
|
|
12579
12652
|
const download = () => {
|
|
@@ -12640,7 +12713,7 @@ function FileViewer({ file, resolveUrl, sidePanel, sidePanelLabel = "Details", o
|
|
|
12640
12713
|
}
|
|
12641
12714
|
|
|
12642
12715
|
// src/components/files/FileBrowser.tsx
|
|
12643
|
-
var
|
|
12716
|
+
var React64 = __toESM(require("react"), 1);
|
|
12644
12717
|
var import_jsx_runtime94 = require("react/jsx-runtime");
|
|
12645
12718
|
function childrenOf(folders, parentId) {
|
|
12646
12719
|
return folders.filter((f) => f.parentId === parentId).sort((a, b) => a.name.localeCompare(b.name));
|
|
@@ -12711,10 +12784,10 @@ function FolderPickerMenu({
|
|
|
12711
12784
|
destinations,
|
|
12712
12785
|
onPick
|
|
12713
12786
|
}) {
|
|
12714
|
-
const [open, setOpen] =
|
|
12787
|
+
const [open, setOpen] = React64.useState(false);
|
|
12715
12788
|
const zIndex = useOverlayLayer(open);
|
|
12716
|
-
const ref =
|
|
12717
|
-
|
|
12789
|
+
const ref = React64.useRef(null);
|
|
12790
|
+
React64.useEffect(() => {
|
|
12718
12791
|
if (!open) return;
|
|
12719
12792
|
const away = (e) => {
|
|
12720
12793
|
if (ref.current && !ref.current.contains(e.target)) setOpen(false);
|
|
@@ -12766,8 +12839,8 @@ function FolderPickerMenu({
|
|
|
12766
12839
|
] });
|
|
12767
12840
|
}
|
|
12768
12841
|
function RowShell({ icon, name, meta, onOpen, draggableId, isDropTarget, onDropPayload, actions, className = "" }) {
|
|
12769
|
-
const [over, setOver] =
|
|
12770
|
-
const dragCounter =
|
|
12842
|
+
const [over, setOver] = React64.useState(false);
|
|
12843
|
+
const dragCounter = React64.useRef(0);
|
|
12771
12844
|
const dropHandlers = isDropTarget ? {
|
|
12772
12845
|
onDragEnter: (e) => {
|
|
12773
12846
|
if (!hasInternalPayload(e)) return;
|
|
@@ -12815,8 +12888,8 @@ function RowShell({ icon, name, meta, onOpen, draggableId, isDropTarget, onDropP
|
|
|
12815
12888
|
}
|
|
12816
12889
|
function TreeNode({ folder, depth, folders, currentFolderId, onNavigate, onMoveInto, canMove }) {
|
|
12817
12890
|
const kids = childrenOf(folders, folder.id);
|
|
12818
|
-
const [expanded, setExpanded] =
|
|
12819
|
-
|
|
12891
|
+
const [expanded, setExpanded] = React64.useState(() => currentFolderId != null && isSelfOrDescendant(folders, folder.id, currentFolderId));
|
|
12892
|
+
React64.useEffect(() => {
|
|
12820
12893
|
if (currentFolderId != null && isSelfOrDescendant(folders, folder.id, currentFolderId)) setExpanded(true);
|
|
12821
12894
|
}, [currentFolderId, folder.id, folders]);
|
|
12822
12895
|
const isCurrent = folder.id === currentFolderId;
|
|
@@ -12882,15 +12955,15 @@ function FileBrowser({
|
|
|
12882
12955
|
const canUpload = perm.canUpload !== false && !!onUpload;
|
|
12883
12956
|
const canRemoveFile = perm.canRemoveFile !== false && !!onRemoveFile;
|
|
12884
12957
|
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 =
|
|
12958
|
+
const [createOpen, setCreateOpen] = React64.useState(false);
|
|
12959
|
+
const [createName, setCreateName] = React64.useState("");
|
|
12960
|
+
const [renameTarget, setRenameTarget] = React64.useState(null);
|
|
12961
|
+
const [renameValue, setRenameValue] = React64.useState("");
|
|
12962
|
+
const [deleteTarget, setDeleteTarget] = React64.useState(null);
|
|
12963
|
+
const uploadInputRef = React64.useRef(null);
|
|
12964
|
+
const crumbFolders = React64.useMemo(() => ancestorsOf(folders, currentFolderId), [folders, currentFolderId]);
|
|
12965
|
+
const subfolders = React64.useMemo(() => childrenOf(folders, currentFolderId), [folders, currentFolderId]);
|
|
12966
|
+
const currentFiles = React64.useMemo(
|
|
12894
12967
|
() => files.filter((f) => f.folderId === currentFolderId).sort((a, b) => a.name.localeCompare(b.name)),
|
|
12895
12968
|
[files, currentFolderId]
|
|
12896
12969
|
);
|
|
@@ -13122,8 +13195,8 @@ function BreadcrumbCrumb({
|
|
|
13122
13195
|
isDropTarget,
|
|
13123
13196
|
onDropPayload
|
|
13124
13197
|
}) {
|
|
13125
|
-
const [over, setOver] =
|
|
13126
|
-
const dragCounter =
|
|
13198
|
+
const [over, setOver] = React64.useState(false);
|
|
13199
|
+
const dragCounter = React64.useRef(0);
|
|
13127
13200
|
const dropHandlers = isDropTarget ? {
|
|
13128
13201
|
onDragEnter: (e) => {
|
|
13129
13202
|
if (!hasInternalPayload(e)) return;
|
|
@@ -13152,9 +13225,27 @@ function BreadcrumbCrumb({
|
|
|
13152
13225
|
}
|
|
13153
13226
|
|
|
13154
13227
|
// src/kits/query.ts
|
|
13155
|
-
var
|
|
13228
|
+
var React65 = __toESM(require("react"), 1);
|
|
13229
|
+
var isMultiSelectShaped = (v) => !!v && typeof v === "object" && Array.isArray(v.values);
|
|
13230
|
+
var isRangeShaped = (v) => !!v && typeof v === "object" && ("min" in v || "max" in v);
|
|
13231
|
+
var isDateShaped = (v) => !!v && typeof v === "object" && "kind" in v;
|
|
13232
|
+
function isActiveFilterValue(v) {
|
|
13233
|
+
if (v == null || v === "" || v === false) return false;
|
|
13234
|
+
if (Array.isArray(v)) return v.length > 0;
|
|
13235
|
+
if (isMultiSelectShaped(v)) return v.values.length > 0;
|
|
13236
|
+
if (isRangeShaped(v)) return v.min != null || v.max != null;
|
|
13237
|
+
if (isDateShaped(v)) return v.kind === "withinDays" ? v.days != null : !!(v.from && v.to);
|
|
13238
|
+
return true;
|
|
13239
|
+
}
|
|
13156
13240
|
function eqFilter(get2) {
|
|
13157
|
-
return (row, value) =>
|
|
13241
|
+
return (row, value) => {
|
|
13242
|
+
if (Array.isArray(value)) return value.includes(get2(row));
|
|
13243
|
+
if (isMultiSelectShaped(value)) {
|
|
13244
|
+
const hit = value.values.some((o) => o.value === get2(row));
|
|
13245
|
+
return value.operator === "notIn" ? !hit : hit;
|
|
13246
|
+
}
|
|
13247
|
+
return get2(row) === value;
|
|
13248
|
+
};
|
|
13158
13249
|
}
|
|
13159
13250
|
function anyOfFilter(get2) {
|
|
13160
13251
|
return (row, value) => {
|
|
@@ -13165,10 +13256,15 @@ function anyOfFilter(get2) {
|
|
|
13165
13256
|
function rangeFilter(get2) {
|
|
13166
13257
|
return (row, value) => {
|
|
13167
13258
|
const n = get2(row);
|
|
13168
|
-
|
|
13169
|
-
|
|
13170
|
-
|
|
13171
|
-
|
|
13259
|
+
let lo = 0;
|
|
13260
|
+
let hi = Number.POSITIVE_INFINITY;
|
|
13261
|
+
if (Array.isArray(value)) {
|
|
13262
|
+
lo = Number(value[0] ?? 0);
|
|
13263
|
+
hi = value[1] == null ? Number.POSITIVE_INFINITY : Number(value[1]);
|
|
13264
|
+
} else if (isRangeShaped(value)) {
|
|
13265
|
+
lo = value.min ?? 0;
|
|
13266
|
+
hi = value.max ?? Number.POSITIVE_INFINITY;
|
|
13267
|
+
}
|
|
13172
13268
|
return n >= lo && (hi === Number.POSITIVE_INFINITY || n <= hi);
|
|
13173
13269
|
};
|
|
13174
13270
|
}
|
|
@@ -13184,22 +13280,22 @@ function compare(a, b, dir) {
|
|
|
13184
13280
|
var API = null;
|
|
13185
13281
|
var PREFS = null;
|
|
13186
13282
|
function useServerTable({ endpoint, params, defaults, deps, prefsKey }) {
|
|
13187
|
-
const [query, setQuery] =
|
|
13283
|
+
const [query, setQuery] = React65.useState(() => {
|
|
13188
13284
|
const store = PREFS || window.PlannerPrefs;
|
|
13189
13285
|
const saved = prefsKey && store ? store.getTable(prefsKey) : {};
|
|
13190
13286
|
return { ...DEFAULTS, ...defaults || {}, ...saved.pageSize ? { pageSize: saved.pageSize } : {}, ...saved.sort ? { sort: saved.sort, dir: saved.dir || "desc" } : {} };
|
|
13191
13287
|
});
|
|
13192
|
-
const savePref =
|
|
13288
|
+
const savePref = React65.useCallback((patch2) => {
|
|
13193
13289
|
const store = PREFS || window.PlannerPrefs;
|
|
13194
13290
|
if (prefsKey && store) store.setTable(prefsKey, patch2);
|
|
13195
13291
|
}, [prefsKey]);
|
|
13196
|
-
const [res, setRes] =
|
|
13197
|
-
const [loading, setLoading] =
|
|
13198
|
-
const seq2 =
|
|
13292
|
+
const [res, setRes] = React65.useState(null);
|
|
13293
|
+
const [loading, setLoading] = React65.useState(true);
|
|
13294
|
+
const seq2 = React65.useRef(0);
|
|
13199
13295
|
const depKey = (deps || []).join("|");
|
|
13200
13296
|
const paramKey = JSON.stringify(params || {});
|
|
13201
13297
|
const queryKey = JSON.stringify(query);
|
|
13202
|
-
|
|
13298
|
+
React65.useEffect(() => {
|
|
13203
13299
|
const id = ++seq2.current;
|
|
13204
13300
|
setLoading(true);
|
|
13205
13301
|
const t = setTimeout(() => {
|
|
@@ -13235,7 +13331,7 @@ function useServerTable({ endpoint, params, defaults, deps, prefsKey }) {
|
|
|
13235
13331
|
loading,
|
|
13236
13332
|
/** True only on the very first load — later loads keep showing stale rows. */
|
|
13237
13333
|
initialLoading: loading && !res,
|
|
13238
|
-
activeFilterCount: Object.values(query.filters).filter(
|
|
13334
|
+
activeFilterCount: Object.values(query.filters).filter(isActiveFilterValue).length,
|
|
13239
13335
|
setPage: (page) => patch({ page }, false),
|
|
13240
13336
|
setPageSize: (pageSize) => {
|
|
13241
13337
|
savePref({ pageSize });
|
|
@@ -13298,7 +13394,6 @@ var QueryKit = {
|
|
|
13298
13394
|
const Q = { ...DEFAULTS, ...query || {} };
|
|
13299
13395
|
const c = cfg;
|
|
13300
13396
|
const filters = Q.filters || {};
|
|
13301
|
-
const active = (v) => !(v == null || v === "" || v === false || Array.isArray(v) && !v.length);
|
|
13302
13397
|
let out = rows;
|
|
13303
13398
|
const term = (Q.q || "").trim().toLowerCase();
|
|
13304
13399
|
if (term && c.searchKeys) {
|
|
@@ -13308,7 +13403,7 @@ var QueryKit = {
|
|
|
13308
13403
|
const searched = out;
|
|
13309
13404
|
Object.entries(filters).forEach(([id, val]) => {
|
|
13310
13405
|
const fn = c.filters && c.filters[id];
|
|
13311
|
-
if (!
|
|
13406
|
+
if (!isActiveFilterValue(val) || !fn) return;
|
|
13312
13407
|
out = out.filter((r) => fn(r, val));
|
|
13313
13408
|
});
|
|
13314
13409
|
const matched = out;
|
|
@@ -13355,9 +13450,30 @@ var QueryKit = {
|
|
|
13355
13450
|
if (Q.sort) parts.push("sort=" + Q.sort + "&dir=" + Q.dir);
|
|
13356
13451
|
if (Q.q) parts.push("q=" + encodeURIComponent(Q.q));
|
|
13357
13452
|
Object.entries(Q.filters || {}).forEach(([k, v]) => {
|
|
13358
|
-
if (
|
|
13359
|
-
if (Array.isArray(v))
|
|
13360
|
-
|
|
13453
|
+
if (!isActiveFilterValue(v)) return;
|
|
13454
|
+
if (Array.isArray(v)) {
|
|
13455
|
+
v.forEach((x) => parts.push(k + "=" + encodeURIComponent(x === Infinity ? "*" : x)));
|
|
13456
|
+
return;
|
|
13457
|
+
}
|
|
13458
|
+
if (isMultiSelectShaped(v)) {
|
|
13459
|
+
const prefix = v.operator === "notIn" ? "notIn:" : "";
|
|
13460
|
+
v.values.forEach((o) => parts.push(k + "=" + encodeURIComponent(prefix + String(o.value))));
|
|
13461
|
+
return;
|
|
13462
|
+
}
|
|
13463
|
+
if (isRangeShaped(v)) {
|
|
13464
|
+
if (v.min != null) parts.push(k + ".min=" + encodeURIComponent(String(v.min)));
|
|
13465
|
+
if (v.max != null) parts.push(k + ".max=" + encodeURIComponent(String(v.max)));
|
|
13466
|
+
return;
|
|
13467
|
+
}
|
|
13468
|
+
if (isDateShaped(v)) {
|
|
13469
|
+
if (v.kind === "withinDays") parts.push(k + "=withinDays:" + encodeURIComponent(String(v.days)));
|
|
13470
|
+
else {
|
|
13471
|
+
parts.push(k + ".from=" + encodeURIComponent(String(v.from)));
|
|
13472
|
+
parts.push(k + ".to=" + encodeURIComponent(String(v.to)));
|
|
13473
|
+
}
|
|
13474
|
+
return;
|
|
13475
|
+
}
|
|
13476
|
+
parts.push(k + "=" + encodeURIComponent(v));
|
|
13361
13477
|
});
|
|
13362
13478
|
return parts.join("&");
|
|
13363
13479
|
},
|
|
@@ -13498,12 +13614,12 @@ function createVersionStore(initialState, options) {
|
|
|
13498
13614
|
}
|
|
13499
13615
|
|
|
13500
13616
|
// src/kits/documentTitle.ts
|
|
13501
|
-
var
|
|
13617
|
+
var React66 = __toESM(require("react"), 1);
|
|
13502
13618
|
function formatDocumentTitle(routeTitle, appName) {
|
|
13503
13619
|
return [routeTitle, appName, "Flytedesk"].filter((part) => !!part && part.length > 0).join(" \xB7 ");
|
|
13504
13620
|
}
|
|
13505
13621
|
function useDocumentTitle(routeTitle, appName) {
|
|
13506
|
-
|
|
13622
|
+
React66.useEffect(() => {
|
|
13507
13623
|
if (typeof document === "undefined") return;
|
|
13508
13624
|
document.title = formatDocumentTitle(routeTitle, appName);
|
|
13509
13625
|
}, [routeTitle, appName]);
|