@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.js
CHANGED
|
@@ -57,6 +57,7 @@ function IconButton({
|
|
|
57
57
|
label,
|
|
58
58
|
size = "md",
|
|
59
59
|
variant = "ghost",
|
|
60
|
+
tone = "neutral",
|
|
60
61
|
round = false,
|
|
61
62
|
disabled = false,
|
|
62
63
|
className = "",
|
|
@@ -64,7 +65,8 @@ function IconButton({
|
|
|
64
65
|
}) {
|
|
65
66
|
const cls = [
|
|
66
67
|
"fd-btn-icon",
|
|
67
|
-
variant === "outline" ? "fd-btn-icon-outline" : "",
|
|
68
|
+
variant === "outline" ? "fd-btn-icon-outline" : variant === "solid" ? "fd-btn-icon-solid" : "",
|
|
69
|
+
tone !== "neutral" ? "is-" + tone : "",
|
|
68
70
|
size === "sm" ? "fd-btn-icon-sm" : size === "lg" ? "fd-btn-icon-lg" : "",
|
|
69
71
|
round ? "fd-btn-icon-round" : "",
|
|
70
72
|
className
|
|
@@ -85,6 +87,15 @@ var samePosition = (a, b) => {
|
|
|
85
87
|
if (!a || !b) return a === b;
|
|
86
88
|
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;
|
|
87
89
|
};
|
|
90
|
+
var SCROLL_REGIONS = ".fd-pop-body, .fd-pop-list";
|
|
91
|
+
function measureLayer(el) {
|
|
92
|
+
if (!el) return { width: 0, height: 0 };
|
|
93
|
+
let hidden = 0;
|
|
94
|
+
el.querySelectorAll(SCROLL_REGIONS).forEach((r) => {
|
|
95
|
+
hidden += Math.max(0, r.scrollHeight - r.clientHeight);
|
|
96
|
+
});
|
|
97
|
+
return { width: el.offsetWidth, height: el.offsetHeight ? el.offsetHeight + hidden : 0 };
|
|
98
|
+
}
|
|
88
99
|
function usePopoverPosition(open, anchorRef, opts) {
|
|
89
100
|
const o = opts || {};
|
|
90
101
|
const { side: wantSide, align } = parsePlacement(o.placement);
|
|
@@ -92,6 +103,7 @@ function usePopoverPosition(open, anchorRef, opts) {
|
|
|
92
103
|
const posRef = React.useRef(null);
|
|
93
104
|
const detachRef = React.useRef(o.onDetach);
|
|
94
105
|
detachRef.current = o.onDetach;
|
|
106
|
+
const layerRef = o.layerRef;
|
|
95
107
|
React.useLayoutEffect(() => {
|
|
96
108
|
if (!open || !anchorRef || !anchorRef.current) {
|
|
97
109
|
posRef.current = null;
|
|
@@ -103,20 +115,22 @@ function usePopoverPosition(open, anchorRef, opts) {
|
|
|
103
115
|
if (!el) return;
|
|
104
116
|
const r = el.getBoundingClientRect();
|
|
105
117
|
const offset = o.offset == null ? 8 : o.offset;
|
|
106
|
-
const
|
|
118
|
+
const layer = measureLayer(layerRef ? layerRef.current : null);
|
|
119
|
+
const need = layer.height || Math.min(o.estHeight || 300, 180);
|
|
107
120
|
const below = window.innerHeight - r.bottom - offset - MARGIN;
|
|
108
121
|
const above = r.top - offset - MARGIN;
|
|
109
122
|
let side = wantSide;
|
|
110
|
-
if (side === "bottom" && below <
|
|
111
|
-
else if (side === "top" && above <
|
|
112
|
-
const
|
|
113
|
-
const
|
|
123
|
+
if (side === "bottom" && below < need && above > below) side = "top";
|
|
124
|
+
else if (side === "top" && above < need && below > above) side = "bottom";
|
|
125
|
+
const exact = o.matchWidth === true;
|
|
126
|
+
const width = exact ? r.width : Math.max(o.width || 0, o.minWidth || 0, o.matchWidth === "min" ? r.width : 0);
|
|
127
|
+
const w = exact || o.width ? width : Math.max(layer.width, width) || o.estWidth || 260;
|
|
114
128
|
let left = align === "end" ? r.right - w : align === "center" ? r.left + r.width / 2 - w / 2 : r.left;
|
|
115
129
|
left = Math.max(MARGIN, Math.min(left, window.innerWidth - w - MARGIN));
|
|
116
130
|
const maxH = Math.max(140, side === "top" ? above : below);
|
|
117
131
|
const next = {
|
|
118
132
|
left,
|
|
119
|
-
width:
|
|
133
|
+
width: exact ? r.width : void 0,
|
|
120
134
|
minWidth: o.minWidth,
|
|
121
135
|
top: side === "bottom" ? r.bottom + offset : null,
|
|
122
136
|
bottom: side === "top" ? window.innerHeight - r.top + offset : null,
|
|
@@ -152,6 +166,7 @@ var portal = (node) => {
|
|
|
152
166
|
function Popover({
|
|
153
167
|
open,
|
|
154
168
|
anchorRef,
|
|
169
|
+
triggerRef,
|
|
155
170
|
onClose,
|
|
156
171
|
placement = "bottom-start",
|
|
157
172
|
offset = 8,
|
|
@@ -167,6 +182,8 @@ function Popover({
|
|
|
167
182
|
returnFocus = true,
|
|
168
183
|
className = "",
|
|
169
184
|
style,
|
|
185
|
+
header,
|
|
186
|
+
footer,
|
|
170
187
|
children
|
|
171
188
|
}) {
|
|
172
189
|
const ref = React.useRef(null);
|
|
@@ -177,7 +194,8 @@ function Popover({
|
|
|
177
194
|
width,
|
|
178
195
|
minWidth,
|
|
179
196
|
estHeight: maxHeight || 320,
|
|
180
|
-
onDetach: onClose
|
|
197
|
+
onDetach: onClose,
|
|
198
|
+
layerRef: ref
|
|
181
199
|
});
|
|
182
200
|
const restore = React.useRef(null);
|
|
183
201
|
React.useEffect(() => {
|
|
@@ -198,7 +216,8 @@ function Popover({
|
|
|
198
216
|
if (!closeOnOutside) return;
|
|
199
217
|
const target = e.target;
|
|
200
218
|
if (ref.current && ref.current.contains(target)) return;
|
|
201
|
-
|
|
219
|
+
const trigger = (triggerRef || anchorRef).current;
|
|
220
|
+
if (trigger && trigger.contains(target)) return;
|
|
202
221
|
if (e.target.closest && e.target.closest(".fd-pop")) return;
|
|
203
222
|
onClose && onClose();
|
|
204
223
|
};
|
|
@@ -214,23 +233,23 @@ function Popover({
|
|
|
214
233
|
document.removeEventListener("pointerdown", away, true);
|
|
215
234
|
document.removeEventListener("keydown", key);
|
|
216
235
|
};
|
|
217
|
-
}, [open, closeOnOutside, closeOnEscape, onClose, anchorRef]);
|
|
236
|
+
}, [open, closeOnOutside, closeOnEscape, onClose, anchorRef, triggerRef]);
|
|
218
237
|
if (!open || !pos) return null;
|
|
219
238
|
return portal(
|
|
220
|
-
/* @__PURE__ */
|
|
239
|
+
/* @__PURE__ */ jsxs2(
|
|
221
240
|
"div",
|
|
222
241
|
{
|
|
223
242
|
ref,
|
|
224
243
|
role,
|
|
225
244
|
"aria-label": label,
|
|
226
|
-
className: ["fd-pop", pos.side === "top" ? "is-up" : "",
|
|
245
|
+
className: ["fd-pop", pos.side === "top" ? "is-up" : "", className].filter(Boolean).join(" "),
|
|
227
246
|
style: {
|
|
228
247
|
position: "fixed",
|
|
229
248
|
left: pos.left,
|
|
230
249
|
top: pos.top == null ? "auto" : pos.top,
|
|
231
250
|
bottom: pos.bottom == null ? "auto" : pos.bottom,
|
|
232
|
-
width: matchWidth ? pos.width : width,
|
|
233
|
-
minWidth: minWidth || (matchWidth ? void 0 : 200),
|
|
251
|
+
width: matchWidth === true ? pos.width : width,
|
|
252
|
+
minWidth: matchWidth === "min" ? Math.max(pos.anchorWidth, minWidth || 0) : minWidth || (matchWidth ? void 0 : 200),
|
|
234
253
|
// Size to content by default — cap only at real available room between the
|
|
235
254
|
// anchor and the viewport edge (pos.maxH, computed by usePopoverPosition).
|
|
236
255
|
// A caller-supplied `maxHeight` narrows that further (e.g. a long menu that
|
|
@@ -243,7 +262,11 @@ function Popover({
|
|
|
243
262
|
zIndex: 140,
|
|
244
263
|
...style
|
|
245
264
|
},
|
|
246
|
-
children
|
|
265
|
+
children: [
|
|
266
|
+
header != null ? /* @__PURE__ */ jsx3("div", { className: "fd-pop-header", children: header }) : null,
|
|
267
|
+
/* @__PURE__ */ jsx3("div", { className: ["fd-pop-body", padded ? "fd-pop-padded" : ""].filter(Boolean).join(" "), children }),
|
|
268
|
+
footer != null ? /* @__PURE__ */ jsx3("div", { className: "fd-pop-footer", children: footer }) : null
|
|
269
|
+
]
|
|
247
270
|
}
|
|
248
271
|
)
|
|
249
272
|
);
|
|
@@ -318,77 +341,79 @@ function Menu({ items = [], onSelect, onClose, autoFocus = true, className = "",
|
|
|
318
341
|
};
|
|
319
342
|
const sub = openSub != null ? items[openSub] : null;
|
|
320
343
|
return /* @__PURE__ */ jsxs2(React.Fragment, { children: [
|
|
321
|
-
|
|
322
|
-
|
|
323
|
-
|
|
324
|
-
|
|
325
|
-
|
|
326
|
-
|
|
327
|
-
|
|
328
|
-
|
|
329
|
-
|
|
330
|
-
|
|
331
|
-
|
|
332
|
-
|
|
333
|
-
|
|
334
|
-
|
|
335
|
-
|
|
336
|
-
|
|
337
|
-
|
|
338
|
-
{
|
|
339
|
-
type: "button",
|
|
340
|
-
"data-i": i,
|
|
341
|
-
role: it.checked != null ? "menuitemradio" : "menuitem",
|
|
342
|
-
"aria-checked": it.checked != null ? on : void 0,
|
|
343
|
-
"aria-haspopup": it.submenu ? "menu" : void 0,
|
|
344
|
-
"aria-expanded": it.submenu ? openSub === i : void 0,
|
|
345
|
-
"aria-disabled": it.disabled || void 0,
|
|
346
|
-
className: ["fd-opt", "fd-menu-item", i === active ? "is-active" : "", on ? "is-selected" : ""].filter(Boolean).join(" "),
|
|
347
|
-
onMouseEnter: () => {
|
|
348
|
-
setActive(i);
|
|
349
|
-
if (openSub != null && openSub !== i) setOpenSub(null);
|
|
350
|
-
},
|
|
351
|
-
onClick: () => choose(it, i),
|
|
352
|
-
children: [
|
|
353
|
-
it.icon ? /* @__PURE__ */ jsx3("span", { className: "fd-menu-icon", children: /* @__PURE__ */ jsx3("i", { className: "ph ph-" + it.icon, "aria-hidden": "true" }) }) : null,
|
|
354
|
-
/* @__PURE__ */ jsxs2("span", { className: "fd-menu-text", children: [
|
|
355
|
-
/* @__PURE__ */ jsx3("span", { className: "fd-opt-label", children: it.label }),
|
|
356
|
-
it.description ? /* @__PURE__ */ jsx3("span", { className: "fd-opt-desc", children: it.description }) : null
|
|
357
|
-
] }),
|
|
358
|
-
it.meta ? /* @__PURE__ */ jsx3("span", { className: "fd-opt-meta", children: it.meta }) : null,
|
|
359
|
-
it.shortcut ? /* @__PURE__ */ jsx3("span", { className: "fd-menu-shortcut", "aria-hidden": "true", children: it.shortcut }) : null,
|
|
360
|
-
it.submenu ? /* @__PURE__ */ jsx3("i", { className: "ph ph-caret-right fd-menu-more", "aria-hidden": "true" }) : null,
|
|
361
|
-
it.checked != null ? /* @__PURE__ */ jsx3("span", { className: "fd-opt-check", children: on ? /* @__PURE__ */ jsx3("i", { className: "ph ph-check", "aria-hidden": "true" }) : null }) : null
|
|
362
|
-
]
|
|
363
|
-
},
|
|
364
|
-
it.id || it.label || i
|
|
365
|
-
);
|
|
366
|
-
const ta = it.trailingAction;
|
|
367
|
-
if (!ta) return row;
|
|
368
|
-
return /* @__PURE__ */ jsxs2("div", { className: "fd-menu-row", onMouseEnter: () => setActive(i), children: [
|
|
369
|
-
row,
|
|
370
|
-
/* @__PURE__ */ jsx3(
|
|
344
|
+
/* @__PURE__ */ jsxs2("div", { className: "fd-menu-frame", children: [
|
|
345
|
+
header != null ? /* @__PURE__ */ jsx3("div", { className: "fd-menu-header", children: header }) : null,
|
|
346
|
+
/* @__PURE__ */ jsx3(
|
|
347
|
+
"div",
|
|
348
|
+
{
|
|
349
|
+
ref: listRef,
|
|
350
|
+
tabIndex: -1,
|
|
351
|
+
role: "menu",
|
|
352
|
+
onKeyDown: onKey,
|
|
353
|
+
className: ["fd-pop-list", "fd-menu", className].filter(Boolean).join(" "),
|
|
354
|
+
children: items.map((it, i) => {
|
|
355
|
+
if (!it) return null;
|
|
356
|
+
if (it.kind === "separator") return /* @__PURE__ */ jsx3("div", { className: "fd-menu-sep", role: "separator" }, "s" + i);
|
|
357
|
+
if (it.kind === "section") return /* @__PURE__ */ jsx3("div", { className: "fd-pop-group", role: "presentation", children: it.label }, "h" + i);
|
|
358
|
+
if (it.kind === "custom") return /* @__PURE__ */ jsx3("div", { className: "fd-menu-custom", children: it.render ? it.render() : null }, "c" + i);
|
|
359
|
+
const on = !!it.checked;
|
|
360
|
+
const row = /* @__PURE__ */ jsxs2(
|
|
371
361
|
"button",
|
|
372
362
|
{
|
|
373
363
|
type: "button",
|
|
374
|
-
|
|
375
|
-
"
|
|
376
|
-
|
|
377
|
-
|
|
378
|
-
|
|
379
|
-
|
|
380
|
-
|
|
381
|
-
|
|
382
|
-
|
|
364
|
+
"data-i": i,
|
|
365
|
+
role: it.checked != null ? "menuitemradio" : "menuitem",
|
|
366
|
+
"aria-checked": it.checked != null ? on : void 0,
|
|
367
|
+
"aria-haspopup": it.submenu ? "menu" : void 0,
|
|
368
|
+
"aria-expanded": it.submenu ? openSub === i : void 0,
|
|
369
|
+
"aria-disabled": it.disabled || void 0,
|
|
370
|
+
className: ["fd-opt", "fd-menu-item", i === active ? "is-active" : "", on ? "is-selected" : ""].filter(Boolean).join(" "),
|
|
371
|
+
onMouseEnter: () => {
|
|
372
|
+
setActive(i);
|
|
373
|
+
if (openSub != null && openSub !== i) setOpenSub(null);
|
|
383
374
|
},
|
|
384
|
-
|
|
385
|
-
|
|
386
|
-
|
|
387
|
-
|
|
388
|
-
|
|
389
|
-
|
|
390
|
-
|
|
391
|
-
|
|
375
|
+
onClick: () => choose(it, i),
|
|
376
|
+
children: [
|
|
377
|
+
it.icon ? /* @__PURE__ */ jsx3("span", { className: "fd-menu-icon", children: /* @__PURE__ */ jsx3("i", { className: "ph ph-" + it.icon, "aria-hidden": "true" }) }) : null,
|
|
378
|
+
/* @__PURE__ */ jsxs2("span", { className: "fd-menu-text", children: [
|
|
379
|
+
/* @__PURE__ */ jsx3("span", { className: "fd-opt-label", children: it.label }),
|
|
380
|
+
it.description ? /* @__PURE__ */ jsx3("span", { className: "fd-opt-desc", children: it.description }) : null
|
|
381
|
+
] }),
|
|
382
|
+
it.meta ? /* @__PURE__ */ jsx3("span", { className: "fd-opt-meta", children: it.meta }) : null,
|
|
383
|
+
it.shortcut ? /* @__PURE__ */ jsx3("span", { className: "fd-menu-shortcut", "aria-hidden": "true", children: it.shortcut }) : null,
|
|
384
|
+
it.submenu ? /* @__PURE__ */ jsx3("i", { className: "ph ph-caret-right fd-menu-more", "aria-hidden": "true" }) : null,
|
|
385
|
+
it.checked != null ? /* @__PURE__ */ jsx3("span", { className: "fd-opt-check", children: on ? /* @__PURE__ */ jsx3("i", { className: "ph ph-check", "aria-hidden": "true" }) : null }) : null
|
|
386
|
+
]
|
|
387
|
+
},
|
|
388
|
+
it.id || it.label || i
|
|
389
|
+
);
|
|
390
|
+
const ta = it.trailingAction;
|
|
391
|
+
if (!ta) return row;
|
|
392
|
+
return /* @__PURE__ */ jsxs2("div", { className: "fd-menu-row", onMouseEnter: () => setActive(i), children: [
|
|
393
|
+
row,
|
|
394
|
+
/* @__PURE__ */ jsx3(
|
|
395
|
+
"button",
|
|
396
|
+
{
|
|
397
|
+
type: "button",
|
|
398
|
+
className: ["fd-menu-row-act", ta.danger ? "is-danger" : ""].filter(Boolean).join(" "),
|
|
399
|
+
"aria-label": ta.label,
|
|
400
|
+
title: ta.label,
|
|
401
|
+
onClick: (e) => {
|
|
402
|
+
e.stopPropagation();
|
|
403
|
+
ta.onSelect && ta.onSelect(it);
|
|
404
|
+
if (ta.closeOnSelect !== false) {
|
|
405
|
+
onClose && onClose();
|
|
406
|
+
}
|
|
407
|
+
},
|
|
408
|
+
children: /* @__PURE__ */ jsx3("i", { className: "ph ph-" + (ta.icon || "trash"), "aria-hidden": "true" })
|
|
409
|
+
}
|
|
410
|
+
)
|
|
411
|
+
] }, it.id || it.label || i);
|
|
412
|
+
})
|
|
413
|
+
}
|
|
414
|
+
),
|
|
415
|
+
footer != null ? /* @__PURE__ */ jsx3("div", { className: "fd-menu-footer", children: footer }) : null
|
|
416
|
+
] }),
|
|
392
417
|
sub && sub.submenu ? /* @__PURE__ */ jsx3(
|
|
393
418
|
Popover,
|
|
394
419
|
{
|
|
@@ -1016,20 +1041,123 @@ function Toast({ title, children, tone = "success", onUndo, onDismiss, className
|
|
|
1016
1041
|
// src/components/feedback/Tooltip.tsx
|
|
1017
1042
|
import * as React6 from "react";
|
|
1018
1043
|
import { jsx as jsx24, jsxs as jsxs19 } from "react/jsx-runtime";
|
|
1044
|
+
var CLOSE_DELAY_MS = 120;
|
|
1019
1045
|
function Tooltip({ label, placement = "top", children, className = "" }) {
|
|
1020
|
-
const
|
|
1021
|
-
const
|
|
1046
|
+
const anchorRef = React6.useRef(null);
|
|
1047
|
+
const bubbleRef = React6.useRef(null);
|
|
1048
|
+
const [reason, setReason] = React6.useState(null);
|
|
1049
|
+
const closeTimer = React6.useRef(null);
|
|
1050
|
+
const id = React6.useId();
|
|
1051
|
+
const descId = id + "-desc";
|
|
1052
|
+
const open = reason != null;
|
|
1053
|
+
const cancelClose = React6.useCallback(() => {
|
|
1054
|
+
if (closeTimer.current) {
|
|
1055
|
+
clearTimeout(closeTimer.current);
|
|
1056
|
+
closeTimer.current = null;
|
|
1057
|
+
}
|
|
1058
|
+
}, []);
|
|
1059
|
+
const show = (why) => {
|
|
1060
|
+
cancelClose();
|
|
1061
|
+
setReason(why);
|
|
1062
|
+
};
|
|
1063
|
+
const hide = React6.useCallback(() => {
|
|
1064
|
+
cancelClose();
|
|
1065
|
+
setReason(null);
|
|
1066
|
+
}, [cancelClose]);
|
|
1067
|
+
const hover = () => {
|
|
1068
|
+
cancelClose();
|
|
1069
|
+
setReason((r) => r || "hover");
|
|
1070
|
+
};
|
|
1071
|
+
const hideSoon = () => {
|
|
1072
|
+
cancelClose();
|
|
1073
|
+
closeTimer.current = setTimeout(() => {
|
|
1074
|
+
closeTimer.current = null;
|
|
1075
|
+
setReason((r) => r === "hover" ? null : r);
|
|
1076
|
+
}, CLOSE_DELAY_MS);
|
|
1077
|
+
};
|
|
1078
|
+
React6.useEffect(() => cancelClose, [cancelClose]);
|
|
1079
|
+
const pos = usePopoverPosition(open, anchorRef, {
|
|
1080
|
+
placement: placement === "bottom" ? "bottom-center" : "top-center",
|
|
1081
|
+
offset: 8,
|
|
1082
|
+
estHeight: 40,
|
|
1083
|
+
estWidth: 160,
|
|
1084
|
+
layerRef: bubbleRef,
|
|
1085
|
+
onDetach: hide
|
|
1086
|
+
});
|
|
1087
|
+
React6.useEffect(() => {
|
|
1088
|
+
if (!open) return;
|
|
1089
|
+
const key = (e) => {
|
|
1090
|
+
if (e.key === "Escape") hide();
|
|
1091
|
+
};
|
|
1092
|
+
const away = (e) => {
|
|
1093
|
+
const t = e.target;
|
|
1094
|
+
if (anchorRef.current && anchorRef.current.contains(t)) return;
|
|
1095
|
+
if (bubbleRef.current && bubbleRef.current.contains(t)) return;
|
|
1096
|
+
hide();
|
|
1097
|
+
};
|
|
1098
|
+
document.addEventListener("keydown", key);
|
|
1099
|
+
document.addEventListener("pointerdown", away, true);
|
|
1100
|
+
return () => {
|
|
1101
|
+
document.removeEventListener("keydown", key);
|
|
1102
|
+
document.removeEventListener("pointerdown", away, true);
|
|
1103
|
+
};
|
|
1104
|
+
}, [open, hide]);
|
|
1105
|
+
const isMouse = (e) => e.pointerType === "mouse";
|
|
1106
|
+
const onFocus = (e) => {
|
|
1107
|
+
const el = e.target;
|
|
1108
|
+
let keyboard = true;
|
|
1109
|
+
try {
|
|
1110
|
+
keyboard = el.matches(":focus-visible");
|
|
1111
|
+
} catch {
|
|
1112
|
+
}
|
|
1113
|
+
if (keyboard) show("focus");
|
|
1114
|
+
};
|
|
1115
|
+
const described = React6.isValidElement(children) ? React6.cloneElement(children, {
|
|
1116
|
+
"aria-describedby": [children.props["aria-describedby"], descId].filter(Boolean).join(" ")
|
|
1117
|
+
}) : children;
|
|
1022
1118
|
return /* @__PURE__ */ jsxs19(
|
|
1023
1119
|
"span",
|
|
1024
1120
|
{
|
|
1025
|
-
|
|
1026
|
-
|
|
1027
|
-
|
|
1028
|
-
|
|
1029
|
-
|
|
1121
|
+
ref: anchorRef,
|
|
1122
|
+
className: "fd-tooltip-anchor",
|
|
1123
|
+
"aria-describedby": React6.isValidElement(children) ? void 0 : descId,
|
|
1124
|
+
onPointerEnter: (e) => {
|
|
1125
|
+
if (isMouse(e)) hover();
|
|
1126
|
+
},
|
|
1127
|
+
onPointerLeave: (e) => {
|
|
1128
|
+
if (isMouse(e)) hideSoon();
|
|
1129
|
+
},
|
|
1130
|
+
onPointerUp: (e) => {
|
|
1131
|
+
if (!isMouse(e)) {
|
|
1132
|
+
if (reason === "tap") hide();
|
|
1133
|
+
else show("tap");
|
|
1134
|
+
}
|
|
1135
|
+
},
|
|
1136
|
+
onFocus,
|
|
1137
|
+
onBlur: () => {
|
|
1138
|
+
if (reason === "focus") hide();
|
|
1139
|
+
},
|
|
1030
1140
|
children: [
|
|
1031
|
-
|
|
1032
|
-
|
|
1141
|
+
described,
|
|
1142
|
+
/* @__PURE__ */ jsx24("span", { id: descId, hidden: true, children: label }),
|
|
1143
|
+
open && pos ? portal(
|
|
1144
|
+
/* @__PURE__ */ jsx24(
|
|
1145
|
+
"span",
|
|
1146
|
+
{
|
|
1147
|
+
ref: bubbleRef,
|
|
1148
|
+
role: "tooltip",
|
|
1149
|
+
className: ["fd-tooltip", pos.side === "bottom" ? "is-below" : "", className].filter(Boolean).join(" "),
|
|
1150
|
+
style: { left: pos.left, top: pos.top == null ? "auto" : pos.top, bottom: pos.bottom == null ? "auto" : pos.bottom },
|
|
1151
|
+
onPointerEnter: (e) => {
|
|
1152
|
+
if (isMouse(e)) cancelClose();
|
|
1153
|
+
},
|
|
1154
|
+
onPointerLeave: (e) => {
|
|
1155
|
+
if (isMouse(e)) hideSoon();
|
|
1156
|
+
},
|
|
1157
|
+
children: label
|
|
1158
|
+
}
|
|
1159
|
+
)
|
|
1160
|
+
) : null
|
|
1033
1161
|
]
|
|
1034
1162
|
}
|
|
1035
1163
|
);
|
|
@@ -2663,6 +2791,7 @@ function VirtualList({
|
|
|
2663
2791
|
}
|
|
2664
2792
|
|
|
2665
2793
|
// src/components/data/EntityRow.tsx
|
|
2794
|
+
import * as React17 from "react";
|
|
2666
2795
|
import { jsx as jsx39, jsxs as jsxs35 } from "react/jsx-runtime";
|
|
2667
2796
|
var ENTITY_ROW_METRIC_WIDTH = 74;
|
|
2668
2797
|
var METRIC_TONE_COLOR = {
|
|
@@ -2671,20 +2800,20 @@ var METRIC_TONE_COLOR = {
|
|
|
2671
2800
|
danger: "var(--danger-text)"
|
|
2672
2801
|
};
|
|
2673
2802
|
function EntityRowMetrics({ metrics, className = "", style }) {
|
|
2674
|
-
return /* @__PURE__ */ jsx39("span", { className: ["fd-erow-metrics", className].filter(Boolean).join(" "), style, children: metrics.map((m, i) =>
|
|
2675
|
-
|
|
2676
|
-
|
|
2677
|
-
|
|
2678
|
-
|
|
2679
|
-
|
|
2680
|
-
children:
|
|
2681
|
-
|
|
2682
|
-
|
|
2683
|
-
|
|
2684
|
-
|
|
2685
|
-
}
|
|
2686
|
-
|
|
2687
|
-
)
|
|
2803
|
+
return /* @__PURE__ */ jsx39("span", { className: ["fd-erow-metrics", className].filter(Boolean).join(" "), style, children: metrics.map((m, i) => {
|
|
2804
|
+
const key = m.id || m.label || i;
|
|
2805
|
+
const className2 = ["fd-erow-metric", m.tone && m.tone !== "default" ? "is-" + m.tone : "", m.tooltip != null ? "is-described" : ""].filter(Boolean).join(" ");
|
|
2806
|
+
const cellStyle = { width: (m.width || ENTITY_ROW_METRIC_WIDTH) + "px", color: METRIC_TONE_COLOR[m.tone || "default"] };
|
|
2807
|
+
const content = /* @__PURE__ */ jsxs35(React17.Fragment, { children: [
|
|
2808
|
+
m.icon ? /* @__PURE__ */ jsx39("i", { className: "ph ph-" + m.icon, "aria-hidden": "true" }) : null,
|
|
2809
|
+
/* @__PURE__ */ jsx39("span", { className: "fd-erow-metric-value fd-tabular", children: m.value }),
|
|
2810
|
+
/* @__PURE__ */ jsx39("span", { className: "fd-sr", children: " " + m.label })
|
|
2811
|
+
] });
|
|
2812
|
+
if (m.tooltip == null) {
|
|
2813
|
+
return /* @__PURE__ */ jsx39("span", { className: className2, style: cellStyle, title: m.label, children: content }, key);
|
|
2814
|
+
}
|
|
2815
|
+
return /* @__PURE__ */ jsx39(Tooltip, { label: m.tooltip, children: /* @__PURE__ */ jsx39("button", { type: "button", className: className2, style: cellStyle, children: content }) }, key);
|
|
2816
|
+
}) });
|
|
2688
2817
|
}
|
|
2689
2818
|
function EntityRow({
|
|
2690
2819
|
title,
|
|
@@ -2734,8 +2863,10 @@ function EntityRow({
|
|
|
2734
2863
|
icon: action.icon,
|
|
2735
2864
|
label: action.label,
|
|
2736
2865
|
size: "sm",
|
|
2737
|
-
|
|
2738
|
-
|
|
2866
|
+
variant: "solid",
|
|
2867
|
+
tone: action.tone === "add" ? "ok" : action.tone === "remove" ? "danger" : "neutral",
|
|
2868
|
+
className: "fd-erow-action",
|
|
2869
|
+
onClick: action.onClick
|
|
2739
2870
|
}
|
|
2740
2871
|
) : null
|
|
2741
2872
|
]
|
|
@@ -2744,14 +2875,14 @@ function EntityRow({
|
|
|
2744
2875
|
}
|
|
2745
2876
|
|
|
2746
2877
|
// src/components/data/TransferList.tsx
|
|
2747
|
-
import * as
|
|
2878
|
+
import * as React19 from "react";
|
|
2748
2879
|
import { createPortal as createPortal4 } from "react-dom";
|
|
2749
2880
|
|
|
2750
2881
|
// src/components/forms/field.tsx
|
|
2751
|
-
import * as
|
|
2882
|
+
import * as React18 from "react";
|
|
2752
2883
|
import { jsx as jsx40, jsxs as jsxs36 } from "react/jsx-runtime";
|
|
2753
2884
|
function useFieldId(id) {
|
|
2754
|
-
const generated =
|
|
2885
|
+
const generated = React18.useId();
|
|
2755
2886
|
return id || generated;
|
|
2756
2887
|
}
|
|
2757
2888
|
function FieldLabel({ htmlFor, id, required = false, onClick, children }) {
|
|
@@ -2792,10 +2923,9 @@ function Input({
|
|
|
2792
2923
|
numeric ? "fd-input-num" : "",
|
|
2793
2924
|
error ? "fd-input-error" : "",
|
|
2794
2925
|
disabled ? "fd-input-disabled" : "",
|
|
2795
|
-
size === "lg" ? "fd-input-lg" : ""
|
|
2796
|
-
className
|
|
2926
|
+
size === "lg" ? "fd-input-lg" : ""
|
|
2797
2927
|
].filter(Boolean).join(" ");
|
|
2798
|
-
return /* @__PURE__ */ jsxs37("div", { className: "fd-field", style, children: [
|
|
2928
|
+
return /* @__PURE__ */ jsxs37("div", { className: ["fd-field", className].filter(Boolean).join(" "), style, children: [
|
|
2799
2929
|
label ? /* @__PURE__ */ jsx41(FieldLabel, { htmlFor: fieldId, required, children: label }) : null,
|
|
2800
2930
|
/* @__PURE__ */ jsxs37("div", { className: box, children: [
|
|
2801
2931
|
icon ? /* @__PURE__ */ jsx41("span", { className: "fd-input-icon", children: /* @__PURE__ */ jsx41("i", { className: "ph ph-" + icon, "aria-hidden": "true" }) }) : null,
|
|
@@ -2870,12 +3000,12 @@ function TransferList({
|
|
|
2870
3000
|
listHeight = 440,
|
|
2871
3001
|
className = ""
|
|
2872
3002
|
}) {
|
|
2873
|
-
const [drag, setDrag] =
|
|
2874
|
-
const [dragOverSide, setDragOverSide] =
|
|
2875
|
-
const dragRef =
|
|
2876
|
-
const armedRef =
|
|
2877
|
-
const sideRefs =
|
|
2878
|
-
const hitTestSide =
|
|
3003
|
+
const [drag, setDrag] = React19.useState(null);
|
|
3004
|
+
const [dragOverSide, setDragOverSide] = React19.useState(null);
|
|
3005
|
+
const dragRef = React19.useRef(null);
|
|
3006
|
+
const armedRef = React19.useRef(null);
|
|
3007
|
+
const sideRefs = React19.useRef({ left: null, right: null });
|
|
3008
|
+
const hitTestSide = React19.useCallback((x, y) => {
|
|
2879
3009
|
for (const side of ["left", "right"]) {
|
|
2880
3010
|
const el = sideRefs.current[side];
|
|
2881
3011
|
if (!el) continue;
|
|
@@ -2884,7 +3014,7 @@ function TransferList({
|
|
|
2884
3014
|
}
|
|
2885
3015
|
return null;
|
|
2886
3016
|
}, []);
|
|
2887
|
-
const findItem =
|
|
3017
|
+
const findItem = React19.useCallback(
|
|
2888
3018
|
(side, key) => (side === "left" ? left.items : right.items).find((it) => keyOf(it) === key),
|
|
2889
3019
|
[left.items, right.items, keyOf]
|
|
2890
3020
|
);
|
|
@@ -2906,7 +3036,7 @@ function TransferList({
|
|
|
2906
3036
|
height: rect.height
|
|
2907
3037
|
};
|
|
2908
3038
|
};
|
|
2909
|
-
|
|
3039
|
+
React19.useEffect(() => {
|
|
2910
3040
|
const onMovePointer = (e) => {
|
|
2911
3041
|
const armed = armedRef.current;
|
|
2912
3042
|
if (!armed || e.pointerId !== armed.pointerId) return;
|
|
@@ -2959,7 +3089,7 @@ function TransferList({
|
|
|
2959
3089
|
window.removeEventListener("pointercancel", endDrag);
|
|
2960
3090
|
};
|
|
2961
3091
|
}, [hitTestSide, findItem, onMove]);
|
|
2962
|
-
|
|
3092
|
+
React19.useEffect(() => {
|
|
2963
3093
|
if (!drag || typeof document === "undefined") return;
|
|
2964
3094
|
const prev = document.body.style.userSelect;
|
|
2965
3095
|
document.body.style.userSelect = "none";
|
|
@@ -3071,11 +3201,11 @@ function TransferList({
|
|
|
3071
3201
|
}
|
|
3072
3202
|
|
|
3073
3203
|
// src/components/forms/Checkbox.tsx
|
|
3074
|
-
import * as
|
|
3204
|
+
import * as React20 from "react";
|
|
3075
3205
|
import { jsx as jsx44, jsxs as jsxs39 } from "react/jsx-runtime";
|
|
3076
3206
|
function Checkbox({ label, description, card = false, indeterminate = false, className = "", ...rest }) {
|
|
3077
|
-
const ref =
|
|
3078
|
-
|
|
3207
|
+
const ref = React20.useRef(null);
|
|
3208
|
+
React20.useEffect(() => {
|
|
3079
3209
|
if (ref.current) ref.current.indeterminate = indeterminate;
|
|
3080
3210
|
}, [indeterminate]);
|
|
3081
3211
|
return /* @__PURE__ */ jsxs39("label", { className: ["fd-choice", card ? "fd-choice-card" : "", className].filter(Boolean).join(" "), children: [
|
|
@@ -3122,8 +3252,8 @@ function Switch({ label, description, className = "", ...rest }) {
|
|
|
3122
3252
|
import { jsx as jsx47, jsxs as jsxs42 } from "react/jsx-runtime";
|
|
3123
3253
|
function Textarea({ label, help, error, required = false, rows = 4, disabled = false, id, className = "", style, ...rest }) {
|
|
3124
3254
|
const fieldId = useFieldId(id);
|
|
3125
|
-
const box = ["fd-input", "fd-input-textarea", error ? "fd-input-error" : "", disabled ? "fd-input-disabled" : ""
|
|
3126
|
-
return /* @__PURE__ */ jsxs42("div", { className: "fd-field", style, children: [
|
|
3255
|
+
const box = ["fd-input", "fd-input-textarea", error ? "fd-input-error" : "", disabled ? "fd-input-disabled" : ""].filter(Boolean).join(" ");
|
|
3256
|
+
return /* @__PURE__ */ jsxs42("div", { className: ["fd-field", className].filter(Boolean).join(" "), style, children: [
|
|
3127
3257
|
label ? /* @__PURE__ */ jsx47(FieldLabel, { htmlFor: fieldId, required, children: label }) : null,
|
|
3128
3258
|
/* @__PURE__ */ jsx47("div", { className: box, children: /* @__PURE__ */ jsx47("textarea", { id: fieldId, rows, disabled, "aria-invalid": error ? "true" : void 0, ...rest }) }),
|
|
3129
3259
|
error ? /* @__PURE__ */ jsxs42("span", { className: "fd-field-error", children: [
|
|
@@ -3134,7 +3264,7 @@ function Textarea({ label, help, error, required = false, rows = 4, disabled = f
|
|
|
3134
3264
|
}
|
|
3135
3265
|
|
|
3136
3266
|
// src/components/forms/NumberInput.tsx
|
|
3137
|
-
import * as
|
|
3267
|
+
import * as React21 from "react";
|
|
3138
3268
|
import { jsx as jsx48, jsxs as jsxs43 } from "react/jsx-runtime";
|
|
3139
3269
|
function NumberInput({
|
|
3140
3270
|
label,
|
|
@@ -3162,10 +3292,10 @@ function NumberInput({
|
|
|
3162
3292
|
const n = Number(String(v == null ? "" : v).replace(/[^0-9.-]/g, ""));
|
|
3163
3293
|
return isNaN(n) ? null : n;
|
|
3164
3294
|
};
|
|
3165
|
-
const [text, setText] =
|
|
3166
|
-
const [editing, setEditing] =
|
|
3167
|
-
const timer =
|
|
3168
|
-
|
|
3295
|
+
const [text, setText] = React21.useState(value == null || value === "" ? "" : String(value));
|
|
3296
|
+
const [editing, setEditing] = React21.useState(false);
|
|
3297
|
+
const timer = React21.useRef(null);
|
|
3298
|
+
React21.useEffect(() => {
|
|
3169
3299
|
if (!editing) setText(value == null || value === "" ? "" : String(value));
|
|
3170
3300
|
}, [value, editing]);
|
|
3171
3301
|
const clamp = (n) => Math.min(max, Math.max(min, n));
|
|
@@ -3189,7 +3319,7 @@ function NumberInput({
|
|
|
3189
3319
|
const release = () => {
|
|
3190
3320
|
if (timer.current) clearTimeout(timer.current);
|
|
3191
3321
|
};
|
|
3192
|
-
|
|
3322
|
+
React21.useEffect(() => () => {
|
|
3193
3323
|
if (timer.current) clearTimeout(timer.current);
|
|
3194
3324
|
}, []);
|
|
3195
3325
|
const shown = editing ? text : (() => {
|
|
@@ -3276,52 +3406,9 @@ function NumberInput({
|
|
|
3276
3406
|
}
|
|
3277
3407
|
|
|
3278
3408
|
// src/components/forms/Select.tsx
|
|
3279
|
-
import * as
|
|
3280
|
-
import { createPortal as createPortal5 } from "react-dom";
|
|
3409
|
+
import * as React22 from "react";
|
|
3281
3410
|
import { jsx as jsx49, jsxs as jsxs44 } from "react/jsx-runtime";
|
|
3282
3411
|
var norm = (o) => typeof o === "string" ? { value: o, label: o } : o;
|
|
3283
|
-
function usePopPos(open, ref, estH, estW) {
|
|
3284
|
-
const [pos, setPos] = React21.useState(null);
|
|
3285
|
-
React21.useLayoutEffect(() => {
|
|
3286
|
-
if (!open || !ref.current) {
|
|
3287
|
-
setPos(null);
|
|
3288
|
-
return;
|
|
3289
|
-
}
|
|
3290
|
-
const calc = () => {
|
|
3291
|
-
const r = ref.current.getBoundingClientRect();
|
|
3292
|
-
const below = window.innerHeight - r.bottom;
|
|
3293
|
-
const up = below < estH && r.top > below;
|
|
3294
|
-
const w = Math.max(r.width, estW || 0);
|
|
3295
|
-
const maxH = Math.min(window.innerHeight - 16, Math.max(160, (up ? r.top : below) - 14));
|
|
3296
|
-
setPos({
|
|
3297
|
-
left: Math.max(8, Math.min(r.left, window.innerWidth - w - 8)),
|
|
3298
|
-
width: r.width,
|
|
3299
|
-
top: up ? null : r.bottom + 6,
|
|
3300
|
-
bottom: up ? window.innerHeight - r.top + 6 : null,
|
|
3301
|
-
up,
|
|
3302
|
-
maxH
|
|
3303
|
-
});
|
|
3304
|
-
};
|
|
3305
|
-
calc();
|
|
3306
|
-
window.addEventListener("scroll", calc, true);
|
|
3307
|
-
window.addEventListener("resize", calc);
|
|
3308
|
-
return () => {
|
|
3309
|
-
window.removeEventListener("scroll", calc, true);
|
|
3310
|
-
window.removeEventListener("resize", calc);
|
|
3311
|
-
};
|
|
3312
|
-
}, [open]);
|
|
3313
|
-
return pos;
|
|
3314
|
-
}
|
|
3315
|
-
var popStyle = (pos, extra) => ({
|
|
3316
|
-
position: "fixed",
|
|
3317
|
-
left: pos.left,
|
|
3318
|
-
top: pos.top == null ? "auto" : pos.top,
|
|
3319
|
-
bottom: pos.bottom == null ? "auto" : pos.bottom,
|
|
3320
|
-
transformOrigin: pos.up ? "bottom center" : "top center",
|
|
3321
|
-
maxHeight: pos.maxH,
|
|
3322
|
-
overflowY: "auto",
|
|
3323
|
-
...extra
|
|
3324
|
-
});
|
|
3325
3412
|
function Select({
|
|
3326
3413
|
label,
|
|
3327
3414
|
help,
|
|
@@ -3346,17 +3433,15 @@ function Select({
|
|
|
3346
3433
|
const isOn = (v) => multiple ? vals.includes(v) : v === value;
|
|
3347
3434
|
const hasSearch = searchable === void 0 ? opts.length > 8 : searchable;
|
|
3348
3435
|
const { fieldId, labelId, ariaLabelledBy } = useTriggerLabelling(label, id);
|
|
3349
|
-
const [open, setOpen] =
|
|
3350
|
-
const [q, setQ] =
|
|
3351
|
-
const [active, setActive] =
|
|
3352
|
-
const rootRef =
|
|
3353
|
-
const boxRef =
|
|
3354
|
-
const
|
|
3355
|
-
const
|
|
3356
|
-
const typeBuf = React21.useRef({ s: "", t: 0 });
|
|
3436
|
+
const [open, setOpen] = React22.useState(false);
|
|
3437
|
+
const [q, setQ] = React22.useState("");
|
|
3438
|
+
const [active, setActive] = React22.useState(-1);
|
|
3439
|
+
const rootRef = React22.useRef(null);
|
|
3440
|
+
const boxRef = React22.useRef(null);
|
|
3441
|
+
const listRef = React22.useRef(null);
|
|
3442
|
+
const typeBuf = React22.useRef({ s: "", t: 0 });
|
|
3357
3443
|
const selected = multiple ? null : opts.find((o) => o.value === value);
|
|
3358
3444
|
const chosen = multiple ? opts.filter((o) => vals.includes(o.value)) : [];
|
|
3359
|
-
const pos = usePopPos(open, boxRef, hasSearch ? 390 : 340, 260);
|
|
3360
3445
|
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;
|
|
3361
3446
|
const visible = q ? opts.filter((o) => (o.label + " " + (o.description || "") + " " + (o.group || "")).toLowerCase().includes(q.toLowerCase())) : opts;
|
|
3362
3447
|
const fire = (v) => {
|
|
@@ -3379,17 +3464,7 @@ function Select({
|
|
|
3379
3464
|
}
|
|
3380
3465
|
setOpen(!open);
|
|
3381
3466
|
};
|
|
3382
|
-
|
|
3383
|
-
if (!open) return;
|
|
3384
|
-
const away = (e) => {
|
|
3385
|
-
if (rootRef.current && rootRef.current.contains(e.target)) return;
|
|
3386
|
-
if (popRef.current && popRef.current.contains(e.target)) return;
|
|
3387
|
-
setOpen(false);
|
|
3388
|
-
};
|
|
3389
|
-
document.addEventListener("pointerdown", away);
|
|
3390
|
-
return () => document.removeEventListener("pointerdown", away);
|
|
3391
|
-
}, [open]);
|
|
3392
|
-
React21.useEffect(() => {
|
|
3467
|
+
React22.useEffect(() => {
|
|
3393
3468
|
if (!open || active < 0 || !listRef.current) return;
|
|
3394
3469
|
const el = listRef.current.querySelector('[data-i="' + active + '"]');
|
|
3395
3470
|
if (el) {
|
|
@@ -3480,94 +3555,96 @@ function Select({
|
|
|
3480
3555
|
) : null,
|
|
3481
3556
|
loading ? /* @__PURE__ */ jsx49("span", { className: "fd-spinner", style: { color: "var(--text-muted)" }, "aria-label": "Loading options" }) : /* @__PURE__ */ jsx49("span", { className: "fd-select-caret", onClick: toggle, children: /* @__PURE__ */ jsx49("i", { className: "ph ph-caret-down", "aria-hidden": "true" }) })
|
|
3482
3557
|
] }),
|
|
3483
|
-
|
|
3484
|
-
|
|
3485
|
-
|
|
3486
|
-
|
|
3487
|
-
|
|
3488
|
-
|
|
3489
|
-
|
|
3490
|
-
|
|
3491
|
-
|
|
3492
|
-
|
|
3493
|
-
|
|
3494
|
-
|
|
3495
|
-
|
|
3496
|
-
|
|
3497
|
-
|
|
3498
|
-
|
|
3499
|
-
|
|
3500
|
-
|
|
3501
|
-
|
|
3502
|
-
|
|
3503
|
-
|
|
3504
|
-
|
|
3505
|
-
)
|
|
3506
|
-
|
|
3507
|
-
|
|
3508
|
-
|
|
3509
|
-
|
|
3510
|
-
|
|
3511
|
-
|
|
3512
|
-
|
|
3513
|
-
|
|
3514
|
-
|
|
3515
|
-
|
|
3516
|
-
|
|
3517
|
-
|
|
3518
|
-
|
|
3519
|
-
|
|
3520
|
-
|
|
3521
|
-
|
|
3522
|
-
|
|
3523
|
-
|
|
3524
|
-
|
|
3525
|
-
|
|
3526
|
-
|
|
3527
|
-
|
|
3528
|
-
|
|
3529
|
-
|
|
3530
|
-
|
|
3531
|
-
|
|
3532
|
-
|
|
3533
|
-
|
|
3534
|
-
|
|
3535
|
-
|
|
3536
|
-
|
|
3537
|
-
|
|
3538
|
-
|
|
3539
|
-
|
|
3540
|
-
|
|
3541
|
-
|
|
3542
|
-
|
|
3543
|
-
|
|
3544
|
-
|
|
3545
|
-
|
|
3546
|
-
|
|
3547
|
-
|
|
3548
|
-
|
|
3549
|
-
|
|
3550
|
-
|
|
3551
|
-
|
|
3552
|
-
|
|
3553
|
-
|
|
3554
|
-
]
|
|
3555
|
-
|
|
3556
|
-
|
|
3557
|
-
|
|
3558
|
-
|
|
3559
|
-
|
|
3560
|
-
|
|
3561
|
-
|
|
3562
|
-
|
|
3563
|
-
}
|
|
3564
|
-
|
|
3565
|
-
|
|
3566
|
-
|
|
3567
|
-
|
|
3568
|
-
|
|
3569
|
-
|
|
3570
|
-
|
|
3558
|
+
/* @__PURE__ */ jsx49(
|
|
3559
|
+
Popover,
|
|
3560
|
+
{
|
|
3561
|
+
open,
|
|
3562
|
+
anchorRef: boxRef,
|
|
3563
|
+
triggerRef: rootRef,
|
|
3564
|
+
onClose: () => setOpen(false),
|
|
3565
|
+
placement: "bottom-start",
|
|
3566
|
+
offset: 6,
|
|
3567
|
+
matchWidth: "min",
|
|
3568
|
+
minWidth: 260,
|
|
3569
|
+
role: "presentation",
|
|
3570
|
+
style: { maxWidth: 380, zIndex: 130 },
|
|
3571
|
+
header: hasSearch ? /* @__PURE__ */ jsxs44("div", { className: "fd-pop-search", children: [
|
|
3572
|
+
/* @__PURE__ */ jsx49("i", { className: "ph ph-magnifying-glass", style: { color: "var(--text-muted)", fontSize: 14 } }),
|
|
3573
|
+
/* @__PURE__ */ jsx49(
|
|
3574
|
+
"input",
|
|
3575
|
+
{
|
|
3576
|
+
autoFocus: true,
|
|
3577
|
+
placeholder: "Search\u2026",
|
|
3578
|
+
value: q,
|
|
3579
|
+
onKeyDown: onKey,
|
|
3580
|
+
onChange: (e) => {
|
|
3581
|
+
setQ(e.target.value);
|
|
3582
|
+
setActive(0);
|
|
3583
|
+
}
|
|
3584
|
+
}
|
|
3585
|
+
),
|
|
3586
|
+
q ? /* @__PURE__ */ jsx49("span", { className: "fd-body-sm fd-muted", children: visible.length }) : null
|
|
3587
|
+
] }) : void 0,
|
|
3588
|
+
footer: multiple ? /* @__PURE__ */ jsxs44(React22.Fragment, { children: [
|
|
3589
|
+
/* @__PURE__ */ jsx49(
|
|
3590
|
+
"button",
|
|
3591
|
+
{
|
|
3592
|
+
type: "button",
|
|
3593
|
+
onClick: () => fire(visible.filter((o) => !o.disabled).map((o) => o.value)),
|
|
3594
|
+
style: { all: "unset", cursor: "pointer", fontSize: "var(--body-sm-size)", fontWeight: 600, color: "var(--brand)" },
|
|
3595
|
+
children: "Select all"
|
|
3596
|
+
}
|
|
3597
|
+
),
|
|
3598
|
+
/* @__PURE__ */ jsx49("span", { style: { flex: 1 } }),
|
|
3599
|
+
/* @__PURE__ */ jsxs44("span", { className: "fd-body-sm fd-muted", children: [
|
|
3600
|
+
vals.length,
|
|
3601
|
+
" of ",
|
|
3602
|
+
opts.length
|
|
3603
|
+
] }),
|
|
3604
|
+
/* @__PURE__ */ jsx49(
|
|
3605
|
+
"button",
|
|
3606
|
+
{
|
|
3607
|
+
type: "button",
|
|
3608
|
+
disabled: !vals.length,
|
|
3609
|
+
onClick: () => fire([]),
|
|
3610
|
+
style: { all: "unset", cursor: vals.length ? "pointer" : "default", fontSize: "var(--body-sm-size)", fontWeight: 600, color: vals.length ? "var(--text-2)" : "var(--text-muted)" },
|
|
3611
|
+
children: "Clear"
|
|
3612
|
+
}
|
|
3613
|
+
)
|
|
3614
|
+
] }) : void 0,
|
|
3615
|
+
children: /* @__PURE__ */ jsx49("div", { className: "fd-pop-list", role: "listbox", "aria-multiselectable": multiple || void 0, ref: listRef, children: visible.length === 0 ? /* @__PURE__ */ jsxs44("div", { className: "fd-pop-empty", children: [
|
|
3616
|
+
'Nothing matches "',
|
|
3617
|
+
q,
|
|
3618
|
+
'".'
|
|
3619
|
+
] }) : groups.map((grp) => /* @__PURE__ */ jsxs44(React22.Fragment, { children: [
|
|
3620
|
+
grp.g ? /* @__PURE__ */ jsx49("div", { className: "fd-pop-group", children: grp.g }) : null,
|
|
3621
|
+
grp.items.map(({ o, i }) => /* @__PURE__ */ jsxs44(
|
|
3622
|
+
"button",
|
|
3623
|
+
{
|
|
3624
|
+
type: "button",
|
|
3625
|
+
"data-i": i,
|
|
3626
|
+
role: "option",
|
|
3627
|
+
"aria-selected": isOn(o.value),
|
|
3628
|
+
"aria-disabled": o.disabled || void 0,
|
|
3629
|
+
className: ["fd-opt", i === active ? "is-active" : "", isOn(o.value) ? "is-selected" : ""].filter(Boolean).join(" "),
|
|
3630
|
+
onMouseEnter: () => setActive(i),
|
|
3631
|
+
onClick: () => pick(o),
|
|
3632
|
+
children: [
|
|
3633
|
+
multiple ? /* @__PURE__ */ jsx49("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__ */ jsx49("i", { className: "ph ph-check", style: { fontSize: 11 } }) : null }) : null,
|
|
3634
|
+
o.icon ? /* @__PURE__ */ jsx49("span", { className: "fd-opt-icon", children: /* @__PURE__ */ jsx49("i", { className: "ph ph-" + o.icon }) }) : null,
|
|
3635
|
+
/* @__PURE__ */ jsxs44("span", { style: { flex: 1, minWidth: 0 }, children: [
|
|
3636
|
+
/* @__PURE__ */ jsx49("span", { className: "fd-opt-label", children: o.label }),
|
|
3637
|
+
o.description ? /* @__PURE__ */ jsx49("span", { className: "fd-opt-desc", children: o.description }) : null
|
|
3638
|
+
] }),
|
|
3639
|
+
o.meta ? /* @__PURE__ */ jsx49("span", { className: "fd-opt-meta", children: o.meta }) : null,
|
|
3640
|
+
multiple ? null : /* @__PURE__ */ jsx49("span", { className: "fd-opt-check", children: o.value === value ? /* @__PURE__ */ jsx49("i", { className: "ph ph-check" }) : null })
|
|
3641
|
+
]
|
|
3642
|
+
},
|
|
3643
|
+
String(o.value)
|
|
3644
|
+
))
|
|
3645
|
+
] }, grp.g || "_")) })
|
|
3646
|
+
}
|
|
3647
|
+
),
|
|
3571
3648
|
error ? /* @__PURE__ */ jsxs44("span", { className: "fd-field-error", children: [
|
|
3572
3649
|
/* @__PURE__ */ jsx49("i", { className: "ph ph-warning-circle", "aria-hidden": "true" }),
|
|
3573
3650
|
error
|
|
@@ -3576,8 +3653,7 @@ function Select({
|
|
|
3576
3653
|
}
|
|
3577
3654
|
|
|
3578
3655
|
// src/components/forms/DatePicker.tsx
|
|
3579
|
-
import * as
|
|
3580
|
-
import { createPortal as createPortal6 } from "react-dom";
|
|
3656
|
+
import * as React23 from "react";
|
|
3581
3657
|
import { jsx as jsx50, jsxs as jsxs45 } from "react/jsx-runtime";
|
|
3582
3658
|
var MONTHS = ["January", "February", "March", "April", "May", "June", "July", "August", "September", "October", "November", "December"];
|
|
3583
3659
|
var DOW = ["Su", "Mo", "Tu", "We", "Th", "Fr", "Sa"];
|
|
@@ -3591,56 +3667,14 @@ var fmt = (s) => {
|
|
|
3591
3667
|
const d = parse(s);
|
|
3592
3668
|
return d ? MONTHS[d.getMonth()].slice(0, 3) + " " + d.getDate() + ", " + d.getFullYear() : "";
|
|
3593
3669
|
};
|
|
3594
|
-
function usePopPos2(open, ref, estH, estW) {
|
|
3595
|
-
const [pos, setPos] = React22.useState(null);
|
|
3596
|
-
React22.useLayoutEffect(() => {
|
|
3597
|
-
if (!open || !ref.current) {
|
|
3598
|
-
setPos(null);
|
|
3599
|
-
return;
|
|
3600
|
-
}
|
|
3601
|
-
const calc = () => {
|
|
3602
|
-
const r = ref.current.getBoundingClientRect();
|
|
3603
|
-
const below = window.innerHeight - r.bottom;
|
|
3604
|
-
const up = below < estH && r.top > below;
|
|
3605
|
-
const w = Math.max(r.width, estW || 0);
|
|
3606
|
-
const maxH = Math.min(window.innerHeight - 16, Math.max(160, (up ? r.top : below) - 14));
|
|
3607
|
-
setPos({
|
|
3608
|
-
left: Math.max(8, Math.min(r.left, window.innerWidth - w - 8)),
|
|
3609
|
-
width: r.width,
|
|
3610
|
-
top: up ? null : r.bottom + 6,
|
|
3611
|
-
bottom: up ? window.innerHeight - r.top + 6 : null,
|
|
3612
|
-
up,
|
|
3613
|
-
maxH
|
|
3614
|
-
});
|
|
3615
|
-
};
|
|
3616
|
-
calc();
|
|
3617
|
-
window.addEventListener("scroll", calc, true);
|
|
3618
|
-
window.addEventListener("resize", calc);
|
|
3619
|
-
return () => {
|
|
3620
|
-
window.removeEventListener("scroll", calc, true);
|
|
3621
|
-
window.removeEventListener("resize", calc);
|
|
3622
|
-
};
|
|
3623
|
-
}, [open]);
|
|
3624
|
-
return pos;
|
|
3625
|
-
}
|
|
3626
|
-
var popStyle2 = (pos, extra) => ({
|
|
3627
|
-
position: "fixed",
|
|
3628
|
-
left: pos.left,
|
|
3629
|
-
top: pos.top == null ? "auto" : pos.top,
|
|
3630
|
-
bottom: pos.bottom == null ? "auto" : pos.bottom,
|
|
3631
|
-
transformOrigin: pos.up ? "bottom center" : "top center",
|
|
3632
|
-
maxHeight: pos.maxH,
|
|
3633
|
-
overflowY: "auto",
|
|
3634
|
-
...extra
|
|
3635
|
-
});
|
|
3636
3670
|
function Calendar({ value, range = false, onPick, initialMonth, months = 1 }) {
|
|
3637
3671
|
const today = /* @__PURE__ */ new Date();
|
|
3638
3672
|
const sel = range ? value || {} : { start: value, end: value };
|
|
3639
3673
|
const anchor = parse(sel.start) || parse(initialMonth) || today;
|
|
3640
|
-
const [vy, setVy] =
|
|
3641
|
-
const [vm, setVm] =
|
|
3642
|
-
const [mode2, setMode] =
|
|
3643
|
-
const [hover, setHover] =
|
|
3674
|
+
const [vy, setVy] = React23.useState(anchor.getFullYear());
|
|
3675
|
+
const [vm, setVm] = React23.useState(anchor.getMonth());
|
|
3676
|
+
const [mode2, setMode] = React23.useState("days");
|
|
3677
|
+
const [hover, setHover] = React23.useState(null);
|
|
3644
3678
|
const s = parse(sel.start), e = parse(sel.end);
|
|
3645
3679
|
const hoverEnd = range && s && !e && hover ? parse(hover) : null;
|
|
3646
3680
|
const inRange = (d) => {
|
|
@@ -3756,28 +3790,9 @@ function Calendar({ value, range = false, onPick, initialMonth, months = 1 }) {
|
|
|
3756
3790
|
}
|
|
3757
3791
|
function DatePicker({ label, help, error, required = false, disabled = false, range = false, value, onChange, placeholder, id, className = "", style, ...rest }) {
|
|
3758
3792
|
const { fieldId, labelId, ariaLabelledBy } = useTriggerLabelling(label, id);
|
|
3759
|
-
const [open, setOpen] =
|
|
3760
|
-
const rootRef =
|
|
3761
|
-
const boxRef =
|
|
3762
|
-
const popRef = React22.useRef(null);
|
|
3763
|
-
const pos = usePopPos2(open, boxRef, 430, range ? 600 : 316);
|
|
3764
|
-
React22.useEffect(() => {
|
|
3765
|
-
if (!open) return;
|
|
3766
|
-
const away = (e) => {
|
|
3767
|
-
if (rootRef.current && rootRef.current.contains(e.target)) return;
|
|
3768
|
-
if (popRef.current && popRef.current.contains(e.target)) return;
|
|
3769
|
-
setOpen(false);
|
|
3770
|
-
};
|
|
3771
|
-
const esc = (e) => {
|
|
3772
|
-
if (e.key === "Escape") setOpen(false);
|
|
3773
|
-
};
|
|
3774
|
-
document.addEventListener("pointerdown", away);
|
|
3775
|
-
document.addEventListener("keydown", esc);
|
|
3776
|
-
return () => {
|
|
3777
|
-
document.removeEventListener("pointerdown", away);
|
|
3778
|
-
document.removeEventListener("keydown", esc);
|
|
3779
|
-
};
|
|
3780
|
-
}, [open]);
|
|
3793
|
+
const [open, setOpen] = React23.useState(false);
|
|
3794
|
+
const rootRef = React23.useRef(null);
|
|
3795
|
+
const boxRef = React23.useRef(null);
|
|
3781
3796
|
const display = range ? value && value.start ? fmt(value.start) + (value.end ? " \u2192 " + fmt(value.end) : " \u2192 \u2026") : "" : fmt(value);
|
|
3782
3797
|
const toggle = () => {
|
|
3783
3798
|
if (!disabled) setOpen(!open);
|
|
@@ -3806,21 +3821,31 @@ function DatePicker({ label, help, error, required = false, disabled = false, ra
|
|
|
3806
3821
|
),
|
|
3807
3822
|
/* @__PURE__ */ jsx50("span", { className: "fd-select-caret", children: /* @__PURE__ */ jsx50("i", { className: "ph ph-caret-down", "aria-hidden": "true" }) })
|
|
3808
3823
|
] }),
|
|
3809
|
-
|
|
3810
|
-
|
|
3811
|
-
|
|
3812
|
-
|
|
3813
|
-
|
|
3814
|
-
|
|
3815
|
-
|
|
3816
|
-
|
|
3817
|
-
|
|
3818
|
-
|
|
3824
|
+
/* @__PURE__ */ jsx50(
|
|
3825
|
+
Popover,
|
|
3826
|
+
{
|
|
3827
|
+
open,
|
|
3828
|
+
anchorRef: boxRef,
|
|
3829
|
+
triggerRef: rootRef,
|
|
3830
|
+
onClose: () => setOpen(false),
|
|
3831
|
+
placement: "bottom-start",
|
|
3832
|
+
offset: 6,
|
|
3833
|
+
role: "presentation",
|
|
3834
|
+
style: { width: "max-content", zIndex: 130 },
|
|
3835
|
+
children: /* @__PURE__ */ jsx50(
|
|
3836
|
+
Calendar,
|
|
3837
|
+
{
|
|
3838
|
+
range,
|
|
3839
|
+
months: range ? 2 : 1,
|
|
3840
|
+
value,
|
|
3841
|
+
onPick: (v) => {
|
|
3842
|
+
onChange && onChange({ target: { value: v } });
|
|
3843
|
+
if (!range || v.start && v.end) setOpen(false);
|
|
3844
|
+
}
|
|
3819
3845
|
}
|
|
3820
|
-
|
|
3821
|
-
|
|
3822
|
-
|
|
3823
|
-
) : null,
|
|
3846
|
+
)
|
|
3847
|
+
}
|
|
3848
|
+
),
|
|
3824
3849
|
error ? /* @__PURE__ */ jsxs45("span", { className: "fd-field-error", children: [
|
|
3825
3850
|
/* @__PURE__ */ jsx50("i", { className: "ph ph-warning-circle", "aria-hidden": "true" }),
|
|
3826
3851
|
error
|
|
@@ -3829,61 +3854,18 @@ function DatePicker({ label, help, error, required = false, disabled = false, ra
|
|
|
3829
3854
|
}
|
|
3830
3855
|
|
|
3831
3856
|
// src/components/forms/TimePicker.tsx
|
|
3832
|
-
import * as
|
|
3833
|
-
import { createPortal as createPortal7 } from "react-dom";
|
|
3857
|
+
import * as React24 from "react";
|
|
3834
3858
|
import { jsx as jsx51, jsxs as jsxs46 } from "react/jsx-runtime";
|
|
3835
3859
|
var pad = (n) => String(n).padStart(2, "0");
|
|
3836
|
-
function usePopPos3(open, ref, estH, estW) {
|
|
3837
|
-
const [pos, setPos] = React23.useState(null);
|
|
3838
|
-
React23.useLayoutEffect(() => {
|
|
3839
|
-
if (!open || !ref.current) {
|
|
3840
|
-
setPos(null);
|
|
3841
|
-
return;
|
|
3842
|
-
}
|
|
3843
|
-
const calc = () => {
|
|
3844
|
-
const r = ref.current.getBoundingClientRect();
|
|
3845
|
-
const below = window.innerHeight - r.bottom;
|
|
3846
|
-
const up = below < estH && r.top > below;
|
|
3847
|
-
const w = Math.max(r.width, estW || 0);
|
|
3848
|
-
const maxH = Math.min(window.innerHeight - 16, Math.max(160, (up ? r.top : below) - 14));
|
|
3849
|
-
setPos({
|
|
3850
|
-
left: Math.max(8, Math.min(r.left, window.innerWidth - w - 8)),
|
|
3851
|
-
width: r.width,
|
|
3852
|
-
top: up ? null : r.bottom + 6,
|
|
3853
|
-
bottom: up ? window.innerHeight - r.top + 6 : null,
|
|
3854
|
-
up,
|
|
3855
|
-
maxH
|
|
3856
|
-
});
|
|
3857
|
-
};
|
|
3858
|
-
calc();
|
|
3859
|
-
window.addEventListener("scroll", calc, true);
|
|
3860
|
-
window.addEventListener("resize", calc);
|
|
3861
|
-
return () => {
|
|
3862
|
-
window.removeEventListener("scroll", calc, true);
|
|
3863
|
-
window.removeEventListener("resize", calc);
|
|
3864
|
-
};
|
|
3865
|
-
}, [open]);
|
|
3866
|
-
return pos;
|
|
3867
|
-
}
|
|
3868
|
-
var popStyle3 = (pos, extra) => ({
|
|
3869
|
-
position: "fixed",
|
|
3870
|
-
left: pos.left,
|
|
3871
|
-
top: pos.top == null ? "auto" : pos.top,
|
|
3872
|
-
bottom: pos.bottom == null ? "auto" : pos.bottom,
|
|
3873
|
-
transformOrigin: pos.up ? "bottom center" : "top center",
|
|
3874
|
-
maxHeight: pos.maxH,
|
|
3875
|
-
overflowY: "auto",
|
|
3876
|
-
...extra
|
|
3877
|
-
});
|
|
3878
3860
|
function ClockFace({ value = "09:00", onChange }) {
|
|
3879
3861
|
let [h24, m] = value.split(":").map(Number);
|
|
3880
3862
|
if (isNaN(h24)) h24 = 9;
|
|
3881
3863
|
if (isNaN(m)) m = 0;
|
|
3882
3864
|
const pm = h24 >= 12;
|
|
3883
3865
|
const h12 = h24 % 12 === 0 ? 12 : h24 % 12;
|
|
3884
|
-
const [mode2, setMode] =
|
|
3885
|
-
const faceRef =
|
|
3886
|
-
const dragging =
|
|
3866
|
+
const [mode2, setMode] = React24.useState("h");
|
|
3867
|
+
const faceRef = React24.useRef(null);
|
|
3868
|
+
const dragging = React24.useRef(false);
|
|
3887
3869
|
const set = (h, mm, isPm) => onChange((isPm ? h % 12 + 12 : h % 12) + ":" + pad(mm));
|
|
3888
3870
|
const R = 108, NR = 80;
|
|
3889
3871
|
const nums = mode2 === "h" ? Array.from({ length: 12 }, (_, i) => i + 1) : Array.from({ length: 12 }, (_, i) => i * 5);
|
|
@@ -3956,28 +3938,9 @@ function ClockFace({ value = "09:00", onChange }) {
|
|
|
3956
3938
|
}
|
|
3957
3939
|
function TimePicker({ label, help, error, required = false, disabled = false, value = "", onChange, placeholder = "Pick a time", id, className = "", style }) {
|
|
3958
3940
|
const { fieldId, labelId, ariaLabelledBy } = useTriggerLabelling(label, id);
|
|
3959
|
-
const [open, setOpen] =
|
|
3960
|
-
const rootRef =
|
|
3961
|
-
const boxRef =
|
|
3962
|
-
const popRef = React23.useRef(null);
|
|
3963
|
-
const pos = usePopPos3(open, boxRef, 420, 262);
|
|
3964
|
-
React23.useEffect(() => {
|
|
3965
|
-
if (!open) return;
|
|
3966
|
-
const away = (e) => {
|
|
3967
|
-
if (rootRef.current && rootRef.current.contains(e.target)) return;
|
|
3968
|
-
if (popRef.current && popRef.current.contains(e.target)) return;
|
|
3969
|
-
setOpen(false);
|
|
3970
|
-
};
|
|
3971
|
-
const esc = (e) => {
|
|
3972
|
-
if (e.key === "Escape") setOpen(false);
|
|
3973
|
-
};
|
|
3974
|
-
document.addEventListener("pointerdown", away);
|
|
3975
|
-
document.addEventListener("keydown", esc);
|
|
3976
|
-
return () => {
|
|
3977
|
-
document.removeEventListener("pointerdown", away);
|
|
3978
|
-
document.removeEventListener("keydown", esc);
|
|
3979
|
-
};
|
|
3980
|
-
}, [open]);
|
|
3941
|
+
const [open, setOpen] = React24.useState(false);
|
|
3942
|
+
const rootRef = React24.useRef(null);
|
|
3943
|
+
const boxRef = React24.useRef(null);
|
|
3981
3944
|
const disp = () => {
|
|
3982
3945
|
if (!value) return "";
|
|
3983
3946
|
const [h, m] = value.split(":").map(Number);
|
|
@@ -4009,10 +3972,19 @@ function TimePicker({ label, help, error, required = false, disabled = false, va
|
|
|
4009
3972
|
),
|
|
4010
3973
|
/* @__PURE__ */ jsx51("span", { className: "fd-select-caret", children: /* @__PURE__ */ jsx51("i", { className: "ph ph-caret-down", "aria-hidden": "true" }) })
|
|
4011
3974
|
] }),
|
|
4012
|
-
|
|
4013
|
-
|
|
4014
|
-
|
|
4015
|
-
|
|
3975
|
+
/* @__PURE__ */ jsx51(
|
|
3976
|
+
Popover,
|
|
3977
|
+
{
|
|
3978
|
+
open,
|
|
3979
|
+
anchorRef: boxRef,
|
|
3980
|
+
triggerRef: rootRef,
|
|
3981
|
+
onClose: () => setOpen(false),
|
|
3982
|
+
placement: "bottom-start",
|
|
3983
|
+
offset: 6,
|
|
3984
|
+
width: 262,
|
|
3985
|
+
role: "presentation",
|
|
3986
|
+
style: { zIndex: 130 },
|
|
3987
|
+
footer: /* @__PURE__ */ jsxs46(React24.Fragment, { children: [
|
|
4016
3988
|
/* @__PURE__ */ jsx51(
|
|
4017
3989
|
"button",
|
|
4018
3990
|
{
|
|
@@ -4028,10 +4000,10 @@ function TimePicker({ label, help, error, required = false, disabled = false, va
|
|
|
4028
4000
|
),
|
|
4029
4001
|
/* @__PURE__ */ jsx51("span", { style: { flex: 1 } }),
|
|
4030
4002
|
/* @__PURE__ */ jsx51("button", { type: "button", className: "fd-btn fd-btn-primary fd-btn-sm", onClick: () => setOpen(false), children: "Done" })
|
|
4031
|
-
] })
|
|
4032
|
-
|
|
4033
|
-
|
|
4034
|
-
)
|
|
4003
|
+
] }),
|
|
4004
|
+
children: /* @__PURE__ */ jsx51(ClockFace, { value: value || "09:00", onChange: (v) => onChange && onChange({ target: { value: v } }) })
|
|
4005
|
+
}
|
|
4006
|
+
),
|
|
4035
4007
|
error ? /* @__PURE__ */ jsxs46("span", { className: "fd-field-error", children: [
|
|
4036
4008
|
/* @__PURE__ */ jsx51("i", { className: "ph ph-warning-circle", "aria-hidden": "true" }),
|
|
4037
4009
|
error
|
|
@@ -4040,7 +4012,7 @@ function TimePicker({ label, help, error, required = false, disabled = false, va
|
|
|
4040
4012
|
}
|
|
4041
4013
|
|
|
4042
4014
|
// src/components/forms/Slider.tsx
|
|
4043
|
-
import * as
|
|
4015
|
+
import * as React25 from "react";
|
|
4044
4016
|
import { jsx as jsx52, jsxs as jsxs47 } from "react/jsx-runtime";
|
|
4045
4017
|
function Slider({
|
|
4046
4018
|
label,
|
|
@@ -4058,7 +4030,7 @@ function Slider({
|
|
|
4058
4030
|
...rest
|
|
4059
4031
|
}) {
|
|
4060
4032
|
const fieldId = useFieldId(id);
|
|
4061
|
-
const [dragging, setDragging] =
|
|
4033
|
+
const [dragging, setDragging] = React25.useState(false);
|
|
4062
4034
|
const v = value === void 0 ? min : Number(value);
|
|
4063
4035
|
const pct = max === min ? 0 : (v - min) / (max - min) * 100;
|
|
4064
4036
|
return /* @__PURE__ */ jsxs47("div", { className: ["fd-field", className].filter(Boolean).join(" "), children: [
|
|
@@ -4092,7 +4064,7 @@ function Slider({
|
|
|
4092
4064
|
}
|
|
4093
4065
|
|
|
4094
4066
|
// src/components/forms/RangeSlider.tsx
|
|
4095
|
-
import * as
|
|
4067
|
+
import * as React26 from "react";
|
|
4096
4068
|
import { jsx as jsx53, jsxs as jsxs48 } from "react/jsx-runtime";
|
|
4097
4069
|
function RangeSlider({
|
|
4098
4070
|
label,
|
|
@@ -4112,9 +4084,9 @@ function RangeSlider({
|
|
|
4112
4084
|
}) {
|
|
4113
4085
|
const fmt2 = format || ((v) => String(v));
|
|
4114
4086
|
const [a, b] = value || [min, max];
|
|
4115
|
-
const [drag, setDrag] =
|
|
4116
|
-
const [focus, setFocus] =
|
|
4117
|
-
const railRef =
|
|
4087
|
+
const [drag, setDrag] = React26.useState(null);
|
|
4088
|
+
const [focus, setFocus] = React26.useState(null);
|
|
4089
|
+
const railRef = React26.useRef(null);
|
|
4118
4090
|
const pct = (v) => max === min ? 0 : (v - min) / (max - min) * 100;
|
|
4119
4091
|
const clampPair = (i, v) => {
|
|
4120
4092
|
v = Math.min(max, Math.max(min, Math.round(v / step) * step));
|
|
@@ -4129,7 +4101,7 @@ function RangeSlider({
|
|
|
4129
4101
|
const r = railRef.current.getBoundingClientRect();
|
|
4130
4102
|
return min + Math.min(1, Math.max(0, (e.clientX - r.left) / r.width)) * (max - min);
|
|
4131
4103
|
};
|
|
4132
|
-
|
|
4104
|
+
React26.useEffect(() => {
|
|
4133
4105
|
if (drag === null) return;
|
|
4134
4106
|
const mv = (e) => onChange && onChange(clampPair(drag, fromEvent(e)));
|
|
4135
4107
|
const upH = () => setDrag(null);
|
|
@@ -4210,7 +4182,7 @@ function RangeSlider({
|
|
|
4210
4182
|
/* @__PURE__ */ jsxs48("div", { className: "fd-range" + (hasLabels ? " has-labels" : ""), onPointerDown: onRailDown, children: [
|
|
4211
4183
|
/* @__PURE__ */ jsx53("span", { className: "fd-range-rail", ref: railRef }),
|
|
4212
4184
|
/* @__PURE__ */ jsx53("span", { className: "fd-range-fill", style: { left: pct(a) + "%", width: pct(b) - pct(a) + "%" } }),
|
|
4213
|
-
marks.map((m) => /* @__PURE__ */ jsxs48(
|
|
4185
|
+
marks.map((m) => /* @__PURE__ */ jsxs48(React26.Fragment, { children: [
|
|
4214
4186
|
/* @__PURE__ */ jsx53("span", { className: "fd-range-mark" + (m.value >= a && m.value <= b ? " is-in" : ""), style: { left: pct(m.value) + "%" } }),
|
|
4215
4187
|
m.label ? /* @__PURE__ */ jsx53("span", { className: "fd-range-mark-label", style: { left: pct(m.value) + "%" }, children: m.label }) : null
|
|
4216
4188
|
] }, m.value)),
|
|
@@ -4239,7 +4211,7 @@ function RangeSlider({
|
|
|
4239
4211
|
}
|
|
4240
4212
|
|
|
4241
4213
|
// src/components/forms/Dropzone.tsx
|
|
4242
|
-
import * as
|
|
4214
|
+
import * as React27 from "react";
|
|
4243
4215
|
import { jsx as jsx54, jsxs as jsxs49 } from "react/jsx-runtime";
|
|
4244
4216
|
function Dropzone({
|
|
4245
4217
|
onFiles,
|
|
@@ -4254,8 +4226,8 @@ function Dropzone({
|
|
|
4254
4226
|
className = "",
|
|
4255
4227
|
style
|
|
4256
4228
|
}) {
|
|
4257
|
-
const [over, setOver] =
|
|
4258
|
-
const depth =
|
|
4229
|
+
const [over, setOver] = React27.useState(false);
|
|
4230
|
+
const depth = React27.useRef(0);
|
|
4259
4231
|
const has = (e) => {
|
|
4260
4232
|
const dt = e.dataTransfer;
|
|
4261
4233
|
if (!dt) return false;
|
|
@@ -4317,8 +4289,8 @@ function FilePickButton({
|
|
|
4317
4289
|
className = "",
|
|
4318
4290
|
children
|
|
4319
4291
|
}) {
|
|
4320
|
-
const ref =
|
|
4321
|
-
return /* @__PURE__ */ jsxs49(
|
|
4292
|
+
const ref = React27.useRef(null);
|
|
4293
|
+
return /* @__PURE__ */ jsxs49(React27.Fragment, { children: [
|
|
4322
4294
|
/* @__PURE__ */ jsx54(
|
|
4323
4295
|
"button",
|
|
4324
4296
|
{
|
|
@@ -4351,10 +4323,10 @@ function FilePickButton({
|
|
|
4351
4323
|
}
|
|
4352
4324
|
function useStagedFiles(upload, opts) {
|
|
4353
4325
|
const o = opts || {};
|
|
4354
|
-
const [items, setItems] =
|
|
4355
|
-
const controllers =
|
|
4326
|
+
const [items, setItems] = React27.useState([]);
|
|
4327
|
+
const controllers = React27.useRef({});
|
|
4356
4328
|
const patch = (id, next) => setItems((list) => list.map((f) => f.id === id ? Object.assign({}, f, next) : f));
|
|
4357
|
-
const run =
|
|
4329
|
+
const run = React27.useCallback((att) => {
|
|
4358
4330
|
if (!upload) return;
|
|
4359
4331
|
const ac = typeof AbortController !== "undefined" ? new AbortController() : null;
|
|
4360
4332
|
controllers.current[att.id] = ac;
|
|
@@ -4371,14 +4343,14 @@ function useStagedFiles(upload, opts) {
|
|
|
4371
4343
|
delete controllers.current[att.id];
|
|
4372
4344
|
});
|
|
4373
4345
|
}, [upload]);
|
|
4374
|
-
const add =
|
|
4346
|
+
const add = React27.useCallback((files) => {
|
|
4375
4347
|
if (!upload) return [];
|
|
4376
4348
|
const atts = Array.from(files).map((f) => toAttachment(f));
|
|
4377
4349
|
setItems((list) => list.concat(atts));
|
|
4378
4350
|
atts.forEach(run);
|
|
4379
4351
|
return atts;
|
|
4380
4352
|
}, [upload, run]);
|
|
4381
|
-
const remove =
|
|
4353
|
+
const remove = React27.useCallback((att) => {
|
|
4382
4354
|
const ac = controllers.current[att.id];
|
|
4383
4355
|
if (ac) {
|
|
4384
4356
|
try {
|
|
@@ -4389,10 +4361,10 @@ function useStagedFiles(upload, opts) {
|
|
|
4389
4361
|
}
|
|
4390
4362
|
setItems((list) => list.filter((f) => f.id !== att.id));
|
|
4391
4363
|
}, []);
|
|
4392
|
-
const retry =
|
|
4364
|
+
const retry = React27.useCallback((att) => {
|
|
4393
4365
|
run(att);
|
|
4394
4366
|
}, [run]);
|
|
4395
|
-
const clear =
|
|
4367
|
+
const clear = React27.useCallback(() => {
|
|
4396
4368
|
Object.values(controllers.current).forEach((ac) => {
|
|
4397
4369
|
try {
|
|
4398
4370
|
ac && ac.abort();
|
|
@@ -4516,7 +4488,7 @@ function FileGrid({ files = [], onOpen, onRemove, onRetry, tiles = true, maxHeig
|
|
|
4516
4488
|
}
|
|
4517
4489
|
|
|
4518
4490
|
// src/components/forms/MarkdownEditor.tsx
|
|
4519
|
-
import * as
|
|
4491
|
+
import * as React28 from "react";
|
|
4520
4492
|
import { jsx as jsx56, jsxs as jsxs51 } from "react/jsx-runtime";
|
|
4521
4493
|
var isMac = typeof navigator !== "undefined" && /Mac|iPhone|iPad/.test(navigator.platform || navigator.userAgent || "");
|
|
4522
4494
|
var INLINE_RE = /(\*\*\*[^*\n]+\*\*\*|\*\*[^*\n]+\*\*|__[^_\n]+__|~~[^~\n]+~~|`[^`\n]+`|\*[^*\s][^*\n]*\*|(?<![A-Za-z0-9_])_[^_\s][^_\n]*_|\[[^\]\n]*\]\([^)\s\n]*\)|https?:\/\/\S+)/g;
|
|
@@ -4730,7 +4702,7 @@ function syncDom(root, value) {
|
|
|
4730
4702
|
while (root.children.length > lines.length) root.removeChild(root.lastChild);
|
|
4731
4703
|
}
|
|
4732
4704
|
var LIST_CONT = RE_LI;
|
|
4733
|
-
var MarkdownEditor =
|
|
4705
|
+
var MarkdownEditor = React28.forwardRef(function MarkdownEditor2({
|
|
4734
4706
|
value = "",
|
|
4735
4707
|
onChange,
|
|
4736
4708
|
onSubmit,
|
|
@@ -4749,10 +4721,10 @@ var MarkdownEditor = React27.forwardRef(function MarkdownEditor2({
|
|
|
4749
4721
|
className = "",
|
|
4750
4722
|
id
|
|
4751
4723
|
}, ref) {
|
|
4752
|
-
const boxRef =
|
|
4753
|
-
const composing =
|
|
4754
|
-
const pendingCaret =
|
|
4755
|
-
|
|
4724
|
+
const boxRef = React28.useRef(null);
|
|
4725
|
+
const composing = React28.useRef(false);
|
|
4726
|
+
const pendingCaret = React28.useRef(null);
|
|
4727
|
+
React28.useLayoutEffect(() => {
|
|
4756
4728
|
const root = boxRef.current;
|
|
4757
4729
|
if (!root || composing.current) return;
|
|
4758
4730
|
const active = document.activeElement === root || root.contains(document.activeElement);
|
|
@@ -4761,7 +4733,7 @@ var MarkdownEditor = React27.forwardRef(function MarkdownEditor2({
|
|
|
4761
4733
|
pendingCaret.current = null;
|
|
4762
4734
|
if (active && caret != null) placeCaret(root, caret);
|
|
4763
4735
|
}, [value]);
|
|
4764
|
-
|
|
4736
|
+
React28.useEffect(() => {
|
|
4765
4737
|
if (autoFocus && boxRef.current) boxRef.current.focus();
|
|
4766
4738
|
}, [autoFocus]);
|
|
4767
4739
|
const caretNow = () => {
|
|
@@ -4828,7 +4800,7 @@ var MarkdownEditor = React27.forwardRef(function MarkdownEditor2({
|
|
|
4828
4800
|
api.replaceRange(from, to, next, from + next.length);
|
|
4829
4801
|
}
|
|
4830
4802
|
};
|
|
4831
|
-
|
|
4803
|
+
React28.useImperativeHandle(ref, () => api);
|
|
4832
4804
|
function detect(text, caret) {
|
|
4833
4805
|
if (!onTrigger) return;
|
|
4834
4806
|
const upto = text.slice(0, caret);
|
|
@@ -4980,10 +4952,10 @@ var MarkdownEditor = React27.forwardRef(function MarkdownEditor2({
|
|
|
4980
4952
|
});
|
|
4981
4953
|
|
|
4982
4954
|
// src/components/platform/AccountMenu.tsx
|
|
4983
|
-
import * as
|
|
4955
|
+
import * as React30 from "react";
|
|
4984
4956
|
|
|
4985
4957
|
// src/kits/session.ts
|
|
4986
|
-
import * as
|
|
4958
|
+
import * as React29 from "react";
|
|
4987
4959
|
var PERMISSION_CATALOG = [
|
|
4988
4960
|
{ group: "Plans", items: [
|
|
4989
4961
|
{ key: "plan.view", label: "View plans", detail: "Read any plan in the workspace." },
|
|
@@ -6550,8 +6522,8 @@ function roadmap(overrides) {
|
|
|
6550
6522
|
};
|
|
6551
6523
|
}
|
|
6552
6524
|
function useSession() {
|
|
6553
|
-
const [s, setS] =
|
|
6554
|
-
|
|
6525
|
+
const [s, setS] = React29.useState(getSession);
|
|
6526
|
+
React29.useEffect(() => subscribe(setS), []);
|
|
6555
6527
|
return s;
|
|
6556
6528
|
}
|
|
6557
6529
|
var SessionKit = {
|
|
@@ -6584,7 +6556,7 @@ var SessionKit = {
|
|
|
6584
6556
|
};
|
|
6585
6557
|
|
|
6586
6558
|
// src/components/platform/AccountMenu.tsx
|
|
6587
|
-
import { Fragment as
|
|
6559
|
+
import { Fragment as Fragment14, jsx as jsx57, jsxs as jsxs52 } from "react/jsx-runtime";
|
|
6588
6560
|
var DEFAULT_LINKS = [
|
|
6589
6561
|
{ id: "profile", label: "Your profile", icon: "user-circle", href: "../admin/index.html#profile" },
|
|
6590
6562
|
{ id: "preferences", label: "Preferences", icon: "sliders-horizontal", href: "../admin/index.html#preferences" }
|
|
@@ -6621,9 +6593,9 @@ function AccountMenu({
|
|
|
6621
6593
|
...rest
|
|
6622
6594
|
}) {
|
|
6623
6595
|
const session = SessionKit.useSession();
|
|
6624
|
-
const [open, setOpen] =
|
|
6625
|
-
const [switching, setSwitching] =
|
|
6626
|
-
const ref =
|
|
6596
|
+
const [open, setOpen] = React30.useState(false);
|
|
6597
|
+
const [switching, setSwitching] = React30.useState(false);
|
|
6598
|
+
const ref = React30.useRef(null);
|
|
6627
6599
|
const user = session.user;
|
|
6628
6600
|
const visibleAdmin = adminLinks.filter((l) => !l.perm || SessionKit.can(l.perm));
|
|
6629
6601
|
const pick = (item) => {
|
|
@@ -6637,7 +6609,7 @@ function AccountMenu({
|
|
|
6637
6609
|
if (onSignOut) return onSignOut();
|
|
6638
6610
|
window.alert("Signed out. (Simulated \u2014 no auth provider is wired up.)");
|
|
6639
6611
|
};
|
|
6640
|
-
return /* @__PURE__ */ jsxs52(
|
|
6612
|
+
return /* @__PURE__ */ jsxs52(Fragment14, { children: [
|
|
6641
6613
|
/* @__PURE__ */ jsxs52(
|
|
6642
6614
|
"button",
|
|
6643
6615
|
{
|
|
@@ -6675,7 +6647,7 @@ function AccountMenu({
|
|
|
6675
6647
|
/* @__PURE__ */ jsx57("span", { style: { flex: 1 }, children: "View as another member" }),
|
|
6676
6648
|
/* @__PURE__ */ jsx57("i", { className: "ph ph-caret-" + (switching ? "up" : "down"), "aria-hidden": "true", style: { fontSize: 11 } })
|
|
6677
6649
|
] }),
|
|
6678
|
-
switching ? /* @__PURE__ */ jsx57("div", { className: "fd-stack", style: { gap: 0
|
|
6650
|
+
switching ? /* @__PURE__ */ jsx57("div", { className: "fd-stack", style: { gap: 0 }, children: session.allUsers.filter((u) => u.status === "active").map((u) => /* @__PURE__ */ jsxs52(
|
|
6679
6651
|
"button",
|
|
6680
6652
|
{
|
|
6681
6653
|
type: "button",
|
|
@@ -6707,14 +6679,14 @@ function AccountMenu({
|
|
|
6707
6679
|
}
|
|
6708
6680
|
|
|
6709
6681
|
// src/components/platform/ApiSpecBrowser.tsx
|
|
6710
|
-
import * as
|
|
6682
|
+
import * as React31 from "react";
|
|
6711
6683
|
import { jsx as jsx58, jsxs as jsxs53 } from "react/jsx-runtime";
|
|
6712
6684
|
var METHOD_TONE = { GET: "success", POST: "info", PATCH: "warning", PUT: "warning", DELETE: "danger" };
|
|
6713
6685
|
function Json({ obj }) {
|
|
6714
6686
|
return /* @__PURE__ */ jsx58("pre", { className: "fd-json", children: JSON.stringify(obj, null, 2) });
|
|
6715
6687
|
}
|
|
6716
6688
|
function Endpoint({ s, onRequest }) {
|
|
6717
|
-
const [tried, setTried] =
|
|
6689
|
+
const [tried, setTried] = React31.useState(null);
|
|
6718
6690
|
const run = async () => {
|
|
6719
6691
|
setTried("busy");
|
|
6720
6692
|
const t0 = (window.performance || Date).now();
|
|
@@ -6787,10 +6759,10 @@ function ApiSpecBrowser({
|
|
|
6787
6759
|
className = "",
|
|
6788
6760
|
...rest
|
|
6789
6761
|
}) {
|
|
6790
|
-
const [q, setQ] =
|
|
6791
|
-
const [method, setMethod] =
|
|
6792
|
-
const [mod, setMod] =
|
|
6793
|
-
const [listOnly, setListOnly] =
|
|
6762
|
+
const [q, setQ] = React31.useState("");
|
|
6763
|
+
const [method, setMethod] = React31.useState(null);
|
|
6764
|
+
const [mod, setMod] = React31.useState(null);
|
|
6765
|
+
const [listOnly, setListOnly] = React31.useState(false);
|
|
6794
6766
|
const activeModule = modules && modules.find((m) => m.id === mod);
|
|
6795
6767
|
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())));
|
|
6796
6768
|
const effGroups = groups && groups.length ? groups : [["All endpoints", spec.map((s) => s.id)]];
|
|
@@ -6869,7 +6841,7 @@ function ApiSpecBrowser({
|
|
|
6869
6841
|
}
|
|
6870
6842
|
|
|
6871
6843
|
// src/components/platform/ProfilePage.tsx
|
|
6872
|
-
import * as
|
|
6844
|
+
import * as React32 from "react";
|
|
6873
6845
|
import { jsx as jsx59, jsxs as jsxs54 } from "react/jsx-runtime";
|
|
6874
6846
|
var TIMEZONES = ["America/New_York", "America/Chicago", "America/Denver", "America/Los_Angeles", "America/Anchorage", "Pacific/Honolulu", "Europe/London", "Europe/Berlin"];
|
|
6875
6847
|
var NOTIFY = [
|
|
@@ -6882,7 +6854,7 @@ var NOTIFY = [
|
|
|
6882
6854
|
function ProfilePage({ user: userProp, onSave, onNavigate, sessions, showSessions = true, className = "", ...rest }) {
|
|
6883
6855
|
const session = SessionKit.useSession();
|
|
6884
6856
|
const user = userProp || session.user;
|
|
6885
|
-
const [draft, setDraft] =
|
|
6857
|
+
const [draft, setDraft] = React32.useState(() => ({
|
|
6886
6858
|
name: user.name || "",
|
|
6887
6859
|
title: user.title || "",
|
|
6888
6860
|
email: user.email || "",
|
|
@@ -6891,8 +6863,8 @@ function ProfilePage({ user: userProp, onSave, onNavigate, sessions, showSession
|
|
|
6891
6863
|
bio: user.bio || "",
|
|
6892
6864
|
notify: user.notify || { planShared: true, planChanged: true, goalMissed: true, flagChanged: false, weekly: true }
|
|
6893
6865
|
}));
|
|
6894
|
-
const [saving, setSaving] =
|
|
6895
|
-
const [saved, setSaved] =
|
|
6866
|
+
const [saving, setSaving] = React32.useState(false);
|
|
6867
|
+
const [saved, setSaved] = React32.useState(false);
|
|
6896
6868
|
const set = (k, v) => {
|
|
6897
6869
|
setDraft((d) => Object.assign({}, d, { [k]: v }));
|
|
6898
6870
|
setSaved(false);
|
|
@@ -7082,10 +7054,10 @@ function ProfilePage({ user: userProp, onSave, onNavigate, sessions, showSession
|
|
|
7082
7054
|
}
|
|
7083
7055
|
|
|
7084
7056
|
// src/components/platform/RoadmapTimeline.tsx
|
|
7085
|
-
import * as
|
|
7057
|
+
import * as React34 from "react";
|
|
7086
7058
|
|
|
7087
7059
|
// src/kits/runtime.ts
|
|
7088
|
-
import * as
|
|
7060
|
+
import * as React33 from "react";
|
|
7089
7061
|
var WIRED_ENDPOINTS = [
|
|
7090
7062
|
// Nothing yet. Every id below would come from a real service:
|
|
7091
7063
|
// "plan.get", "placements.list", …
|
|
@@ -7256,8 +7228,8 @@ var RuntimeKit = {
|
|
|
7256
7228
|
};
|
|
7257
7229
|
RuntimeKit.declare(FEATURE_NEEDS);
|
|
7258
7230
|
function useRuntimeMode() {
|
|
7259
|
-
const [m, setM] =
|
|
7260
|
-
|
|
7231
|
+
const [m, setM] = React33.useState(RuntimeKit.getMode());
|
|
7232
|
+
React33.useEffect(() => RuntimeKit.subscribe(setM), []);
|
|
7261
7233
|
return m;
|
|
7262
7234
|
}
|
|
7263
7235
|
function useFeatureStatus(key) {
|
|
@@ -7340,12 +7312,12 @@ function RoadmapCard({ item, byKey, onOpenFlag }) {
|
|
|
7340
7312
|
}
|
|
7341
7313
|
function RoadmapTimeline({ onOpenFlag, title = "Roadmap", lede }) {
|
|
7342
7314
|
const session = SessionKit.useSession();
|
|
7343
|
-
const [project, setProject] =
|
|
7344
|
-
const [q, setQ] =
|
|
7345
|
-
const scrollRef =
|
|
7346
|
-
const nowRef =
|
|
7347
|
-
const rm =
|
|
7348
|
-
const byKey =
|
|
7315
|
+
const [project, setProject] = React34.useState("");
|
|
7316
|
+
const [q, setQ] = React34.useState("");
|
|
7317
|
+
const scrollRef = React34.useRef(null);
|
|
7318
|
+
const nowRef = React34.useRef(null);
|
|
7319
|
+
const rm = React34.useMemo(() => SessionKit.roadmap({ isComplete: RuntimeKit.isComplete }), [session]);
|
|
7320
|
+
const byKey = React34.useMemo(() => {
|
|
7349
7321
|
const m = {};
|
|
7350
7322
|
rm.items.forEach((i) => {
|
|
7351
7323
|
m[i.key] = i;
|
|
@@ -7354,7 +7326,7 @@ function RoadmapTimeline({ onOpenFlag, title = "Roadmap", lede }) {
|
|
|
7354
7326
|
}, [rm]);
|
|
7355
7327
|
const items = rm.items.filter((i) => (!project || i.project === project) && (!q || (i.label + " " + i.description + " " + (i.backend || "") + " " + i.key).toLowerCase().includes(q.toLowerCase())));
|
|
7356
7328
|
const projects = [...new Set(rm.items.map((i) => i.project))];
|
|
7357
|
-
|
|
7329
|
+
React34.useEffect(() => {
|
|
7358
7330
|
let raf1 = 0, raf2 = 0;
|
|
7359
7331
|
const place = () => {
|
|
7360
7332
|
const box = scrollRef.current, mark = nowRef.current;
|
|
@@ -7428,7 +7400,7 @@ function RoadmapTimeline({ onOpenFlag, title = "Roadmap", lede }) {
|
|
|
7428
7400
|
lastPhase = item.phase;
|
|
7429
7401
|
const inPhase = items.filter((i) => i.phase === item.phase).length;
|
|
7430
7402
|
const isBoundary = n === firstPending;
|
|
7431
|
-
return /* @__PURE__ */ jsxs55(
|
|
7403
|
+
return /* @__PURE__ */ jsxs55(React34.Fragment, { children: [
|
|
7432
7404
|
showPhase ? /* @__PURE__ */ jsxs55("div", { className: "fd-rm-era", children: [
|
|
7433
7405
|
/* @__PURE__ */ jsxs55("span", { className: "fd-row", style: { gap: 8, flexWrap: "wrap", alignItems: "baseline" }, children: [
|
|
7434
7406
|
/* @__PURE__ */ jsx60("span", { style: { fontWeight: 700 }, children: item.phase === 0 ? "Shipped" : "Phase " + item.phase + " \u2014 " + item.phaseName }),
|
|
@@ -7472,9 +7444,9 @@ function RoadmapTimeline({ onOpenFlag, title = "Roadmap", lede }) {
|
|
|
7472
7444
|
}
|
|
7473
7445
|
|
|
7474
7446
|
// src/components/platform/ComingSoon.tsx
|
|
7475
|
-
import * as
|
|
7476
|
-
import { createPortal as
|
|
7477
|
-
import { Fragment as
|
|
7447
|
+
import * as React35 from "react";
|
|
7448
|
+
import { createPortal as createPortal5 } from "react-dom";
|
|
7449
|
+
import { Fragment as Fragment16, jsx as jsx61, jsxs as jsxs56 } from "react/jsx-runtime";
|
|
7478
7450
|
var BYPASS_STORE = "fd.soon.bypass.v1";
|
|
7479
7451
|
function readBypassed() {
|
|
7480
7452
|
try {
|
|
@@ -7490,8 +7462,8 @@ function writeBypassed(list) {
|
|
|
7490
7462
|
}
|
|
7491
7463
|
}
|
|
7492
7464
|
function useBypass(key) {
|
|
7493
|
-
const [on, setOn] =
|
|
7494
|
-
|
|
7465
|
+
const [on, setOn] = React35.useState(() => !!key && readBypassed().indexOf(key) >= 0);
|
|
7466
|
+
React35.useEffect(() => {
|
|
7495
7467
|
setOn(!!key && readBypassed().indexOf(key) >= 0);
|
|
7496
7468
|
}, [key]);
|
|
7497
7469
|
const set = (next) => {
|
|
@@ -7504,7 +7476,7 @@ function useBypass(key) {
|
|
|
7504
7476
|
return [on, set];
|
|
7505
7477
|
}
|
|
7506
7478
|
function SoonCard({ label, detail, backend, eta, effort, onRoadmap, allowed, onBypass }) {
|
|
7507
|
-
return /* @__PURE__ */ jsxs56(
|
|
7479
|
+
return /* @__PURE__ */ jsxs56(Fragment16, { children: [
|
|
7508
7480
|
/* @__PURE__ */ jsxs56("span", { className: "fd-soon-badge", children: [
|
|
7509
7481
|
/* @__PURE__ */ jsx61("i", { className: "ph ph-traffic-cone", "aria-hidden": "true" }),
|
|
7510
7482
|
label
|
|
@@ -7538,9 +7510,9 @@ function SoonCard({ label, detail, backend, eta, effort, onRoadmap, allowed, onB
|
|
|
7538
7510
|
] });
|
|
7539
7511
|
}
|
|
7540
7512
|
function useHoverCard(open) {
|
|
7541
|
-
const anchor =
|
|
7542
|
-
const [pos, setPos] =
|
|
7543
|
-
|
|
7513
|
+
const anchor = React35.useRef(null);
|
|
7514
|
+
const [pos, setPos] = React35.useState(null);
|
|
7515
|
+
React35.useLayoutEffect(() => {
|
|
7544
7516
|
if (!open || !anchor.current) {
|
|
7545
7517
|
setPos(null);
|
|
7546
7518
|
return;
|
|
@@ -7667,9 +7639,9 @@ function ComingSoon({
|
|
|
7667
7639
|
] });
|
|
7668
7640
|
}
|
|
7669
7641
|
function InlineSoon({ label, detail, backend, eta, effort, onRoadmap, allowed, onBypass, blur, tip, className, rest, children }) {
|
|
7670
|
-
const [open, setOpen] =
|
|
7642
|
+
const [open, setOpen] = React35.useState(false);
|
|
7671
7643
|
const [anchor, pos] = useHoverCard(open);
|
|
7672
|
-
const close =
|
|
7644
|
+
const close = React35.useRef(null);
|
|
7673
7645
|
const show = () => {
|
|
7674
7646
|
if (close.current) {
|
|
7675
7647
|
clearTimeout(close.current);
|
|
@@ -7685,7 +7657,7 @@ function InlineSoon({ label, detail, backend, eta, effort, onRoadmap, allowed, o
|
|
|
7685
7657
|
setOpen(false);
|
|
7686
7658
|
}, 140);
|
|
7687
7659
|
};
|
|
7688
|
-
|
|
7660
|
+
React35.useEffect(() => () => {
|
|
7689
7661
|
if (close.current) clearTimeout(close.current);
|
|
7690
7662
|
}, []);
|
|
7691
7663
|
return /* @__PURE__ */ jsxs56(
|
|
@@ -7714,7 +7686,7 @@ function InlineSoon({ label, detail, backend, eta, effort, onRoadmap, allowed, o
|
|
|
7714
7686
|
children: /* @__PURE__ */ jsx61("i", { className: "ph ph-traffic-cone", "aria-hidden": "true" })
|
|
7715
7687
|
}
|
|
7716
7688
|
),
|
|
7717
|
-
open && pos ?
|
|
7689
|
+
open && pos ? createPortal5(
|
|
7718
7690
|
/* @__PURE__ */ jsx61(
|
|
7719
7691
|
"div",
|
|
7720
7692
|
{
|
|
@@ -7854,13 +7826,13 @@ function PermissionHint({ perm, children }) {
|
|
|
7854
7826
|
}
|
|
7855
7827
|
|
|
7856
7828
|
// src/components/platform/ModeSwitch.tsx
|
|
7857
|
-
import * as
|
|
7858
|
-
import { Fragment as
|
|
7829
|
+
import * as React36 from "react";
|
|
7830
|
+
import { Fragment as Fragment17, jsx as jsx63, jsxs as jsxs58 } from "react/jsx-runtime";
|
|
7859
7831
|
function ModeSwitch({ canToggle = false, requestCount = 0, onClearLog, renderLog, onOpenSpec, summary }) {
|
|
7860
7832
|
const mode2 = useRuntimeMode();
|
|
7861
|
-
const [open, setOpen] =
|
|
7862
|
-
const ref =
|
|
7863
|
-
|
|
7833
|
+
const [open, setOpen] = React36.useState(false);
|
|
7834
|
+
const ref = React36.useRef(null);
|
|
7835
|
+
React36.useEffect(() => {
|
|
7864
7836
|
if (!open) return;
|
|
7865
7837
|
const away = (e) => {
|
|
7866
7838
|
if (ref.current && !ref.current.contains(e.target)) setOpen(false);
|
|
@@ -7925,7 +7897,7 @@ function ModeSwitch({ canToggle = false, requestCount = 0, onClearLog, renderLog
|
|
|
7925
7897
|
s.total,
|
|
7926
7898
|
" features complete"
|
|
7927
7899
|
] }),
|
|
7928
|
-
onOpenSpec ? /* @__PURE__ */ jsxs58(
|
|
7900
|
+
onOpenSpec ? /* @__PURE__ */ jsxs58(Fragment17, { children: [
|
|
7929
7901
|
/* @__PURE__ */ jsx63("span", { style: { flex: 1 } }),
|
|
7930
7902
|
/* @__PURE__ */ jsxs58("button", { type: "button", className: "fd-soon-link", onClick: () => {
|
|
7931
7903
|
setOpen(false);
|
|
@@ -8109,11 +8081,11 @@ function SaturationDistribution({ campuses = [], floorBand, floorScore, onSelect
|
|
|
8109
8081
|
}
|
|
8110
8082
|
|
|
8111
8083
|
// src/components/planner/MixGap.tsx
|
|
8112
|
-
import * as
|
|
8113
|
-
import { Fragment as
|
|
8084
|
+
import * as React37 from "react";
|
|
8085
|
+
import { Fragment as Fragment18, jsx as jsx66, jsxs as jsxs61 } from "react/jsx-runtime";
|
|
8114
8086
|
function MixGap({ rows = [], loading = false, className = "" }) {
|
|
8115
8087
|
const max = Math.max(1, ...rows.flatMap((r) => [r.target, r.realized]));
|
|
8116
|
-
const [hover, setHover] =
|
|
8088
|
+
const [hover, setHover] = React37.useState(null);
|
|
8117
8089
|
const toneOf = (gap) => gap >= -1 ? "ok" : gap >= -4 ? "warn" : "danger";
|
|
8118
8090
|
const TONE = { ok: "var(--ok-solid)", warn: "var(--warn-solid)", danger: "var(--danger-solid)" };
|
|
8119
8091
|
return /* @__PURE__ */ jsxs61("div", { className: ["fd-stack", className].filter(Boolean).join(" "), style: { gap: 4 }, children: [
|
|
@@ -8140,7 +8112,7 @@ function MixGap({ rows = [], loading = false, className = "" }) {
|
|
|
8140
8112
|
onMouseLeave: () => setHover(null),
|
|
8141
8113
|
children: [
|
|
8142
8114
|
/* @__PURE__ */ jsx66("span", { style: { width: 128, flex: "none" }, children: /* @__PURE__ */ jsx66(ChannelTag, { channel: r.channel, size: "sm" }) }),
|
|
8143
|
-
/* @__PURE__ */ jsx66("span", { style: { position: "relative", flex: 1, height: 22, minWidth: 120 }, children: loading ? /* @__PURE__ */ jsx66("span", { className: "fd-skel", style: { position: "absolute", inset: "5px 0", borderRadius: 3 } }) : /* @__PURE__ */ jsxs61(
|
|
8115
|
+
/* @__PURE__ */ jsx66("span", { style: { position: "relative", flex: 1, height: 22, minWidth: 120 }, children: loading ? /* @__PURE__ */ jsx66("span", { className: "fd-skel", style: { position: "absolute", inset: "5px 0", borderRadius: 3 } }) : /* @__PURE__ */ jsxs61(Fragment18, { children: [
|
|
8144
8116
|
/* @__PURE__ */ jsx66("span", { style: { position: "absolute", left: 0, top: 5, height: 12, width: r.realized / max * 100 + "%", background: TONE[tone], borderRadius: "2px 3px 3px 2px", transition: "width var(--dur-slow) var(--ease), background var(--dur-base) var(--ease)" } }),
|
|
8145
8117
|
/* @__PURE__ */ jsx66("span", { style: { position: "absolute", left: r.target / max * 100 + "%", top: 0, width: 3, height: 22, background: "var(--n-500)", borderRadius: 1 } }),
|
|
8146
8118
|
/* @__PURE__ */ jsxs61("span", { className: "fd-num", style: { position: "absolute", right: Math.max(r.realized, r.target) / max > 0.82 ? 0 : "auto", left: Math.max(r.realized, r.target) / max > 0.82 ? "auto" : "calc(" + Math.max(r.realized, r.target) / max * 100 + "% + 10px)", top: 2, fontSize: 12, color: "var(--text-muted)", whiteSpace: "nowrap", background: Math.max(r.realized, r.target) / max > 0.82 ? "var(--surface)" : "none", paddingLeft: 3 }, children: [
|
|
@@ -8253,8 +8225,8 @@ function ChannelContribution({
|
|
|
8253
8225
|
}
|
|
8254
8226
|
|
|
8255
8227
|
// src/components/planner/BudgetReallocator.tsx
|
|
8256
|
-
import * as
|
|
8257
|
-
import { Fragment as
|
|
8228
|
+
import * as React38 from "react";
|
|
8229
|
+
import { Fragment as Fragment19, jsx as jsx68, jsxs as jsxs63 } from "react/jsx-runtime";
|
|
8258
8230
|
var bandFor = (crp) => crp >= 200 ? "dominant" : crp >= 100 ? "strong" : crp >= 50 ? "adequate" : "weak";
|
|
8259
8231
|
function BudgetReallocator({
|
|
8260
8232
|
campus,
|
|
@@ -8269,8 +8241,8 @@ function BudgetReallocator({
|
|
|
8269
8241
|
onCancel,
|
|
8270
8242
|
className = ""
|
|
8271
8243
|
}) {
|
|
8272
|
-
const [draft, setDraft] =
|
|
8273
|
-
|
|
8244
|
+
const [draft, setDraft] = React38.useState(spend);
|
|
8245
|
+
React38.useEffect(() => setDraft(spend), [spend]);
|
|
8274
8246
|
const dirty = draft !== spend;
|
|
8275
8247
|
const nextCrp = scoreFor ? scoreFor(draft) : crp;
|
|
8276
8248
|
const nextBand = bandFor(nextCrp);
|
|
@@ -8294,7 +8266,7 @@ function BudgetReallocator({
|
|
|
8294
8266
|
/* @__PURE__ */ jsxs63("div", { className: "fd-row", style: { gap: 12, flexWrap: "wrap" }, children: [
|
|
8295
8267
|
/* @__PURE__ */ jsx68("span", { className: "fd-h4", style: { flex: 1, minWidth: 140 }, children: campus }),
|
|
8296
8268
|
/* @__PURE__ */ jsx68(CsiBadge, { band: nowBand, crp, size: "medium" }),
|
|
8297
|
-
dirty ? /* @__PURE__ */ jsxs63(
|
|
8269
|
+
dirty ? /* @__PURE__ */ jsxs63(Fragment19, { children: [
|
|
8298
8270
|
/* @__PURE__ */ jsx68("i", { className: "ph ph-arrow-right fd-muted", "aria-hidden": "true" }),
|
|
8299
8271
|
/* @__PURE__ */ jsx68(CsiBadge, { band: nextBand, crp: nextCrp, size: "medium", preview: true })
|
|
8300
8272
|
] }) : null
|
|
@@ -8440,7 +8412,7 @@ function ImportanceTag({ level, showLabel = true, size = "sm", className = "" })
|
|
|
8440
8412
|
}
|
|
8441
8413
|
|
|
8442
8414
|
// src/components/planner/PreferenceMeter.tsx
|
|
8443
|
-
import * as
|
|
8415
|
+
import * as React39 from "react";
|
|
8444
8416
|
import { jsx as jsx71, jsxs as jsxs66 } from "react/jsx-runtime";
|
|
8445
8417
|
function preferenceScore(criteria) {
|
|
8446
8418
|
const earned = criteria.reduce((n, c) => n + (Number(c.earned) || 0), 0);
|
|
@@ -8470,7 +8442,7 @@ function PreferenceMeter({
|
|
|
8470
8442
|
className = ""
|
|
8471
8443
|
}) {
|
|
8472
8444
|
const value = score == null ? preferenceScore(criteria) : score;
|
|
8473
|
-
const segments =
|
|
8445
|
+
const segments = React39.useMemo(() => preferenceSegments(criteria), [criteria]);
|
|
8474
8446
|
return /* @__PURE__ */ jsx71(
|
|
8475
8447
|
ScoreMeter,
|
|
8476
8448
|
{
|
|
@@ -8509,10 +8481,10 @@ function PreferenceMeter({
|
|
|
8509
8481
|
}
|
|
8510
8482
|
|
|
8511
8483
|
// src/components/chat/AgentChatPanel.tsx
|
|
8512
|
-
import * as
|
|
8484
|
+
import * as React45 from "react";
|
|
8513
8485
|
|
|
8514
8486
|
// src/components/chat/chatEngine.ts
|
|
8515
|
-
import * as
|
|
8487
|
+
import * as React40 from "react";
|
|
8516
8488
|
var CHAT_UNAVAILABLE = "chat_unavailable";
|
|
8517
8489
|
var JOB_PENDING = ["queued", "running"];
|
|
8518
8490
|
var JOB_SUCCESS = ["completed", "recovered"];
|
|
@@ -8566,22 +8538,22 @@ function useChatEngine(opts) {
|
|
|
8566
8538
|
onClear,
|
|
8567
8539
|
onFeedback
|
|
8568
8540
|
} = opts || {};
|
|
8569
|
-
const [status, setStatus] =
|
|
8570
|
-
const [threadId, setThreadId] =
|
|
8571
|
-
const [messages, setMessages] =
|
|
8572
|
-
const [queue, setQueue] =
|
|
8573
|
-
const [fatal, setFatal] =
|
|
8574
|
-
const [busy, setBusy] =
|
|
8575
|
-
const [turnStartedAt, setTurnStartedAt] =
|
|
8576
|
-
const listRef =
|
|
8577
|
-
const queueRef =
|
|
8578
|
-
const busyRef =
|
|
8579
|
-
const stoppedRef =
|
|
8580
|
-
const abortRef =
|
|
8581
|
-
const serverCount =
|
|
8582
|
-
const threadRef =
|
|
8583
|
-
const mounted =
|
|
8584
|
-
|
|
8541
|
+
const [status, setStatus] = React40.useState("idle");
|
|
8542
|
+
const [threadId, setThreadId] = React40.useState(null);
|
|
8543
|
+
const [messages, setMessages] = React40.useState([]);
|
|
8544
|
+
const [queue, setQueue] = React40.useState([]);
|
|
8545
|
+
const [fatal, setFatal] = React40.useState(null);
|
|
8546
|
+
const [busy, setBusy] = React40.useState(false);
|
|
8547
|
+
const [turnStartedAt, setTurnStartedAt] = React40.useState(null);
|
|
8548
|
+
const listRef = React40.useRef([]);
|
|
8549
|
+
const queueRef = React40.useRef([]);
|
|
8550
|
+
const busyRef = React40.useRef(false);
|
|
8551
|
+
const stoppedRef = React40.useRef(false);
|
|
8552
|
+
const abortRef = React40.useRef(null);
|
|
8553
|
+
const serverCount = React40.useRef(0);
|
|
8554
|
+
const threadRef = React40.useRef(null);
|
|
8555
|
+
const mounted = React40.useRef(true);
|
|
8556
|
+
React40.useEffect(() => {
|
|
8585
8557
|
mounted.current = true;
|
|
8586
8558
|
return () => {
|
|
8587
8559
|
mounted.current = false;
|
|
@@ -8603,14 +8575,14 @@ function useChatEngine(opts) {
|
|
|
8603
8575
|
}
|
|
8604
8576
|
return false;
|
|
8605
8577
|
};
|
|
8606
|
-
const loadThread =
|
|
8578
|
+
const loadThread = React40.useCallback(async (id) => {
|
|
8607
8579
|
const data = await apiAdapter.getThread(id);
|
|
8608
8580
|
const list = [...data && data.messages || []];
|
|
8609
8581
|
serverCount.current = list.length;
|
|
8610
8582
|
commit(list);
|
|
8611
8583
|
return list;
|
|
8612
8584
|
}, [apiAdapter]);
|
|
8613
|
-
|
|
8585
|
+
React40.useEffect(() => {
|
|
8614
8586
|
if (!apiAdapter) {
|
|
8615
8587
|
setStatus("idle");
|
|
8616
8588
|
setFatal(null);
|
|
@@ -8823,7 +8795,7 @@ function useChatEngine(opts) {
|
|
|
8823
8795
|
await dispatchTurn(turn);
|
|
8824
8796
|
}
|
|
8825
8797
|
}
|
|
8826
|
-
const send =
|
|
8798
|
+
const send = React40.useCallback((text, attachments) => {
|
|
8827
8799
|
const body = (text || "").trim();
|
|
8828
8800
|
if (!body && !(attachments && attachments.length)) return;
|
|
8829
8801
|
if (status === "disconnected") return;
|
|
@@ -8833,7 +8805,7 @@ function useChatEngine(opts) {
|
|
|
8833
8805
|
stoppedRef.current = false;
|
|
8834
8806
|
drain();
|
|
8835
8807
|
}, [status]);
|
|
8836
|
-
const stop =
|
|
8808
|
+
const stop = React40.useCallback(() => {
|
|
8837
8809
|
stoppedRef.current = true;
|
|
8838
8810
|
const ac = abortRef.current;
|
|
8839
8811
|
if (ac) {
|
|
@@ -8852,11 +8824,11 @@ function useChatEngine(opts) {
|
|
|
8852
8824
|
store.del(STORAGE_PREFIX + threadRef.current);
|
|
8853
8825
|
}
|
|
8854
8826
|
}, [apiAdapter]);
|
|
8855
|
-
const removeQueued =
|
|
8827
|
+
const removeQueued = React40.useCallback((id) => {
|
|
8856
8828
|
queueRef.current = queueRef.current.filter((t) => t.id !== id);
|
|
8857
8829
|
setQueue(queueRef.current.slice());
|
|
8858
8830
|
}, []);
|
|
8859
|
-
const retry =
|
|
8831
|
+
const retry = React40.useCallback(() => {
|
|
8860
8832
|
const list = listRef.current;
|
|
8861
8833
|
let at = -1;
|
|
8862
8834
|
for (let i = list.length - 1; i >= 0; i--) if (list[i].role === "user") {
|
|
@@ -8872,19 +8844,19 @@ function useChatEngine(opts) {
|
|
|
8872
8844
|
setQueue(queueRef.current.slice());
|
|
8873
8845
|
drain();
|
|
8874
8846
|
}, []);
|
|
8875
|
-
const clear =
|
|
8847
|
+
const clear = React40.useCallback(() => {
|
|
8876
8848
|
commit([]);
|
|
8877
8849
|
serverCount.current = 0;
|
|
8878
8850
|
queueRef.current = [];
|
|
8879
8851
|
setQueue([]);
|
|
8880
8852
|
onClear && onClear();
|
|
8881
8853
|
}, [onClear]);
|
|
8882
|
-
const setFeedback =
|
|
8854
|
+
const setFeedback = React40.useCallback((id, value) => {
|
|
8883
8855
|
patch(id, (m) => ({ feedback: m.feedback === value ? null : value }));
|
|
8884
8856
|
const msg = listRef.current.find((m) => m.id === id);
|
|
8885
8857
|
onFeedback && onFeedback({ message: msg, feedback: msg ? msg.feedback : value });
|
|
8886
8858
|
}, [onFeedback]);
|
|
8887
|
-
const reload =
|
|
8859
|
+
const reload = React40.useCallback(async () => {
|
|
8888
8860
|
if (!threadRef.current) return;
|
|
8889
8861
|
setStatus("loading");
|
|
8890
8862
|
try {
|
|
@@ -8922,10 +8894,10 @@ var ChatKit = {
|
|
|
8922
8894
|
};
|
|
8923
8895
|
|
|
8924
8896
|
// src/components/chat/ChatTranscript.tsx
|
|
8925
|
-
import * as
|
|
8897
|
+
import * as React42 from "react";
|
|
8926
8898
|
|
|
8927
8899
|
// src/components/chat/ChatTurn.tsx
|
|
8928
|
-
import * as
|
|
8900
|
+
import * as React41 from "react";
|
|
8929
8901
|
import { jsx as jsx72, jsxs as jsxs67 } from "react/jsx-runtime";
|
|
8930
8902
|
function JsonView({ value }) {
|
|
8931
8903
|
let text;
|
|
@@ -8962,7 +8934,7 @@ function PacketCard({ packet, schema, render, onApply, applied }) {
|
|
|
8962
8934
|
] });
|
|
8963
8935
|
}
|
|
8964
8936
|
function ThinkingBlock({ text, durationMs, streaming, defaultOpen = false }) {
|
|
8965
|
-
const [open, setOpen] =
|
|
8937
|
+
const [open, setOpen] = React41.useState(defaultOpen);
|
|
8966
8938
|
if (!text) return null;
|
|
8967
8939
|
return /* @__PURE__ */ jsxs67("div", { className: "fdc-think" + (open ? " is-open" : ""), children: [
|
|
8968
8940
|
/* @__PURE__ */ jsxs67("button", { type: "button", className: "fdc-think-head", onClick: () => setOpen((v) => !v), "aria-expanded": open, children: [
|
|
@@ -8979,7 +8951,7 @@ function ThinkingBlock({ text, durationMs, streaming, defaultOpen = false }) {
|
|
|
8979
8951
|
] });
|
|
8980
8952
|
}
|
|
8981
8953
|
function Citations({ items = [], onOpen }) {
|
|
8982
|
-
const [open, setOpen] =
|
|
8954
|
+
const [open, setOpen] = React41.useState(false);
|
|
8983
8955
|
if (!items.length) return null;
|
|
8984
8956
|
return /* @__PURE__ */ jsxs67("div", { className: "fdc-cites", children: [
|
|
8985
8957
|
/* @__PURE__ */ jsxs67("button", { type: "button", className: "fdc-cites-head", onClick: () => setOpen((v) => !v), "aria-expanded": open, children: [
|
|
@@ -9005,7 +8977,7 @@ function clampText(text, max) {
|
|
|
9005
8977
|
return (at > max * 0.6 ? cut.slice(0, at) : cut).trimEnd() + "\u2026";
|
|
9006
8978
|
}
|
|
9007
8979
|
function MessageBody({ message: m, ctx }) {
|
|
9008
|
-
const [expanded, setExpanded] =
|
|
8980
|
+
const [expanded, setExpanded] = React41.useState(false);
|
|
9009
8981
|
const isUser = m.role === "user";
|
|
9010
8982
|
const raw = m.text || "";
|
|
9011
8983
|
const clamped = !expanded && !m.streaming ? clampText(raw, ctx.maxVisibleChars) : null;
|
|
@@ -9072,9 +9044,9 @@ function MessageBody({ message: m, ctx }) {
|
|
|
9072
9044
|
] });
|
|
9073
9045
|
}
|
|
9074
9046
|
function useCopyRun() {
|
|
9075
|
-
const [done, setDone] =
|
|
9076
|
-
const t =
|
|
9077
|
-
|
|
9047
|
+
const [done, setDone] = React41.useState(false);
|
|
9048
|
+
const t = React41.useRef(null);
|
|
9049
|
+
React41.useEffect(() => () => {
|
|
9078
9050
|
if (t.current) clearTimeout(t.current);
|
|
9079
9051
|
}, []);
|
|
9080
9052
|
return [done, (text) => {
|
|
@@ -9101,7 +9073,7 @@ function RunActions({ group, ctx }) {
|
|
|
9101
9073
|
] }),
|
|
9102
9074
|
isAssistant && ctx.onRetry ? /* @__PURE__ */ jsx72("button", { type: "button", className: "fdc-act", onClick: ctx.onRetry, "aria-label": "Retry this turn", children: /* @__PURE__ */ jsx72("i", { className: "ph ph-arrow-clockwise", "aria-hidden": "true" }) }) : null,
|
|
9103
9075
|
group.role === "user" && ctx.onEdit ? /* @__PURE__ */ jsx72("button", { type: "button", className: "fdc-act", onClick: () => ctx.onEdit(last), "aria-label": "Edit and resend", children: /* @__PURE__ */ jsx72("i", { className: "ph ph-pencil-simple", "aria-hidden": "true" }) }) : null,
|
|
9104
|
-
isAssistant && ctx.onFeedback ? /* @__PURE__ */ jsxs67(
|
|
9076
|
+
isAssistant && ctx.onFeedback ? /* @__PURE__ */ jsxs67(React41.Fragment, { children: [
|
|
9105
9077
|
/* @__PURE__ */ jsx72("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__ */ jsx72("i", { className: "ph ph-thumbs-up", "aria-hidden": "true" }) }),
|
|
9106
9078
|
/* @__PURE__ */ jsx72("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__ */ jsx72("i", { className: "ph ph-thumbs-down", "aria-hidden": "true" }) })
|
|
9107
9079
|
] }) : null,
|
|
@@ -9196,10 +9168,10 @@ function ChatTranscript({
|
|
|
9196
9168
|
renderEmpty,
|
|
9197
9169
|
className = ""
|
|
9198
9170
|
}) {
|
|
9199
|
-
const scroller =
|
|
9200
|
-
const stick =
|
|
9201
|
-
const [pill, setPill] =
|
|
9202
|
-
const seen =
|
|
9171
|
+
const scroller = React42.useRef(null);
|
|
9172
|
+
const stick = React42.useRef(true);
|
|
9173
|
+
const [pill, setPill] = React42.useState(0);
|
|
9174
|
+
const seen = React42.useRef(0);
|
|
9203
9175
|
const toBottom = (smooth) => {
|
|
9204
9176
|
const el = scroller.current;
|
|
9205
9177
|
if (!el) return;
|
|
@@ -9218,7 +9190,7 @@ function ChatTranscript({
|
|
|
9218
9190
|
seen.current = messages.length;
|
|
9219
9191
|
}
|
|
9220
9192
|
};
|
|
9221
|
-
|
|
9193
|
+
React42.useLayoutEffect(() => {
|
|
9222
9194
|
const el = scroller.current;
|
|
9223
9195
|
if (!el) return;
|
|
9224
9196
|
if (stick.current) {
|
|
@@ -9226,7 +9198,7 @@ function ChatTranscript({
|
|
|
9226
9198
|
seen.current = messages.length;
|
|
9227
9199
|
} else setPill(Math.max(0, messages.length - seen.current));
|
|
9228
9200
|
}, [messages]);
|
|
9229
|
-
|
|
9201
|
+
React42.useEffect(() => {
|
|
9230
9202
|
const el = scroller.current;
|
|
9231
9203
|
const inner = el && el.firstChild;
|
|
9232
9204
|
if (!el || !inner || typeof ResizeObserver === "undefined") return;
|
|
@@ -9236,7 +9208,7 @@ function ChatTranscript({
|
|
|
9236
9208
|
ro.observe(inner);
|
|
9237
9209
|
return () => ro.disconnect();
|
|
9238
9210
|
}, []);
|
|
9239
|
-
const groups =
|
|
9211
|
+
const groups = React42.useMemo(() => groupMessages(messages), [messages]);
|
|
9240
9212
|
const empty = !messages.length && status === "ready";
|
|
9241
9213
|
return /* @__PURE__ */ jsxs68("div", { className: ["fdc-scroll", className].filter(Boolean).join(" "), ref: scroller, onScroll, children: [
|
|
9242
9214
|
/* @__PURE__ */ jsxs68("div", { className: "fdc-log", role: "log", "aria-label": "Conversation", children: [
|
|
@@ -9260,7 +9232,7 @@ function ChatTranscript({
|
|
|
9260
9232
|
const prev = groups[i - 1];
|
|
9261
9233
|
const k = dayKey(g.messages[0].timestamp);
|
|
9262
9234
|
const showDay = !!k && (!prev || dayKey(prev.messages[0].timestamp) !== k);
|
|
9263
|
-
return /* @__PURE__ */ jsxs68(
|
|
9235
|
+
return /* @__PURE__ */ jsxs68(React42.Fragment, { children: [
|
|
9264
9236
|
showDay ? /* @__PURE__ */ jsx73("div", { className: "fdc-day", children: /* @__PURE__ */ jsx73("span", { children: dayLabel(k) }) }) : null,
|
|
9265
9237
|
/* @__PURE__ */ jsx73(ChatTurn, { group: g, ctx })
|
|
9266
9238
|
] }, g.key || i);
|
|
@@ -9277,7 +9249,7 @@ function ChatTranscript({
|
|
|
9277
9249
|
var TranscriptKit = { groupMessages };
|
|
9278
9250
|
|
|
9279
9251
|
// src/components/chat/ChatComposer.tsx
|
|
9280
|
-
import * as
|
|
9252
|
+
import * as React43 from "react";
|
|
9281
9253
|
import { jsx as jsx74, jsxs as jsxs69 } from "react/jsx-runtime";
|
|
9282
9254
|
function ChatComposer({
|
|
9283
9255
|
onSubmit,
|
|
@@ -9305,17 +9277,17 @@ function ChatComposer({
|
|
|
9305
9277
|
onReject,
|
|
9306
9278
|
onOpenAttachment
|
|
9307
9279
|
}) {
|
|
9308
|
-
const [text, setText] =
|
|
9309
|
-
const [trigger, setTrigger] =
|
|
9310
|
-
const [mentionItems, setMentionItems] =
|
|
9311
|
-
const [listening, setListening] =
|
|
9312
|
-
const [notice, setNotice] =
|
|
9313
|
-
const editor =
|
|
9314
|
-
const wrap =
|
|
9315
|
-
const stopVoice =
|
|
9280
|
+
const [text, setText] = React43.useState(draft || "");
|
|
9281
|
+
const [trigger, setTrigger] = React43.useState(null);
|
|
9282
|
+
const [mentionItems, setMentionItems] = React43.useState([]);
|
|
9283
|
+
const [listening, setListening] = React43.useState(false);
|
|
9284
|
+
const [notice, setNotice] = React43.useState(null);
|
|
9285
|
+
const editor = React43.useRef(null);
|
|
9286
|
+
const wrap = React43.useRef(null);
|
|
9287
|
+
const stopVoice = React43.useRef(null);
|
|
9316
9288
|
const staged = useStagedFiles(fileUploadHandler, { onError: () => {
|
|
9317
9289
|
} });
|
|
9318
|
-
|
|
9290
|
+
React43.useEffect(() => {
|
|
9319
9291
|
if (draft != null && draft !== text) setText(draft);
|
|
9320
9292
|
}, [draft]);
|
|
9321
9293
|
const change = (v) => {
|
|
@@ -9349,7 +9321,7 @@ function ChatComposer({
|
|
|
9349
9321
|
e.preventDefault();
|
|
9350
9322
|
staged.add(found.files);
|
|
9351
9323
|
};
|
|
9352
|
-
|
|
9324
|
+
React43.useEffect(() => {
|
|
9353
9325
|
if (!trigger || trigger.type !== "mention" || !mentionSources) {
|
|
9354
9326
|
setMentionItems([]);
|
|
9355
9327
|
return;
|
|
@@ -9367,7 +9339,7 @@ function ChatComposer({
|
|
|
9367
9339
|
const q = (trigger.query || "").toLowerCase();
|
|
9368
9340
|
setMentionItems(mentionSources.filter((m) => !q || (m.label + " " + (m.description || "")).toLowerCase().includes(q)));
|
|
9369
9341
|
}, [trigger, mentionSources]);
|
|
9370
|
-
const slashItems =
|
|
9342
|
+
const slashItems = React43.useMemo(() => {
|
|
9371
9343
|
if (!trigger || trigger.type !== "slash" || !slashCommands) return [];
|
|
9372
9344
|
const q = (trigger.query || "").toLowerCase();
|
|
9373
9345
|
return slashCommands.filter((c) => !q || (c.id + " " + c.label + " " + (c.description || "")).toLowerCase().includes(q));
|
|
@@ -9541,12 +9513,12 @@ function ChatComposer({
|
|
|
9541
9513
|
}
|
|
9542
9514
|
|
|
9543
9515
|
// src/components/chat/ChatSessionBar.tsx
|
|
9544
|
-
import * as
|
|
9516
|
+
import * as React44 from "react";
|
|
9545
9517
|
import { jsx as jsx75, jsxs as jsxs70 } from "react/jsx-runtime";
|
|
9546
9518
|
var compact2 = meterFormats.compact;
|
|
9547
9519
|
function ChatSessionBar({ sessionStats, contextUsage, usageLimits, onClear, extras }) {
|
|
9548
|
-
const [open, setOpen] =
|
|
9549
|
-
const anchor =
|
|
9520
|
+
const [open, setOpen] = React44.useState(false);
|
|
9521
|
+
const anchor = React44.useRef(null);
|
|
9550
9522
|
const stats = sessionStats || null;
|
|
9551
9523
|
const cu = contextUsage || null;
|
|
9552
9524
|
const limits = usageLimits || null;
|
|
@@ -9561,7 +9533,7 @@ function ChatSessionBar({ sessionStats, contextUsage, usageLimits, onClear, extr
|
|
|
9561
9533
|
if (stats && stats.runningTasks) bits.push(stats.runningTasks + " running task" + (stats.runningTasks === 1 ? "" : "s"));
|
|
9562
9534
|
if (cu) bits.push(pct + "% context");
|
|
9563
9535
|
const expandable = !!(cu || limits);
|
|
9564
|
-
return /* @__PURE__ */ jsxs70(
|
|
9536
|
+
return /* @__PURE__ */ jsxs70(React44.Fragment, { children: [
|
|
9565
9537
|
/* @__PURE__ */ jsxs70("div", { className: "fdc-bar", children: [
|
|
9566
9538
|
/* @__PURE__ */ jsxs70(
|
|
9567
9539
|
"button",
|
|
@@ -9582,60 +9554,73 @@ function ChatSessionBar({ sessionStats, contextUsage, usageLimits, onClear, extr
|
|
|
9582
9554
|
),
|
|
9583
9555
|
extras
|
|
9584
9556
|
] }),
|
|
9585
|
-
/* @__PURE__ */ jsx75(
|
|
9586
|
-
|
|
9587
|
-
|
|
9588
|
-
|
|
9589
|
-
|
|
9590
|
-
|
|
9591
|
-
|
|
9592
|
-
|
|
9593
|
-
|
|
9594
|
-
|
|
9595
|
-
|
|
9596
|
-
|
|
9597
|
-
|
|
9598
|
-
|
|
9599
|
-
|
|
9600
|
-
|
|
9601
|
-
|
|
9602
|
-
|
|
9603
|
-
|
|
9604
|
-
|
|
9605
|
-
|
|
9606
|
-
|
|
9607
|
-
|
|
9608
|
-
|
|
9609
|
-
|
|
9610
|
-
|
|
9611
|
-
|
|
9612
|
-
|
|
9613
|
-
|
|
9614
|
-
|
|
9615
|
-
|
|
9616
|
-
/* @__PURE__ */
|
|
9617
|
-
|
|
9618
|
-
|
|
9619
|
-
|
|
9620
|
-
|
|
9621
|
-
|
|
9622
|
-
|
|
9623
|
-
|
|
9624
|
-
|
|
9625
|
-
|
|
9626
|
-
|
|
9627
|
-
|
|
9628
|
-
/* @__PURE__ */
|
|
9629
|
-
|
|
9630
|
-
|
|
9631
|
-
|
|
9632
|
-
|
|
9633
|
-
|
|
9634
|
-
|
|
9635
|
-
|
|
9636
|
-
|
|
9637
|
-
|
|
9638
|
-
|
|
9557
|
+
/* @__PURE__ */ jsx75(
|
|
9558
|
+
Popover,
|
|
9559
|
+
{
|
|
9560
|
+
open,
|
|
9561
|
+
anchorRef: anchor,
|
|
9562
|
+
placement: "top-start",
|
|
9563
|
+
onClose: () => setOpen(false),
|
|
9564
|
+
minWidth: 330,
|
|
9565
|
+
maxHeight: 460,
|
|
9566
|
+
padded: true,
|
|
9567
|
+
label: "Usage",
|
|
9568
|
+
footer: onClear ? /* @__PURE__ */ jsxs70("button", { type: "button", className: "fdc-usage-clear", onClick: () => {
|
|
9569
|
+
setOpen(false);
|
|
9570
|
+
onClear();
|
|
9571
|
+
}, children: [
|
|
9572
|
+
/* @__PURE__ */ jsx75("i", { className: "ph ph-trash", "aria-hidden": "true" }),
|
|
9573
|
+
"Clear conversation"
|
|
9574
|
+
] }) : void 0,
|
|
9575
|
+
children: /* @__PURE__ */ jsxs70("div", { className: "fdc-usage", children: [
|
|
9576
|
+
cu ? /* @__PURE__ */ jsx75("section", { className: "fdc-usage-sec", children: /* @__PURE__ */ jsx75(
|
|
9577
|
+
SegmentedMeter,
|
|
9578
|
+
{
|
|
9579
|
+
total,
|
|
9580
|
+
segments: cu.segments,
|
|
9581
|
+
label: cu.label || "Context window",
|
|
9582
|
+
format: cu.format === "bytes" ? meterFormats.bytes : compact2,
|
|
9583
|
+
height: 8,
|
|
9584
|
+
legend: true,
|
|
9585
|
+
remainderLabel: "Free"
|
|
9586
|
+
}
|
|
9587
|
+
) }) : null,
|
|
9588
|
+
limits && limits.length ? /* @__PURE__ */ jsxs70("section", { className: "fdc-usage-sec", children: [
|
|
9589
|
+
/* @__PURE__ */ jsx75("h4", { className: "fdc-usage-h", children: "Usage limits" }),
|
|
9590
|
+
/* @__PURE__ */ jsx75("div", { className: "fdc-usage-rows", children: limits.map((l) => /* @__PURE__ */ jsx75(
|
|
9591
|
+
QuotaRow,
|
|
9592
|
+
{
|
|
9593
|
+
label: l.label,
|
|
9594
|
+
percent: l.percent,
|
|
9595
|
+
note: l.resetsAt ? "Resets " + formatRelative(l.resetsAt) : l.note
|
|
9596
|
+
},
|
|
9597
|
+
l.id
|
|
9598
|
+
)) })
|
|
9599
|
+
] }) : null,
|
|
9600
|
+
stats ? /* @__PURE__ */ jsxs70("section", { className: "fdc-usage-sec fdc-usage-stats", children: [
|
|
9601
|
+
stats.elapsedMs ? /* @__PURE__ */ jsxs70("div", { children: [
|
|
9602
|
+
/* @__PURE__ */ jsx75("span", { children: "Session" }),
|
|
9603
|
+
/* @__PURE__ */ jsx75("b", { className: "fd-tabular", children: formatDuration(stats.elapsedMs) })
|
|
9604
|
+
] }) : null,
|
|
9605
|
+
stats.tokens ? /* @__PURE__ */ jsxs70("div", { children: [
|
|
9606
|
+
/* @__PURE__ */ jsx75("span", { children: "Tokens" }),
|
|
9607
|
+
/* @__PURE__ */ jsx75("b", { className: "fd-tabular", children: stats.tokens.toLocaleString() })
|
|
9608
|
+
] }) : null,
|
|
9609
|
+
stats.costUsd != null ? /* @__PURE__ */ jsxs70("div", { children: [
|
|
9610
|
+
/* @__PURE__ */ jsx75("span", { children: "Cost" }),
|
|
9611
|
+
/* @__PURE__ */ jsxs70("b", { className: "fd-tabular", children: [
|
|
9612
|
+
"$",
|
|
9613
|
+
Number(stats.costUsd).toFixed(3)
|
|
9614
|
+
] })
|
|
9615
|
+
] }) : null,
|
|
9616
|
+
stats.turns ? /* @__PURE__ */ jsxs70("div", { children: [
|
|
9617
|
+
/* @__PURE__ */ jsx75("span", { children: "Turns" }),
|
|
9618
|
+
/* @__PURE__ */ jsx75("b", { className: "fd-tabular", children: stats.turns })
|
|
9619
|
+
] }) : null
|
|
9620
|
+
] }) : null
|
|
9621
|
+
] })
|
|
9622
|
+
}
|
|
9623
|
+
)
|
|
9639
9624
|
] });
|
|
9640
9625
|
}
|
|
9641
9626
|
function ModelControls({
|
|
@@ -9689,7 +9674,7 @@ function ModelControls({
|
|
|
9689
9674
|
] })
|
|
9690
9675
|
});
|
|
9691
9676
|
}
|
|
9692
|
-
return /* @__PURE__ */ jsxs70(
|
|
9677
|
+
return /* @__PURE__ */ jsxs70(React44.Fragment, { children: [
|
|
9693
9678
|
/* @__PURE__ */ jsx75(
|
|
9694
9679
|
MenuButton,
|
|
9695
9680
|
{
|
|
@@ -9806,11 +9791,11 @@ function AgentChatPanel({
|
|
|
9806
9791
|
onFeedback,
|
|
9807
9792
|
onEditMessage
|
|
9808
9793
|
}) {
|
|
9809
|
-
const [panelWidth, setPanelWidth] =
|
|
9810
|
-
const [applied, setApplied] =
|
|
9811
|
-
const [draft, setDraft] =
|
|
9812
|
-
const dragging =
|
|
9813
|
-
|
|
9794
|
+
const [panelWidth, setPanelWidth] = React45.useState(width);
|
|
9795
|
+
const [applied, setApplied] = React45.useState({});
|
|
9796
|
+
const [draft, setDraft] = React45.useState("");
|
|
9797
|
+
const dragging = React45.useRef(null);
|
|
9798
|
+
React45.useEffect(() => setPanelWidth(width), [width]);
|
|
9814
9799
|
const engine = useChatEngine({
|
|
9815
9800
|
contextType,
|
|
9816
9801
|
contextId,
|
|
@@ -10014,7 +9999,7 @@ function AgentChatPanel({
|
|
|
10014
9999
|
}
|
|
10015
10000
|
|
|
10016
10001
|
// src/kits/query.ts
|
|
10017
|
-
import * as
|
|
10002
|
+
import * as React46 from "react";
|
|
10018
10003
|
function eqFilter(get2) {
|
|
10019
10004
|
return (row, value) => Array.isArray(value) ? value.includes(get2(row)) : get2(row) === value;
|
|
10020
10005
|
}
|
|
@@ -10046,22 +10031,22 @@ function compare(a, b, dir) {
|
|
|
10046
10031
|
var API = null;
|
|
10047
10032
|
var PREFS = null;
|
|
10048
10033
|
function useServerTable({ endpoint, params, defaults, deps, prefsKey }) {
|
|
10049
|
-
const [query, setQuery] =
|
|
10034
|
+
const [query, setQuery] = React46.useState(() => {
|
|
10050
10035
|
const store = PREFS || window.PlannerPrefs;
|
|
10051
10036
|
const saved = prefsKey && store ? store.getTable(prefsKey) : {};
|
|
10052
10037
|
return { ...DEFAULTS, ...defaults || {}, ...saved.pageSize ? { pageSize: saved.pageSize } : {}, ...saved.sort ? { sort: saved.sort, dir: saved.dir || "desc" } : {} };
|
|
10053
10038
|
});
|
|
10054
|
-
const savePref =
|
|
10039
|
+
const savePref = React46.useCallback((patch2) => {
|
|
10055
10040
|
const store = PREFS || window.PlannerPrefs;
|
|
10056
10041
|
if (prefsKey && store) store.setTable(prefsKey, patch2);
|
|
10057
10042
|
}, [prefsKey]);
|
|
10058
|
-
const [res, setRes] =
|
|
10059
|
-
const [loading, setLoading] =
|
|
10060
|
-
const seq2 =
|
|
10043
|
+
const [res, setRes] = React46.useState(null);
|
|
10044
|
+
const [loading, setLoading] = React46.useState(true);
|
|
10045
|
+
const seq2 = React46.useRef(0);
|
|
10061
10046
|
const depKey = (deps || []).join("|");
|
|
10062
10047
|
const paramKey = JSON.stringify(params || {});
|
|
10063
10048
|
const queryKey = JSON.stringify(query);
|
|
10064
|
-
|
|
10049
|
+
React46.useEffect(() => {
|
|
10065
10050
|
const id = ++seq2.current;
|
|
10066
10051
|
setLoading(true);
|
|
10067
10052
|
const t = setTimeout(() => {
|