@flytedan/flytebot-design-system 0.10.0 → 0.11.1
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 +665 -658
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +120 -13
- package/dist/index.d.ts +120 -13
- package/dist/index.js +674 -668
- 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,23 @@ 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
|
+
var PINNED_REGIONS = ":scope > .fd-pop-header, :scope > .fd-pop-footer";
|
|
92
|
+
var POPOVER_BODY_MIN = 96;
|
|
93
|
+
function measureLayer(el) {
|
|
94
|
+
if (!el || !el.offsetHeight) return { width: el ? el.offsetWidth : 0, height: 0, pinned: 0 };
|
|
95
|
+
let hidden = 0;
|
|
96
|
+
el.querySelectorAll(SCROLL_REGIONS).forEach((r) => {
|
|
97
|
+
hidden += Math.max(0, r.scrollHeight - r.clientHeight);
|
|
98
|
+
});
|
|
99
|
+
let pinned = 0;
|
|
100
|
+
el.querySelectorAll(PINNED_REGIONS).forEach((r) => {
|
|
101
|
+
pinned += r.offsetHeight;
|
|
102
|
+
});
|
|
103
|
+
const border = Math.max(0, el.offsetHeight - el.clientHeight);
|
|
104
|
+
const content = Math.max(el.scrollHeight, el.clientHeight);
|
|
105
|
+
return { width: el.offsetWidth, height: content + border + hidden, pinned: pinned + border };
|
|
106
|
+
}
|
|
88
107
|
function usePopoverPosition(open, anchorRef, opts) {
|
|
89
108
|
const o = opts || {};
|
|
90
109
|
const { side: wantSide, align } = parsePlacement(o.placement);
|
|
@@ -92,6 +111,7 @@ function usePopoverPosition(open, anchorRef, opts) {
|
|
|
92
111
|
const posRef = React.useRef(null);
|
|
93
112
|
const detachRef = React.useRef(o.onDetach);
|
|
94
113
|
detachRef.current = o.onDetach;
|
|
114
|
+
const layerRef = o.layerRef;
|
|
95
115
|
React.useLayoutEffect(() => {
|
|
96
116
|
if (!open || !anchorRef || !anchorRef.current) {
|
|
97
117
|
posRef.current = null;
|
|
@@ -103,23 +123,36 @@ function usePopoverPosition(open, anchorRef, opts) {
|
|
|
103
123
|
if (!el) return;
|
|
104
124
|
const r = el.getBoundingClientRect();
|
|
105
125
|
const offset = o.offset == null ? 8 : o.offset;
|
|
106
|
-
const
|
|
107
|
-
const
|
|
126
|
+
const layer = measureLayer(layerRef ? layerRef.current : null);
|
|
127
|
+
const vh = window.innerHeight;
|
|
128
|
+
const need = layer.height || Math.min(o.estHeight || 300, 180);
|
|
129
|
+
const below = vh - r.bottom - offset - MARGIN;
|
|
108
130
|
const above = r.top - offset - MARGIN;
|
|
109
131
|
let side = wantSide;
|
|
110
|
-
if (side === "bottom" && below <
|
|
111
|
-
else if (side === "top" && above <
|
|
112
|
-
const
|
|
113
|
-
const
|
|
132
|
+
if (side === "bottom" && below < need && above > below) side = "top";
|
|
133
|
+
else if (side === "top" && above < need && below > above) side = "bottom";
|
|
134
|
+
const ceiling = Math.min(vh - 2 * MARGIN, o.maxHeight != null ? o.maxHeight : Infinity);
|
|
135
|
+
const floor = Math.min(
|
|
136
|
+
ceiling,
|
|
137
|
+
layer.height ? layer.pinned + Math.min(POPOVER_BODY_MIN, layer.height - layer.pinned) : Math.min(need, 140)
|
|
138
|
+
);
|
|
139
|
+
const room = side === "top" ? above : below;
|
|
140
|
+
const beside = room >= floor;
|
|
141
|
+
const edge = beside ? 0 : Math.max(MARGIN, vh - MARGIN - Math.min(need, ceiling));
|
|
142
|
+
const top = side === "bottom" ? beside ? r.bottom + offset : edge : null;
|
|
143
|
+
const bottom = side === "top" ? beside ? vh - r.top + offset : edge : null;
|
|
144
|
+
const maxH = beside ? room : vh - MARGIN - edge;
|
|
145
|
+
const exact = o.matchWidth === true;
|
|
146
|
+
const width = exact ? r.width : Math.max(o.width || 0, o.minWidth || 0, o.matchWidth === "min" ? r.width : 0);
|
|
147
|
+
const w = exact || o.width ? width : Math.max(layer.width, width) || o.estWidth || 260;
|
|
114
148
|
let left = align === "end" ? r.right - w : align === "center" ? r.left + r.width / 2 - w / 2 : r.left;
|
|
115
149
|
left = Math.max(MARGIN, Math.min(left, window.innerWidth - w - MARGIN));
|
|
116
|
-
const maxH = Math.max(140, side === "top" ? above : below);
|
|
117
150
|
const next = {
|
|
118
151
|
left,
|
|
119
|
-
width:
|
|
152
|
+
width: exact ? r.width : void 0,
|
|
120
153
|
minWidth: o.minWidth,
|
|
121
|
-
top
|
|
122
|
-
bottom
|
|
154
|
+
top,
|
|
155
|
+
bottom,
|
|
123
156
|
maxH,
|
|
124
157
|
side,
|
|
125
158
|
anchorWidth: r.width
|
|
@@ -142,7 +175,7 @@ function usePopoverPosition(open, anchorRef, opts) {
|
|
|
142
175
|
};
|
|
143
176
|
raf = requestAnimationFrame(tick);
|
|
144
177
|
return () => cancelAnimationFrame(raf);
|
|
145
|
-
}, [open, o.placement, o.offset, o.matchWidth, o.width, o.minWidth, o.estHeight]);
|
|
178
|
+
}, [open, o.placement, o.offset, o.matchWidth, o.width, o.minWidth, o.maxHeight, o.estHeight]);
|
|
146
179
|
return pos;
|
|
147
180
|
}
|
|
148
181
|
var portal = (node) => {
|
|
@@ -152,6 +185,7 @@ var portal = (node) => {
|
|
|
152
185
|
function Popover({
|
|
153
186
|
open,
|
|
154
187
|
anchorRef,
|
|
188
|
+
triggerRef,
|
|
155
189
|
onClose,
|
|
156
190
|
placement = "bottom-start",
|
|
157
191
|
offset = 8,
|
|
@@ -167,6 +201,8 @@ function Popover({
|
|
|
167
201
|
returnFocus = true,
|
|
168
202
|
className = "",
|
|
169
203
|
style,
|
|
204
|
+
header,
|
|
205
|
+
footer,
|
|
170
206
|
children
|
|
171
207
|
}) {
|
|
172
208
|
const ref = React.useRef(null);
|
|
@@ -176,8 +212,10 @@ function Popover({
|
|
|
176
212
|
matchWidth,
|
|
177
213
|
width,
|
|
178
214
|
minWidth,
|
|
215
|
+
maxHeight,
|
|
179
216
|
estHeight: maxHeight || 320,
|
|
180
|
-
onDetach: onClose
|
|
217
|
+
onDetach: onClose,
|
|
218
|
+
layerRef: ref
|
|
181
219
|
});
|
|
182
220
|
const restore = React.useRef(null);
|
|
183
221
|
React.useEffect(() => {
|
|
@@ -198,7 +236,8 @@ function Popover({
|
|
|
198
236
|
if (!closeOnOutside) return;
|
|
199
237
|
const target = e.target;
|
|
200
238
|
if (ref.current && ref.current.contains(target)) return;
|
|
201
|
-
|
|
239
|
+
const trigger = (triggerRef || anchorRef).current;
|
|
240
|
+
if (trigger && trigger.contains(target)) return;
|
|
202
241
|
if (e.target.closest && e.target.closest(".fd-pop")) return;
|
|
203
242
|
onClose && onClose();
|
|
204
243
|
};
|
|
@@ -214,23 +253,23 @@ function Popover({
|
|
|
214
253
|
document.removeEventListener("pointerdown", away, true);
|
|
215
254
|
document.removeEventListener("keydown", key);
|
|
216
255
|
};
|
|
217
|
-
}, [open, closeOnOutside, closeOnEscape, onClose, anchorRef]);
|
|
256
|
+
}, [open, closeOnOutside, closeOnEscape, onClose, anchorRef, triggerRef]);
|
|
218
257
|
if (!open || !pos) return null;
|
|
219
258
|
return portal(
|
|
220
|
-
/* @__PURE__ */
|
|
259
|
+
/* @__PURE__ */ jsxs2(
|
|
221
260
|
"div",
|
|
222
261
|
{
|
|
223
262
|
ref,
|
|
224
263
|
role,
|
|
225
264
|
"aria-label": label,
|
|
226
|
-
className: ["fd-pop", pos.side === "top" ? "is-up" : "",
|
|
265
|
+
className: ["fd-pop", pos.side === "top" ? "is-up" : "", className].filter(Boolean).join(" "),
|
|
227
266
|
style: {
|
|
228
267
|
position: "fixed",
|
|
229
268
|
left: pos.left,
|
|
230
269
|
top: pos.top == null ? "auto" : pos.top,
|
|
231
270
|
bottom: pos.bottom == null ? "auto" : pos.bottom,
|
|
232
|
-
width: matchWidth ? pos.width : width,
|
|
233
|
-
minWidth: minWidth || (matchWidth ? void 0 : 200),
|
|
271
|
+
width: matchWidth === true ? pos.width : width,
|
|
272
|
+
minWidth: matchWidth === "min" ? Math.max(pos.anchorWidth, minWidth || 0) : minWidth || (matchWidth ? void 0 : 200),
|
|
234
273
|
// Size to content by default — cap only at real available room between the
|
|
235
274
|
// anchor and the viewport edge (pos.maxH, computed by usePopoverPosition).
|
|
236
275
|
// A caller-supplied `maxHeight` narrows that further (e.g. a long menu that
|
|
@@ -243,7 +282,11 @@ function Popover({
|
|
|
243
282
|
zIndex: 140,
|
|
244
283
|
...style
|
|
245
284
|
},
|
|
246
|
-
children
|
|
285
|
+
children: [
|
|
286
|
+
header != null ? /* @__PURE__ */ jsx3("div", { className: "fd-pop-header", children: header }) : null,
|
|
287
|
+
/* @__PURE__ */ jsx3("div", { className: ["fd-pop-body", padded ? "fd-pop-padded" : ""].filter(Boolean).join(" "), children }),
|
|
288
|
+
footer != null ? /* @__PURE__ */ jsx3("div", { className: "fd-pop-footer", children: footer }) : null
|
|
289
|
+
]
|
|
247
290
|
}
|
|
248
291
|
)
|
|
249
292
|
);
|
|
@@ -318,77 +361,79 @@ function Menu({ items = [], onSelect, onClose, autoFocus = true, className = "",
|
|
|
318
361
|
};
|
|
319
362
|
const sub = openSub != null ? items[openSub] : null;
|
|
320
363
|
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(
|
|
364
|
+
/* @__PURE__ */ jsxs2("div", { className: "fd-menu-frame", children: [
|
|
365
|
+
header != null ? /* @__PURE__ */ jsx3("div", { className: "fd-menu-header", children: header }) : null,
|
|
366
|
+
/* @__PURE__ */ jsx3(
|
|
367
|
+
"div",
|
|
368
|
+
{
|
|
369
|
+
ref: listRef,
|
|
370
|
+
tabIndex: -1,
|
|
371
|
+
role: "menu",
|
|
372
|
+
onKeyDown: onKey,
|
|
373
|
+
className: ["fd-pop-list", "fd-menu", className].filter(Boolean).join(" "),
|
|
374
|
+
children: items.map((it, i) => {
|
|
375
|
+
if (!it) return null;
|
|
376
|
+
if (it.kind === "separator") return /* @__PURE__ */ jsx3("div", { className: "fd-menu-sep", role: "separator" }, "s" + i);
|
|
377
|
+
if (it.kind === "section") return /* @__PURE__ */ jsx3("div", { className: "fd-pop-group", role: "presentation", children: it.label }, "h" + i);
|
|
378
|
+
if (it.kind === "custom") return /* @__PURE__ */ jsx3("div", { className: "fd-menu-custom", children: it.render ? it.render() : null }, "c" + i);
|
|
379
|
+
const on = !!it.checked;
|
|
380
|
+
const row = /* @__PURE__ */ jsxs2(
|
|
371
381
|
"button",
|
|
372
382
|
{
|
|
373
383
|
type: "button",
|
|
374
|
-
|
|
375
|
-
"
|
|
376
|
-
|
|
377
|
-
|
|
378
|
-
|
|
379
|
-
|
|
380
|
-
|
|
381
|
-
|
|
382
|
-
|
|
384
|
+
"data-i": i,
|
|
385
|
+
role: it.checked != null ? "menuitemradio" : "menuitem",
|
|
386
|
+
"aria-checked": it.checked != null ? on : void 0,
|
|
387
|
+
"aria-haspopup": it.submenu ? "menu" : void 0,
|
|
388
|
+
"aria-expanded": it.submenu ? openSub === i : void 0,
|
|
389
|
+
"aria-disabled": it.disabled || void 0,
|
|
390
|
+
className: ["fd-opt", "fd-menu-item", i === active ? "is-active" : "", on ? "is-selected" : ""].filter(Boolean).join(" "),
|
|
391
|
+
onMouseEnter: () => {
|
|
392
|
+
setActive(i);
|
|
393
|
+
if (openSub != null && openSub !== i) setOpenSub(null);
|
|
383
394
|
},
|
|
384
|
-
|
|
385
|
-
|
|
386
|
-
|
|
387
|
-
|
|
388
|
-
|
|
389
|
-
|
|
390
|
-
|
|
391
|
-
|
|
395
|
+
onClick: () => choose(it, i),
|
|
396
|
+
children: [
|
|
397
|
+
it.icon ? /* @__PURE__ */ jsx3("span", { className: "fd-menu-icon", children: /* @__PURE__ */ jsx3("i", { className: "ph ph-" + it.icon, "aria-hidden": "true" }) }) : null,
|
|
398
|
+
/* @__PURE__ */ jsxs2("span", { className: "fd-menu-text", children: [
|
|
399
|
+
/* @__PURE__ */ jsx3("span", { className: "fd-opt-label", children: it.label }),
|
|
400
|
+
it.description ? /* @__PURE__ */ jsx3("span", { className: "fd-opt-desc", children: it.description }) : null
|
|
401
|
+
] }),
|
|
402
|
+
it.meta ? /* @__PURE__ */ jsx3("span", { className: "fd-opt-meta", children: it.meta }) : null,
|
|
403
|
+
it.shortcut ? /* @__PURE__ */ jsx3("span", { className: "fd-menu-shortcut", "aria-hidden": "true", children: it.shortcut }) : null,
|
|
404
|
+
it.submenu ? /* @__PURE__ */ jsx3("i", { className: "ph ph-caret-right fd-menu-more", "aria-hidden": "true" }) : null,
|
|
405
|
+
it.checked != null ? /* @__PURE__ */ jsx3("span", { className: "fd-opt-check", children: on ? /* @__PURE__ */ jsx3("i", { className: "ph ph-check", "aria-hidden": "true" }) : null }) : null
|
|
406
|
+
]
|
|
407
|
+
},
|
|
408
|
+
it.id || it.label || i
|
|
409
|
+
);
|
|
410
|
+
const ta = it.trailingAction;
|
|
411
|
+
if (!ta) return row;
|
|
412
|
+
return /* @__PURE__ */ jsxs2("div", { className: "fd-menu-row", onMouseEnter: () => setActive(i), children: [
|
|
413
|
+
row,
|
|
414
|
+
/* @__PURE__ */ jsx3(
|
|
415
|
+
"button",
|
|
416
|
+
{
|
|
417
|
+
type: "button",
|
|
418
|
+
className: ["fd-menu-row-act", ta.danger ? "is-danger" : ""].filter(Boolean).join(" "),
|
|
419
|
+
"aria-label": ta.label,
|
|
420
|
+
title: ta.label,
|
|
421
|
+
onClick: (e) => {
|
|
422
|
+
e.stopPropagation();
|
|
423
|
+
ta.onSelect && ta.onSelect(it);
|
|
424
|
+
if (ta.closeOnSelect !== false) {
|
|
425
|
+
onClose && onClose();
|
|
426
|
+
}
|
|
427
|
+
},
|
|
428
|
+
children: /* @__PURE__ */ jsx3("i", { className: "ph ph-" + (ta.icon || "trash"), "aria-hidden": "true" })
|
|
429
|
+
}
|
|
430
|
+
)
|
|
431
|
+
] }, it.id || it.label || i);
|
|
432
|
+
})
|
|
433
|
+
}
|
|
434
|
+
),
|
|
435
|
+
footer != null ? /* @__PURE__ */ jsx3("div", { className: "fd-menu-footer", children: footer }) : null
|
|
436
|
+
] }),
|
|
392
437
|
sub && sub.submenu ? /* @__PURE__ */ jsx3(
|
|
393
438
|
Popover,
|
|
394
439
|
{
|
|
@@ -1016,20 +1061,123 @@ function Toast({ title, children, tone = "success", onUndo, onDismiss, className
|
|
|
1016
1061
|
// src/components/feedback/Tooltip.tsx
|
|
1017
1062
|
import * as React6 from "react";
|
|
1018
1063
|
import { jsx as jsx24, jsxs as jsxs19 } from "react/jsx-runtime";
|
|
1064
|
+
var CLOSE_DELAY_MS = 120;
|
|
1019
1065
|
function Tooltip({ label, placement = "top", children, className = "" }) {
|
|
1020
|
-
const
|
|
1021
|
-
const
|
|
1066
|
+
const anchorRef = React6.useRef(null);
|
|
1067
|
+
const bubbleRef = React6.useRef(null);
|
|
1068
|
+
const [reason, setReason] = React6.useState(null);
|
|
1069
|
+
const closeTimer = React6.useRef(null);
|
|
1070
|
+
const id = React6.useId();
|
|
1071
|
+
const descId = id + "-desc";
|
|
1072
|
+
const open = reason != null;
|
|
1073
|
+
const cancelClose = React6.useCallback(() => {
|
|
1074
|
+
if (closeTimer.current) {
|
|
1075
|
+
clearTimeout(closeTimer.current);
|
|
1076
|
+
closeTimer.current = null;
|
|
1077
|
+
}
|
|
1078
|
+
}, []);
|
|
1079
|
+
const show = (why) => {
|
|
1080
|
+
cancelClose();
|
|
1081
|
+
setReason(why);
|
|
1082
|
+
};
|
|
1083
|
+
const hide = React6.useCallback(() => {
|
|
1084
|
+
cancelClose();
|
|
1085
|
+
setReason(null);
|
|
1086
|
+
}, [cancelClose]);
|
|
1087
|
+
const hover = () => {
|
|
1088
|
+
cancelClose();
|
|
1089
|
+
setReason((r) => r || "hover");
|
|
1090
|
+
};
|
|
1091
|
+
const hideSoon = () => {
|
|
1092
|
+
cancelClose();
|
|
1093
|
+
closeTimer.current = setTimeout(() => {
|
|
1094
|
+
closeTimer.current = null;
|
|
1095
|
+
setReason((r) => r === "hover" ? null : r);
|
|
1096
|
+
}, CLOSE_DELAY_MS);
|
|
1097
|
+
};
|
|
1098
|
+
React6.useEffect(() => cancelClose, [cancelClose]);
|
|
1099
|
+
const pos = usePopoverPosition(open, anchorRef, {
|
|
1100
|
+
placement: placement === "bottom" ? "bottom-center" : "top-center",
|
|
1101
|
+
offset: 8,
|
|
1102
|
+
estHeight: 40,
|
|
1103
|
+
estWidth: 160,
|
|
1104
|
+
layerRef: bubbleRef,
|
|
1105
|
+
onDetach: hide
|
|
1106
|
+
});
|
|
1107
|
+
React6.useEffect(() => {
|
|
1108
|
+
if (!open) return;
|
|
1109
|
+
const key = (e) => {
|
|
1110
|
+
if (e.key === "Escape") hide();
|
|
1111
|
+
};
|
|
1112
|
+
const away = (e) => {
|
|
1113
|
+
const t = e.target;
|
|
1114
|
+
if (anchorRef.current && anchorRef.current.contains(t)) return;
|
|
1115
|
+
if (bubbleRef.current && bubbleRef.current.contains(t)) return;
|
|
1116
|
+
hide();
|
|
1117
|
+
};
|
|
1118
|
+
document.addEventListener("keydown", key);
|
|
1119
|
+
document.addEventListener("pointerdown", away, true);
|
|
1120
|
+
return () => {
|
|
1121
|
+
document.removeEventListener("keydown", key);
|
|
1122
|
+
document.removeEventListener("pointerdown", away, true);
|
|
1123
|
+
};
|
|
1124
|
+
}, [open, hide]);
|
|
1125
|
+
const isMouse = (e) => e.pointerType === "mouse";
|
|
1126
|
+
const onFocus = (e) => {
|
|
1127
|
+
const el = e.target;
|
|
1128
|
+
let keyboard = true;
|
|
1129
|
+
try {
|
|
1130
|
+
keyboard = el.matches(":focus-visible");
|
|
1131
|
+
} catch {
|
|
1132
|
+
}
|
|
1133
|
+
if (keyboard) show("focus");
|
|
1134
|
+
};
|
|
1135
|
+
const described = React6.isValidElement(children) ? React6.cloneElement(children, {
|
|
1136
|
+
"aria-describedby": [children.props["aria-describedby"], descId].filter(Boolean).join(" ")
|
|
1137
|
+
}) : children;
|
|
1022
1138
|
return /* @__PURE__ */ jsxs19(
|
|
1023
1139
|
"span",
|
|
1024
1140
|
{
|
|
1025
|
-
|
|
1026
|
-
|
|
1027
|
-
|
|
1028
|
-
|
|
1029
|
-
|
|
1141
|
+
ref: anchorRef,
|
|
1142
|
+
className: "fd-tooltip-anchor",
|
|
1143
|
+
"aria-describedby": React6.isValidElement(children) ? void 0 : descId,
|
|
1144
|
+
onPointerEnter: (e) => {
|
|
1145
|
+
if (isMouse(e)) hover();
|
|
1146
|
+
},
|
|
1147
|
+
onPointerLeave: (e) => {
|
|
1148
|
+
if (isMouse(e)) hideSoon();
|
|
1149
|
+
},
|
|
1150
|
+
onPointerUp: (e) => {
|
|
1151
|
+
if (!isMouse(e)) {
|
|
1152
|
+
if (reason === "tap") hide();
|
|
1153
|
+
else show("tap");
|
|
1154
|
+
}
|
|
1155
|
+
},
|
|
1156
|
+
onFocus,
|
|
1157
|
+
onBlur: () => {
|
|
1158
|
+
if (reason === "focus") hide();
|
|
1159
|
+
},
|
|
1030
1160
|
children: [
|
|
1031
|
-
|
|
1032
|
-
|
|
1161
|
+
described,
|
|
1162
|
+
/* @__PURE__ */ jsx24("span", { id: descId, hidden: true, children: label }),
|
|
1163
|
+
open && pos ? portal(
|
|
1164
|
+
/* @__PURE__ */ jsx24(
|
|
1165
|
+
"span",
|
|
1166
|
+
{
|
|
1167
|
+
ref: bubbleRef,
|
|
1168
|
+
role: "tooltip",
|
|
1169
|
+
className: ["fd-tooltip", pos.side === "bottom" ? "is-below" : "", className].filter(Boolean).join(" "),
|
|
1170
|
+
style: { left: pos.left, top: pos.top == null ? "auto" : pos.top, bottom: pos.bottom == null ? "auto" : pos.bottom },
|
|
1171
|
+
onPointerEnter: (e) => {
|
|
1172
|
+
if (isMouse(e)) cancelClose();
|
|
1173
|
+
},
|
|
1174
|
+
onPointerLeave: (e) => {
|
|
1175
|
+
if (isMouse(e)) hideSoon();
|
|
1176
|
+
},
|
|
1177
|
+
children: label
|
|
1178
|
+
}
|
|
1179
|
+
)
|
|
1180
|
+
) : null
|
|
1033
1181
|
]
|
|
1034
1182
|
}
|
|
1035
1183
|
);
|
|
@@ -2663,6 +2811,7 @@ function VirtualList({
|
|
|
2663
2811
|
}
|
|
2664
2812
|
|
|
2665
2813
|
// src/components/data/EntityRow.tsx
|
|
2814
|
+
import * as React17 from "react";
|
|
2666
2815
|
import { jsx as jsx39, jsxs as jsxs35 } from "react/jsx-runtime";
|
|
2667
2816
|
var ENTITY_ROW_METRIC_WIDTH = 74;
|
|
2668
2817
|
var METRIC_TONE_COLOR = {
|
|
@@ -2671,20 +2820,20 @@ var METRIC_TONE_COLOR = {
|
|
|
2671
2820
|
danger: "var(--danger-text)"
|
|
2672
2821
|
};
|
|
2673
2822
|
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
|
-
)
|
|
2823
|
+
return /* @__PURE__ */ jsx39("span", { className: ["fd-erow-metrics", className].filter(Boolean).join(" "), style, children: metrics.map((m, i) => {
|
|
2824
|
+
const key = m.id || m.label || i;
|
|
2825
|
+
const className2 = ["fd-erow-metric", m.tone && m.tone !== "default" ? "is-" + m.tone : "", m.tooltip != null ? "is-described" : ""].filter(Boolean).join(" ");
|
|
2826
|
+
const cellStyle = { width: (m.width || ENTITY_ROW_METRIC_WIDTH) + "px", color: METRIC_TONE_COLOR[m.tone || "default"] };
|
|
2827
|
+
const content = /* @__PURE__ */ jsxs35(React17.Fragment, { children: [
|
|
2828
|
+
m.icon ? /* @__PURE__ */ jsx39("i", { className: "ph ph-" + m.icon, "aria-hidden": "true" }) : null,
|
|
2829
|
+
/* @__PURE__ */ jsx39("span", { className: "fd-erow-metric-value fd-tabular", children: m.value }),
|
|
2830
|
+
/* @__PURE__ */ jsx39("span", { className: "fd-sr", children: " " + m.label })
|
|
2831
|
+
] });
|
|
2832
|
+
if (m.tooltip == null) {
|
|
2833
|
+
return /* @__PURE__ */ jsx39("span", { className: className2, style: cellStyle, title: m.label, children: content }, key);
|
|
2834
|
+
}
|
|
2835
|
+
return /* @__PURE__ */ jsx39(Tooltip, { label: m.tooltip, children: /* @__PURE__ */ jsx39("button", { type: "button", className: className2, style: cellStyle, children: content }) }, key);
|
|
2836
|
+
}) });
|
|
2688
2837
|
}
|
|
2689
2838
|
function EntityRow({
|
|
2690
2839
|
title,
|
|
@@ -2734,8 +2883,10 @@ function EntityRow({
|
|
|
2734
2883
|
icon: action.icon,
|
|
2735
2884
|
label: action.label,
|
|
2736
2885
|
size: "sm",
|
|
2737
|
-
|
|
2738
|
-
|
|
2886
|
+
variant: "solid",
|
|
2887
|
+
tone: action.tone === "add" ? "ok" : action.tone === "remove" ? "danger" : "neutral",
|
|
2888
|
+
className: "fd-erow-action",
|
|
2889
|
+
onClick: action.onClick
|
|
2739
2890
|
}
|
|
2740
2891
|
) : null
|
|
2741
2892
|
]
|
|
@@ -2744,14 +2895,14 @@ function EntityRow({
|
|
|
2744
2895
|
}
|
|
2745
2896
|
|
|
2746
2897
|
// src/components/data/TransferList.tsx
|
|
2747
|
-
import * as
|
|
2898
|
+
import * as React19 from "react";
|
|
2748
2899
|
import { createPortal as createPortal4 } from "react-dom";
|
|
2749
2900
|
|
|
2750
2901
|
// src/components/forms/field.tsx
|
|
2751
|
-
import * as
|
|
2902
|
+
import * as React18 from "react";
|
|
2752
2903
|
import { jsx as jsx40, jsxs as jsxs36 } from "react/jsx-runtime";
|
|
2753
2904
|
function useFieldId(id) {
|
|
2754
|
-
const generated =
|
|
2905
|
+
const generated = React18.useId();
|
|
2755
2906
|
return id || generated;
|
|
2756
2907
|
}
|
|
2757
2908
|
function FieldLabel({ htmlFor, id, required = false, onClick, children }) {
|
|
@@ -2792,10 +2943,9 @@ function Input({
|
|
|
2792
2943
|
numeric ? "fd-input-num" : "",
|
|
2793
2944
|
error ? "fd-input-error" : "",
|
|
2794
2945
|
disabled ? "fd-input-disabled" : "",
|
|
2795
|
-
size === "lg" ? "fd-input-lg" : ""
|
|
2796
|
-
className
|
|
2946
|
+
size === "lg" ? "fd-input-lg" : ""
|
|
2797
2947
|
].filter(Boolean).join(" ");
|
|
2798
|
-
return /* @__PURE__ */ jsxs37("div", { className: "fd-field", style, children: [
|
|
2948
|
+
return /* @__PURE__ */ jsxs37("div", { className: ["fd-field", className].filter(Boolean).join(" "), style, children: [
|
|
2799
2949
|
label ? /* @__PURE__ */ jsx41(FieldLabel, { htmlFor: fieldId, required, children: label }) : null,
|
|
2800
2950
|
/* @__PURE__ */ jsxs37("div", { className: box, children: [
|
|
2801
2951
|
icon ? /* @__PURE__ */ jsx41("span", { className: "fd-input-icon", children: /* @__PURE__ */ jsx41("i", { className: "ph ph-" + icon, "aria-hidden": "true" }) }) : null,
|
|
@@ -2870,12 +3020,12 @@ function TransferList({
|
|
|
2870
3020
|
listHeight = 440,
|
|
2871
3021
|
className = ""
|
|
2872
3022
|
}) {
|
|
2873
|
-
const [drag, setDrag] =
|
|
2874
|
-
const [dragOverSide, setDragOverSide] =
|
|
2875
|
-
const dragRef =
|
|
2876
|
-
const armedRef =
|
|
2877
|
-
const sideRefs =
|
|
2878
|
-
const hitTestSide =
|
|
3023
|
+
const [drag, setDrag] = React19.useState(null);
|
|
3024
|
+
const [dragOverSide, setDragOverSide] = React19.useState(null);
|
|
3025
|
+
const dragRef = React19.useRef(null);
|
|
3026
|
+
const armedRef = React19.useRef(null);
|
|
3027
|
+
const sideRefs = React19.useRef({ left: null, right: null });
|
|
3028
|
+
const hitTestSide = React19.useCallback((x, y) => {
|
|
2879
3029
|
for (const side of ["left", "right"]) {
|
|
2880
3030
|
const el = sideRefs.current[side];
|
|
2881
3031
|
if (!el) continue;
|
|
@@ -2884,7 +3034,7 @@ function TransferList({
|
|
|
2884
3034
|
}
|
|
2885
3035
|
return null;
|
|
2886
3036
|
}, []);
|
|
2887
|
-
const findItem =
|
|
3037
|
+
const findItem = React19.useCallback(
|
|
2888
3038
|
(side, key) => (side === "left" ? left.items : right.items).find((it) => keyOf(it) === key),
|
|
2889
3039
|
[left.items, right.items, keyOf]
|
|
2890
3040
|
);
|
|
@@ -2906,7 +3056,7 @@ function TransferList({
|
|
|
2906
3056
|
height: rect.height
|
|
2907
3057
|
};
|
|
2908
3058
|
};
|
|
2909
|
-
|
|
3059
|
+
React19.useEffect(() => {
|
|
2910
3060
|
const onMovePointer = (e) => {
|
|
2911
3061
|
const armed = armedRef.current;
|
|
2912
3062
|
if (!armed || e.pointerId !== armed.pointerId) return;
|
|
@@ -2959,7 +3109,7 @@ function TransferList({
|
|
|
2959
3109
|
window.removeEventListener("pointercancel", endDrag);
|
|
2960
3110
|
};
|
|
2961
3111
|
}, [hitTestSide, findItem, onMove]);
|
|
2962
|
-
|
|
3112
|
+
React19.useEffect(() => {
|
|
2963
3113
|
if (!drag || typeof document === "undefined") return;
|
|
2964
3114
|
const prev = document.body.style.userSelect;
|
|
2965
3115
|
document.body.style.userSelect = "none";
|
|
@@ -3071,11 +3221,11 @@ function TransferList({
|
|
|
3071
3221
|
}
|
|
3072
3222
|
|
|
3073
3223
|
// src/components/forms/Checkbox.tsx
|
|
3074
|
-
import * as
|
|
3224
|
+
import * as React20 from "react";
|
|
3075
3225
|
import { jsx as jsx44, jsxs as jsxs39 } from "react/jsx-runtime";
|
|
3076
3226
|
function Checkbox({ label, description, card = false, indeterminate = false, className = "", ...rest }) {
|
|
3077
|
-
const ref =
|
|
3078
|
-
|
|
3227
|
+
const ref = React20.useRef(null);
|
|
3228
|
+
React20.useEffect(() => {
|
|
3079
3229
|
if (ref.current) ref.current.indeterminate = indeterminate;
|
|
3080
3230
|
}, [indeterminate]);
|
|
3081
3231
|
return /* @__PURE__ */ jsxs39("label", { className: ["fd-choice", card ? "fd-choice-card" : "", className].filter(Boolean).join(" "), children: [
|
|
@@ -3122,8 +3272,8 @@ function Switch({ label, description, className = "", ...rest }) {
|
|
|
3122
3272
|
import { jsx as jsx47, jsxs as jsxs42 } from "react/jsx-runtime";
|
|
3123
3273
|
function Textarea({ label, help, error, required = false, rows = 4, disabled = false, id, className = "", style, ...rest }) {
|
|
3124
3274
|
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: [
|
|
3275
|
+
const box = ["fd-input", "fd-input-textarea", error ? "fd-input-error" : "", disabled ? "fd-input-disabled" : ""].filter(Boolean).join(" ");
|
|
3276
|
+
return /* @__PURE__ */ jsxs42("div", { className: ["fd-field", className].filter(Boolean).join(" "), style, children: [
|
|
3127
3277
|
label ? /* @__PURE__ */ jsx47(FieldLabel, { htmlFor: fieldId, required, children: label }) : null,
|
|
3128
3278
|
/* @__PURE__ */ jsx47("div", { className: box, children: /* @__PURE__ */ jsx47("textarea", { id: fieldId, rows, disabled, "aria-invalid": error ? "true" : void 0, ...rest }) }),
|
|
3129
3279
|
error ? /* @__PURE__ */ jsxs42("span", { className: "fd-field-error", children: [
|
|
@@ -3134,7 +3284,7 @@ function Textarea({ label, help, error, required = false, rows = 4, disabled = f
|
|
|
3134
3284
|
}
|
|
3135
3285
|
|
|
3136
3286
|
// src/components/forms/NumberInput.tsx
|
|
3137
|
-
import * as
|
|
3287
|
+
import * as React21 from "react";
|
|
3138
3288
|
import { jsx as jsx48, jsxs as jsxs43 } from "react/jsx-runtime";
|
|
3139
3289
|
function NumberInput({
|
|
3140
3290
|
label,
|
|
@@ -3162,10 +3312,10 @@ function NumberInput({
|
|
|
3162
3312
|
const n = Number(String(v == null ? "" : v).replace(/[^0-9.-]/g, ""));
|
|
3163
3313
|
return isNaN(n) ? null : n;
|
|
3164
3314
|
};
|
|
3165
|
-
const [text, setText] =
|
|
3166
|
-
const [editing, setEditing] =
|
|
3167
|
-
const timer =
|
|
3168
|
-
|
|
3315
|
+
const [text, setText] = React21.useState(value == null || value === "" ? "" : String(value));
|
|
3316
|
+
const [editing, setEditing] = React21.useState(false);
|
|
3317
|
+
const timer = React21.useRef(null);
|
|
3318
|
+
React21.useEffect(() => {
|
|
3169
3319
|
if (!editing) setText(value == null || value === "" ? "" : String(value));
|
|
3170
3320
|
}, [value, editing]);
|
|
3171
3321
|
const clamp = (n) => Math.min(max, Math.max(min, n));
|
|
@@ -3189,7 +3339,7 @@ function NumberInput({
|
|
|
3189
3339
|
const release = () => {
|
|
3190
3340
|
if (timer.current) clearTimeout(timer.current);
|
|
3191
3341
|
};
|
|
3192
|
-
|
|
3342
|
+
React21.useEffect(() => () => {
|
|
3193
3343
|
if (timer.current) clearTimeout(timer.current);
|
|
3194
3344
|
}, []);
|
|
3195
3345
|
const shown = editing ? text : (() => {
|
|
@@ -3276,52 +3426,9 @@ function NumberInput({
|
|
|
3276
3426
|
}
|
|
3277
3427
|
|
|
3278
3428
|
// src/components/forms/Select.tsx
|
|
3279
|
-
import * as
|
|
3280
|
-
import { createPortal as createPortal5 } from "react-dom";
|
|
3429
|
+
import * as React22 from "react";
|
|
3281
3430
|
import { jsx as jsx49, jsxs as jsxs44 } from "react/jsx-runtime";
|
|
3282
3431
|
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
3432
|
function Select({
|
|
3326
3433
|
label,
|
|
3327
3434
|
help,
|
|
@@ -3346,17 +3453,15 @@ function Select({
|
|
|
3346
3453
|
const isOn = (v) => multiple ? vals.includes(v) : v === value;
|
|
3347
3454
|
const hasSearch = searchable === void 0 ? opts.length > 8 : searchable;
|
|
3348
3455
|
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 });
|
|
3456
|
+
const [open, setOpen] = React22.useState(false);
|
|
3457
|
+
const [q, setQ] = React22.useState("");
|
|
3458
|
+
const [active, setActive] = React22.useState(-1);
|
|
3459
|
+
const rootRef = React22.useRef(null);
|
|
3460
|
+
const boxRef = React22.useRef(null);
|
|
3461
|
+
const listRef = React22.useRef(null);
|
|
3462
|
+
const typeBuf = React22.useRef({ s: "", t: 0 });
|
|
3357
3463
|
const selected = multiple ? null : opts.find((o) => o.value === value);
|
|
3358
3464
|
const chosen = multiple ? opts.filter((o) => vals.includes(o.value)) : [];
|
|
3359
|
-
const pos = usePopPos(open, boxRef, hasSearch ? 390 : 340, 260);
|
|
3360
3465
|
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
3466
|
const visible = q ? opts.filter((o) => (o.label + " " + (o.description || "") + " " + (o.group || "")).toLowerCase().includes(q.toLowerCase())) : opts;
|
|
3362
3467
|
const fire = (v) => {
|
|
@@ -3379,17 +3484,7 @@ function Select({
|
|
|
3379
3484
|
}
|
|
3380
3485
|
setOpen(!open);
|
|
3381
3486
|
};
|
|
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(() => {
|
|
3487
|
+
React22.useEffect(() => {
|
|
3393
3488
|
if (!open || active < 0 || !listRef.current) return;
|
|
3394
3489
|
const el = listRef.current.querySelector('[data-i="' + active + '"]');
|
|
3395
3490
|
if (el) {
|
|
@@ -3480,94 +3575,96 @@ function Select({
|
|
|
3480
3575
|
) : null,
|
|
3481
3576
|
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
3577
|
] }),
|
|
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
|
-
|
|
3578
|
+
/* @__PURE__ */ jsx49(
|
|
3579
|
+
Popover,
|
|
3580
|
+
{
|
|
3581
|
+
open,
|
|
3582
|
+
anchorRef: boxRef,
|
|
3583
|
+
triggerRef: rootRef,
|
|
3584
|
+
onClose: () => setOpen(false),
|
|
3585
|
+
placement: "bottom-start",
|
|
3586
|
+
offset: 6,
|
|
3587
|
+
matchWidth: "min",
|
|
3588
|
+
minWidth: 260,
|
|
3589
|
+
role: "presentation",
|
|
3590
|
+
style: { maxWidth: 380, zIndex: 130 },
|
|
3591
|
+
header: hasSearch ? /* @__PURE__ */ jsxs44("div", { className: "fd-pop-search", children: [
|
|
3592
|
+
/* @__PURE__ */ jsx49("i", { className: "ph ph-magnifying-glass", style: { color: "var(--text-muted)", fontSize: 14 } }),
|
|
3593
|
+
/* @__PURE__ */ jsx49(
|
|
3594
|
+
"input",
|
|
3595
|
+
{
|
|
3596
|
+
autoFocus: true,
|
|
3597
|
+
placeholder: "Search\u2026",
|
|
3598
|
+
value: q,
|
|
3599
|
+
onKeyDown: onKey,
|
|
3600
|
+
onChange: (e) => {
|
|
3601
|
+
setQ(e.target.value);
|
|
3602
|
+
setActive(0);
|
|
3603
|
+
}
|
|
3604
|
+
}
|
|
3605
|
+
),
|
|
3606
|
+
q ? /* @__PURE__ */ jsx49("span", { className: "fd-body-sm fd-muted", children: visible.length }) : null
|
|
3607
|
+
] }) : void 0,
|
|
3608
|
+
footer: multiple ? /* @__PURE__ */ jsxs44(React22.Fragment, { children: [
|
|
3609
|
+
/* @__PURE__ */ jsx49(
|
|
3610
|
+
"button",
|
|
3611
|
+
{
|
|
3612
|
+
type: "button",
|
|
3613
|
+
onClick: () => fire(visible.filter((o) => !o.disabled).map((o) => o.value)),
|
|
3614
|
+
style: { all: "unset", cursor: "pointer", fontSize: "var(--body-sm-size)", fontWeight: 600, color: "var(--brand)" },
|
|
3615
|
+
children: "Select all"
|
|
3616
|
+
}
|
|
3617
|
+
),
|
|
3618
|
+
/* @__PURE__ */ jsx49("span", { style: { flex: 1 } }),
|
|
3619
|
+
/* @__PURE__ */ jsxs44("span", { className: "fd-body-sm fd-muted", children: [
|
|
3620
|
+
vals.length,
|
|
3621
|
+
" of ",
|
|
3622
|
+
opts.length
|
|
3623
|
+
] }),
|
|
3624
|
+
/* @__PURE__ */ jsx49(
|
|
3625
|
+
"button",
|
|
3626
|
+
{
|
|
3627
|
+
type: "button",
|
|
3628
|
+
disabled: !vals.length,
|
|
3629
|
+
onClick: () => fire([]),
|
|
3630
|
+
style: { all: "unset", cursor: vals.length ? "pointer" : "default", fontSize: "var(--body-sm-size)", fontWeight: 600, color: vals.length ? "var(--text-2)" : "var(--text-muted)" },
|
|
3631
|
+
children: "Clear"
|
|
3632
|
+
}
|
|
3633
|
+
)
|
|
3634
|
+
] }) : void 0,
|
|
3635
|
+
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: [
|
|
3636
|
+
'Nothing matches "',
|
|
3637
|
+
q,
|
|
3638
|
+
'".'
|
|
3639
|
+
] }) : groups.map((grp) => /* @__PURE__ */ jsxs44(React22.Fragment, { children: [
|
|
3640
|
+
grp.g ? /* @__PURE__ */ jsx49("div", { className: "fd-pop-group", children: grp.g }) : null,
|
|
3641
|
+
grp.items.map(({ o, i }) => /* @__PURE__ */ jsxs44(
|
|
3642
|
+
"button",
|
|
3643
|
+
{
|
|
3644
|
+
type: "button",
|
|
3645
|
+
"data-i": i,
|
|
3646
|
+
role: "option",
|
|
3647
|
+
"aria-selected": isOn(o.value),
|
|
3648
|
+
"aria-disabled": o.disabled || void 0,
|
|
3649
|
+
className: ["fd-opt", i === active ? "is-active" : "", isOn(o.value) ? "is-selected" : ""].filter(Boolean).join(" "),
|
|
3650
|
+
onMouseEnter: () => setActive(i),
|
|
3651
|
+
onClick: () => pick(o),
|
|
3652
|
+
children: [
|
|
3653
|
+
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,
|
|
3654
|
+
o.icon ? /* @__PURE__ */ jsx49("span", { className: "fd-opt-icon", children: /* @__PURE__ */ jsx49("i", { className: "ph ph-" + o.icon }) }) : null,
|
|
3655
|
+
/* @__PURE__ */ jsxs44("span", { style: { flex: 1, minWidth: 0 }, children: [
|
|
3656
|
+
/* @__PURE__ */ jsx49("span", { className: "fd-opt-label", children: o.label }),
|
|
3657
|
+
o.description ? /* @__PURE__ */ jsx49("span", { className: "fd-opt-desc", children: o.description }) : null
|
|
3658
|
+
] }),
|
|
3659
|
+
o.meta ? /* @__PURE__ */ jsx49("span", { className: "fd-opt-meta", children: o.meta }) : null,
|
|
3660
|
+
multiple ? null : /* @__PURE__ */ jsx49("span", { className: "fd-opt-check", children: o.value === value ? /* @__PURE__ */ jsx49("i", { className: "ph ph-check" }) : null })
|
|
3661
|
+
]
|
|
3662
|
+
},
|
|
3663
|
+
String(o.value)
|
|
3664
|
+
))
|
|
3665
|
+
] }, grp.g || "_")) })
|
|
3666
|
+
}
|
|
3667
|
+
),
|
|
3571
3668
|
error ? /* @__PURE__ */ jsxs44("span", { className: "fd-field-error", children: [
|
|
3572
3669
|
/* @__PURE__ */ jsx49("i", { className: "ph ph-warning-circle", "aria-hidden": "true" }),
|
|
3573
3670
|
error
|
|
@@ -3576,8 +3673,7 @@ function Select({
|
|
|
3576
3673
|
}
|
|
3577
3674
|
|
|
3578
3675
|
// src/components/forms/DatePicker.tsx
|
|
3579
|
-
import * as
|
|
3580
|
-
import { createPortal as createPortal6 } from "react-dom";
|
|
3676
|
+
import * as React23 from "react";
|
|
3581
3677
|
import { jsx as jsx50, jsxs as jsxs45 } from "react/jsx-runtime";
|
|
3582
3678
|
var MONTHS = ["January", "February", "March", "April", "May", "June", "July", "August", "September", "October", "November", "December"];
|
|
3583
3679
|
var DOW = ["Su", "Mo", "Tu", "We", "Th", "Fr", "Sa"];
|
|
@@ -3591,56 +3687,14 @@ var fmt = (s) => {
|
|
|
3591
3687
|
const d = parse(s);
|
|
3592
3688
|
return d ? MONTHS[d.getMonth()].slice(0, 3) + " " + d.getDate() + ", " + d.getFullYear() : "";
|
|
3593
3689
|
};
|
|
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
3690
|
function Calendar({ value, range = false, onPick, initialMonth, months = 1 }) {
|
|
3637
3691
|
const today = /* @__PURE__ */ new Date();
|
|
3638
3692
|
const sel = range ? value || {} : { start: value, end: value };
|
|
3639
3693
|
const anchor = parse(sel.start) || parse(initialMonth) || today;
|
|
3640
|
-
const [vy, setVy] =
|
|
3641
|
-
const [vm, setVm] =
|
|
3642
|
-
const [mode2, setMode] =
|
|
3643
|
-
const [hover, setHover] =
|
|
3694
|
+
const [vy, setVy] = React23.useState(anchor.getFullYear());
|
|
3695
|
+
const [vm, setVm] = React23.useState(anchor.getMonth());
|
|
3696
|
+
const [mode2, setMode] = React23.useState("days");
|
|
3697
|
+
const [hover, setHover] = React23.useState(null);
|
|
3644
3698
|
const s = parse(sel.start), e = parse(sel.end);
|
|
3645
3699
|
const hoverEnd = range && s && !e && hover ? parse(hover) : null;
|
|
3646
3700
|
const inRange = (d) => {
|
|
@@ -3756,28 +3810,9 @@ function Calendar({ value, range = false, onPick, initialMonth, months = 1 }) {
|
|
|
3756
3810
|
}
|
|
3757
3811
|
function DatePicker({ label, help, error, required = false, disabled = false, range = false, value, onChange, placeholder, id, className = "", style, ...rest }) {
|
|
3758
3812
|
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]);
|
|
3813
|
+
const [open, setOpen] = React23.useState(false);
|
|
3814
|
+
const rootRef = React23.useRef(null);
|
|
3815
|
+
const boxRef = React23.useRef(null);
|
|
3781
3816
|
const display = range ? value && value.start ? fmt(value.start) + (value.end ? " \u2192 " + fmt(value.end) : " \u2192 \u2026") : "" : fmt(value);
|
|
3782
3817
|
const toggle = () => {
|
|
3783
3818
|
if (!disabled) setOpen(!open);
|
|
@@ -3806,21 +3841,31 @@ function DatePicker({ label, help, error, required = false, disabled = false, ra
|
|
|
3806
3841
|
),
|
|
3807
3842
|
/* @__PURE__ */ jsx50("span", { className: "fd-select-caret", children: /* @__PURE__ */ jsx50("i", { className: "ph ph-caret-down", "aria-hidden": "true" }) })
|
|
3808
3843
|
] }),
|
|
3809
|
-
|
|
3810
|
-
|
|
3811
|
-
|
|
3812
|
-
|
|
3813
|
-
|
|
3814
|
-
|
|
3815
|
-
|
|
3816
|
-
|
|
3817
|
-
|
|
3818
|
-
|
|
3844
|
+
/* @__PURE__ */ jsx50(
|
|
3845
|
+
Popover,
|
|
3846
|
+
{
|
|
3847
|
+
open,
|
|
3848
|
+
anchorRef: boxRef,
|
|
3849
|
+
triggerRef: rootRef,
|
|
3850
|
+
onClose: () => setOpen(false),
|
|
3851
|
+
placement: "bottom-start",
|
|
3852
|
+
offset: 6,
|
|
3853
|
+
role: "presentation",
|
|
3854
|
+
style: { width: "max-content", zIndex: 130 },
|
|
3855
|
+
children: /* @__PURE__ */ jsx50(
|
|
3856
|
+
Calendar,
|
|
3857
|
+
{
|
|
3858
|
+
range,
|
|
3859
|
+
months: range ? 2 : 1,
|
|
3860
|
+
value,
|
|
3861
|
+
onPick: (v) => {
|
|
3862
|
+
onChange && onChange({ target: { value: v } });
|
|
3863
|
+
if (!range || v.start && v.end) setOpen(false);
|
|
3864
|
+
}
|
|
3819
3865
|
}
|
|
3820
|
-
|
|
3821
|
-
|
|
3822
|
-
|
|
3823
|
-
) : null,
|
|
3866
|
+
)
|
|
3867
|
+
}
|
|
3868
|
+
),
|
|
3824
3869
|
error ? /* @__PURE__ */ jsxs45("span", { className: "fd-field-error", children: [
|
|
3825
3870
|
/* @__PURE__ */ jsx50("i", { className: "ph ph-warning-circle", "aria-hidden": "true" }),
|
|
3826
3871
|
error
|
|
@@ -3829,61 +3874,18 @@ function DatePicker({ label, help, error, required = false, disabled = false, ra
|
|
|
3829
3874
|
}
|
|
3830
3875
|
|
|
3831
3876
|
// src/components/forms/TimePicker.tsx
|
|
3832
|
-
import * as
|
|
3833
|
-
import { createPortal as createPortal7 } from "react-dom";
|
|
3877
|
+
import * as React24 from "react";
|
|
3834
3878
|
import { jsx as jsx51, jsxs as jsxs46 } from "react/jsx-runtime";
|
|
3835
3879
|
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
3880
|
function ClockFace({ value = "09:00", onChange }) {
|
|
3879
3881
|
let [h24, m] = value.split(":").map(Number);
|
|
3880
3882
|
if (isNaN(h24)) h24 = 9;
|
|
3881
3883
|
if (isNaN(m)) m = 0;
|
|
3882
3884
|
const pm = h24 >= 12;
|
|
3883
3885
|
const h12 = h24 % 12 === 0 ? 12 : h24 % 12;
|
|
3884
|
-
const [mode2, setMode] =
|
|
3885
|
-
const faceRef =
|
|
3886
|
-
const dragging =
|
|
3886
|
+
const [mode2, setMode] = React24.useState("h");
|
|
3887
|
+
const faceRef = React24.useRef(null);
|
|
3888
|
+
const dragging = React24.useRef(false);
|
|
3887
3889
|
const set = (h, mm, isPm) => onChange((isPm ? h % 12 + 12 : h % 12) + ":" + pad(mm));
|
|
3888
3890
|
const R = 108, NR = 80;
|
|
3889
3891
|
const nums = mode2 === "h" ? Array.from({ length: 12 }, (_, i) => i + 1) : Array.from({ length: 12 }, (_, i) => i * 5);
|
|
@@ -3956,28 +3958,9 @@ function ClockFace({ value = "09:00", onChange }) {
|
|
|
3956
3958
|
}
|
|
3957
3959
|
function TimePicker({ label, help, error, required = false, disabled = false, value = "", onChange, placeholder = "Pick a time", id, className = "", style }) {
|
|
3958
3960
|
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]);
|
|
3961
|
+
const [open, setOpen] = React24.useState(false);
|
|
3962
|
+
const rootRef = React24.useRef(null);
|
|
3963
|
+
const boxRef = React24.useRef(null);
|
|
3981
3964
|
const disp = () => {
|
|
3982
3965
|
if (!value) return "";
|
|
3983
3966
|
const [h, m] = value.split(":").map(Number);
|
|
@@ -4009,10 +3992,19 @@ function TimePicker({ label, help, error, required = false, disabled = false, va
|
|
|
4009
3992
|
),
|
|
4010
3993
|
/* @__PURE__ */ jsx51("span", { className: "fd-select-caret", children: /* @__PURE__ */ jsx51("i", { className: "ph ph-caret-down", "aria-hidden": "true" }) })
|
|
4011
3994
|
] }),
|
|
4012
|
-
|
|
4013
|
-
|
|
4014
|
-
|
|
4015
|
-
|
|
3995
|
+
/* @__PURE__ */ jsx51(
|
|
3996
|
+
Popover,
|
|
3997
|
+
{
|
|
3998
|
+
open,
|
|
3999
|
+
anchorRef: boxRef,
|
|
4000
|
+
triggerRef: rootRef,
|
|
4001
|
+
onClose: () => setOpen(false),
|
|
4002
|
+
placement: "bottom-start",
|
|
4003
|
+
offset: 6,
|
|
4004
|
+
width: 262,
|
|
4005
|
+
role: "presentation",
|
|
4006
|
+
style: { zIndex: 130 },
|
|
4007
|
+
footer: /* @__PURE__ */ jsxs46(React24.Fragment, { children: [
|
|
4016
4008
|
/* @__PURE__ */ jsx51(
|
|
4017
4009
|
"button",
|
|
4018
4010
|
{
|
|
@@ -4028,10 +4020,10 @@ function TimePicker({ label, help, error, required = false, disabled = false, va
|
|
|
4028
4020
|
),
|
|
4029
4021
|
/* @__PURE__ */ jsx51("span", { style: { flex: 1 } }),
|
|
4030
4022
|
/* @__PURE__ */ jsx51("button", { type: "button", className: "fd-btn fd-btn-primary fd-btn-sm", onClick: () => setOpen(false), children: "Done" })
|
|
4031
|
-
] })
|
|
4032
|
-
|
|
4033
|
-
|
|
4034
|
-
)
|
|
4023
|
+
] }),
|
|
4024
|
+
children: /* @__PURE__ */ jsx51(ClockFace, { value: value || "09:00", onChange: (v) => onChange && onChange({ target: { value: v } }) })
|
|
4025
|
+
}
|
|
4026
|
+
),
|
|
4035
4027
|
error ? /* @__PURE__ */ jsxs46("span", { className: "fd-field-error", children: [
|
|
4036
4028
|
/* @__PURE__ */ jsx51("i", { className: "ph ph-warning-circle", "aria-hidden": "true" }),
|
|
4037
4029
|
error
|
|
@@ -4040,7 +4032,7 @@ function TimePicker({ label, help, error, required = false, disabled = false, va
|
|
|
4040
4032
|
}
|
|
4041
4033
|
|
|
4042
4034
|
// src/components/forms/Slider.tsx
|
|
4043
|
-
import * as
|
|
4035
|
+
import * as React25 from "react";
|
|
4044
4036
|
import { jsx as jsx52, jsxs as jsxs47 } from "react/jsx-runtime";
|
|
4045
4037
|
function Slider({
|
|
4046
4038
|
label,
|
|
@@ -4058,7 +4050,7 @@ function Slider({
|
|
|
4058
4050
|
...rest
|
|
4059
4051
|
}) {
|
|
4060
4052
|
const fieldId = useFieldId(id);
|
|
4061
|
-
const [dragging, setDragging] =
|
|
4053
|
+
const [dragging, setDragging] = React25.useState(false);
|
|
4062
4054
|
const v = value === void 0 ? min : Number(value);
|
|
4063
4055
|
const pct = max === min ? 0 : (v - min) / (max - min) * 100;
|
|
4064
4056
|
return /* @__PURE__ */ jsxs47("div", { className: ["fd-field", className].filter(Boolean).join(" "), children: [
|
|
@@ -4092,7 +4084,7 @@ function Slider({
|
|
|
4092
4084
|
}
|
|
4093
4085
|
|
|
4094
4086
|
// src/components/forms/RangeSlider.tsx
|
|
4095
|
-
import * as
|
|
4087
|
+
import * as React26 from "react";
|
|
4096
4088
|
import { jsx as jsx53, jsxs as jsxs48 } from "react/jsx-runtime";
|
|
4097
4089
|
function RangeSlider({
|
|
4098
4090
|
label,
|
|
@@ -4112,9 +4104,9 @@ function RangeSlider({
|
|
|
4112
4104
|
}) {
|
|
4113
4105
|
const fmt2 = format || ((v) => String(v));
|
|
4114
4106
|
const [a, b] = value || [min, max];
|
|
4115
|
-
const [drag, setDrag] =
|
|
4116
|
-
const [focus, setFocus] =
|
|
4117
|
-
const railRef =
|
|
4107
|
+
const [drag, setDrag] = React26.useState(null);
|
|
4108
|
+
const [focus, setFocus] = React26.useState(null);
|
|
4109
|
+
const railRef = React26.useRef(null);
|
|
4118
4110
|
const pct = (v) => max === min ? 0 : (v - min) / (max - min) * 100;
|
|
4119
4111
|
const clampPair = (i, v) => {
|
|
4120
4112
|
v = Math.min(max, Math.max(min, Math.round(v / step) * step));
|
|
@@ -4129,7 +4121,7 @@ function RangeSlider({
|
|
|
4129
4121
|
const r = railRef.current.getBoundingClientRect();
|
|
4130
4122
|
return min + Math.min(1, Math.max(0, (e.clientX - r.left) / r.width)) * (max - min);
|
|
4131
4123
|
};
|
|
4132
|
-
|
|
4124
|
+
React26.useEffect(() => {
|
|
4133
4125
|
if (drag === null) return;
|
|
4134
4126
|
const mv = (e) => onChange && onChange(clampPair(drag, fromEvent(e)));
|
|
4135
4127
|
const upH = () => setDrag(null);
|
|
@@ -4210,7 +4202,7 @@ function RangeSlider({
|
|
|
4210
4202
|
/* @__PURE__ */ jsxs48("div", { className: "fd-range" + (hasLabels ? " has-labels" : ""), onPointerDown: onRailDown, children: [
|
|
4211
4203
|
/* @__PURE__ */ jsx53("span", { className: "fd-range-rail", ref: railRef }),
|
|
4212
4204
|
/* @__PURE__ */ jsx53("span", { className: "fd-range-fill", style: { left: pct(a) + "%", width: pct(b) - pct(a) + "%" } }),
|
|
4213
|
-
marks.map((m) => /* @__PURE__ */ jsxs48(
|
|
4205
|
+
marks.map((m) => /* @__PURE__ */ jsxs48(React26.Fragment, { children: [
|
|
4214
4206
|
/* @__PURE__ */ jsx53("span", { className: "fd-range-mark" + (m.value >= a && m.value <= b ? " is-in" : ""), style: { left: pct(m.value) + "%" } }),
|
|
4215
4207
|
m.label ? /* @__PURE__ */ jsx53("span", { className: "fd-range-mark-label", style: { left: pct(m.value) + "%" }, children: m.label }) : null
|
|
4216
4208
|
] }, m.value)),
|
|
@@ -4239,7 +4231,7 @@ function RangeSlider({
|
|
|
4239
4231
|
}
|
|
4240
4232
|
|
|
4241
4233
|
// src/components/forms/Dropzone.tsx
|
|
4242
|
-
import * as
|
|
4234
|
+
import * as React27 from "react";
|
|
4243
4235
|
import { jsx as jsx54, jsxs as jsxs49 } from "react/jsx-runtime";
|
|
4244
4236
|
function Dropzone({
|
|
4245
4237
|
onFiles,
|
|
@@ -4254,8 +4246,8 @@ function Dropzone({
|
|
|
4254
4246
|
className = "",
|
|
4255
4247
|
style
|
|
4256
4248
|
}) {
|
|
4257
|
-
const [over, setOver] =
|
|
4258
|
-
const depth =
|
|
4249
|
+
const [over, setOver] = React27.useState(false);
|
|
4250
|
+
const depth = React27.useRef(0);
|
|
4259
4251
|
const has = (e) => {
|
|
4260
4252
|
const dt = e.dataTransfer;
|
|
4261
4253
|
if (!dt) return false;
|
|
@@ -4317,8 +4309,8 @@ function FilePickButton({
|
|
|
4317
4309
|
className = "",
|
|
4318
4310
|
children
|
|
4319
4311
|
}) {
|
|
4320
|
-
const ref =
|
|
4321
|
-
return /* @__PURE__ */ jsxs49(
|
|
4312
|
+
const ref = React27.useRef(null);
|
|
4313
|
+
return /* @__PURE__ */ jsxs49(React27.Fragment, { children: [
|
|
4322
4314
|
/* @__PURE__ */ jsx54(
|
|
4323
4315
|
"button",
|
|
4324
4316
|
{
|
|
@@ -4351,10 +4343,10 @@ function FilePickButton({
|
|
|
4351
4343
|
}
|
|
4352
4344
|
function useStagedFiles(upload, opts) {
|
|
4353
4345
|
const o = opts || {};
|
|
4354
|
-
const [items, setItems] =
|
|
4355
|
-
const controllers =
|
|
4346
|
+
const [items, setItems] = React27.useState([]);
|
|
4347
|
+
const controllers = React27.useRef({});
|
|
4356
4348
|
const patch = (id, next) => setItems((list) => list.map((f) => f.id === id ? Object.assign({}, f, next) : f));
|
|
4357
|
-
const run =
|
|
4349
|
+
const run = React27.useCallback((att) => {
|
|
4358
4350
|
if (!upload) return;
|
|
4359
4351
|
const ac = typeof AbortController !== "undefined" ? new AbortController() : null;
|
|
4360
4352
|
controllers.current[att.id] = ac;
|
|
@@ -4371,14 +4363,14 @@ function useStagedFiles(upload, opts) {
|
|
|
4371
4363
|
delete controllers.current[att.id];
|
|
4372
4364
|
});
|
|
4373
4365
|
}, [upload]);
|
|
4374
|
-
const add =
|
|
4366
|
+
const add = React27.useCallback((files) => {
|
|
4375
4367
|
if (!upload) return [];
|
|
4376
4368
|
const atts = Array.from(files).map((f) => toAttachment(f));
|
|
4377
4369
|
setItems((list) => list.concat(atts));
|
|
4378
4370
|
atts.forEach(run);
|
|
4379
4371
|
return atts;
|
|
4380
4372
|
}, [upload, run]);
|
|
4381
|
-
const remove =
|
|
4373
|
+
const remove = React27.useCallback((att) => {
|
|
4382
4374
|
const ac = controllers.current[att.id];
|
|
4383
4375
|
if (ac) {
|
|
4384
4376
|
try {
|
|
@@ -4389,10 +4381,10 @@ function useStagedFiles(upload, opts) {
|
|
|
4389
4381
|
}
|
|
4390
4382
|
setItems((list) => list.filter((f) => f.id !== att.id));
|
|
4391
4383
|
}, []);
|
|
4392
|
-
const retry =
|
|
4384
|
+
const retry = React27.useCallback((att) => {
|
|
4393
4385
|
run(att);
|
|
4394
4386
|
}, [run]);
|
|
4395
|
-
const clear =
|
|
4387
|
+
const clear = React27.useCallback(() => {
|
|
4396
4388
|
Object.values(controllers.current).forEach((ac) => {
|
|
4397
4389
|
try {
|
|
4398
4390
|
ac && ac.abort();
|
|
@@ -4516,7 +4508,7 @@ function FileGrid({ files = [], onOpen, onRemove, onRetry, tiles = true, maxHeig
|
|
|
4516
4508
|
}
|
|
4517
4509
|
|
|
4518
4510
|
// src/components/forms/MarkdownEditor.tsx
|
|
4519
|
-
import * as
|
|
4511
|
+
import * as React28 from "react";
|
|
4520
4512
|
import { jsx as jsx56, jsxs as jsxs51 } from "react/jsx-runtime";
|
|
4521
4513
|
var isMac = typeof navigator !== "undefined" && /Mac|iPhone|iPad/.test(navigator.platform || navigator.userAgent || "");
|
|
4522
4514
|
var INLINE_RE = /(\*\*\*[^*\n]+\*\*\*|\*\*[^*\n]+\*\*|__[^_\n]+__|~~[^~\n]+~~|`[^`\n]+`|\*[^*\s][^*\n]*\*|(?<![A-Za-z0-9_])_[^_\s][^_\n]*_|\[[^\]\n]*\]\([^)\s\n]*\)|https?:\/\/\S+)/g;
|
|
@@ -4730,7 +4722,7 @@ function syncDom(root, value) {
|
|
|
4730
4722
|
while (root.children.length > lines.length) root.removeChild(root.lastChild);
|
|
4731
4723
|
}
|
|
4732
4724
|
var LIST_CONT = RE_LI;
|
|
4733
|
-
var MarkdownEditor =
|
|
4725
|
+
var MarkdownEditor = React28.forwardRef(function MarkdownEditor2({
|
|
4734
4726
|
value = "",
|
|
4735
4727
|
onChange,
|
|
4736
4728
|
onSubmit,
|
|
@@ -4749,10 +4741,10 @@ var MarkdownEditor = React27.forwardRef(function MarkdownEditor2({
|
|
|
4749
4741
|
className = "",
|
|
4750
4742
|
id
|
|
4751
4743
|
}, ref) {
|
|
4752
|
-
const boxRef =
|
|
4753
|
-
const composing =
|
|
4754
|
-
const pendingCaret =
|
|
4755
|
-
|
|
4744
|
+
const boxRef = React28.useRef(null);
|
|
4745
|
+
const composing = React28.useRef(false);
|
|
4746
|
+
const pendingCaret = React28.useRef(null);
|
|
4747
|
+
React28.useLayoutEffect(() => {
|
|
4756
4748
|
const root = boxRef.current;
|
|
4757
4749
|
if (!root || composing.current) return;
|
|
4758
4750
|
const active = document.activeElement === root || root.contains(document.activeElement);
|
|
@@ -4761,7 +4753,7 @@ var MarkdownEditor = React27.forwardRef(function MarkdownEditor2({
|
|
|
4761
4753
|
pendingCaret.current = null;
|
|
4762
4754
|
if (active && caret != null) placeCaret(root, caret);
|
|
4763
4755
|
}, [value]);
|
|
4764
|
-
|
|
4756
|
+
React28.useEffect(() => {
|
|
4765
4757
|
if (autoFocus && boxRef.current) boxRef.current.focus();
|
|
4766
4758
|
}, [autoFocus]);
|
|
4767
4759
|
const caretNow = () => {
|
|
@@ -4828,7 +4820,7 @@ var MarkdownEditor = React27.forwardRef(function MarkdownEditor2({
|
|
|
4828
4820
|
api.replaceRange(from, to, next, from + next.length);
|
|
4829
4821
|
}
|
|
4830
4822
|
};
|
|
4831
|
-
|
|
4823
|
+
React28.useImperativeHandle(ref, () => api);
|
|
4832
4824
|
function detect(text, caret) {
|
|
4833
4825
|
if (!onTrigger) return;
|
|
4834
4826
|
const upto = text.slice(0, caret);
|
|
@@ -4980,10 +4972,10 @@ var MarkdownEditor = React27.forwardRef(function MarkdownEditor2({
|
|
|
4980
4972
|
});
|
|
4981
4973
|
|
|
4982
4974
|
// src/components/platform/AccountMenu.tsx
|
|
4983
|
-
import * as
|
|
4975
|
+
import * as React30 from "react";
|
|
4984
4976
|
|
|
4985
4977
|
// src/kits/session.ts
|
|
4986
|
-
import * as
|
|
4978
|
+
import * as React29 from "react";
|
|
4987
4979
|
var PERMISSION_CATALOG = [
|
|
4988
4980
|
{ group: "Plans", items: [
|
|
4989
4981
|
{ key: "plan.view", label: "View plans", detail: "Read any plan in the workspace." },
|
|
@@ -6550,8 +6542,8 @@ function roadmap(overrides) {
|
|
|
6550
6542
|
};
|
|
6551
6543
|
}
|
|
6552
6544
|
function useSession() {
|
|
6553
|
-
const [s, setS] =
|
|
6554
|
-
|
|
6545
|
+
const [s, setS] = React29.useState(getSession);
|
|
6546
|
+
React29.useEffect(() => subscribe(setS), []);
|
|
6555
6547
|
return s;
|
|
6556
6548
|
}
|
|
6557
6549
|
var SessionKit = {
|
|
@@ -6584,7 +6576,7 @@ var SessionKit = {
|
|
|
6584
6576
|
};
|
|
6585
6577
|
|
|
6586
6578
|
// src/components/platform/AccountMenu.tsx
|
|
6587
|
-
import { Fragment as
|
|
6579
|
+
import { Fragment as Fragment14, jsx as jsx57, jsxs as jsxs52 } from "react/jsx-runtime";
|
|
6588
6580
|
var DEFAULT_LINKS = [
|
|
6589
6581
|
{ id: "profile", label: "Your profile", icon: "user-circle", href: "../admin/index.html#profile" },
|
|
6590
6582
|
{ id: "preferences", label: "Preferences", icon: "sliders-horizontal", href: "../admin/index.html#preferences" }
|
|
@@ -6621,9 +6613,9 @@ function AccountMenu({
|
|
|
6621
6613
|
...rest
|
|
6622
6614
|
}) {
|
|
6623
6615
|
const session = SessionKit.useSession();
|
|
6624
|
-
const [open, setOpen] =
|
|
6625
|
-
const [switching, setSwitching] =
|
|
6626
|
-
const ref =
|
|
6616
|
+
const [open, setOpen] = React30.useState(false);
|
|
6617
|
+
const [switching, setSwitching] = React30.useState(false);
|
|
6618
|
+
const ref = React30.useRef(null);
|
|
6627
6619
|
const user = session.user;
|
|
6628
6620
|
const visibleAdmin = adminLinks.filter((l) => !l.perm || SessionKit.can(l.perm));
|
|
6629
6621
|
const pick = (item) => {
|
|
@@ -6637,7 +6629,7 @@ function AccountMenu({
|
|
|
6637
6629
|
if (onSignOut) return onSignOut();
|
|
6638
6630
|
window.alert("Signed out. (Simulated \u2014 no auth provider is wired up.)");
|
|
6639
6631
|
};
|
|
6640
|
-
return /* @__PURE__ */ jsxs52(
|
|
6632
|
+
return /* @__PURE__ */ jsxs52(Fragment14, { children: [
|
|
6641
6633
|
/* @__PURE__ */ jsxs52(
|
|
6642
6634
|
"button",
|
|
6643
6635
|
{
|
|
@@ -6675,7 +6667,7 @@ function AccountMenu({
|
|
|
6675
6667
|
/* @__PURE__ */ jsx57("span", { style: { flex: 1 }, children: "View as another member" }),
|
|
6676
6668
|
/* @__PURE__ */ jsx57("i", { className: "ph ph-caret-" + (switching ? "up" : "down"), "aria-hidden": "true", style: { fontSize: 11 } })
|
|
6677
6669
|
] }),
|
|
6678
|
-
switching ? /* @__PURE__ */ jsx57("div", { className: "fd-stack", style: { gap: 0
|
|
6670
|
+
switching ? /* @__PURE__ */ jsx57("div", { className: "fd-stack", style: { gap: 0 }, children: session.allUsers.filter((u) => u.status === "active").map((u) => /* @__PURE__ */ jsxs52(
|
|
6679
6671
|
"button",
|
|
6680
6672
|
{
|
|
6681
6673
|
type: "button",
|
|
@@ -6707,14 +6699,14 @@ function AccountMenu({
|
|
|
6707
6699
|
}
|
|
6708
6700
|
|
|
6709
6701
|
// src/components/platform/ApiSpecBrowser.tsx
|
|
6710
|
-
import * as
|
|
6702
|
+
import * as React31 from "react";
|
|
6711
6703
|
import { jsx as jsx58, jsxs as jsxs53 } from "react/jsx-runtime";
|
|
6712
6704
|
var METHOD_TONE = { GET: "success", POST: "info", PATCH: "warning", PUT: "warning", DELETE: "danger" };
|
|
6713
6705
|
function Json({ obj }) {
|
|
6714
6706
|
return /* @__PURE__ */ jsx58("pre", { className: "fd-json", children: JSON.stringify(obj, null, 2) });
|
|
6715
6707
|
}
|
|
6716
6708
|
function Endpoint({ s, onRequest }) {
|
|
6717
|
-
const [tried, setTried] =
|
|
6709
|
+
const [tried, setTried] = React31.useState(null);
|
|
6718
6710
|
const run = async () => {
|
|
6719
6711
|
setTried("busy");
|
|
6720
6712
|
const t0 = (window.performance || Date).now();
|
|
@@ -6787,10 +6779,10 @@ function ApiSpecBrowser({
|
|
|
6787
6779
|
className = "",
|
|
6788
6780
|
...rest
|
|
6789
6781
|
}) {
|
|
6790
|
-
const [q, setQ] =
|
|
6791
|
-
const [method, setMethod] =
|
|
6792
|
-
const [mod, setMod] =
|
|
6793
|
-
const [listOnly, setListOnly] =
|
|
6782
|
+
const [q, setQ] = React31.useState("");
|
|
6783
|
+
const [method, setMethod] = React31.useState(null);
|
|
6784
|
+
const [mod, setMod] = React31.useState(null);
|
|
6785
|
+
const [listOnly, setListOnly] = React31.useState(false);
|
|
6794
6786
|
const activeModule = modules && modules.find((m) => m.id === mod);
|
|
6795
6787
|
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
6788
|
const effGroups = groups && groups.length ? groups : [["All endpoints", spec.map((s) => s.id)]];
|
|
@@ -6869,7 +6861,7 @@ function ApiSpecBrowser({
|
|
|
6869
6861
|
}
|
|
6870
6862
|
|
|
6871
6863
|
// src/components/platform/ProfilePage.tsx
|
|
6872
|
-
import * as
|
|
6864
|
+
import * as React32 from "react";
|
|
6873
6865
|
import { jsx as jsx59, jsxs as jsxs54 } from "react/jsx-runtime";
|
|
6874
6866
|
var TIMEZONES = ["America/New_York", "America/Chicago", "America/Denver", "America/Los_Angeles", "America/Anchorage", "Pacific/Honolulu", "Europe/London", "Europe/Berlin"];
|
|
6875
6867
|
var NOTIFY = [
|
|
@@ -6882,7 +6874,7 @@ var NOTIFY = [
|
|
|
6882
6874
|
function ProfilePage({ user: userProp, onSave, onNavigate, sessions, showSessions = true, className = "", ...rest }) {
|
|
6883
6875
|
const session = SessionKit.useSession();
|
|
6884
6876
|
const user = userProp || session.user;
|
|
6885
|
-
const [draft, setDraft] =
|
|
6877
|
+
const [draft, setDraft] = React32.useState(() => ({
|
|
6886
6878
|
name: user.name || "",
|
|
6887
6879
|
title: user.title || "",
|
|
6888
6880
|
email: user.email || "",
|
|
@@ -6891,8 +6883,8 @@ function ProfilePage({ user: userProp, onSave, onNavigate, sessions, showSession
|
|
|
6891
6883
|
bio: user.bio || "",
|
|
6892
6884
|
notify: user.notify || { planShared: true, planChanged: true, goalMissed: true, flagChanged: false, weekly: true }
|
|
6893
6885
|
}));
|
|
6894
|
-
const [saving, setSaving] =
|
|
6895
|
-
const [saved, setSaved] =
|
|
6886
|
+
const [saving, setSaving] = React32.useState(false);
|
|
6887
|
+
const [saved, setSaved] = React32.useState(false);
|
|
6896
6888
|
const set = (k, v) => {
|
|
6897
6889
|
setDraft((d) => Object.assign({}, d, { [k]: v }));
|
|
6898
6890
|
setSaved(false);
|
|
@@ -7082,10 +7074,10 @@ function ProfilePage({ user: userProp, onSave, onNavigate, sessions, showSession
|
|
|
7082
7074
|
}
|
|
7083
7075
|
|
|
7084
7076
|
// src/components/platform/RoadmapTimeline.tsx
|
|
7085
|
-
import * as
|
|
7077
|
+
import * as React34 from "react";
|
|
7086
7078
|
|
|
7087
7079
|
// src/kits/runtime.ts
|
|
7088
|
-
import * as
|
|
7080
|
+
import * as React33 from "react";
|
|
7089
7081
|
var WIRED_ENDPOINTS = [
|
|
7090
7082
|
// Nothing yet. Every id below would come from a real service:
|
|
7091
7083
|
// "plan.get", "placements.list", …
|
|
@@ -7256,8 +7248,8 @@ var RuntimeKit = {
|
|
|
7256
7248
|
};
|
|
7257
7249
|
RuntimeKit.declare(FEATURE_NEEDS);
|
|
7258
7250
|
function useRuntimeMode() {
|
|
7259
|
-
const [m, setM] =
|
|
7260
|
-
|
|
7251
|
+
const [m, setM] = React33.useState(RuntimeKit.getMode());
|
|
7252
|
+
React33.useEffect(() => RuntimeKit.subscribe(setM), []);
|
|
7261
7253
|
return m;
|
|
7262
7254
|
}
|
|
7263
7255
|
function useFeatureStatus(key) {
|
|
@@ -7340,12 +7332,12 @@ function RoadmapCard({ item, byKey, onOpenFlag }) {
|
|
|
7340
7332
|
}
|
|
7341
7333
|
function RoadmapTimeline({ onOpenFlag, title = "Roadmap", lede }) {
|
|
7342
7334
|
const session = SessionKit.useSession();
|
|
7343
|
-
const [project, setProject] =
|
|
7344
|
-
const [q, setQ] =
|
|
7345
|
-
const scrollRef =
|
|
7346
|
-
const nowRef =
|
|
7347
|
-
const rm =
|
|
7348
|
-
const byKey =
|
|
7335
|
+
const [project, setProject] = React34.useState("");
|
|
7336
|
+
const [q, setQ] = React34.useState("");
|
|
7337
|
+
const scrollRef = React34.useRef(null);
|
|
7338
|
+
const nowRef = React34.useRef(null);
|
|
7339
|
+
const rm = React34.useMemo(() => SessionKit.roadmap({ isComplete: RuntimeKit.isComplete }), [session]);
|
|
7340
|
+
const byKey = React34.useMemo(() => {
|
|
7349
7341
|
const m = {};
|
|
7350
7342
|
rm.items.forEach((i) => {
|
|
7351
7343
|
m[i.key] = i;
|
|
@@ -7354,7 +7346,7 @@ function RoadmapTimeline({ onOpenFlag, title = "Roadmap", lede }) {
|
|
|
7354
7346
|
}, [rm]);
|
|
7355
7347
|
const items = rm.items.filter((i) => (!project || i.project === project) && (!q || (i.label + " " + i.description + " " + (i.backend || "") + " " + i.key).toLowerCase().includes(q.toLowerCase())));
|
|
7356
7348
|
const projects = [...new Set(rm.items.map((i) => i.project))];
|
|
7357
|
-
|
|
7349
|
+
React34.useEffect(() => {
|
|
7358
7350
|
let raf1 = 0, raf2 = 0;
|
|
7359
7351
|
const place = () => {
|
|
7360
7352
|
const box = scrollRef.current, mark = nowRef.current;
|
|
@@ -7428,7 +7420,7 @@ function RoadmapTimeline({ onOpenFlag, title = "Roadmap", lede }) {
|
|
|
7428
7420
|
lastPhase = item.phase;
|
|
7429
7421
|
const inPhase = items.filter((i) => i.phase === item.phase).length;
|
|
7430
7422
|
const isBoundary = n === firstPending;
|
|
7431
|
-
return /* @__PURE__ */ jsxs55(
|
|
7423
|
+
return /* @__PURE__ */ jsxs55(React34.Fragment, { children: [
|
|
7432
7424
|
showPhase ? /* @__PURE__ */ jsxs55("div", { className: "fd-rm-era", children: [
|
|
7433
7425
|
/* @__PURE__ */ jsxs55("span", { className: "fd-row", style: { gap: 8, flexWrap: "wrap", alignItems: "baseline" }, children: [
|
|
7434
7426
|
/* @__PURE__ */ jsx60("span", { style: { fontWeight: 700 }, children: item.phase === 0 ? "Shipped" : "Phase " + item.phase + " \u2014 " + item.phaseName }),
|
|
@@ -7472,9 +7464,9 @@ function RoadmapTimeline({ onOpenFlag, title = "Roadmap", lede }) {
|
|
|
7472
7464
|
}
|
|
7473
7465
|
|
|
7474
7466
|
// src/components/platform/ComingSoon.tsx
|
|
7475
|
-
import * as
|
|
7476
|
-
import { createPortal as
|
|
7477
|
-
import { Fragment as
|
|
7467
|
+
import * as React35 from "react";
|
|
7468
|
+
import { createPortal as createPortal5 } from "react-dom";
|
|
7469
|
+
import { Fragment as Fragment16, jsx as jsx61, jsxs as jsxs56 } from "react/jsx-runtime";
|
|
7478
7470
|
var BYPASS_STORE = "fd.soon.bypass.v1";
|
|
7479
7471
|
function readBypassed() {
|
|
7480
7472
|
try {
|
|
@@ -7490,8 +7482,8 @@ function writeBypassed(list) {
|
|
|
7490
7482
|
}
|
|
7491
7483
|
}
|
|
7492
7484
|
function useBypass(key) {
|
|
7493
|
-
const [on, setOn] =
|
|
7494
|
-
|
|
7485
|
+
const [on, setOn] = React35.useState(() => !!key && readBypassed().indexOf(key) >= 0);
|
|
7486
|
+
React35.useEffect(() => {
|
|
7495
7487
|
setOn(!!key && readBypassed().indexOf(key) >= 0);
|
|
7496
7488
|
}, [key]);
|
|
7497
7489
|
const set = (next) => {
|
|
@@ -7504,7 +7496,7 @@ function useBypass(key) {
|
|
|
7504
7496
|
return [on, set];
|
|
7505
7497
|
}
|
|
7506
7498
|
function SoonCard({ label, detail, backend, eta, effort, onRoadmap, allowed, onBypass }) {
|
|
7507
|
-
return /* @__PURE__ */ jsxs56(
|
|
7499
|
+
return /* @__PURE__ */ jsxs56(Fragment16, { children: [
|
|
7508
7500
|
/* @__PURE__ */ jsxs56("span", { className: "fd-soon-badge", children: [
|
|
7509
7501
|
/* @__PURE__ */ jsx61("i", { className: "ph ph-traffic-cone", "aria-hidden": "true" }),
|
|
7510
7502
|
label
|
|
@@ -7538,9 +7530,9 @@ function SoonCard({ label, detail, backend, eta, effort, onRoadmap, allowed, onB
|
|
|
7538
7530
|
] });
|
|
7539
7531
|
}
|
|
7540
7532
|
function useHoverCard(open) {
|
|
7541
|
-
const anchor =
|
|
7542
|
-
const [pos, setPos] =
|
|
7543
|
-
|
|
7533
|
+
const anchor = React35.useRef(null);
|
|
7534
|
+
const [pos, setPos] = React35.useState(null);
|
|
7535
|
+
React35.useLayoutEffect(() => {
|
|
7544
7536
|
if (!open || !anchor.current) {
|
|
7545
7537
|
setPos(null);
|
|
7546
7538
|
return;
|
|
@@ -7667,9 +7659,9 @@ function ComingSoon({
|
|
|
7667
7659
|
] });
|
|
7668
7660
|
}
|
|
7669
7661
|
function InlineSoon({ label, detail, backend, eta, effort, onRoadmap, allowed, onBypass, blur, tip, className, rest, children }) {
|
|
7670
|
-
const [open, setOpen] =
|
|
7662
|
+
const [open, setOpen] = React35.useState(false);
|
|
7671
7663
|
const [anchor, pos] = useHoverCard(open);
|
|
7672
|
-
const close =
|
|
7664
|
+
const close = React35.useRef(null);
|
|
7673
7665
|
const show = () => {
|
|
7674
7666
|
if (close.current) {
|
|
7675
7667
|
clearTimeout(close.current);
|
|
@@ -7685,7 +7677,7 @@ function InlineSoon({ label, detail, backend, eta, effort, onRoadmap, allowed, o
|
|
|
7685
7677
|
setOpen(false);
|
|
7686
7678
|
}, 140);
|
|
7687
7679
|
};
|
|
7688
|
-
|
|
7680
|
+
React35.useEffect(() => () => {
|
|
7689
7681
|
if (close.current) clearTimeout(close.current);
|
|
7690
7682
|
}, []);
|
|
7691
7683
|
return /* @__PURE__ */ jsxs56(
|
|
@@ -7714,7 +7706,7 @@ function InlineSoon({ label, detail, backend, eta, effort, onRoadmap, allowed, o
|
|
|
7714
7706
|
children: /* @__PURE__ */ jsx61("i", { className: "ph ph-traffic-cone", "aria-hidden": "true" })
|
|
7715
7707
|
}
|
|
7716
7708
|
),
|
|
7717
|
-
open && pos ?
|
|
7709
|
+
open && pos ? createPortal5(
|
|
7718
7710
|
/* @__PURE__ */ jsx61(
|
|
7719
7711
|
"div",
|
|
7720
7712
|
{
|
|
@@ -7854,13 +7846,13 @@ function PermissionHint({ perm, children }) {
|
|
|
7854
7846
|
}
|
|
7855
7847
|
|
|
7856
7848
|
// src/components/platform/ModeSwitch.tsx
|
|
7857
|
-
import * as
|
|
7858
|
-
import { Fragment as
|
|
7849
|
+
import * as React36 from "react";
|
|
7850
|
+
import { Fragment as Fragment17, jsx as jsx63, jsxs as jsxs58 } from "react/jsx-runtime";
|
|
7859
7851
|
function ModeSwitch({ canToggle = false, requestCount = 0, onClearLog, renderLog, onOpenSpec, summary }) {
|
|
7860
7852
|
const mode2 = useRuntimeMode();
|
|
7861
|
-
const [open, setOpen] =
|
|
7862
|
-
const ref =
|
|
7863
|
-
|
|
7853
|
+
const [open, setOpen] = React36.useState(false);
|
|
7854
|
+
const ref = React36.useRef(null);
|
|
7855
|
+
React36.useEffect(() => {
|
|
7864
7856
|
if (!open) return;
|
|
7865
7857
|
const away = (e) => {
|
|
7866
7858
|
if (ref.current && !ref.current.contains(e.target)) setOpen(false);
|
|
@@ -7925,7 +7917,7 @@ function ModeSwitch({ canToggle = false, requestCount = 0, onClearLog, renderLog
|
|
|
7925
7917
|
s.total,
|
|
7926
7918
|
" features complete"
|
|
7927
7919
|
] }),
|
|
7928
|
-
onOpenSpec ? /* @__PURE__ */ jsxs58(
|
|
7920
|
+
onOpenSpec ? /* @__PURE__ */ jsxs58(Fragment17, { children: [
|
|
7929
7921
|
/* @__PURE__ */ jsx63("span", { style: { flex: 1 } }),
|
|
7930
7922
|
/* @__PURE__ */ jsxs58("button", { type: "button", className: "fd-soon-link", onClick: () => {
|
|
7931
7923
|
setOpen(false);
|
|
@@ -8109,11 +8101,11 @@ function SaturationDistribution({ campuses = [], floorBand, floorScore, onSelect
|
|
|
8109
8101
|
}
|
|
8110
8102
|
|
|
8111
8103
|
// src/components/planner/MixGap.tsx
|
|
8112
|
-
import * as
|
|
8113
|
-
import { Fragment as
|
|
8104
|
+
import * as React37 from "react";
|
|
8105
|
+
import { Fragment as Fragment18, jsx as jsx66, jsxs as jsxs61 } from "react/jsx-runtime";
|
|
8114
8106
|
function MixGap({ rows = [], loading = false, className = "" }) {
|
|
8115
8107
|
const max = Math.max(1, ...rows.flatMap((r) => [r.target, r.realized]));
|
|
8116
|
-
const [hover, setHover] =
|
|
8108
|
+
const [hover, setHover] = React37.useState(null);
|
|
8117
8109
|
const toneOf = (gap) => gap >= -1 ? "ok" : gap >= -4 ? "warn" : "danger";
|
|
8118
8110
|
const TONE = { ok: "var(--ok-solid)", warn: "var(--warn-solid)", danger: "var(--danger-solid)" };
|
|
8119
8111
|
return /* @__PURE__ */ jsxs61("div", { className: ["fd-stack", className].filter(Boolean).join(" "), style: { gap: 4 }, children: [
|
|
@@ -8140,7 +8132,7 @@ function MixGap({ rows = [], loading = false, className = "" }) {
|
|
|
8140
8132
|
onMouseLeave: () => setHover(null),
|
|
8141
8133
|
children: [
|
|
8142
8134
|
/* @__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(
|
|
8135
|
+
/* @__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
8136
|
/* @__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
8137
|
/* @__PURE__ */ jsx66("span", { style: { position: "absolute", left: r.target / max * 100 + "%", top: 0, width: 3, height: 22, background: "var(--n-500)", borderRadius: 1 } }),
|
|
8146
8138
|
/* @__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 +8245,8 @@ function ChannelContribution({
|
|
|
8253
8245
|
}
|
|
8254
8246
|
|
|
8255
8247
|
// src/components/planner/BudgetReallocator.tsx
|
|
8256
|
-
import * as
|
|
8257
|
-
import { Fragment as
|
|
8248
|
+
import * as React38 from "react";
|
|
8249
|
+
import { Fragment as Fragment19, jsx as jsx68, jsxs as jsxs63 } from "react/jsx-runtime";
|
|
8258
8250
|
var bandFor = (crp) => crp >= 200 ? "dominant" : crp >= 100 ? "strong" : crp >= 50 ? "adequate" : "weak";
|
|
8259
8251
|
function BudgetReallocator({
|
|
8260
8252
|
campus,
|
|
@@ -8269,8 +8261,8 @@ function BudgetReallocator({
|
|
|
8269
8261
|
onCancel,
|
|
8270
8262
|
className = ""
|
|
8271
8263
|
}) {
|
|
8272
|
-
const [draft, setDraft] =
|
|
8273
|
-
|
|
8264
|
+
const [draft, setDraft] = React38.useState(spend);
|
|
8265
|
+
React38.useEffect(() => setDraft(spend), [spend]);
|
|
8274
8266
|
const dirty = draft !== spend;
|
|
8275
8267
|
const nextCrp = scoreFor ? scoreFor(draft) : crp;
|
|
8276
8268
|
const nextBand = bandFor(nextCrp);
|
|
@@ -8294,7 +8286,7 @@ function BudgetReallocator({
|
|
|
8294
8286
|
/* @__PURE__ */ jsxs63("div", { className: "fd-row", style: { gap: 12, flexWrap: "wrap" }, children: [
|
|
8295
8287
|
/* @__PURE__ */ jsx68("span", { className: "fd-h4", style: { flex: 1, minWidth: 140 }, children: campus }),
|
|
8296
8288
|
/* @__PURE__ */ jsx68(CsiBadge, { band: nowBand, crp, size: "medium" }),
|
|
8297
|
-
dirty ? /* @__PURE__ */ jsxs63(
|
|
8289
|
+
dirty ? /* @__PURE__ */ jsxs63(Fragment19, { children: [
|
|
8298
8290
|
/* @__PURE__ */ jsx68("i", { className: "ph ph-arrow-right fd-muted", "aria-hidden": "true" }),
|
|
8299
8291
|
/* @__PURE__ */ jsx68(CsiBadge, { band: nextBand, crp: nextCrp, size: "medium", preview: true })
|
|
8300
8292
|
] }) : null
|
|
@@ -8440,7 +8432,7 @@ function ImportanceTag({ level, showLabel = true, size = "sm", className = "" })
|
|
|
8440
8432
|
}
|
|
8441
8433
|
|
|
8442
8434
|
// src/components/planner/PreferenceMeter.tsx
|
|
8443
|
-
import * as
|
|
8435
|
+
import * as React39 from "react";
|
|
8444
8436
|
import { jsx as jsx71, jsxs as jsxs66 } from "react/jsx-runtime";
|
|
8445
8437
|
function preferenceScore(criteria) {
|
|
8446
8438
|
const earned = criteria.reduce((n, c) => n + (Number(c.earned) || 0), 0);
|
|
@@ -8470,7 +8462,7 @@ function PreferenceMeter({
|
|
|
8470
8462
|
className = ""
|
|
8471
8463
|
}) {
|
|
8472
8464
|
const value = score == null ? preferenceScore(criteria) : score;
|
|
8473
|
-
const segments =
|
|
8465
|
+
const segments = React39.useMemo(() => preferenceSegments(criteria), [criteria]);
|
|
8474
8466
|
return /* @__PURE__ */ jsx71(
|
|
8475
8467
|
ScoreMeter,
|
|
8476
8468
|
{
|
|
@@ -8509,10 +8501,10 @@ function PreferenceMeter({
|
|
|
8509
8501
|
}
|
|
8510
8502
|
|
|
8511
8503
|
// src/components/chat/AgentChatPanel.tsx
|
|
8512
|
-
import * as
|
|
8504
|
+
import * as React45 from "react";
|
|
8513
8505
|
|
|
8514
8506
|
// src/components/chat/chatEngine.ts
|
|
8515
|
-
import * as
|
|
8507
|
+
import * as React40 from "react";
|
|
8516
8508
|
var CHAT_UNAVAILABLE = "chat_unavailable";
|
|
8517
8509
|
var JOB_PENDING = ["queued", "running"];
|
|
8518
8510
|
var JOB_SUCCESS = ["completed", "recovered"];
|
|
@@ -8566,22 +8558,22 @@ function useChatEngine(opts) {
|
|
|
8566
8558
|
onClear,
|
|
8567
8559
|
onFeedback
|
|
8568
8560
|
} = 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
|
-
|
|
8561
|
+
const [status, setStatus] = React40.useState("idle");
|
|
8562
|
+
const [threadId, setThreadId] = React40.useState(null);
|
|
8563
|
+
const [messages, setMessages] = React40.useState([]);
|
|
8564
|
+
const [queue, setQueue] = React40.useState([]);
|
|
8565
|
+
const [fatal, setFatal] = React40.useState(null);
|
|
8566
|
+
const [busy, setBusy] = React40.useState(false);
|
|
8567
|
+
const [turnStartedAt, setTurnStartedAt] = React40.useState(null);
|
|
8568
|
+
const listRef = React40.useRef([]);
|
|
8569
|
+
const queueRef = React40.useRef([]);
|
|
8570
|
+
const busyRef = React40.useRef(false);
|
|
8571
|
+
const stoppedRef = React40.useRef(false);
|
|
8572
|
+
const abortRef = React40.useRef(null);
|
|
8573
|
+
const serverCount = React40.useRef(0);
|
|
8574
|
+
const threadRef = React40.useRef(null);
|
|
8575
|
+
const mounted = React40.useRef(true);
|
|
8576
|
+
React40.useEffect(() => {
|
|
8585
8577
|
mounted.current = true;
|
|
8586
8578
|
return () => {
|
|
8587
8579
|
mounted.current = false;
|
|
@@ -8603,14 +8595,14 @@ function useChatEngine(opts) {
|
|
|
8603
8595
|
}
|
|
8604
8596
|
return false;
|
|
8605
8597
|
};
|
|
8606
|
-
const loadThread =
|
|
8598
|
+
const loadThread = React40.useCallback(async (id) => {
|
|
8607
8599
|
const data = await apiAdapter.getThread(id);
|
|
8608
8600
|
const list = [...data && data.messages || []];
|
|
8609
8601
|
serverCount.current = list.length;
|
|
8610
8602
|
commit(list);
|
|
8611
8603
|
return list;
|
|
8612
8604
|
}, [apiAdapter]);
|
|
8613
|
-
|
|
8605
|
+
React40.useEffect(() => {
|
|
8614
8606
|
if (!apiAdapter) {
|
|
8615
8607
|
setStatus("idle");
|
|
8616
8608
|
setFatal(null);
|
|
@@ -8823,7 +8815,7 @@ function useChatEngine(opts) {
|
|
|
8823
8815
|
await dispatchTurn(turn);
|
|
8824
8816
|
}
|
|
8825
8817
|
}
|
|
8826
|
-
const send =
|
|
8818
|
+
const send = React40.useCallback((text, attachments) => {
|
|
8827
8819
|
const body = (text || "").trim();
|
|
8828
8820
|
if (!body && !(attachments && attachments.length)) return;
|
|
8829
8821
|
if (status === "disconnected") return;
|
|
@@ -8833,7 +8825,7 @@ function useChatEngine(opts) {
|
|
|
8833
8825
|
stoppedRef.current = false;
|
|
8834
8826
|
drain();
|
|
8835
8827
|
}, [status]);
|
|
8836
|
-
const stop =
|
|
8828
|
+
const stop = React40.useCallback(() => {
|
|
8837
8829
|
stoppedRef.current = true;
|
|
8838
8830
|
const ac = abortRef.current;
|
|
8839
8831
|
if (ac) {
|
|
@@ -8852,11 +8844,11 @@ function useChatEngine(opts) {
|
|
|
8852
8844
|
store.del(STORAGE_PREFIX + threadRef.current);
|
|
8853
8845
|
}
|
|
8854
8846
|
}, [apiAdapter]);
|
|
8855
|
-
const removeQueued =
|
|
8847
|
+
const removeQueued = React40.useCallback((id) => {
|
|
8856
8848
|
queueRef.current = queueRef.current.filter((t) => t.id !== id);
|
|
8857
8849
|
setQueue(queueRef.current.slice());
|
|
8858
8850
|
}, []);
|
|
8859
|
-
const retry =
|
|
8851
|
+
const retry = React40.useCallback(() => {
|
|
8860
8852
|
const list = listRef.current;
|
|
8861
8853
|
let at = -1;
|
|
8862
8854
|
for (let i = list.length - 1; i >= 0; i--) if (list[i].role === "user") {
|
|
@@ -8872,19 +8864,19 @@ function useChatEngine(opts) {
|
|
|
8872
8864
|
setQueue(queueRef.current.slice());
|
|
8873
8865
|
drain();
|
|
8874
8866
|
}, []);
|
|
8875
|
-
const clear =
|
|
8867
|
+
const clear = React40.useCallback(() => {
|
|
8876
8868
|
commit([]);
|
|
8877
8869
|
serverCount.current = 0;
|
|
8878
8870
|
queueRef.current = [];
|
|
8879
8871
|
setQueue([]);
|
|
8880
8872
|
onClear && onClear();
|
|
8881
8873
|
}, [onClear]);
|
|
8882
|
-
const setFeedback =
|
|
8874
|
+
const setFeedback = React40.useCallback((id, value) => {
|
|
8883
8875
|
patch(id, (m) => ({ feedback: m.feedback === value ? null : value }));
|
|
8884
8876
|
const msg = listRef.current.find((m) => m.id === id);
|
|
8885
8877
|
onFeedback && onFeedback({ message: msg, feedback: msg ? msg.feedback : value });
|
|
8886
8878
|
}, [onFeedback]);
|
|
8887
|
-
const reload =
|
|
8879
|
+
const reload = React40.useCallback(async () => {
|
|
8888
8880
|
if (!threadRef.current) return;
|
|
8889
8881
|
setStatus("loading");
|
|
8890
8882
|
try {
|
|
@@ -8922,10 +8914,10 @@ var ChatKit = {
|
|
|
8922
8914
|
};
|
|
8923
8915
|
|
|
8924
8916
|
// src/components/chat/ChatTranscript.tsx
|
|
8925
|
-
import * as
|
|
8917
|
+
import * as React42 from "react";
|
|
8926
8918
|
|
|
8927
8919
|
// src/components/chat/ChatTurn.tsx
|
|
8928
|
-
import * as
|
|
8920
|
+
import * as React41 from "react";
|
|
8929
8921
|
import { jsx as jsx72, jsxs as jsxs67 } from "react/jsx-runtime";
|
|
8930
8922
|
function JsonView({ value }) {
|
|
8931
8923
|
let text;
|
|
@@ -8962,7 +8954,7 @@ function PacketCard({ packet, schema, render, onApply, applied }) {
|
|
|
8962
8954
|
] });
|
|
8963
8955
|
}
|
|
8964
8956
|
function ThinkingBlock({ text, durationMs, streaming, defaultOpen = false }) {
|
|
8965
|
-
const [open, setOpen] =
|
|
8957
|
+
const [open, setOpen] = React41.useState(defaultOpen);
|
|
8966
8958
|
if (!text) return null;
|
|
8967
8959
|
return /* @__PURE__ */ jsxs67("div", { className: "fdc-think" + (open ? " is-open" : ""), children: [
|
|
8968
8960
|
/* @__PURE__ */ jsxs67("button", { type: "button", className: "fdc-think-head", onClick: () => setOpen((v) => !v), "aria-expanded": open, children: [
|
|
@@ -8979,7 +8971,7 @@ function ThinkingBlock({ text, durationMs, streaming, defaultOpen = false }) {
|
|
|
8979
8971
|
] });
|
|
8980
8972
|
}
|
|
8981
8973
|
function Citations({ items = [], onOpen }) {
|
|
8982
|
-
const [open, setOpen] =
|
|
8974
|
+
const [open, setOpen] = React41.useState(false);
|
|
8983
8975
|
if (!items.length) return null;
|
|
8984
8976
|
return /* @__PURE__ */ jsxs67("div", { className: "fdc-cites", children: [
|
|
8985
8977
|
/* @__PURE__ */ jsxs67("button", { type: "button", className: "fdc-cites-head", onClick: () => setOpen((v) => !v), "aria-expanded": open, children: [
|
|
@@ -9005,7 +8997,7 @@ function clampText(text, max) {
|
|
|
9005
8997
|
return (at > max * 0.6 ? cut.slice(0, at) : cut).trimEnd() + "\u2026";
|
|
9006
8998
|
}
|
|
9007
8999
|
function MessageBody({ message: m, ctx }) {
|
|
9008
|
-
const [expanded, setExpanded] =
|
|
9000
|
+
const [expanded, setExpanded] = React41.useState(false);
|
|
9009
9001
|
const isUser = m.role === "user";
|
|
9010
9002
|
const raw = m.text || "";
|
|
9011
9003
|
const clamped = !expanded && !m.streaming ? clampText(raw, ctx.maxVisibleChars) : null;
|
|
@@ -9072,9 +9064,9 @@ function MessageBody({ message: m, ctx }) {
|
|
|
9072
9064
|
] });
|
|
9073
9065
|
}
|
|
9074
9066
|
function useCopyRun() {
|
|
9075
|
-
const [done, setDone] =
|
|
9076
|
-
const t =
|
|
9077
|
-
|
|
9067
|
+
const [done, setDone] = React41.useState(false);
|
|
9068
|
+
const t = React41.useRef(null);
|
|
9069
|
+
React41.useEffect(() => () => {
|
|
9078
9070
|
if (t.current) clearTimeout(t.current);
|
|
9079
9071
|
}, []);
|
|
9080
9072
|
return [done, (text) => {
|
|
@@ -9101,7 +9093,7 @@ function RunActions({ group, ctx }) {
|
|
|
9101
9093
|
] }),
|
|
9102
9094
|
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
9095
|
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(
|
|
9096
|
+
isAssistant && ctx.onFeedback ? /* @__PURE__ */ jsxs67(React41.Fragment, { children: [
|
|
9105
9097
|
/* @__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
9098
|
/* @__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
9099
|
] }) : null,
|
|
@@ -9196,10 +9188,10 @@ function ChatTranscript({
|
|
|
9196
9188
|
renderEmpty,
|
|
9197
9189
|
className = ""
|
|
9198
9190
|
}) {
|
|
9199
|
-
const scroller =
|
|
9200
|
-
const stick =
|
|
9201
|
-
const [pill, setPill] =
|
|
9202
|
-
const seen =
|
|
9191
|
+
const scroller = React42.useRef(null);
|
|
9192
|
+
const stick = React42.useRef(true);
|
|
9193
|
+
const [pill, setPill] = React42.useState(0);
|
|
9194
|
+
const seen = React42.useRef(0);
|
|
9203
9195
|
const toBottom = (smooth) => {
|
|
9204
9196
|
const el = scroller.current;
|
|
9205
9197
|
if (!el) return;
|
|
@@ -9218,7 +9210,7 @@ function ChatTranscript({
|
|
|
9218
9210
|
seen.current = messages.length;
|
|
9219
9211
|
}
|
|
9220
9212
|
};
|
|
9221
|
-
|
|
9213
|
+
React42.useLayoutEffect(() => {
|
|
9222
9214
|
const el = scroller.current;
|
|
9223
9215
|
if (!el) return;
|
|
9224
9216
|
if (stick.current) {
|
|
@@ -9226,7 +9218,7 @@ function ChatTranscript({
|
|
|
9226
9218
|
seen.current = messages.length;
|
|
9227
9219
|
} else setPill(Math.max(0, messages.length - seen.current));
|
|
9228
9220
|
}, [messages]);
|
|
9229
|
-
|
|
9221
|
+
React42.useEffect(() => {
|
|
9230
9222
|
const el = scroller.current;
|
|
9231
9223
|
const inner = el && el.firstChild;
|
|
9232
9224
|
if (!el || !inner || typeof ResizeObserver === "undefined") return;
|
|
@@ -9236,7 +9228,7 @@ function ChatTranscript({
|
|
|
9236
9228
|
ro.observe(inner);
|
|
9237
9229
|
return () => ro.disconnect();
|
|
9238
9230
|
}, []);
|
|
9239
|
-
const groups =
|
|
9231
|
+
const groups = React42.useMemo(() => groupMessages(messages), [messages]);
|
|
9240
9232
|
const empty = !messages.length && status === "ready";
|
|
9241
9233
|
return /* @__PURE__ */ jsxs68("div", { className: ["fdc-scroll", className].filter(Boolean).join(" "), ref: scroller, onScroll, children: [
|
|
9242
9234
|
/* @__PURE__ */ jsxs68("div", { className: "fdc-log", role: "log", "aria-label": "Conversation", children: [
|
|
@@ -9260,7 +9252,7 @@ function ChatTranscript({
|
|
|
9260
9252
|
const prev = groups[i - 1];
|
|
9261
9253
|
const k = dayKey(g.messages[0].timestamp);
|
|
9262
9254
|
const showDay = !!k && (!prev || dayKey(prev.messages[0].timestamp) !== k);
|
|
9263
|
-
return /* @__PURE__ */ jsxs68(
|
|
9255
|
+
return /* @__PURE__ */ jsxs68(React42.Fragment, { children: [
|
|
9264
9256
|
showDay ? /* @__PURE__ */ jsx73("div", { className: "fdc-day", children: /* @__PURE__ */ jsx73("span", { children: dayLabel(k) }) }) : null,
|
|
9265
9257
|
/* @__PURE__ */ jsx73(ChatTurn, { group: g, ctx })
|
|
9266
9258
|
] }, g.key || i);
|
|
@@ -9277,7 +9269,7 @@ function ChatTranscript({
|
|
|
9277
9269
|
var TranscriptKit = { groupMessages };
|
|
9278
9270
|
|
|
9279
9271
|
// src/components/chat/ChatComposer.tsx
|
|
9280
|
-
import * as
|
|
9272
|
+
import * as React43 from "react";
|
|
9281
9273
|
import { jsx as jsx74, jsxs as jsxs69 } from "react/jsx-runtime";
|
|
9282
9274
|
function ChatComposer({
|
|
9283
9275
|
onSubmit,
|
|
@@ -9305,17 +9297,17 @@ function ChatComposer({
|
|
|
9305
9297
|
onReject,
|
|
9306
9298
|
onOpenAttachment
|
|
9307
9299
|
}) {
|
|
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 =
|
|
9300
|
+
const [text, setText] = React43.useState(draft || "");
|
|
9301
|
+
const [trigger, setTrigger] = React43.useState(null);
|
|
9302
|
+
const [mentionItems, setMentionItems] = React43.useState([]);
|
|
9303
|
+
const [listening, setListening] = React43.useState(false);
|
|
9304
|
+
const [notice, setNotice] = React43.useState(null);
|
|
9305
|
+
const editor = React43.useRef(null);
|
|
9306
|
+
const wrap = React43.useRef(null);
|
|
9307
|
+
const stopVoice = React43.useRef(null);
|
|
9316
9308
|
const staged = useStagedFiles(fileUploadHandler, { onError: () => {
|
|
9317
9309
|
} });
|
|
9318
|
-
|
|
9310
|
+
React43.useEffect(() => {
|
|
9319
9311
|
if (draft != null && draft !== text) setText(draft);
|
|
9320
9312
|
}, [draft]);
|
|
9321
9313
|
const change = (v) => {
|
|
@@ -9349,7 +9341,7 @@ function ChatComposer({
|
|
|
9349
9341
|
e.preventDefault();
|
|
9350
9342
|
staged.add(found.files);
|
|
9351
9343
|
};
|
|
9352
|
-
|
|
9344
|
+
React43.useEffect(() => {
|
|
9353
9345
|
if (!trigger || trigger.type !== "mention" || !mentionSources) {
|
|
9354
9346
|
setMentionItems([]);
|
|
9355
9347
|
return;
|
|
@@ -9367,7 +9359,7 @@ function ChatComposer({
|
|
|
9367
9359
|
const q = (trigger.query || "").toLowerCase();
|
|
9368
9360
|
setMentionItems(mentionSources.filter((m) => !q || (m.label + " " + (m.description || "")).toLowerCase().includes(q)));
|
|
9369
9361
|
}, [trigger, mentionSources]);
|
|
9370
|
-
const slashItems =
|
|
9362
|
+
const slashItems = React43.useMemo(() => {
|
|
9371
9363
|
if (!trigger || trigger.type !== "slash" || !slashCommands) return [];
|
|
9372
9364
|
const q = (trigger.query || "").toLowerCase();
|
|
9373
9365
|
return slashCommands.filter((c) => !q || (c.id + " " + c.label + " " + (c.description || "")).toLowerCase().includes(q));
|
|
@@ -9541,12 +9533,12 @@ function ChatComposer({
|
|
|
9541
9533
|
}
|
|
9542
9534
|
|
|
9543
9535
|
// src/components/chat/ChatSessionBar.tsx
|
|
9544
|
-
import * as
|
|
9536
|
+
import * as React44 from "react";
|
|
9545
9537
|
import { jsx as jsx75, jsxs as jsxs70 } from "react/jsx-runtime";
|
|
9546
9538
|
var compact2 = meterFormats.compact;
|
|
9547
9539
|
function ChatSessionBar({ sessionStats, contextUsage, usageLimits, onClear, extras }) {
|
|
9548
|
-
const [open, setOpen] =
|
|
9549
|
-
const anchor =
|
|
9540
|
+
const [open, setOpen] = React44.useState(false);
|
|
9541
|
+
const anchor = React44.useRef(null);
|
|
9550
9542
|
const stats = sessionStats || null;
|
|
9551
9543
|
const cu = contextUsage || null;
|
|
9552
9544
|
const limits = usageLimits || null;
|
|
@@ -9561,7 +9553,7 @@ function ChatSessionBar({ sessionStats, contextUsage, usageLimits, onClear, extr
|
|
|
9561
9553
|
if (stats && stats.runningTasks) bits.push(stats.runningTasks + " running task" + (stats.runningTasks === 1 ? "" : "s"));
|
|
9562
9554
|
if (cu) bits.push(pct + "% context");
|
|
9563
9555
|
const expandable = !!(cu || limits);
|
|
9564
|
-
return /* @__PURE__ */ jsxs70(
|
|
9556
|
+
return /* @__PURE__ */ jsxs70(React44.Fragment, { children: [
|
|
9565
9557
|
/* @__PURE__ */ jsxs70("div", { className: "fdc-bar", children: [
|
|
9566
9558
|
/* @__PURE__ */ jsxs70(
|
|
9567
9559
|
"button",
|
|
@@ -9582,60 +9574,73 @@ function ChatSessionBar({ sessionStats, contextUsage, usageLimits, onClear, extr
|
|
|
9582
9574
|
),
|
|
9583
9575
|
extras
|
|
9584
9576
|
] }),
|
|
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
|
-
|
|
9577
|
+
/* @__PURE__ */ jsx75(
|
|
9578
|
+
Popover,
|
|
9579
|
+
{
|
|
9580
|
+
open,
|
|
9581
|
+
anchorRef: anchor,
|
|
9582
|
+
placement: "top-start",
|
|
9583
|
+
onClose: () => setOpen(false),
|
|
9584
|
+
minWidth: 330,
|
|
9585
|
+
maxHeight: 460,
|
|
9586
|
+
padded: true,
|
|
9587
|
+
label: "Usage",
|
|
9588
|
+
footer: onClear ? /* @__PURE__ */ jsxs70("button", { type: "button", className: "fdc-usage-clear", onClick: () => {
|
|
9589
|
+
setOpen(false);
|
|
9590
|
+
onClear();
|
|
9591
|
+
}, children: [
|
|
9592
|
+
/* @__PURE__ */ jsx75("i", { className: "ph ph-trash", "aria-hidden": "true" }),
|
|
9593
|
+
"Clear conversation"
|
|
9594
|
+
] }) : void 0,
|
|
9595
|
+
children: /* @__PURE__ */ jsxs70("div", { className: "fdc-usage", children: [
|
|
9596
|
+
cu ? /* @__PURE__ */ jsx75("section", { className: "fdc-usage-sec", children: /* @__PURE__ */ jsx75(
|
|
9597
|
+
SegmentedMeter,
|
|
9598
|
+
{
|
|
9599
|
+
total,
|
|
9600
|
+
segments: cu.segments,
|
|
9601
|
+
label: cu.label || "Context window",
|
|
9602
|
+
format: cu.format === "bytes" ? meterFormats.bytes : compact2,
|
|
9603
|
+
height: 8,
|
|
9604
|
+
legend: true,
|
|
9605
|
+
remainderLabel: "Free"
|
|
9606
|
+
}
|
|
9607
|
+
) }) : null,
|
|
9608
|
+
limits && limits.length ? /* @__PURE__ */ jsxs70("section", { className: "fdc-usage-sec", children: [
|
|
9609
|
+
/* @__PURE__ */ jsx75("h4", { className: "fdc-usage-h", children: "Usage limits" }),
|
|
9610
|
+
/* @__PURE__ */ jsx75("div", { className: "fdc-usage-rows", children: limits.map((l) => /* @__PURE__ */ jsx75(
|
|
9611
|
+
QuotaRow,
|
|
9612
|
+
{
|
|
9613
|
+
label: l.label,
|
|
9614
|
+
percent: l.percent,
|
|
9615
|
+
note: l.resetsAt ? "Resets " + formatRelative(l.resetsAt) : l.note
|
|
9616
|
+
},
|
|
9617
|
+
l.id
|
|
9618
|
+
)) })
|
|
9619
|
+
] }) : null,
|
|
9620
|
+
stats ? /* @__PURE__ */ jsxs70("section", { className: "fdc-usage-sec fdc-usage-stats", children: [
|
|
9621
|
+
stats.elapsedMs ? /* @__PURE__ */ jsxs70("div", { children: [
|
|
9622
|
+
/* @__PURE__ */ jsx75("span", { children: "Session" }),
|
|
9623
|
+
/* @__PURE__ */ jsx75("b", { className: "fd-tabular", children: formatDuration(stats.elapsedMs) })
|
|
9624
|
+
] }) : null,
|
|
9625
|
+
stats.tokens ? /* @__PURE__ */ jsxs70("div", { children: [
|
|
9626
|
+
/* @__PURE__ */ jsx75("span", { children: "Tokens" }),
|
|
9627
|
+
/* @__PURE__ */ jsx75("b", { className: "fd-tabular", children: stats.tokens.toLocaleString() })
|
|
9628
|
+
] }) : null,
|
|
9629
|
+
stats.costUsd != null ? /* @__PURE__ */ jsxs70("div", { children: [
|
|
9630
|
+
/* @__PURE__ */ jsx75("span", { children: "Cost" }),
|
|
9631
|
+
/* @__PURE__ */ jsxs70("b", { className: "fd-tabular", children: [
|
|
9632
|
+
"$",
|
|
9633
|
+
Number(stats.costUsd).toFixed(3)
|
|
9634
|
+
] })
|
|
9635
|
+
] }) : null,
|
|
9636
|
+
stats.turns ? /* @__PURE__ */ jsxs70("div", { children: [
|
|
9637
|
+
/* @__PURE__ */ jsx75("span", { children: "Turns" }),
|
|
9638
|
+
/* @__PURE__ */ jsx75("b", { className: "fd-tabular", children: stats.turns })
|
|
9639
|
+
] }) : null
|
|
9640
|
+
] }) : null
|
|
9641
|
+
] })
|
|
9642
|
+
}
|
|
9643
|
+
)
|
|
9639
9644
|
] });
|
|
9640
9645
|
}
|
|
9641
9646
|
function ModelControls({
|
|
@@ -9689,7 +9694,7 @@ function ModelControls({
|
|
|
9689
9694
|
] })
|
|
9690
9695
|
});
|
|
9691
9696
|
}
|
|
9692
|
-
return /* @__PURE__ */ jsxs70(
|
|
9697
|
+
return /* @__PURE__ */ jsxs70(React44.Fragment, { children: [
|
|
9693
9698
|
/* @__PURE__ */ jsx75(
|
|
9694
9699
|
MenuButton,
|
|
9695
9700
|
{
|
|
@@ -9806,11 +9811,11 @@ function AgentChatPanel({
|
|
|
9806
9811
|
onFeedback,
|
|
9807
9812
|
onEditMessage
|
|
9808
9813
|
}) {
|
|
9809
|
-
const [panelWidth, setPanelWidth] =
|
|
9810
|
-
const [applied, setApplied] =
|
|
9811
|
-
const [draft, setDraft] =
|
|
9812
|
-
const dragging =
|
|
9813
|
-
|
|
9814
|
+
const [panelWidth, setPanelWidth] = React45.useState(width);
|
|
9815
|
+
const [applied, setApplied] = React45.useState({});
|
|
9816
|
+
const [draft, setDraft] = React45.useState("");
|
|
9817
|
+
const dragging = React45.useRef(null);
|
|
9818
|
+
React45.useEffect(() => setPanelWidth(width), [width]);
|
|
9814
9819
|
const engine = useChatEngine({
|
|
9815
9820
|
contextType,
|
|
9816
9821
|
contextId,
|
|
@@ -10014,7 +10019,7 @@ function AgentChatPanel({
|
|
|
10014
10019
|
}
|
|
10015
10020
|
|
|
10016
10021
|
// src/kits/query.ts
|
|
10017
|
-
import * as
|
|
10022
|
+
import * as React46 from "react";
|
|
10018
10023
|
function eqFilter(get2) {
|
|
10019
10024
|
return (row, value) => Array.isArray(value) ? value.includes(get2(row)) : get2(row) === value;
|
|
10020
10025
|
}
|
|
@@ -10046,22 +10051,22 @@ function compare(a, b, dir) {
|
|
|
10046
10051
|
var API = null;
|
|
10047
10052
|
var PREFS = null;
|
|
10048
10053
|
function useServerTable({ endpoint, params, defaults, deps, prefsKey }) {
|
|
10049
|
-
const [query, setQuery] =
|
|
10054
|
+
const [query, setQuery] = React46.useState(() => {
|
|
10050
10055
|
const store = PREFS || window.PlannerPrefs;
|
|
10051
10056
|
const saved = prefsKey && store ? store.getTable(prefsKey) : {};
|
|
10052
10057
|
return { ...DEFAULTS, ...defaults || {}, ...saved.pageSize ? { pageSize: saved.pageSize } : {}, ...saved.sort ? { sort: saved.sort, dir: saved.dir || "desc" } : {} };
|
|
10053
10058
|
});
|
|
10054
|
-
const savePref =
|
|
10059
|
+
const savePref = React46.useCallback((patch2) => {
|
|
10055
10060
|
const store = PREFS || window.PlannerPrefs;
|
|
10056
10061
|
if (prefsKey && store) store.setTable(prefsKey, patch2);
|
|
10057
10062
|
}, [prefsKey]);
|
|
10058
|
-
const [res, setRes] =
|
|
10059
|
-
const [loading, setLoading] =
|
|
10060
|
-
const seq2 =
|
|
10063
|
+
const [res, setRes] = React46.useState(null);
|
|
10064
|
+
const [loading, setLoading] = React46.useState(true);
|
|
10065
|
+
const seq2 = React46.useRef(0);
|
|
10061
10066
|
const depKey = (deps || []).join("|");
|
|
10062
10067
|
const paramKey = JSON.stringify(params || {});
|
|
10063
10068
|
const queryKey = JSON.stringify(query);
|
|
10064
|
-
|
|
10069
|
+
React46.useEffect(() => {
|
|
10065
10070
|
const id = ++seq2.current;
|
|
10066
10071
|
setLoading(true);
|
|
10067
10072
|
const t = setTimeout(() => {
|
|
@@ -10435,6 +10440,7 @@ export {
|
|
|
10435
10440
|
ModeSwitch,
|
|
10436
10441
|
ModelControls,
|
|
10437
10442
|
NumberInput,
|
|
10443
|
+
POPOVER_BODY_MIN,
|
|
10438
10444
|
PacketCard,
|
|
10439
10445
|
Pagination,
|
|
10440
10446
|
PermissionDenied,
|