gridsmith-ui 0.19.0 → 0.20.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/{chunk-5PDTHKW3.js → chunk-6MXHGH3D.js} +40 -9
- package/dist/chunk-6MXHGH3D.js.map +1 -0
- package/dist/chunk-XVB55M3N.js +42 -0
- package/dist/chunk-XVB55M3N.js.map +1 -0
- package/dist/editor.d.ts +38 -2
- package/dist/editor.js +83 -7
- package/dist/editor.js.map +1 -1
- package/dist/index.d.ts +199 -52
- package/dist/index.js +1000 -419
- package/dist/index.js.map +1 -1
- package/dist/resizable.js +1 -1
- package/package.json +1 -1
- package/dist/chunk-5PDTHKW3.js.map +0 -1
package/dist/index.js
CHANGED
|
@@ -1,7 +1,9 @@
|
|
|
1
|
-
import { Button, useAppShell, REACT_VERSION_PROBLEM, ControlSizeContext, useDirtyGuard, OverlayCloseCtx, DiscardConfirm, Spinner, DrawerFooterCtx, useCompact, useElementWidth, Sheet, useCloseSettle, Drawer, useRememberedWidth, pxOf, ResizeEdge, defaultMaxWidth } from './chunk-
|
|
2
|
-
export { AppShell, Button, ButtonSizeContext, ControlSizeContext, Drawer, Sheet, SkipLink, Spinner, useAppShell, useUnsavedChanges } from './chunk-
|
|
1
|
+
import { Button, useAppShell, REACT_VERSION_PROBLEM, ControlSizeContext, useOverlayMark, useDirtyGuard, OverlayMarkCtx, OverlayCloseCtx, DiscardConfirm, Spinner, DrawerFooterCtx, useCompact, useElementWidth, Sheet, useCloseSettle, Drawer, useRememberedWidth, pxOf, ResizeEdge, defaultMaxWidth } from './chunk-6MXHGH3D.js';
|
|
2
|
+
export { AppShell, Button, ButtonSizeContext, ControlSizeContext, Drawer, Sheet, SkipLink, Spinner, useAppShell, useUnsavedChanges } from './chunk-6MXHGH3D.js';
|
|
3
3
|
import { Skeleton, TITLE_TEXT } from './chunk-NCIZQYXQ.js';
|
|
4
4
|
export { Skeleton } from './chunk-NCIZQYXQ.js';
|
|
5
|
+
import { useReportedChange, useOptionalFormContext, FormChangeCtx, FormCtx } from './chunk-XVB55M3N.js';
|
|
6
|
+
export { useFormContext } from './chunk-XVB55M3N.js';
|
|
5
7
|
import { FOCUSABLE, usePopupFocus, FIELD, ZOOM_KEYS, useOverlayLayer, useFocusTrap, useFocusBeforeOpen, rememberFocus, focusInitial, OVERLAY_CLOSE_ATTR, focusAfterRemoval, rovingTabStop, useGridKeyboard, useNonModalDialog, usePressMarks, useReturnFocus, useCloseOnFocusOut } from './chunk-JXANCXK6.js';
|
|
6
8
|
export { useGridKeyboard } from './chunk-JXANCXK6.js';
|
|
7
9
|
import { Link } from './chunk-EQDR57AM.js';
|
|
@@ -115,6 +117,7 @@ function DropdownMenu({ trigger, items, align = "end", className, container }) {
|
|
|
115
117
|
return /* @__PURE__ */ jsxs(
|
|
116
118
|
"button",
|
|
117
119
|
{
|
|
120
|
+
type: "button",
|
|
118
121
|
"data-index": i,
|
|
119
122
|
role: "menuitem",
|
|
120
123
|
disabled: item.disabled,
|
|
@@ -194,6 +197,7 @@ function BulkActionBar({ selectedCount, actions, onClearSelection, className })
|
|
|
194
197
|
/* @__PURE__ */ jsx(
|
|
195
198
|
"button",
|
|
196
199
|
{
|
|
200
|
+
type: "button",
|
|
197
201
|
onClick: onClearSelection,
|
|
198
202
|
className: "ml-auto text-[var(--ds-text-muted)] hover:text-[var(--ds-text-primary)] transition-colors cursor-pointer",
|
|
199
203
|
"aria-label": "Clear selection",
|
|
@@ -204,6 +208,11 @@ function BulkActionBar({ selectedCount, actions, onClearSelection, className })
|
|
|
204
208
|
}
|
|
205
209
|
);
|
|
206
210
|
}
|
|
211
|
+
var valueOf = (e) => {
|
|
212
|
+
const t = e.target;
|
|
213
|
+
if (!t) return void 0;
|
|
214
|
+
return t instanceof HTMLInputElement && (t.type === "checkbox" || t.type === "radio") ? t.checked : t.value;
|
|
215
|
+
};
|
|
207
216
|
var INPUT_HEIGHT = {
|
|
208
217
|
sm: "h-[var(--ds-control-height-sm)]",
|
|
209
218
|
md: "h-[var(--ds-control-height-md)]",
|
|
@@ -217,6 +226,7 @@ var INPUT_TEXT = {
|
|
|
217
226
|
function Input({ className, size: sizeProp, error = false, prefix, suffix, ...props }) {
|
|
218
227
|
const contextSize = useContext(ControlSizeContext);
|
|
219
228
|
const size = sizeProp ?? contextSize ?? "md";
|
|
229
|
+
const onChange = useReportedChange(props.onChange, props.value, valueOf);
|
|
220
230
|
const borderColor = error ? "border-[var(--ds-status-error)]" : "border-[var(--ds-input-border)]";
|
|
221
231
|
const hoverBorder = !error && !props.disabled && !props.readOnly ? "hover:border-[var(--ds-input-border-hover)]" : "";
|
|
222
232
|
if (prefix || suffix) {
|
|
@@ -252,7 +262,8 @@ function Input({ className, size: sizeProp, error = false, prefix, suffix, ...pr
|
|
|
252
262
|
"disabled:cursor-not-allowed",
|
|
253
263
|
"read-only:text-[var(--ds-text-secondary)] read-only:cursor-default"
|
|
254
264
|
),
|
|
255
|
-
...props
|
|
265
|
+
...props,
|
|
266
|
+
onChange: props.onChange || props.value === void 0 ? onChange : void 0
|
|
256
267
|
}
|
|
257
268
|
),
|
|
258
269
|
suffix && /* @__PURE__ */ jsx("span", { className: "shrink-0 pr-ds-3 text-[var(--ds-text-muted)] flex items-center", children: suffix })
|
|
@@ -281,11 +292,13 @@ function Input({ className, size: sizeProp, error = false, prefix, suffix, ...pr
|
|
|
281
292
|
"transition-colors duration-[var(--ds-transition-speed)]",
|
|
282
293
|
className
|
|
283
294
|
),
|
|
284
|
-
...props
|
|
295
|
+
...props,
|
|
296
|
+
onChange: props.onChange || props.value === void 0 ? onChange : void 0
|
|
285
297
|
}
|
|
286
298
|
);
|
|
287
299
|
}
|
|
288
300
|
function Textarea({ className, autoResize, maxRows, error = false, ref, ...props }) {
|
|
301
|
+
const onChange = useReportedChange(props.onChange, props.value, valueOf);
|
|
289
302
|
const internalRef = useRef(null);
|
|
290
303
|
const textareaRef = ref ?? internalRef;
|
|
291
304
|
const resize = useCallback(() => {
|
|
@@ -324,7 +337,8 @@ function Textarea({ className, autoResize, maxRows, error = false, ref, ...props
|
|
|
324
337
|
className
|
|
325
338
|
),
|
|
326
339
|
onInput: autoResize ? resize : void 0,
|
|
327
|
-
...props
|
|
340
|
+
...props,
|
|
341
|
+
onChange: props.onChange || props.value === void 0 ? onChange : void 0
|
|
328
342
|
}
|
|
329
343
|
);
|
|
330
344
|
}
|
|
@@ -347,18 +361,20 @@ var TOGGLE_SIZES = {
|
|
|
347
361
|
md: { w: 44, h: 24, thumb: 16 }
|
|
348
362
|
};
|
|
349
363
|
function Toggle({ checked, onChange, label, disabled, error = false, layout = "full", size = "md", "aria-labelledby": ariaLabelledBy, ...rest }) {
|
|
364
|
+
const change = useReportedChange(onChange, checked);
|
|
350
365
|
const dims = TOGGLE_SIZES[size];
|
|
351
366
|
const travel = dims.w - dims.thumb - 3;
|
|
352
367
|
const switchButton = /* @__PURE__ */ jsx(
|
|
353
368
|
"button",
|
|
354
369
|
{
|
|
370
|
+
type: "button",
|
|
355
371
|
role: "switch",
|
|
356
372
|
"aria-checked": checked,
|
|
357
373
|
"aria-label": !label && !ariaLabelledBy ? "Toggle" : void 0,
|
|
358
374
|
"aria-labelledby": ariaLabelledBy,
|
|
359
375
|
"aria-invalid": error || void 0,
|
|
360
376
|
disabled,
|
|
361
|
-
onClick: () => !disabled &&
|
|
377
|
+
onClick: () => !disabled && change(!checked),
|
|
362
378
|
...rest,
|
|
363
379
|
className: cn(
|
|
364
380
|
"relative inline-flex shrink-0 items-center overflow-hidden",
|
|
@@ -407,15 +423,6 @@ function Toggle({ checked, onChange, label, disabled, error = false, layout = "f
|
|
|
407
423
|
}
|
|
408
424
|
);
|
|
409
425
|
}
|
|
410
|
-
var FormCtx = createContext(null);
|
|
411
|
-
function useFormContext() {
|
|
412
|
-
const ctx = useContext(FormCtx);
|
|
413
|
-
if (!ctx) throw new Error("useFormContext must be used within FormWrapper");
|
|
414
|
-
return ctx;
|
|
415
|
-
}
|
|
416
|
-
function useOptionalFormContext() {
|
|
417
|
-
return useContext(FormCtx);
|
|
418
|
-
}
|
|
419
426
|
function InlineFieldError({ message, id, className }) {
|
|
420
427
|
return /* @__PURE__ */ jsxs(
|
|
421
428
|
"p",
|
|
@@ -454,7 +461,9 @@ function useFieldControl(own, options = {}) {
|
|
|
454
461
|
requiredNote: noteId ? /* @__PURE__ */ jsx("span", { id: noteId, hidden: true, children: "Required" }) : null
|
|
455
462
|
};
|
|
456
463
|
}
|
|
457
|
-
|
|
464
|
+
var AddAnotherRowCtx = createContext(false);
|
|
465
|
+
function Field({ label, children, hint, error, required, labelAction, hideLabel = false, id: idProp, validate, className }) {
|
|
466
|
+
const inGroupRow = useContext(AddAnotherRowCtx);
|
|
458
467
|
const generated = useId();
|
|
459
468
|
const id = idProp ?? `field-${generated}`;
|
|
460
469
|
const hintId = `${id}-hint`;
|
|
@@ -533,6 +542,10 @@ function Field({ label, children, hint, error, required, labelAction, id: idProp
|
|
|
533
542
|
} } : {};
|
|
534
543
|
control = cloneElement(child, isNative ? ariaOnly : { ...ariaOnly, ...errorFlag ? { error: true } : {}, ...onChange });
|
|
535
544
|
}
|
|
545
|
+
const labelNode = /* @__PURE__ */ jsxs(Label, { id: labelId, htmlFor: id, className: cn(hideLabel && "sr-only", hideLabel && inGroupRow && "@max-[30rem]:not-sr-only"), children: [
|
|
546
|
+
label,
|
|
547
|
+
required && /* @__PURE__ */ jsx("span", { "aria-hidden": "true", className: "ml-ds-0.5 text-[var(--ds-status-error)]", children: "*" })
|
|
548
|
+
] });
|
|
536
549
|
return (
|
|
537
550
|
// In a settings panel a field keeps the narrow reading width however wide the page is (--ds-form-max, Sprint 25.9 A4)
|
|
538
551
|
/* @__PURE__ */ jsxs(
|
|
@@ -541,11 +554,8 @@ function Field({ label, children, hint, error, required, labelAction, id: idProp
|
|
|
541
554
|
className: cn("flex flex-col gap-ds-1.5 max-w-[var(--ds-form-max,none)]", className),
|
|
542
555
|
...validate ? { onFocusCapture, onBlurCapture, onInputCapture: recheck } : {},
|
|
543
556
|
children: [
|
|
544
|
-
/* @__PURE__ */ jsxs("div", { className: "flex items-center justify-between gap-ds-2", children: [
|
|
545
|
-
|
|
546
|
-
label,
|
|
547
|
-
required && /* @__PURE__ */ jsx("span", { "aria-hidden": "true", className: "ml-ds-0.5 text-[var(--ds-status-error)]", children: "*" })
|
|
548
|
-
] }),
|
|
557
|
+
hideLabel && !labelAction ? labelNode : /* @__PURE__ */ jsxs("div", { className: "flex items-center justify-between gap-ds-2", children: [
|
|
558
|
+
labelNode,
|
|
549
559
|
labelAction
|
|
550
560
|
] }),
|
|
551
561
|
/* @__PURE__ */ jsx(FieldContext.Provider, { value: fieldContext, children: control }),
|
|
@@ -564,7 +574,7 @@ var DROPDOWN_HEIGHT = {
|
|
|
564
574
|
function Dropdown({
|
|
565
575
|
options,
|
|
566
576
|
value,
|
|
567
|
-
onChange,
|
|
577
|
+
onChange: onChangeProp,
|
|
568
578
|
label,
|
|
569
579
|
disabled,
|
|
570
580
|
placeholder = "Select...",
|
|
@@ -579,6 +589,7 @@ function Dropdown({
|
|
|
579
589
|
"aria-label": ariaLabel,
|
|
580
590
|
...wiring
|
|
581
591
|
}) {
|
|
592
|
+
const onChange = useReportedChange(onChangeProp, value);
|
|
582
593
|
const contextSize = useContext(ControlSizeContext);
|
|
583
594
|
const generatedId = useId();
|
|
584
595
|
const control = useFieldControl({ ...wiring, error: error || void 0 }, { requiredInDescription: true });
|
|
@@ -865,6 +876,7 @@ function Dropdown({
|
|
|
865
876
|
/* @__PURE__ */ jsx(
|
|
866
877
|
"button",
|
|
867
878
|
{
|
|
879
|
+
type: "button",
|
|
868
880
|
"data-chip-remove": "",
|
|
869
881
|
onClick: () => {
|
|
870
882
|
pendingChipFocus.current = { index: i, value: v };
|
|
@@ -932,7 +944,8 @@ var TEXT_SIZE = {
|
|
|
932
944
|
md: "text-sm",
|
|
933
945
|
lg: "text-base"
|
|
934
946
|
};
|
|
935
|
-
function Combobox({ value, onChange, options, placeholder = "Search\u2026", disabled, loading = false, className, ref, container, error = false, size: sizeProp, ...wiring }) {
|
|
947
|
+
function Combobox({ value, onChange: onChangeProp, options, placeholder = "Search\u2026", disabled, loading = false, className, ref, container, error = false, size: sizeProp, ...wiring }) {
|
|
948
|
+
const onChange = useReportedChange(onChangeProp, value);
|
|
936
949
|
const contextSize = useContext(ControlSizeContext);
|
|
937
950
|
const control = useFieldControl({ ...wiring, error: error || void 0 });
|
|
938
951
|
const size = sizeProp ?? contextSize ?? "md";
|
|
@@ -1130,6 +1143,7 @@ function Combobox({ value, onChange, options, placeholder = "Search\u2026", disa
|
|
|
1130
1143
|
children: /* @__PURE__ */ jsx("div", { style: { padding: "var(--ds-space-1)" }, children: loading ? /* @__PURE__ */ jsx("div", { className: "flex items-center justify-center py-ds-4", children: /* @__PURE__ */ jsx(Spinner, { size: "sm", label: "Loading options" }) }) : filtered.length === 0 ? /* @__PURE__ */ jsx("div", { className: "px-ds-2 py-ds-3 text-sm text-[var(--ds-text-muted)] text-center", children: "No results" }) : filtered.map((opt, i) => /* @__PURE__ */ jsxs(
|
|
1131
1144
|
"button",
|
|
1132
1145
|
{
|
|
1146
|
+
type: "button",
|
|
1133
1147
|
id: `${listboxId}-opt-${i}`,
|
|
1134
1148
|
role: "option",
|
|
1135
1149
|
tabIndex: -1,
|
|
@@ -1161,7 +1175,8 @@ var CHECKBOX_SIZES = {
|
|
|
1161
1175
|
sm: { box: "h-[16px] w-[16px]", glyph: 10, label: "text-xs" },
|
|
1162
1176
|
md: { box: "h-[18px] w-[18px]", glyph: 12, label: "text-sm" }
|
|
1163
1177
|
};
|
|
1164
|
-
function Checkbox({ checked, onChange, label, size = "md", disabled = false, indeterminate = false, className, ref }) {
|
|
1178
|
+
function Checkbox({ checked, onChange: onChangeProp, label, size = "md", disabled = false, indeterminate = false, className, ref }) {
|
|
1179
|
+
const onChange = useReportedChange(onChangeProp, checked);
|
|
1165
1180
|
const internalRef = useRef(null);
|
|
1166
1181
|
const dims = CHECKBOX_SIZES[size];
|
|
1167
1182
|
const mergedRef = useCallback(
|
|
@@ -1253,7 +1268,8 @@ function CheckboxGroupItem({ value, label, disabled, groupValue, onGroupChange }
|
|
|
1253
1268
|
}
|
|
1254
1269
|
);
|
|
1255
1270
|
}
|
|
1256
|
-
function RadioGroup({ value, onChange, options, orientation = "vertical", className, label }) {
|
|
1271
|
+
function RadioGroup({ value, onChange: onChangeProp, options, orientation = "vertical", className, label }) {
|
|
1272
|
+
const onChange = useReportedChange(onChangeProp, value);
|
|
1257
1273
|
const groupRef = useRef(null);
|
|
1258
1274
|
const groupId = useId();
|
|
1259
1275
|
const enabledOptions = options.filter((o) => !o.disabled);
|
|
@@ -1478,7 +1494,8 @@ function parseTypedDate(text, dayFirst = localeDayFirst()) {
|
|
|
1478
1494
|
}
|
|
1479
1495
|
return null;
|
|
1480
1496
|
}
|
|
1481
|
-
function DatePicker({ value, onChange, placeholder = "Pick a date", disabled, className, ref, container, error = false, label, id, size: sizeProp, min, max, range: range2, ...wiring }) {
|
|
1497
|
+
function DatePicker({ value, onChange: onChangeProp, placeholder = "Pick a date", disabled, className, ref, container, error = false, label, id, size: sizeProp, min, max, range: range2, ...wiring }) {
|
|
1498
|
+
const onChange = useReportedChange(onChangeProp, value);
|
|
1482
1499
|
const contextSize = useContext(ControlSizeContext);
|
|
1483
1500
|
const size = sizeProp ?? contextSize ?? "md";
|
|
1484
1501
|
const [open, setOpen] = useState(false);
|
|
@@ -2083,7 +2100,7 @@ var DEFAULT_DATE_RANGE_PRESETS = [
|
|
|
2083
2100
|
];
|
|
2084
2101
|
function DateRangePicker({
|
|
2085
2102
|
value,
|
|
2086
|
-
onChange,
|
|
2103
|
+
onChange: onChangeProp,
|
|
2087
2104
|
placeholder = "Pick a date range",
|
|
2088
2105
|
disabled,
|
|
2089
2106
|
error = false,
|
|
@@ -2099,6 +2116,7 @@ function DateRangePicker({
|
|
|
2099
2116
|
size: sizeProp,
|
|
2100
2117
|
...wiring
|
|
2101
2118
|
}) {
|
|
2119
|
+
const onChange = useReportedChange(onChangeProp, value);
|
|
2102
2120
|
const contextSize = useContext(ControlSizeContext);
|
|
2103
2121
|
const size = sizeProp ?? contextSize ?? "md";
|
|
2104
2122
|
const [open, setOpen] = useState(false);
|
|
@@ -2462,22 +2480,27 @@ function TruncFileName({ children, className }) {
|
|
|
2462
2480
|
if (!isTruncated) return el;
|
|
2463
2481
|
return /* @__PURE__ */ jsx(Tooltip, { content: children, children: el });
|
|
2464
2482
|
}
|
|
2483
|
+
var PARALLEL = 3;
|
|
2465
2484
|
function formatSize(bytes) {
|
|
2466
2485
|
if (bytes < 1024) return `${bytes} B`;
|
|
2467
2486
|
if (bytes < 1024 * 1024) return `${(bytes / 1024).toFixed(1)} KB`;
|
|
2468
2487
|
return `${(bytes / (1024 * 1024)).toFixed(1)} MB`;
|
|
2469
2488
|
}
|
|
2470
|
-
|
|
2471
|
-
|
|
2489
|
+
var running = (item) => item.status === "queued" || item.status === "uploading";
|
|
2490
|
+
var failureOf = (err) => err instanceof Error && err.message ? err.message : "The upload didn't work.";
|
|
2491
|
+
function FileUpload({ onFiles, files, upload, onCancel, onRetry, onRemove, accept, multiple = true, maxSize, className, error = false, label, id }) {
|
|
2492
|
+
const controlled = files !== void 0;
|
|
2493
|
+
const [own, setOwn] = useState([]);
|
|
2494
|
+
const shown = controlled ? files : own;
|
|
2472
2495
|
const [dragOver, setDragOver] = useState(false);
|
|
2473
2496
|
const [rejected, setRejected] = useState(null);
|
|
2474
2497
|
const inputRef = useRef(null);
|
|
2498
|
+
const listRef = useRef(null);
|
|
2475
2499
|
const nextEntryId = useRef(0);
|
|
2476
|
-
const
|
|
2477
|
-
|
|
2478
|
-
|
|
2479
|
-
|
|
2480
|
-
}, []);
|
|
2500
|
+
const controllers = useRef(/* @__PURE__ */ new Map());
|
|
2501
|
+
const uploadRef = useLatest(upload);
|
|
2502
|
+
const overlayMark = useContext(OverlayMarkCtx);
|
|
2503
|
+
const reportChange = useContext(FormChangeCtx);
|
|
2481
2504
|
const field = useField();
|
|
2482
2505
|
const ownId = useId();
|
|
2483
2506
|
const inputId = id ?? `${ownId}-input`;
|
|
@@ -2487,37 +2510,100 @@ function FileUpload({ onFiles, accept, multiple = true, maxSize, className, erro
|
|
|
2487
2510
|
const constraints = fileConstraints(accept, maxSize, multiple);
|
|
2488
2511
|
const invalid = error || rejected != null;
|
|
2489
2512
|
const describedBy = [constraints ? constraintsId : null, field?.describedBy, rejected ? rejectedId : null].filter(Boolean).join(" ") || void 0;
|
|
2490
|
-
const
|
|
2491
|
-
|
|
2492
|
-
|
|
2513
|
+
const patch = (itemId, change) => setOwn((prev) => prev.map((i) => i.id === itemId ? { ...i, ...change } : i));
|
|
2514
|
+
const stop = (itemId) => {
|
|
2515
|
+
controllers.current.get(itemId)?.abort();
|
|
2516
|
+
controllers.current.delete(itemId);
|
|
2517
|
+
};
|
|
2518
|
+
const start = (item) => {
|
|
2519
|
+
const run = uploadRef.current;
|
|
2520
|
+
if (!run || !item.file) return;
|
|
2521
|
+
const controller = new AbortController();
|
|
2522
|
+
controllers.current.set(item.id, controller);
|
|
2523
|
+
patch(item.id, { status: "uploading", progress: 0, error: void 0 });
|
|
2524
|
+
const settle = (change) => {
|
|
2525
|
+
if (controller.signal.aborted) return;
|
|
2526
|
+
controllers.current.delete(item.id);
|
|
2527
|
+
patch(item.id, change);
|
|
2528
|
+
};
|
|
2529
|
+
let attempt;
|
|
2530
|
+
try {
|
|
2531
|
+
attempt = Promise.resolve(run(item.file, {
|
|
2532
|
+
signal: controller.signal,
|
|
2533
|
+
onProgress: (percent) => {
|
|
2534
|
+
if (!controller.signal.aborted) patch(item.id, { progress: Math.max(0, Math.min(100, percent)) });
|
|
2535
|
+
}
|
|
2536
|
+
}));
|
|
2537
|
+
} catch (err) {
|
|
2538
|
+
attempt = Promise.reject(err);
|
|
2539
|
+
}
|
|
2540
|
+
attempt.then(() => settle({ status: "done", progress: 100 }), (err) => settle({ status: "error", error: failureOf(err) }));
|
|
2493
2541
|
};
|
|
2542
|
+
useEffect(() => {
|
|
2543
|
+
if (controlled || !upload) return;
|
|
2544
|
+
let active = own.filter((i) => i.status === "uploading" && controllers.current.has(i.id)).length;
|
|
2545
|
+
for (const item of own) {
|
|
2546
|
+
if (active >= PARALLEL) break;
|
|
2547
|
+
if (item.status === "queued" || item.status === "uploading" && !controllers.current.has(item.id)) {
|
|
2548
|
+
start(item);
|
|
2549
|
+
active++;
|
|
2550
|
+
}
|
|
2551
|
+
}
|
|
2552
|
+
}, [own, controlled, upload]);
|
|
2553
|
+
const stopAll = useCallback(() => {
|
|
2554
|
+
controllers.current.forEach((c) => c.abort());
|
|
2555
|
+
controllers.current.clear();
|
|
2556
|
+
}, []);
|
|
2557
|
+
useEffect(() => stopAll, [stopAll]);
|
|
2558
|
+
const overlayOpen = overlayMark?.open ?? true;
|
|
2559
|
+
const [wasOpen, setWasOpen] = useState(overlayOpen);
|
|
2560
|
+
if (overlayOpen !== wasOpen) {
|
|
2561
|
+
setWasOpen(overlayOpen);
|
|
2562
|
+
if (!overlayOpen && !controlled) setOwn((prev) => prev.filter((i) => !running(i)));
|
|
2563
|
+
}
|
|
2564
|
+
useEffect(() => {
|
|
2565
|
+
if (!overlayOpen && !controlled) stopAll();
|
|
2566
|
+
}, [overlayOpen, controlled, stopAll]);
|
|
2567
|
+
const busy = shown.some(running);
|
|
2568
|
+
useEffect(() => {
|
|
2569
|
+
if (!busy || !overlayMark) return;
|
|
2570
|
+
return overlayMark.hold();
|
|
2571
|
+
}, [busy, overlayMark]);
|
|
2572
|
+
const [heard, setHeard] = useState("");
|
|
2573
|
+
const [seen, setSeen] = useState(() => new Map(shown.map((i) => [i.id, i.status])));
|
|
2574
|
+
if (shown.length !== seen.size || shown.some((i) => seen.get(i.id) !== i.status)) {
|
|
2575
|
+
const said = [];
|
|
2576
|
+
for (const item of shown) {
|
|
2577
|
+
const before = seen.get(item.id);
|
|
2578
|
+
if (!before || before === item.status) continue;
|
|
2579
|
+
if (item.status === "done") said.push(`${item.name} uploaded`);
|
|
2580
|
+
else if (item.status === "error") said.push(`${item.name} didn't upload: ${item.error ?? "the upload failed"}`);
|
|
2581
|
+
}
|
|
2582
|
+
setSeen(new Map(shown.map((i) => [i.id, i.status])));
|
|
2583
|
+
if (said.length) setHeard(said.join(". "));
|
|
2584
|
+
}
|
|
2585
|
+
const pendingFocus = useRef(null);
|
|
2586
|
+
useEffect(() => {
|
|
2587
|
+
const index = pendingFocus.current;
|
|
2588
|
+
if (index === null) return;
|
|
2589
|
+
pendingFocus.current = null;
|
|
2590
|
+
const rows = Array.from(listRef.current?.querySelectorAll(":scope > li") ?? []).map((row) => row.querySelector("button")).filter((b) => !!b);
|
|
2591
|
+
focusAfterRemoval(rows, index, inputRef.current);
|
|
2592
|
+
}, [shown]);
|
|
2494
2593
|
const addFiles = useCallback(
|
|
2495
2594
|
(fileList) => {
|
|
2496
2595
|
const { accepted, message } = checkFiles(Array.from(fileList), { accept, maxSize, multiple });
|
|
2497
2596
|
setRejected(message);
|
|
2498
2597
|
if (accepted.length === 0) return;
|
|
2499
|
-
|
|
2500
|
-
|
|
2501
|
-
|
|
2502
|
-
|
|
2503
|
-
}
|
|
2504
|
-
|
|
2505
|
-
|
|
2506
|
-
for (const { id: id2 } of entries) {
|
|
2507
|
-
let progress = 0;
|
|
2508
|
-
const timer = setInterval(() => {
|
|
2509
|
-
progress = Math.min(100, progress + Math.random() * 30 + 10);
|
|
2510
|
-
const done = progress >= 100;
|
|
2511
|
-
if (done) {
|
|
2512
|
-
clearInterval(timer);
|
|
2513
|
-
timers.current.delete(id2);
|
|
2514
|
-
}
|
|
2515
|
-
setFiles((prev) => prev.map((f) => f.id === id2 ? { ...f, progress, status: done ? "complete" : "uploading" } : f));
|
|
2516
|
-
}, 300);
|
|
2517
|
-
timers.current.set(id2, timer);
|
|
2518
|
-
}
|
|
2598
|
+
reportChange?.();
|
|
2599
|
+
onFiles?.(accepted);
|
|
2600
|
+
if (controlled) return;
|
|
2601
|
+
const status = uploadRef.current ? "queued" : "added";
|
|
2602
|
+
const entries = accepted.map((file) => ({ id: `${ownId}-file-${nextEntryId.current++}`, name: file.name, size: file.size, status, file }));
|
|
2603
|
+
if (!multiple) stopAll();
|
|
2604
|
+
setOwn((prev) => multiple ? [...prev, ...entries] : entries);
|
|
2519
2605
|
},
|
|
2520
|
-
[accept, maxSize, multiple, onFiles]
|
|
2606
|
+
[accept, maxSize, multiple, onFiles, controlled, ownId, reportChange, stopAll, uploadRef]
|
|
2521
2607
|
);
|
|
2522
2608
|
const handleDrop = useCallback(
|
|
2523
2609
|
(e) => {
|
|
@@ -2527,10 +2613,31 @@ function FileUpload({ onFiles, accept, multiple = true, maxSize, className, erro
|
|
|
2527
2613
|
},
|
|
2528
2614
|
[addFiles]
|
|
2529
2615
|
);
|
|
2530
|
-
const
|
|
2531
|
-
|
|
2532
|
-
|
|
2616
|
+
const indexOf = (item) => shown.findIndex((i) => i.id === item.id);
|
|
2617
|
+
const cancel = (item) => {
|
|
2618
|
+
pendingFocus.current = indexOf(item);
|
|
2619
|
+
if (!controlled) {
|
|
2620
|
+
stop(item.id);
|
|
2621
|
+
setOwn((prev) => prev.filter((i) => i.id !== item.id));
|
|
2622
|
+
}
|
|
2623
|
+
onCancel?.(item);
|
|
2533
2624
|
};
|
|
2625
|
+
const retry = (item) => {
|
|
2626
|
+
if (!controlled) patch(item.id, { status: "queued", progress: 0, error: void 0 });
|
|
2627
|
+
onRetry?.(item);
|
|
2628
|
+
};
|
|
2629
|
+
const remove = (item) => {
|
|
2630
|
+
pendingFocus.current = indexOf(item);
|
|
2631
|
+
reportChange?.();
|
|
2632
|
+
if (!controlled) {
|
|
2633
|
+
stop(item.id);
|
|
2634
|
+
setOwn((prev) => prev.filter((i) => i.id !== item.id));
|
|
2635
|
+
}
|
|
2636
|
+
onRemove?.(item);
|
|
2637
|
+
};
|
|
2638
|
+
const canCancel = !controlled || !!onCancel;
|
|
2639
|
+
const canRetry = !controlled || !!onRetry;
|
|
2640
|
+
const canRemove = !controlled || !!onRemove;
|
|
2534
2641
|
return /* @__PURE__ */ jsxs("div", { className: cn("space-y-ds-3", className), children: [
|
|
2535
2642
|
/* @__PURE__ */ jsxs("div", { className: "flex flex-col gap-ds-1.5", children: [
|
|
2536
2643
|
showLabel && /* @__PURE__ */ jsx(Label, { htmlFor: inputId, children: label }),
|
|
@@ -2586,33 +2693,43 @@ function FileUpload({ onFiles, accept, multiple = true, maxSize, className, erro
|
|
|
2586
2693
|
),
|
|
2587
2694
|
rejected && /* @__PURE__ */ jsx(InlineFieldError, { id: rejectedId, message: rejected, className: "mt-0" })
|
|
2588
2695
|
] }),
|
|
2589
|
-
|
|
2590
|
-
"
|
|
2591
|
-
|
|
2592
|
-
|
|
2593
|
-
|
|
2594
|
-
"
|
|
2595
|
-
|
|
2596
|
-
|
|
2597
|
-
|
|
2598
|
-
|
|
2599
|
-
|
|
2600
|
-
|
|
2601
|
-
|
|
2602
|
-
|
|
2603
|
-
|
|
2604
|
-
|
|
2605
|
-
|
|
2606
|
-
|
|
2607
|
-
|
|
2608
|
-
|
|
2609
|
-
|
|
2610
|
-
|
|
2696
|
+
shown.length > 0 && /* @__PURE__ */ jsx("ul", { ref: listRef, className: "space-y-ds-2", children: shown.map((item) => {
|
|
2697
|
+
const words = item.status === "queued" ? "Waiting" : item.status === "uploading" ? `${Math.round(item.progress ?? 0)}%` : item.status === "done" ? "Uploaded" : item.status === "error" ? "Failed" : null;
|
|
2698
|
+
return /* @__PURE__ */ jsxs(
|
|
2699
|
+
"li",
|
|
2700
|
+
{
|
|
2701
|
+
"data-upload-status": item.status,
|
|
2702
|
+
className: cn(
|
|
2703
|
+
"flex items-center gap-ds-3 text-sm",
|
|
2704
|
+
"border-[length:var(--ds-border-width)]",
|
|
2705
|
+
item.status === "error" ? "border-[var(--ds-status-error)]" : "border-[var(--ds-border-subtle)]",
|
|
2706
|
+
"rounded-[var(--ds-radius-md)] bg-[var(--ds-bg-surface)]"
|
|
2707
|
+
),
|
|
2708
|
+
style: { padding: "var(--ds-space-3)" },
|
|
2709
|
+
children: [
|
|
2710
|
+
/* @__PURE__ */ jsx(Icon, { name: "folder", size: 16, className: "text-[var(--ds-text-muted)] shrink-0" }),
|
|
2711
|
+
/* @__PURE__ */ jsxs("div", { className: "flex-1 min-w-0", children: [
|
|
2712
|
+
/* @__PURE__ */ jsx(TruncFileName, { className: "text-[var(--ds-text-primary)]", children: item.name }),
|
|
2713
|
+
(item.size != null || words) && /* @__PURE__ */ jsx("p", { className: "text-xs text-[var(--ds-text-muted)]", children: [item.size != null ? formatSize(item.size) : null, words].filter(Boolean).join(" \xB7 ") }),
|
|
2714
|
+
item.status === "uploading" && /* @__PURE__ */ jsx(Progress, { value: item.progress ?? 0, size: "sm", label: `Uploading ${item.name}`, className: "mt-ds-1" }),
|
|
2715
|
+
item.status === "error" && /* @__PURE__ */ jsx("p", { className: "mt-ds-1 text-xs text-[var(--ds-status-error)]", children: item.error ?? "The upload didn't work." })
|
|
2716
|
+
] }),
|
|
2717
|
+
item.status === "done" && /* @__PURE__ */ jsx(Icon, { name: "check", size: 16, className: "text-[var(--ds-status-success)] shrink-0", "aria-hidden": "true" }),
|
|
2718
|
+
running(item) && canCancel && // the visible word starts the name, which says which file (WCAG 2.5.3)
|
|
2719
|
+
/* @__PURE__ */ jsx(Button, { variant: "ghost", size: "sm", onClick: () => cancel(item), "aria-label": `Cancel ${item.name}`, children: "Cancel" }),
|
|
2720
|
+
item.status === "error" && canRetry && /* @__PURE__ */ jsx(Button, { variant: "ghost", size: "sm", onClick: () => retry(item), "aria-label": `Retry ${item.name}`, children: "Retry" }),
|
|
2721
|
+
!running(item) && canRemove && /* @__PURE__ */ jsx(Button, { variant: "ghost", size: "icon-sm", onClick: () => remove(item), "aria-label": `Remove ${item.name}`, children: /* @__PURE__ */ jsx(Icon, { name: "close", size: 14 }) })
|
|
2722
|
+
]
|
|
2723
|
+
},
|
|
2724
|
+
item.id
|
|
2725
|
+
);
|
|
2726
|
+
}) }),
|
|
2727
|
+
/* @__PURE__ */ jsx("p", { role: "status", className: "sr-only", children: heard })
|
|
2611
2728
|
] });
|
|
2612
2729
|
}
|
|
2613
2730
|
function SliderRange({
|
|
2614
2731
|
value,
|
|
2615
|
-
onChange,
|
|
2732
|
+
onChange: onChangeProp,
|
|
2616
2733
|
min = 0,
|
|
2617
2734
|
max = 100,
|
|
2618
2735
|
step = 1,
|
|
@@ -2627,6 +2744,7 @@ function SliderRange({
|
|
|
2627
2744
|
trackStyle,
|
|
2628
2745
|
formatValue
|
|
2629
2746
|
}) {
|
|
2747
|
+
const onChange = useReportedChange(onChangeProp, value);
|
|
2630
2748
|
const field = useField();
|
|
2631
2749
|
const ownId = useId();
|
|
2632
2750
|
const showLabel = label != null && !field;
|
|
@@ -2832,7 +2950,7 @@ function parseTime(value) {
|
|
|
2832
2950
|
}
|
|
2833
2951
|
function TimePicker({
|
|
2834
2952
|
value,
|
|
2835
|
-
onChange,
|
|
2953
|
+
onChange: onChangeProp,
|
|
2836
2954
|
use24Hour = false,
|
|
2837
2955
|
minuteStep = 15,
|
|
2838
2956
|
disabled,
|
|
@@ -2844,6 +2962,7 @@ function TimePicker({
|
|
|
2844
2962
|
size: sizeProp,
|
|
2845
2963
|
...wiring
|
|
2846
2964
|
}) {
|
|
2965
|
+
const onChange = useReportedChange(onChangeProp, value);
|
|
2847
2966
|
const contextSize = useContext(ControlSizeContext);
|
|
2848
2967
|
const control = useFieldControl({ ...wiring, id, error: error || void 0 }, { requiredInDescription: true });
|
|
2849
2968
|
const size = sizeProp ?? contextSize ?? "md";
|
|
@@ -3222,7 +3341,7 @@ var sizes = {
|
|
|
3222
3341
|
};
|
|
3223
3342
|
function NumberInput({
|
|
3224
3343
|
value,
|
|
3225
|
-
onChange,
|
|
3344
|
+
onChange: onChangeProp,
|
|
3226
3345
|
min = -Infinity,
|
|
3227
3346
|
max = Infinity,
|
|
3228
3347
|
step = 1,
|
|
@@ -3236,6 +3355,7 @@ function NumberInput({
|
|
|
3236
3355
|
allowDecimals,
|
|
3237
3356
|
id
|
|
3238
3357
|
}) {
|
|
3358
|
+
const onChange = useReportedChange(onChangeProp, value);
|
|
3239
3359
|
const contextSize = useContext(ControlSizeContext);
|
|
3240
3360
|
const size = sizeProp ?? contextSize ?? "md";
|
|
3241
3361
|
const intervalRef = useRef(void 0);
|
|
@@ -3254,13 +3374,13 @@ function NumberInput({
|
|
|
3254
3374
|
[min, max]
|
|
3255
3375
|
);
|
|
3256
3376
|
const valueRef = useLatest(value);
|
|
3257
|
-
const commitValue = useCallback((v) => {
|
|
3377
|
+
const commitValue = useCallback((v, own = false) => {
|
|
3258
3378
|
const clamped = clamp(v);
|
|
3259
3379
|
valueRef.current = clamped;
|
|
3260
3380
|
setDraft(String(clamped));
|
|
3261
|
-
onChange(clamped);
|
|
3381
|
+
(own ? onChangeProp : onChange)(clamped);
|
|
3262
3382
|
return clamped;
|
|
3263
|
-
}, [onChange, clamp, valueRef]);
|
|
3383
|
+
}, [onChange, onChangeProp, clamp, valueRef]);
|
|
3264
3384
|
const increment = useCallback(() => commitValue(valueRef.current + step), [commitValue, step, valueRef]);
|
|
3265
3385
|
const decrement = useCallback(() => commitValue(valueRef.current - step), [commitValue, step, valueRef]);
|
|
3266
3386
|
const startRepeat = useCallback(
|
|
@@ -3302,7 +3422,7 @@ function NumberInput({
|
|
|
3302
3422
|
setDraft(String(committed));
|
|
3303
3423
|
} else {
|
|
3304
3424
|
const fallback = isFinite(min) ? min : 0;
|
|
3305
|
-
const committed = commitValue(value !== void 0 ? value : fallback);
|
|
3425
|
+
const committed = commitValue(value !== void 0 ? value : fallback, true);
|
|
3306
3426
|
setDraft(String(committed));
|
|
3307
3427
|
}
|
|
3308
3428
|
}, [draft, commitValue, min, value]);
|
|
@@ -3543,7 +3663,7 @@ var Tag = forwardRef(function Tag2({
|
|
|
3543
3663
|
});
|
|
3544
3664
|
function TagInput({
|
|
3545
3665
|
value,
|
|
3546
|
-
onChange,
|
|
3666
|
+
onChange: onChangeProp,
|
|
3547
3667
|
placeholder = "Add a tag...",
|
|
3548
3668
|
maxTags = Infinity,
|
|
3549
3669
|
disabled = false,
|
|
@@ -3552,6 +3672,7 @@ function TagInput({
|
|
|
3552
3672
|
id,
|
|
3553
3673
|
"aria-label": ariaLabel
|
|
3554
3674
|
}) {
|
|
3675
|
+
const onChange = useReportedChange(onChangeProp, value);
|
|
3555
3676
|
const [input, setInput] = useState("");
|
|
3556
3677
|
const inputRef = useRef(null);
|
|
3557
3678
|
const addTag = useCallback(
|
|
@@ -3677,7 +3798,7 @@ var sizes2 = {
|
|
|
3677
3798
|
};
|
|
3678
3799
|
function PinInput({
|
|
3679
3800
|
value,
|
|
3680
|
-
onChange,
|
|
3801
|
+
onChange: onChangeProp,
|
|
3681
3802
|
length = 6,
|
|
3682
3803
|
mask = false,
|
|
3683
3804
|
disabled = false,
|
|
@@ -3686,6 +3807,7 @@ function PinInput({
|
|
|
3686
3807
|
error = false,
|
|
3687
3808
|
id
|
|
3688
3809
|
}) {
|
|
3810
|
+
const onChange = useReportedChange(onChangeProp, value);
|
|
3689
3811
|
const contextSize = useContext(ControlSizeContext);
|
|
3690
3812
|
const size = sizeProp ?? contextSize ?? "md";
|
|
3691
3813
|
const inputsRef = useRef([]);
|
|
@@ -3821,7 +3943,7 @@ function StarIcon({ filled, half, size }) {
|
|
|
3821
3943
|
}
|
|
3822
3944
|
function Rating({
|
|
3823
3945
|
value,
|
|
3824
|
-
onChange,
|
|
3946
|
+
onChange: onChangeProp,
|
|
3825
3947
|
max = 5,
|
|
3826
3948
|
allowHalf = false,
|
|
3827
3949
|
readOnly = false,
|
|
@@ -3829,15 +3951,16 @@ function Rating({
|
|
|
3829
3951
|
className,
|
|
3830
3952
|
error = false
|
|
3831
3953
|
}) {
|
|
3954
|
+
const onChange = useReportedChange(onChangeProp, value);
|
|
3832
3955
|
const [hoverValue, setHoverValue] = useState(null);
|
|
3833
3956
|
const displayValue = hoverValue ?? value;
|
|
3834
3957
|
const handleClick = useCallback(
|
|
3835
3958
|
(starIdx, isLeftHalf) => {
|
|
3836
|
-
if (readOnly || !
|
|
3959
|
+
if (readOnly || !onChangeProp) return;
|
|
3837
3960
|
const newValue = allowHalf && isLeftHalf ? starIdx + 0.5 : starIdx + 1;
|
|
3838
3961
|
onChange(newValue === value ? 0 : newValue);
|
|
3839
3962
|
},
|
|
3840
|
-
[readOnly, onChange, allowHalf, value]
|
|
3963
|
+
[readOnly, onChangeProp, onChange, allowHalf, value]
|
|
3841
3964
|
);
|
|
3842
3965
|
const handleMouseMove = useCallback(
|
|
3843
3966
|
(starIdx, e) => {
|
|
@@ -3851,7 +3974,7 @@ function Rating({
|
|
|
3851
3974
|
const iconSize = iconSizes[size];
|
|
3852
3975
|
const step = allowHalf ? 0.5 : 1;
|
|
3853
3976
|
const handleKeyDown = (e) => {
|
|
3854
|
-
if (readOnly || !
|
|
3977
|
+
if (readOnly || !onChangeProp) return;
|
|
3855
3978
|
let next = null;
|
|
3856
3979
|
if (e.key === "ArrowRight" || e.key === "ArrowUp") next = Math.min(max, value + step);
|
|
3857
3980
|
else if (e.key === "ArrowLeft" || e.key === "ArrowDown") next = Math.max(0, value - step);
|
|
@@ -3975,13 +4098,14 @@ var DEFAULT_SWATCHES = [
|
|
|
3975
4098
|
];
|
|
3976
4099
|
function ColorPicker({
|
|
3977
4100
|
value,
|
|
3978
|
-
onChange,
|
|
4101
|
+
onChange: onChangeProp,
|
|
3979
4102
|
showAlpha = false,
|
|
3980
4103
|
swatches = DEFAULT_SWATCHES,
|
|
3981
4104
|
disabled = false,
|
|
3982
4105
|
className,
|
|
3983
4106
|
error = false
|
|
3984
4107
|
}) {
|
|
4108
|
+
const onChange = useReportedChange(onChangeProp, value);
|
|
3985
4109
|
const [hsl, setHsl] = useState(() => hexToHsl(value));
|
|
3986
4110
|
const [hexInput, setHexInput] = useState(value);
|
|
3987
4111
|
const satLightRef = useRef(null);
|
|
@@ -4222,6 +4346,7 @@ var Alert = forwardRef(function Alert2({
|
|
|
4222
4346
|
trigger: /* @__PURE__ */ jsx(
|
|
4223
4347
|
"button",
|
|
4224
4348
|
{
|
|
4349
|
+
type: "button",
|
|
4225
4350
|
className: cn(
|
|
4226
4351
|
"shrink-0 text-xs font-medium px-ds-2.5 py-ds-1 rounded-[var(--ds-radius-sm)]",
|
|
4227
4352
|
"transition-colors cursor-pointer",
|
|
@@ -4246,6 +4371,7 @@ var Alert = forwardRef(function Alert2({
|
|
|
4246
4371
|
return /* @__PURE__ */ jsxs(
|
|
4247
4372
|
"button",
|
|
4248
4373
|
{
|
|
4374
|
+
type: "button",
|
|
4249
4375
|
onClick: a.onClick,
|
|
4250
4376
|
className: cn(
|
|
4251
4377
|
"shrink-0 text-xs font-medium px-ds-2.5 py-ds-1 rounded-[var(--ds-radius-sm)]",
|
|
@@ -4266,6 +4392,7 @@ var Alert = forwardRef(function Alert2({
|
|
|
4266
4392
|
/* @__PURE__ */ jsxs(
|
|
4267
4393
|
"button",
|
|
4268
4394
|
{
|
|
4395
|
+
type: "button",
|
|
4269
4396
|
onClick: () => setDetailsExpanded(!detailsExpanded),
|
|
4270
4397
|
"aria-expanded": detailsExpanded,
|
|
4271
4398
|
className: cn(
|
|
@@ -4293,6 +4420,7 @@ var Alert = forwardRef(function Alert2({
|
|
|
4293
4420
|
dismissible && /* @__PURE__ */ jsx(
|
|
4294
4421
|
"button",
|
|
4295
4422
|
{
|
|
4423
|
+
type: "button",
|
|
4296
4424
|
onClick: onDismiss,
|
|
4297
4425
|
className: "shrink-0 text-[var(--ds-text-muted)] hover:text-[var(--ds-text-primary)] transition-colors cursor-pointer",
|
|
4298
4426
|
"aria-label": "Dismiss",
|
|
@@ -4303,6 +4431,12 @@ var Alert = forwardRef(function Alert2({
|
|
|
4303
4431
|
}
|
|
4304
4432
|
);
|
|
4305
4433
|
});
|
|
4434
|
+
function controlsOf(form) {
|
|
4435
|
+
if (!form) return "";
|
|
4436
|
+
const controls = form.querySelectorAll("input, select, textarea, [role='combobox'], [role='radiogroup'], [role='checkbox'], [role='switch'], [role='slider'], [role='spinbutton'], [contenteditable='true']");
|
|
4437
|
+
return Array.from(controls).map((el) => el.id || el.getAttribute("name") || el.getAttribute("role") || el.tagName).join("|");
|
|
4438
|
+
}
|
|
4439
|
+
var isThenable = (value) => !!value && typeof value.then === "function";
|
|
4306
4440
|
function stampFormId(node, formId) {
|
|
4307
4441
|
return Children.map(node, (child) => {
|
|
4308
4442
|
if (!isValidElement(child)) return child;
|
|
@@ -4359,12 +4493,30 @@ function FormWrapper({ onSubmit, validationMode: validationModeProp, children, a
|
|
|
4359
4493
|
const pendingSubmit = useRef(false);
|
|
4360
4494
|
const pendingFocus = useRef(false);
|
|
4361
4495
|
const onSubmitRef = useLatest(onSubmit);
|
|
4496
|
+
const overlayMark = useContext(OverlayMarkCtx);
|
|
4497
|
+
const reportChange = overlayMark ? overlayMark.report : null;
|
|
4498
|
+
const [savedCheck, setSavedCheck] = useState(null);
|
|
4499
|
+
useEffect(() => {
|
|
4500
|
+
if (!savedCheck) return;
|
|
4501
|
+
const form = formRef.current;
|
|
4502
|
+
if (form && !form.querySelector("[aria-invalid='true']") && controlsOf(form) === savedCheck.controls) overlayMark?.clear();
|
|
4503
|
+
}, [savedCheck, overlayMark]);
|
|
4362
4504
|
useEffect(() => {
|
|
4363
4505
|
if (pendingSubmit.current && submitted) {
|
|
4364
4506
|
pendingSubmit.current = false;
|
|
4365
|
-
|
|
4507
|
+
const form = formRef.current;
|
|
4508
|
+
const passed = Object.keys(errorsRef.current).length === 0 && !form?.querySelector("[aria-invalid='true']");
|
|
4509
|
+
const controls = controlsOf(form);
|
|
4510
|
+
const result = onSubmitRef.current(errorsRef.current);
|
|
4511
|
+
if (!passed || !overlayMark) return;
|
|
4512
|
+
if (isThenable(result)) {
|
|
4513
|
+
result.then(() => overlayMark.clear(), () => {
|
|
4514
|
+
});
|
|
4515
|
+
} else {
|
|
4516
|
+
setSavedCheck({ controls });
|
|
4517
|
+
}
|
|
4366
4518
|
}
|
|
4367
|
-
}, [submitted, submitCount, errors, errorsRef, onSubmitRef]);
|
|
4519
|
+
}, [submitted, submitCount, errors, errorsRef, onSubmitRef, overlayMark]);
|
|
4368
4520
|
const submittedRef = useLatest(submitted);
|
|
4369
4521
|
const errorSummaryRef = useLatest(errorSummary);
|
|
4370
4522
|
const summaryRef = useRef(null);
|
|
@@ -4418,7 +4570,15 @@ function FormWrapper({ onSubmit, validationMode: validationModeProp, children, a
|
|
|
4418
4570
|
pendingFocus.current = false;
|
|
4419
4571
|
}, []);
|
|
4420
4572
|
const setError = useCallback((field, message) => {
|
|
4421
|
-
setErrors((prev) =>
|
|
4573
|
+
setErrors((prev) => {
|
|
4574
|
+
if (!message) {
|
|
4575
|
+
if (!(field in prev)) return prev;
|
|
4576
|
+
const next = { ...prev };
|
|
4577
|
+
delete next[field];
|
|
4578
|
+
return next;
|
|
4579
|
+
}
|
|
4580
|
+
return prev[field] === message ? prev : { ...prev, [field]: message };
|
|
4581
|
+
});
|
|
4422
4582
|
}, []);
|
|
4423
4583
|
const checks = useRef(/* @__PURE__ */ new Map());
|
|
4424
4584
|
const register = useCallback((field, check) => {
|
|
@@ -4443,9 +4603,16 @@ function FormWrapper({ onSubmit, validationMode: validationModeProp, children, a
|
|
|
4443
4603
|
(e) => {
|
|
4444
4604
|
e.preventDefault();
|
|
4445
4605
|
if (checks.current.size > 0) {
|
|
4446
|
-
const found =
|
|
4447
|
-
for (const [field, check] of checks.current) found
|
|
4448
|
-
setErrors((prev) =>
|
|
4606
|
+
const found = /* @__PURE__ */ new Map();
|
|
4607
|
+
for (const [field, check] of checks.current) found.set(field, check());
|
|
4608
|
+
setErrors((prev) => {
|
|
4609
|
+
const next = { ...prev };
|
|
4610
|
+
for (const [field, message] of found) {
|
|
4611
|
+
if (message) next[field] = message;
|
|
4612
|
+
else delete next[field];
|
|
4613
|
+
}
|
|
4614
|
+
return next;
|
|
4615
|
+
});
|
|
4449
4616
|
}
|
|
4450
4617
|
pendingSubmit.current = true;
|
|
4451
4618
|
pendingFocus.current = focusFirstError;
|
|
@@ -4468,22 +4635,67 @@ function FormWrapper({ onSubmit, validationMode: validationModeProp, children, a
|
|
|
4468
4635
|
f.message
|
|
4469
4636
|
] }, f.id || f.label)) }) }) : null;
|
|
4470
4637
|
const actionsNode = actions && !drawerFooter ? /* @__PURE__ */ jsx("div", { "data-form-actions": "", className: cn("flex flex-wrap items-center gap-ds-2 pt-ds-2", actionsAlign === "end" ? "justify-end" : "justify-start"), children: actions }) : null;
|
|
4471
|
-
return /* @__PURE__ */ jsx(FormCtx.Provider, { value: { errors, setError, clearErrors, validationMode, submitted, register }, children: /* @__PURE__ */ jsxs("form", { ref: setRefs, id: drawerFooter ? formId : void 0, onSubmit: handleSubmit, onFocusCapture: userActed, onInputCapture: userActed, className: cn("flex flex-col gap-ds-5 max-w-[var(--ds-form-max,none)]", className), noValidate: true, children: [
|
|
4638
|
+
return /* @__PURE__ */ jsx(FormCtx.Provider, { value: { errors, setError, clearErrors, validationMode, submitted, register }, children: /* @__PURE__ */ jsx(FormChangeCtx.Provider, { value: reportChange, children: /* @__PURE__ */ jsxs("form", { ref: setRefs, id: drawerFooter ? formId : void 0, onSubmit: handleSubmit, onFocusCapture: userActed, onInputCapture: userActed, className: cn("flex flex-col gap-ds-5 max-w-[var(--ds-form-max,none)]", className), noValidate: true, children: [
|
|
4472
4639
|
summaryNode && /* @__PURE__ */ jsx("div", { ref: summaryRef, "data-form-error-summary": "", tabIndex: -1, className: "rounded-[var(--ds-radius-md)] outline-none focus-visible:shadow-[var(--ds-shadow-focus)]", children: summaryNode }),
|
|
4473
4640
|
children,
|
|
4474
4641
|
actionsNode
|
|
4475
|
-
] }) });
|
|
4642
|
+
] }) }) });
|
|
4643
|
+
}
|
|
4644
|
+
var FOCUSABLE2 = "input:not([disabled]):not([type='hidden']), select:not([disabled]), textarea:not([disabled]), [role='combobox'], [role='switch'], [role='radio'], [tabindex]:not([tabindex='-1'])";
|
|
4645
|
+
function AddAnother({ items, getId, itemName, columns, renderRow, onAdd, onRemove, addLabel = "Add another", label, minItems = 1, maxItems, className }) {
|
|
4646
|
+
const listRef = useRef(null);
|
|
4647
|
+
const addRef = useRef(null);
|
|
4648
|
+
const pending = useRef(null);
|
|
4649
|
+
const firstFields = () => Array.from(listRef.current?.querySelectorAll(":scope > li") ?? []).map((row) => row.querySelector(FOCUSABLE2)).filter((el) => !!el);
|
|
4650
|
+
useEffect(() => {
|
|
4651
|
+
const next = pending.current;
|
|
4652
|
+
if (!next) return;
|
|
4653
|
+
pending.current = null;
|
|
4654
|
+
const fields = firstFields();
|
|
4655
|
+
if (next.kind === "add") fields[fields.length - 1]?.focus();
|
|
4656
|
+
else focusAfterRemoval(fields, next.index, addRef.current);
|
|
4657
|
+
}, [items]);
|
|
4658
|
+
const canRemove = items.length > minItems;
|
|
4659
|
+
const canAdd = maxItems === void 0 || items.length < maxItems;
|
|
4660
|
+
const grid = { "--gs-add-another-cols": `repeat(${columns.length}, minmax(0, 1fr)) max-content` };
|
|
4661
|
+
const body = /* @__PURE__ */ jsxs("div", { "data-add-another": "", className: cn("@container flex flex-col gap-ds-3", className), style: grid, children: [
|
|
4662
|
+
/* @__PURE__ */ jsxs("div", { "aria-hidden": "true", className: "hidden gap-ds-3 text-sm font-medium text-[var(--ds-text-secondary)] @min-[30rem]:grid @min-[30rem]:grid-cols-[var(--gs-add-another-cols)]", children: [
|
|
4663
|
+
columns.map((column) => /* @__PURE__ */ jsx("span", { children: column }, column)),
|
|
4664
|
+
canRemove && /* @__PURE__ */ jsx("span", { className: "invisible inline-flex items-center whitespace-nowrap px-ds-4 text-xs font-medium", children: "Remove" })
|
|
4665
|
+
] }),
|
|
4666
|
+
/* @__PURE__ */ jsx("ul", { ref: listRef, className: "flex flex-col gap-ds-4 @min-[30rem]:gap-ds-3", children: items.map((item, index) => {
|
|
4667
|
+
const id = getId(item);
|
|
4668
|
+
return /* @__PURE__ */ jsxs("li", { "data-add-another-row": "", className: "grid grid-cols-1 items-start gap-ds-3 @min-[30rem]:grid-cols-[var(--gs-add-another-cols)]", children: [
|
|
4669
|
+
/* @__PURE__ */ jsx(AddAnotherRowCtx.Provider, { value: true, children: renderRow(item, index, (column) => `${column}, ${itemName(index)}`) }),
|
|
4670
|
+
canRemove && // the visible "Remove" starts its name, which says whose row it removes (WCAG 2.5.3 label in name)
|
|
4671
|
+
/* @__PURE__ */ jsx(Button, { type: "button", variant: "ghost", size: "sm", "aria-label": `Remove ${itemName(index)}`, className: "justify-self-start @min-[30rem]:mt-[calc((var(--ds-control-height-md)-var(--ds-control-height-sm))/2)]", onClick: () => {
|
|
4672
|
+
pending.current = { kind: "remove", index };
|
|
4673
|
+
onRemove(id);
|
|
4674
|
+
}, children: "Remove" })
|
|
4675
|
+
] }, id);
|
|
4676
|
+
}) }),
|
|
4677
|
+
canAdd && /* @__PURE__ */ jsx("div", { children: /* @__PURE__ */ jsx(Button, { ref: addRef, type: "button", variant: "secondary", onClick: () => {
|
|
4678
|
+
pending.current = { kind: "add" };
|
|
4679
|
+
onAdd();
|
|
4680
|
+
}, children: addLabel }) })
|
|
4681
|
+
] });
|
|
4682
|
+
if (!label) return body;
|
|
4683
|
+
return /* @__PURE__ */ jsxs("fieldset", { className: "min-w-0", children: [
|
|
4684
|
+
/* @__PURE__ */ jsx("legend", { className: "mb-ds-2 text-sm font-medium text-[var(--ds-text-primary)]", children: label }),
|
|
4685
|
+
body
|
|
4686
|
+
] });
|
|
4476
4687
|
}
|
|
4477
4688
|
function TransferList({
|
|
4478
4689
|
available,
|
|
4479
4690
|
selected,
|
|
4480
|
-
onChange,
|
|
4691
|
+
onChange: onChangeProp,
|
|
4481
4692
|
availableTitle = "Available",
|
|
4482
4693
|
selectedTitle = "Selected",
|
|
4483
4694
|
searchable = true,
|
|
4484
4695
|
className,
|
|
4485
4696
|
ref
|
|
4486
4697
|
}) {
|
|
4698
|
+
const onChange = useReportedChange(onChangeProp, selected);
|
|
4487
4699
|
const [checkedAvailable, setCheckedAvailable] = useState(/* @__PURE__ */ new Set());
|
|
4488
4700
|
const [checkedSelected, setCheckedSelected] = useState(/* @__PURE__ */ new Set());
|
|
4489
4701
|
const [searchLeft, setSearchLeft] = useState("");
|
|
@@ -4565,6 +4777,7 @@ function TransferList({
|
|
|
4565
4777
|
/* @__PURE__ */ jsx(
|
|
4566
4778
|
"button",
|
|
4567
4779
|
{
|
|
4780
|
+
type: "button",
|
|
4568
4781
|
onClick: moveAllRight,
|
|
4569
4782
|
disabled: !available.filter((i) => !i.disabled).length,
|
|
4570
4783
|
"aria-label": isStacked ? "Move all down" : "Move all right",
|
|
@@ -4575,6 +4788,7 @@ function TransferList({
|
|
|
4575
4788
|
/* @__PURE__ */ jsx(
|
|
4576
4789
|
"button",
|
|
4577
4790
|
{
|
|
4791
|
+
type: "button",
|
|
4578
4792
|
onClick: moveRight,
|
|
4579
4793
|
disabled: !checkedAvailable.size,
|
|
4580
4794
|
"aria-label": isStacked ? "Move selected down" : "Move selected right",
|
|
@@ -4585,6 +4799,7 @@ function TransferList({
|
|
|
4585
4799
|
/* @__PURE__ */ jsx(
|
|
4586
4800
|
"button",
|
|
4587
4801
|
{
|
|
4802
|
+
type: "button",
|
|
4588
4803
|
onClick: moveLeft,
|
|
4589
4804
|
disabled: !checkedSelected.size,
|
|
4590
4805
|
"aria-label": isStacked ? "Move selected up" : "Move selected left",
|
|
@@ -4595,6 +4810,7 @@ function TransferList({
|
|
|
4595
4810
|
/* @__PURE__ */ jsx(
|
|
4596
4811
|
"button",
|
|
4597
4812
|
{
|
|
4813
|
+
type: "button",
|
|
4598
4814
|
onClick: moveAllLeft,
|
|
4599
4815
|
disabled: !selected.filter((i) => !i.disabled).length,
|
|
4600
4816
|
"aria-label": isStacked ? "Move all up" : "Move all left",
|
|
@@ -4726,62 +4942,6 @@ function toInitials(value) {
|
|
|
4726
4942
|
if (!/\s/.test(s) && Array.from(s).length <= 3) return s;
|
|
4727
4943
|
return initialsOf(s);
|
|
4728
4944
|
}
|
|
4729
|
-
var variantColors = {
|
|
4730
|
-
success: "bg-[var(--ds-status-success)]",
|
|
4731
|
-
warning: "bg-[var(--ds-status-warning)]",
|
|
4732
|
-
error: "bg-[var(--ds-status-error)]",
|
|
4733
|
-
info: "bg-[var(--ds-accent-primary)]",
|
|
4734
|
-
neutral: "bg-[var(--ds-text-muted)]",
|
|
4735
|
-
offline: "bg-[var(--ds-text-muted)] opacity-disabled"
|
|
4736
|
-
};
|
|
4737
|
-
var pulseRingColors = {
|
|
4738
|
-
success: "bg-[color-mix(in_oklch,var(--ds-status-success)_30%,transparent)]",
|
|
4739
|
-
warning: "bg-[color-mix(in_oklch,var(--ds-status-warning)_30%,transparent)]",
|
|
4740
|
-
error: "bg-[color-mix(in_oklch,var(--ds-status-error)_30%,transparent)]",
|
|
4741
|
-
info: "bg-[var(--ds-accent-soft)]",
|
|
4742
|
-
neutral: "bg-[color-mix(in_oklch,var(--ds-text-muted)_20%,transparent)]",
|
|
4743
|
-
offline: "bg-[color-mix(in_oklch,var(--ds-text-muted)_10%,transparent)]"
|
|
4744
|
-
};
|
|
4745
|
-
var StatusDot = forwardRef(function StatusDot2({
|
|
4746
|
-
variant = "neutral",
|
|
4747
|
-
label,
|
|
4748
|
-
pulse = false,
|
|
4749
|
-
className
|
|
4750
|
-
}, ref) {
|
|
4751
|
-
return /* @__PURE__ */ jsxs(
|
|
4752
|
-
"span",
|
|
4753
|
-
{
|
|
4754
|
-
ref,
|
|
4755
|
-
className: cn("inline-flex items-center gap-ds-1.5", className),
|
|
4756
|
-
role: "status",
|
|
4757
|
-
"aria-label": label ?? variant,
|
|
4758
|
-
children: [
|
|
4759
|
-
/* @__PURE__ */ jsxs("span", { className: "relative inline-flex shrink-0", children: [
|
|
4760
|
-
/* @__PURE__ */ jsx(
|
|
4761
|
-
"span",
|
|
4762
|
-
{
|
|
4763
|
-
className: cn(
|
|
4764
|
-
"rounded-[var(--ds-radius-full)] h-2.5 w-2.5",
|
|
4765
|
-
variantColors[variant]
|
|
4766
|
-
)
|
|
4767
|
-
}
|
|
4768
|
-
),
|
|
4769
|
-
pulse && variant !== "offline" && /* @__PURE__ */ jsx(
|
|
4770
|
-
"span",
|
|
4771
|
-
{
|
|
4772
|
-
className: cn(
|
|
4773
|
-
"absolute inset-0 rounded-[var(--ds-radius-full)]",
|
|
4774
|
-
"animate-ping motion-reduce:animate-none",
|
|
4775
|
-
pulseRingColors[variant]
|
|
4776
|
-
)
|
|
4777
|
-
}
|
|
4778
|
-
)
|
|
4779
|
-
] }),
|
|
4780
|
-
label && /* @__PURE__ */ jsx("span", { className: "font-normal text-[var(--ds-text-primary)] text-[length:var(--ds-font-size-xs)]", children: label })
|
|
4781
|
-
]
|
|
4782
|
-
}
|
|
4783
|
-
);
|
|
4784
|
-
});
|
|
4785
4945
|
var sizeStyles2 = {
|
|
4786
4946
|
sm: "h-8 w-8 text-xs",
|
|
4787
4947
|
md: "h-10 w-10 text-sm",
|
|
@@ -4804,13 +4964,23 @@ function colorStyles(color, seed) {
|
|
|
4804
4964
|
if (color === "neutral") return "bg-[var(--ds-bg-muted)] text-[var(--ds-text-secondary)]";
|
|
4805
4965
|
return paletteStyles[color === "auto" ? paletteFor(seed) : color];
|
|
4806
4966
|
}
|
|
4807
|
-
|
|
4808
|
-
|
|
4809
|
-
|
|
4810
|
-
|
|
4811
|
-
|
|
4812
|
-
}
|
|
4967
|
+
function PresenceMark({ status }) {
|
|
4968
|
+
return /* @__PURE__ */ jsxs("svg", { viewBox: "0 0 10 10", width: "10", height: "10", "aria-hidden": "true", focusable: "false", "data-presence": status, className: "block", children: [
|
|
4969
|
+
status === "online" && /* @__PURE__ */ jsx("circle", { cx: "5", cy: "5", r: "5", className: "fill-[var(--ds-status-success)]" }),
|
|
4970
|
+
status === "away" && /* @__PURE__ */ jsx("circle", { cx: "5", cy: "5", r: "4", fill: "none", strokeWidth: "2", className: "stroke-[var(--ds-status-warning)]" }),
|
|
4971
|
+
status === "busy" && /* @__PURE__ */ jsxs(Fragment, { children: [
|
|
4972
|
+
/* @__PURE__ */ jsx("circle", { cx: "5", cy: "5", r: "5", className: "fill-[var(--ds-status-error)]" }),
|
|
4973
|
+
/* @__PURE__ */ jsx("rect", { x: "2.5", y: "4.1", width: "5", height: "1.8", rx: "0.9", className: "fill-[var(--ds-bg-canvas)]" })
|
|
4974
|
+
] }),
|
|
4975
|
+
status === "offline" && /* @__PURE__ */ jsxs(Fragment, { children: [
|
|
4976
|
+
/* @__PURE__ */ jsx("circle", { cx: "5", cy: "5", r: "4", fill: "none", strokeWidth: "2", className: "stroke-[var(--ds-text-muted)]" }),
|
|
4977
|
+
/* @__PURE__ */ jsx("line", { x1: "3.1", y1: "6.9", x2: "6.9", y2: "3.1", strokeWidth: "1.5", strokeLinecap: "round", className: "stroke-[var(--ds-text-muted)]" })
|
|
4978
|
+
] })
|
|
4979
|
+
] });
|
|
4980
|
+
}
|
|
4813
4981
|
function Avatar({ initials, src, alt, size = "md", status, color = "auto", className }) {
|
|
4982
|
+
const who = alt ?? initials ?? "";
|
|
4983
|
+
const named = status ? [who, status].filter(Boolean).join(", ") : void 0;
|
|
4814
4984
|
const base = cn(
|
|
4815
4985
|
"inline-flex items-center justify-center font-medium shrink-0",
|
|
4816
4986
|
"rounded-[var(--ds-radius-full)]",
|
|
@@ -4822,13 +4992,15 @@ function Avatar({ initials, src, alt, size = "md", status, color = "auto", class
|
|
|
4822
4992
|
{
|
|
4823
4993
|
"data-avatar": "",
|
|
4824
4994
|
src,
|
|
4825
|
-
alt: alt ?? initials ?? "",
|
|
4995
|
+
alt: named ?? alt ?? initials ?? "",
|
|
4826
4996
|
className: cn(base, "object-cover")
|
|
4827
4997
|
}
|
|
4828
4998
|
) : /* @__PURE__ */ jsx(
|
|
4829
4999
|
"div",
|
|
4830
5000
|
{
|
|
4831
5001
|
"data-avatar": "",
|
|
5002
|
+
role: named ? "img" : void 0,
|
|
5003
|
+
"aria-label": named,
|
|
4832
5004
|
className: cn(
|
|
4833
5005
|
base,
|
|
4834
5006
|
colorStyles(color, alt ?? initials ?? ""),
|
|
@@ -4850,20 +5022,14 @@ function Avatar({ initials, src, alt, size = "md", status, color = "auto", class
|
|
|
4850
5022
|
size === "lg" && "bottom-[0px] right-[0px]"
|
|
4851
5023
|
),
|
|
4852
5024
|
"aria-hidden": "true",
|
|
4853
|
-
children: /* @__PURE__ */ jsx(
|
|
4854
|
-
StatusDot,
|
|
4855
|
-
{
|
|
4856
|
-
variant: statusVariantMap[status],
|
|
4857
|
-
className: "rounded-[var(--ds-radius-full)] shadow-[0_0_0_2px_var(--ds-bg-canvas)]"
|
|
4858
|
-
}
|
|
4859
|
-
)
|
|
5025
|
+
children: /* @__PURE__ */ jsx("span", { className: "block rounded-[var(--ds-radius-full)] bg-[var(--ds-bg-canvas)] shadow-[0_0_0_2px_var(--ds-bg-canvas)]", children: /* @__PURE__ */ jsx(PresenceMark, { status }) })
|
|
4860
5026
|
}
|
|
4861
5027
|
)
|
|
4862
5028
|
] });
|
|
4863
5029
|
}
|
|
4864
5030
|
function MentionInput({
|
|
4865
5031
|
value: controlledValue,
|
|
4866
|
-
onChange,
|
|
5032
|
+
onChange: onChangeProp,
|
|
4867
5033
|
suggestions,
|
|
4868
5034
|
trigger = "@",
|
|
4869
5035
|
placeholder,
|
|
@@ -4872,6 +5038,7 @@ function MentionInput({
|
|
|
4872
5038
|
}) {
|
|
4873
5039
|
const [internalValue, setInternalValue] = useState("");
|
|
4874
5040
|
const value = controlledValue ?? internalValue;
|
|
5041
|
+
const onChange = useReportedChange(onChangeProp, value);
|
|
4875
5042
|
const [query, setQuery] = useState("");
|
|
4876
5043
|
const [showPopup, setShowPopup] = useState(false);
|
|
4877
5044
|
const [activeIndex, setActiveIndex] = useState(0);
|
|
@@ -5777,6 +5944,57 @@ var DescriptionList = forwardRef(function DescriptionList2({
|
|
|
5777
5944
|
}
|
|
5778
5945
|
);
|
|
5779
5946
|
});
|
|
5947
|
+
var variantColors = {
|
|
5948
|
+
success: "bg-[var(--ds-status-success)]",
|
|
5949
|
+
warning: "bg-[var(--ds-status-warning)]",
|
|
5950
|
+
error: "bg-[var(--ds-status-error)]",
|
|
5951
|
+
info: "bg-[var(--ds-accent-primary)]",
|
|
5952
|
+
neutral: "bg-[var(--ds-text-muted)]",
|
|
5953
|
+
offline: "bg-[var(--ds-text-muted)] opacity-disabled"
|
|
5954
|
+
};
|
|
5955
|
+
var pulseRingColors = {
|
|
5956
|
+
success: "bg-[color-mix(in_oklch,var(--ds-status-success)_30%,transparent)]",
|
|
5957
|
+
warning: "bg-[color-mix(in_oklch,var(--ds-status-warning)_30%,transparent)]",
|
|
5958
|
+
error: "bg-[color-mix(in_oklch,var(--ds-status-error)_30%,transparent)]",
|
|
5959
|
+
info: "bg-[var(--ds-accent-soft)]",
|
|
5960
|
+
neutral: "bg-[color-mix(in_oklch,var(--ds-text-muted)_20%,transparent)]",
|
|
5961
|
+
offline: "bg-[color-mix(in_oklch,var(--ds-text-muted)_10%,transparent)]"
|
|
5962
|
+
};
|
|
5963
|
+
var StatusDot = forwardRef(function StatusDot2({
|
|
5964
|
+
variant = "neutral",
|
|
5965
|
+
label,
|
|
5966
|
+
pulse = false,
|
|
5967
|
+
className
|
|
5968
|
+
}, ref) {
|
|
5969
|
+
return (
|
|
5970
|
+
// No live region (A48): the dot is read as its words where it sits; telling the user about a change as it happens
|
|
5971
|
+
// is the toasts' job (WCAG 4.1.3). The dot itself is hidden from assistive technology.
|
|
5972
|
+
/* @__PURE__ */ jsxs("span", { ref, "data-status-dot": variant, className: cn("inline-flex items-center gap-ds-1.5", className), children: [
|
|
5973
|
+
/* @__PURE__ */ jsxs("span", { "aria-hidden": "true", className: "relative inline-flex shrink-0", children: [
|
|
5974
|
+
/* @__PURE__ */ jsx(
|
|
5975
|
+
"span",
|
|
5976
|
+
{
|
|
5977
|
+
className: cn(
|
|
5978
|
+
"rounded-[var(--ds-radius-full)] h-2.5 w-2.5",
|
|
5979
|
+
variantColors[variant]
|
|
5980
|
+
)
|
|
5981
|
+
}
|
|
5982
|
+
),
|
|
5983
|
+
pulse && variant !== "offline" && /* @__PURE__ */ jsx(
|
|
5984
|
+
"span",
|
|
5985
|
+
{
|
|
5986
|
+
className: cn(
|
|
5987
|
+
"absolute inset-0 rounded-[var(--ds-radius-full)]",
|
|
5988
|
+
"animate-ping motion-reduce:animate-none",
|
|
5989
|
+
pulseRingColors[variant]
|
|
5990
|
+
)
|
|
5991
|
+
}
|
|
5992
|
+
)
|
|
5993
|
+
] }),
|
|
5994
|
+
/* @__PURE__ */ jsx("span", { className: "font-normal text-[var(--ds-text-primary)] text-[length:var(--ds-font-size-xs)]", children: label })
|
|
5995
|
+
] })
|
|
5996
|
+
);
|
|
5997
|
+
});
|
|
5780
5998
|
function Accordion({ items, type = "single", defaultOpen = [], open: controlledOpen, onOpenChange, className }) {
|
|
5781
5999
|
const [internalOpen, setInternalOpen] = useState(new Set(defaultOpen));
|
|
5782
6000
|
const baseId = useId();
|
|
@@ -5811,6 +6029,7 @@ function Accordion({ items, type = "single", defaultOpen = [], open: controlledO
|
|
|
5811
6029
|
/* @__PURE__ */ jsxs(
|
|
5812
6030
|
"button",
|
|
5813
6031
|
{
|
|
6032
|
+
type: "button",
|
|
5814
6033
|
id: triggerId,
|
|
5815
6034
|
"aria-expanded": isOpen,
|
|
5816
6035
|
"aria-controls": panelId,
|
|
@@ -6196,6 +6415,7 @@ function Table({
|
|
|
6196
6415
|
expandable && /* @__PURE__ */ jsx("td", { className: cn("w-8", density === "compact" ? "px-ds-1 py-ds-2" : "px-ds-2 py-ds-3"), children: /* @__PURE__ */ jsx(
|
|
6197
6416
|
"button",
|
|
6198
6417
|
{
|
|
6418
|
+
type: "button",
|
|
6199
6419
|
onClick: () => toggleExpand(i),
|
|
6200
6420
|
className: "text-[var(--ds-text-muted)] hover:text-[var(--ds-text-primary)] cursor-pointer",
|
|
6201
6421
|
"aria-expanded": isExpanded,
|
|
@@ -6312,7 +6532,7 @@ var indicatorInset = {
|
|
|
6312
6532
|
};
|
|
6313
6533
|
function SegmentedControl({
|
|
6314
6534
|
value,
|
|
6315
|
-
onChange,
|
|
6535
|
+
onChange: onChangeProp,
|
|
6316
6536
|
options,
|
|
6317
6537
|
size: sizeProp,
|
|
6318
6538
|
variant = "default",
|
|
@@ -6323,6 +6543,7 @@ function SegmentedControl({
|
|
|
6323
6543
|
maxOptions = 6,
|
|
6324
6544
|
...wiring
|
|
6325
6545
|
}) {
|
|
6546
|
+
const onChange = useReportedChange(onChangeProp, value);
|
|
6326
6547
|
const contextSize = useContext(ControlSizeContext);
|
|
6327
6548
|
const control = useFieldControl(wiring);
|
|
6328
6549
|
const named = !ariaLabel && control.labelId ? { "aria-labelledby": control.labelId } : {};
|
|
@@ -8864,6 +9085,7 @@ function Carousel({
|
|
|
8864
9085
|
/* @__PURE__ */ jsx(
|
|
8865
9086
|
"button",
|
|
8866
9087
|
{
|
|
9088
|
+
type: "button",
|
|
8867
9089
|
onClick: prev,
|
|
8868
9090
|
disabled: !canPrev,
|
|
8869
9091
|
"aria-label": "Previous slide",
|
|
@@ -8883,6 +9105,7 @@ function Carousel({
|
|
|
8883
9105
|
/* @__PURE__ */ jsx(
|
|
8884
9106
|
"button",
|
|
8885
9107
|
{
|
|
9108
|
+
type: "button",
|
|
8886
9109
|
onClick: next,
|
|
8887
9110
|
disabled: !canNext,
|
|
8888
9111
|
"aria-label": "Next slide",
|
|
@@ -8903,6 +9126,7 @@ function Carousel({
|
|
|
8903
9126
|
showIndicators && count > 1 && /* @__PURE__ */ jsx("div", { className: "absolute bottom-ds-3 left-1/2 -translate-x-1/2 flex gap-ds-1.5 z-10", children: children.map((_, i) => /* @__PURE__ */ jsx(
|
|
8904
9127
|
"button",
|
|
8905
9128
|
{
|
|
9129
|
+
type: "button",
|
|
8906
9130
|
onClick: () => goTo(i),
|
|
8907
9131
|
"aria-label": `Go to slide ${i + 1}`,
|
|
8908
9132
|
className: cn(
|
|
@@ -11651,6 +11875,7 @@ function TabButton({
|
|
|
11651
11875
|
const btn2 = /* @__PURE__ */ jsxs(
|
|
11652
11876
|
"button",
|
|
11653
11877
|
{
|
|
11878
|
+
type: "button",
|
|
11654
11879
|
id: tabId,
|
|
11655
11880
|
role: "tab",
|
|
11656
11881
|
"aria-selected": isActive,
|
|
@@ -11686,6 +11911,7 @@ function TabButton({
|
|
|
11686
11911
|
const btn = /* @__PURE__ */ jsx(
|
|
11687
11912
|
"button",
|
|
11688
11913
|
{
|
|
11914
|
+
type: "button",
|
|
11689
11915
|
id: tabId,
|
|
11690
11916
|
role: "tab",
|
|
11691
11917
|
"aria-selected": isActive,
|
|
@@ -12059,6 +12285,7 @@ var Breadcrumbs = forwardRef(function Breadcrumbs2({
|
|
|
12059
12285
|
/* @__PURE__ */ jsx(
|
|
12060
12286
|
"button",
|
|
12061
12287
|
{
|
|
12288
|
+
type: "button",
|
|
12062
12289
|
ref: ellipsisBtnRef,
|
|
12063
12290
|
onClick: () => {
|
|
12064
12291
|
if (!dropdownOpen) setActiveIdx(0);
|
|
@@ -12109,6 +12336,7 @@ var Breadcrumbs = forwardRef(function Breadcrumbs2({
|
|
|
12109
12336
|
children: collapsedItems.map((ci, idx) => /* @__PURE__ */ jsxs(
|
|
12110
12337
|
"button",
|
|
12111
12338
|
{
|
|
12339
|
+
type: "button",
|
|
12112
12340
|
"data-index": idx,
|
|
12113
12341
|
role: "menuitem",
|
|
12114
12342
|
tabIndex: idx === activeIdx ? 0 : -1,
|
|
@@ -12304,6 +12532,7 @@ function PageNumbers({ currentPage, totalPages, onPageChange, pageSize: pageSize
|
|
|
12304
12532
|
/* @__PURE__ */ jsx(
|
|
12305
12533
|
"button",
|
|
12306
12534
|
{
|
|
12535
|
+
type: "button",
|
|
12307
12536
|
onClick: () => onPageChange(currentPage - 1),
|
|
12308
12537
|
disabled: currentPage <= 1,
|
|
12309
12538
|
"aria-label": "Previous page",
|
|
@@ -12323,6 +12552,7 @@ function PageNumbers({ currentPage, totalPages, onPageChange, pageSize: pageSize
|
|
|
12323
12552
|
(p, i) => p === "..." ? /* @__PURE__ */ jsx(EllipsisJumper, { totalPages, onPageChange }, `ellipsis-${i}`) : /* @__PURE__ */ jsx(
|
|
12324
12553
|
"button",
|
|
12325
12554
|
{
|
|
12555
|
+
type: "button",
|
|
12326
12556
|
onClick: () => onPageChange(p),
|
|
12327
12557
|
"aria-current": p === currentPage ? "page" : void 0,
|
|
12328
12558
|
className: cn(
|
|
@@ -12340,6 +12570,7 @@ function PageNumbers({ currentPage, totalPages, onPageChange, pageSize: pageSize
|
|
|
12340
12570
|
/* @__PURE__ */ jsx(
|
|
12341
12571
|
"button",
|
|
12342
12572
|
{
|
|
12573
|
+
type: "button",
|
|
12343
12574
|
onClick: () => onPageChange(currentPage + 1),
|
|
12344
12575
|
disabled: currentPage >= totalPages,
|
|
12345
12576
|
"aria-label": "Next page",
|
|
@@ -12602,6 +12833,7 @@ function StepCircle({ status, index, onClick, clickable }) {
|
|
|
12602
12833
|
return /* @__PURE__ */ jsx(
|
|
12603
12834
|
"button",
|
|
12604
12835
|
{
|
|
12836
|
+
type: "button",
|
|
12605
12837
|
onClick,
|
|
12606
12838
|
disabled: !clickable,
|
|
12607
12839
|
"aria-current": status === "current" ? "step" : void 0,
|
|
@@ -12796,7 +13028,7 @@ var Sidebar = forwardRef(function Sidebar2({
|
|
|
12796
13028
|
position = "flush",
|
|
12797
13029
|
navbarFloating: navbarFloatingProp,
|
|
12798
13030
|
navSize = "md",
|
|
12799
|
-
fill = false,
|
|
13031
|
+
fill: fill2 = false,
|
|
12800
13032
|
className
|
|
12801
13033
|
}, ref) {
|
|
12802
13034
|
const [internalCollapsed, setInternalCollapsed] = useState(defaultCollapsed ?? false);
|
|
@@ -12806,10 +13038,10 @@ var Sidebar = forwardRef(function Sidebar2({
|
|
|
12806
13038
|
const appShell = useAppShell();
|
|
12807
13039
|
const navbarFloating = navbarFloatingProp ?? appShell?.navbarFloating;
|
|
12808
13040
|
useLayoutEffect(() => {
|
|
12809
|
-
if (
|
|
13041
|
+
if (fill2 || !appShell) return;
|
|
12810
13042
|
return appShell.registerChrome("sidebar", position);
|
|
12811
|
-
}, [appShell?.registerChrome,
|
|
12812
|
-
const usesShellState = appShell !== null && !isControlled && defaultCollapsed === void 0 && !
|
|
13043
|
+
}, [appShell?.registerChrome, fill2, position]);
|
|
13044
|
+
const usesShellState = appShell !== null && !isControlled && defaultCollapsed === void 0 && !fill2 && type === "traditional";
|
|
12813
13045
|
const uncontrolledCollapsed = usesShellState ? appShell.sidebarCollapsed : internalCollapsed;
|
|
12814
13046
|
const collapsed = mini || (isControlled ? controlledCollapsed : uncontrolledCollapsed);
|
|
12815
13047
|
const handleCollapsedChange = (value) => {
|
|
@@ -12828,11 +13060,11 @@ var Sidebar = forwardRef(function Sidebar2({
|
|
|
12828
13060
|
effectiveDarkMode = false;
|
|
12829
13061
|
}
|
|
12830
13062
|
const isDark = effectiveDarkMode ?? variant === "dark";
|
|
12831
|
-
const showCollapse = type === "traditional" && !mini && !
|
|
13063
|
+
const showCollapse = type === "traditional" && !mini && !fill2;
|
|
12832
13064
|
const isMinimal = type === "minimal";
|
|
12833
13065
|
const isCompact = type === "compact";
|
|
12834
|
-
const isFloating = position === "floating" && !
|
|
12835
|
-
const sidebarWidth =
|
|
13066
|
+
const isFloating = position === "floating" && !fill2;
|
|
13067
|
+
const sidebarWidth = fill2 ? "100%" : isCompact ? "var(--ds-sidebar-compact-width)" : collapsed ? "var(--ds-sidebar-collapsed-width)" : "var(--ds-sidebar-width)";
|
|
12836
13068
|
const aside = /* @__PURE__ */ jsxs(
|
|
12837
13069
|
"aside",
|
|
12838
13070
|
{
|
|
@@ -12870,6 +13102,7 @@ var Sidebar = forwardRef(function Sidebar2({
|
|
|
12870
13102
|
const collapseButton = /* @__PURE__ */ jsxs(
|
|
12871
13103
|
"button",
|
|
12872
13104
|
{
|
|
13105
|
+
type: "button",
|
|
12873
13106
|
onClick: () => handleCollapsedChange(!collapsed),
|
|
12874
13107
|
"aria-expanded": !collapsed,
|
|
12875
13108
|
"aria-label": collapsed ? "Expand sidebar" : "Collapse sidebar",
|
|
@@ -13222,6 +13455,7 @@ function SidebarNav({
|
|
|
13222
13455
|
/* @__PURE__ */ jsxs(
|
|
13223
13456
|
"button",
|
|
13224
13457
|
{
|
|
13458
|
+
type: "button",
|
|
13225
13459
|
onClick: () => {
|
|
13226
13460
|
toggleExpand(key);
|
|
13227
13461
|
onItemClick?.(item, index);
|
|
@@ -13356,6 +13590,7 @@ function SidebarNav({
|
|
|
13356
13590
|
collapsible && /* @__PURE__ */ jsxs(
|
|
13357
13591
|
"button",
|
|
13358
13592
|
{
|
|
13593
|
+
type: "button",
|
|
13359
13594
|
onClick: () => onCollapsedChange(!collapsed),
|
|
13360
13595
|
title: collapsed ? "Expand sidebar" : "Collapse sidebar",
|
|
13361
13596
|
className: cn(
|
|
@@ -13422,6 +13657,7 @@ function CompactNavItem({
|
|
|
13422
13657
|
/* @__PURE__ */ jsxs(
|
|
13423
13658
|
"button",
|
|
13424
13659
|
{
|
|
13660
|
+
type: "button",
|
|
13425
13661
|
ref: setTriggerEl,
|
|
13426
13662
|
onMouseEnter: !mobile && hasChildren ? handleMouseEnter : void 0,
|
|
13427
13663
|
onMouseLeave: !mobile && hasChildren && isOpen ? handleMouseLeave : void 0,
|
|
@@ -13484,6 +13720,7 @@ function CompactNavItem({
|
|
|
13484
13720
|
mobile && expanded && hasChildren && item.children && /* @__PURE__ */ jsx("div", { className: "w-full flex flex-col gap-ds-1 pb-ds-1", children: item.children.map((child, ci) => /* @__PURE__ */ jsxs(
|
|
13485
13721
|
"button",
|
|
13486
13722
|
{
|
|
13723
|
+
type: "button",
|
|
13487
13724
|
onClick: () => onItemClick?.(child, ci),
|
|
13488
13725
|
className: cn(
|
|
13489
13726
|
"flex items-center gap-ds-2 px-ds-3 py-ds-1.5 text-[length:var(--ds-font-size-xs)] rounded-[var(--ds-radius-sm)] transition-colors cursor-pointer w-full",
|
|
@@ -13498,20 +13735,486 @@ function CompactNavItem({
|
|
|
13498
13735
|
)) })
|
|
13499
13736
|
] });
|
|
13500
13737
|
}
|
|
13501
|
-
|
|
13502
|
-
|
|
13503
|
-
|
|
13504
|
-
|
|
13505
|
-
|
|
13506
|
-
|
|
13507
|
-
|
|
13508
|
-
|
|
13738
|
+
var variantStyles4 = {
|
|
13739
|
+
default: "border-[var(--ds-border-default)] bg-[var(--ds-bg-surface)]",
|
|
13740
|
+
success: "border-[var(--ds-status-success)] bg-[var(--ds-status-success-bg)]",
|
|
13741
|
+
warning: "border-[var(--ds-status-warning)] bg-[var(--ds-status-warning-bg)]",
|
|
13742
|
+
error: "border-[var(--ds-status-error)] bg-[var(--ds-status-error-bg)]"
|
|
13743
|
+
};
|
|
13744
|
+
var variantIcons = {
|
|
13745
|
+
default: { name: "info", className: "text-[var(--ds-text-muted)]" },
|
|
13746
|
+
success: { name: "check", className: "text-[var(--ds-status-success)]" },
|
|
13747
|
+
warning: { name: "warning", className: "text-[var(--ds-status-warning)]" },
|
|
13748
|
+
error: { name: "error", className: "text-[var(--ds-status-error)]" }
|
|
13749
|
+
};
|
|
13750
|
+
var TOAST_POSITION_CLASSES = {
|
|
13751
|
+
"top-right": "top-[var(--ds-toast-inset-top)] right-[var(--ds-toast-inset-right)]",
|
|
13752
|
+
"top-left": "top-[var(--ds-toast-inset-top)] left-[var(--ds-toast-inset-left)]",
|
|
13753
|
+
"bottom-right": "bottom-[var(--ds-toast-inset-bottom-right)] right-[var(--ds-toast-inset-right)]",
|
|
13754
|
+
"bottom-left": "bottom-[var(--ds-toast-inset-bottom-left)] left-[var(--ds-toast-inset-left)]",
|
|
13755
|
+
"top-center": "top-[var(--ds-toast-inset-top)] left-1/2 -translate-x-1/2",
|
|
13756
|
+
"bottom-center": "bottom-ds-4 left-1/2 -translate-x-1/2"
|
|
13757
|
+
};
|
|
13758
|
+
var finite = (ms) => typeof ms === "number" && Number.isFinite(ms) && ms > 0;
|
|
13759
|
+
function Toast({ variant = "default", message, visible, onDismiss, duration = 5e3, pauseOnHover = false, action, actionWindow, position = "bottom-right", mode, container, inline = false, paused = false, onActionLapse, onAction, restartKey = 0 }) {
|
|
13760
|
+
const isMobile = useBreakpoint("sm");
|
|
13761
|
+
const isCentered = position === "top-center" || position === "bottom-center";
|
|
13762
|
+
const [hovered, setHovered] = useState(false);
|
|
13763
|
+
const onDismissRef = useLatest(onDismiss);
|
|
13764
|
+
const onLapseRef = useLatest(onActionLapse);
|
|
13765
|
+
const actionUsed = useRef(false);
|
|
13766
|
+
const phase = action ? finite(actionWindow) ? "window" : "none" : finite(duration) ? "plain" : "none";
|
|
13767
|
+
const total = phase === "window" ? actionWindow : phase === "plain" ? duration : 0;
|
|
13768
|
+
const timer = useRef(void 0);
|
|
13769
|
+
const remaining = useRef(total);
|
|
13770
|
+
const startedAt = useRef(0);
|
|
13771
|
+
const isPaused = paused || !inline && pauseOnHover && hovered;
|
|
13772
|
+
const stop = useCallback(() => {
|
|
13773
|
+
if (timer.current) {
|
|
13774
|
+
clearTimeout(timer.current);
|
|
13775
|
+
timer.current = void 0;
|
|
13776
|
+
remaining.current -= Date.now() - startedAt.current;
|
|
13777
|
+
}
|
|
13778
|
+
}, []);
|
|
13779
|
+
const start = useCallback(() => {
|
|
13780
|
+
if (phase === "none" || timer.current) return;
|
|
13781
|
+
startedAt.current = Date.now();
|
|
13782
|
+
const expire = phase === "window" ? () => {
|
|
13783
|
+
timer.current = void 0;
|
|
13784
|
+
if (onLapseRef.current) onLapseRef.current();
|
|
13785
|
+
else onDismissRef.current();
|
|
13786
|
+
} : () => {
|
|
13787
|
+
timer.current = void 0;
|
|
13788
|
+
onDismissRef.current();
|
|
13789
|
+
};
|
|
13790
|
+
timer.current = setTimeout(expire, Math.max(0, remaining.current));
|
|
13791
|
+
}, [phase, onDismissRef, onLapseRef]);
|
|
13509
13792
|
useEffect(() => {
|
|
13510
|
-
if (!
|
|
13511
|
-
|
|
13512
|
-
|
|
13793
|
+
if (!visible) return;
|
|
13794
|
+
remaining.current = total;
|
|
13795
|
+
if (timer.current) {
|
|
13796
|
+
clearTimeout(timer.current);
|
|
13797
|
+
timer.current = void 0;
|
|
13513
13798
|
}
|
|
13514
|
-
|
|
13799
|
+
if (!isPaused) start();
|
|
13800
|
+
return () => {
|
|
13801
|
+
if (timer.current) {
|
|
13802
|
+
clearTimeout(timer.current);
|
|
13803
|
+
timer.current = void 0;
|
|
13804
|
+
}
|
|
13805
|
+
};
|
|
13806
|
+
}, [visible, phase, total, restartKey]);
|
|
13807
|
+
useEffect(() => {
|
|
13808
|
+
if (!visible) return;
|
|
13809
|
+
if (isPaused) stop();
|
|
13810
|
+
else start();
|
|
13811
|
+
}, [isPaused, visible, start, stop]);
|
|
13812
|
+
useEffect(() => {
|
|
13813
|
+
actionUsed.current = false;
|
|
13814
|
+
}, [restartKey]);
|
|
13815
|
+
if (!visible) return null;
|
|
13816
|
+
const icon = variantIcons[variant];
|
|
13817
|
+
const pressAction = () => {
|
|
13818
|
+
if (!action || actionUsed.current) return;
|
|
13819
|
+
actionUsed.current = true;
|
|
13820
|
+
if (onAction) onAction();
|
|
13821
|
+
else {
|
|
13822
|
+
void action.onClick();
|
|
13823
|
+
onDismissRef.current();
|
|
13824
|
+
}
|
|
13825
|
+
};
|
|
13826
|
+
const card = /* @__PURE__ */ jsxs(
|
|
13827
|
+
"div",
|
|
13828
|
+
{
|
|
13829
|
+
"data-toast": "",
|
|
13830
|
+
"data-variant": variant,
|
|
13831
|
+
role: inline ? void 0 : variant === "error" ? "alert" : "status",
|
|
13832
|
+
"aria-live": inline ? void 0 : variant === "error" ? "assertive" : "polite",
|
|
13833
|
+
"data-mode": inline ? mode : void 0,
|
|
13834
|
+
className: cn(
|
|
13835
|
+
"flex items-center gap-ds-3 px-ds-4 py-ds-3",
|
|
13836
|
+
isCentered ? "min-w-[360px] max-w-[560px]" : "min-w-[280px] max-w-[420px]",
|
|
13837
|
+
"border-[length:var(--ds-border-width)]",
|
|
13838
|
+
GLASS_DROPDOWN,
|
|
13839
|
+
"rounded-[var(--ds-radius-md)]",
|
|
13840
|
+
"text-sm text-[var(--ds-text-primary)]",
|
|
13841
|
+
variantStyles4[variant]
|
|
13842
|
+
),
|
|
13843
|
+
children: [
|
|
13844
|
+
/* @__PURE__ */ jsx(Icon, { name: icon.name, size: 18, className: cn("shrink-0", icon.className) }),
|
|
13845
|
+
/* @__PURE__ */ jsx("span", { className: "flex-1", children: message }),
|
|
13846
|
+
action && /* @__PURE__ */ jsx(
|
|
13847
|
+
"button",
|
|
13848
|
+
{
|
|
13849
|
+
type: "button",
|
|
13850
|
+
onClick: pressAction,
|
|
13851
|
+
className: "shrink-0 text-xs font-semibold text-[var(--ds-accent-primary)] hover:underline cursor-pointer",
|
|
13852
|
+
children: action.label
|
|
13853
|
+
}
|
|
13854
|
+
),
|
|
13855
|
+
/* @__PURE__ */ jsx(
|
|
13856
|
+
"button",
|
|
13857
|
+
{
|
|
13858
|
+
type: "button",
|
|
13859
|
+
onClick: onDismiss,
|
|
13860
|
+
"aria-label": "Dismiss notification",
|
|
13861
|
+
className: "text-[var(--ds-text-muted)] hover:text-[var(--ds-text-primary)] transition-colors cursor-pointer shrink-0",
|
|
13862
|
+
children: /* @__PURE__ */ jsx(Icon, { name: "close", size: 16 })
|
|
13863
|
+
}
|
|
13864
|
+
)
|
|
13865
|
+
]
|
|
13866
|
+
}
|
|
13867
|
+
);
|
|
13868
|
+
if (inline) return card;
|
|
13869
|
+
return createPortal(
|
|
13870
|
+
/* @__PURE__ */ jsx(
|
|
13871
|
+
"div",
|
|
13872
|
+
{
|
|
13873
|
+
"data-mode": mode,
|
|
13874
|
+
onMouseEnter: pauseOnHover ? () => setHovered(true) : void 0,
|
|
13875
|
+
onMouseLeave: pauseOnHover ? () => setHovered(false) : void 0,
|
|
13876
|
+
className: cn(
|
|
13877
|
+
"fixed z-[var(--ds-z-toast)]",
|
|
13878
|
+
isMobile ? "bottom-ds-4 left-ds-4 right-ds-4" : TOAST_POSITION_CLASSES[position]
|
|
13879
|
+
),
|
|
13880
|
+
children: card
|
|
13881
|
+
}
|
|
13882
|
+
),
|
|
13883
|
+
container ?? document.body
|
|
13884
|
+
);
|
|
13885
|
+
}
|
|
13886
|
+
var ToastContext = createContext(null);
|
|
13887
|
+
var ToastLedgerCtx = createContext(null);
|
|
13888
|
+
var BottomNavPresenceCtx = createContext(null);
|
|
13889
|
+
function useToast() {
|
|
13890
|
+
const ctx = useContext(ToastContext);
|
|
13891
|
+
if (!ctx) {
|
|
13892
|
+
throw new Error("useToast must be used within <ToastProvider>: the app shell's (get_app_shell writes it around AppShell). A page outside the shell (sign-in, a public page) shows its messages inline instead: an Alert above the form, and each field's error below the field.");
|
|
13893
|
+
}
|
|
13894
|
+
return ctx;
|
|
13895
|
+
}
|
|
13896
|
+
function useToastOptional() {
|
|
13897
|
+
return useContext(ToastContext);
|
|
13898
|
+
}
|
|
13899
|
+
var toastSeq = 0;
|
|
13900
|
+
var heardSeq = 0;
|
|
13901
|
+
var mergeable = (e) => !e.action && e.variant !== "error";
|
|
13902
|
+
function fill(entries, slots) {
|
|
13903
|
+
let shown = entries.filter((e) => e.shown).length;
|
|
13904
|
+
if (shown >= slots || shown === entries.length) return entries;
|
|
13905
|
+
const next = [...entries];
|
|
13906
|
+
while (shown < slots) {
|
|
13907
|
+
const urgent = next.findIndex((e) => !e.shown && !mergeable(e));
|
|
13908
|
+
const at = urgent !== -1 ? urgent : next.findIndex((e) => !e.shown);
|
|
13909
|
+
if (at === -1) break;
|
|
13910
|
+
next[at] = { ...next[at], shown: true };
|
|
13911
|
+
shown++;
|
|
13912
|
+
}
|
|
13913
|
+
return next;
|
|
13914
|
+
}
|
|
13915
|
+
function ToastProvider({ children, maxVisible = 3, position = "bottom-right", duration = 5e3, mode, pauseOnHover = true, coalesce = true }) {
|
|
13916
|
+
const slots = Math.max(1, Math.floor(Number.isFinite(maxVisible) ? maxVisible : 1));
|
|
13917
|
+
const [list, setList] = useState([]);
|
|
13918
|
+
const entries = useRef([]);
|
|
13919
|
+
const isMobile = useBreakpoint("sm");
|
|
13920
|
+
const createdIds = useRef([]);
|
|
13921
|
+
const [heard, setHeard] = useState([]);
|
|
13922
|
+
const [hovered, setHovered] = useState(false);
|
|
13923
|
+
const [focusInside, setFocusInside] = useState(false);
|
|
13924
|
+
const paused = pauseOnHover && hovered || focusInside;
|
|
13925
|
+
const stackRef = useRef(null);
|
|
13926
|
+
const returnTo = useRef(null);
|
|
13927
|
+
const answering = useRef([]);
|
|
13928
|
+
const viaKey = useRef(false);
|
|
13929
|
+
const refocus = useRef(false);
|
|
13930
|
+
const pendingHeard = useRef(/* @__PURE__ */ new Map());
|
|
13931
|
+
const heardTimer = useRef(void 0);
|
|
13932
|
+
const [bottomNavs, setBottomNavs] = useState(0);
|
|
13933
|
+
const registerBottomNav = useCallback(() => {
|
|
13934
|
+
setBottomNavs((n) => n + 1);
|
|
13935
|
+
let gone = false;
|
|
13936
|
+
return () => {
|
|
13937
|
+
if (gone) return;
|
|
13938
|
+
gone = true;
|
|
13939
|
+
setBottomNavs((n) => n - 1);
|
|
13940
|
+
};
|
|
13941
|
+
}, []);
|
|
13942
|
+
const commit = useCallback((next) => {
|
|
13943
|
+
entries.current = fill(next, slots);
|
|
13944
|
+
setList(entries.current);
|
|
13945
|
+
}, [slots]);
|
|
13946
|
+
const [slotsSeen, setSlotsSeen] = useState(slots);
|
|
13947
|
+
if (slots !== slotsSeen) {
|
|
13948
|
+
setSlotsSeen(slots);
|
|
13949
|
+
let kept = 0;
|
|
13950
|
+
setList(fill(list.map((e) => e.shown && ++kept > slots ? { ...e, shown: false } : e), slots));
|
|
13951
|
+
}
|
|
13952
|
+
useEffect(() => {
|
|
13953
|
+
entries.current = list;
|
|
13954
|
+
}, [list]);
|
|
13955
|
+
const announce = useCallback((entry) => {
|
|
13956
|
+
pendingHeard.current.set(entry.id, entry);
|
|
13957
|
+
if (heardTimer.current) return;
|
|
13958
|
+
heardTimer.current = setTimeout(() => {
|
|
13959
|
+
heardTimer.current = void 0;
|
|
13960
|
+
const batch = [...pendingHeard.current.values()];
|
|
13961
|
+
pendingHeard.current.clear();
|
|
13962
|
+
setHeard((list2) => [...list2, ...batch.map((e) => ({
|
|
13963
|
+
id: `heard-${++heardSeq}`,
|
|
13964
|
+
assertive: e.variant === "error",
|
|
13965
|
+
node: /* @__PURE__ */ jsxs(Fragment, { children: [
|
|
13966
|
+
e.message,
|
|
13967
|
+
e.action ? ` Press F8 to reach ${e.action.label}.` : ""
|
|
13968
|
+
] })
|
|
13969
|
+
}))].slice(-5));
|
|
13970
|
+
}, 0);
|
|
13971
|
+
}, []);
|
|
13972
|
+
useEffect(() => () => {
|
|
13973
|
+
if (heardTimer.current) clearTimeout(heardTimer.current);
|
|
13974
|
+
}, []);
|
|
13975
|
+
const leaving = useCallback(() => {
|
|
13976
|
+
if (!stackRef.current?.contains(document.activeElement)) return;
|
|
13977
|
+
refocus.current = true;
|
|
13978
|
+
setFocusInside(false);
|
|
13979
|
+
}, []);
|
|
13980
|
+
const remove = useCallback((id) => {
|
|
13981
|
+
leaving();
|
|
13982
|
+
commit(entries.current.filter((t) => t.id !== id));
|
|
13983
|
+
}, [commit, leaving]);
|
|
13984
|
+
const dismissAll = useCallback(() => {
|
|
13985
|
+
leaving();
|
|
13986
|
+
commit([]);
|
|
13987
|
+
}, [commit, leaving]);
|
|
13988
|
+
const update = useCallback((id, message, options = {}) => {
|
|
13989
|
+
const list2 = entries.current;
|
|
13990
|
+
const at = list2.findIndex((t2) => t2.id === id);
|
|
13991
|
+
if (at === -1) return;
|
|
13992
|
+
const t = list2[at];
|
|
13993
|
+
const next = [...list2];
|
|
13994
|
+
next[at] = { ...t, message, variant: options.variant ?? t.variant, duration: options.duration ?? t.duration, action: options.action ?? t.action, actionWindow: options.actionWindow ?? t.actionWindow, key: options.key ?? t.key, version: t.version + 1 };
|
|
13995
|
+
commit(next);
|
|
13996
|
+
announce(next[at]);
|
|
13997
|
+
}, [commit, announce]);
|
|
13998
|
+
const toast = useCallback((message, options = {}) => {
|
|
13999
|
+
const list2 = entries.current;
|
|
14000
|
+
const base = { message, variant: options.variant ?? "default", duration: options.duration ?? duration, action: options.action, actionWindow: options.actionWindow, key: options.key };
|
|
14001
|
+
if (options.id) {
|
|
14002
|
+
const at = list2.findIndex((t) => t.id === options.id);
|
|
14003
|
+
if (at !== -1) {
|
|
14004
|
+
const next = [...list2];
|
|
14005
|
+
next[at] = { ...list2[at], ...base, version: list2[at].version + 1 };
|
|
14006
|
+
createdIds.current.push(options.id);
|
|
14007
|
+
commit(next);
|
|
14008
|
+
announce(next[at]);
|
|
14009
|
+
return options.id;
|
|
14010
|
+
}
|
|
14011
|
+
}
|
|
14012
|
+
while (answering.current.length) {
|
|
14013
|
+
const answered = answering.current.shift();
|
|
14014
|
+
const at = list2.findIndex((t) => t.id === answered);
|
|
14015
|
+
if (at === -1) continue;
|
|
14016
|
+
const next = [...list2];
|
|
14017
|
+
next[at] = { ...list2[at], ...base, version: list2[at].version + 1 };
|
|
14018
|
+
createdIds.current.push(answered);
|
|
14019
|
+
commit(next);
|
|
14020
|
+
announce(next[at]);
|
|
14021
|
+
return answered;
|
|
14022
|
+
}
|
|
14023
|
+
if (coalesce && base.key && mergeable(base)) {
|
|
14024
|
+
const at = list2.findIndex((t) => t.key === base.key && mergeable(t));
|
|
14025
|
+
if (at !== -1) {
|
|
14026
|
+
const next = [...list2];
|
|
14027
|
+
next[at] = { ...list2[at], ...base, version: list2[at].version + 1 };
|
|
14028
|
+
createdIds.current.push(list2[at].id);
|
|
14029
|
+
commit(next);
|
|
14030
|
+
announce(next[at]);
|
|
14031
|
+
return list2[at].id;
|
|
14032
|
+
}
|
|
14033
|
+
}
|
|
14034
|
+
const id = options.id ?? `toast-${++toastSeq}`;
|
|
14035
|
+
const entry = { id, ...base, shown: false, version: 0 };
|
|
14036
|
+
createdIds.current.push(id);
|
|
14037
|
+
commit([...list2, entry]);
|
|
14038
|
+
announce(entry);
|
|
14039
|
+
return id;
|
|
14040
|
+
}, [duration, coalesce, commit, announce]);
|
|
14041
|
+
const api = useMemo(() => ({
|
|
14042
|
+
toast,
|
|
14043
|
+
success: (m, o) => toast(m, { ...o, variant: "success" }),
|
|
14044
|
+
warning: (m, o) => toast(m, { ...o, variant: "warning" }),
|
|
14045
|
+
error: (m, o) => toast(m, { ...o, variant: "error" }),
|
|
14046
|
+
update,
|
|
14047
|
+
dismiss: remove,
|
|
14048
|
+
dismissAll,
|
|
14049
|
+
promise: async (promise, messages, options = {}) => {
|
|
14050
|
+
const id = toast(messages.loading, { ...options, variant: "default", duration: Infinity });
|
|
14051
|
+
try {
|
|
14052
|
+
const value = await promise;
|
|
14053
|
+
update(id, typeof messages.success === "function" ? messages.success(value) : messages.success, { variant: "success", duration });
|
|
14054
|
+
return value;
|
|
14055
|
+
} catch (err) {
|
|
14056
|
+
update(id, typeof messages.error === "function" ? messages.error(err) : messages.error, { variant: "error", duration });
|
|
14057
|
+
throw err;
|
|
14058
|
+
}
|
|
14059
|
+
}
|
|
14060
|
+
}), [toast, update, remove, dismissAll, duration]);
|
|
14061
|
+
const ledger = useMemo(() => ({
|
|
14062
|
+
created: () => createdIds.current.length,
|
|
14063
|
+
latestSince: (count) => {
|
|
14064
|
+
if (createdIds.current.length <= count) return void 0;
|
|
14065
|
+
const id = createdIds.current[createdIds.current.length - 1];
|
|
14066
|
+
const entry = entries.current.find((t) => t.id === id);
|
|
14067
|
+
return entry ? { id, message: entry.message } : void 0;
|
|
14068
|
+
}
|
|
14069
|
+
}), []);
|
|
14070
|
+
const pressAction = useCallback((id) => {
|
|
14071
|
+
const entry = entries.current.find((t) => t.id === id);
|
|
14072
|
+
if (!entry?.action) return;
|
|
14073
|
+
const run = entry.action.onClick;
|
|
14074
|
+
leaving();
|
|
14075
|
+
commit(entries.current.map((t) => t.id === id ? { ...t, action: void 0, actionWindow: void 0, version: t.version + 1 } : t));
|
|
14076
|
+
answering.current.push(id);
|
|
14077
|
+
const done = () => {
|
|
14078
|
+
const waiting2 = answering.current.indexOf(id);
|
|
14079
|
+
if (waiting2 === -1) return;
|
|
14080
|
+
answering.current.splice(waiting2, 1);
|
|
14081
|
+
remove(id);
|
|
14082
|
+
};
|
|
14083
|
+
let result;
|
|
14084
|
+
try {
|
|
14085
|
+
result = run();
|
|
14086
|
+
} catch {
|
|
14087
|
+
result = void 0;
|
|
14088
|
+
}
|
|
14089
|
+
if (result && typeof result.then === "function") result.then(done, done);
|
|
14090
|
+
else done();
|
|
14091
|
+
}, [commit, leaving, remove]);
|
|
14092
|
+
const lapse = useCallback((id) => {
|
|
14093
|
+
const list2 = entries.current;
|
|
14094
|
+
const at = list2.findIndex((t) => t.id === id);
|
|
14095
|
+
if (at === -1) return;
|
|
14096
|
+
const next = [...list2];
|
|
14097
|
+
next[at] = { ...list2[at], action: void 0, actionWindow: void 0, version: list2[at].version + 1 };
|
|
14098
|
+
commit(next);
|
|
14099
|
+
}, [commit]);
|
|
14100
|
+
useEffect(() => {
|
|
14101
|
+
const onKey = (e) => {
|
|
14102
|
+
if (e.key !== "F8" || e.defaultPrevented) return;
|
|
14103
|
+
const stack = stackRef.current;
|
|
14104
|
+
if (!stack) return;
|
|
14105
|
+
e.preventDefault();
|
|
14106
|
+
const active = document.activeElement;
|
|
14107
|
+
if (!stack.contains(active)) {
|
|
14108
|
+
returnTo.current = active instanceof HTMLElement && active !== document.body ? active : null;
|
|
14109
|
+
viaKey.current = true;
|
|
14110
|
+
}
|
|
14111
|
+
(stack.querySelector("button") ?? stack).focus();
|
|
14112
|
+
viaKey.current = false;
|
|
14113
|
+
};
|
|
14114
|
+
document.addEventListener("keydown", onKey);
|
|
14115
|
+
return () => document.removeEventListener("keydown", onKey);
|
|
14116
|
+
}, []);
|
|
14117
|
+
useEffect(() => {
|
|
14118
|
+
if (!refocus.current) return;
|
|
14119
|
+
refocus.current = false;
|
|
14120
|
+
const back = returnTo.current;
|
|
14121
|
+
const next = stackRef.current?.querySelector("button");
|
|
14122
|
+
const main = document.querySelector("main");
|
|
14123
|
+
if (back?.isConnected) back.focus();
|
|
14124
|
+
else if (next) next.focus();
|
|
14125
|
+
else if (main) {
|
|
14126
|
+
if (!main.hasAttribute("tabindex")) {
|
|
14127
|
+
main.setAttribute("tabindex", "-1");
|
|
14128
|
+
main.addEventListener("blur", () => main.removeAttribute("tabindex"), { once: true });
|
|
14129
|
+
}
|
|
14130
|
+
main.focus();
|
|
14131
|
+
}
|
|
14132
|
+
}, [list]);
|
|
14133
|
+
const shown = list.filter((t) => t.shown);
|
|
14134
|
+
const waiting = list.length - shown.length;
|
|
14135
|
+
const isTop = position.startsWith("top");
|
|
14136
|
+
const hasBottomNav = isMobile && bottomNavs > 0;
|
|
14137
|
+
return /* @__PURE__ */ jsx(ToastContext.Provider, { value: api, children: /* @__PURE__ */ jsxs(ToastLedgerCtx.Provider, { value: ledger, children: [
|
|
14138
|
+
/* @__PURE__ */ jsx(BottomNavPresenceCtx.Provider, { value: registerBottomNav, children }),
|
|
14139
|
+
/* @__PURE__ */ jsx("div", { className: "sr-only", role: "status", "aria-live": "polite", "data-toast-announcer": "polite", children: heard.filter((h) => !h.assertive).map((h) => /* @__PURE__ */ jsx("p", { children: h.node }, h.id)) }),
|
|
14140
|
+
/* @__PURE__ */ jsx("div", { className: "sr-only", role: "alert", "aria-live": "assertive", "data-toast-announcer": "assertive", children: heard.filter((h) => h.assertive).map((h) => /* @__PURE__ */ jsx("p", { children: h.node }, h.id)) }),
|
|
14141
|
+
shown.length > 0 && createPortal(
|
|
14142
|
+
/* @__PURE__ */ jsxs(
|
|
14143
|
+
"div",
|
|
14144
|
+
{
|
|
14145
|
+
ref: stackRef,
|
|
14146
|
+
role: "region",
|
|
14147
|
+
"aria-label": "Notifications",
|
|
14148
|
+
tabIndex: -1,
|
|
14149
|
+
"data-mode": mode,
|
|
14150
|
+
"data-toast-stack": "",
|
|
14151
|
+
onMouseEnter: () => setHovered(true),
|
|
14152
|
+
onMouseLeave: () => setHovered(false),
|
|
14153
|
+
onFocusCapture: (e) => {
|
|
14154
|
+
setFocusInside(true);
|
|
14155
|
+
const from = e.relatedTarget;
|
|
14156
|
+
if (viaKey.current || from instanceof Node && e.currentTarget.contains(from)) return;
|
|
14157
|
+
returnTo.current = from instanceof HTMLElement ? from : null;
|
|
14158
|
+
},
|
|
14159
|
+
onBlurCapture: (e) => {
|
|
14160
|
+
if (!e.currentTarget.contains(e.relatedTarget)) setFocusInside(false);
|
|
14161
|
+
},
|
|
14162
|
+
className: cn(
|
|
14163
|
+
"fixed z-[var(--ds-z-toast)] flex gap-ds-2 pointer-events-none outline-none",
|
|
14164
|
+
isTop ? "flex-col" : "flex-col-reverse",
|
|
14165
|
+
isMobile ? cn("left-ds-4 right-ds-4", !hasBottomNav && "bottom-ds-4") : TOAST_POSITION_CLASSES[position]
|
|
14166
|
+
),
|
|
14167
|
+
style: hasBottomNav ? { bottom: "calc(var(--ds-space-12) + var(--ds-space-2) + var(--ds-space-4) + env(safe-area-inset-bottom))" } : void 0,
|
|
14168
|
+
children: [
|
|
14169
|
+
shown.map((t) => /* @__PURE__ */ jsx("div", { className: "pointer-events-auto", children: /* @__PURE__ */ jsx(
|
|
14170
|
+
Toast,
|
|
14171
|
+
{
|
|
14172
|
+
inline: true,
|
|
14173
|
+
visible: true,
|
|
14174
|
+
variant: t.variant,
|
|
14175
|
+
message: t.message,
|
|
14176
|
+
duration: t.duration,
|
|
14177
|
+
action: t.action,
|
|
14178
|
+
actionWindow: t.actionWindow,
|
|
14179
|
+
mode,
|
|
14180
|
+
paused,
|
|
14181
|
+
restartKey: t.version,
|
|
14182
|
+
onAction: () => pressAction(t.id),
|
|
14183
|
+
onActionLapse: () => lapse(t.id),
|
|
14184
|
+
onDismiss: () => remove(t.id)
|
|
14185
|
+
}
|
|
14186
|
+
) }, t.id)),
|
|
14187
|
+
(waiting > 0 || shown.length >= 2) && /* @__PURE__ */ jsxs("div", { className: "pointer-events-auto flex items-center justify-end gap-ds-2 text-xs", "data-toast-overflow": "", children: [
|
|
14188
|
+
waiting > 0 && /* @__PURE__ */ jsxs("span", { className: "rounded-[var(--ds-radius-full)] bg-[var(--ds-bg-muted)] px-ds-2 py-ds-0.5 font-medium text-[var(--ds-text-secondary)]", children: [
|
|
14189
|
+
"+",
|
|
14190
|
+
waiting,
|
|
14191
|
+
/* @__PURE__ */ jsx("span", { className: "sr-only", children: " more waiting" })
|
|
14192
|
+
] }),
|
|
14193
|
+
/* @__PURE__ */ jsx("button", { type: "button", onClick: dismissAll, className: "font-medium text-[var(--ds-text-secondary)] hover:text-[var(--ds-text-primary)] hover:underline cursor-pointer", children: "Clear all" })
|
|
14194
|
+
] })
|
|
14195
|
+
]
|
|
14196
|
+
}
|
|
14197
|
+
),
|
|
14198
|
+
document.body
|
|
14199
|
+
)
|
|
14200
|
+
] }) });
|
|
14201
|
+
}
|
|
14202
|
+
function BottomNav({ items, onItemClick, maxVisible = 5, className, ref }) {
|
|
14203
|
+
const registerWithToasts = useContext(BottomNavPresenceCtx);
|
|
14204
|
+
useEffect(() => registerWithToasts?.(), [registerWithToasts]);
|
|
14205
|
+
const needsOverflow = items.length > maxVisible;
|
|
14206
|
+
const visibleItems = needsOverflow ? items.slice(0, maxVisible - 1) : items;
|
|
14207
|
+
const overflowItems = needsOverflow ? items.slice(maxVisible - 1) : [];
|
|
14208
|
+
const overflowHasActive = overflowItems.some((it) => it.active);
|
|
14209
|
+
const [overflowOpen, setOverflowOpen] = useState(false);
|
|
14210
|
+
const menuRef = useRef(null);
|
|
14211
|
+
const closeOverflow = useCallback(() => setOverflowOpen(false), []);
|
|
14212
|
+
useEffect(() => {
|
|
14213
|
+
if (!overflowOpen) return;
|
|
14214
|
+
function handleClick(e) {
|
|
14215
|
+
if (menuRef.current && !menuRef.current.contains(e.target)) closeOverflow();
|
|
14216
|
+
}
|
|
14217
|
+
document.addEventListener("mousedown", handleClick);
|
|
13515
14218
|
return () => document.removeEventListener("mousedown", handleClick);
|
|
13516
14219
|
}, [overflowOpen, closeOverflow]);
|
|
13517
14220
|
return /* @__PURE__ */ jsxs(
|
|
@@ -13533,6 +14236,7 @@ function BottomNav({ items, onItemClick, maxVisible = 5, className, ref }) {
|
|
|
13533
14236
|
/* @__PURE__ */ jsxs(
|
|
13534
14237
|
"button",
|
|
13535
14238
|
{
|
|
14239
|
+
type: "button",
|
|
13536
14240
|
onClick: () => setOverflowOpen(!overflowOpen),
|
|
13537
14241
|
"aria-expanded": overflowOpen,
|
|
13538
14242
|
"aria-haspopup": "true",
|
|
@@ -13560,6 +14264,7 @@ function BottomNav({ items, onItemClick, maxVisible = 5, className, ref }) {
|
|
|
13560
14264
|
children: overflowItems.map((item, i) => /* @__PURE__ */ jsxs(
|
|
13561
14265
|
"button",
|
|
13562
14266
|
{
|
|
14267
|
+
type: "button",
|
|
13563
14268
|
role: "menuitem",
|
|
13564
14269
|
onClick: () => {
|
|
13565
14270
|
onItemClick?.(item, maxVisible - 1 + i);
|
|
@@ -13589,6 +14294,7 @@ function NavButton({ item, onClick }) {
|
|
|
13589
14294
|
return /* @__PURE__ */ jsxs(
|
|
13590
14295
|
"button",
|
|
13591
14296
|
{
|
|
14297
|
+
type: "button",
|
|
13592
14298
|
onClick,
|
|
13593
14299
|
className: cn(
|
|
13594
14300
|
"flex flex-col items-center justify-center gap-ds-0.5 flex-1 h-full",
|
|
@@ -14991,6 +15697,7 @@ function NavMenu({
|
|
|
14991
15697
|
/* @__PURE__ */ jsxs(
|
|
14992
15698
|
"button",
|
|
14993
15699
|
{
|
|
15700
|
+
type: "button",
|
|
14994
15701
|
ref: triggerRef,
|
|
14995
15702
|
onClick: () => setOpen(!open),
|
|
14996
15703
|
"aria-expanded": open,
|
|
@@ -15187,7 +15894,8 @@ var sizeClasses = {
|
|
|
15187
15894
|
full: "max-w-[calc(100vw-2rem)]"
|
|
15188
15895
|
};
|
|
15189
15896
|
function Dialog({ open, onClose: onCloseProp, title, description, children, footer, variant = "default", size = "md", alert = false, container, onSubmit, dirty, onDiscard }) {
|
|
15190
|
-
const
|
|
15897
|
+
const { marked, mark } = useOverlayMark(open);
|
|
15898
|
+
const guard = useDirtyGuard(dirty ?? marked, onCloseProp, onDiscard);
|
|
15191
15899
|
const onClose = guard.requestClose;
|
|
15192
15900
|
const titleId = useId();
|
|
15193
15901
|
const descriptionId = useId();
|
|
@@ -15324,7 +16032,7 @@ function Dialog({ open, onClose: onCloseProp, title, description, children, foot
|
|
|
15324
16032
|
}
|
|
15325
16033
|
),
|
|
15326
16034
|
description && /* @__PURE__ */ jsx("p", { id: descriptionId, className: "mt-ds-2 text-sm text-[var(--ds-text-muted)]", children: description }),
|
|
15327
|
-
children && /* @__PURE__ */ jsx("div", { className: "mt-ds-4", children: /* @__PURE__ */ jsx(OverlayCloseCtx, { value: onClose, children }) })
|
|
16035
|
+
children && /* @__PURE__ */ jsx("div", { className: "mt-ds-4", children: /* @__PURE__ */ jsx(OverlayMarkCtx, { value: mark, children: /* @__PURE__ */ jsx(OverlayCloseCtx, { value: onClose, children }) }) })
|
|
15328
16036
|
] })
|
|
15329
16037
|
] }) }),
|
|
15330
16038
|
/* @__PURE__ */ jsx(DiscardConfirm, { open: guard.confirming, onKeep: guard.keep, onDiscard: guard.discard }),
|
|
@@ -15350,6 +16058,7 @@ function HamburgerButton({ onClick, open, className: cls }) {
|
|
|
15350
16058
|
return /* @__PURE__ */ jsx(
|
|
15351
16059
|
"button",
|
|
15352
16060
|
{
|
|
16061
|
+
type: "button",
|
|
15353
16062
|
onClick,
|
|
15354
16063
|
"aria-label": open ? "Close navigation menu" : "Open navigation menu",
|
|
15355
16064
|
"aria-expanded": open ?? void 0,
|
|
@@ -15652,6 +16361,7 @@ function MobileMenuItem({
|
|
|
15652
16361
|
return /* @__PURE__ */ jsxs(
|
|
15653
16362
|
"button",
|
|
15654
16363
|
{
|
|
16364
|
+
type: "button",
|
|
15655
16365
|
onClick,
|
|
15656
16366
|
className: cn(
|
|
15657
16367
|
"flex items-center gap-ds-3 px-ds-3 py-ds-3 text-sm relative cursor-pointer w-full text-left",
|
|
@@ -15676,6 +16386,7 @@ function MobileMenuItem({
|
|
|
15676
16386
|
return /* @__PURE__ */ jsxs(
|
|
15677
16387
|
"button",
|
|
15678
16388
|
{
|
|
16389
|
+
type: "button",
|
|
15679
16390
|
onClick,
|
|
15680
16391
|
className: cn(
|
|
15681
16392
|
"flex items-center gap-ds-3 px-ds-3 py-ds-2.5 text-sm cursor-pointer w-full text-left",
|
|
@@ -15693,6 +16404,7 @@ function MobileMenuItem({
|
|
|
15693
16404
|
return /* @__PURE__ */ jsxs(
|
|
15694
16405
|
"button",
|
|
15695
16406
|
{
|
|
16407
|
+
type: "button",
|
|
15696
16408
|
onClick,
|
|
15697
16409
|
className: cn(
|
|
15698
16410
|
"flex items-center gap-ds-3 px-ds-3 py-ds-2.5 text-sm rounded-[var(--ds-radius-md)] cursor-pointer w-full text-left",
|
|
@@ -15709,6 +16421,7 @@ function MobileMenuItem({
|
|
|
15709
16421
|
return /* @__PURE__ */ jsxs(
|
|
15710
16422
|
"button",
|
|
15711
16423
|
{
|
|
16424
|
+
type: "button",
|
|
15712
16425
|
onClick,
|
|
15713
16426
|
className: cn(
|
|
15714
16427
|
"flex items-center gap-ds-3 px-ds-3 py-ds-2.5 text-sm rounded-[var(--ds-radius-md)] cursor-pointer w-full text-left",
|
|
@@ -15870,6 +16583,7 @@ function CommandPalette({ open, onOpenChange, commands, placeholder = "Type a co
|
|
|
15870
16583
|
return /* @__PURE__ */ jsxs(
|
|
15871
16584
|
"button",
|
|
15872
16585
|
{
|
|
16586
|
+
type: "button",
|
|
15873
16587
|
id: `${listboxId}-opt-${myIdx}`,
|
|
15874
16588
|
role: "option",
|
|
15875
16589
|
tabIndex: -1,
|
|
@@ -16058,6 +16772,7 @@ function ContextMenu({ items, children, className, ref, container }) {
|
|
|
16058
16772
|
return /* @__PURE__ */ jsxs(
|
|
16059
16773
|
"button",
|
|
16060
16774
|
{
|
|
16775
|
+
type: "button",
|
|
16061
16776
|
role: "menuitem",
|
|
16062
16777
|
disabled: item.disabled,
|
|
16063
16778
|
onClick: () => {
|
|
@@ -16168,6 +16883,7 @@ function NotificationCenter({
|
|
|
16168
16883
|
/* @__PURE__ */ jsx("div", { className: "flex items-center gap-ds-3", children: unreadCount > 0 && /* @__PURE__ */ jsx(
|
|
16169
16884
|
"button",
|
|
16170
16885
|
{
|
|
16886
|
+
type: "button",
|
|
16171
16887
|
onClick: onMarkAllRead,
|
|
16172
16888
|
className: "text-sm text-[var(--ds-accent-primary)] hover:underline cursor-pointer",
|
|
16173
16889
|
children: "Mark all read"
|
|
@@ -16178,6 +16894,7 @@ function NotificationCenter({
|
|
|
16178
16894
|
/* @__PURE__ */ jsx(
|
|
16179
16895
|
"button",
|
|
16180
16896
|
{
|
|
16897
|
+
type: "button",
|
|
16181
16898
|
onClick: () => setFilter("all"),
|
|
16182
16899
|
className: cn(
|
|
16183
16900
|
"px-ds-3 py-ds-1.5 text-sm rounded-[var(--ds-radius-md)] transition-colors cursor-pointer",
|
|
@@ -16189,6 +16906,7 @@ function NotificationCenter({
|
|
|
16189
16906
|
/* @__PURE__ */ jsxs(
|
|
16190
16907
|
"button",
|
|
16191
16908
|
{
|
|
16909
|
+
type: "button",
|
|
16192
16910
|
onClick: () => setFilter("unread"),
|
|
16193
16911
|
className: cn(
|
|
16194
16912
|
"px-ds-3 py-ds-1.5 text-sm rounded-[var(--ds-radius-md)] transition-colors cursor-pointer",
|
|
@@ -16238,6 +16956,7 @@ function NotificationCenter({
|
|
|
16238
16956
|
!n.read && onMarkRead && /* @__PURE__ */ jsx(
|
|
16239
16957
|
"button",
|
|
16240
16958
|
{
|
|
16959
|
+
type: "button",
|
|
16241
16960
|
onClick: () => onMarkRead(n.id),
|
|
16242
16961
|
"aria-label": "Mark as read",
|
|
16243
16962
|
className: "text-[var(--ds-text-muted)] hover:text-[var(--ds-text-primary)] transition-colors cursor-pointer p-ds-0.5",
|
|
@@ -16247,6 +16966,7 @@ function NotificationCenter({
|
|
|
16247
16966
|
onDismiss && /* @__PURE__ */ jsx(
|
|
16248
16967
|
"button",
|
|
16249
16968
|
{
|
|
16969
|
+
type: "button",
|
|
16250
16970
|
onClick: () => onDismiss(n.id),
|
|
16251
16971
|
"aria-label": "Dismiss",
|
|
16252
16972
|
className: "text-[var(--ds-text-muted)] hover:text-[var(--ds-text-primary)] transition-colors cursor-pointer p-ds-0.5",
|
|
@@ -16265,6 +16985,7 @@ function NotificationCenter({
|
|
|
16265
16985
|
/* @__PURE__ */ jsxs(
|
|
16266
16986
|
"button",
|
|
16267
16987
|
{
|
|
16988
|
+
type: "button",
|
|
16268
16989
|
ref: triggerRef,
|
|
16269
16990
|
onClick: () => setOpen(!open),
|
|
16270
16991
|
"aria-label": `Notifications${unreadCount ? ` (${unreadCount} unread)` : ""}`,
|
|
@@ -16304,6 +17025,7 @@ function NotificationCenter({
|
|
|
16304
17025
|
unreadCount > 0 && /* @__PURE__ */ jsx(
|
|
16305
17026
|
"button",
|
|
16306
17027
|
{
|
|
17028
|
+
type: "button",
|
|
16307
17029
|
onClick: onMarkAllRead,
|
|
16308
17030
|
className: "text-xs text-[var(--ds-accent-primary)] hover:underline cursor-pointer",
|
|
16309
17031
|
children: "Mark all read"
|
|
@@ -16348,6 +17070,7 @@ function NotificationCenter({
|
|
|
16348
17070
|
!n.read && onMarkRead && /* @__PURE__ */ jsx(
|
|
16349
17071
|
"button",
|
|
16350
17072
|
{
|
|
17073
|
+
type: "button",
|
|
16351
17074
|
onClick: () => onMarkRead(n.id),
|
|
16352
17075
|
"aria-label": "Mark as read",
|
|
16353
17076
|
className: "text-[var(--ds-text-muted)] hover:text-[var(--ds-text-primary)] transition-colors cursor-pointer p-ds-0.5",
|
|
@@ -16357,6 +17080,7 @@ function NotificationCenter({
|
|
|
16357
17080
|
onDismiss && /* @__PURE__ */ jsx(
|
|
16358
17081
|
"button",
|
|
16359
17082
|
{
|
|
17083
|
+
type: "button",
|
|
16360
17084
|
onClick: () => onDismiss(n.id),
|
|
16361
17085
|
"aria-label": "Dismiss",
|
|
16362
17086
|
className: "text-[var(--ds-text-muted)] hover:text-[var(--ds-text-primary)] transition-colors cursor-pointer p-ds-0.5",
|
|
@@ -16520,6 +17244,7 @@ function Tour({ steps, open, onClose, onComplete, container }) {
|
|
|
16520
17244
|
/* @__PURE__ */ jsx(
|
|
16521
17245
|
"button",
|
|
16522
17246
|
{
|
|
17247
|
+
type: "button",
|
|
16523
17248
|
onClick: onClose,
|
|
16524
17249
|
className: "shrink-0 text-[var(--ds-text-muted)] hover:text-[var(--ds-text-primary)] transition-colors cursor-pointer -mt-ds-0.5",
|
|
16525
17250
|
"aria-label": "Close tour",
|
|
@@ -16539,6 +17264,7 @@ function Tour({ steps, open, onClose, onComplete, container }) {
|
|
|
16539
17264
|
current > 0 && /* @__PURE__ */ jsx(
|
|
16540
17265
|
"button",
|
|
16541
17266
|
{
|
|
17267
|
+
type: "button",
|
|
16542
17268
|
onClick: handlePrev,
|
|
16543
17269
|
className: cn(
|
|
16544
17270
|
"px-ds-3 py-ds-1.5 text-xs font-medium rounded-[var(--ds-radius-sm)]",
|
|
@@ -16552,6 +17278,7 @@ function Tour({ steps, open, onClose, onComplete, container }) {
|
|
|
16552
17278
|
/* @__PURE__ */ jsx(
|
|
16553
17279
|
"button",
|
|
16554
17280
|
{
|
|
17281
|
+
type: "button",
|
|
16555
17282
|
ref: nextRef,
|
|
16556
17283
|
onClick: handleNext,
|
|
16557
17284
|
className: cn(
|
|
@@ -16600,223 +17327,6 @@ function getPopoverPosition(rect, placement, padding) {
|
|
|
16600
17327
|
top = Math.max(8, Math.min(top, window.innerHeight - popH - 8));
|
|
16601
17328
|
return { top, left };
|
|
16602
17329
|
}
|
|
16603
|
-
var variantStyles4 = {
|
|
16604
|
-
default: "border-[var(--ds-border-default)] bg-[var(--ds-bg-surface)]",
|
|
16605
|
-
success: "border-[var(--ds-status-success)] bg-[var(--ds-status-success-bg)]",
|
|
16606
|
-
warning: "border-[var(--ds-status-warning)] bg-[var(--ds-status-warning-bg)]",
|
|
16607
|
-
error: "border-[var(--ds-status-error)] bg-[var(--ds-status-error-bg)]"
|
|
16608
|
-
};
|
|
16609
|
-
var variantIcons = {
|
|
16610
|
-
default: { name: "info", className: "text-[var(--ds-text-muted)]" },
|
|
16611
|
-
success: { name: "check", className: "text-[var(--ds-status-success)]" },
|
|
16612
|
-
warning: { name: "warning", className: "text-[var(--ds-status-warning)]" },
|
|
16613
|
-
error: { name: "error", className: "text-[var(--ds-status-error)]" }
|
|
16614
|
-
};
|
|
16615
|
-
var TOAST_POSITION_CLASSES = {
|
|
16616
|
-
"top-right": "top-[var(--ds-toast-inset-top)] right-[var(--ds-toast-inset-right)]",
|
|
16617
|
-
"top-left": "top-[var(--ds-toast-inset-top)] left-[var(--ds-toast-inset-left)]",
|
|
16618
|
-
"bottom-right": "bottom-[var(--ds-toast-inset-bottom-right)] right-[var(--ds-toast-inset-right)]",
|
|
16619
|
-
"bottom-left": "bottom-[var(--ds-toast-inset-bottom-left)] left-[var(--ds-toast-inset-left)]",
|
|
16620
|
-
"top-center": "top-[var(--ds-toast-inset-top)] left-1/2 -translate-x-1/2",
|
|
16621
|
-
"bottom-center": "bottom-ds-4 left-1/2 -translate-x-1/2"
|
|
16622
|
-
};
|
|
16623
|
-
function Toast({ variant = "default", message, visible, onDismiss, duration = 5e3, pauseOnHover = false, action, position = "bottom-right", mode, container, inline = false }) {
|
|
16624
|
-
const isMobile = useBreakpoint("sm");
|
|
16625
|
-
const isCentered = position === "top-center" || position === "bottom-center";
|
|
16626
|
-
const timerRef = useRef(void 0);
|
|
16627
|
-
const startedAtRef = useRef(0);
|
|
16628
|
-
const remainingRef = useRef(duration);
|
|
16629
|
-
const onDismissRef = useLatest(onDismiss);
|
|
16630
|
-
const startTimer = useCallback((ms) => {
|
|
16631
|
-
const delay = ms ?? remainingRef.current;
|
|
16632
|
-
remainingRef.current = delay;
|
|
16633
|
-
startedAtRef.current = Date.now();
|
|
16634
|
-
if (!Number.isFinite(delay) || delay <= 0) return;
|
|
16635
|
-
timerRef.current = setTimeout(() => onDismissRef.current(), delay);
|
|
16636
|
-
}, [onDismissRef]);
|
|
16637
|
-
const clearTimer = useCallback(() => {
|
|
16638
|
-
if (timerRef.current) {
|
|
16639
|
-
clearTimeout(timerRef.current);
|
|
16640
|
-
remainingRef.current -= Date.now() - startedAtRef.current;
|
|
16641
|
-
}
|
|
16642
|
-
}, []);
|
|
16643
|
-
useEffect(() => {
|
|
16644
|
-
if (!visible) return;
|
|
16645
|
-
remainingRef.current = duration;
|
|
16646
|
-
startTimer(duration);
|
|
16647
|
-
return () => {
|
|
16648
|
-
if (timerRef.current) clearTimeout(timerRef.current);
|
|
16649
|
-
};
|
|
16650
|
-
}, [visible, duration, startTimer]);
|
|
16651
|
-
const handleMouseEnter = pauseOnHover ? () => {
|
|
16652
|
-
clearTimer();
|
|
16653
|
-
} : void 0;
|
|
16654
|
-
const handleMouseLeave = pauseOnHover ? () => {
|
|
16655
|
-
startTimer();
|
|
16656
|
-
} : void 0;
|
|
16657
|
-
if (!visible) return null;
|
|
16658
|
-
const icon = variantIcons[variant];
|
|
16659
|
-
const card = /* @__PURE__ */ jsxs(
|
|
16660
|
-
"div",
|
|
16661
|
-
{
|
|
16662
|
-
role: variant === "error" ? "alert" : "status",
|
|
16663
|
-
"aria-live": variant === "error" ? "assertive" : "polite",
|
|
16664
|
-
"data-mode": inline ? mode : void 0,
|
|
16665
|
-
onMouseEnter: inline ? handleMouseEnter : void 0,
|
|
16666
|
-
onMouseLeave: inline ? handleMouseLeave : void 0,
|
|
16667
|
-
className: cn(
|
|
16668
|
-
"flex items-center gap-ds-3 px-ds-4 py-ds-3",
|
|
16669
|
-
isCentered ? "min-w-[360px] max-w-[560px]" : "min-w-[280px] max-w-[420px]",
|
|
16670
|
-
"border-[length:var(--ds-border-width)]",
|
|
16671
|
-
GLASS_DROPDOWN,
|
|
16672
|
-
"rounded-[var(--ds-radius-md)]",
|
|
16673
|
-
"text-sm text-[var(--ds-text-primary)]",
|
|
16674
|
-
variantStyles4[variant]
|
|
16675
|
-
),
|
|
16676
|
-
children: [
|
|
16677
|
-
/* @__PURE__ */ jsx(Icon, { name: icon.name, size: 18, className: cn("shrink-0", icon.className) }),
|
|
16678
|
-
/* @__PURE__ */ jsx("span", { className: "flex-1", children: message }),
|
|
16679
|
-
action && /* @__PURE__ */ jsx(
|
|
16680
|
-
"button",
|
|
16681
|
-
{
|
|
16682
|
-
type: "button",
|
|
16683
|
-
onClick: action.onClick,
|
|
16684
|
-
className: "shrink-0 text-xs font-semibold text-[var(--ds-accent-primary)] hover:underline cursor-pointer",
|
|
16685
|
-
children: action.label
|
|
16686
|
-
}
|
|
16687
|
-
),
|
|
16688
|
-
/* @__PURE__ */ jsx(
|
|
16689
|
-
"button",
|
|
16690
|
-
{
|
|
16691
|
-
type: "button",
|
|
16692
|
-
onClick: onDismiss,
|
|
16693
|
-
"aria-label": "Dismiss notification",
|
|
16694
|
-
className: "text-[var(--ds-text-muted)] hover:text-[var(--ds-text-primary)] transition-colors cursor-pointer shrink-0",
|
|
16695
|
-
children: /* @__PURE__ */ jsx(Icon, { name: "close", size: 16 })
|
|
16696
|
-
}
|
|
16697
|
-
)
|
|
16698
|
-
]
|
|
16699
|
-
}
|
|
16700
|
-
);
|
|
16701
|
-
if (inline) return card;
|
|
16702
|
-
return createPortal(
|
|
16703
|
-
/* @__PURE__ */ jsx(
|
|
16704
|
-
"div",
|
|
16705
|
-
{
|
|
16706
|
-
"data-mode": mode,
|
|
16707
|
-
onMouseEnter: handleMouseEnter,
|
|
16708
|
-
onMouseLeave: handleMouseLeave,
|
|
16709
|
-
className: cn(
|
|
16710
|
-
"fixed z-[var(--ds-z-toast)]",
|
|
16711
|
-
isMobile ? "bottom-ds-4 left-ds-4 right-ds-4" : TOAST_POSITION_CLASSES[position]
|
|
16712
|
-
),
|
|
16713
|
-
children: card
|
|
16714
|
-
}
|
|
16715
|
-
),
|
|
16716
|
-
container ?? document.body
|
|
16717
|
-
);
|
|
16718
|
-
}
|
|
16719
|
-
var ToastContext = createContext(null);
|
|
16720
|
-
function useToast() {
|
|
16721
|
-
const ctx = useContext(ToastContext);
|
|
16722
|
-
if (!ctx) {
|
|
16723
|
-
throw new Error("useToast must be used within <ToastProvider>: the app shell's (get_app_shell writes it around AppShell). A page outside the shell (sign-in, a public page) shows its messages inline instead: an Alert above the form, and each field's error below the field.");
|
|
16724
|
-
}
|
|
16725
|
-
return ctx;
|
|
16726
|
-
}
|
|
16727
|
-
function useToastOptional() {
|
|
16728
|
-
return useContext(ToastContext);
|
|
16729
|
-
}
|
|
16730
|
-
var toastSeq = 0;
|
|
16731
|
-
function ToastProvider({ children, maxVisible = 1, position = "bottom-right", duration = 5e3, mode, pauseOnHover = true, coalesce = true }) {
|
|
16732
|
-
const [queue, setQueue] = useState([]);
|
|
16733
|
-
const isMobile = useBreakpoint("sm");
|
|
16734
|
-
const dismiss = useCallback((id) => {
|
|
16735
|
-
setQueue((q) => q.filter((t) => t.id !== id));
|
|
16736
|
-
}, []);
|
|
16737
|
-
const dismissAll = useCallback(() => setQueue([]), []);
|
|
16738
|
-
const update = useCallback((id, message, options = {}) => {
|
|
16739
|
-
setQueue((q) => q.map((t) => t.id === id ? { ...t, message, variant: options.variant ?? t.variant, duration: options.duration ?? t.duration, action: options.action ?? t.action } : t));
|
|
16740
|
-
}, []);
|
|
16741
|
-
const toast = useCallback((message, options = {}) => {
|
|
16742
|
-
const id = options.id ?? `toast-${++toastSeq}`;
|
|
16743
|
-
const entry = {
|
|
16744
|
-
id,
|
|
16745
|
-
message,
|
|
16746
|
-
variant: options.variant ?? "default",
|
|
16747
|
-
duration: options.duration ?? duration,
|
|
16748
|
-
action: options.action,
|
|
16749
|
-
key: options.key ?? options.variant ?? "default"
|
|
16750
|
-
};
|
|
16751
|
-
const slots = Math.max(1, maxVisible);
|
|
16752
|
-
setQueue((q) => {
|
|
16753
|
-
if (q.some((t) => t.id === id)) return q.map((t) => t.id === id ? entry : t);
|
|
16754
|
-
if (coalesce && q.length >= slots) {
|
|
16755
|
-
const waiting = q.findIndex((t, i) => i >= slots && t.key === entry.key);
|
|
16756
|
-
if (waiting >= 0) {
|
|
16757
|
-
const next = [...q];
|
|
16758
|
-
next[waiting] = entry;
|
|
16759
|
-
return next;
|
|
16760
|
-
}
|
|
16761
|
-
}
|
|
16762
|
-
return [...q, entry];
|
|
16763
|
-
});
|
|
16764
|
-
return id;
|
|
16765
|
-
}, [duration, maxVisible, coalesce]);
|
|
16766
|
-
const api = useMemo(() => ({
|
|
16767
|
-
toast,
|
|
16768
|
-
success: (m, o) => toast(m, { ...o, variant: "success" }),
|
|
16769
|
-
warning: (m, o) => toast(m, { ...o, variant: "warning" }),
|
|
16770
|
-
error: (m, o) => toast(m, { ...o, variant: "error" }),
|
|
16771
|
-
update,
|
|
16772
|
-
dismiss,
|
|
16773
|
-
dismissAll,
|
|
16774
|
-
promise: async (promise, messages, options = {}) => {
|
|
16775
|
-
const id = toast(messages.loading, { ...options, variant: "default", duration: Infinity });
|
|
16776
|
-
try {
|
|
16777
|
-
const value = await promise;
|
|
16778
|
-
update(id, typeof messages.success === "function" ? messages.success(value) : messages.success, { variant: "success", duration });
|
|
16779
|
-
return value;
|
|
16780
|
-
} catch (err) {
|
|
16781
|
-
update(id, typeof messages.error === "function" ? messages.error(err) : messages.error, { variant: "error", duration });
|
|
16782
|
-
throw err;
|
|
16783
|
-
}
|
|
16784
|
-
}
|
|
16785
|
-
}), [toast, update, dismiss, dismissAll, duration]);
|
|
16786
|
-
const visible = queue.slice(0, Math.max(1, maxVisible));
|
|
16787
|
-
const isTop = position.startsWith("top");
|
|
16788
|
-
return /* @__PURE__ */ jsxs(ToastContext.Provider, { value: api, children: [
|
|
16789
|
-
children,
|
|
16790
|
-
visible.length > 0 && createPortal(
|
|
16791
|
-
/* @__PURE__ */ jsx(
|
|
16792
|
-
"div",
|
|
16793
|
-
{
|
|
16794
|
-
"data-mode": mode,
|
|
16795
|
-
className: cn(
|
|
16796
|
-
"fixed z-[var(--ds-z-toast)] flex gap-ds-2 pointer-events-none",
|
|
16797
|
-
isTop ? "flex-col" : "flex-col-reverse",
|
|
16798
|
-
isMobile ? "bottom-ds-4 left-ds-4 right-ds-4" : TOAST_POSITION_CLASSES[position]
|
|
16799
|
-
),
|
|
16800
|
-
children: visible.map((t) => /* @__PURE__ */ jsx("div", { className: "pointer-events-auto", children: /* @__PURE__ */ jsx(
|
|
16801
|
-
Toast,
|
|
16802
|
-
{
|
|
16803
|
-
inline: true,
|
|
16804
|
-
visible: true,
|
|
16805
|
-
variant: t.variant,
|
|
16806
|
-
message: t.message,
|
|
16807
|
-
duration: t.duration,
|
|
16808
|
-
pauseOnHover,
|
|
16809
|
-
action: t.action,
|
|
16810
|
-
mode,
|
|
16811
|
-
onDismiss: () => dismiss(t.id)
|
|
16812
|
-
}
|
|
16813
|
-
) }, t.id))
|
|
16814
|
-
}
|
|
16815
|
-
),
|
|
16816
|
-
document.body
|
|
16817
|
-
)
|
|
16818
|
-
] });
|
|
16819
|
-
}
|
|
16820
17330
|
function firstKey(item) {
|
|
16821
17331
|
if (item !== null && typeof item === "object") return "id" in item ? item.id : void 0;
|
|
16822
17332
|
return item;
|
|
@@ -16879,9 +17389,10 @@ function usePagination(list, options = {}) {
|
|
|
16879
17389
|
};
|
|
16880
17390
|
}
|
|
16881
17391
|
function useDestructiveAction(options) {
|
|
16882
|
-
const { action, title, description, confirmLabel, typeToConfirm, onConfirm, onUndo, undoMessage, severity } = options;
|
|
17392
|
+
const { action, title, description, confirmLabel, typeToConfirm, onConfirm, onUndo, doneMessage, undoMessage, restoredMessage, severity } = options;
|
|
16883
17393
|
const preferences = useShellPreferences();
|
|
16884
17394
|
const toast = useToastOptional();
|
|
17395
|
+
const ledger = useContext(ToastLedgerCtx);
|
|
16885
17396
|
const [open, setOpen] = useState(false);
|
|
16886
17397
|
const [typed, setTyped] = useState("");
|
|
16887
17398
|
const [busy, setBusy] = useState(false);
|
|
@@ -16898,20 +17409,32 @@ function useDestructiveAction(options) {
|
|
|
16898
17409
|
setTyped("");
|
|
16899
17410
|
};
|
|
16900
17411
|
const failureMessage = (err) => err instanceof Error && err.message ? err.message : `${title.replace(/\?$/, "")} failed. Try again.`;
|
|
17412
|
+
const done = doneMessage ?? undoMessage ?? pastTenseOf(label);
|
|
16901
17413
|
const confirm = async () => {
|
|
16902
17414
|
setBusy(true);
|
|
17415
|
+
const before = ledger?.created() ?? 0;
|
|
16903
17416
|
try {
|
|
16904
17417
|
await onConfirm();
|
|
16905
17418
|
close();
|
|
17419
|
+
if (toast && (ledger?.created() ?? 0) === before) toast.success(done);
|
|
16906
17420
|
} catch (err) {
|
|
16907
17421
|
toast?.error(failureMessage(err));
|
|
16908
17422
|
} finally {
|
|
16909
17423
|
setBusy(false);
|
|
16910
17424
|
}
|
|
16911
17425
|
};
|
|
17426
|
+
const undo = async () => {
|
|
17427
|
+
try {
|
|
17428
|
+
await onUndo();
|
|
17429
|
+
toast?.success(restoredMessage ?? "Restored");
|
|
17430
|
+
} catch (err) {
|
|
17431
|
+
toast?.error(err instanceof Error && err.message ? err.message : "Undo didn't work. Try again.");
|
|
17432
|
+
}
|
|
17433
|
+
};
|
|
16912
17434
|
const run = () => {
|
|
16913
17435
|
if (undoable) {
|
|
16914
17436
|
void (async () => {
|
|
17437
|
+
const before = ledger?.created() ?? 0;
|
|
16915
17438
|
try {
|
|
16916
17439
|
await onConfirm();
|
|
16917
17440
|
} catch (err) {
|
|
@@ -16919,7 +17442,10 @@ function useDestructiveAction(options) {
|
|
|
16919
17442
|
return;
|
|
16920
17443
|
}
|
|
16921
17444
|
const seconds = preferences.undoWindowSeconds ?? 5;
|
|
16922
|
-
|
|
17445
|
+
const undoAction = { label: "Undo", onClick: () => undo() };
|
|
17446
|
+
const pages = (ledger?.created() ?? 0) > before ? ledger?.latestSince(before) : void 0;
|
|
17447
|
+
if (pages) toast.update(pages.id, pages.message, { variant: "success", action: undoAction, actionWindow: seconds * 1e3 });
|
|
17448
|
+
else toast.success(done, { action: undoAction, actionWindow: seconds * 1e3 });
|
|
16923
17449
|
})();
|
|
16924
17450
|
return;
|
|
16925
17451
|
}
|
|
@@ -16947,6 +17473,61 @@ function useDestructiveAction(options) {
|
|
|
16947
17473
|
) : null;
|
|
16948
17474
|
return { run, element, open };
|
|
16949
17475
|
}
|
|
17476
|
+
var PAST_TENSE = {
|
|
17477
|
+
delete: "Deleted",
|
|
17478
|
+
remove: "Removed",
|
|
17479
|
+
archive: "Archived",
|
|
17480
|
+
leave: "Left",
|
|
17481
|
+
revoke: "Revoked",
|
|
17482
|
+
disconnect: "Disconnected",
|
|
17483
|
+
cancel: "Cancelled",
|
|
17484
|
+
reset: "Reset",
|
|
17485
|
+
clear: "Cleared",
|
|
17486
|
+
discard: "Discarded",
|
|
17487
|
+
unpublish: "Unpublished",
|
|
17488
|
+
deactivate: "Deactivated",
|
|
17489
|
+
disable: "Disabled",
|
|
17490
|
+
uninstall: "Uninstalled",
|
|
17491
|
+
unsubscribe: "Unsubscribed",
|
|
17492
|
+
block: "Blocked",
|
|
17493
|
+
ban: "Banned",
|
|
17494
|
+
suspend: "Suspended",
|
|
17495
|
+
close: "Closed",
|
|
17496
|
+
end: "Ended",
|
|
17497
|
+
stop: "Stopped",
|
|
17498
|
+
"sign out": "Signed out",
|
|
17499
|
+
"log out": "Logged out",
|
|
17500
|
+
transfer: "Transferred",
|
|
17501
|
+
merge: "Merged",
|
|
17502
|
+
overwrite: "Overwritten",
|
|
17503
|
+
replace: "Replaced",
|
|
17504
|
+
erase: "Erased",
|
|
17505
|
+
purge: "Purged",
|
|
17506
|
+
wipe: "Wiped",
|
|
17507
|
+
drop: "Dropped",
|
|
17508
|
+
detach: "Detached",
|
|
17509
|
+
unlink: "Unlinked",
|
|
17510
|
+
expire: "Expired",
|
|
17511
|
+
reject: "Rejected",
|
|
17512
|
+
decline: "Declined"
|
|
17513
|
+
};
|
|
17514
|
+
var warned2 = /* @__PURE__ */ new Set();
|
|
17515
|
+
function pastTenseOf(label) {
|
|
17516
|
+
const words = label.trim().toLowerCase().split(/\s+/);
|
|
17517
|
+
const found = PAST_TENSE[words.slice(0, 2).join(" ")] ?? PAST_TENSE[words[0] ?? ""];
|
|
17518
|
+
if (found) return found;
|
|
17519
|
+
let dev = false;
|
|
17520
|
+
try {
|
|
17521
|
+
dev = process.env.NODE_ENV !== "production";
|
|
17522
|
+
} catch {
|
|
17523
|
+
dev = false;
|
|
17524
|
+
}
|
|
17525
|
+
if (dev && !warned2.has(label)) {
|
|
17526
|
+
warned2.add(label);
|
|
17527
|
+
console.warn(`useDestructiveAction: "${label}" isn't a verb the hook knows; pass doneMessage so the confirmation says what happened.`);
|
|
17528
|
+
}
|
|
17529
|
+
return "Done";
|
|
17530
|
+
}
|
|
16950
17531
|
var SectionHeading = forwardRef(function SectionHeading2({
|
|
16951
17532
|
title,
|
|
16952
17533
|
description,
|
|
@@ -17087,6 +17668,6 @@ var TextOverflow = forwardRef(function TextOverflow2({
|
|
|
17087
17668
|
return /* @__PURE__ */ jsx(Tooltip, { content: resolvedTooltipContent, children: content });
|
|
17088
17669
|
});
|
|
17089
17670
|
|
|
17090
|
-
export { Accordion, ActionPanel, ActionPanelGroup, Alert, AsidePanel, Avatar, AvatarGroup, BottomNav, Breadcrumbs, BulkActionBar, Calendar, Card, CardContent, CardDescription, CardFooter, CardGrid, CardHeader, CardTitle, Carousel, ChatMessageList, ChatPanel, Checkbox, CheckboxGroup, CheckboxGroupItem, Collapsible, ColorPicker, Combobox, CommandPalette, ContextMenu, CornerPanel, DEFAULT_DATE_RANGE_PRESETS, DataList, DatePicker, DateRangePicker, DescriptionList, Dialog, Dock, Dropdown, DropdownMenu, EmptyState, EntityCell, Field, FileUpload, FormWrapper, Gantt, HoverCard, InlineFieldError, Input, Kbd, Label, Launcher, MentionInput, MobileHeaderMenu, NavItem, NavMenu, Navbar, NotificationCenter, NumberInput, PageContainer, PageHeader, Pagination, PinInput, Popover, Progress, RadioGroup, Rating, ScrollArea, SectionHeading, SegmentedControl, SettingsLayout, Sidebar, SidebarNav, SliderRange, StackedList, StatsCard, StatusDot, Stepper, TIME_ZOOMS, Table, TableToolbar, Tabs, Tag, TagInput, TextOverflow, Textarea, TimeBar, TimePicker, TimeRow, TimeScaleHeader, TimeViewport, Timeline, Toast, ToastProvider, Toggle, Tour, TransferList, TreeView, dateOfDay, dayOf, endDayOf, fitLabel, fitLabels, formatDateRange, timeExtent, useContentWidth, useDestructiveAction, useFittedLabels,
|
|
17671
|
+
export { Accordion, ActionPanel, ActionPanelGroup, AddAnother, Alert, AsidePanel, Avatar, AvatarGroup, BottomNav, Breadcrumbs, BulkActionBar, Calendar, Card, CardContent, CardDescription, CardFooter, CardGrid, CardHeader, CardTitle, Carousel, ChatMessageList, ChatPanel, Checkbox, CheckboxGroup, CheckboxGroupItem, Collapsible, ColorPicker, Combobox, CommandPalette, ContextMenu, CornerPanel, DEFAULT_DATE_RANGE_PRESETS, DataList, DatePicker, DateRangePicker, DescriptionList, Dialog, Dock, Dropdown, DropdownMenu, EmptyState, EntityCell, Field, FileUpload, FormWrapper, Gantt, HoverCard, InlineFieldError, Input, Kbd, Label, Launcher, MentionInput, MobileHeaderMenu, NavItem, NavMenu, Navbar, NotificationCenter, NumberInput, PageContainer, PageHeader, Pagination, PinInput, Popover, Progress, RadioGroup, Rating, ScrollArea, SectionHeading, SegmentedControl, SettingsLayout, Sidebar, SidebarNav, SliderRange, StackedList, StatsCard, StatusDot, Stepper, TIME_ZOOMS, Table, TableToolbar, Tabs, Tag, TagInput, TextOverflow, Textarea, TimeBar, TimePicker, TimeRow, TimeScaleHeader, TimeViewport, Timeline, Toast, ToastProvider, Toggle, Tour, TransferList, TreeView, dateOfDay, dayOf, endDayOf, fitLabel, fitLabels, formatDateRange, timeExtent, useContentWidth, useDestructiveAction, useFittedLabels, usePagination, useSidebar, useTextMeasure, useTimeScale, useTimeViewport, useTimeViewportLayout, useToast, useToastOptional };
|
|
17091
17672
|
//# sourceMappingURL=index.js.map
|
|
17092
17673
|
//# sourceMappingURL=index.js.map
|