@flytedan/flytebot-design-system 0.10.0 → 0.11.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 +638 -653
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +104 -12
- package/dist/index.d.ts +104 -12
- package/dist/index.js +648 -663
- package/dist/index.js.map +1 -1
- package/package.json +1 -1
- package/styles/components.css +165 -16
- package/styles/tokens.css +20 -0
package/dist/index.cjs
CHANGED
|
@@ -259,6 +259,7 @@ function IconButton({
|
|
|
259
259
|
label,
|
|
260
260
|
size = "md",
|
|
261
261
|
variant = "ghost",
|
|
262
|
+
tone = "neutral",
|
|
262
263
|
round = false,
|
|
263
264
|
disabled = false,
|
|
264
265
|
className = "",
|
|
@@ -266,7 +267,8 @@ function IconButton({
|
|
|
266
267
|
}) {
|
|
267
268
|
const cls = [
|
|
268
269
|
"fd-btn-icon",
|
|
269
|
-
variant === "outline" ? "fd-btn-icon-outline" : "",
|
|
270
|
+
variant === "outline" ? "fd-btn-icon-outline" : variant === "solid" ? "fd-btn-icon-solid" : "",
|
|
271
|
+
tone !== "neutral" ? "is-" + tone : "",
|
|
270
272
|
size === "sm" ? "fd-btn-icon-sm" : size === "lg" ? "fd-btn-icon-lg" : "",
|
|
271
273
|
round ? "fd-btn-icon-round" : "",
|
|
272
274
|
className
|
|
@@ -287,6 +289,15 @@ var samePosition = (a, b) => {
|
|
|
287
289
|
if (!a || !b) return a === b;
|
|
288
290
|
return a.left === b.left && a.top === b.top && a.bottom === b.bottom && a.width === b.width && a.minWidth === b.minWidth && a.maxH === b.maxH && a.side === b.side && a.anchorWidth === b.anchorWidth;
|
|
289
291
|
};
|
|
292
|
+
var SCROLL_REGIONS = ".fd-pop-body, .fd-pop-list";
|
|
293
|
+
function measureLayer(el) {
|
|
294
|
+
if (!el) return { width: 0, height: 0 };
|
|
295
|
+
let hidden = 0;
|
|
296
|
+
el.querySelectorAll(SCROLL_REGIONS).forEach((r) => {
|
|
297
|
+
hidden += Math.max(0, r.scrollHeight - r.clientHeight);
|
|
298
|
+
});
|
|
299
|
+
return { width: el.offsetWidth, height: el.offsetHeight ? el.offsetHeight + hidden : 0 };
|
|
300
|
+
}
|
|
290
301
|
function usePopoverPosition(open, anchorRef, opts) {
|
|
291
302
|
const o = opts || {};
|
|
292
303
|
const { side: wantSide, align } = parsePlacement(o.placement);
|
|
@@ -294,6 +305,7 @@ function usePopoverPosition(open, anchorRef, opts) {
|
|
|
294
305
|
const posRef = React.useRef(null);
|
|
295
306
|
const detachRef = React.useRef(o.onDetach);
|
|
296
307
|
detachRef.current = o.onDetach;
|
|
308
|
+
const layerRef = o.layerRef;
|
|
297
309
|
React.useLayoutEffect(() => {
|
|
298
310
|
if (!open || !anchorRef || !anchorRef.current) {
|
|
299
311
|
posRef.current = null;
|
|
@@ -305,20 +317,22 @@ function usePopoverPosition(open, anchorRef, opts) {
|
|
|
305
317
|
if (!el) return;
|
|
306
318
|
const r = el.getBoundingClientRect();
|
|
307
319
|
const offset = o.offset == null ? 8 : o.offset;
|
|
308
|
-
const
|
|
320
|
+
const layer = measureLayer(layerRef ? layerRef.current : null);
|
|
321
|
+
const need = layer.height || Math.min(o.estHeight || 300, 180);
|
|
309
322
|
const below = window.innerHeight - r.bottom - offset - MARGIN;
|
|
310
323
|
const above = r.top - offset - MARGIN;
|
|
311
324
|
let side = wantSide;
|
|
312
|
-
if (side === "bottom" && below <
|
|
313
|
-
else if (side === "top" && above <
|
|
314
|
-
const
|
|
315
|
-
const
|
|
325
|
+
if (side === "bottom" && below < need && above > below) side = "top";
|
|
326
|
+
else if (side === "top" && above < need && below > above) side = "bottom";
|
|
327
|
+
const exact = o.matchWidth === true;
|
|
328
|
+
const width = exact ? r.width : Math.max(o.width || 0, o.minWidth || 0, o.matchWidth === "min" ? r.width : 0);
|
|
329
|
+
const w = exact || o.width ? width : Math.max(layer.width, width) || o.estWidth || 260;
|
|
316
330
|
let left = align === "end" ? r.right - w : align === "center" ? r.left + r.width / 2 - w / 2 : r.left;
|
|
317
331
|
left = Math.max(MARGIN, Math.min(left, window.innerWidth - w - MARGIN));
|
|
318
332
|
const maxH = Math.max(140, side === "top" ? above : below);
|
|
319
333
|
const next = {
|
|
320
334
|
left,
|
|
321
|
-
width:
|
|
335
|
+
width: exact ? r.width : void 0,
|
|
322
336
|
minWidth: o.minWidth,
|
|
323
337
|
top: side === "bottom" ? r.bottom + offset : null,
|
|
324
338
|
bottom: side === "top" ? window.innerHeight - r.top + offset : null,
|
|
@@ -354,6 +368,7 @@ var portal = (node) => {
|
|
|
354
368
|
function Popover({
|
|
355
369
|
open,
|
|
356
370
|
anchorRef,
|
|
371
|
+
triggerRef,
|
|
357
372
|
onClose,
|
|
358
373
|
placement = "bottom-start",
|
|
359
374
|
offset = 8,
|
|
@@ -369,6 +384,8 @@ function Popover({
|
|
|
369
384
|
returnFocus = true,
|
|
370
385
|
className = "",
|
|
371
386
|
style,
|
|
387
|
+
header,
|
|
388
|
+
footer,
|
|
372
389
|
children
|
|
373
390
|
}) {
|
|
374
391
|
const ref = React.useRef(null);
|
|
@@ -379,7 +396,8 @@ function Popover({
|
|
|
379
396
|
width,
|
|
380
397
|
minWidth,
|
|
381
398
|
estHeight: maxHeight || 320,
|
|
382
|
-
onDetach: onClose
|
|
399
|
+
onDetach: onClose,
|
|
400
|
+
layerRef: ref
|
|
383
401
|
});
|
|
384
402
|
const restore = React.useRef(null);
|
|
385
403
|
React.useEffect(() => {
|
|
@@ -400,7 +418,8 @@ function Popover({
|
|
|
400
418
|
if (!closeOnOutside) return;
|
|
401
419
|
const target = e.target;
|
|
402
420
|
if (ref.current && ref.current.contains(target)) return;
|
|
403
|
-
|
|
421
|
+
const trigger = (triggerRef || anchorRef).current;
|
|
422
|
+
if (trigger && trigger.contains(target)) return;
|
|
404
423
|
if (e.target.closest && e.target.closest(".fd-pop")) return;
|
|
405
424
|
onClose && onClose();
|
|
406
425
|
};
|
|
@@ -416,23 +435,23 @@ function Popover({
|
|
|
416
435
|
document.removeEventListener("pointerdown", away, true);
|
|
417
436
|
document.removeEventListener("keydown", key);
|
|
418
437
|
};
|
|
419
|
-
}, [open, closeOnOutside, closeOnEscape, onClose, anchorRef]);
|
|
438
|
+
}, [open, closeOnOutside, closeOnEscape, onClose, anchorRef, triggerRef]);
|
|
420
439
|
if (!open || !pos) return null;
|
|
421
440
|
return portal(
|
|
422
|
-
/* @__PURE__ */ (0, import_jsx_runtime3.
|
|
441
|
+
/* @__PURE__ */ (0, import_jsx_runtime3.jsxs)(
|
|
423
442
|
"div",
|
|
424
443
|
{
|
|
425
444
|
ref,
|
|
426
445
|
role,
|
|
427
446
|
"aria-label": label,
|
|
428
|
-
className: ["fd-pop", pos.side === "top" ? "is-up" : "",
|
|
447
|
+
className: ["fd-pop", pos.side === "top" ? "is-up" : "", className].filter(Boolean).join(" "),
|
|
429
448
|
style: {
|
|
430
449
|
position: "fixed",
|
|
431
450
|
left: pos.left,
|
|
432
451
|
top: pos.top == null ? "auto" : pos.top,
|
|
433
452
|
bottom: pos.bottom == null ? "auto" : pos.bottom,
|
|
434
|
-
width: matchWidth ? pos.width : width,
|
|
435
|
-
minWidth: minWidth || (matchWidth ? void 0 : 200),
|
|
453
|
+
width: matchWidth === true ? pos.width : width,
|
|
454
|
+
minWidth: matchWidth === "min" ? Math.max(pos.anchorWidth, minWidth || 0) : minWidth || (matchWidth ? void 0 : 200),
|
|
436
455
|
// Size to content by default — cap only at real available room between the
|
|
437
456
|
// anchor and the viewport edge (pos.maxH, computed by usePopoverPosition).
|
|
438
457
|
// A caller-supplied `maxHeight` narrows that further (e.g. a long menu that
|
|
@@ -445,7 +464,11 @@ function Popover({
|
|
|
445
464
|
zIndex: 140,
|
|
446
465
|
...style
|
|
447
466
|
},
|
|
448
|
-
children
|
|
467
|
+
children: [
|
|
468
|
+
header != null ? /* @__PURE__ */ (0, import_jsx_runtime3.jsx)("div", { className: "fd-pop-header", children: header }) : null,
|
|
469
|
+
/* @__PURE__ */ (0, import_jsx_runtime3.jsx)("div", { className: ["fd-pop-body", padded ? "fd-pop-padded" : ""].filter(Boolean).join(" "), children }),
|
|
470
|
+
footer != null ? /* @__PURE__ */ (0, import_jsx_runtime3.jsx)("div", { className: "fd-pop-footer", children: footer }) : null
|
|
471
|
+
]
|
|
449
472
|
}
|
|
450
473
|
)
|
|
451
474
|
);
|
|
@@ -520,77 +543,79 @@ function Menu({ items = [], onSelect, onClose, autoFocus = true, className = "",
|
|
|
520
543
|
};
|
|
521
544
|
const sub = openSub != null ? items[openSub] : null;
|
|
522
545
|
return /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)(React.Fragment, { children: [
|
|
523
|
-
|
|
524
|
-
|
|
525
|
-
|
|
526
|
-
|
|
527
|
-
|
|
528
|
-
|
|
529
|
-
|
|
530
|
-
|
|
531
|
-
|
|
532
|
-
|
|
533
|
-
|
|
534
|
-
|
|
535
|
-
|
|
536
|
-
|
|
537
|
-
|
|
538
|
-
|
|
539
|
-
|
|
540
|
-
{
|
|
541
|
-
type: "button",
|
|
542
|
-
"data-i": i,
|
|
543
|
-
role: it.checked != null ? "menuitemradio" : "menuitem",
|
|
544
|
-
"aria-checked": it.checked != null ? on : void 0,
|
|
545
|
-
"aria-haspopup": it.submenu ? "menu" : void 0,
|
|
546
|
-
"aria-expanded": it.submenu ? openSub === i : void 0,
|
|
547
|
-
"aria-disabled": it.disabled || void 0,
|
|
548
|
-
className: ["fd-opt", "fd-menu-item", i === active ? "is-active" : "", on ? "is-selected" : ""].filter(Boolean).join(" "),
|
|
549
|
-
onMouseEnter: () => {
|
|
550
|
-
setActive(i);
|
|
551
|
-
if (openSub != null && openSub !== i) setOpenSub(null);
|
|
552
|
-
},
|
|
553
|
-
onClick: () => choose(it, i),
|
|
554
|
-
children: [
|
|
555
|
-
it.icon ? /* @__PURE__ */ (0, import_jsx_runtime3.jsx)("span", { className: "fd-menu-icon", children: /* @__PURE__ */ (0, import_jsx_runtime3.jsx)("i", { className: "ph ph-" + it.icon, "aria-hidden": "true" }) }) : null,
|
|
556
|
-
/* @__PURE__ */ (0, import_jsx_runtime3.jsxs)("span", { className: "fd-menu-text", children: [
|
|
557
|
-
/* @__PURE__ */ (0, import_jsx_runtime3.jsx)("span", { className: "fd-opt-label", children: it.label }),
|
|
558
|
-
it.description ? /* @__PURE__ */ (0, import_jsx_runtime3.jsx)("span", { className: "fd-opt-desc", children: it.description }) : null
|
|
559
|
-
] }),
|
|
560
|
-
it.meta ? /* @__PURE__ */ (0, import_jsx_runtime3.jsx)("span", { className: "fd-opt-meta", children: it.meta }) : null,
|
|
561
|
-
it.shortcut ? /* @__PURE__ */ (0, import_jsx_runtime3.jsx)("span", { className: "fd-menu-shortcut", "aria-hidden": "true", children: it.shortcut }) : null,
|
|
562
|
-
it.submenu ? /* @__PURE__ */ (0, import_jsx_runtime3.jsx)("i", { className: "ph ph-caret-right fd-menu-more", "aria-hidden": "true" }) : null,
|
|
563
|
-
it.checked != null ? /* @__PURE__ */ (0, import_jsx_runtime3.jsx)("span", { className: "fd-opt-check", children: on ? /* @__PURE__ */ (0, import_jsx_runtime3.jsx)("i", { className: "ph ph-check", "aria-hidden": "true" }) : null }) : null
|
|
564
|
-
]
|
|
565
|
-
},
|
|
566
|
-
it.id || it.label || i
|
|
567
|
-
);
|
|
568
|
-
const ta = it.trailingAction;
|
|
569
|
-
if (!ta) return row;
|
|
570
|
-
return /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)("div", { className: "fd-menu-row", onMouseEnter: () => setActive(i), children: [
|
|
571
|
-
row,
|
|
572
|
-
/* @__PURE__ */ (0, import_jsx_runtime3.jsx)(
|
|
546
|
+
/* @__PURE__ */ (0, import_jsx_runtime3.jsxs)("div", { className: "fd-menu-frame", children: [
|
|
547
|
+
header != null ? /* @__PURE__ */ (0, import_jsx_runtime3.jsx)("div", { className: "fd-menu-header", children: header }) : null,
|
|
548
|
+
/* @__PURE__ */ (0, import_jsx_runtime3.jsx)(
|
|
549
|
+
"div",
|
|
550
|
+
{
|
|
551
|
+
ref: listRef,
|
|
552
|
+
tabIndex: -1,
|
|
553
|
+
role: "menu",
|
|
554
|
+
onKeyDown: onKey,
|
|
555
|
+
className: ["fd-pop-list", "fd-menu", className].filter(Boolean).join(" "),
|
|
556
|
+
children: items.map((it, i) => {
|
|
557
|
+
if (!it) return null;
|
|
558
|
+
if (it.kind === "separator") return /* @__PURE__ */ (0, import_jsx_runtime3.jsx)("div", { className: "fd-menu-sep", role: "separator" }, "s" + i);
|
|
559
|
+
if (it.kind === "section") return /* @__PURE__ */ (0, import_jsx_runtime3.jsx)("div", { className: "fd-pop-group", role: "presentation", children: it.label }, "h" + i);
|
|
560
|
+
if (it.kind === "custom") return /* @__PURE__ */ (0, import_jsx_runtime3.jsx)("div", { className: "fd-menu-custom", children: it.render ? it.render() : null }, "c" + i);
|
|
561
|
+
const on = !!it.checked;
|
|
562
|
+
const row = /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)(
|
|
573
563
|
"button",
|
|
574
564
|
{
|
|
575
565
|
type: "button",
|
|
576
|
-
|
|
577
|
-
"
|
|
578
|
-
|
|
579
|
-
|
|
580
|
-
|
|
581
|
-
|
|
582
|
-
|
|
583
|
-
|
|
584
|
-
|
|
566
|
+
"data-i": i,
|
|
567
|
+
role: it.checked != null ? "menuitemradio" : "menuitem",
|
|
568
|
+
"aria-checked": it.checked != null ? on : void 0,
|
|
569
|
+
"aria-haspopup": it.submenu ? "menu" : void 0,
|
|
570
|
+
"aria-expanded": it.submenu ? openSub === i : void 0,
|
|
571
|
+
"aria-disabled": it.disabled || void 0,
|
|
572
|
+
className: ["fd-opt", "fd-menu-item", i === active ? "is-active" : "", on ? "is-selected" : ""].filter(Boolean).join(" "),
|
|
573
|
+
onMouseEnter: () => {
|
|
574
|
+
setActive(i);
|
|
575
|
+
if (openSub != null && openSub !== i) setOpenSub(null);
|
|
585
576
|
},
|
|
586
|
-
|
|
587
|
-
|
|
588
|
-
|
|
589
|
-
|
|
590
|
-
|
|
591
|
-
|
|
592
|
-
|
|
593
|
-
|
|
577
|
+
onClick: () => choose(it, i),
|
|
578
|
+
children: [
|
|
579
|
+
it.icon ? /* @__PURE__ */ (0, import_jsx_runtime3.jsx)("span", { className: "fd-menu-icon", children: /* @__PURE__ */ (0, import_jsx_runtime3.jsx)("i", { className: "ph ph-" + it.icon, "aria-hidden": "true" }) }) : null,
|
|
580
|
+
/* @__PURE__ */ (0, import_jsx_runtime3.jsxs)("span", { className: "fd-menu-text", children: [
|
|
581
|
+
/* @__PURE__ */ (0, import_jsx_runtime3.jsx)("span", { className: "fd-opt-label", children: it.label }),
|
|
582
|
+
it.description ? /* @__PURE__ */ (0, import_jsx_runtime3.jsx)("span", { className: "fd-opt-desc", children: it.description }) : null
|
|
583
|
+
] }),
|
|
584
|
+
it.meta ? /* @__PURE__ */ (0, import_jsx_runtime3.jsx)("span", { className: "fd-opt-meta", children: it.meta }) : null,
|
|
585
|
+
it.shortcut ? /* @__PURE__ */ (0, import_jsx_runtime3.jsx)("span", { className: "fd-menu-shortcut", "aria-hidden": "true", children: it.shortcut }) : null,
|
|
586
|
+
it.submenu ? /* @__PURE__ */ (0, import_jsx_runtime3.jsx)("i", { className: "ph ph-caret-right fd-menu-more", "aria-hidden": "true" }) : null,
|
|
587
|
+
it.checked != null ? /* @__PURE__ */ (0, import_jsx_runtime3.jsx)("span", { className: "fd-opt-check", children: on ? /* @__PURE__ */ (0, import_jsx_runtime3.jsx)("i", { className: "ph ph-check", "aria-hidden": "true" }) : null }) : null
|
|
588
|
+
]
|
|
589
|
+
},
|
|
590
|
+
it.id || it.label || i
|
|
591
|
+
);
|
|
592
|
+
const ta = it.trailingAction;
|
|
593
|
+
if (!ta) return row;
|
|
594
|
+
return /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)("div", { className: "fd-menu-row", onMouseEnter: () => setActive(i), children: [
|
|
595
|
+
row,
|
|
596
|
+
/* @__PURE__ */ (0, import_jsx_runtime3.jsx)(
|
|
597
|
+
"button",
|
|
598
|
+
{
|
|
599
|
+
type: "button",
|
|
600
|
+
className: ["fd-menu-row-act", ta.danger ? "is-danger" : ""].filter(Boolean).join(" "),
|
|
601
|
+
"aria-label": ta.label,
|
|
602
|
+
title: ta.label,
|
|
603
|
+
onClick: (e) => {
|
|
604
|
+
e.stopPropagation();
|
|
605
|
+
ta.onSelect && ta.onSelect(it);
|
|
606
|
+
if (ta.closeOnSelect !== false) {
|
|
607
|
+
onClose && onClose();
|
|
608
|
+
}
|
|
609
|
+
},
|
|
610
|
+
children: /* @__PURE__ */ (0, import_jsx_runtime3.jsx)("i", { className: "ph ph-" + (ta.icon || "trash"), "aria-hidden": "true" })
|
|
611
|
+
}
|
|
612
|
+
)
|
|
613
|
+
] }, it.id || it.label || i);
|
|
614
|
+
})
|
|
615
|
+
}
|
|
616
|
+
),
|
|
617
|
+
footer != null ? /* @__PURE__ */ (0, import_jsx_runtime3.jsx)("div", { className: "fd-menu-footer", children: footer }) : null
|
|
618
|
+
] }),
|
|
594
619
|
sub && sub.submenu ? /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(
|
|
595
620
|
Popover,
|
|
596
621
|
{
|
|
@@ -1218,20 +1243,123 @@ function Toast({ title, children, tone = "success", onUndo, onDismiss, className
|
|
|
1218
1243
|
// src/components/feedback/Tooltip.tsx
|
|
1219
1244
|
var React6 = __toESM(require("react"), 1);
|
|
1220
1245
|
var import_jsx_runtime24 = require("react/jsx-runtime");
|
|
1246
|
+
var CLOSE_DELAY_MS = 120;
|
|
1221
1247
|
function Tooltip({ label, placement = "top", children, className = "" }) {
|
|
1222
|
-
const
|
|
1223
|
-
const
|
|
1248
|
+
const anchorRef = React6.useRef(null);
|
|
1249
|
+
const bubbleRef = React6.useRef(null);
|
|
1250
|
+
const [reason, setReason] = React6.useState(null);
|
|
1251
|
+
const closeTimer = React6.useRef(null);
|
|
1252
|
+
const id = React6.useId();
|
|
1253
|
+
const descId = id + "-desc";
|
|
1254
|
+
const open = reason != null;
|
|
1255
|
+
const cancelClose = React6.useCallback(() => {
|
|
1256
|
+
if (closeTimer.current) {
|
|
1257
|
+
clearTimeout(closeTimer.current);
|
|
1258
|
+
closeTimer.current = null;
|
|
1259
|
+
}
|
|
1260
|
+
}, []);
|
|
1261
|
+
const show = (why) => {
|
|
1262
|
+
cancelClose();
|
|
1263
|
+
setReason(why);
|
|
1264
|
+
};
|
|
1265
|
+
const hide = React6.useCallback(() => {
|
|
1266
|
+
cancelClose();
|
|
1267
|
+
setReason(null);
|
|
1268
|
+
}, [cancelClose]);
|
|
1269
|
+
const hover = () => {
|
|
1270
|
+
cancelClose();
|
|
1271
|
+
setReason((r) => r || "hover");
|
|
1272
|
+
};
|
|
1273
|
+
const hideSoon = () => {
|
|
1274
|
+
cancelClose();
|
|
1275
|
+
closeTimer.current = setTimeout(() => {
|
|
1276
|
+
closeTimer.current = null;
|
|
1277
|
+
setReason((r) => r === "hover" ? null : r);
|
|
1278
|
+
}, CLOSE_DELAY_MS);
|
|
1279
|
+
};
|
|
1280
|
+
React6.useEffect(() => cancelClose, [cancelClose]);
|
|
1281
|
+
const pos = usePopoverPosition(open, anchorRef, {
|
|
1282
|
+
placement: placement === "bottom" ? "bottom-center" : "top-center",
|
|
1283
|
+
offset: 8,
|
|
1284
|
+
estHeight: 40,
|
|
1285
|
+
estWidth: 160,
|
|
1286
|
+
layerRef: bubbleRef,
|
|
1287
|
+
onDetach: hide
|
|
1288
|
+
});
|
|
1289
|
+
React6.useEffect(() => {
|
|
1290
|
+
if (!open) return;
|
|
1291
|
+
const key = (e) => {
|
|
1292
|
+
if (e.key === "Escape") hide();
|
|
1293
|
+
};
|
|
1294
|
+
const away = (e) => {
|
|
1295
|
+
const t = e.target;
|
|
1296
|
+
if (anchorRef.current && anchorRef.current.contains(t)) return;
|
|
1297
|
+
if (bubbleRef.current && bubbleRef.current.contains(t)) return;
|
|
1298
|
+
hide();
|
|
1299
|
+
};
|
|
1300
|
+
document.addEventListener("keydown", key);
|
|
1301
|
+
document.addEventListener("pointerdown", away, true);
|
|
1302
|
+
return () => {
|
|
1303
|
+
document.removeEventListener("keydown", key);
|
|
1304
|
+
document.removeEventListener("pointerdown", away, true);
|
|
1305
|
+
};
|
|
1306
|
+
}, [open, hide]);
|
|
1307
|
+
const isMouse = (e) => e.pointerType === "mouse";
|
|
1308
|
+
const onFocus = (e) => {
|
|
1309
|
+
const el = e.target;
|
|
1310
|
+
let keyboard = true;
|
|
1311
|
+
try {
|
|
1312
|
+
keyboard = el.matches(":focus-visible");
|
|
1313
|
+
} catch {
|
|
1314
|
+
}
|
|
1315
|
+
if (keyboard) show("focus");
|
|
1316
|
+
};
|
|
1317
|
+
const described = React6.isValidElement(children) ? React6.cloneElement(children, {
|
|
1318
|
+
"aria-describedby": [children.props["aria-describedby"], descId].filter(Boolean).join(" ")
|
|
1319
|
+
}) : children;
|
|
1224
1320
|
return /* @__PURE__ */ (0, import_jsx_runtime24.jsxs)(
|
|
1225
1321
|
"span",
|
|
1226
1322
|
{
|
|
1227
|
-
|
|
1228
|
-
|
|
1229
|
-
|
|
1230
|
-
|
|
1231
|
-
|
|
1323
|
+
ref: anchorRef,
|
|
1324
|
+
className: "fd-tooltip-anchor",
|
|
1325
|
+
"aria-describedby": React6.isValidElement(children) ? void 0 : descId,
|
|
1326
|
+
onPointerEnter: (e) => {
|
|
1327
|
+
if (isMouse(e)) hover();
|
|
1328
|
+
},
|
|
1329
|
+
onPointerLeave: (e) => {
|
|
1330
|
+
if (isMouse(e)) hideSoon();
|
|
1331
|
+
},
|
|
1332
|
+
onPointerUp: (e) => {
|
|
1333
|
+
if (!isMouse(e)) {
|
|
1334
|
+
if (reason === "tap") hide();
|
|
1335
|
+
else show("tap");
|
|
1336
|
+
}
|
|
1337
|
+
},
|
|
1338
|
+
onFocus,
|
|
1339
|
+
onBlur: () => {
|
|
1340
|
+
if (reason === "focus") hide();
|
|
1341
|
+
},
|
|
1232
1342
|
children: [
|
|
1233
|
-
|
|
1234
|
-
|
|
1343
|
+
described,
|
|
1344
|
+
/* @__PURE__ */ (0, import_jsx_runtime24.jsx)("span", { id: descId, hidden: true, children: label }),
|
|
1345
|
+
open && pos ? portal(
|
|
1346
|
+
/* @__PURE__ */ (0, import_jsx_runtime24.jsx)(
|
|
1347
|
+
"span",
|
|
1348
|
+
{
|
|
1349
|
+
ref: bubbleRef,
|
|
1350
|
+
role: "tooltip",
|
|
1351
|
+
className: ["fd-tooltip", pos.side === "bottom" ? "is-below" : "", className].filter(Boolean).join(" "),
|
|
1352
|
+
style: { left: pos.left, top: pos.top == null ? "auto" : pos.top, bottom: pos.bottom == null ? "auto" : pos.bottom },
|
|
1353
|
+
onPointerEnter: (e) => {
|
|
1354
|
+
if (isMouse(e)) cancelClose();
|
|
1355
|
+
},
|
|
1356
|
+
onPointerLeave: (e) => {
|
|
1357
|
+
if (isMouse(e)) hideSoon();
|
|
1358
|
+
},
|
|
1359
|
+
children: label
|
|
1360
|
+
}
|
|
1361
|
+
)
|
|
1362
|
+
) : null
|
|
1235
1363
|
]
|
|
1236
1364
|
}
|
|
1237
1365
|
);
|
|
@@ -2865,6 +2993,7 @@ function VirtualList({
|
|
|
2865
2993
|
}
|
|
2866
2994
|
|
|
2867
2995
|
// src/components/data/EntityRow.tsx
|
|
2996
|
+
var React17 = __toESM(require("react"), 1);
|
|
2868
2997
|
var import_jsx_runtime40 = require("react/jsx-runtime");
|
|
2869
2998
|
var ENTITY_ROW_METRIC_WIDTH = 74;
|
|
2870
2999
|
var METRIC_TONE_COLOR = {
|
|
@@ -2873,20 +3002,20 @@ var METRIC_TONE_COLOR = {
|
|
|
2873
3002
|
danger: "var(--danger-text)"
|
|
2874
3003
|
};
|
|
2875
3004
|
function EntityRowMetrics({ metrics, className = "", style }) {
|
|
2876
|
-
return /* @__PURE__ */ (0, import_jsx_runtime40.jsx)("span", { className: ["fd-erow-metrics", className].filter(Boolean).join(" "), style, children: metrics.map((m, i) =>
|
|
2877
|
-
|
|
2878
|
-
|
|
2879
|
-
|
|
2880
|
-
|
|
2881
|
-
|
|
2882
|
-
children:
|
|
2883
|
-
|
|
2884
|
-
|
|
2885
|
-
|
|
2886
|
-
|
|
2887
|
-
}
|
|
2888
|
-
|
|
2889
|
-
)
|
|
3005
|
+
return /* @__PURE__ */ (0, import_jsx_runtime40.jsx)("span", { className: ["fd-erow-metrics", className].filter(Boolean).join(" "), style, children: metrics.map((m, i) => {
|
|
3006
|
+
const key = m.id || m.label || i;
|
|
3007
|
+
const className2 = ["fd-erow-metric", m.tone && m.tone !== "default" ? "is-" + m.tone : "", m.tooltip != null ? "is-described" : ""].filter(Boolean).join(" ");
|
|
3008
|
+
const cellStyle = { width: (m.width || ENTITY_ROW_METRIC_WIDTH) + "px", color: METRIC_TONE_COLOR[m.tone || "default"] };
|
|
3009
|
+
const content = /* @__PURE__ */ (0, import_jsx_runtime40.jsxs)(React17.Fragment, { children: [
|
|
3010
|
+
m.icon ? /* @__PURE__ */ (0, import_jsx_runtime40.jsx)("i", { className: "ph ph-" + m.icon, "aria-hidden": "true" }) : null,
|
|
3011
|
+
/* @__PURE__ */ (0, import_jsx_runtime40.jsx)("span", { className: "fd-erow-metric-value fd-tabular", children: m.value }),
|
|
3012
|
+
/* @__PURE__ */ (0, import_jsx_runtime40.jsx)("span", { className: "fd-sr", children: " " + m.label })
|
|
3013
|
+
] });
|
|
3014
|
+
if (m.tooltip == null) {
|
|
3015
|
+
return /* @__PURE__ */ (0, import_jsx_runtime40.jsx)("span", { className: className2, style: cellStyle, title: m.label, children: content }, key);
|
|
3016
|
+
}
|
|
3017
|
+
return /* @__PURE__ */ (0, import_jsx_runtime40.jsx)(Tooltip, { label: m.tooltip, children: /* @__PURE__ */ (0, import_jsx_runtime40.jsx)("button", { type: "button", className: className2, style: cellStyle, children: content }) }, key);
|
|
3018
|
+
}) });
|
|
2890
3019
|
}
|
|
2891
3020
|
function EntityRow({
|
|
2892
3021
|
title,
|
|
@@ -2936,8 +3065,10 @@ function EntityRow({
|
|
|
2936
3065
|
icon: action.icon,
|
|
2937
3066
|
label: action.label,
|
|
2938
3067
|
size: "sm",
|
|
2939
|
-
|
|
2940
|
-
|
|
3068
|
+
variant: "solid",
|
|
3069
|
+
tone: action.tone === "add" ? "ok" : action.tone === "remove" ? "danger" : "neutral",
|
|
3070
|
+
className: "fd-erow-action",
|
|
3071
|
+
onClick: action.onClick
|
|
2941
3072
|
}
|
|
2942
3073
|
) : null
|
|
2943
3074
|
]
|
|
@@ -2946,14 +3077,14 @@ function EntityRow({
|
|
|
2946
3077
|
}
|
|
2947
3078
|
|
|
2948
3079
|
// src/components/data/TransferList.tsx
|
|
2949
|
-
var
|
|
3080
|
+
var React19 = __toESM(require("react"), 1);
|
|
2950
3081
|
var import_react_dom4 = require("react-dom");
|
|
2951
3082
|
|
|
2952
3083
|
// src/components/forms/field.tsx
|
|
2953
|
-
var
|
|
3084
|
+
var React18 = __toESM(require("react"), 1);
|
|
2954
3085
|
var import_jsx_runtime41 = require("react/jsx-runtime");
|
|
2955
3086
|
function useFieldId(id) {
|
|
2956
|
-
const generated =
|
|
3087
|
+
const generated = React18.useId();
|
|
2957
3088
|
return id || generated;
|
|
2958
3089
|
}
|
|
2959
3090
|
function FieldLabel({ htmlFor, id, required = false, onClick, children }) {
|
|
@@ -2994,10 +3125,9 @@ function Input({
|
|
|
2994
3125
|
numeric ? "fd-input-num" : "",
|
|
2995
3126
|
error ? "fd-input-error" : "",
|
|
2996
3127
|
disabled ? "fd-input-disabled" : "",
|
|
2997
|
-
size === "lg" ? "fd-input-lg" : ""
|
|
2998
|
-
className
|
|
3128
|
+
size === "lg" ? "fd-input-lg" : ""
|
|
2999
3129
|
].filter(Boolean).join(" ");
|
|
3000
|
-
return /* @__PURE__ */ (0, import_jsx_runtime42.jsxs)("div", { className: "fd-field", style, children: [
|
|
3130
|
+
return /* @__PURE__ */ (0, import_jsx_runtime42.jsxs)("div", { className: ["fd-field", className].filter(Boolean).join(" "), style, children: [
|
|
3001
3131
|
label ? /* @__PURE__ */ (0, import_jsx_runtime42.jsx)(FieldLabel, { htmlFor: fieldId, required, children: label }) : null,
|
|
3002
3132
|
/* @__PURE__ */ (0, import_jsx_runtime42.jsxs)("div", { className: box, children: [
|
|
3003
3133
|
icon ? /* @__PURE__ */ (0, import_jsx_runtime42.jsx)("span", { className: "fd-input-icon", children: /* @__PURE__ */ (0, import_jsx_runtime42.jsx)("i", { className: "ph ph-" + icon, "aria-hidden": "true" }) }) : null,
|
|
@@ -3072,12 +3202,12 @@ function TransferList({
|
|
|
3072
3202
|
listHeight = 440,
|
|
3073
3203
|
className = ""
|
|
3074
3204
|
}) {
|
|
3075
|
-
const [drag, setDrag] =
|
|
3076
|
-
const [dragOverSide, setDragOverSide] =
|
|
3077
|
-
const dragRef =
|
|
3078
|
-
const armedRef =
|
|
3079
|
-
const sideRefs =
|
|
3080
|
-
const hitTestSide =
|
|
3205
|
+
const [drag, setDrag] = React19.useState(null);
|
|
3206
|
+
const [dragOverSide, setDragOverSide] = React19.useState(null);
|
|
3207
|
+
const dragRef = React19.useRef(null);
|
|
3208
|
+
const armedRef = React19.useRef(null);
|
|
3209
|
+
const sideRefs = React19.useRef({ left: null, right: null });
|
|
3210
|
+
const hitTestSide = React19.useCallback((x, y) => {
|
|
3081
3211
|
for (const side of ["left", "right"]) {
|
|
3082
3212
|
const el = sideRefs.current[side];
|
|
3083
3213
|
if (!el) continue;
|
|
@@ -3086,7 +3216,7 @@ function TransferList({
|
|
|
3086
3216
|
}
|
|
3087
3217
|
return null;
|
|
3088
3218
|
}, []);
|
|
3089
|
-
const findItem =
|
|
3219
|
+
const findItem = React19.useCallback(
|
|
3090
3220
|
(side, key) => (side === "left" ? left.items : right.items).find((it) => keyOf(it) === key),
|
|
3091
3221
|
[left.items, right.items, keyOf]
|
|
3092
3222
|
);
|
|
@@ -3108,7 +3238,7 @@ function TransferList({
|
|
|
3108
3238
|
height: rect.height
|
|
3109
3239
|
};
|
|
3110
3240
|
};
|
|
3111
|
-
|
|
3241
|
+
React19.useEffect(() => {
|
|
3112
3242
|
const onMovePointer = (e) => {
|
|
3113
3243
|
const armed = armedRef.current;
|
|
3114
3244
|
if (!armed || e.pointerId !== armed.pointerId) return;
|
|
@@ -3161,7 +3291,7 @@ function TransferList({
|
|
|
3161
3291
|
window.removeEventListener("pointercancel", endDrag);
|
|
3162
3292
|
};
|
|
3163
3293
|
}, [hitTestSide, findItem, onMove]);
|
|
3164
|
-
|
|
3294
|
+
React19.useEffect(() => {
|
|
3165
3295
|
if (!drag || typeof document === "undefined") return;
|
|
3166
3296
|
const prev = document.body.style.userSelect;
|
|
3167
3297
|
document.body.style.userSelect = "none";
|
|
@@ -3273,11 +3403,11 @@ function TransferList({
|
|
|
3273
3403
|
}
|
|
3274
3404
|
|
|
3275
3405
|
// src/components/forms/Checkbox.tsx
|
|
3276
|
-
var
|
|
3406
|
+
var React20 = __toESM(require("react"), 1);
|
|
3277
3407
|
var import_jsx_runtime45 = require("react/jsx-runtime");
|
|
3278
3408
|
function Checkbox({ label, description, card = false, indeterminate = false, className = "", ...rest }) {
|
|
3279
|
-
const ref =
|
|
3280
|
-
|
|
3409
|
+
const ref = React20.useRef(null);
|
|
3410
|
+
React20.useEffect(() => {
|
|
3281
3411
|
if (ref.current) ref.current.indeterminate = indeterminate;
|
|
3282
3412
|
}, [indeterminate]);
|
|
3283
3413
|
return /* @__PURE__ */ (0, import_jsx_runtime45.jsxs)("label", { className: ["fd-choice", card ? "fd-choice-card" : "", className].filter(Boolean).join(" "), children: [
|
|
@@ -3324,8 +3454,8 @@ function Switch({ label, description, className = "", ...rest }) {
|
|
|
3324
3454
|
var import_jsx_runtime48 = require("react/jsx-runtime");
|
|
3325
3455
|
function Textarea({ label, help, error, required = false, rows = 4, disabled = false, id, className = "", style, ...rest }) {
|
|
3326
3456
|
const fieldId = useFieldId(id);
|
|
3327
|
-
const box = ["fd-input", "fd-input-textarea", error ? "fd-input-error" : "", disabled ? "fd-input-disabled" : ""
|
|
3328
|
-
return /* @__PURE__ */ (0, import_jsx_runtime48.jsxs)("div", { className: "fd-field", style, children: [
|
|
3457
|
+
const box = ["fd-input", "fd-input-textarea", error ? "fd-input-error" : "", disabled ? "fd-input-disabled" : ""].filter(Boolean).join(" ");
|
|
3458
|
+
return /* @__PURE__ */ (0, import_jsx_runtime48.jsxs)("div", { className: ["fd-field", className].filter(Boolean).join(" "), style, children: [
|
|
3329
3459
|
label ? /* @__PURE__ */ (0, import_jsx_runtime48.jsx)(FieldLabel, { htmlFor: fieldId, required, children: label }) : null,
|
|
3330
3460
|
/* @__PURE__ */ (0, import_jsx_runtime48.jsx)("div", { className: box, children: /* @__PURE__ */ (0, import_jsx_runtime48.jsx)("textarea", { id: fieldId, rows, disabled, "aria-invalid": error ? "true" : void 0, ...rest }) }),
|
|
3331
3461
|
error ? /* @__PURE__ */ (0, import_jsx_runtime48.jsxs)("span", { className: "fd-field-error", children: [
|
|
@@ -3336,7 +3466,7 @@ function Textarea({ label, help, error, required = false, rows = 4, disabled = f
|
|
|
3336
3466
|
}
|
|
3337
3467
|
|
|
3338
3468
|
// src/components/forms/NumberInput.tsx
|
|
3339
|
-
var
|
|
3469
|
+
var React21 = __toESM(require("react"), 1);
|
|
3340
3470
|
var import_jsx_runtime49 = require("react/jsx-runtime");
|
|
3341
3471
|
function NumberInput({
|
|
3342
3472
|
label,
|
|
@@ -3364,10 +3494,10 @@ function NumberInput({
|
|
|
3364
3494
|
const n = Number(String(v == null ? "" : v).replace(/[^0-9.-]/g, ""));
|
|
3365
3495
|
return isNaN(n) ? null : n;
|
|
3366
3496
|
};
|
|
3367
|
-
const [text, setText] =
|
|
3368
|
-
const [editing, setEditing] =
|
|
3369
|
-
const timer =
|
|
3370
|
-
|
|
3497
|
+
const [text, setText] = React21.useState(value == null || value === "" ? "" : String(value));
|
|
3498
|
+
const [editing, setEditing] = React21.useState(false);
|
|
3499
|
+
const timer = React21.useRef(null);
|
|
3500
|
+
React21.useEffect(() => {
|
|
3371
3501
|
if (!editing) setText(value == null || value === "" ? "" : String(value));
|
|
3372
3502
|
}, [value, editing]);
|
|
3373
3503
|
const clamp = (n) => Math.min(max, Math.max(min, n));
|
|
@@ -3391,7 +3521,7 @@ function NumberInput({
|
|
|
3391
3521
|
const release = () => {
|
|
3392
3522
|
if (timer.current) clearTimeout(timer.current);
|
|
3393
3523
|
};
|
|
3394
|
-
|
|
3524
|
+
React21.useEffect(() => () => {
|
|
3395
3525
|
if (timer.current) clearTimeout(timer.current);
|
|
3396
3526
|
}, []);
|
|
3397
3527
|
const shown = editing ? text : (() => {
|
|
@@ -3478,52 +3608,9 @@ function NumberInput({
|
|
|
3478
3608
|
}
|
|
3479
3609
|
|
|
3480
3610
|
// src/components/forms/Select.tsx
|
|
3481
|
-
var
|
|
3482
|
-
var import_react_dom5 = require("react-dom");
|
|
3611
|
+
var React22 = __toESM(require("react"), 1);
|
|
3483
3612
|
var import_jsx_runtime50 = require("react/jsx-runtime");
|
|
3484
3613
|
var norm = (o) => typeof o === "string" ? { value: o, label: o } : o;
|
|
3485
|
-
function usePopPos(open, ref, estH, estW) {
|
|
3486
|
-
const [pos, setPos] = React21.useState(null);
|
|
3487
|
-
React21.useLayoutEffect(() => {
|
|
3488
|
-
if (!open || !ref.current) {
|
|
3489
|
-
setPos(null);
|
|
3490
|
-
return;
|
|
3491
|
-
}
|
|
3492
|
-
const calc = () => {
|
|
3493
|
-
const r = ref.current.getBoundingClientRect();
|
|
3494
|
-
const below = window.innerHeight - r.bottom;
|
|
3495
|
-
const up = below < estH && r.top > below;
|
|
3496
|
-
const w = Math.max(r.width, estW || 0);
|
|
3497
|
-
const maxH = Math.min(window.innerHeight - 16, Math.max(160, (up ? r.top : below) - 14));
|
|
3498
|
-
setPos({
|
|
3499
|
-
left: Math.max(8, Math.min(r.left, window.innerWidth - w - 8)),
|
|
3500
|
-
width: r.width,
|
|
3501
|
-
top: up ? null : r.bottom + 6,
|
|
3502
|
-
bottom: up ? window.innerHeight - r.top + 6 : null,
|
|
3503
|
-
up,
|
|
3504
|
-
maxH
|
|
3505
|
-
});
|
|
3506
|
-
};
|
|
3507
|
-
calc();
|
|
3508
|
-
window.addEventListener("scroll", calc, true);
|
|
3509
|
-
window.addEventListener("resize", calc);
|
|
3510
|
-
return () => {
|
|
3511
|
-
window.removeEventListener("scroll", calc, true);
|
|
3512
|
-
window.removeEventListener("resize", calc);
|
|
3513
|
-
};
|
|
3514
|
-
}, [open]);
|
|
3515
|
-
return pos;
|
|
3516
|
-
}
|
|
3517
|
-
var popStyle = (pos, extra) => ({
|
|
3518
|
-
position: "fixed",
|
|
3519
|
-
left: pos.left,
|
|
3520
|
-
top: pos.top == null ? "auto" : pos.top,
|
|
3521
|
-
bottom: pos.bottom == null ? "auto" : pos.bottom,
|
|
3522
|
-
transformOrigin: pos.up ? "bottom center" : "top center",
|
|
3523
|
-
maxHeight: pos.maxH,
|
|
3524
|
-
overflowY: "auto",
|
|
3525
|
-
...extra
|
|
3526
|
-
});
|
|
3527
3614
|
function Select({
|
|
3528
3615
|
label,
|
|
3529
3616
|
help,
|
|
@@ -3548,17 +3635,15 @@ function Select({
|
|
|
3548
3635
|
const isOn = (v) => multiple ? vals.includes(v) : v === value;
|
|
3549
3636
|
const hasSearch = searchable === void 0 ? opts.length > 8 : searchable;
|
|
3550
3637
|
const { fieldId, labelId, ariaLabelledBy } = useTriggerLabelling(label, id);
|
|
3551
|
-
const [open, setOpen] =
|
|
3552
|
-
const [q, setQ] =
|
|
3553
|
-
const [active, setActive] =
|
|
3554
|
-
const rootRef =
|
|
3555
|
-
const boxRef =
|
|
3556
|
-
const
|
|
3557
|
-
const
|
|
3558
|
-
const typeBuf = React21.useRef({ s: "", t: 0 });
|
|
3638
|
+
const [open, setOpen] = React22.useState(false);
|
|
3639
|
+
const [q, setQ] = React22.useState("");
|
|
3640
|
+
const [active, setActive] = React22.useState(-1);
|
|
3641
|
+
const rootRef = React22.useRef(null);
|
|
3642
|
+
const boxRef = React22.useRef(null);
|
|
3643
|
+
const listRef = React22.useRef(null);
|
|
3644
|
+
const typeBuf = React22.useRef({ s: "", t: 0 });
|
|
3559
3645
|
const selected = multiple ? null : opts.find((o) => o.value === value);
|
|
3560
3646
|
const chosen = multiple ? opts.filter((o) => vals.includes(o.value)) : [];
|
|
3561
|
-
const pos = usePopPos(open, boxRef, hasSearch ? 390 : 340, 260);
|
|
3562
3647
|
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;
|
|
3563
3648
|
const visible = q ? opts.filter((o) => (o.label + " " + (o.description || "") + " " + (o.group || "")).toLowerCase().includes(q.toLowerCase())) : opts;
|
|
3564
3649
|
const fire = (v) => {
|
|
@@ -3581,17 +3666,7 @@ function Select({
|
|
|
3581
3666
|
}
|
|
3582
3667
|
setOpen(!open);
|
|
3583
3668
|
};
|
|
3584
|
-
|
|
3585
|
-
if (!open) return;
|
|
3586
|
-
const away = (e) => {
|
|
3587
|
-
if (rootRef.current && rootRef.current.contains(e.target)) return;
|
|
3588
|
-
if (popRef.current && popRef.current.contains(e.target)) return;
|
|
3589
|
-
setOpen(false);
|
|
3590
|
-
};
|
|
3591
|
-
document.addEventListener("pointerdown", away);
|
|
3592
|
-
return () => document.removeEventListener("pointerdown", away);
|
|
3593
|
-
}, [open]);
|
|
3594
|
-
React21.useEffect(() => {
|
|
3669
|
+
React22.useEffect(() => {
|
|
3595
3670
|
if (!open || active < 0 || !listRef.current) return;
|
|
3596
3671
|
const el = listRef.current.querySelector('[data-i="' + active + '"]');
|
|
3597
3672
|
if (el) {
|
|
@@ -3682,94 +3757,96 @@ function Select({
|
|
|
3682
3757
|
) : null,
|
|
3683
3758
|
loading ? /* @__PURE__ */ (0, import_jsx_runtime50.jsx)("span", { className: "fd-spinner", style: { color: "var(--text-muted)" }, "aria-label": "Loading options" }) : /* @__PURE__ */ (0, import_jsx_runtime50.jsx)("span", { className: "fd-select-caret", onClick: toggle, children: /* @__PURE__ */ (0, import_jsx_runtime50.jsx)("i", { className: "ph ph-caret-down", "aria-hidden": "true" }) })
|
|
3684
3759
|
] }),
|
|
3685
|
-
|
|
3686
|
-
|
|
3687
|
-
|
|
3688
|
-
|
|
3689
|
-
|
|
3690
|
-
|
|
3691
|
-
|
|
3692
|
-
|
|
3693
|
-
|
|
3694
|
-
|
|
3695
|
-
|
|
3696
|
-
|
|
3697
|
-
|
|
3698
|
-
|
|
3699
|
-
|
|
3700
|
-
|
|
3701
|
-
|
|
3702
|
-
|
|
3703
|
-
|
|
3704
|
-
|
|
3705
|
-
|
|
3706
|
-
|
|
3707
|
-
)
|
|
3708
|
-
|
|
3709
|
-
|
|
3710
|
-
|
|
3711
|
-
|
|
3712
|
-
|
|
3713
|
-
|
|
3714
|
-
|
|
3715
|
-
|
|
3716
|
-
|
|
3717
|
-
|
|
3718
|
-
|
|
3719
|
-
|
|
3720
|
-
|
|
3721
|
-
|
|
3722
|
-
|
|
3723
|
-
|
|
3724
|
-
|
|
3725
|
-
|
|
3726
|
-
|
|
3727
|
-
|
|
3728
|
-
|
|
3729
|
-
|
|
3730
|
-
|
|
3731
|
-
|
|
3732
|
-
|
|
3733
|
-
|
|
3734
|
-
|
|
3735
|
-
|
|
3736
|
-
|
|
3737
|
-
|
|
3738
|
-
|
|
3739
|
-
|
|
3740
|
-
|
|
3741
|
-
|
|
3742
|
-
|
|
3743
|
-
|
|
3744
|
-
|
|
3745
|
-
|
|
3746
|
-
|
|
3747
|
-
|
|
3748
|
-
|
|
3749
|
-
|
|
3750
|
-
|
|
3751
|
-
|
|
3752
|
-
|
|
3753
|
-
|
|
3754
|
-
|
|
3755
|
-
|
|
3756
|
-
]
|
|
3757
|
-
|
|
3758
|
-
|
|
3759
|
-
|
|
3760
|
-
|
|
3761
|
-
|
|
3762
|
-
|
|
3763
|
-
|
|
3764
|
-
|
|
3765
|
-
}
|
|
3766
|
-
|
|
3767
|
-
|
|
3768
|
-
|
|
3769
|
-
|
|
3770
|
-
|
|
3771
|
-
|
|
3772
|
-
|
|
3760
|
+
/* @__PURE__ */ (0, import_jsx_runtime50.jsx)(
|
|
3761
|
+
Popover,
|
|
3762
|
+
{
|
|
3763
|
+
open,
|
|
3764
|
+
anchorRef: boxRef,
|
|
3765
|
+
triggerRef: rootRef,
|
|
3766
|
+
onClose: () => setOpen(false),
|
|
3767
|
+
placement: "bottom-start",
|
|
3768
|
+
offset: 6,
|
|
3769
|
+
matchWidth: "min",
|
|
3770
|
+
minWidth: 260,
|
|
3771
|
+
role: "presentation",
|
|
3772
|
+
style: { maxWidth: 380, zIndex: 130 },
|
|
3773
|
+
header: hasSearch ? /* @__PURE__ */ (0, import_jsx_runtime50.jsxs)("div", { className: "fd-pop-search", children: [
|
|
3774
|
+
/* @__PURE__ */ (0, import_jsx_runtime50.jsx)("i", { className: "ph ph-magnifying-glass", style: { color: "var(--text-muted)", fontSize: 14 } }),
|
|
3775
|
+
/* @__PURE__ */ (0, import_jsx_runtime50.jsx)(
|
|
3776
|
+
"input",
|
|
3777
|
+
{
|
|
3778
|
+
autoFocus: true,
|
|
3779
|
+
placeholder: "Search\u2026",
|
|
3780
|
+
value: q,
|
|
3781
|
+
onKeyDown: onKey,
|
|
3782
|
+
onChange: (e) => {
|
|
3783
|
+
setQ(e.target.value);
|
|
3784
|
+
setActive(0);
|
|
3785
|
+
}
|
|
3786
|
+
}
|
|
3787
|
+
),
|
|
3788
|
+
q ? /* @__PURE__ */ (0, import_jsx_runtime50.jsx)("span", { className: "fd-body-sm fd-muted", children: visible.length }) : null
|
|
3789
|
+
] }) : void 0,
|
|
3790
|
+
footer: multiple ? /* @__PURE__ */ (0, import_jsx_runtime50.jsxs)(React22.Fragment, { children: [
|
|
3791
|
+
/* @__PURE__ */ (0, import_jsx_runtime50.jsx)(
|
|
3792
|
+
"button",
|
|
3793
|
+
{
|
|
3794
|
+
type: "button",
|
|
3795
|
+
onClick: () => fire(visible.filter((o) => !o.disabled).map((o) => o.value)),
|
|
3796
|
+
style: { all: "unset", cursor: "pointer", fontSize: "var(--body-sm-size)", fontWeight: 600, color: "var(--brand)" },
|
|
3797
|
+
children: "Select all"
|
|
3798
|
+
}
|
|
3799
|
+
),
|
|
3800
|
+
/* @__PURE__ */ (0, import_jsx_runtime50.jsx)("span", { style: { flex: 1 } }),
|
|
3801
|
+
/* @__PURE__ */ (0, import_jsx_runtime50.jsxs)("span", { className: "fd-body-sm fd-muted", children: [
|
|
3802
|
+
vals.length,
|
|
3803
|
+
" of ",
|
|
3804
|
+
opts.length
|
|
3805
|
+
] }),
|
|
3806
|
+
/* @__PURE__ */ (0, import_jsx_runtime50.jsx)(
|
|
3807
|
+
"button",
|
|
3808
|
+
{
|
|
3809
|
+
type: "button",
|
|
3810
|
+
disabled: !vals.length,
|
|
3811
|
+
onClick: () => fire([]),
|
|
3812
|
+
style: { all: "unset", cursor: vals.length ? "pointer" : "default", fontSize: "var(--body-sm-size)", fontWeight: 600, color: vals.length ? "var(--text-2)" : "var(--text-muted)" },
|
|
3813
|
+
children: "Clear"
|
|
3814
|
+
}
|
|
3815
|
+
)
|
|
3816
|
+
] }) : void 0,
|
|
3817
|
+
children: /* @__PURE__ */ (0, import_jsx_runtime50.jsx)("div", { className: "fd-pop-list", role: "listbox", "aria-multiselectable": multiple || void 0, ref: listRef, children: visible.length === 0 ? /* @__PURE__ */ (0, import_jsx_runtime50.jsxs)("div", { className: "fd-pop-empty", children: [
|
|
3818
|
+
'Nothing matches "',
|
|
3819
|
+
q,
|
|
3820
|
+
'".'
|
|
3821
|
+
] }) : groups.map((grp) => /* @__PURE__ */ (0, import_jsx_runtime50.jsxs)(React22.Fragment, { children: [
|
|
3822
|
+
grp.g ? /* @__PURE__ */ (0, import_jsx_runtime50.jsx)("div", { className: "fd-pop-group", children: grp.g }) : null,
|
|
3823
|
+
grp.items.map(({ o, i }) => /* @__PURE__ */ (0, import_jsx_runtime50.jsxs)(
|
|
3824
|
+
"button",
|
|
3825
|
+
{
|
|
3826
|
+
type: "button",
|
|
3827
|
+
"data-i": i,
|
|
3828
|
+
role: "option",
|
|
3829
|
+
"aria-selected": isOn(o.value),
|
|
3830
|
+
"aria-disabled": o.disabled || void 0,
|
|
3831
|
+
className: ["fd-opt", i === active ? "is-active" : "", isOn(o.value) ? "is-selected" : ""].filter(Boolean).join(" "),
|
|
3832
|
+
onMouseEnter: () => setActive(i),
|
|
3833
|
+
onClick: () => pick(o),
|
|
3834
|
+
children: [
|
|
3835
|
+
multiple ? /* @__PURE__ */ (0, import_jsx_runtime50.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_runtime50.jsx)("i", { className: "ph ph-check", style: { fontSize: 11 } }) : null }) : null,
|
|
3836
|
+
o.icon ? /* @__PURE__ */ (0, import_jsx_runtime50.jsx)("span", { className: "fd-opt-icon", children: /* @__PURE__ */ (0, import_jsx_runtime50.jsx)("i", { className: "ph ph-" + o.icon }) }) : null,
|
|
3837
|
+
/* @__PURE__ */ (0, import_jsx_runtime50.jsxs)("span", { style: { flex: 1, minWidth: 0 }, children: [
|
|
3838
|
+
/* @__PURE__ */ (0, import_jsx_runtime50.jsx)("span", { className: "fd-opt-label", children: o.label }),
|
|
3839
|
+
o.description ? /* @__PURE__ */ (0, import_jsx_runtime50.jsx)("span", { className: "fd-opt-desc", children: o.description }) : null
|
|
3840
|
+
] }),
|
|
3841
|
+
o.meta ? /* @__PURE__ */ (0, import_jsx_runtime50.jsx)("span", { className: "fd-opt-meta", children: o.meta }) : null,
|
|
3842
|
+
multiple ? null : /* @__PURE__ */ (0, import_jsx_runtime50.jsx)("span", { className: "fd-opt-check", children: o.value === value ? /* @__PURE__ */ (0, import_jsx_runtime50.jsx)("i", { className: "ph ph-check" }) : null })
|
|
3843
|
+
]
|
|
3844
|
+
},
|
|
3845
|
+
String(o.value)
|
|
3846
|
+
))
|
|
3847
|
+
] }, grp.g || "_")) })
|
|
3848
|
+
}
|
|
3849
|
+
),
|
|
3773
3850
|
error ? /* @__PURE__ */ (0, import_jsx_runtime50.jsxs)("span", { className: "fd-field-error", children: [
|
|
3774
3851
|
/* @__PURE__ */ (0, import_jsx_runtime50.jsx)("i", { className: "ph ph-warning-circle", "aria-hidden": "true" }),
|
|
3775
3852
|
error
|
|
@@ -3778,8 +3855,7 @@ function Select({
|
|
|
3778
3855
|
}
|
|
3779
3856
|
|
|
3780
3857
|
// src/components/forms/DatePicker.tsx
|
|
3781
|
-
var
|
|
3782
|
-
var import_react_dom6 = require("react-dom");
|
|
3858
|
+
var React23 = __toESM(require("react"), 1);
|
|
3783
3859
|
var import_jsx_runtime51 = require("react/jsx-runtime");
|
|
3784
3860
|
var MONTHS = ["January", "February", "March", "April", "May", "June", "July", "August", "September", "October", "November", "December"];
|
|
3785
3861
|
var DOW = ["Su", "Mo", "Tu", "We", "Th", "Fr", "Sa"];
|
|
@@ -3793,56 +3869,14 @@ var fmt = (s) => {
|
|
|
3793
3869
|
const d = parse(s);
|
|
3794
3870
|
return d ? MONTHS[d.getMonth()].slice(0, 3) + " " + d.getDate() + ", " + d.getFullYear() : "";
|
|
3795
3871
|
};
|
|
3796
|
-
function usePopPos2(open, ref, estH, estW) {
|
|
3797
|
-
const [pos, setPos] = React22.useState(null);
|
|
3798
|
-
React22.useLayoutEffect(() => {
|
|
3799
|
-
if (!open || !ref.current) {
|
|
3800
|
-
setPos(null);
|
|
3801
|
-
return;
|
|
3802
|
-
}
|
|
3803
|
-
const calc = () => {
|
|
3804
|
-
const r = ref.current.getBoundingClientRect();
|
|
3805
|
-
const below = window.innerHeight - r.bottom;
|
|
3806
|
-
const up = below < estH && r.top > below;
|
|
3807
|
-
const w = Math.max(r.width, estW || 0);
|
|
3808
|
-
const maxH = Math.min(window.innerHeight - 16, Math.max(160, (up ? r.top : below) - 14));
|
|
3809
|
-
setPos({
|
|
3810
|
-
left: Math.max(8, Math.min(r.left, window.innerWidth - w - 8)),
|
|
3811
|
-
width: r.width,
|
|
3812
|
-
top: up ? null : r.bottom + 6,
|
|
3813
|
-
bottom: up ? window.innerHeight - r.top + 6 : null,
|
|
3814
|
-
up,
|
|
3815
|
-
maxH
|
|
3816
|
-
});
|
|
3817
|
-
};
|
|
3818
|
-
calc();
|
|
3819
|
-
window.addEventListener("scroll", calc, true);
|
|
3820
|
-
window.addEventListener("resize", calc);
|
|
3821
|
-
return () => {
|
|
3822
|
-
window.removeEventListener("scroll", calc, true);
|
|
3823
|
-
window.removeEventListener("resize", calc);
|
|
3824
|
-
};
|
|
3825
|
-
}, [open]);
|
|
3826
|
-
return pos;
|
|
3827
|
-
}
|
|
3828
|
-
var popStyle2 = (pos, extra) => ({
|
|
3829
|
-
position: "fixed",
|
|
3830
|
-
left: pos.left,
|
|
3831
|
-
top: pos.top == null ? "auto" : pos.top,
|
|
3832
|
-
bottom: pos.bottom == null ? "auto" : pos.bottom,
|
|
3833
|
-
transformOrigin: pos.up ? "bottom center" : "top center",
|
|
3834
|
-
maxHeight: pos.maxH,
|
|
3835
|
-
overflowY: "auto",
|
|
3836
|
-
...extra
|
|
3837
|
-
});
|
|
3838
3872
|
function Calendar({ value, range = false, onPick, initialMonth, months = 1 }) {
|
|
3839
3873
|
const today = /* @__PURE__ */ new Date();
|
|
3840
3874
|
const sel = range ? value || {} : { start: value, end: value };
|
|
3841
3875
|
const anchor = parse(sel.start) || parse(initialMonth) || today;
|
|
3842
|
-
const [vy, setVy] =
|
|
3843
|
-
const [vm, setVm] =
|
|
3844
|
-
const [mode2, setMode] =
|
|
3845
|
-
const [hover, setHover] =
|
|
3876
|
+
const [vy, setVy] = React23.useState(anchor.getFullYear());
|
|
3877
|
+
const [vm, setVm] = React23.useState(anchor.getMonth());
|
|
3878
|
+
const [mode2, setMode] = React23.useState("days");
|
|
3879
|
+
const [hover, setHover] = React23.useState(null);
|
|
3846
3880
|
const s = parse(sel.start), e = parse(sel.end);
|
|
3847
3881
|
const hoverEnd = range && s && !e && hover ? parse(hover) : null;
|
|
3848
3882
|
const inRange = (d) => {
|
|
@@ -3958,28 +3992,9 @@ function Calendar({ value, range = false, onPick, initialMonth, months = 1 }) {
|
|
|
3958
3992
|
}
|
|
3959
3993
|
function DatePicker({ label, help, error, required = false, disabled = false, range = false, value, onChange, placeholder, id, className = "", style, ...rest }) {
|
|
3960
3994
|
const { fieldId, labelId, ariaLabelledBy } = useTriggerLabelling(label, id);
|
|
3961
|
-
const [open, setOpen] =
|
|
3962
|
-
const rootRef =
|
|
3963
|
-
const boxRef =
|
|
3964
|
-
const popRef = React22.useRef(null);
|
|
3965
|
-
const pos = usePopPos2(open, boxRef, 430, range ? 600 : 316);
|
|
3966
|
-
React22.useEffect(() => {
|
|
3967
|
-
if (!open) return;
|
|
3968
|
-
const away = (e) => {
|
|
3969
|
-
if (rootRef.current && rootRef.current.contains(e.target)) return;
|
|
3970
|
-
if (popRef.current && popRef.current.contains(e.target)) return;
|
|
3971
|
-
setOpen(false);
|
|
3972
|
-
};
|
|
3973
|
-
const esc = (e) => {
|
|
3974
|
-
if (e.key === "Escape") setOpen(false);
|
|
3975
|
-
};
|
|
3976
|
-
document.addEventListener("pointerdown", away);
|
|
3977
|
-
document.addEventListener("keydown", esc);
|
|
3978
|
-
return () => {
|
|
3979
|
-
document.removeEventListener("pointerdown", away);
|
|
3980
|
-
document.removeEventListener("keydown", esc);
|
|
3981
|
-
};
|
|
3982
|
-
}, [open]);
|
|
3995
|
+
const [open, setOpen] = React23.useState(false);
|
|
3996
|
+
const rootRef = React23.useRef(null);
|
|
3997
|
+
const boxRef = React23.useRef(null);
|
|
3983
3998
|
const display = range ? value && value.start ? fmt(value.start) + (value.end ? " \u2192 " + fmt(value.end) : " \u2192 \u2026") : "" : fmt(value);
|
|
3984
3999
|
const toggle = () => {
|
|
3985
4000
|
if (!disabled) setOpen(!open);
|
|
@@ -4008,21 +4023,31 @@ function DatePicker({ label, help, error, required = false, disabled = false, ra
|
|
|
4008
4023
|
),
|
|
4009
4024
|
/* @__PURE__ */ (0, import_jsx_runtime51.jsx)("span", { className: "fd-select-caret", children: /* @__PURE__ */ (0, import_jsx_runtime51.jsx)("i", { className: "ph ph-caret-down", "aria-hidden": "true" }) })
|
|
4010
4025
|
] }),
|
|
4011
|
-
|
|
4012
|
-
|
|
4013
|
-
|
|
4014
|
-
|
|
4015
|
-
|
|
4016
|
-
|
|
4017
|
-
|
|
4018
|
-
|
|
4019
|
-
|
|
4020
|
-
|
|
4026
|
+
/* @__PURE__ */ (0, import_jsx_runtime51.jsx)(
|
|
4027
|
+
Popover,
|
|
4028
|
+
{
|
|
4029
|
+
open,
|
|
4030
|
+
anchorRef: boxRef,
|
|
4031
|
+
triggerRef: rootRef,
|
|
4032
|
+
onClose: () => setOpen(false),
|
|
4033
|
+
placement: "bottom-start",
|
|
4034
|
+
offset: 6,
|
|
4035
|
+
role: "presentation",
|
|
4036
|
+
style: { width: "max-content", zIndex: 130 },
|
|
4037
|
+
children: /* @__PURE__ */ (0, import_jsx_runtime51.jsx)(
|
|
4038
|
+
Calendar,
|
|
4039
|
+
{
|
|
4040
|
+
range,
|
|
4041
|
+
months: range ? 2 : 1,
|
|
4042
|
+
value,
|
|
4043
|
+
onPick: (v) => {
|
|
4044
|
+
onChange && onChange({ target: { value: v } });
|
|
4045
|
+
if (!range || v.start && v.end) setOpen(false);
|
|
4046
|
+
}
|
|
4021
4047
|
}
|
|
4022
|
-
|
|
4023
|
-
|
|
4024
|
-
|
|
4025
|
-
) : null,
|
|
4048
|
+
)
|
|
4049
|
+
}
|
|
4050
|
+
),
|
|
4026
4051
|
error ? /* @__PURE__ */ (0, import_jsx_runtime51.jsxs)("span", { className: "fd-field-error", children: [
|
|
4027
4052
|
/* @__PURE__ */ (0, import_jsx_runtime51.jsx)("i", { className: "ph ph-warning-circle", "aria-hidden": "true" }),
|
|
4028
4053
|
error
|
|
@@ -4031,61 +4056,18 @@ function DatePicker({ label, help, error, required = false, disabled = false, ra
|
|
|
4031
4056
|
}
|
|
4032
4057
|
|
|
4033
4058
|
// src/components/forms/TimePicker.tsx
|
|
4034
|
-
var
|
|
4035
|
-
var import_react_dom7 = require("react-dom");
|
|
4059
|
+
var React24 = __toESM(require("react"), 1);
|
|
4036
4060
|
var import_jsx_runtime52 = require("react/jsx-runtime");
|
|
4037
4061
|
var pad = (n) => String(n).padStart(2, "0");
|
|
4038
|
-
function usePopPos3(open, ref, estH, estW) {
|
|
4039
|
-
const [pos, setPos] = React23.useState(null);
|
|
4040
|
-
React23.useLayoutEffect(() => {
|
|
4041
|
-
if (!open || !ref.current) {
|
|
4042
|
-
setPos(null);
|
|
4043
|
-
return;
|
|
4044
|
-
}
|
|
4045
|
-
const calc = () => {
|
|
4046
|
-
const r = ref.current.getBoundingClientRect();
|
|
4047
|
-
const below = window.innerHeight - r.bottom;
|
|
4048
|
-
const up = below < estH && r.top > below;
|
|
4049
|
-
const w = Math.max(r.width, estW || 0);
|
|
4050
|
-
const maxH = Math.min(window.innerHeight - 16, Math.max(160, (up ? r.top : below) - 14));
|
|
4051
|
-
setPos({
|
|
4052
|
-
left: Math.max(8, Math.min(r.left, window.innerWidth - w - 8)),
|
|
4053
|
-
width: r.width,
|
|
4054
|
-
top: up ? null : r.bottom + 6,
|
|
4055
|
-
bottom: up ? window.innerHeight - r.top + 6 : null,
|
|
4056
|
-
up,
|
|
4057
|
-
maxH
|
|
4058
|
-
});
|
|
4059
|
-
};
|
|
4060
|
-
calc();
|
|
4061
|
-
window.addEventListener("scroll", calc, true);
|
|
4062
|
-
window.addEventListener("resize", calc);
|
|
4063
|
-
return () => {
|
|
4064
|
-
window.removeEventListener("scroll", calc, true);
|
|
4065
|
-
window.removeEventListener("resize", calc);
|
|
4066
|
-
};
|
|
4067
|
-
}, [open]);
|
|
4068
|
-
return pos;
|
|
4069
|
-
}
|
|
4070
|
-
var popStyle3 = (pos, extra) => ({
|
|
4071
|
-
position: "fixed",
|
|
4072
|
-
left: pos.left,
|
|
4073
|
-
top: pos.top == null ? "auto" : pos.top,
|
|
4074
|
-
bottom: pos.bottom == null ? "auto" : pos.bottom,
|
|
4075
|
-
transformOrigin: pos.up ? "bottom center" : "top center",
|
|
4076
|
-
maxHeight: pos.maxH,
|
|
4077
|
-
overflowY: "auto",
|
|
4078
|
-
...extra
|
|
4079
|
-
});
|
|
4080
4062
|
function ClockFace({ value = "09:00", onChange }) {
|
|
4081
4063
|
let [h24, m] = value.split(":").map(Number);
|
|
4082
4064
|
if (isNaN(h24)) h24 = 9;
|
|
4083
4065
|
if (isNaN(m)) m = 0;
|
|
4084
4066
|
const pm = h24 >= 12;
|
|
4085
4067
|
const h12 = h24 % 12 === 0 ? 12 : h24 % 12;
|
|
4086
|
-
const [mode2, setMode] =
|
|
4087
|
-
const faceRef =
|
|
4088
|
-
const dragging =
|
|
4068
|
+
const [mode2, setMode] = React24.useState("h");
|
|
4069
|
+
const faceRef = React24.useRef(null);
|
|
4070
|
+
const dragging = React24.useRef(false);
|
|
4089
4071
|
const set = (h, mm, isPm) => onChange((isPm ? h % 12 + 12 : h % 12) + ":" + pad(mm));
|
|
4090
4072
|
const R = 108, NR = 80;
|
|
4091
4073
|
const nums = mode2 === "h" ? Array.from({ length: 12 }, (_, i) => i + 1) : Array.from({ length: 12 }, (_, i) => i * 5);
|
|
@@ -4158,28 +4140,9 @@ function ClockFace({ value = "09:00", onChange }) {
|
|
|
4158
4140
|
}
|
|
4159
4141
|
function TimePicker({ label, help, error, required = false, disabled = false, value = "", onChange, placeholder = "Pick a time", id, className = "", style }) {
|
|
4160
4142
|
const { fieldId, labelId, ariaLabelledBy } = useTriggerLabelling(label, id);
|
|
4161
|
-
const [open, setOpen] =
|
|
4162
|
-
const rootRef =
|
|
4163
|
-
const boxRef =
|
|
4164
|
-
const popRef = React23.useRef(null);
|
|
4165
|
-
const pos = usePopPos3(open, boxRef, 420, 262);
|
|
4166
|
-
React23.useEffect(() => {
|
|
4167
|
-
if (!open) return;
|
|
4168
|
-
const away = (e) => {
|
|
4169
|
-
if (rootRef.current && rootRef.current.contains(e.target)) return;
|
|
4170
|
-
if (popRef.current && popRef.current.contains(e.target)) return;
|
|
4171
|
-
setOpen(false);
|
|
4172
|
-
};
|
|
4173
|
-
const esc = (e) => {
|
|
4174
|
-
if (e.key === "Escape") setOpen(false);
|
|
4175
|
-
};
|
|
4176
|
-
document.addEventListener("pointerdown", away);
|
|
4177
|
-
document.addEventListener("keydown", esc);
|
|
4178
|
-
return () => {
|
|
4179
|
-
document.removeEventListener("pointerdown", away);
|
|
4180
|
-
document.removeEventListener("keydown", esc);
|
|
4181
|
-
};
|
|
4182
|
-
}, [open]);
|
|
4143
|
+
const [open, setOpen] = React24.useState(false);
|
|
4144
|
+
const rootRef = React24.useRef(null);
|
|
4145
|
+
const boxRef = React24.useRef(null);
|
|
4183
4146
|
const disp = () => {
|
|
4184
4147
|
if (!value) return "";
|
|
4185
4148
|
const [h, m] = value.split(":").map(Number);
|
|
@@ -4211,10 +4174,19 @@ function TimePicker({ label, help, error, required = false, disabled = false, va
|
|
|
4211
4174
|
),
|
|
4212
4175
|
/* @__PURE__ */ (0, import_jsx_runtime52.jsx)("span", { className: "fd-select-caret", children: /* @__PURE__ */ (0, import_jsx_runtime52.jsx)("i", { className: "ph ph-caret-down", "aria-hidden": "true" }) })
|
|
4213
4176
|
] }),
|
|
4214
|
-
|
|
4215
|
-
|
|
4216
|
-
|
|
4217
|
-
|
|
4177
|
+
/* @__PURE__ */ (0, import_jsx_runtime52.jsx)(
|
|
4178
|
+
Popover,
|
|
4179
|
+
{
|
|
4180
|
+
open,
|
|
4181
|
+
anchorRef: boxRef,
|
|
4182
|
+
triggerRef: rootRef,
|
|
4183
|
+
onClose: () => setOpen(false),
|
|
4184
|
+
placement: "bottom-start",
|
|
4185
|
+
offset: 6,
|
|
4186
|
+
width: 262,
|
|
4187
|
+
role: "presentation",
|
|
4188
|
+
style: { zIndex: 130 },
|
|
4189
|
+
footer: /* @__PURE__ */ (0, import_jsx_runtime52.jsxs)(React24.Fragment, { children: [
|
|
4218
4190
|
/* @__PURE__ */ (0, import_jsx_runtime52.jsx)(
|
|
4219
4191
|
"button",
|
|
4220
4192
|
{
|
|
@@ -4230,10 +4202,10 @@ function TimePicker({ label, help, error, required = false, disabled = false, va
|
|
|
4230
4202
|
),
|
|
4231
4203
|
/* @__PURE__ */ (0, import_jsx_runtime52.jsx)("span", { style: { flex: 1 } }),
|
|
4232
4204
|
/* @__PURE__ */ (0, import_jsx_runtime52.jsx)("button", { type: "button", className: "fd-btn fd-btn-primary fd-btn-sm", onClick: () => setOpen(false), children: "Done" })
|
|
4233
|
-
] })
|
|
4234
|
-
|
|
4235
|
-
|
|
4236
|
-
)
|
|
4205
|
+
] }),
|
|
4206
|
+
children: /* @__PURE__ */ (0, import_jsx_runtime52.jsx)(ClockFace, { value: value || "09:00", onChange: (v) => onChange && onChange({ target: { value: v } }) })
|
|
4207
|
+
}
|
|
4208
|
+
),
|
|
4237
4209
|
error ? /* @__PURE__ */ (0, import_jsx_runtime52.jsxs)("span", { className: "fd-field-error", children: [
|
|
4238
4210
|
/* @__PURE__ */ (0, import_jsx_runtime52.jsx)("i", { className: "ph ph-warning-circle", "aria-hidden": "true" }),
|
|
4239
4211
|
error
|
|
@@ -4242,7 +4214,7 @@ function TimePicker({ label, help, error, required = false, disabled = false, va
|
|
|
4242
4214
|
}
|
|
4243
4215
|
|
|
4244
4216
|
// src/components/forms/Slider.tsx
|
|
4245
|
-
var
|
|
4217
|
+
var React25 = __toESM(require("react"), 1);
|
|
4246
4218
|
var import_jsx_runtime53 = require("react/jsx-runtime");
|
|
4247
4219
|
function Slider({
|
|
4248
4220
|
label,
|
|
@@ -4260,7 +4232,7 @@ function Slider({
|
|
|
4260
4232
|
...rest
|
|
4261
4233
|
}) {
|
|
4262
4234
|
const fieldId = useFieldId(id);
|
|
4263
|
-
const [dragging, setDragging] =
|
|
4235
|
+
const [dragging, setDragging] = React25.useState(false);
|
|
4264
4236
|
const v = value === void 0 ? min : Number(value);
|
|
4265
4237
|
const pct = max === min ? 0 : (v - min) / (max - min) * 100;
|
|
4266
4238
|
return /* @__PURE__ */ (0, import_jsx_runtime53.jsxs)("div", { className: ["fd-field", className].filter(Boolean).join(" "), children: [
|
|
@@ -4294,7 +4266,7 @@ function Slider({
|
|
|
4294
4266
|
}
|
|
4295
4267
|
|
|
4296
4268
|
// src/components/forms/RangeSlider.tsx
|
|
4297
|
-
var
|
|
4269
|
+
var React26 = __toESM(require("react"), 1);
|
|
4298
4270
|
var import_jsx_runtime54 = require("react/jsx-runtime");
|
|
4299
4271
|
function RangeSlider({
|
|
4300
4272
|
label,
|
|
@@ -4314,9 +4286,9 @@ function RangeSlider({
|
|
|
4314
4286
|
}) {
|
|
4315
4287
|
const fmt2 = format || ((v) => String(v));
|
|
4316
4288
|
const [a, b] = value || [min, max];
|
|
4317
|
-
const [drag, setDrag] =
|
|
4318
|
-
const [focus, setFocus] =
|
|
4319
|
-
const railRef =
|
|
4289
|
+
const [drag, setDrag] = React26.useState(null);
|
|
4290
|
+
const [focus, setFocus] = React26.useState(null);
|
|
4291
|
+
const railRef = React26.useRef(null);
|
|
4320
4292
|
const pct = (v) => max === min ? 0 : (v - min) / (max - min) * 100;
|
|
4321
4293
|
const clampPair = (i, v) => {
|
|
4322
4294
|
v = Math.min(max, Math.max(min, Math.round(v / step) * step));
|
|
@@ -4331,7 +4303,7 @@ function RangeSlider({
|
|
|
4331
4303
|
const r = railRef.current.getBoundingClientRect();
|
|
4332
4304
|
return min + Math.min(1, Math.max(0, (e.clientX - r.left) / r.width)) * (max - min);
|
|
4333
4305
|
};
|
|
4334
|
-
|
|
4306
|
+
React26.useEffect(() => {
|
|
4335
4307
|
if (drag === null) return;
|
|
4336
4308
|
const mv = (e) => onChange && onChange(clampPair(drag, fromEvent(e)));
|
|
4337
4309
|
const upH = () => setDrag(null);
|
|
@@ -4412,7 +4384,7 @@ function RangeSlider({
|
|
|
4412
4384
|
/* @__PURE__ */ (0, import_jsx_runtime54.jsxs)("div", { className: "fd-range" + (hasLabels ? " has-labels" : ""), onPointerDown: onRailDown, children: [
|
|
4413
4385
|
/* @__PURE__ */ (0, import_jsx_runtime54.jsx)("span", { className: "fd-range-rail", ref: railRef }),
|
|
4414
4386
|
/* @__PURE__ */ (0, import_jsx_runtime54.jsx)("span", { className: "fd-range-fill", style: { left: pct(a) + "%", width: pct(b) - pct(a) + "%" } }),
|
|
4415
|
-
marks.map((m) => /* @__PURE__ */ (0, import_jsx_runtime54.jsxs)(
|
|
4387
|
+
marks.map((m) => /* @__PURE__ */ (0, import_jsx_runtime54.jsxs)(React26.Fragment, { children: [
|
|
4416
4388
|
/* @__PURE__ */ (0, import_jsx_runtime54.jsx)("span", { className: "fd-range-mark" + (m.value >= a && m.value <= b ? " is-in" : ""), style: { left: pct(m.value) + "%" } }),
|
|
4417
4389
|
m.label ? /* @__PURE__ */ (0, import_jsx_runtime54.jsx)("span", { className: "fd-range-mark-label", style: { left: pct(m.value) + "%" }, children: m.label }) : null
|
|
4418
4390
|
] }, m.value)),
|
|
@@ -4441,7 +4413,7 @@ function RangeSlider({
|
|
|
4441
4413
|
}
|
|
4442
4414
|
|
|
4443
4415
|
// src/components/forms/Dropzone.tsx
|
|
4444
|
-
var
|
|
4416
|
+
var React27 = __toESM(require("react"), 1);
|
|
4445
4417
|
var import_jsx_runtime55 = require("react/jsx-runtime");
|
|
4446
4418
|
function Dropzone({
|
|
4447
4419
|
onFiles,
|
|
@@ -4456,8 +4428,8 @@ function Dropzone({
|
|
|
4456
4428
|
className = "",
|
|
4457
4429
|
style
|
|
4458
4430
|
}) {
|
|
4459
|
-
const [over, setOver] =
|
|
4460
|
-
const depth =
|
|
4431
|
+
const [over, setOver] = React27.useState(false);
|
|
4432
|
+
const depth = React27.useRef(0);
|
|
4461
4433
|
const has = (e) => {
|
|
4462
4434
|
const dt = e.dataTransfer;
|
|
4463
4435
|
if (!dt) return false;
|
|
@@ -4519,8 +4491,8 @@ function FilePickButton({
|
|
|
4519
4491
|
className = "",
|
|
4520
4492
|
children
|
|
4521
4493
|
}) {
|
|
4522
|
-
const ref =
|
|
4523
|
-
return /* @__PURE__ */ (0, import_jsx_runtime55.jsxs)(
|
|
4494
|
+
const ref = React27.useRef(null);
|
|
4495
|
+
return /* @__PURE__ */ (0, import_jsx_runtime55.jsxs)(React27.Fragment, { children: [
|
|
4524
4496
|
/* @__PURE__ */ (0, import_jsx_runtime55.jsx)(
|
|
4525
4497
|
"button",
|
|
4526
4498
|
{
|
|
@@ -4553,10 +4525,10 @@ function FilePickButton({
|
|
|
4553
4525
|
}
|
|
4554
4526
|
function useStagedFiles(upload, opts) {
|
|
4555
4527
|
const o = opts || {};
|
|
4556
|
-
const [items, setItems] =
|
|
4557
|
-
const controllers =
|
|
4528
|
+
const [items, setItems] = React27.useState([]);
|
|
4529
|
+
const controllers = React27.useRef({});
|
|
4558
4530
|
const patch = (id, next) => setItems((list) => list.map((f) => f.id === id ? Object.assign({}, f, next) : f));
|
|
4559
|
-
const run =
|
|
4531
|
+
const run = React27.useCallback((att) => {
|
|
4560
4532
|
if (!upload) return;
|
|
4561
4533
|
const ac = typeof AbortController !== "undefined" ? new AbortController() : null;
|
|
4562
4534
|
controllers.current[att.id] = ac;
|
|
@@ -4573,14 +4545,14 @@ function useStagedFiles(upload, opts) {
|
|
|
4573
4545
|
delete controllers.current[att.id];
|
|
4574
4546
|
});
|
|
4575
4547
|
}, [upload]);
|
|
4576
|
-
const add =
|
|
4548
|
+
const add = React27.useCallback((files) => {
|
|
4577
4549
|
if (!upload) return [];
|
|
4578
4550
|
const atts = Array.from(files).map((f) => toAttachment(f));
|
|
4579
4551
|
setItems((list) => list.concat(atts));
|
|
4580
4552
|
atts.forEach(run);
|
|
4581
4553
|
return atts;
|
|
4582
4554
|
}, [upload, run]);
|
|
4583
|
-
const remove =
|
|
4555
|
+
const remove = React27.useCallback((att) => {
|
|
4584
4556
|
const ac = controllers.current[att.id];
|
|
4585
4557
|
if (ac) {
|
|
4586
4558
|
try {
|
|
@@ -4591,10 +4563,10 @@ function useStagedFiles(upload, opts) {
|
|
|
4591
4563
|
}
|
|
4592
4564
|
setItems((list) => list.filter((f) => f.id !== att.id));
|
|
4593
4565
|
}, []);
|
|
4594
|
-
const retry =
|
|
4566
|
+
const retry = React27.useCallback((att) => {
|
|
4595
4567
|
run(att);
|
|
4596
4568
|
}, [run]);
|
|
4597
|
-
const clear =
|
|
4569
|
+
const clear = React27.useCallback(() => {
|
|
4598
4570
|
Object.values(controllers.current).forEach((ac) => {
|
|
4599
4571
|
try {
|
|
4600
4572
|
ac && ac.abort();
|
|
@@ -4718,7 +4690,7 @@ function FileGrid({ files = [], onOpen, onRemove, onRetry, tiles = true, maxHeig
|
|
|
4718
4690
|
}
|
|
4719
4691
|
|
|
4720
4692
|
// src/components/forms/MarkdownEditor.tsx
|
|
4721
|
-
var
|
|
4693
|
+
var React28 = __toESM(require("react"), 1);
|
|
4722
4694
|
var import_jsx_runtime57 = require("react/jsx-runtime");
|
|
4723
4695
|
var isMac = typeof navigator !== "undefined" && /Mac|iPhone|iPad/.test(navigator.platform || navigator.userAgent || "");
|
|
4724
4696
|
var INLINE_RE = /(\*\*\*[^*\n]+\*\*\*|\*\*[^*\n]+\*\*|__[^_\n]+__|~~[^~\n]+~~|`[^`\n]+`|\*[^*\s][^*\n]*\*|(?<![A-Za-z0-9_])_[^_\s][^_\n]*_|\[[^\]\n]*\]\([^)\s\n]*\)|https?:\/\/\S+)/g;
|
|
@@ -4932,7 +4904,7 @@ function syncDom(root, value) {
|
|
|
4932
4904
|
while (root.children.length > lines.length) root.removeChild(root.lastChild);
|
|
4933
4905
|
}
|
|
4934
4906
|
var LIST_CONT = RE_LI;
|
|
4935
|
-
var MarkdownEditor =
|
|
4907
|
+
var MarkdownEditor = React28.forwardRef(function MarkdownEditor2({
|
|
4936
4908
|
value = "",
|
|
4937
4909
|
onChange,
|
|
4938
4910
|
onSubmit,
|
|
@@ -4951,10 +4923,10 @@ var MarkdownEditor = React27.forwardRef(function MarkdownEditor2({
|
|
|
4951
4923
|
className = "",
|
|
4952
4924
|
id
|
|
4953
4925
|
}, ref) {
|
|
4954
|
-
const boxRef =
|
|
4955
|
-
const composing =
|
|
4956
|
-
const pendingCaret =
|
|
4957
|
-
|
|
4926
|
+
const boxRef = React28.useRef(null);
|
|
4927
|
+
const composing = React28.useRef(false);
|
|
4928
|
+
const pendingCaret = React28.useRef(null);
|
|
4929
|
+
React28.useLayoutEffect(() => {
|
|
4958
4930
|
const root = boxRef.current;
|
|
4959
4931
|
if (!root || composing.current) return;
|
|
4960
4932
|
const active = document.activeElement === root || root.contains(document.activeElement);
|
|
@@ -4963,7 +4935,7 @@ var MarkdownEditor = React27.forwardRef(function MarkdownEditor2({
|
|
|
4963
4935
|
pendingCaret.current = null;
|
|
4964
4936
|
if (active && caret != null) placeCaret(root, caret);
|
|
4965
4937
|
}, [value]);
|
|
4966
|
-
|
|
4938
|
+
React28.useEffect(() => {
|
|
4967
4939
|
if (autoFocus && boxRef.current) boxRef.current.focus();
|
|
4968
4940
|
}, [autoFocus]);
|
|
4969
4941
|
const caretNow = () => {
|
|
@@ -5030,7 +5002,7 @@ var MarkdownEditor = React27.forwardRef(function MarkdownEditor2({
|
|
|
5030
5002
|
api.replaceRange(from, to, next, from + next.length);
|
|
5031
5003
|
}
|
|
5032
5004
|
};
|
|
5033
|
-
|
|
5005
|
+
React28.useImperativeHandle(ref, () => api);
|
|
5034
5006
|
function detect(text, caret) {
|
|
5035
5007
|
if (!onTrigger) return;
|
|
5036
5008
|
const upto = text.slice(0, caret);
|
|
@@ -5182,10 +5154,10 @@ var MarkdownEditor = React27.forwardRef(function MarkdownEditor2({
|
|
|
5182
5154
|
});
|
|
5183
5155
|
|
|
5184
5156
|
// src/components/platform/AccountMenu.tsx
|
|
5185
|
-
var
|
|
5157
|
+
var React30 = __toESM(require("react"), 1);
|
|
5186
5158
|
|
|
5187
5159
|
// src/kits/session.ts
|
|
5188
|
-
var
|
|
5160
|
+
var React29 = __toESM(require("react"), 1);
|
|
5189
5161
|
var PERMISSION_CATALOG = [
|
|
5190
5162
|
{ group: "Plans", items: [
|
|
5191
5163
|
{ key: "plan.view", label: "View plans", detail: "Read any plan in the workspace." },
|
|
@@ -6752,8 +6724,8 @@ function roadmap(overrides) {
|
|
|
6752
6724
|
};
|
|
6753
6725
|
}
|
|
6754
6726
|
function useSession() {
|
|
6755
|
-
const [s, setS] =
|
|
6756
|
-
|
|
6727
|
+
const [s, setS] = React29.useState(getSession);
|
|
6728
|
+
React29.useEffect(() => subscribe(setS), []);
|
|
6757
6729
|
return s;
|
|
6758
6730
|
}
|
|
6759
6731
|
var SessionKit = {
|
|
@@ -6823,9 +6795,9 @@ function AccountMenu({
|
|
|
6823
6795
|
...rest
|
|
6824
6796
|
}) {
|
|
6825
6797
|
const session = SessionKit.useSession();
|
|
6826
|
-
const [open, setOpen] =
|
|
6827
|
-
const [switching, setSwitching] =
|
|
6828
|
-
const ref =
|
|
6798
|
+
const [open, setOpen] = React30.useState(false);
|
|
6799
|
+
const [switching, setSwitching] = React30.useState(false);
|
|
6800
|
+
const ref = React30.useRef(null);
|
|
6829
6801
|
const user = session.user;
|
|
6830
6802
|
const visibleAdmin = adminLinks.filter((l) => !l.perm || SessionKit.can(l.perm));
|
|
6831
6803
|
const pick = (item) => {
|
|
@@ -6877,7 +6849,7 @@ function AccountMenu({
|
|
|
6877
6849
|
/* @__PURE__ */ (0, import_jsx_runtime58.jsx)("span", { style: { flex: 1 }, children: "View as another member" }),
|
|
6878
6850
|
/* @__PURE__ */ (0, import_jsx_runtime58.jsx)("i", { className: "ph ph-caret-" + (switching ? "up" : "down"), "aria-hidden": "true", style: { fontSize: 11 } })
|
|
6879
6851
|
] }),
|
|
6880
|
-
switching ? /* @__PURE__ */ (0, import_jsx_runtime58.jsx)("div", { className: "fd-stack", style: { gap: 0
|
|
6852
|
+
switching ? /* @__PURE__ */ (0, import_jsx_runtime58.jsx)("div", { className: "fd-stack", style: { gap: 0 }, children: session.allUsers.filter((u) => u.status === "active").map((u) => /* @__PURE__ */ (0, import_jsx_runtime58.jsxs)(
|
|
6881
6853
|
"button",
|
|
6882
6854
|
{
|
|
6883
6855
|
type: "button",
|
|
@@ -6909,14 +6881,14 @@ function AccountMenu({
|
|
|
6909
6881
|
}
|
|
6910
6882
|
|
|
6911
6883
|
// src/components/platform/ApiSpecBrowser.tsx
|
|
6912
|
-
var
|
|
6884
|
+
var React31 = __toESM(require("react"), 1);
|
|
6913
6885
|
var import_jsx_runtime59 = require("react/jsx-runtime");
|
|
6914
6886
|
var METHOD_TONE = { GET: "success", POST: "info", PATCH: "warning", PUT: "warning", DELETE: "danger" };
|
|
6915
6887
|
function Json({ obj }) {
|
|
6916
6888
|
return /* @__PURE__ */ (0, import_jsx_runtime59.jsx)("pre", { className: "fd-json", children: JSON.stringify(obj, null, 2) });
|
|
6917
6889
|
}
|
|
6918
6890
|
function Endpoint({ s, onRequest }) {
|
|
6919
|
-
const [tried, setTried] =
|
|
6891
|
+
const [tried, setTried] = React31.useState(null);
|
|
6920
6892
|
const run = async () => {
|
|
6921
6893
|
setTried("busy");
|
|
6922
6894
|
const t0 = (window.performance || Date).now();
|
|
@@ -6989,10 +6961,10 @@ function ApiSpecBrowser({
|
|
|
6989
6961
|
className = "",
|
|
6990
6962
|
...rest
|
|
6991
6963
|
}) {
|
|
6992
|
-
const [q, setQ] =
|
|
6993
|
-
const [method, setMethod] =
|
|
6994
|
-
const [mod, setMod] =
|
|
6995
|
-
const [listOnly, setListOnly] =
|
|
6964
|
+
const [q, setQ] = React31.useState("");
|
|
6965
|
+
const [method, setMethod] = React31.useState(null);
|
|
6966
|
+
const [mod, setMod] = React31.useState(null);
|
|
6967
|
+
const [listOnly, setListOnly] = React31.useState(false);
|
|
6996
6968
|
const activeModule = modules && modules.find((m) => m.id === mod);
|
|
6997
6969
|
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())));
|
|
6998
6970
|
const effGroups = groups && groups.length ? groups : [["All endpoints", spec.map((s) => s.id)]];
|
|
@@ -7071,7 +7043,7 @@ function ApiSpecBrowser({
|
|
|
7071
7043
|
}
|
|
7072
7044
|
|
|
7073
7045
|
// src/components/platform/ProfilePage.tsx
|
|
7074
|
-
var
|
|
7046
|
+
var React32 = __toESM(require("react"), 1);
|
|
7075
7047
|
var import_jsx_runtime60 = require("react/jsx-runtime");
|
|
7076
7048
|
var TIMEZONES = ["America/New_York", "America/Chicago", "America/Denver", "America/Los_Angeles", "America/Anchorage", "Pacific/Honolulu", "Europe/London", "Europe/Berlin"];
|
|
7077
7049
|
var NOTIFY = [
|
|
@@ -7084,7 +7056,7 @@ var NOTIFY = [
|
|
|
7084
7056
|
function ProfilePage({ user: userProp, onSave, onNavigate, sessions, showSessions = true, className = "", ...rest }) {
|
|
7085
7057
|
const session = SessionKit.useSession();
|
|
7086
7058
|
const user = userProp || session.user;
|
|
7087
|
-
const [draft, setDraft] =
|
|
7059
|
+
const [draft, setDraft] = React32.useState(() => ({
|
|
7088
7060
|
name: user.name || "",
|
|
7089
7061
|
title: user.title || "",
|
|
7090
7062
|
email: user.email || "",
|
|
@@ -7093,8 +7065,8 @@ function ProfilePage({ user: userProp, onSave, onNavigate, sessions, showSession
|
|
|
7093
7065
|
bio: user.bio || "",
|
|
7094
7066
|
notify: user.notify || { planShared: true, planChanged: true, goalMissed: true, flagChanged: false, weekly: true }
|
|
7095
7067
|
}));
|
|
7096
|
-
const [saving, setSaving] =
|
|
7097
|
-
const [saved, setSaved] =
|
|
7068
|
+
const [saving, setSaving] = React32.useState(false);
|
|
7069
|
+
const [saved, setSaved] = React32.useState(false);
|
|
7098
7070
|
const set = (k, v) => {
|
|
7099
7071
|
setDraft((d) => Object.assign({}, d, { [k]: v }));
|
|
7100
7072
|
setSaved(false);
|
|
@@ -7284,10 +7256,10 @@ function ProfilePage({ user: userProp, onSave, onNavigate, sessions, showSession
|
|
|
7284
7256
|
}
|
|
7285
7257
|
|
|
7286
7258
|
// src/components/platform/RoadmapTimeline.tsx
|
|
7287
|
-
var
|
|
7259
|
+
var React34 = __toESM(require("react"), 1);
|
|
7288
7260
|
|
|
7289
7261
|
// src/kits/runtime.ts
|
|
7290
|
-
var
|
|
7262
|
+
var React33 = __toESM(require("react"), 1);
|
|
7291
7263
|
var WIRED_ENDPOINTS = [
|
|
7292
7264
|
// Nothing yet. Every id below would come from a real service:
|
|
7293
7265
|
// "plan.get", "placements.list", …
|
|
@@ -7458,8 +7430,8 @@ var RuntimeKit = {
|
|
|
7458
7430
|
};
|
|
7459
7431
|
RuntimeKit.declare(FEATURE_NEEDS);
|
|
7460
7432
|
function useRuntimeMode() {
|
|
7461
|
-
const [m, setM] =
|
|
7462
|
-
|
|
7433
|
+
const [m, setM] = React33.useState(RuntimeKit.getMode());
|
|
7434
|
+
React33.useEffect(() => RuntimeKit.subscribe(setM), []);
|
|
7463
7435
|
return m;
|
|
7464
7436
|
}
|
|
7465
7437
|
function useFeatureStatus(key) {
|
|
@@ -7542,12 +7514,12 @@ function RoadmapCard({ item, byKey, onOpenFlag }) {
|
|
|
7542
7514
|
}
|
|
7543
7515
|
function RoadmapTimeline({ onOpenFlag, title = "Roadmap", lede }) {
|
|
7544
7516
|
const session = SessionKit.useSession();
|
|
7545
|
-
const [project, setProject] =
|
|
7546
|
-
const [q, setQ] =
|
|
7547
|
-
const scrollRef =
|
|
7548
|
-
const nowRef =
|
|
7549
|
-
const rm =
|
|
7550
|
-
const byKey =
|
|
7517
|
+
const [project, setProject] = React34.useState("");
|
|
7518
|
+
const [q, setQ] = React34.useState("");
|
|
7519
|
+
const scrollRef = React34.useRef(null);
|
|
7520
|
+
const nowRef = React34.useRef(null);
|
|
7521
|
+
const rm = React34.useMemo(() => SessionKit.roadmap({ isComplete: RuntimeKit.isComplete }), [session]);
|
|
7522
|
+
const byKey = React34.useMemo(() => {
|
|
7551
7523
|
const m = {};
|
|
7552
7524
|
rm.items.forEach((i) => {
|
|
7553
7525
|
m[i.key] = i;
|
|
@@ -7556,7 +7528,7 @@ function RoadmapTimeline({ onOpenFlag, title = "Roadmap", lede }) {
|
|
|
7556
7528
|
}, [rm]);
|
|
7557
7529
|
const items = rm.items.filter((i) => (!project || i.project === project) && (!q || (i.label + " " + i.description + " " + (i.backend || "") + " " + i.key).toLowerCase().includes(q.toLowerCase())));
|
|
7558
7530
|
const projects = [...new Set(rm.items.map((i) => i.project))];
|
|
7559
|
-
|
|
7531
|
+
React34.useEffect(() => {
|
|
7560
7532
|
let raf1 = 0, raf2 = 0;
|
|
7561
7533
|
const place = () => {
|
|
7562
7534
|
const box = scrollRef.current, mark = nowRef.current;
|
|
@@ -7630,7 +7602,7 @@ function RoadmapTimeline({ onOpenFlag, title = "Roadmap", lede }) {
|
|
|
7630
7602
|
lastPhase = item.phase;
|
|
7631
7603
|
const inPhase = items.filter((i) => i.phase === item.phase).length;
|
|
7632
7604
|
const isBoundary = n === firstPending;
|
|
7633
|
-
return /* @__PURE__ */ (0, import_jsx_runtime61.jsxs)(
|
|
7605
|
+
return /* @__PURE__ */ (0, import_jsx_runtime61.jsxs)(React34.Fragment, { children: [
|
|
7634
7606
|
showPhase ? /* @__PURE__ */ (0, import_jsx_runtime61.jsxs)("div", { className: "fd-rm-era", children: [
|
|
7635
7607
|
/* @__PURE__ */ (0, import_jsx_runtime61.jsxs)("span", { className: "fd-row", style: { gap: 8, flexWrap: "wrap", alignItems: "baseline" }, children: [
|
|
7636
7608
|
/* @__PURE__ */ (0, import_jsx_runtime61.jsx)("span", { style: { fontWeight: 700 }, children: item.phase === 0 ? "Shipped" : "Phase " + item.phase + " \u2014 " + item.phaseName }),
|
|
@@ -7674,8 +7646,8 @@ function RoadmapTimeline({ onOpenFlag, title = "Roadmap", lede }) {
|
|
|
7674
7646
|
}
|
|
7675
7647
|
|
|
7676
7648
|
// src/components/platform/ComingSoon.tsx
|
|
7677
|
-
var
|
|
7678
|
-
var
|
|
7649
|
+
var React35 = __toESM(require("react"), 1);
|
|
7650
|
+
var import_react_dom5 = require("react-dom");
|
|
7679
7651
|
var import_jsx_runtime62 = require("react/jsx-runtime");
|
|
7680
7652
|
var BYPASS_STORE = "fd.soon.bypass.v1";
|
|
7681
7653
|
function readBypassed() {
|
|
@@ -7692,8 +7664,8 @@ function writeBypassed(list) {
|
|
|
7692
7664
|
}
|
|
7693
7665
|
}
|
|
7694
7666
|
function useBypass(key) {
|
|
7695
|
-
const [on, setOn] =
|
|
7696
|
-
|
|
7667
|
+
const [on, setOn] = React35.useState(() => !!key && readBypassed().indexOf(key) >= 0);
|
|
7668
|
+
React35.useEffect(() => {
|
|
7697
7669
|
setOn(!!key && readBypassed().indexOf(key) >= 0);
|
|
7698
7670
|
}, [key]);
|
|
7699
7671
|
const set = (next) => {
|
|
@@ -7740,9 +7712,9 @@ function SoonCard({ label, detail, backend, eta, effort, onRoadmap, allowed, onB
|
|
|
7740
7712
|
] });
|
|
7741
7713
|
}
|
|
7742
7714
|
function useHoverCard(open) {
|
|
7743
|
-
const anchor =
|
|
7744
|
-
const [pos, setPos] =
|
|
7745
|
-
|
|
7715
|
+
const anchor = React35.useRef(null);
|
|
7716
|
+
const [pos, setPos] = React35.useState(null);
|
|
7717
|
+
React35.useLayoutEffect(() => {
|
|
7746
7718
|
if (!open || !anchor.current) {
|
|
7747
7719
|
setPos(null);
|
|
7748
7720
|
return;
|
|
@@ -7869,9 +7841,9 @@ function ComingSoon({
|
|
|
7869
7841
|
] });
|
|
7870
7842
|
}
|
|
7871
7843
|
function InlineSoon({ label, detail, backend, eta, effort, onRoadmap, allowed, onBypass, blur, tip, className, rest, children }) {
|
|
7872
|
-
const [open, setOpen] =
|
|
7844
|
+
const [open, setOpen] = React35.useState(false);
|
|
7873
7845
|
const [anchor, pos] = useHoverCard(open);
|
|
7874
|
-
const close =
|
|
7846
|
+
const close = React35.useRef(null);
|
|
7875
7847
|
const show = () => {
|
|
7876
7848
|
if (close.current) {
|
|
7877
7849
|
clearTimeout(close.current);
|
|
@@ -7887,7 +7859,7 @@ function InlineSoon({ label, detail, backend, eta, effort, onRoadmap, allowed, o
|
|
|
7887
7859
|
setOpen(false);
|
|
7888
7860
|
}, 140);
|
|
7889
7861
|
};
|
|
7890
|
-
|
|
7862
|
+
React35.useEffect(() => () => {
|
|
7891
7863
|
if (close.current) clearTimeout(close.current);
|
|
7892
7864
|
}, []);
|
|
7893
7865
|
return /* @__PURE__ */ (0, import_jsx_runtime62.jsxs)(
|
|
@@ -7916,7 +7888,7 @@ function InlineSoon({ label, detail, backend, eta, effort, onRoadmap, allowed, o
|
|
|
7916
7888
|
children: /* @__PURE__ */ (0, import_jsx_runtime62.jsx)("i", { className: "ph ph-traffic-cone", "aria-hidden": "true" })
|
|
7917
7889
|
}
|
|
7918
7890
|
),
|
|
7919
|
-
open && pos ? (0,
|
|
7891
|
+
open && pos ? (0, import_react_dom5.createPortal)(
|
|
7920
7892
|
/* @__PURE__ */ (0, import_jsx_runtime62.jsx)(
|
|
7921
7893
|
"div",
|
|
7922
7894
|
{
|
|
@@ -8056,13 +8028,13 @@ function PermissionHint({ perm, children }) {
|
|
|
8056
8028
|
}
|
|
8057
8029
|
|
|
8058
8030
|
// src/components/platform/ModeSwitch.tsx
|
|
8059
|
-
var
|
|
8031
|
+
var React36 = __toESM(require("react"), 1);
|
|
8060
8032
|
var import_jsx_runtime64 = require("react/jsx-runtime");
|
|
8061
8033
|
function ModeSwitch({ canToggle = false, requestCount = 0, onClearLog, renderLog, onOpenSpec, summary }) {
|
|
8062
8034
|
const mode2 = useRuntimeMode();
|
|
8063
|
-
const [open, setOpen] =
|
|
8064
|
-
const ref =
|
|
8065
|
-
|
|
8035
|
+
const [open, setOpen] = React36.useState(false);
|
|
8036
|
+
const ref = React36.useRef(null);
|
|
8037
|
+
React36.useEffect(() => {
|
|
8066
8038
|
if (!open) return;
|
|
8067
8039
|
const away = (e) => {
|
|
8068
8040
|
if (ref.current && !ref.current.contains(e.target)) setOpen(false);
|
|
@@ -8311,11 +8283,11 @@ function SaturationDistribution({ campuses = [], floorBand, floorScore, onSelect
|
|
|
8311
8283
|
}
|
|
8312
8284
|
|
|
8313
8285
|
// src/components/planner/MixGap.tsx
|
|
8314
|
-
var
|
|
8286
|
+
var React37 = __toESM(require("react"), 1);
|
|
8315
8287
|
var import_jsx_runtime67 = require("react/jsx-runtime");
|
|
8316
8288
|
function MixGap({ rows = [], loading = false, className = "" }) {
|
|
8317
8289
|
const max = Math.max(1, ...rows.flatMap((r) => [r.target, r.realized]));
|
|
8318
|
-
const [hover, setHover] =
|
|
8290
|
+
const [hover, setHover] = React37.useState(null);
|
|
8319
8291
|
const toneOf = (gap) => gap >= -1 ? "ok" : gap >= -4 ? "warn" : "danger";
|
|
8320
8292
|
const TONE = { ok: "var(--ok-solid)", warn: "var(--warn-solid)", danger: "var(--danger-solid)" };
|
|
8321
8293
|
return /* @__PURE__ */ (0, import_jsx_runtime67.jsxs)("div", { className: ["fd-stack", className].filter(Boolean).join(" "), style: { gap: 4 }, children: [
|
|
@@ -8455,7 +8427,7 @@ function ChannelContribution({
|
|
|
8455
8427
|
}
|
|
8456
8428
|
|
|
8457
8429
|
// src/components/planner/BudgetReallocator.tsx
|
|
8458
|
-
var
|
|
8430
|
+
var React38 = __toESM(require("react"), 1);
|
|
8459
8431
|
var import_jsx_runtime69 = require("react/jsx-runtime");
|
|
8460
8432
|
var bandFor = (crp) => crp >= 200 ? "dominant" : crp >= 100 ? "strong" : crp >= 50 ? "adequate" : "weak";
|
|
8461
8433
|
function BudgetReallocator({
|
|
@@ -8471,8 +8443,8 @@ function BudgetReallocator({
|
|
|
8471
8443
|
onCancel,
|
|
8472
8444
|
className = ""
|
|
8473
8445
|
}) {
|
|
8474
|
-
const [draft, setDraft] =
|
|
8475
|
-
|
|
8446
|
+
const [draft, setDraft] = React38.useState(spend);
|
|
8447
|
+
React38.useEffect(() => setDraft(spend), [spend]);
|
|
8476
8448
|
const dirty = draft !== spend;
|
|
8477
8449
|
const nextCrp = scoreFor ? scoreFor(draft) : crp;
|
|
8478
8450
|
const nextBand = bandFor(nextCrp);
|
|
@@ -8642,7 +8614,7 @@ function ImportanceTag({ level, showLabel = true, size = "sm", className = "" })
|
|
|
8642
8614
|
}
|
|
8643
8615
|
|
|
8644
8616
|
// src/components/planner/PreferenceMeter.tsx
|
|
8645
|
-
var
|
|
8617
|
+
var React39 = __toESM(require("react"), 1);
|
|
8646
8618
|
var import_jsx_runtime72 = require("react/jsx-runtime");
|
|
8647
8619
|
function preferenceScore(criteria) {
|
|
8648
8620
|
const earned = criteria.reduce((n, c) => n + (Number(c.earned) || 0), 0);
|
|
@@ -8672,7 +8644,7 @@ function PreferenceMeter({
|
|
|
8672
8644
|
className = ""
|
|
8673
8645
|
}) {
|
|
8674
8646
|
const value = score == null ? preferenceScore(criteria) : score;
|
|
8675
|
-
const segments =
|
|
8647
|
+
const segments = React39.useMemo(() => preferenceSegments(criteria), [criteria]);
|
|
8676
8648
|
return /* @__PURE__ */ (0, import_jsx_runtime72.jsx)(
|
|
8677
8649
|
ScoreMeter,
|
|
8678
8650
|
{
|
|
@@ -8711,10 +8683,10 @@ function PreferenceMeter({
|
|
|
8711
8683
|
}
|
|
8712
8684
|
|
|
8713
8685
|
// src/components/chat/AgentChatPanel.tsx
|
|
8714
|
-
var
|
|
8686
|
+
var React45 = __toESM(require("react"), 1);
|
|
8715
8687
|
|
|
8716
8688
|
// src/components/chat/chatEngine.ts
|
|
8717
|
-
var
|
|
8689
|
+
var React40 = __toESM(require("react"), 1);
|
|
8718
8690
|
var CHAT_UNAVAILABLE = "chat_unavailable";
|
|
8719
8691
|
var JOB_PENDING = ["queued", "running"];
|
|
8720
8692
|
var JOB_SUCCESS = ["completed", "recovered"];
|
|
@@ -8768,22 +8740,22 @@ function useChatEngine(opts) {
|
|
|
8768
8740
|
onClear,
|
|
8769
8741
|
onFeedback
|
|
8770
8742
|
} = opts || {};
|
|
8771
|
-
const [status, setStatus] =
|
|
8772
|
-
const [threadId, setThreadId] =
|
|
8773
|
-
const [messages, setMessages] =
|
|
8774
|
-
const [queue, setQueue] =
|
|
8775
|
-
const [fatal, setFatal] =
|
|
8776
|
-
const [busy, setBusy] =
|
|
8777
|
-
const [turnStartedAt, setTurnStartedAt] =
|
|
8778
|
-
const listRef =
|
|
8779
|
-
const queueRef =
|
|
8780
|
-
const busyRef =
|
|
8781
|
-
const stoppedRef =
|
|
8782
|
-
const abortRef =
|
|
8783
|
-
const serverCount =
|
|
8784
|
-
const threadRef =
|
|
8785
|
-
const mounted =
|
|
8786
|
-
|
|
8743
|
+
const [status, setStatus] = React40.useState("idle");
|
|
8744
|
+
const [threadId, setThreadId] = React40.useState(null);
|
|
8745
|
+
const [messages, setMessages] = React40.useState([]);
|
|
8746
|
+
const [queue, setQueue] = React40.useState([]);
|
|
8747
|
+
const [fatal, setFatal] = React40.useState(null);
|
|
8748
|
+
const [busy, setBusy] = React40.useState(false);
|
|
8749
|
+
const [turnStartedAt, setTurnStartedAt] = React40.useState(null);
|
|
8750
|
+
const listRef = React40.useRef([]);
|
|
8751
|
+
const queueRef = React40.useRef([]);
|
|
8752
|
+
const busyRef = React40.useRef(false);
|
|
8753
|
+
const stoppedRef = React40.useRef(false);
|
|
8754
|
+
const abortRef = React40.useRef(null);
|
|
8755
|
+
const serverCount = React40.useRef(0);
|
|
8756
|
+
const threadRef = React40.useRef(null);
|
|
8757
|
+
const mounted = React40.useRef(true);
|
|
8758
|
+
React40.useEffect(() => {
|
|
8787
8759
|
mounted.current = true;
|
|
8788
8760
|
return () => {
|
|
8789
8761
|
mounted.current = false;
|
|
@@ -8805,14 +8777,14 @@ function useChatEngine(opts) {
|
|
|
8805
8777
|
}
|
|
8806
8778
|
return false;
|
|
8807
8779
|
};
|
|
8808
|
-
const loadThread =
|
|
8780
|
+
const loadThread = React40.useCallback(async (id) => {
|
|
8809
8781
|
const data = await apiAdapter.getThread(id);
|
|
8810
8782
|
const list = [...data && data.messages || []];
|
|
8811
8783
|
serverCount.current = list.length;
|
|
8812
8784
|
commit(list);
|
|
8813
8785
|
return list;
|
|
8814
8786
|
}, [apiAdapter]);
|
|
8815
|
-
|
|
8787
|
+
React40.useEffect(() => {
|
|
8816
8788
|
if (!apiAdapter) {
|
|
8817
8789
|
setStatus("idle");
|
|
8818
8790
|
setFatal(null);
|
|
@@ -9025,7 +8997,7 @@ function useChatEngine(opts) {
|
|
|
9025
8997
|
await dispatchTurn(turn);
|
|
9026
8998
|
}
|
|
9027
8999
|
}
|
|
9028
|
-
const send =
|
|
9000
|
+
const send = React40.useCallback((text, attachments) => {
|
|
9029
9001
|
const body = (text || "").trim();
|
|
9030
9002
|
if (!body && !(attachments && attachments.length)) return;
|
|
9031
9003
|
if (status === "disconnected") return;
|
|
@@ -9035,7 +9007,7 @@ function useChatEngine(opts) {
|
|
|
9035
9007
|
stoppedRef.current = false;
|
|
9036
9008
|
drain();
|
|
9037
9009
|
}, [status]);
|
|
9038
|
-
const stop =
|
|
9010
|
+
const stop = React40.useCallback(() => {
|
|
9039
9011
|
stoppedRef.current = true;
|
|
9040
9012
|
const ac = abortRef.current;
|
|
9041
9013
|
if (ac) {
|
|
@@ -9054,11 +9026,11 @@ function useChatEngine(opts) {
|
|
|
9054
9026
|
store.del(STORAGE_PREFIX + threadRef.current);
|
|
9055
9027
|
}
|
|
9056
9028
|
}, [apiAdapter]);
|
|
9057
|
-
const removeQueued =
|
|
9029
|
+
const removeQueued = React40.useCallback((id) => {
|
|
9058
9030
|
queueRef.current = queueRef.current.filter((t) => t.id !== id);
|
|
9059
9031
|
setQueue(queueRef.current.slice());
|
|
9060
9032
|
}, []);
|
|
9061
|
-
const retry =
|
|
9033
|
+
const retry = React40.useCallback(() => {
|
|
9062
9034
|
const list = listRef.current;
|
|
9063
9035
|
let at = -1;
|
|
9064
9036
|
for (let i = list.length - 1; i >= 0; i--) if (list[i].role === "user") {
|
|
@@ -9074,19 +9046,19 @@ function useChatEngine(opts) {
|
|
|
9074
9046
|
setQueue(queueRef.current.slice());
|
|
9075
9047
|
drain();
|
|
9076
9048
|
}, []);
|
|
9077
|
-
const clear =
|
|
9049
|
+
const clear = React40.useCallback(() => {
|
|
9078
9050
|
commit([]);
|
|
9079
9051
|
serverCount.current = 0;
|
|
9080
9052
|
queueRef.current = [];
|
|
9081
9053
|
setQueue([]);
|
|
9082
9054
|
onClear && onClear();
|
|
9083
9055
|
}, [onClear]);
|
|
9084
|
-
const setFeedback =
|
|
9056
|
+
const setFeedback = React40.useCallback((id, value) => {
|
|
9085
9057
|
patch(id, (m) => ({ feedback: m.feedback === value ? null : value }));
|
|
9086
9058
|
const msg = listRef.current.find((m) => m.id === id);
|
|
9087
9059
|
onFeedback && onFeedback({ message: msg, feedback: msg ? msg.feedback : value });
|
|
9088
9060
|
}, [onFeedback]);
|
|
9089
|
-
const reload =
|
|
9061
|
+
const reload = React40.useCallback(async () => {
|
|
9090
9062
|
if (!threadRef.current) return;
|
|
9091
9063
|
setStatus("loading");
|
|
9092
9064
|
try {
|
|
@@ -9124,10 +9096,10 @@ var ChatKit = {
|
|
|
9124
9096
|
};
|
|
9125
9097
|
|
|
9126
9098
|
// src/components/chat/ChatTranscript.tsx
|
|
9127
|
-
var
|
|
9099
|
+
var React42 = __toESM(require("react"), 1);
|
|
9128
9100
|
|
|
9129
9101
|
// src/components/chat/ChatTurn.tsx
|
|
9130
|
-
var
|
|
9102
|
+
var React41 = __toESM(require("react"), 1);
|
|
9131
9103
|
var import_jsx_runtime73 = require("react/jsx-runtime");
|
|
9132
9104
|
function JsonView({ value }) {
|
|
9133
9105
|
let text;
|
|
@@ -9164,7 +9136,7 @@ function PacketCard({ packet, schema, render, onApply, applied }) {
|
|
|
9164
9136
|
] });
|
|
9165
9137
|
}
|
|
9166
9138
|
function ThinkingBlock({ text, durationMs, streaming, defaultOpen = false }) {
|
|
9167
|
-
const [open, setOpen] =
|
|
9139
|
+
const [open, setOpen] = React41.useState(defaultOpen);
|
|
9168
9140
|
if (!text) return null;
|
|
9169
9141
|
return /* @__PURE__ */ (0, import_jsx_runtime73.jsxs)("div", { className: "fdc-think" + (open ? " is-open" : ""), children: [
|
|
9170
9142
|
/* @__PURE__ */ (0, import_jsx_runtime73.jsxs)("button", { type: "button", className: "fdc-think-head", onClick: () => setOpen((v) => !v), "aria-expanded": open, children: [
|
|
@@ -9181,7 +9153,7 @@ function ThinkingBlock({ text, durationMs, streaming, defaultOpen = false }) {
|
|
|
9181
9153
|
] });
|
|
9182
9154
|
}
|
|
9183
9155
|
function Citations({ items = [], onOpen }) {
|
|
9184
|
-
const [open, setOpen] =
|
|
9156
|
+
const [open, setOpen] = React41.useState(false);
|
|
9185
9157
|
if (!items.length) return null;
|
|
9186
9158
|
return /* @__PURE__ */ (0, import_jsx_runtime73.jsxs)("div", { className: "fdc-cites", children: [
|
|
9187
9159
|
/* @__PURE__ */ (0, import_jsx_runtime73.jsxs)("button", { type: "button", className: "fdc-cites-head", onClick: () => setOpen((v) => !v), "aria-expanded": open, children: [
|
|
@@ -9207,7 +9179,7 @@ function clampText(text, max) {
|
|
|
9207
9179
|
return (at > max * 0.6 ? cut.slice(0, at) : cut).trimEnd() + "\u2026";
|
|
9208
9180
|
}
|
|
9209
9181
|
function MessageBody({ message: m, ctx }) {
|
|
9210
|
-
const [expanded, setExpanded] =
|
|
9182
|
+
const [expanded, setExpanded] = React41.useState(false);
|
|
9211
9183
|
const isUser = m.role === "user";
|
|
9212
9184
|
const raw = m.text || "";
|
|
9213
9185
|
const clamped = !expanded && !m.streaming ? clampText(raw, ctx.maxVisibleChars) : null;
|
|
@@ -9274,9 +9246,9 @@ function MessageBody({ message: m, ctx }) {
|
|
|
9274
9246
|
] });
|
|
9275
9247
|
}
|
|
9276
9248
|
function useCopyRun() {
|
|
9277
|
-
const [done, setDone] =
|
|
9278
|
-
const t =
|
|
9279
|
-
|
|
9249
|
+
const [done, setDone] = React41.useState(false);
|
|
9250
|
+
const t = React41.useRef(null);
|
|
9251
|
+
React41.useEffect(() => () => {
|
|
9280
9252
|
if (t.current) clearTimeout(t.current);
|
|
9281
9253
|
}, []);
|
|
9282
9254
|
return [done, (text) => {
|
|
@@ -9303,7 +9275,7 @@ function RunActions({ group, ctx }) {
|
|
|
9303
9275
|
] }),
|
|
9304
9276
|
isAssistant && ctx.onRetry ? /* @__PURE__ */ (0, import_jsx_runtime73.jsx)("button", { type: "button", className: "fdc-act", onClick: ctx.onRetry, "aria-label": "Retry this turn", children: /* @__PURE__ */ (0, import_jsx_runtime73.jsx)("i", { className: "ph ph-arrow-clockwise", "aria-hidden": "true" }) }) : null,
|
|
9305
9277
|
group.role === "user" && ctx.onEdit ? /* @__PURE__ */ (0, import_jsx_runtime73.jsx)("button", { type: "button", className: "fdc-act", onClick: () => ctx.onEdit(last), "aria-label": "Edit and resend", children: /* @__PURE__ */ (0, import_jsx_runtime73.jsx)("i", { className: "ph ph-pencil-simple", "aria-hidden": "true" }) }) : null,
|
|
9306
|
-
isAssistant && ctx.onFeedback ? /* @__PURE__ */ (0, import_jsx_runtime73.jsxs)(
|
|
9278
|
+
isAssistant && ctx.onFeedback ? /* @__PURE__ */ (0, import_jsx_runtime73.jsxs)(React41.Fragment, { children: [
|
|
9307
9279
|
/* @__PURE__ */ (0, import_jsx_runtime73.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_runtime73.jsx)("i", { className: "ph ph-thumbs-up", "aria-hidden": "true" }) }),
|
|
9308
9280
|
/* @__PURE__ */ (0, import_jsx_runtime73.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_runtime73.jsx)("i", { className: "ph ph-thumbs-down", "aria-hidden": "true" }) })
|
|
9309
9281
|
] }) : null,
|
|
@@ -9398,10 +9370,10 @@ function ChatTranscript({
|
|
|
9398
9370
|
renderEmpty,
|
|
9399
9371
|
className = ""
|
|
9400
9372
|
}) {
|
|
9401
|
-
const scroller =
|
|
9402
|
-
const stick =
|
|
9403
|
-
const [pill, setPill] =
|
|
9404
|
-
const seen =
|
|
9373
|
+
const scroller = React42.useRef(null);
|
|
9374
|
+
const stick = React42.useRef(true);
|
|
9375
|
+
const [pill, setPill] = React42.useState(0);
|
|
9376
|
+
const seen = React42.useRef(0);
|
|
9405
9377
|
const toBottom = (smooth) => {
|
|
9406
9378
|
const el = scroller.current;
|
|
9407
9379
|
if (!el) return;
|
|
@@ -9420,7 +9392,7 @@ function ChatTranscript({
|
|
|
9420
9392
|
seen.current = messages.length;
|
|
9421
9393
|
}
|
|
9422
9394
|
};
|
|
9423
|
-
|
|
9395
|
+
React42.useLayoutEffect(() => {
|
|
9424
9396
|
const el = scroller.current;
|
|
9425
9397
|
if (!el) return;
|
|
9426
9398
|
if (stick.current) {
|
|
@@ -9428,7 +9400,7 @@ function ChatTranscript({
|
|
|
9428
9400
|
seen.current = messages.length;
|
|
9429
9401
|
} else setPill(Math.max(0, messages.length - seen.current));
|
|
9430
9402
|
}, [messages]);
|
|
9431
|
-
|
|
9403
|
+
React42.useEffect(() => {
|
|
9432
9404
|
const el = scroller.current;
|
|
9433
9405
|
const inner = el && el.firstChild;
|
|
9434
9406
|
if (!el || !inner || typeof ResizeObserver === "undefined") return;
|
|
@@ -9438,7 +9410,7 @@ function ChatTranscript({
|
|
|
9438
9410
|
ro.observe(inner);
|
|
9439
9411
|
return () => ro.disconnect();
|
|
9440
9412
|
}, []);
|
|
9441
|
-
const groups =
|
|
9413
|
+
const groups = React42.useMemo(() => groupMessages(messages), [messages]);
|
|
9442
9414
|
const empty = !messages.length && status === "ready";
|
|
9443
9415
|
return /* @__PURE__ */ (0, import_jsx_runtime74.jsxs)("div", { className: ["fdc-scroll", className].filter(Boolean).join(" "), ref: scroller, onScroll, children: [
|
|
9444
9416
|
/* @__PURE__ */ (0, import_jsx_runtime74.jsxs)("div", { className: "fdc-log", role: "log", "aria-label": "Conversation", children: [
|
|
@@ -9462,7 +9434,7 @@ function ChatTranscript({
|
|
|
9462
9434
|
const prev = groups[i - 1];
|
|
9463
9435
|
const k = dayKey(g.messages[0].timestamp);
|
|
9464
9436
|
const showDay = !!k && (!prev || dayKey(prev.messages[0].timestamp) !== k);
|
|
9465
|
-
return /* @__PURE__ */ (0, import_jsx_runtime74.jsxs)(
|
|
9437
|
+
return /* @__PURE__ */ (0, import_jsx_runtime74.jsxs)(React42.Fragment, { children: [
|
|
9466
9438
|
showDay ? /* @__PURE__ */ (0, import_jsx_runtime74.jsx)("div", { className: "fdc-day", children: /* @__PURE__ */ (0, import_jsx_runtime74.jsx)("span", { children: dayLabel(k) }) }) : null,
|
|
9467
9439
|
/* @__PURE__ */ (0, import_jsx_runtime74.jsx)(ChatTurn, { group: g, ctx })
|
|
9468
9440
|
] }, g.key || i);
|
|
@@ -9479,7 +9451,7 @@ function ChatTranscript({
|
|
|
9479
9451
|
var TranscriptKit = { groupMessages };
|
|
9480
9452
|
|
|
9481
9453
|
// src/components/chat/ChatComposer.tsx
|
|
9482
|
-
var
|
|
9454
|
+
var React43 = __toESM(require("react"), 1);
|
|
9483
9455
|
var import_jsx_runtime75 = require("react/jsx-runtime");
|
|
9484
9456
|
function ChatComposer({
|
|
9485
9457
|
onSubmit,
|
|
@@ -9507,17 +9479,17 @@ function ChatComposer({
|
|
|
9507
9479
|
onReject,
|
|
9508
9480
|
onOpenAttachment
|
|
9509
9481
|
}) {
|
|
9510
|
-
const [text, setText] =
|
|
9511
|
-
const [trigger, setTrigger] =
|
|
9512
|
-
const [mentionItems, setMentionItems] =
|
|
9513
|
-
const [listening, setListening] =
|
|
9514
|
-
const [notice, setNotice] =
|
|
9515
|
-
const editor =
|
|
9516
|
-
const wrap =
|
|
9517
|
-
const stopVoice =
|
|
9482
|
+
const [text, setText] = React43.useState(draft || "");
|
|
9483
|
+
const [trigger, setTrigger] = React43.useState(null);
|
|
9484
|
+
const [mentionItems, setMentionItems] = React43.useState([]);
|
|
9485
|
+
const [listening, setListening] = React43.useState(false);
|
|
9486
|
+
const [notice, setNotice] = React43.useState(null);
|
|
9487
|
+
const editor = React43.useRef(null);
|
|
9488
|
+
const wrap = React43.useRef(null);
|
|
9489
|
+
const stopVoice = React43.useRef(null);
|
|
9518
9490
|
const staged = useStagedFiles(fileUploadHandler, { onError: () => {
|
|
9519
9491
|
} });
|
|
9520
|
-
|
|
9492
|
+
React43.useEffect(() => {
|
|
9521
9493
|
if (draft != null && draft !== text) setText(draft);
|
|
9522
9494
|
}, [draft]);
|
|
9523
9495
|
const change = (v) => {
|
|
@@ -9551,7 +9523,7 @@ function ChatComposer({
|
|
|
9551
9523
|
e.preventDefault();
|
|
9552
9524
|
staged.add(found.files);
|
|
9553
9525
|
};
|
|
9554
|
-
|
|
9526
|
+
React43.useEffect(() => {
|
|
9555
9527
|
if (!trigger || trigger.type !== "mention" || !mentionSources) {
|
|
9556
9528
|
setMentionItems([]);
|
|
9557
9529
|
return;
|
|
@@ -9569,7 +9541,7 @@ function ChatComposer({
|
|
|
9569
9541
|
const q = (trigger.query || "").toLowerCase();
|
|
9570
9542
|
setMentionItems(mentionSources.filter((m) => !q || (m.label + " " + (m.description || "")).toLowerCase().includes(q)));
|
|
9571
9543
|
}, [trigger, mentionSources]);
|
|
9572
|
-
const slashItems =
|
|
9544
|
+
const slashItems = React43.useMemo(() => {
|
|
9573
9545
|
if (!trigger || trigger.type !== "slash" || !slashCommands) return [];
|
|
9574
9546
|
const q = (trigger.query || "").toLowerCase();
|
|
9575
9547
|
return slashCommands.filter((c) => !q || (c.id + " " + c.label + " " + (c.description || "")).toLowerCase().includes(q));
|
|
@@ -9743,12 +9715,12 @@ function ChatComposer({
|
|
|
9743
9715
|
}
|
|
9744
9716
|
|
|
9745
9717
|
// src/components/chat/ChatSessionBar.tsx
|
|
9746
|
-
var
|
|
9718
|
+
var React44 = __toESM(require("react"), 1);
|
|
9747
9719
|
var import_jsx_runtime76 = require("react/jsx-runtime");
|
|
9748
9720
|
var compact2 = meterFormats.compact;
|
|
9749
9721
|
function ChatSessionBar({ sessionStats, contextUsage, usageLimits, onClear, extras }) {
|
|
9750
|
-
const [open, setOpen] =
|
|
9751
|
-
const anchor =
|
|
9722
|
+
const [open, setOpen] = React44.useState(false);
|
|
9723
|
+
const anchor = React44.useRef(null);
|
|
9752
9724
|
const stats = sessionStats || null;
|
|
9753
9725
|
const cu = contextUsage || null;
|
|
9754
9726
|
const limits = usageLimits || null;
|
|
@@ -9763,7 +9735,7 @@ function ChatSessionBar({ sessionStats, contextUsage, usageLimits, onClear, extr
|
|
|
9763
9735
|
if (stats && stats.runningTasks) bits.push(stats.runningTasks + " running task" + (stats.runningTasks === 1 ? "" : "s"));
|
|
9764
9736
|
if (cu) bits.push(pct + "% context");
|
|
9765
9737
|
const expandable = !!(cu || limits);
|
|
9766
|
-
return /* @__PURE__ */ (0, import_jsx_runtime76.jsxs)(
|
|
9738
|
+
return /* @__PURE__ */ (0, import_jsx_runtime76.jsxs)(React44.Fragment, { children: [
|
|
9767
9739
|
/* @__PURE__ */ (0, import_jsx_runtime76.jsxs)("div", { className: "fdc-bar", children: [
|
|
9768
9740
|
/* @__PURE__ */ (0, import_jsx_runtime76.jsxs)(
|
|
9769
9741
|
"button",
|
|
@@ -9784,60 +9756,73 @@ function ChatSessionBar({ sessionStats, contextUsage, usageLimits, onClear, extr
|
|
|
9784
9756
|
),
|
|
9785
9757
|
extras
|
|
9786
9758
|
] }),
|
|
9787
|
-
/* @__PURE__ */ (0, import_jsx_runtime76.jsx)(
|
|
9788
|
-
|
|
9789
|
-
|
|
9790
|
-
|
|
9791
|
-
|
|
9792
|
-
|
|
9793
|
-
|
|
9794
|
-
|
|
9795
|
-
|
|
9796
|
-
|
|
9797
|
-
|
|
9798
|
-
|
|
9799
|
-
|
|
9800
|
-
|
|
9801
|
-
|
|
9802
|
-
|
|
9803
|
-
|
|
9804
|
-
|
|
9805
|
-
|
|
9806
|
-
|
|
9807
|
-
|
|
9808
|
-
|
|
9809
|
-
|
|
9810
|
-
|
|
9811
|
-
|
|
9812
|
-
|
|
9813
|
-
|
|
9814
|
-
|
|
9815
|
-
|
|
9816
|
-
|
|
9817
|
-
|
|
9818
|
-
/* @__PURE__ */ (0, import_jsx_runtime76.
|
|
9819
|
-
|
|
9820
|
-
|
|
9821
|
-
|
|
9822
|
-
|
|
9823
|
-
|
|
9824
|
-
|
|
9825
|
-
|
|
9826
|
-
|
|
9827
|
-
|
|
9828
|
-
|
|
9829
|
-
|
|
9830
|
-
/* @__PURE__ */ (0, import_jsx_runtime76.
|
|
9831
|
-
|
|
9832
|
-
|
|
9833
|
-
|
|
9834
|
-
|
|
9835
|
-
|
|
9836
|
-
|
|
9837
|
-
|
|
9838
|
-
|
|
9839
|
-
|
|
9840
|
-
|
|
9759
|
+
/* @__PURE__ */ (0, import_jsx_runtime76.jsx)(
|
|
9760
|
+
Popover,
|
|
9761
|
+
{
|
|
9762
|
+
open,
|
|
9763
|
+
anchorRef: anchor,
|
|
9764
|
+
placement: "top-start",
|
|
9765
|
+
onClose: () => setOpen(false),
|
|
9766
|
+
minWidth: 330,
|
|
9767
|
+
maxHeight: 460,
|
|
9768
|
+
padded: true,
|
|
9769
|
+
label: "Usage",
|
|
9770
|
+
footer: onClear ? /* @__PURE__ */ (0, import_jsx_runtime76.jsxs)("button", { type: "button", className: "fdc-usage-clear", onClick: () => {
|
|
9771
|
+
setOpen(false);
|
|
9772
|
+
onClear();
|
|
9773
|
+
}, children: [
|
|
9774
|
+
/* @__PURE__ */ (0, import_jsx_runtime76.jsx)("i", { className: "ph ph-trash", "aria-hidden": "true" }),
|
|
9775
|
+
"Clear conversation"
|
|
9776
|
+
] }) : void 0,
|
|
9777
|
+
children: /* @__PURE__ */ (0, import_jsx_runtime76.jsxs)("div", { className: "fdc-usage", children: [
|
|
9778
|
+
cu ? /* @__PURE__ */ (0, import_jsx_runtime76.jsx)("section", { className: "fdc-usage-sec", children: /* @__PURE__ */ (0, import_jsx_runtime76.jsx)(
|
|
9779
|
+
SegmentedMeter,
|
|
9780
|
+
{
|
|
9781
|
+
total,
|
|
9782
|
+
segments: cu.segments,
|
|
9783
|
+
label: cu.label || "Context window",
|
|
9784
|
+
format: cu.format === "bytes" ? meterFormats.bytes : compact2,
|
|
9785
|
+
height: 8,
|
|
9786
|
+
legend: true,
|
|
9787
|
+
remainderLabel: "Free"
|
|
9788
|
+
}
|
|
9789
|
+
) }) : null,
|
|
9790
|
+
limits && limits.length ? /* @__PURE__ */ (0, import_jsx_runtime76.jsxs)("section", { className: "fdc-usage-sec", children: [
|
|
9791
|
+
/* @__PURE__ */ (0, import_jsx_runtime76.jsx)("h4", { className: "fdc-usage-h", children: "Usage limits" }),
|
|
9792
|
+
/* @__PURE__ */ (0, import_jsx_runtime76.jsx)("div", { className: "fdc-usage-rows", children: limits.map((l) => /* @__PURE__ */ (0, import_jsx_runtime76.jsx)(
|
|
9793
|
+
QuotaRow,
|
|
9794
|
+
{
|
|
9795
|
+
label: l.label,
|
|
9796
|
+
percent: l.percent,
|
|
9797
|
+
note: l.resetsAt ? "Resets " + formatRelative(l.resetsAt) : l.note
|
|
9798
|
+
},
|
|
9799
|
+
l.id
|
|
9800
|
+
)) })
|
|
9801
|
+
] }) : null,
|
|
9802
|
+
stats ? /* @__PURE__ */ (0, import_jsx_runtime76.jsxs)("section", { className: "fdc-usage-sec fdc-usage-stats", children: [
|
|
9803
|
+
stats.elapsedMs ? /* @__PURE__ */ (0, import_jsx_runtime76.jsxs)("div", { children: [
|
|
9804
|
+
/* @__PURE__ */ (0, import_jsx_runtime76.jsx)("span", { children: "Session" }),
|
|
9805
|
+
/* @__PURE__ */ (0, import_jsx_runtime76.jsx)("b", { className: "fd-tabular", children: formatDuration(stats.elapsedMs) })
|
|
9806
|
+
] }) : null,
|
|
9807
|
+
stats.tokens ? /* @__PURE__ */ (0, import_jsx_runtime76.jsxs)("div", { children: [
|
|
9808
|
+
/* @__PURE__ */ (0, import_jsx_runtime76.jsx)("span", { children: "Tokens" }),
|
|
9809
|
+
/* @__PURE__ */ (0, import_jsx_runtime76.jsx)("b", { className: "fd-tabular", children: stats.tokens.toLocaleString() })
|
|
9810
|
+
] }) : null,
|
|
9811
|
+
stats.costUsd != null ? /* @__PURE__ */ (0, import_jsx_runtime76.jsxs)("div", { children: [
|
|
9812
|
+
/* @__PURE__ */ (0, import_jsx_runtime76.jsx)("span", { children: "Cost" }),
|
|
9813
|
+
/* @__PURE__ */ (0, import_jsx_runtime76.jsxs)("b", { className: "fd-tabular", children: [
|
|
9814
|
+
"$",
|
|
9815
|
+
Number(stats.costUsd).toFixed(3)
|
|
9816
|
+
] })
|
|
9817
|
+
] }) : null,
|
|
9818
|
+
stats.turns ? /* @__PURE__ */ (0, import_jsx_runtime76.jsxs)("div", { children: [
|
|
9819
|
+
/* @__PURE__ */ (0, import_jsx_runtime76.jsx)("span", { children: "Turns" }),
|
|
9820
|
+
/* @__PURE__ */ (0, import_jsx_runtime76.jsx)("b", { className: "fd-tabular", children: stats.turns })
|
|
9821
|
+
] }) : null
|
|
9822
|
+
] }) : null
|
|
9823
|
+
] })
|
|
9824
|
+
}
|
|
9825
|
+
)
|
|
9841
9826
|
] });
|
|
9842
9827
|
}
|
|
9843
9828
|
function ModelControls({
|
|
@@ -9891,7 +9876,7 @@ function ModelControls({
|
|
|
9891
9876
|
] })
|
|
9892
9877
|
});
|
|
9893
9878
|
}
|
|
9894
|
-
return /* @__PURE__ */ (0, import_jsx_runtime76.jsxs)(
|
|
9879
|
+
return /* @__PURE__ */ (0, import_jsx_runtime76.jsxs)(React44.Fragment, { children: [
|
|
9895
9880
|
/* @__PURE__ */ (0, import_jsx_runtime76.jsx)(
|
|
9896
9881
|
MenuButton,
|
|
9897
9882
|
{
|
|
@@ -10008,11 +9993,11 @@ function AgentChatPanel({
|
|
|
10008
9993
|
onFeedback,
|
|
10009
9994
|
onEditMessage
|
|
10010
9995
|
}) {
|
|
10011
|
-
const [panelWidth, setPanelWidth] =
|
|
10012
|
-
const [applied, setApplied] =
|
|
10013
|
-
const [draft, setDraft] =
|
|
10014
|
-
const dragging =
|
|
10015
|
-
|
|
9996
|
+
const [panelWidth, setPanelWidth] = React45.useState(width);
|
|
9997
|
+
const [applied, setApplied] = React45.useState({});
|
|
9998
|
+
const [draft, setDraft] = React45.useState("");
|
|
9999
|
+
const dragging = React45.useRef(null);
|
|
10000
|
+
React45.useEffect(() => setPanelWidth(width), [width]);
|
|
10016
10001
|
const engine = useChatEngine({
|
|
10017
10002
|
contextType,
|
|
10018
10003
|
contextId,
|
|
@@ -10216,7 +10201,7 @@ function AgentChatPanel({
|
|
|
10216
10201
|
}
|
|
10217
10202
|
|
|
10218
10203
|
// src/kits/query.ts
|
|
10219
|
-
var
|
|
10204
|
+
var React46 = __toESM(require("react"), 1);
|
|
10220
10205
|
function eqFilter(get2) {
|
|
10221
10206
|
return (row, value) => Array.isArray(value) ? value.includes(get2(row)) : get2(row) === value;
|
|
10222
10207
|
}
|
|
@@ -10248,22 +10233,22 @@ function compare(a, b, dir) {
|
|
|
10248
10233
|
var API = null;
|
|
10249
10234
|
var PREFS = null;
|
|
10250
10235
|
function useServerTable({ endpoint, params, defaults, deps, prefsKey }) {
|
|
10251
|
-
const [query, setQuery] =
|
|
10236
|
+
const [query, setQuery] = React46.useState(() => {
|
|
10252
10237
|
const store = PREFS || window.PlannerPrefs;
|
|
10253
10238
|
const saved = prefsKey && store ? store.getTable(prefsKey) : {};
|
|
10254
10239
|
return { ...DEFAULTS, ...defaults || {}, ...saved.pageSize ? { pageSize: saved.pageSize } : {}, ...saved.sort ? { sort: saved.sort, dir: saved.dir || "desc" } : {} };
|
|
10255
10240
|
});
|
|
10256
|
-
const savePref =
|
|
10241
|
+
const savePref = React46.useCallback((patch2) => {
|
|
10257
10242
|
const store = PREFS || window.PlannerPrefs;
|
|
10258
10243
|
if (prefsKey && store) store.setTable(prefsKey, patch2);
|
|
10259
10244
|
}, [prefsKey]);
|
|
10260
|
-
const [res, setRes] =
|
|
10261
|
-
const [loading, setLoading] =
|
|
10262
|
-
const seq2 =
|
|
10245
|
+
const [res, setRes] = React46.useState(null);
|
|
10246
|
+
const [loading, setLoading] = React46.useState(true);
|
|
10247
|
+
const seq2 = React46.useRef(0);
|
|
10263
10248
|
const depKey = (deps || []).join("|");
|
|
10264
10249
|
const paramKey = JSON.stringify(params || {});
|
|
10265
10250
|
const queryKey = JSON.stringify(query);
|
|
10266
|
-
|
|
10251
|
+
React46.useEffect(() => {
|
|
10267
10252
|
const id = ++seq2.current;
|
|
10268
10253
|
setLoading(true);
|
|
10269
10254
|
const t = setTimeout(() => {
|