gridsmith-ui 0.18.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/charts.js +3 -3
- package/dist/charts.js.map +1 -1
- package/dist/chat.js +4 -4
- package/dist/{chunk-CIVSNXFG.js → chunk-6MXHGH3D.js} +54 -15
- package/dist/chunk-6MXHGH3D.js.map +1 -0
- package/dist/{chunk-XGSQOMEY.js → chunk-EQDR57AM.js} +4 -4
- package/dist/{chunk-XGSQOMEY.js.map → chunk-EQDR57AM.js.map} +1 -1
- package/dist/{chunk-EMCSARQO.js → chunk-ILIODA7W.js} +3 -3
- package/dist/{chunk-EMCSARQO.js.map → chunk-ILIODA7W.js.map} +1 -1
- package/dist/{chunk-OENJCGTJ.js → chunk-JN37OVTP.js} +4 -4
- package/dist/{chunk-OENJCGTJ.js.map → chunk-JN37OVTP.js.map} +1 -1
- package/dist/{chunk-4KVFH5KC.js → chunk-M2QRNBDQ.js} +4 -3
- package/dist/chunk-M2QRNBDQ.js.map +1 -0
- package/dist/{chunk-Z63OSN64.js → chunk-NCIZQYXQ.js} +7 -4
- package/dist/chunk-NCIZQYXQ.js.map +1 -0
- package/dist/chunk-XVB55M3N.js +42 -0
- package/dist/chunk-XVB55M3N.js.map +1 -0
- package/dist/{chunk-PVTGMCVR.js → chunk-XYDIBW3J.js} +4 -4
- package/dist/{chunk-PVTGMCVR.js.map → chunk-XYDIBW3J.js.map} +1 -1
- package/dist/data-grid.js +3 -3
- package/dist/editor.d.ts +38 -2
- package/dist/editor.js +86 -10
- package/dist/editor.js.map +1 -1
- package/dist/index.d.ts +332 -92
- package/dist/index.js +1404 -542
- package/dist/index.js.map +1 -1
- package/dist/kanban.js +3 -3
- package/dist/resizable.d.ts +8 -1
- package/dist/resizable.js +35 -15
- package/dist/resizable.js.map +1 -1
- package/dist/roots.css +164 -2
- package/dist/tailwind.css +14 -0
- package/dist/utils.js +1 -1
- package/dist/virtualized.js +1 -1
- package/dist-static/tailwind.css +14 -0
- package/package.json +1 -1
- package/dist/chunk-4KVFH5KC.js.map +0 -1
- package/dist/chunk-CIVSNXFG.js.map +0 -1
- package/dist/chunk-Z63OSN64.js.map +0 -1
package/dist/index.js
CHANGED
|
@@ -1,24 +1,26 @@
|
|
|
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-
|
|
3
|
-
import { Skeleton } from './chunk-
|
|
4
|
-
export { Skeleton } 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
|
+
import { Skeleton, TITLE_TEXT } from './chunk-NCIZQYXQ.js';
|
|
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
|
-
import { Link } from './chunk-
|
|
8
|
-
export { CodeBlock, Divider, Link } from './chunk-
|
|
9
|
-
import { Badge } from './chunk-
|
|
10
|
-
export { Badge } from './chunk-
|
|
11
|
-
import { inferColumnKinds, CardValue } from './chunk-
|
|
9
|
+
import { Link } from './chunk-EQDR57AM.js';
|
|
10
|
+
export { CodeBlock, Divider, Link } from './chunk-EQDR57AM.js';
|
|
11
|
+
import { Badge } from './chunk-XYDIBW3J.js';
|
|
12
|
+
export { Badge } from './chunk-XYDIBW3J.js';
|
|
13
|
+
import { inferColumnKinds, CardValue } from './chunk-JN37OVTP.js';
|
|
12
14
|
import { SplitPaneCtx, useShellPreferences, TableCardCtx, PREFERENCE_HOUSE_DEFAULTS, preferenceActionKey } from './chunk-TKVTZWBN.js';
|
|
13
15
|
export { PreferencesContext, preferenceActionKey, usePreferences } from './chunk-TKVTZWBN.js';
|
|
14
16
|
import { useBreakpoint, readBreakpointPx } from './chunk-CRQ6KCRD.js';
|
|
15
17
|
export { BreakpointWidthProvider, useBreakpoint } from './chunk-CRQ6KCRD.js';
|
|
16
|
-
import { useTextOverflow, Tooltip, usePosition } from './chunk-
|
|
17
|
-
export { Tooltip, useTextOverflow } from './chunk-
|
|
18
|
+
import { useTextOverflow, Tooltip, usePosition } from './chunk-ILIODA7W.js';
|
|
19
|
+
export { Tooltip, useTextOverflow } from './chunk-ILIODA7W.js';
|
|
18
20
|
import { mergeRefs, Slot } from './chunk-7Q46JXSK.js';
|
|
19
21
|
import { useLatest } from './chunk-WH2FUFAC.js';
|
|
20
22
|
import { Icon } from './chunk-4LDYR7QP.js';
|
|
21
|
-
import { cn, GLASS_SURFACE,
|
|
23
|
+
import { cn, GLASS_SURFACE, GLASS_BACKDROP, GLASS_DROPDOWN, lockBodyScroll, unlockBodyScroll, OVERLAY_SURFACE, GLASS_OVERLAY, ERROR_ACTIVE_RING, ACTIVE_RING, ERROR_FOCUS_RING, FOCUS_RING, ERROR_HAS_FOCUS_RING, HAS_FOCUS_RING, ERROR_FOCUS_WITHIN_RING, FOCUS_WITHIN_RING } from './chunk-M2QRNBDQ.js';
|
|
22
24
|
import { createContext, forwardRef, useState, useRef, useCallback, useLayoutEffect, useMemo, useContext, Children, isValidElement, useId, memo, useEffect, useImperativeHandle, Fragment as Fragment$1, cloneElement, useSyncExternalStore } from 'react';
|
|
23
25
|
import { createPortal, flushSync } from 'react-dom';
|
|
24
26
|
import { jsxs, jsx, Fragment } from 'react/jsx-runtime';
|
|
@@ -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,
|
|
@@ -184,7 +187,7 @@ function BulkActionBar({ selectedCount, actions, onClearSelection, className })
|
|
|
184
187
|
) : /* @__PURE__ */ jsx("div", { className: "flex items-center gap-ds-2", children: actions.map((action, i) => /* @__PURE__ */ jsx(
|
|
185
188
|
Button,
|
|
186
189
|
{
|
|
187
|
-
variant:
|
|
190
|
+
variant: "secondary",
|
|
188
191
|
size: "sm",
|
|
189
192
|
onClick: action.onClick,
|
|
190
193
|
children: action.label
|
|
@@ -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,6 +423,149 @@ function Toggle({ checked, onChange, label, disabled, error = false, layout = "f
|
|
|
407
423
|
}
|
|
408
424
|
);
|
|
409
425
|
}
|
|
426
|
+
function InlineFieldError({ message, id, className }) {
|
|
427
|
+
return /* @__PURE__ */ jsxs(
|
|
428
|
+
"p",
|
|
429
|
+
{
|
|
430
|
+
id,
|
|
431
|
+
role: "alert",
|
|
432
|
+
className: cn(
|
|
433
|
+
"flex items-center gap-ds-1.5 text-xs text-[var(--ds-status-error)]",
|
|
434
|
+
"mt-ds-1.5",
|
|
435
|
+
className
|
|
436
|
+
),
|
|
437
|
+
children: [
|
|
438
|
+
/* @__PURE__ */ jsx(Icon, { name: "error", size: 14, className: "shrink-0" }),
|
|
439
|
+
/* @__PURE__ */ jsx("span", { children: message })
|
|
440
|
+
]
|
|
441
|
+
}
|
|
442
|
+
);
|
|
443
|
+
}
|
|
444
|
+
var FieldContext = createContext(null);
|
|
445
|
+
function useField() {
|
|
446
|
+
return useContext(FieldContext);
|
|
447
|
+
}
|
|
448
|
+
function useFieldControl(own, options = {}) {
|
|
449
|
+
const field = useField();
|
|
450
|
+
const id = own.id ?? field?.controlId;
|
|
451
|
+
const invalid = !!own.error || own["aria-invalid"] === true || own["aria-invalid"] === "true" || !!field?.invalid;
|
|
452
|
+
const required = !!own.required || own["aria-required"] === true || own["aria-required"] === "true" || !!field?.required;
|
|
453
|
+
const noteId = options.requiredInDescription && required && id ? `${id}-required` : void 0;
|
|
454
|
+
const ids = [own["aria-describedby"], field?.describedBy, noteId].filter(Boolean).join(" ").split(/\s+/).filter(Boolean);
|
|
455
|
+
return {
|
|
456
|
+
id,
|
|
457
|
+
labelId: own["aria-labelledby"] ?? field?.labelId,
|
|
458
|
+
describedBy: [...new Set(ids)].join(" ") || void 0,
|
|
459
|
+
invalid,
|
|
460
|
+
required,
|
|
461
|
+
requiredNote: noteId ? /* @__PURE__ */ jsx("span", { id: noteId, hidden: true, children: "Required" }) : null
|
|
462
|
+
};
|
|
463
|
+
}
|
|
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);
|
|
467
|
+
const generated = useId();
|
|
468
|
+
const id = idProp ?? `field-${generated}`;
|
|
469
|
+
const hintId = `${id}-hint`;
|
|
470
|
+
const errorId = `${id}-error`;
|
|
471
|
+
const form = useOptionalFormContext();
|
|
472
|
+
const mode = form?.validationMode ?? "onBlur";
|
|
473
|
+
const [localError, setLocalError] = useState(void 0);
|
|
474
|
+
const [left, setLeft] = useState(false);
|
|
475
|
+
const checkError = validate ? form ? form.errors[id] : localError : void 0;
|
|
476
|
+
const child = typeof children === "function" ? null : Children.only(children);
|
|
477
|
+
const childProps = child && isValidElement(child) ? child.props : null;
|
|
478
|
+
const latest = useLatest({ validate, childProps, id, mode, left, showing: !!checkError, form });
|
|
479
|
+
const check = useCallback(() => {
|
|
480
|
+
const { validate: fn, childProps: props, id: controlId } = latest.current;
|
|
481
|
+
if (!fn) return void 0;
|
|
482
|
+
const value = props && "value" in props ? props.value : props && "checked" in props ? props.checked : document.getElementById(controlId)?.value;
|
|
483
|
+
const message = fn(value);
|
|
484
|
+
return typeof message === "string" && message.length > 0 ? message : void 0;
|
|
485
|
+
}, [latest]);
|
|
486
|
+
const show = useCallback((message) => {
|
|
487
|
+
const { form: f, id: controlId } = latest.current;
|
|
488
|
+
if (f) f.setError(controlId, message);
|
|
489
|
+
else setLocalError(message);
|
|
490
|
+
}, [latest]);
|
|
491
|
+
const register = form?.register;
|
|
492
|
+
const checks = !!validate;
|
|
493
|
+
useEffect(() => register && checks ? register(id, check) : void 0, [register, checks, id, check]);
|
|
494
|
+
const leaving = useRef(null);
|
|
495
|
+
useEffect(() => () => {
|
|
496
|
+
if (leaving.current) clearTimeout(leaving.current);
|
|
497
|
+
}, []);
|
|
498
|
+
const onFocusCapture = () => {
|
|
499
|
+
if (leaving.current) {
|
|
500
|
+
clearTimeout(leaving.current);
|
|
501
|
+
leaving.current = null;
|
|
502
|
+
}
|
|
503
|
+
};
|
|
504
|
+
const onBlurCapture = () => {
|
|
505
|
+
if (!validate) return;
|
|
506
|
+
if (leaving.current) clearTimeout(leaving.current);
|
|
507
|
+
leaving.current = setTimeout(() => {
|
|
508
|
+
leaving.current = null;
|
|
509
|
+
setLeft(true);
|
|
510
|
+
if (latest.current.mode !== "onSubmit" || latest.current.showing) show(check());
|
|
511
|
+
}, 0);
|
|
512
|
+
};
|
|
513
|
+
const recheck = () => {
|
|
514
|
+
if (!validate) return;
|
|
515
|
+
setTimeout(() => {
|
|
516
|
+
const { mode: m, left: wasLeft, showing } = latest.current;
|
|
517
|
+
if (m === "onChange" && wasLeft || showing) show(check());
|
|
518
|
+
}, 0);
|
|
519
|
+
};
|
|
520
|
+
const shownError = typeof error === "string" && error.length > 0 ? error : checkError;
|
|
521
|
+
const hasError = typeof shownError === "string" && shownError.length > 0;
|
|
522
|
+
const describedBy = [hint ? hintId : null, hasError ? errorId : null].filter(Boolean).join(" ") || void 0;
|
|
523
|
+
const labelId = `${id}-label`;
|
|
524
|
+
const fieldContext = useMemo(() => ({ controlId: id, labelId, describedBy, invalid: hasError, required: !!required }), [id, labelId, describedBy, hasError, required]);
|
|
525
|
+
const controlProps = {
|
|
526
|
+
id,
|
|
527
|
+
"aria-describedby": describedBy,
|
|
528
|
+
...hasError ? { "aria-invalid": true, error: true } : {},
|
|
529
|
+
...required ? { "aria-required": true, required: true } : {}
|
|
530
|
+
};
|
|
531
|
+
let control;
|
|
532
|
+
if (typeof children === "function") {
|
|
533
|
+
control = children(controlProps);
|
|
534
|
+
} else {
|
|
535
|
+
if (!child || !isValidElement(child)) throw new Error("Field expects a single form control as its child");
|
|
536
|
+
const isNative = typeof child.type === "string";
|
|
537
|
+
const { error: errorFlag, ...ariaOnly } = controlProps;
|
|
538
|
+
const ownOnChange = childProps?.onChange;
|
|
539
|
+
const onChange = validate && !isNative ? { onChange: (...args) => {
|
|
540
|
+
ownOnChange?.(...args);
|
|
541
|
+
recheck();
|
|
542
|
+
} } : {};
|
|
543
|
+
control = cloneElement(child, isNative ? ariaOnly : { ...ariaOnly, ...errorFlag ? { error: true } : {}, ...onChange });
|
|
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
|
+
] });
|
|
549
|
+
return (
|
|
550
|
+
// In a settings panel a field keeps the narrow reading width however wide the page is (--ds-form-max, Sprint 25.9 A4)
|
|
551
|
+
/* @__PURE__ */ jsxs(
|
|
552
|
+
"div",
|
|
553
|
+
{
|
|
554
|
+
className: cn("flex flex-col gap-ds-1.5 max-w-[var(--ds-form-max,none)]", className),
|
|
555
|
+
...validate ? { onFocusCapture, onBlurCapture, onInputCapture: recheck } : {},
|
|
556
|
+
children: [
|
|
557
|
+
hideLabel && !labelAction ? labelNode : /* @__PURE__ */ jsxs("div", { className: "flex items-center justify-between gap-ds-2", children: [
|
|
558
|
+
labelNode,
|
|
559
|
+
labelAction
|
|
560
|
+
] }),
|
|
561
|
+
/* @__PURE__ */ jsx(FieldContext.Provider, { value: fieldContext, children: control }),
|
|
562
|
+
hint && /* @__PURE__ */ jsx("p", { id: hintId, className: "text-xs text-[var(--ds-text-muted)]", children: hint }),
|
|
563
|
+
hasError && /* @__PURE__ */ jsx(InlineFieldError, { id: errorId, message: shownError, className: "mt-0" })
|
|
564
|
+
]
|
|
565
|
+
}
|
|
566
|
+
)
|
|
567
|
+
);
|
|
568
|
+
}
|
|
410
569
|
var DROPDOWN_HEIGHT = {
|
|
411
570
|
sm: "px-ds-2 py-ds-1 text-xs h-[var(--ds-control-height-sm)]",
|
|
412
571
|
md: "px-ds-3 py-ds-2 text-sm h-[var(--ds-control-height-md)]",
|
|
@@ -415,7 +574,7 @@ var DROPDOWN_HEIGHT = {
|
|
|
415
574
|
function Dropdown({
|
|
416
575
|
options,
|
|
417
576
|
value,
|
|
418
|
-
onChange,
|
|
577
|
+
onChange: onChangeProp,
|
|
419
578
|
label,
|
|
420
579
|
disabled,
|
|
421
580
|
placeholder = "Select...",
|
|
@@ -427,9 +586,17 @@ function Dropdown({
|
|
|
427
586
|
container,
|
|
428
587
|
error = false,
|
|
429
588
|
showChips = true,
|
|
430
|
-
"aria-label": ariaLabel
|
|
589
|
+
"aria-label": ariaLabel,
|
|
590
|
+
...wiring
|
|
431
591
|
}) {
|
|
592
|
+
const onChange = useReportedChange(onChangeProp, value);
|
|
432
593
|
const contextSize = useContext(ControlSizeContext);
|
|
594
|
+
const generatedId = useId();
|
|
595
|
+
const control = useFieldControl({ ...wiring, error: error || void 0 }, { requiredInDescription: true });
|
|
596
|
+
const triggerId = control.id ?? generatedId;
|
|
597
|
+
const labelSpanId = `${triggerId}-label`;
|
|
598
|
+
const labelledBy = control.labelId ? `${control.labelId} ${triggerId}` : label && !ariaLabel ? `${labelSpanId} ${triggerId}` : void 0;
|
|
599
|
+
const invalid = control.invalid;
|
|
433
600
|
const size = sizeProp ?? contextSize ?? "md";
|
|
434
601
|
const [open, setOpen] = useState(false);
|
|
435
602
|
const [search, setSearch] = useState("");
|
|
@@ -597,11 +764,13 @@ function Dropdown({
|
|
|
597
764
|
const displayLabel = multiple ? selectedValues.length > 0 ? `${selectedValues.length} selected` : placeholder : options.find((o) => o.id === selectedValues[0])?.label ?? placeholder;
|
|
598
765
|
const { ref: overflowRef, isTruncated } = useTextOverflow({ lines: 1, content: displayLabel });
|
|
599
766
|
return /* @__PURE__ */ jsxs("div", { ref, className: cn("relative", className), children: [
|
|
600
|
-
label && /* @__PURE__ */ jsx("span", { className: "block mb-ds-1.5 text-sm font-medium text-[var(--ds-text-secondary)]", children: label }),
|
|
767
|
+
label && /* @__PURE__ */ jsx("span", { id: labelSpanId, className: "block mb-ds-1.5 text-sm font-medium text-[var(--ds-text-secondary)]", children: label }),
|
|
768
|
+
control.requiredNote,
|
|
601
769
|
/* @__PURE__ */ jsxs(
|
|
602
770
|
"button",
|
|
603
771
|
{
|
|
604
772
|
ref: triggerRef,
|
|
773
|
+
id: triggerId,
|
|
605
774
|
type: "button",
|
|
606
775
|
onClick: () => !disabled && setOpen(!open),
|
|
607
776
|
onKeyDown: (e) => {
|
|
@@ -612,22 +781,24 @@ function Dropdown({
|
|
|
612
781
|
}
|
|
613
782
|
},
|
|
614
783
|
disabled,
|
|
615
|
-
"aria-invalid":
|
|
784
|
+
"aria-invalid": invalid || void 0,
|
|
616
785
|
"aria-haspopup": "listbox",
|
|
617
786
|
"aria-expanded": open,
|
|
618
|
-
"aria-label": ariaLabel,
|
|
787
|
+
"aria-label": labelledBy ? void 0 : ariaLabel,
|
|
788
|
+
"aria-labelledby": labelledBy,
|
|
789
|
+
"aria-describedby": control.describedBy,
|
|
619
790
|
className: cn(
|
|
620
791
|
"w-full flex items-center justify-between gap-ds-2",
|
|
621
792
|
DROPDOWN_HEIGHT[size],
|
|
622
793
|
"bg-[var(--ds-input-bg)] text-[var(--ds-text-primary)]",
|
|
623
794
|
"border-[length:var(--ds-border-width)]",
|
|
624
|
-
|
|
795
|
+
invalid ? "border-[var(--ds-status-error)]" : "border-[var(--ds-input-border)]",
|
|
625
796
|
"rounded-[var(--ds-radius-md)]",
|
|
626
797
|
"shadow-[var(--ds-input-shadow)]",
|
|
627
798
|
"transition-colors",
|
|
628
|
-
!
|
|
629
|
-
open && (
|
|
630
|
-
|
|
799
|
+
!invalid && !disabled && !open && "hover:border-[var(--ds-input-border-hover)]",
|
|
800
|
+
open && (invalid ? ERROR_ACTIVE_RING : ACTIVE_RING),
|
|
801
|
+
invalid ? ERROR_FOCUS_RING : FOCUS_RING,
|
|
631
802
|
"cursor-pointer disabled:cursor-not-allowed disabled:opacity-disabled",
|
|
632
803
|
!selectedValues.length && "text-[var(--ds-text-muted)]"
|
|
633
804
|
),
|
|
@@ -642,9 +813,10 @@ function Dropdown({
|
|
|
642
813
|
"div",
|
|
643
814
|
{
|
|
644
815
|
ref: menuRef,
|
|
816
|
+
tabIndex: -1,
|
|
645
817
|
onClick: (e) => e.stopPropagation(),
|
|
646
818
|
className: cn(
|
|
647
|
-
"fixed z-[var(--ds-z-popover)]",
|
|
819
|
+
"fixed z-[var(--ds-z-popover)] outline-none",
|
|
648
820
|
"bg-[var(--ds-bg-surface-elevated)]",
|
|
649
821
|
"[backdrop-filter:var(--ds-glass-filter)] [-webkit-backdrop-filter:var(--ds-glass-filter)]",
|
|
650
822
|
"border-[length:var(--ds-border-width)] border-[var(--ds-border-default)]",
|
|
@@ -704,6 +876,7 @@ function Dropdown({
|
|
|
704
876
|
/* @__PURE__ */ jsx(
|
|
705
877
|
"button",
|
|
706
878
|
{
|
|
879
|
+
type: "button",
|
|
707
880
|
"data-chip-remove": "",
|
|
708
881
|
onClick: () => {
|
|
709
882
|
pendingChipFocus.current = { index: i, value: v };
|
|
@@ -771,8 +944,10 @@ var TEXT_SIZE = {
|
|
|
771
944
|
md: "text-sm",
|
|
772
945
|
lg: "text-base"
|
|
773
946
|
};
|
|
774
|
-
function Combobox({ value, onChange, options, placeholder = "Search\u2026", disabled, loading = false, className, ref, container, error = false, size: sizeProp }) {
|
|
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);
|
|
775
949
|
const contextSize = useContext(ControlSizeContext);
|
|
950
|
+
const control = useFieldControl({ ...wiring, error: error || void 0 });
|
|
776
951
|
const size = sizeProp ?? contextSize ?? "md";
|
|
777
952
|
const [open, setOpen] = useState(false);
|
|
778
953
|
useOverlayLayer(open);
|
|
@@ -883,12 +1058,12 @@ function Combobox({ value, onChange, options, placeholder = "Search\u2026", disa
|
|
|
883
1058
|
"flex items-center",
|
|
884
1059
|
CONTROL_HEIGHT[size],
|
|
885
1060
|
"border-[length:var(--ds-border-width)]",
|
|
886
|
-
|
|
1061
|
+
control.invalid ? "border-[var(--ds-status-error)]" : "border-[var(--ds-input-border)]",
|
|
887
1062
|
"bg-[var(--ds-input-bg)] rounded-[var(--ds-radius-md)]",
|
|
888
1063
|
"shadow-[var(--ds-input-shadow)]",
|
|
889
1064
|
"transition-colors duration-[var(--ds-transition-speed)]",
|
|
890
|
-
!
|
|
891
|
-
|
|
1065
|
+
!control.invalid && !disabled && "hover:border-[var(--ds-input-border-hover)]",
|
|
1066
|
+
control.invalid ? ERROR_HAS_FOCUS_RING : HAS_FOCUS_RING,
|
|
892
1067
|
disabled && "opacity-disabled pointer-events-none"
|
|
893
1068
|
),
|
|
894
1069
|
children: [
|
|
@@ -898,8 +1073,12 @@ function Combobox({ value, onChange, options, placeholder = "Search\u2026", disa
|
|
|
898
1073
|
{
|
|
899
1074
|
ref: mergeInputRefs,
|
|
900
1075
|
type: "text",
|
|
1076
|
+
id: control.id,
|
|
901
1077
|
role: "combobox",
|
|
902
|
-
"aria-
|
|
1078
|
+
"aria-labelledby": wiring["aria-labelledby"],
|
|
1079
|
+
"aria-describedby": control.describedBy,
|
|
1080
|
+
"aria-invalid": control.invalid || void 0,
|
|
1081
|
+
"aria-required": control.required || void 0,
|
|
903
1082
|
"aria-expanded": open,
|
|
904
1083
|
"aria-controls": listboxId,
|
|
905
1084
|
"aria-autocomplete": "list",
|
|
@@ -964,6 +1143,7 @@ function Combobox({ value, onChange, options, placeholder = "Search\u2026", disa
|
|
|
964
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(
|
|
965
1144
|
"button",
|
|
966
1145
|
{
|
|
1146
|
+
type: "button",
|
|
967
1147
|
id: `${listboxId}-opt-${i}`,
|
|
968
1148
|
role: "option",
|
|
969
1149
|
tabIndex: -1,
|
|
@@ -995,7 +1175,8 @@ var CHECKBOX_SIZES = {
|
|
|
995
1175
|
sm: { box: "h-[16px] w-[16px]", glyph: 10, label: "text-xs" },
|
|
996
1176
|
md: { box: "h-[18px] w-[18px]", glyph: 12, label: "text-sm" }
|
|
997
1177
|
};
|
|
998
|
-
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);
|
|
999
1180
|
const internalRef = useRef(null);
|
|
1000
1181
|
const dims = CHECKBOX_SIZES[size];
|
|
1001
1182
|
const mergedRef = useCallback(
|
|
@@ -1087,7 +1268,8 @@ function CheckboxGroupItem({ value, label, disabled, groupValue, onGroupChange }
|
|
|
1087
1268
|
}
|
|
1088
1269
|
);
|
|
1089
1270
|
}
|
|
1090
|
-
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);
|
|
1091
1273
|
const groupRef = useRef(null);
|
|
1092
1274
|
const groupId = useId();
|
|
1093
1275
|
const enabledOptions = options.filter((o) => !o.disabled);
|
|
@@ -1312,7 +1494,8 @@ function parseTypedDate(text, dayFirst = localeDayFirst()) {
|
|
|
1312
1494
|
}
|
|
1313
1495
|
return null;
|
|
1314
1496
|
}
|
|
1315
|
-
function DatePicker({ value, onChange, placeholder = "Pick a date", disabled, className, ref, container, error = false, label, id, size: sizeProp, min, max, range: range2 }) {
|
|
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);
|
|
1316
1499
|
const contextSize = useContext(ControlSizeContext);
|
|
1317
1500
|
const size = sizeProp ?? contextSize ?? "md";
|
|
1318
1501
|
const [open, setOpen] = useState(false);
|
|
@@ -1323,7 +1506,8 @@ function DatePicker({ value, onChange, placeholder = "Pick a date", disabled, cl
|
|
|
1323
1506
|
const panelRef = useRef(null);
|
|
1324
1507
|
const gridRef = useRef(null);
|
|
1325
1508
|
const generatedId = useId();
|
|
1326
|
-
const
|
|
1509
|
+
const control = useFieldControl({ ...wiring, id, error: error || void 0 }, { requiredInDescription: true });
|
|
1510
|
+
const inputId = control.id ?? generatedId;
|
|
1327
1511
|
const pos = usePosition(triggerRef, panelRef, open, { side: "bottom", align: "start", offset: 4, flip: true });
|
|
1328
1512
|
const year = viewDate.getFullYear();
|
|
1329
1513
|
const month = viewDate.getMonth();
|
|
@@ -1508,6 +1692,7 @@ function DatePicker({ value, onChange, placeholder = "Pick a date", disabled, cl
|
|
|
1508
1692
|
for (let i = 0; i < cells.length; i += 7) weeks.push(cells.slice(i, i + 7));
|
|
1509
1693
|
return /* @__PURE__ */ jsxs("div", { ref, className: cn(className), children: [
|
|
1510
1694
|
label && /* @__PURE__ */ jsx("label", { htmlFor: inputId, className: "block text-sm font-medium text-[var(--ds-text-primary)] mb-ds-1", children: label }),
|
|
1695
|
+
control.requiredNote,
|
|
1511
1696
|
/* @__PURE__ */ jsxs(
|
|
1512
1697
|
"div",
|
|
1513
1698
|
{
|
|
@@ -1515,9 +1700,11 @@ function DatePicker({ value, onChange, placeholder = "Pick a date", disabled, cl
|
|
|
1515
1700
|
"data-date-field": "",
|
|
1516
1701
|
role: "group",
|
|
1517
1702
|
id: inputId,
|
|
1518
|
-
"aria-label": label ?? "Date",
|
|
1703
|
+
"aria-label": control.labelId ? void 0 : label ?? "Date",
|
|
1704
|
+
"aria-labelledby": control.labelId,
|
|
1705
|
+
"aria-describedby": control.describedBy,
|
|
1519
1706
|
"aria-description": !value ? placeholder : void 0,
|
|
1520
|
-
"aria-invalid":
|
|
1707
|
+
"aria-invalid": control.invalid || typedInvalid || void 0,
|
|
1521
1708
|
onPaste: (e) => {
|
|
1522
1709
|
const text = e.clipboardData.getData("text");
|
|
1523
1710
|
if (text) {
|
|
@@ -1530,12 +1717,12 @@ function DatePicker({ value, onChange, placeholder = "Pick a date", disabled, cl
|
|
|
1530
1717
|
CONTROL_HEIGHT2[size],
|
|
1531
1718
|
TEXT_SIZE2[size],
|
|
1532
1719
|
"border-[length:var(--ds-border-width)]",
|
|
1533
|
-
|
|
1720
|
+
control.invalid || typedInvalid ? "border-[var(--ds-status-error)]" : "border-[var(--ds-input-border)]",
|
|
1534
1721
|
"bg-[var(--ds-input-bg)] rounded-[var(--ds-radius-md)]",
|
|
1535
1722
|
"shadow-[var(--ds-input-shadow)]",
|
|
1536
1723
|
"transition-colors",
|
|
1537
1724
|
"px-ds-3 py-ds-2",
|
|
1538
|
-
!
|
|
1725
|
+
!control.invalid && !disabled && !open && "hover:border-[var(--ds-input-border-hover)] focus-within:border-[var(--ds-input-border-hover)]",
|
|
1539
1726
|
open && ACTIVE_RING,
|
|
1540
1727
|
disabled && "opacity-disabled cursor-not-allowed",
|
|
1541
1728
|
"text-[var(--ds-text-primary)]"
|
|
@@ -1592,8 +1779,9 @@ function DatePicker({ value, onChange, placeholder = "Pick a date", disabled, cl
|
|
|
1592
1779
|
ref: panelRef,
|
|
1593
1780
|
role: "dialog",
|
|
1594
1781
|
"aria-label": "Choose a date",
|
|
1782
|
+
tabIndex: -1,
|
|
1595
1783
|
className: cn(
|
|
1596
|
-
"fixed z-[var(--ds-z-popover)] w-[280px]",
|
|
1784
|
+
"fixed z-[var(--ds-z-popover)] w-[280px] outline-none",
|
|
1597
1785
|
"bg-[var(--ds-bg-surface-elevated)]",
|
|
1598
1786
|
"[backdrop-filter:var(--ds-glass-filter)] [-webkit-backdrop-filter:var(--ds-glass-filter)]",
|
|
1599
1787
|
"border-[length:var(--ds-border-width)] border-[var(--ds-border-default)]",
|
|
@@ -1912,7 +2100,7 @@ var DEFAULT_DATE_RANGE_PRESETS = [
|
|
|
1912
2100
|
];
|
|
1913
2101
|
function DateRangePicker({
|
|
1914
2102
|
value,
|
|
1915
|
-
onChange,
|
|
2103
|
+
onChange: onChangeProp,
|
|
1916
2104
|
placeholder = "Pick a date range",
|
|
1917
2105
|
disabled,
|
|
1918
2106
|
error = false,
|
|
@@ -1925,8 +2113,10 @@ function DateRangePicker({
|
|
|
1925
2113
|
max,
|
|
1926
2114
|
presets = DEFAULT_DATE_RANGE_PRESETS,
|
|
1927
2115
|
weekStartsOn = 0,
|
|
1928
|
-
size: sizeProp
|
|
2116
|
+
size: sizeProp,
|
|
2117
|
+
...wiring
|
|
1929
2118
|
}) {
|
|
2119
|
+
const onChange = useReportedChange(onChangeProp, value);
|
|
1930
2120
|
const contextSize = useContext(ControlSizeContext);
|
|
1931
2121
|
const size = sizeProp ?? contextSize ?? "md";
|
|
1932
2122
|
const [open, setOpen] = useState(false);
|
|
@@ -1935,7 +2125,9 @@ function DateRangePicker({
|
|
|
1935
2125
|
const triggerRef = useRef(null);
|
|
1936
2126
|
const panelRef = useRef(null);
|
|
1937
2127
|
const generatedId = useId();
|
|
1938
|
-
const
|
|
2128
|
+
const control = useFieldControl({ ...wiring, id, error: error || void 0 }, { requiredInDescription: true });
|
|
2129
|
+
const triggerId = control.id ?? generatedId;
|
|
2130
|
+
const labelledBy = control.labelId ? `${control.labelId} ${triggerId}` : void 0;
|
|
1939
2131
|
const pos = usePosition(triggerRef, panelRef, open, { side: "bottom", align: "start", offset: 4, flip: true });
|
|
1940
2132
|
const today = useMemo(() => startOfDay(/* @__PURE__ */ new Date()), []);
|
|
1941
2133
|
const dayNames = getOrderedDayNamesShort(weekStartsOn);
|
|
@@ -2018,6 +2210,7 @@ function DateRangePicker({
|
|
|
2018
2210
|
const summary = value.start && value.end ? `${fmt(value.start)} \u2013 ${fmt(value.end)}` : value.start ? `${fmt(value.start)} \u2013 \u2026` : null;
|
|
2019
2211
|
return /* @__PURE__ */ jsxs("div", { ref, className: cn(className), children: [
|
|
2020
2212
|
label && /* @__PURE__ */ jsx("label", { htmlFor: triggerId, className: "block text-sm font-medium text-[var(--ds-text-primary)] mb-ds-1", children: label }),
|
|
2213
|
+
control.requiredNote,
|
|
2021
2214
|
/* @__PURE__ */ jsxs(
|
|
2022
2215
|
"button",
|
|
2023
2216
|
{
|
|
@@ -2026,7 +2219,9 @@ function DateRangePicker({
|
|
|
2026
2219
|
type: "button",
|
|
2027
2220
|
onClick: () => !disabled && setOpen((o) => !o),
|
|
2028
2221
|
disabled,
|
|
2029
|
-
"aria-
|
|
2222
|
+
"aria-labelledby": labelledBy,
|
|
2223
|
+
"aria-describedby": control.describedBy,
|
|
2224
|
+
"aria-invalid": control.invalid || void 0,
|
|
2030
2225
|
"aria-haspopup": "dialog",
|
|
2031
2226
|
"aria-expanded": open,
|
|
2032
2227
|
className: cn(
|
|
@@ -2034,14 +2229,14 @@ function DateRangePicker({
|
|
|
2034
2229
|
CONTROL_HEIGHT3[size],
|
|
2035
2230
|
TEXT_SIZE3[size],
|
|
2036
2231
|
"border-[length:var(--ds-border-width)]",
|
|
2037
|
-
|
|
2232
|
+
control.invalid ? "border-[var(--ds-status-error)]" : "border-[var(--ds-input-border)]",
|
|
2038
2233
|
"bg-[var(--ds-input-bg)] rounded-[var(--ds-radius-md)]",
|
|
2039
2234
|
"shadow-[var(--ds-input-shadow)]",
|
|
2040
2235
|
"transition-colors cursor-pointer",
|
|
2041
2236
|
"px-ds-3 py-ds-2",
|
|
2042
|
-
!
|
|
2043
|
-
open && (
|
|
2044
|
-
|
|
2237
|
+
!control.invalid && !disabled && !open && "hover:border-[var(--ds-input-border-hover)]",
|
|
2238
|
+
open && (control.invalid ? ERROR_ACTIVE_RING : ACTIVE_RING),
|
|
2239
|
+
control.invalid ? ERROR_FOCUS_RING : FOCUS_RING,
|
|
2045
2240
|
disabled && "opacity-disabled cursor-not-allowed",
|
|
2046
2241
|
summary ? "text-[var(--ds-text-primary)]" : "text-[var(--ds-text-muted)]"
|
|
2047
2242
|
),
|
|
@@ -2058,8 +2253,9 @@ function DateRangePicker({
|
|
|
2058
2253
|
ref: panelRef,
|
|
2059
2254
|
role: "dialog",
|
|
2060
2255
|
"aria-label": "Choose a date range",
|
|
2256
|
+
tabIndex: -1,
|
|
2061
2257
|
className: cn(
|
|
2062
|
-
"fixed z-[var(--ds-z-popover)] flex",
|
|
2258
|
+
"fixed z-[var(--ds-z-popover)] flex outline-none",
|
|
2063
2259
|
"bg-[var(--ds-bg-surface-elevated)]",
|
|
2064
2260
|
"[backdrop-filter:var(--ds-glass-filter)] [-webkit-backdrop-filter:var(--ds-glass-filter)]",
|
|
2065
2261
|
"border-[length:var(--ds-border-width)] border-[var(--ds-border-default)]",
|
|
@@ -2264,7 +2460,7 @@ function Progress({ value, max = 100, variant = "default", size = "md", indeterm
|
|
|
2264
2460
|
{
|
|
2265
2461
|
className: cn(
|
|
2266
2462
|
"h-full rounded-[var(--ds-radius-full)]",
|
|
2267
|
-
indeterminate ? "animate-[indeterminate_1.5s_ease-in-out_infinite] w-1/3" : "transition-all",
|
|
2463
|
+
indeterminate ? "animate-[gs-indeterminate_1.5s_ease-in-out_infinite] w-1/3" : "transition-all",
|
|
2268
2464
|
variantFills[variant]
|
|
2269
2465
|
),
|
|
2270
2466
|
style: indeterminate ? void 0 : { width: `${pct}%` }
|
|
@@ -2278,91 +2474,33 @@ function Progress({ value, max = 100, variant = "default", size = "md", indeterm
|
|
|
2278
2474
|
] })
|
|
2279
2475
|
] });
|
|
2280
2476
|
}
|
|
2281
|
-
function InlineFieldError({ message, id, className }) {
|
|
2282
|
-
return /* @__PURE__ */ jsxs(
|
|
2283
|
-
"p",
|
|
2284
|
-
{
|
|
2285
|
-
id,
|
|
2286
|
-
role: "alert",
|
|
2287
|
-
className: cn(
|
|
2288
|
-
"flex items-center gap-ds-1.5 text-xs text-[var(--ds-status-error)]",
|
|
2289
|
-
"mt-ds-1.5",
|
|
2290
|
-
className
|
|
2291
|
-
),
|
|
2292
|
-
children: [
|
|
2293
|
-
/* @__PURE__ */ jsx(Icon, { name: "error", size: 14, className: "shrink-0" }),
|
|
2294
|
-
/* @__PURE__ */ jsx("span", { children: message })
|
|
2295
|
-
]
|
|
2296
|
-
}
|
|
2297
|
-
);
|
|
2298
|
-
}
|
|
2299
|
-
var FieldContext = createContext(null);
|
|
2300
|
-
function useField() {
|
|
2301
|
-
return useContext(FieldContext);
|
|
2302
|
-
}
|
|
2303
|
-
function Field({ label, children, hint, error, required, labelAction, id: idProp, className }) {
|
|
2304
|
-
const generated = useId();
|
|
2305
|
-
const id = idProp ?? `field-${generated}`;
|
|
2306
|
-
const hintId = `${id}-hint`;
|
|
2307
|
-
const errorId = `${id}-error`;
|
|
2308
|
-
const hasError = typeof error === "string" && error.length > 0;
|
|
2309
|
-
const describedBy = [hint ? hintId : null, hasError ? errorId : null].filter(Boolean).join(" ") || void 0;
|
|
2310
|
-
const labelId = `${id}-label`;
|
|
2311
|
-
const fieldContext = useMemo(() => ({ controlId: id, labelId, describedBy }), [id, labelId, describedBy]);
|
|
2312
|
-
const controlProps = {
|
|
2313
|
-
id,
|
|
2314
|
-
"aria-describedby": describedBy,
|
|
2315
|
-
...hasError ? { "aria-invalid": true, error: true } : {},
|
|
2316
|
-
...required ? { "aria-required": true, required: true } : {}
|
|
2317
|
-
};
|
|
2318
|
-
let control;
|
|
2319
|
-
if (typeof children === "function") {
|
|
2320
|
-
control = children(controlProps);
|
|
2321
|
-
} else {
|
|
2322
|
-
const child = Children.only(children);
|
|
2323
|
-
if (!isValidElement(child)) throw new Error("Field expects a single form control as its child");
|
|
2324
|
-
const isNative = typeof child.type === "string";
|
|
2325
|
-
const { error: errorFlag, ...ariaOnly } = controlProps;
|
|
2326
|
-
control = cloneElement(child, isNative ? ariaOnly : { ...ariaOnly, ...errorFlag ? { error: true } : {} });
|
|
2327
|
-
}
|
|
2328
|
-
return (
|
|
2329
|
-
// In a settings panel a field keeps the narrow reading width however wide the page is (--ds-form-max, Sprint 25.9 A4)
|
|
2330
|
-
/* @__PURE__ */ jsxs("div", { className: cn("flex flex-col gap-ds-1.5 max-w-[var(--ds-form-max,none)]", className), children: [
|
|
2331
|
-
/* @__PURE__ */ jsxs("div", { className: "flex items-center justify-between gap-ds-2", children: [
|
|
2332
|
-
/* @__PURE__ */ jsxs(Label, { id: labelId, htmlFor: id, children: [
|
|
2333
|
-
label,
|
|
2334
|
-
required && /* @__PURE__ */ jsx("span", { "aria-hidden": "true", className: "ml-ds-0.5 text-[var(--ds-status-error)]", children: "*" })
|
|
2335
|
-
] }),
|
|
2336
|
-
labelAction
|
|
2337
|
-
] }),
|
|
2338
|
-
/* @__PURE__ */ jsx(FieldContext.Provider, { value: fieldContext, children: control }),
|
|
2339
|
-
hint && /* @__PURE__ */ jsx("p", { id: hintId, className: "text-xs text-[var(--ds-text-muted)]", children: hint }),
|
|
2340
|
-
hasError && /* @__PURE__ */ jsx(InlineFieldError, { id: errorId, message: error, className: "mt-0" })
|
|
2341
|
-
] })
|
|
2342
|
-
);
|
|
2343
|
-
}
|
|
2344
2477
|
function TruncFileName({ children, className }) {
|
|
2345
2478
|
const { ref, isTruncated } = useTextOverflow({ lines: 1 });
|
|
2346
2479
|
const el = /* @__PURE__ */ jsx("p", { ref, className: cn("truncate", className), children });
|
|
2347
2480
|
if (!isTruncated) return el;
|
|
2348
2481
|
return /* @__PURE__ */ jsx(Tooltip, { content: children, children: el });
|
|
2349
2482
|
}
|
|
2483
|
+
var PARALLEL = 3;
|
|
2350
2484
|
function formatSize(bytes) {
|
|
2351
2485
|
if (bytes < 1024) return `${bytes} B`;
|
|
2352
2486
|
if (bytes < 1024 * 1024) return `${(bytes / 1024).toFixed(1)} KB`;
|
|
2353
2487
|
return `${(bytes / (1024 * 1024)).toFixed(1)} MB`;
|
|
2354
2488
|
}
|
|
2355
|
-
|
|
2356
|
-
|
|
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;
|
|
2357
2495
|
const [dragOver, setDragOver] = useState(false);
|
|
2358
2496
|
const [rejected, setRejected] = useState(null);
|
|
2359
2497
|
const inputRef = useRef(null);
|
|
2498
|
+
const listRef = useRef(null);
|
|
2360
2499
|
const nextEntryId = useRef(0);
|
|
2361
|
-
const
|
|
2362
|
-
|
|
2363
|
-
|
|
2364
|
-
|
|
2365
|
-
}, []);
|
|
2500
|
+
const controllers = useRef(/* @__PURE__ */ new Map());
|
|
2501
|
+
const uploadRef = useLatest(upload);
|
|
2502
|
+
const overlayMark = useContext(OverlayMarkCtx);
|
|
2503
|
+
const reportChange = useContext(FormChangeCtx);
|
|
2366
2504
|
const field = useField();
|
|
2367
2505
|
const ownId = useId();
|
|
2368
2506
|
const inputId = id ?? `${ownId}-input`;
|
|
@@ -2372,37 +2510,100 @@ function FileUpload({ onFiles, accept, multiple = true, maxSize, className, erro
|
|
|
2372
2510
|
const constraints = fileConstraints(accept, maxSize, multiple);
|
|
2373
2511
|
const invalid = error || rejected != null;
|
|
2374
2512
|
const describedBy = [constraints ? constraintsId : null, field?.describedBy, rejected ? rejectedId : null].filter(Boolean).join(" ") || void 0;
|
|
2375
|
-
const
|
|
2376
|
-
|
|
2377
|
-
|
|
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) }));
|
|
2378
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]);
|
|
2379
2593
|
const addFiles = useCallback(
|
|
2380
2594
|
(fileList) => {
|
|
2381
2595
|
const { accepted, message } = checkFiles(Array.from(fileList), { accept, maxSize, multiple });
|
|
2382
2596
|
setRejected(message);
|
|
2383
2597
|
if (accepted.length === 0) return;
|
|
2384
|
-
|
|
2385
|
-
|
|
2386
|
-
|
|
2387
|
-
|
|
2388
|
-
}
|
|
2389
|
-
|
|
2390
|
-
|
|
2391
|
-
for (const { id: id2 } of entries) {
|
|
2392
|
-
let progress = 0;
|
|
2393
|
-
const timer = setInterval(() => {
|
|
2394
|
-
progress = Math.min(100, progress + Math.random() * 30 + 10);
|
|
2395
|
-
const done = progress >= 100;
|
|
2396
|
-
if (done) {
|
|
2397
|
-
clearInterval(timer);
|
|
2398
|
-
timers.current.delete(id2);
|
|
2399
|
-
}
|
|
2400
|
-
setFiles((prev) => prev.map((f) => f.id === id2 ? { ...f, progress, status: done ? "complete" : "uploading" } : f));
|
|
2401
|
-
}, 300);
|
|
2402
|
-
timers.current.set(id2, timer);
|
|
2403
|
-
}
|
|
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);
|
|
2404
2605
|
},
|
|
2405
|
-
[accept, maxSize, multiple, onFiles]
|
|
2606
|
+
[accept, maxSize, multiple, onFiles, controlled, ownId, reportChange, stopAll, uploadRef]
|
|
2406
2607
|
);
|
|
2407
2608
|
const handleDrop = useCallback(
|
|
2408
2609
|
(e) => {
|
|
@@ -2412,10 +2613,31 @@ function FileUpload({ onFiles, accept, multiple = true, maxSize, className, erro
|
|
|
2412
2613
|
},
|
|
2413
2614
|
[addFiles]
|
|
2414
2615
|
);
|
|
2415
|
-
const
|
|
2416
|
-
|
|
2417
|
-
|
|
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);
|
|
2418
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;
|
|
2419
2641
|
return /* @__PURE__ */ jsxs("div", { className: cn("space-y-ds-3", className), children: [
|
|
2420
2642
|
/* @__PURE__ */ jsxs("div", { className: "flex flex-col gap-ds-1.5", children: [
|
|
2421
2643
|
showLabel && /* @__PURE__ */ jsx(Label, { htmlFor: inputId, children: label }),
|
|
@@ -2471,33 +2693,43 @@ function FileUpload({ onFiles, accept, multiple = true, maxSize, className, erro
|
|
|
2471
2693
|
),
|
|
2472
2694
|
rejected && /* @__PURE__ */ jsx(InlineFieldError, { id: rejectedId, message: rejected, className: "mt-0" })
|
|
2473
2695
|
] }),
|
|
2474
|
-
|
|
2475
|
-
"
|
|
2476
|
-
|
|
2477
|
-
|
|
2478
|
-
|
|
2479
|
-
"
|
|
2480
|
-
|
|
2481
|
-
|
|
2482
|
-
|
|
2483
|
-
|
|
2484
|
-
|
|
2485
|
-
|
|
2486
|
-
|
|
2487
|
-
|
|
2488
|
-
|
|
2489
|
-
|
|
2490
|
-
|
|
2491
|
-
|
|
2492
|
-
|
|
2493
|
-
|
|
2494
|
-
|
|
2495
|
-
|
|
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 })
|
|
2496
2728
|
] });
|
|
2497
2729
|
}
|
|
2498
2730
|
function SliderRange({
|
|
2499
2731
|
value,
|
|
2500
|
-
onChange,
|
|
2732
|
+
onChange: onChangeProp,
|
|
2501
2733
|
min = 0,
|
|
2502
2734
|
max = 100,
|
|
2503
2735
|
step = 1,
|
|
@@ -2512,6 +2744,7 @@ function SliderRange({
|
|
|
2512
2744
|
trackStyle,
|
|
2513
2745
|
formatValue
|
|
2514
2746
|
}) {
|
|
2747
|
+
const onChange = useReportedChange(onChangeProp, value);
|
|
2515
2748
|
const field = useField();
|
|
2516
2749
|
const ownId = useId();
|
|
2517
2750
|
const showLabel = label != null && !field;
|
|
@@ -2717,7 +2950,7 @@ function parseTime(value) {
|
|
|
2717
2950
|
}
|
|
2718
2951
|
function TimePicker({
|
|
2719
2952
|
value,
|
|
2720
|
-
onChange,
|
|
2953
|
+
onChange: onChangeProp,
|
|
2721
2954
|
use24Hour = false,
|
|
2722
2955
|
minuteStep = 15,
|
|
2723
2956
|
disabled,
|
|
@@ -2726,9 +2959,12 @@ function TimePicker({
|
|
|
2726
2959
|
container,
|
|
2727
2960
|
error = false,
|
|
2728
2961
|
id,
|
|
2729
|
-
size: sizeProp
|
|
2962
|
+
size: sizeProp,
|
|
2963
|
+
...wiring
|
|
2730
2964
|
}) {
|
|
2965
|
+
const onChange = useReportedChange(onChangeProp, value);
|
|
2731
2966
|
const contextSize = useContext(ControlSizeContext);
|
|
2967
|
+
const control = useFieldControl({ ...wiring, id, error: error || void 0 }, { requiredInDescription: true });
|
|
2732
2968
|
const size = sizeProp ?? contextSize ?? "md";
|
|
2733
2969
|
const [open, setOpen] = useState(false);
|
|
2734
2970
|
const triggerRef = useRef(null);
|
|
@@ -2912,15 +3148,18 @@ function TimePicker({
|
|
|
2912
3148
|
return segs[k] === null ? spec.placeholder : pad2(segs[k]);
|
|
2913
3149
|
};
|
|
2914
3150
|
return /* @__PURE__ */ jsxs("div", { ref, className: cn(className), children: [
|
|
3151
|
+
control.requiredNote,
|
|
2915
3152
|
/* @__PURE__ */ jsxs(
|
|
2916
3153
|
"div",
|
|
2917
3154
|
{
|
|
2918
3155
|
ref: triggerRef,
|
|
2919
3156
|
"data-time-field": "",
|
|
2920
3157
|
role: "group",
|
|
2921
|
-
id,
|
|
2922
|
-
"aria-label": "Time",
|
|
2923
|
-
"aria-
|
|
3158
|
+
id: control.id,
|
|
3159
|
+
"aria-label": control.labelId ? void 0 : "Time",
|
|
3160
|
+
"aria-labelledby": control.labelId,
|
|
3161
|
+
"aria-describedby": control.describedBy,
|
|
3162
|
+
"aria-invalid": control.invalid || void 0,
|
|
2924
3163
|
onPaste: (e) => {
|
|
2925
3164
|
const text = e.clipboardData.getData("text");
|
|
2926
3165
|
if (text) {
|
|
@@ -2933,12 +3172,12 @@ function TimePicker({
|
|
|
2933
3172
|
CONTROL_HEIGHT4[size],
|
|
2934
3173
|
TEXT_SIZE4[size],
|
|
2935
3174
|
"border-[length:var(--ds-border-width)]",
|
|
2936
|
-
|
|
3175
|
+
control.invalid ? "border-[var(--ds-status-error)]" : "border-[var(--ds-input-border)]",
|
|
2937
3176
|
"bg-[var(--ds-input-bg)] rounded-[var(--ds-radius-md)]",
|
|
2938
3177
|
"shadow-[var(--ds-input-shadow)]",
|
|
2939
3178
|
"transition-colors",
|
|
2940
3179
|
"px-ds-3 py-ds-2",
|
|
2941
|
-
!
|
|
3180
|
+
!control.invalid && !disabled && !open && "hover:border-[var(--ds-input-border-hover)] focus-within:border-[var(--ds-input-border-hover)]",
|
|
2942
3181
|
open && ACTIVE_RING,
|
|
2943
3182
|
disabled && "opacity-disabled cursor-not-allowed",
|
|
2944
3183
|
"text-[var(--ds-text-primary)]"
|
|
@@ -3019,9 +3258,10 @@ function TimePicker({
|
|
|
3019
3258
|
id: listboxId,
|
|
3020
3259
|
role: "dialog",
|
|
3021
3260
|
"aria-label": "Choose a time",
|
|
3261
|
+
tabIndex: -1,
|
|
3022
3262
|
onKeyDown: handlePanelKeyDown,
|
|
3023
3263
|
className: cn(
|
|
3024
|
-
"fixed z-[var(--ds-z-popover)]",
|
|
3264
|
+
"fixed z-[var(--ds-z-popover)] outline-none",
|
|
3025
3265
|
"bg-[var(--ds-bg-surface-elevated)]",
|
|
3026
3266
|
GLASS_DROPDOWN,
|
|
3027
3267
|
"border-[length:var(--ds-border-width)] border-[var(--ds-border-default)]",
|
|
@@ -3101,7 +3341,7 @@ var sizes = {
|
|
|
3101
3341
|
};
|
|
3102
3342
|
function NumberInput({
|
|
3103
3343
|
value,
|
|
3104
|
-
onChange,
|
|
3344
|
+
onChange: onChangeProp,
|
|
3105
3345
|
min = -Infinity,
|
|
3106
3346
|
max = Infinity,
|
|
3107
3347
|
step = 1,
|
|
@@ -3115,6 +3355,7 @@ function NumberInput({
|
|
|
3115
3355
|
allowDecimals,
|
|
3116
3356
|
id
|
|
3117
3357
|
}) {
|
|
3358
|
+
const onChange = useReportedChange(onChangeProp, value);
|
|
3118
3359
|
const contextSize = useContext(ControlSizeContext);
|
|
3119
3360
|
const size = sizeProp ?? contextSize ?? "md";
|
|
3120
3361
|
const intervalRef = useRef(void 0);
|
|
@@ -3133,13 +3374,13 @@ function NumberInput({
|
|
|
3133
3374
|
[min, max]
|
|
3134
3375
|
);
|
|
3135
3376
|
const valueRef = useLatest(value);
|
|
3136
|
-
const commitValue = useCallback((v) => {
|
|
3377
|
+
const commitValue = useCallback((v, own = false) => {
|
|
3137
3378
|
const clamped = clamp(v);
|
|
3138
3379
|
valueRef.current = clamped;
|
|
3139
3380
|
setDraft(String(clamped));
|
|
3140
|
-
onChange(clamped);
|
|
3381
|
+
(own ? onChangeProp : onChange)(clamped);
|
|
3141
3382
|
return clamped;
|
|
3142
|
-
}, [onChange, clamp, valueRef]);
|
|
3383
|
+
}, [onChange, onChangeProp, clamp, valueRef]);
|
|
3143
3384
|
const increment = useCallback(() => commitValue(valueRef.current + step), [commitValue, step, valueRef]);
|
|
3144
3385
|
const decrement = useCallback(() => commitValue(valueRef.current - step), [commitValue, step, valueRef]);
|
|
3145
3386
|
const startRepeat = useCallback(
|
|
@@ -3181,7 +3422,7 @@ function NumberInput({
|
|
|
3181
3422
|
setDraft(String(committed));
|
|
3182
3423
|
} else {
|
|
3183
3424
|
const fallback = isFinite(min) ? min : 0;
|
|
3184
|
-
const committed = commitValue(value !== void 0 ? value : fallback);
|
|
3425
|
+
const committed = commitValue(value !== void 0 ? value : fallback, true);
|
|
3185
3426
|
setDraft(String(committed));
|
|
3186
3427
|
}
|
|
3187
3428
|
}, [draft, commitValue, min, value]);
|
|
@@ -3422,7 +3663,7 @@ var Tag = forwardRef(function Tag2({
|
|
|
3422
3663
|
});
|
|
3423
3664
|
function TagInput({
|
|
3424
3665
|
value,
|
|
3425
|
-
onChange,
|
|
3666
|
+
onChange: onChangeProp,
|
|
3426
3667
|
placeholder = "Add a tag...",
|
|
3427
3668
|
maxTags = Infinity,
|
|
3428
3669
|
disabled = false,
|
|
@@ -3431,6 +3672,7 @@ function TagInput({
|
|
|
3431
3672
|
id,
|
|
3432
3673
|
"aria-label": ariaLabel
|
|
3433
3674
|
}) {
|
|
3675
|
+
const onChange = useReportedChange(onChangeProp, value);
|
|
3434
3676
|
const [input, setInput] = useState("");
|
|
3435
3677
|
const inputRef = useRef(null);
|
|
3436
3678
|
const addTag = useCallback(
|
|
@@ -3556,7 +3798,7 @@ var sizes2 = {
|
|
|
3556
3798
|
};
|
|
3557
3799
|
function PinInput({
|
|
3558
3800
|
value,
|
|
3559
|
-
onChange,
|
|
3801
|
+
onChange: onChangeProp,
|
|
3560
3802
|
length = 6,
|
|
3561
3803
|
mask = false,
|
|
3562
3804
|
disabled = false,
|
|
@@ -3565,6 +3807,7 @@ function PinInput({
|
|
|
3565
3807
|
error = false,
|
|
3566
3808
|
id
|
|
3567
3809
|
}) {
|
|
3810
|
+
const onChange = useReportedChange(onChangeProp, value);
|
|
3568
3811
|
const contextSize = useContext(ControlSizeContext);
|
|
3569
3812
|
const size = sizeProp ?? contextSize ?? "md";
|
|
3570
3813
|
const inputsRef = useRef([]);
|
|
@@ -3700,7 +3943,7 @@ function StarIcon({ filled, half, size }) {
|
|
|
3700
3943
|
}
|
|
3701
3944
|
function Rating({
|
|
3702
3945
|
value,
|
|
3703
|
-
onChange,
|
|
3946
|
+
onChange: onChangeProp,
|
|
3704
3947
|
max = 5,
|
|
3705
3948
|
allowHalf = false,
|
|
3706
3949
|
readOnly = false,
|
|
@@ -3708,15 +3951,16 @@ function Rating({
|
|
|
3708
3951
|
className,
|
|
3709
3952
|
error = false
|
|
3710
3953
|
}) {
|
|
3954
|
+
const onChange = useReportedChange(onChangeProp, value);
|
|
3711
3955
|
const [hoverValue, setHoverValue] = useState(null);
|
|
3712
3956
|
const displayValue = hoverValue ?? value;
|
|
3713
3957
|
const handleClick = useCallback(
|
|
3714
3958
|
(starIdx, isLeftHalf) => {
|
|
3715
|
-
if (readOnly || !
|
|
3959
|
+
if (readOnly || !onChangeProp) return;
|
|
3716
3960
|
const newValue = allowHalf && isLeftHalf ? starIdx + 0.5 : starIdx + 1;
|
|
3717
3961
|
onChange(newValue === value ? 0 : newValue);
|
|
3718
3962
|
},
|
|
3719
|
-
[readOnly, onChange, allowHalf, value]
|
|
3963
|
+
[readOnly, onChangeProp, onChange, allowHalf, value]
|
|
3720
3964
|
);
|
|
3721
3965
|
const handleMouseMove = useCallback(
|
|
3722
3966
|
(starIdx, e) => {
|
|
@@ -3730,7 +3974,7 @@ function Rating({
|
|
|
3730
3974
|
const iconSize = iconSizes[size];
|
|
3731
3975
|
const step = allowHalf ? 0.5 : 1;
|
|
3732
3976
|
const handleKeyDown = (e) => {
|
|
3733
|
-
if (readOnly || !
|
|
3977
|
+
if (readOnly || !onChangeProp) return;
|
|
3734
3978
|
let next = null;
|
|
3735
3979
|
if (e.key === "ArrowRight" || e.key === "ArrowUp") next = Math.min(max, value + step);
|
|
3736
3980
|
else if (e.key === "ArrowLeft" || e.key === "ArrowDown") next = Math.max(0, value - step);
|
|
@@ -3854,13 +4098,14 @@ var DEFAULT_SWATCHES = [
|
|
|
3854
4098
|
];
|
|
3855
4099
|
function ColorPicker({
|
|
3856
4100
|
value,
|
|
3857
|
-
onChange,
|
|
4101
|
+
onChange: onChangeProp,
|
|
3858
4102
|
showAlpha = false,
|
|
3859
4103
|
swatches = DEFAULT_SWATCHES,
|
|
3860
4104
|
disabled = false,
|
|
3861
4105
|
className,
|
|
3862
4106
|
error = false
|
|
3863
4107
|
}) {
|
|
4108
|
+
const onChange = useReportedChange(onChangeProp, value);
|
|
3864
4109
|
const [hsl, setHsl] = useState(() => hexToHsl(value));
|
|
3865
4110
|
const [hexInput, setHexInput] = useState(value);
|
|
3866
4111
|
const satLightRef = useRef(null);
|
|
@@ -4101,6 +4346,7 @@ var Alert = forwardRef(function Alert2({
|
|
|
4101
4346
|
trigger: /* @__PURE__ */ jsx(
|
|
4102
4347
|
"button",
|
|
4103
4348
|
{
|
|
4349
|
+
type: "button",
|
|
4104
4350
|
className: cn(
|
|
4105
4351
|
"shrink-0 text-xs font-medium px-ds-2.5 py-ds-1 rounded-[var(--ds-radius-sm)]",
|
|
4106
4352
|
"transition-colors cursor-pointer",
|
|
@@ -4125,6 +4371,7 @@ var Alert = forwardRef(function Alert2({
|
|
|
4125
4371
|
return /* @__PURE__ */ jsxs(
|
|
4126
4372
|
"button",
|
|
4127
4373
|
{
|
|
4374
|
+
type: "button",
|
|
4128
4375
|
onClick: a.onClick,
|
|
4129
4376
|
className: cn(
|
|
4130
4377
|
"shrink-0 text-xs font-medium px-ds-2.5 py-ds-1 rounded-[var(--ds-radius-sm)]",
|
|
@@ -4145,6 +4392,7 @@ var Alert = forwardRef(function Alert2({
|
|
|
4145
4392
|
/* @__PURE__ */ jsxs(
|
|
4146
4393
|
"button",
|
|
4147
4394
|
{
|
|
4395
|
+
type: "button",
|
|
4148
4396
|
onClick: () => setDetailsExpanded(!detailsExpanded),
|
|
4149
4397
|
"aria-expanded": detailsExpanded,
|
|
4150
4398
|
className: cn(
|
|
@@ -4172,6 +4420,7 @@ var Alert = forwardRef(function Alert2({
|
|
|
4172
4420
|
dismissible && /* @__PURE__ */ jsx(
|
|
4173
4421
|
"button",
|
|
4174
4422
|
{
|
|
4423
|
+
type: "button",
|
|
4175
4424
|
onClick: onDismiss,
|
|
4176
4425
|
className: "shrink-0 text-[var(--ds-text-muted)] hover:text-[var(--ds-text-primary)] transition-colors cursor-pointer",
|
|
4177
4426
|
"aria-label": "Dismiss",
|
|
@@ -4182,6 +4431,12 @@ var Alert = forwardRef(function Alert2({
|
|
|
4182
4431
|
}
|
|
4183
4432
|
);
|
|
4184
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";
|
|
4185
4440
|
function stampFormId(node, formId) {
|
|
4186
4441
|
return Children.map(node, (child) => {
|
|
4187
4442
|
if (!isValidElement(child)) return child;
|
|
@@ -4189,23 +4444,21 @@ function stampFormId(node, formId) {
|
|
|
4189
4444
|
return cloneElement(child, { form: formId });
|
|
4190
4445
|
});
|
|
4191
4446
|
}
|
|
4192
|
-
var FormCtx = createContext(null);
|
|
4193
|
-
function useFormContext() {
|
|
4194
|
-
const ctx = useContext(FormCtx);
|
|
4195
|
-
if (!ctx) throw new Error("useFormContext must be used within FormWrapper");
|
|
4196
|
-
return ctx;
|
|
4197
|
-
}
|
|
4198
4447
|
function collectInvalidFields(form) {
|
|
4199
4448
|
const out = [];
|
|
4200
4449
|
for (const el of Array.from(form.querySelectorAll("[aria-invalid='true']"))) {
|
|
4201
4450
|
const id = el.id || "";
|
|
4202
4451
|
const label = id && form.querySelector(`label[for="${CSS.escape(id)}"]`)?.textContent?.replace(/\*\s*$/, "").trim() || el.getAttribute("aria-label") || el.closest("[data-field]")?.querySelector("label")?.textContent?.trim() || id || "A field";
|
|
4203
|
-
const described = (el.getAttribute("aria-describedby") ?? "").split(/\s+/).filter(Boolean);
|
|
4204
|
-
const message = described.
|
|
4452
|
+
const described = (el.getAttribute("aria-describedby") ?? "").split(/\s+/).filter(Boolean).map((d) => document.getElementById(d)).filter((d) => !!d);
|
|
4453
|
+
const message = described.find((d) => d.getAttribute("role") === "alert")?.textContent?.trim() || described.map((d) => d.textContent?.trim()).find((t) => t && t !== "Required" && /error|invalid|required|must|enter|choose|select|please/i.test(t)) || described.map((d) => d.textContent?.trim()).filter(Boolean).pop() || "Needs attention";
|
|
4205
4454
|
out.push({ id, label, message });
|
|
4206
4455
|
}
|
|
4207
4456
|
return out;
|
|
4208
4457
|
}
|
|
4458
|
+
function focusTarget(el) {
|
|
4459
|
+
if (el.tabIndex >= 0 || /^(?:INPUT|SELECT|TEXTAREA|BUTTON)$/.test(el.tagName)) return el;
|
|
4460
|
+
return el.querySelector("[aria-checked='true'], [aria-selected='true']:not([tabindex='-1'])") ?? el.querySelector("input, select, textarea, button, [tabindex]:not([tabindex='-1'])") ?? el;
|
|
4461
|
+
}
|
|
4209
4462
|
function FormWrapper({ onSubmit, validationMode: validationModeProp, children, actions: actionsProp, actionsAlign: actionsAlignProp, onCancel, cancelLabel = "Cancel", focusFirstError = true, errorSummary = true, className, ref }) {
|
|
4210
4463
|
const preferences = useShellPreferences();
|
|
4211
4464
|
const validationMode = validationModeProp ?? preferences.validationTiming ?? "onSubmit";
|
|
@@ -4240,27 +4493,65 @@ function FormWrapper({ onSubmit, validationMode: validationModeProp, children, a
|
|
|
4240
4493
|
const pendingSubmit = useRef(false);
|
|
4241
4494
|
const pendingFocus = useRef(false);
|
|
4242
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]);
|
|
4243
4504
|
useEffect(() => {
|
|
4244
4505
|
if (pendingSubmit.current && submitted) {
|
|
4245
4506
|
pendingSubmit.current = false;
|
|
4246
|
-
|
|
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
|
+
}
|
|
4247
4518
|
}
|
|
4248
|
-
}, [submitted, submitCount, errors, errorsRef, onSubmitRef]);
|
|
4519
|
+
}, [submitted, submitCount, errors, errorsRef, onSubmitRef, overlayMark]);
|
|
4520
|
+
const submittedRef = useLatest(submitted);
|
|
4521
|
+
const errorSummaryRef = useLatest(errorSummary);
|
|
4522
|
+
const summaryRef = useRef(null);
|
|
4523
|
+
const pendingSummaryFocus = useRef(false);
|
|
4524
|
+
const focusSummary = useCallback(() => {
|
|
4525
|
+
const el = summaryRef.current;
|
|
4526
|
+
if (!el) return;
|
|
4527
|
+
if (typeof el.scrollIntoView === "function") el.scrollIntoView({ block: "center", behavior: "smooth" });
|
|
4528
|
+
el.focus({ preventScroll: true });
|
|
4529
|
+
}, []);
|
|
4249
4530
|
const settle = useCallback(() => {
|
|
4250
4531
|
const form = formRef.current;
|
|
4251
4532
|
if (!form) return;
|
|
4252
4533
|
const invalid = collectInvalidFields(form);
|
|
4253
|
-
const next = invalid.length >= 2 ? invalid : [];
|
|
4534
|
+
const next = submittedRef.current && invalid.length >= 2 ? invalid : [];
|
|
4254
4535
|
setSummary((prev) => prev.length === next.length && prev.every((f, i) => f.id === next[i].id && f.message === next[i].message && f.label === next[i].label) ? prev : next);
|
|
4255
4536
|
if (pendingFocus.current && invalid.length > 0) {
|
|
4256
4537
|
pendingFocus.current = false;
|
|
4538
|
+
if (errorSummaryRef.current && next.length >= 2) {
|
|
4539
|
+
if (summaryRef.current) focusSummary();
|
|
4540
|
+
else pendingSummaryFocus.current = true;
|
|
4541
|
+
return;
|
|
4542
|
+
}
|
|
4257
4543
|
const first = form.querySelector("[aria-invalid='true']");
|
|
4258
4544
|
if (first) {
|
|
4259
4545
|
if (typeof first.scrollIntoView === "function") first.scrollIntoView({ block: "center", behavior: "smooth" });
|
|
4260
|
-
first.focus({ preventScroll: true });
|
|
4546
|
+
focusTarget(first).focus({ preventScroll: true });
|
|
4261
4547
|
}
|
|
4262
4548
|
}
|
|
4263
|
-
}, []);
|
|
4549
|
+
}, [submittedRef, errorSummaryRef, focusSummary]);
|
|
4550
|
+
useLayoutEffect(() => {
|
|
4551
|
+
if (!pendingSummaryFocus.current || summary.length < 2) return;
|
|
4552
|
+
pendingSummaryFocus.current = false;
|
|
4553
|
+
focusSummary();
|
|
4554
|
+
}, [summary, focusSummary]);
|
|
4264
4555
|
useLayoutEffect(() => {
|
|
4265
4556
|
if (!submitted) return;
|
|
4266
4557
|
settle();
|
|
@@ -4279,7 +4570,29 @@ function FormWrapper({ onSubmit, validationMode: validationModeProp, children, a
|
|
|
4279
4570
|
pendingFocus.current = false;
|
|
4280
4571
|
}, []);
|
|
4281
4572
|
const setError = useCallback((field, message) => {
|
|
4282
|
-
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
|
+
});
|
|
4582
|
+
}, []);
|
|
4583
|
+
const checks = useRef(/* @__PURE__ */ new Map());
|
|
4584
|
+
const register = useCallback((field, check) => {
|
|
4585
|
+
checks.current.set(field, check);
|
|
4586
|
+
return () => {
|
|
4587
|
+
if (checks.current.get(field) !== check) return;
|
|
4588
|
+
checks.current.delete(field);
|
|
4589
|
+
setErrors((prev) => {
|
|
4590
|
+
if (!(field in prev)) return prev;
|
|
4591
|
+
const next = { ...prev };
|
|
4592
|
+
delete next[field];
|
|
4593
|
+
return next;
|
|
4594
|
+
});
|
|
4595
|
+
};
|
|
4283
4596
|
}, []);
|
|
4284
4597
|
const clearErrors = useCallback(() => {
|
|
4285
4598
|
setErrors({});
|
|
@@ -4289,6 +4602,18 @@ function FormWrapper({ onSubmit, validationMode: validationModeProp, children, a
|
|
|
4289
4602
|
const handleSubmit = useCallback(
|
|
4290
4603
|
(e) => {
|
|
4291
4604
|
e.preventDefault();
|
|
4605
|
+
if (checks.current.size > 0) {
|
|
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
|
+
});
|
|
4616
|
+
}
|
|
4292
4617
|
pendingSubmit.current = true;
|
|
4293
4618
|
pendingFocus.current = focusFirstError;
|
|
4294
4619
|
setSubmitted(true);
|
|
@@ -4301,7 +4626,7 @@ function FormWrapper({ onSubmit, validationMode: validationModeProp, children, a
|
|
|
4301
4626
|
const el = id ? document.getElementById(id) : null;
|
|
4302
4627
|
if (el) {
|
|
4303
4628
|
el.scrollIntoView?.({ block: "center" });
|
|
4304
|
-
el.focus();
|
|
4629
|
+
focusTarget(el).focus();
|
|
4305
4630
|
}
|
|
4306
4631
|
};
|
|
4307
4632
|
const summaryNode = errorSummary && summary.length >= 2 ? typeof errorSummary === "function" ? errorSummary(summary) : /* @__PURE__ */ jsx(Alert, { variant: "error", title: `${summary.length} fields need attention`, className: "mb-ds-4", children: /* @__PURE__ */ jsx("ul", { className: "list-disc pl-ds-5 flex flex-col gap-ds-1", children: summary.map((f) => /* @__PURE__ */ jsxs("li", { children: [
|
|
@@ -4310,22 +4635,67 @@ function FormWrapper({ onSubmit, validationMode: validationModeProp, children, a
|
|
|
4310
4635
|
f.message
|
|
4311
4636
|
] }, f.id || f.label)) }) }) : null;
|
|
4312
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;
|
|
4313
|
-
return /* @__PURE__ */ jsx(FormCtx.Provider, { value: { errors, setError, clearErrors, validationMode, submitted }, 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: [
|
|
4314
|
-
summaryNode && /* @__PURE__ */ jsx("div", { "data-form-error-summary": "", children: summaryNode }),
|
|
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: [
|
|
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 }),
|
|
4315
4640
|
children,
|
|
4316
4641
|
actionsNode
|
|
4317
|
-
] }) });
|
|
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
|
+
] });
|
|
4318
4687
|
}
|
|
4319
4688
|
function TransferList({
|
|
4320
4689
|
available,
|
|
4321
4690
|
selected,
|
|
4322
|
-
onChange,
|
|
4691
|
+
onChange: onChangeProp,
|
|
4323
4692
|
availableTitle = "Available",
|
|
4324
4693
|
selectedTitle = "Selected",
|
|
4325
4694
|
searchable = true,
|
|
4326
4695
|
className,
|
|
4327
4696
|
ref
|
|
4328
4697
|
}) {
|
|
4698
|
+
const onChange = useReportedChange(onChangeProp, selected);
|
|
4329
4699
|
const [checkedAvailable, setCheckedAvailable] = useState(/* @__PURE__ */ new Set());
|
|
4330
4700
|
const [checkedSelected, setCheckedSelected] = useState(/* @__PURE__ */ new Set());
|
|
4331
4701
|
const [searchLeft, setSearchLeft] = useState("");
|
|
@@ -4407,6 +4777,7 @@ function TransferList({
|
|
|
4407
4777
|
/* @__PURE__ */ jsx(
|
|
4408
4778
|
"button",
|
|
4409
4779
|
{
|
|
4780
|
+
type: "button",
|
|
4410
4781
|
onClick: moveAllRight,
|
|
4411
4782
|
disabled: !available.filter((i) => !i.disabled).length,
|
|
4412
4783
|
"aria-label": isStacked ? "Move all down" : "Move all right",
|
|
@@ -4417,6 +4788,7 @@ function TransferList({
|
|
|
4417
4788
|
/* @__PURE__ */ jsx(
|
|
4418
4789
|
"button",
|
|
4419
4790
|
{
|
|
4791
|
+
type: "button",
|
|
4420
4792
|
onClick: moveRight,
|
|
4421
4793
|
disabled: !checkedAvailable.size,
|
|
4422
4794
|
"aria-label": isStacked ? "Move selected down" : "Move selected right",
|
|
@@ -4427,6 +4799,7 @@ function TransferList({
|
|
|
4427
4799
|
/* @__PURE__ */ jsx(
|
|
4428
4800
|
"button",
|
|
4429
4801
|
{
|
|
4802
|
+
type: "button",
|
|
4430
4803
|
onClick: moveLeft,
|
|
4431
4804
|
disabled: !checkedSelected.size,
|
|
4432
4805
|
"aria-label": isStacked ? "Move selected up" : "Move selected left",
|
|
@@ -4437,6 +4810,7 @@ function TransferList({
|
|
|
4437
4810
|
/* @__PURE__ */ jsx(
|
|
4438
4811
|
"button",
|
|
4439
4812
|
{
|
|
4813
|
+
type: "button",
|
|
4440
4814
|
onClick: moveAllLeft,
|
|
4441
4815
|
disabled: !selected.filter((i) => !i.disabled).length,
|
|
4442
4816
|
"aria-label": isStacked ? "Move all up" : "Move all left",
|
|
@@ -4568,66 +4942,10 @@ function toInitials(value) {
|
|
|
4568
4942
|
if (!/\s/.test(s) && Array.from(s).length <= 3) return s;
|
|
4569
4943
|
return initialsOf(s);
|
|
4570
4944
|
}
|
|
4571
|
-
var
|
|
4572
|
-
|
|
4573
|
-
|
|
4574
|
-
|
|
4575
|
-
info: "bg-[var(--ds-accent-primary)]",
|
|
4576
|
-
neutral: "bg-[var(--ds-text-muted)]",
|
|
4577
|
-
offline: "bg-[var(--ds-text-muted)] opacity-disabled"
|
|
4578
|
-
};
|
|
4579
|
-
var pulseRingColors = {
|
|
4580
|
-
success: "bg-[color-mix(in_oklch,var(--ds-status-success)_30%,transparent)]",
|
|
4581
|
-
warning: "bg-[color-mix(in_oklch,var(--ds-status-warning)_30%,transparent)]",
|
|
4582
|
-
error: "bg-[color-mix(in_oklch,var(--ds-status-error)_30%,transparent)]",
|
|
4583
|
-
info: "bg-[var(--ds-accent-soft)]",
|
|
4584
|
-
neutral: "bg-[color-mix(in_oklch,var(--ds-text-muted)_20%,transparent)]",
|
|
4585
|
-
offline: "bg-[color-mix(in_oklch,var(--ds-text-muted)_10%,transparent)]"
|
|
4586
|
-
};
|
|
4587
|
-
var StatusDot = forwardRef(function StatusDot2({
|
|
4588
|
-
variant = "neutral",
|
|
4589
|
-
label,
|
|
4590
|
-
pulse = false,
|
|
4591
|
-
className
|
|
4592
|
-
}, ref) {
|
|
4593
|
-
return /* @__PURE__ */ jsxs(
|
|
4594
|
-
"span",
|
|
4595
|
-
{
|
|
4596
|
-
ref,
|
|
4597
|
-
className: cn("inline-flex items-center gap-ds-1.5", className),
|
|
4598
|
-
role: "status",
|
|
4599
|
-
"aria-label": label ?? variant,
|
|
4600
|
-
children: [
|
|
4601
|
-
/* @__PURE__ */ jsxs("span", { className: "relative inline-flex shrink-0", children: [
|
|
4602
|
-
/* @__PURE__ */ jsx(
|
|
4603
|
-
"span",
|
|
4604
|
-
{
|
|
4605
|
-
className: cn(
|
|
4606
|
-
"rounded-[var(--ds-radius-full)] h-2.5 w-2.5",
|
|
4607
|
-
variantColors[variant]
|
|
4608
|
-
)
|
|
4609
|
-
}
|
|
4610
|
-
),
|
|
4611
|
-
pulse && variant !== "offline" && /* @__PURE__ */ jsx(
|
|
4612
|
-
"span",
|
|
4613
|
-
{
|
|
4614
|
-
className: cn(
|
|
4615
|
-
"absolute inset-0 rounded-[var(--ds-radius-full)]",
|
|
4616
|
-
"animate-ping motion-reduce:animate-none",
|
|
4617
|
-
pulseRingColors[variant]
|
|
4618
|
-
)
|
|
4619
|
-
}
|
|
4620
|
-
)
|
|
4621
|
-
] }),
|
|
4622
|
-
label && /* @__PURE__ */ jsx("span", { className: "font-normal text-[var(--ds-text-primary)] text-[length:var(--ds-font-size-xs)]", children: label })
|
|
4623
|
-
]
|
|
4624
|
-
}
|
|
4625
|
-
);
|
|
4626
|
-
});
|
|
4627
|
-
var sizeStyles2 = {
|
|
4628
|
-
sm: "h-8 w-8 text-xs",
|
|
4629
|
-
md: "h-10 w-10 text-sm",
|
|
4630
|
-
lg: "h-12 w-12 text-base"
|
|
4945
|
+
var sizeStyles2 = {
|
|
4946
|
+
sm: "h-8 w-8 text-xs",
|
|
4947
|
+
md: "h-10 w-10 text-sm",
|
|
4948
|
+
lg: "h-12 w-12 text-base"
|
|
4631
4949
|
};
|
|
4632
4950
|
var paletteStyles = {
|
|
4633
4951
|
1: "bg-[var(--ds-palette-1-bg,var(--ds-bg-muted))] text-[var(--ds-palette-1-text,var(--ds-text-secondary))]",
|
|
@@ -4646,13 +4964,23 @@ function colorStyles(color, seed) {
|
|
|
4646
4964
|
if (color === "neutral") return "bg-[var(--ds-bg-muted)] text-[var(--ds-text-secondary)]";
|
|
4647
4965
|
return paletteStyles[color === "auto" ? paletteFor(seed) : color];
|
|
4648
4966
|
}
|
|
4649
|
-
|
|
4650
|
-
|
|
4651
|
-
|
|
4652
|
-
|
|
4653
|
-
|
|
4654
|
-
}
|
|
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
|
+
}
|
|
4655
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;
|
|
4656
4984
|
const base = cn(
|
|
4657
4985
|
"inline-flex items-center justify-center font-medium shrink-0",
|
|
4658
4986
|
"rounded-[var(--ds-radius-full)]",
|
|
@@ -4664,13 +4992,15 @@ function Avatar({ initials, src, alt, size = "md", status, color = "auto", class
|
|
|
4664
4992
|
{
|
|
4665
4993
|
"data-avatar": "",
|
|
4666
4994
|
src,
|
|
4667
|
-
alt: alt ?? initials ?? "",
|
|
4995
|
+
alt: named ?? alt ?? initials ?? "",
|
|
4668
4996
|
className: cn(base, "object-cover")
|
|
4669
4997
|
}
|
|
4670
4998
|
) : /* @__PURE__ */ jsx(
|
|
4671
4999
|
"div",
|
|
4672
5000
|
{
|
|
4673
5001
|
"data-avatar": "",
|
|
5002
|
+
role: named ? "img" : void 0,
|
|
5003
|
+
"aria-label": named,
|
|
4674
5004
|
className: cn(
|
|
4675
5005
|
base,
|
|
4676
5006
|
colorStyles(color, alt ?? initials ?? ""),
|
|
@@ -4692,20 +5022,14 @@ function Avatar({ initials, src, alt, size = "md", status, color = "auto", class
|
|
|
4692
5022
|
size === "lg" && "bottom-[0px] right-[0px]"
|
|
4693
5023
|
),
|
|
4694
5024
|
"aria-hidden": "true",
|
|
4695
|
-
children: /* @__PURE__ */ jsx(
|
|
4696
|
-
StatusDot,
|
|
4697
|
-
{
|
|
4698
|
-
variant: statusVariantMap[status],
|
|
4699
|
-
className: "rounded-[var(--ds-radius-full)] shadow-[0_0_0_2px_var(--ds-bg-canvas)]"
|
|
4700
|
-
}
|
|
4701
|
-
)
|
|
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 }) })
|
|
4702
5026
|
}
|
|
4703
5027
|
)
|
|
4704
5028
|
] });
|
|
4705
5029
|
}
|
|
4706
5030
|
function MentionInput({
|
|
4707
5031
|
value: controlledValue,
|
|
4708
|
-
onChange,
|
|
5032
|
+
onChange: onChangeProp,
|
|
4709
5033
|
suggestions,
|
|
4710
5034
|
trigger = "@",
|
|
4711
5035
|
placeholder,
|
|
@@ -4714,6 +5038,7 @@ function MentionInput({
|
|
|
4714
5038
|
}) {
|
|
4715
5039
|
const [internalValue, setInternalValue] = useState("");
|
|
4716
5040
|
const value = controlledValue ?? internalValue;
|
|
5041
|
+
const onChange = useReportedChange(onChangeProp, value);
|
|
4717
5042
|
const [query, setQuery] = useState("");
|
|
4718
5043
|
const [showPopup, setShowPopup] = useState(false);
|
|
4719
5044
|
const [activeIndex, setActiveIndex] = useState(0);
|
|
@@ -4909,11 +5234,36 @@ function MentionInput({
|
|
|
4909
5234
|
}
|
|
4910
5235
|
var HEADER_LAYOUT = {
|
|
4911
5236
|
row: "flex flex-wrap items-start justify-between gap-ds-4",
|
|
4912
|
-
block: "flex flex-col space-y-ds-1.5 grow basis-1/2 [
|
|
4913
|
-
titleLeads: "grow basis-1/2 max-w-max [
|
|
5237
|
+
block: "flex flex-col space-y-ds-1.5 grow basis-1/2 break-words max-w-full has-[[data-title-one-line]]:min-w-0",
|
|
5238
|
+
titleLeads: "grow basis-1/2 max-w-max break-words has-[[data-title-one-line]]:min-w-0",
|
|
5239
|
+
floorOff: "min-w-0",
|
|
4914
5240
|
actions: "flex items-center gap-ds-2 shrink-0 ml-auto",
|
|
4915
5241
|
below: "mt-ds-1.5"
|
|
4916
5242
|
};
|
|
5243
|
+
function useTitleFloorFits(rowRef, active) {
|
|
5244
|
+
const [fits, setFits] = useState(true);
|
|
5245
|
+
useLayoutEffect(() => {
|
|
5246
|
+
const row = rowRef.current;
|
|
5247
|
+
if (!active || !row) return;
|
|
5248
|
+
const measure = () => {
|
|
5249
|
+
const title = row.querySelector("h1, h2, h3, h4, h5, h6");
|
|
5250
|
+
if (!title) return;
|
|
5251
|
+
const width = title.style.width;
|
|
5252
|
+
title.style.width = "min-content";
|
|
5253
|
+
const longest = title.getBoundingClientRect().width;
|
|
5254
|
+
title.style.width = width;
|
|
5255
|
+
if (longest === 0) return;
|
|
5256
|
+
const next = longest <= row.clientWidth + 0.5;
|
|
5257
|
+
setFits((was) => was === next ? was : next);
|
|
5258
|
+
};
|
|
5259
|
+
measure();
|
|
5260
|
+
if (typeof ResizeObserver === "undefined") return;
|
|
5261
|
+
const observer = new ResizeObserver(measure);
|
|
5262
|
+
observer.observe(row);
|
|
5263
|
+
return () => observer.disconnect();
|
|
5264
|
+
}, [rowRef, active]);
|
|
5265
|
+
return fits;
|
|
5266
|
+
}
|
|
4917
5267
|
function actionsAreBadges(actions) {
|
|
4918
5268
|
const items = Children.toArray(actions);
|
|
4919
5269
|
return items.length > 0 && items.every((item) => isValidElement(item) && (item.type === Fragment$1 ? actionsAreBadges(item.props.children) : item.type === Badge));
|
|
@@ -5038,7 +5388,6 @@ var Card = forwardRef(function Card2({
|
|
|
5038
5388
|
...props
|
|
5039
5389
|
}, ref) {
|
|
5040
5390
|
const isSelectable = selectable || !!selectType;
|
|
5041
|
-
const isToggle = selectType === "toggle";
|
|
5042
5391
|
const hasSelectType = !!selectType;
|
|
5043
5392
|
const isAction = !isSelectable && variant === "interactive" && !!onClick;
|
|
5044
5393
|
const rootRef = useRef(null);
|
|
@@ -5092,7 +5441,6 @@ var Card = forwardRef(function Card2({
|
|
|
5092
5441
|
const isButton = isSelectable || isAction && !holdsControls;
|
|
5093
5442
|
const role = selectType === "radio" ? "radio" : selectType === "checkbox" ? "checkbox" : selectType === "toggle" ? "switch" : isButton ? "button" : void 0;
|
|
5094
5443
|
const ariaAttr = selectType === "radio" || selectType === "checkbox" || selectType === "toggle" ? { "aria-checked": !!selected } : isSelectable ? { "aria-pressed": !!selected } : {};
|
|
5095
|
-
const showRing = isSelectable && !isToggle && !hasSelectType && selected;
|
|
5096
5444
|
const indicator = selectType === "radio" ? /* @__PURE__ */ jsx(RadioIndicator, { checked: !!selected, disabled }) : selectType === "checkbox" ? /* @__PURE__ */ jsx(CheckboxIndicator, { checked: !!selected, indeterminate, disabled }) : selectType === "toggle" ? /* @__PURE__ */ jsx(ToggleIndicator, { checked: !!selected, disabled }) : null;
|
|
5097
5445
|
const defaultCheckBadge = !hasSelectType && !checkable && selected && !loading ? /* @__PURE__ */ jsx("div", { className: "absolute top-ds-3 right-ds-3 w-5 h-5 rounded-[var(--ds-radius-full)] bg-[var(--ds-accent-primary)] flex items-center justify-center", children: /* @__PURE__ */ jsx(Icon, { name: "check", size: 12, className: "text-[var(--ds-text-on-primary)]" }) }) : null;
|
|
5098
5446
|
return /* @__PURE__ */ jsxs(
|
|
@@ -5111,7 +5459,10 @@ var Card = forwardRef(function Card2({
|
|
|
5111
5459
|
isSelectable && !disabled && "cursor-pointer select-none transition-all duration-[var(--ds-transition-speed)] ease-[var(--ds-transition-ease)]",
|
|
5112
5460
|
isSelectable && !disabled && !selected && "hover:border-[var(--ds-accent-primary)]",
|
|
5113
5461
|
isButton && "focus-visible:outline-none focus-visible:shadow-[var(--ds-shadow-focus)]",
|
|
5114
|
-
|
|
5462
|
+
// Selected is the accent border, with the accent-subtle fill on a card with a selectType. No ring: a ring round the
|
|
5463
|
+
// whole card is the focus state (focus-visible:shadow-[var(--ds-shadow-focus)] above), and the active halo other
|
|
5464
|
+
// controls take (ACTIVE_RING, since Sprint 20.6) made a selected card look focused (the owner, 27 September 2026).
|
|
5465
|
+
isSelectable && selected && "border-[var(--ds-border-focus)]",
|
|
5115
5466
|
hasSelectType && selected && "bg-[var(--ds-accent-subtle)]",
|
|
5116
5467
|
disabled && "opacity-disabled cursor-not-allowed",
|
|
5117
5468
|
className
|
|
@@ -5184,14 +5535,16 @@ var CardHeader = forwardRef(function CardHeader2({ className, children, actions,
|
|
|
5184
5535
|
)
|
|
5185
5536
|
] }) : null;
|
|
5186
5537
|
const iconBlock = icon ? /* @__PURE__ */ jsx("span", { className: "shrink-0 h-10 w-10 rounded-[var(--ds-radius-md)] bg-[var(--ds-bg-muted)] flex items-center justify-center mb-ds-1", children: /* @__PURE__ */ jsx(Icon, { name: icon, size: 20, className: "text-[var(--ds-text-secondary)]" }) }) : null;
|
|
5538
|
+
const parts = Children.toArray(children);
|
|
5539
|
+
const titleLeads = !!hasActions && !iconBlock && !menuItems && actionsAreBadges(actions) && parts.length > 0 && isValidElement(parts[0]) && parts[0].type === CardTitle;
|
|
5540
|
+
const leadRowRef = useRef(null);
|
|
5541
|
+
const leadFloorFits = useTitleFloorFits(leadRowRef, titleLeads);
|
|
5187
5542
|
if (hasActions) {
|
|
5188
|
-
const parts = Children.toArray(children);
|
|
5189
|
-
const titleLeads = !iconBlock && !menuItems && actionsAreBadges(actions) && parts.length > 0 && isValidElement(parts[0]) && parts[0].type === CardTitle;
|
|
5190
5543
|
if (titleLeads) {
|
|
5191
5544
|
const below = parts.slice(1);
|
|
5192
5545
|
return /* @__PURE__ */ jsxs("div", { ref, className: cn(pl, "pr-ds-5 pt-ds-4 last:pb-ds-4", className), ...props, children: [
|
|
5193
|
-
/* @__PURE__ */ jsxs("div", { className: HEADER_LAYOUT.row, children: [
|
|
5194
|
-
/* @__PURE__ */ jsx("div", { "data-card-title-row": "", className: HEADER_LAYOUT.titleLeads, children: parts[0] }),
|
|
5546
|
+
/* @__PURE__ */ jsxs("div", { ref: leadRowRef, className: HEADER_LAYOUT.row, children: [
|
|
5547
|
+
/* @__PURE__ */ jsx("div", { "data-card-title-row": "", className: cn(HEADER_LAYOUT.titleLeads, !leadFloorFits && HEADER_LAYOUT.floorOff), children: parts[0] }),
|
|
5195
5548
|
actionsBlock
|
|
5196
5549
|
] }),
|
|
5197
5550
|
below.length > 0 && /* @__PURE__ */ jsx("div", { className: cn("flex flex-col space-y-ds-1.5 break-words", HEADER_LAYOUT.below), children: below })
|
|
@@ -5233,7 +5586,8 @@ var CardTitle = forwardRef(function CardTitle2({ className, children, lines = 2,
|
|
|
5233
5586
|
},
|
|
5234
5587
|
id: id ?? generatedId,
|
|
5235
5588
|
"data-card-title": "",
|
|
5236
|
-
|
|
5589
|
+
...lines === 1 ? { "data-title-one-line": "" } : {},
|
|
5590
|
+
className: cn(TITLE_TEXT, !action && lines > 0 && lineClampClass, action && lines === 1 && "text-ellipsis", className),
|
|
5237
5591
|
...props,
|
|
5238
5592
|
children: action ? (
|
|
5239
5593
|
// The card's action when the card holds controls of its own (Sprint 25.7): a real button, which a click
|
|
@@ -5401,6 +5755,58 @@ function DataList({ items, columns = 1, className }) {
|
|
|
5401
5755
|
}
|
|
5402
5756
|
);
|
|
5403
5757
|
}
|
|
5758
|
+
var COUNT_FROM_PAGE = [
|
|
5759
|
+
"[&:has(>:nth-child(2):last-child)]:[--gs-cards:2]",
|
|
5760
|
+
"[&:has(>:nth-child(3):last-child)]:[--gs-cards:3]",
|
|
5761
|
+
"[&:has(>:nth-child(4):last-child)]:[--gs-cards:4]",
|
|
5762
|
+
"[&:has(>:nth-child(5):last-child)]:[--gs-cards:5]",
|
|
5763
|
+
"[&:has(>:nth-child(6):last-child)]:[--gs-cards:6]",
|
|
5764
|
+
"[&:has(>:nth-child(7):last-child)]:[--gs-cards:7]",
|
|
5765
|
+
"[&:has(>:nth-child(8):last-child)]:[--gs-cards:8]",
|
|
5766
|
+
"[&:has(>:nth-child(9):last-child)]:[--gs-cards:9]",
|
|
5767
|
+
"[&:has(>:nth-child(10):last-child)]:[--gs-cards:10]",
|
|
5768
|
+
"[&:has(>:nth-child(11):last-child)]:[--gs-cards:11]",
|
|
5769
|
+
"[&:has(>:nth-child(12))]:[--gs-cards:12]"
|
|
5770
|
+
].join(" ");
|
|
5771
|
+
function countCards(children) {
|
|
5772
|
+
let n = 0;
|
|
5773
|
+
Children.forEach(children, (child) => {
|
|
5774
|
+
if (isValidElement(child) && child.type === Fragment$1) n += countCards(child.props.children);
|
|
5775
|
+
else if (child !== null && child !== void 0 && typeof child !== "boolean" && child !== "") n += 1;
|
|
5776
|
+
});
|
|
5777
|
+
return n;
|
|
5778
|
+
}
|
|
5779
|
+
function CardGrid({ minWidth = "14rem", maxColumns = 4, compare = false, gap = "var(--ds-space-4)", className, style, children, ref, ...props }) {
|
|
5780
|
+
const most = Math.max(1, Math.floor(maxColumns));
|
|
5781
|
+
const n = compare ? "var(--gs-cards, var(--gs-cards-counted))" : String(most);
|
|
5782
|
+
const share = `calc((100% - (${n} - 1) * var(--gs-card-gap)) / ${n})`;
|
|
5783
|
+
const column = compare ? `max(${share}, min(100%, calc((${n} * ${minWidth} + (${n} - 1) * var(--gs-card-gap) - 100%) * 999)))` : `max(min(${minWidth}, 100%), ${share})`;
|
|
5784
|
+
const template = {
|
|
5785
|
+
"--gs-card-gap": gap,
|
|
5786
|
+
...compare ? { "--gs-cards-counted": Math.max(1, countCards(children)) } : {},
|
|
5787
|
+
gap: "var(--gs-card-gap)",
|
|
5788
|
+
gridTemplateColumns: `repeat(auto-fill, minmax(${column}, 1fr))`,
|
|
5789
|
+
// a comparison's cards share their rows: the headers, the contents and the footers line up across the row
|
|
5790
|
+
...compare ? { gridAutoRows: "auto 1fr auto" } : {}
|
|
5791
|
+
};
|
|
5792
|
+
return /* @__PURE__ */ jsx(
|
|
5793
|
+
"div",
|
|
5794
|
+
{
|
|
5795
|
+
ref,
|
|
5796
|
+
"data-card-grid": compare ? "compare" : "",
|
|
5797
|
+
className: cn(
|
|
5798
|
+
"grid",
|
|
5799
|
+
compare && COUNT_FROM_PAGE,
|
|
5800
|
+
// each card spans its three rows and lays its parts in them; anything else just fills them
|
|
5801
|
+
compare && "[&>*]:row-span-3 [&>[data-card]]:grid [&>[data-card]]:grid-rows-subgrid [&>[data-card]]:gap-y-0",
|
|
5802
|
+
className
|
|
5803
|
+
),
|
|
5804
|
+
style: { ...template, ...style },
|
|
5805
|
+
...props,
|
|
5806
|
+
children
|
|
5807
|
+
}
|
|
5808
|
+
);
|
|
5809
|
+
}
|
|
5404
5810
|
var sizeStyles3 = {
|
|
5405
5811
|
sm: { gap: "gap-ds-0.5", label: "text-[length:var(--ds-font-size-xs)]", value: "text-[length:var(--ds-font-size-xs)]", iconSize: 12, py: "py-ds-1.5" },
|
|
5406
5812
|
md: { gap: "gap-ds-1", label: "text-[length:var(--ds-font-size-sm)]", value: "text-[length:var(--ds-font-size-sm)]", iconSize: 14, py: "py-ds-2.5" },
|
|
@@ -5530,7 +5936,7 @@ var DescriptionList = forwardRef(function DescriptionList2({
|
|
|
5530
5936
|
]
|
|
5531
5937
|
}
|
|
5532
5938
|
),
|
|
5533
|
-
/* @__PURE__ */ jsx("dd", { className: cn("font-normal text-[var(--ds-text-primary)] text-right flex-1 min-w-0", s.value), children: item.value })
|
|
5939
|
+
/* @__PURE__ */ jsx("dd", { className: cn("font-normal text-[var(--ds-text-primary)] text-right flex-1 min-w-0 [overflow-wrap:anywhere] [:where(&)>*]:[justify-content:safe_flex-end] [:where(&)>*]:flex-wrap", s.value), children: item.value })
|
|
5534
5940
|
]
|
|
5535
5941
|
},
|
|
5536
5942
|
i
|
|
@@ -5538,6 +5944,57 @@ var DescriptionList = forwardRef(function DescriptionList2({
|
|
|
5538
5944
|
}
|
|
5539
5945
|
);
|
|
5540
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
|
+
});
|
|
5541
5998
|
function Accordion({ items, type = "single", defaultOpen = [], open: controlledOpen, onOpenChange, className }) {
|
|
5542
5999
|
const [internalOpen, setInternalOpen] = useState(new Set(defaultOpen));
|
|
5543
6000
|
const baseId = useId();
|
|
@@ -5572,6 +6029,7 @@ function Accordion({ items, type = "single", defaultOpen = [], open: controlledO
|
|
|
5572
6029
|
/* @__PURE__ */ jsxs(
|
|
5573
6030
|
"button",
|
|
5574
6031
|
{
|
|
6032
|
+
type: "button",
|
|
5575
6033
|
id: triggerId,
|
|
5576
6034
|
"aria-expanded": isOpen,
|
|
5577
6035
|
"aria-controls": panelId,
|
|
@@ -5692,7 +6150,7 @@ function TruncCell({ children, lines }) {
|
|
|
5692
6150
|
if (!isTruncated) return cell;
|
|
5693
6151
|
return /* @__PURE__ */ jsx(Tooltip, { content: children, children: cell });
|
|
5694
6152
|
}
|
|
5695
|
-
var TITLE_CLASSES =
|
|
6153
|
+
var TITLE_CLASSES = TITLE_TEXT;
|
|
5696
6154
|
var FRAME_CLASSES = cn(
|
|
5697
6155
|
"border-[length:var(--ds-border-width)] border-[var(--ds-border-subtle)]",
|
|
5698
6156
|
"rounded-[var(--ds-radius-md)]",
|
|
@@ -5702,16 +6160,19 @@ var FRAME_CLASSES = cn(
|
|
|
5702
6160
|
function TableHeading({ title, description, actions, titleId, descriptionId, inset }) {
|
|
5703
6161
|
const heading = /* @__PURE__ */ jsx("h3", { id: titleId, className: TITLE_CLASSES, children: title });
|
|
5704
6162
|
const actionsBlock = actions ? /* @__PURE__ */ jsx("div", { className: HEADER_LAYOUT.actions, children: actions }) : null;
|
|
6163
|
+
const titleLeads = !actions || actionsAreBadges(actions);
|
|
6164
|
+
const leadRowRef = useRef(null);
|
|
6165
|
+
const leadFloorFits = useTitleFloorFits(leadRowRef, titleLeads);
|
|
5705
6166
|
const descriptionText = (className) => description ? /* @__PURE__ */ jsx("p", { id: descriptionId, className: cn(className, "text-sm text-[var(--ds-text-muted)] break-words"), children: description }) : null;
|
|
5706
|
-
return /* @__PURE__ */ jsx("div", { "data-table-heading": "", className: cn(inset ? "px-ds-5 py-ds-4" : "pb-ds-4"), children:
|
|
6167
|
+
return /* @__PURE__ */ jsx("div", { "data-table-heading": "", className: cn(inset ? "px-ds-5 py-ds-4" : "pb-ds-4"), children: !titleLeads ? /* @__PURE__ */ jsxs("div", { className: HEADER_LAYOUT.row, children: [
|
|
5707
6168
|
/* @__PURE__ */ jsxs("div", { className: HEADER_LAYOUT.block, children: [
|
|
5708
6169
|
heading,
|
|
5709
6170
|
descriptionText()
|
|
5710
6171
|
] }),
|
|
5711
6172
|
actionsBlock
|
|
5712
6173
|
] }) : /* @__PURE__ */ jsxs(Fragment, { children: [
|
|
5713
|
-
/* @__PURE__ */ jsxs("div", { className: HEADER_LAYOUT.row, children: [
|
|
5714
|
-
/* @__PURE__ */ jsx("div", { className: HEADER_LAYOUT.titleLeads, children: heading }),
|
|
6174
|
+
/* @__PURE__ */ jsxs("div", { ref: leadRowRef, className: HEADER_LAYOUT.row, children: [
|
|
6175
|
+
/* @__PURE__ */ jsx("div", { className: cn(HEADER_LAYOUT.titleLeads, !leadFloorFits && HEADER_LAYOUT.floorOff), children: heading }),
|
|
5715
6176
|
actionsBlock
|
|
5716
6177
|
] }),
|
|
5717
6178
|
descriptionText(HEADER_LAYOUT.below)
|
|
@@ -5954,6 +6415,7 @@ function Table({
|
|
|
5954
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(
|
|
5955
6416
|
"button",
|
|
5956
6417
|
{
|
|
6418
|
+
type: "button",
|
|
5957
6419
|
onClick: () => toggleExpand(i),
|
|
5958
6420
|
className: "text-[var(--ds-text-muted)] hover:text-[var(--ds-text-primary)] cursor-pointer",
|
|
5959
6421
|
"aria-expanded": isExpanded,
|
|
@@ -6070,7 +6532,7 @@ var indicatorInset = {
|
|
|
6070
6532
|
};
|
|
6071
6533
|
function SegmentedControl({
|
|
6072
6534
|
value,
|
|
6073
|
-
onChange,
|
|
6535
|
+
onChange: onChangeProp,
|
|
6074
6536
|
options,
|
|
6075
6537
|
size: sizeProp,
|
|
6076
6538
|
variant = "default",
|
|
@@ -6078,9 +6540,13 @@ function SegmentedControl({
|
|
|
6078
6540
|
onHoverChange,
|
|
6079
6541
|
className,
|
|
6080
6542
|
"aria-label": ariaLabel,
|
|
6081
|
-
maxOptions = 6
|
|
6543
|
+
maxOptions = 6,
|
|
6544
|
+
...wiring
|
|
6082
6545
|
}) {
|
|
6546
|
+
const onChange = useReportedChange(onChangeProp, value);
|
|
6083
6547
|
const contextSize = useContext(ControlSizeContext);
|
|
6548
|
+
const control = useFieldControl(wiring);
|
|
6549
|
+
const named = !ariaLabel && control.labelId ? { "aria-labelledby": control.labelId } : {};
|
|
6084
6550
|
const size = sizeProp ?? contextSize ?? "md";
|
|
6085
6551
|
const containerRef = useRef(null);
|
|
6086
6552
|
const [indicator, setIndicator] = useState({ left: 0, width: 0 });
|
|
@@ -6176,6 +6642,7 @@ function SegmentedControl({
|
|
|
6176
6642
|
Dropdown,
|
|
6177
6643
|
{
|
|
6178
6644
|
"aria-label": ariaLabel,
|
|
6645
|
+
...wiring,
|
|
6179
6646
|
size: size === "md" || size === "lg" ? "md" : "sm",
|
|
6180
6647
|
options: options.filter((o) => !o.disabled).map((o) => ({ id: o.value, label: o.label })),
|
|
6181
6648
|
value,
|
|
@@ -6189,7 +6656,12 @@ function SegmentedControl({
|
|
|
6189
6656
|
{
|
|
6190
6657
|
ref: containerRef,
|
|
6191
6658
|
role: "radiogroup",
|
|
6659
|
+
id: control.id,
|
|
6192
6660
|
"aria-label": ariaLabel,
|
|
6661
|
+
...named,
|
|
6662
|
+
"aria-describedby": control.describedBy,
|
|
6663
|
+
"aria-invalid": control.invalid || void 0,
|
|
6664
|
+
"aria-required": control.required || void 0,
|
|
6193
6665
|
onKeyDown: handleKeyDown,
|
|
6194
6666
|
className: cn(
|
|
6195
6667
|
"relative items-center",
|
|
@@ -6199,6 +6671,7 @@ function SegmentedControl({
|
|
|
6199
6671
|
"bg-[var(--ds-bg-muted)]",
|
|
6200
6672
|
"rounded-[var(--ds-radius-lg)]",
|
|
6201
6673
|
variant === "default" && "border-[length:var(--ds-border-width)] border-[var(--ds-border-default)]",
|
|
6674
|
+
control.invalid && "border-[length:var(--ds-border-width)] border-[var(--ds-status-error)]",
|
|
6202
6675
|
className
|
|
6203
6676
|
),
|
|
6204
6677
|
children: [
|
|
@@ -6709,7 +7182,7 @@ function WeekView({
|
|
|
6709
7182
|
return /* @__PURE__ */ jsxs("div", { ref: containerRef, className: "flex flex-col h-full overflow-hidden", children: [
|
|
6710
7183
|
/* @__PURE__ */ jsxs("div", { className: "flex border-b-[length:var(--ds-divider-width)] border-[var(--ds-border-subtle)]", children: [
|
|
6711
7184
|
/* @__PURE__ */ jsx("div", { className: "w-14 shrink-0 border-r-[length:var(--ds-divider-width)] border-[var(--ds-border-subtle)]" }),
|
|
6712
|
-
/* @__PURE__ */ jsx("div", { className: "flex-1 overflow-x-auto scrollbar-none", "data-week-scroll": true, children: /* @__PURE__ */ jsx(
|
|
7185
|
+
/* @__PURE__ */ jsx("div", { className: "flex-1 overflow-x-auto gs-scrollbar-none", "data-week-scroll": true, children: /* @__PURE__ */ jsx(
|
|
6713
7186
|
"div",
|
|
6714
7187
|
{
|
|
6715
7188
|
className: "grid",
|
|
@@ -6749,7 +7222,7 @@ function WeekView({
|
|
|
6749
7222
|
] }),
|
|
6750
7223
|
hasAllDay && /* @__PURE__ */ jsxs("div", { className: "flex border-b-[length:var(--ds-divider-width)] border-[var(--ds-border-subtle)] bg-[var(--ds-bg-muted)]/30", children: [
|
|
6751
7224
|
/* @__PURE__ */ jsx("div", { className: "w-14 shrink-0 border-r-[length:var(--ds-divider-width)] border-[var(--ds-border-subtle)] text-2xs text-[var(--ds-text-muted)] px-ds-1 py-ds-1 text-right", children: "all-day" }),
|
|
6752
|
-
/* @__PURE__ */ jsx("div", { className: "flex-1 overflow-x-auto scrollbar-none", "data-week-scroll": true, children: /* @__PURE__ */ jsx(
|
|
7225
|
+
/* @__PURE__ */ jsx("div", { className: "flex-1 overflow-x-auto gs-scrollbar-none", "data-week-scroll": true, children: /* @__PURE__ */ jsx(
|
|
6753
7226
|
"div",
|
|
6754
7227
|
{
|
|
6755
7228
|
className: "grid",
|
|
@@ -6786,7 +7259,7 @@ function WeekView({
|
|
|
6786
7259
|
},
|
|
6787
7260
|
h
|
|
6788
7261
|
)) }),
|
|
6789
|
-
/* @__PURE__ */ jsx("div", { className: "flex-1 overflow-x-auto scrollbar-none", "data-week-scroll": true, children: /* @__PURE__ */ jsx(
|
|
7262
|
+
/* @__PURE__ */ jsx("div", { className: "flex-1 overflow-x-auto gs-scrollbar-none", "data-week-scroll": true, children: /* @__PURE__ */ jsx(
|
|
6790
7263
|
"div",
|
|
6791
7264
|
{
|
|
6792
7265
|
className: "relative",
|
|
@@ -7799,7 +8272,7 @@ function AvatarGroup({ items, max = 4, size = "sm", ring = "canvas", onOverflowC
|
|
|
7799
8272
|
const shown = items.slice(0, Math.max(0, max));
|
|
7800
8273
|
const hidden = items.slice(shown.length);
|
|
7801
8274
|
const ringClass = cn(
|
|
7802
|
-
"rounded-[var(--ds-radius-full)] ring-2",
|
|
8275
|
+
"relative rounded-[var(--ds-radius-full)] ring-2",
|
|
7803
8276
|
ring === "canvas" ? "ring-[var(--ds-bg-canvas)]" : "ring-[var(--ds-bg-surface)]"
|
|
7804
8277
|
);
|
|
7805
8278
|
const hiddenNames = hidden.map((i) => i.name ?? i.initials).filter(Boolean).join(", ");
|
|
@@ -8099,11 +8572,38 @@ function HorizontalLayout({ items, minItemWidth, className }) {
|
|
|
8099
8572
|
/* @__PURE__ */ jsxs("div", { className: "text-center mt-ds-2 px-ds-3", children: [
|
|
8100
8573
|
/* @__PURE__ */ jsx("p", { className: "text-sm font-medium text-[var(--ds-text-primary)]", children: item.title }),
|
|
8101
8574
|
item.description && /* @__PURE__ */ jsx(ExpandableDescription, { className: "text-center", children: item.description }),
|
|
8102
|
-
|
|
8575
|
+
/* @__PURE__ */ jsx(ItemTime, { item })
|
|
8103
8576
|
] })
|
|
8104
8577
|
] }, i);
|
|
8105
8578
|
}) });
|
|
8106
8579
|
}
|
|
8580
|
+
var EXACT = new Intl.DateTimeFormat(void 0, { dateStyle: "medium", timeStyle: "short" });
|
|
8581
|
+
var EXACT_DAY = new Intl.DateTimeFormat(void 0, { dateStyle: "medium" });
|
|
8582
|
+
var DATE_ONLY = /^(\d{4})-(\d{2})-(\d{2})$/;
|
|
8583
|
+
function exactTime(value) {
|
|
8584
|
+
if (typeof value === "string") {
|
|
8585
|
+
const day = DATE_ONLY.exec(value.trim());
|
|
8586
|
+
if (day) {
|
|
8587
|
+
const [y, m, d] = [Number(day[1]), Number(day[2]) - 1, Number(day[3])];
|
|
8588
|
+
const date2 = new Date(y, m, d);
|
|
8589
|
+
return date2.getFullYear() === y && date2.getMonth() === m && date2.getDate() === d ? { iso: value.trim(), text: EXACT_DAY.format(date2) } : null;
|
|
8590
|
+
}
|
|
8591
|
+
}
|
|
8592
|
+
const date = value instanceof Date ? value : new Date(value);
|
|
8593
|
+
return Number.isNaN(date.getTime()) ? null : { iso: date.toISOString(), text: EXACT.format(date) };
|
|
8594
|
+
}
|
|
8595
|
+
function ItemTime({ item }) {
|
|
8596
|
+
const exact = item.dateTime ? exactTime(item.dateTime) : null;
|
|
8597
|
+
if (!item.timestamp && !exact) return null;
|
|
8598
|
+
return /* @__PURE__ */ jsx("p", { className: "text-2xs text-[var(--ds-text-muted)] mt-ds-0.5 tabular-nums", children: exact ? /* @__PURE__ */ jsxs("time", { dateTime: exact.iso, title: exact.text, children: [
|
|
8599
|
+
item.timestamp ?? exact.text,
|
|
8600
|
+
item.timestamp && /* @__PURE__ */ jsxs("span", { className: "sr-only", children: [
|
|
8601
|
+
" (",
|
|
8602
|
+
exact.text,
|
|
8603
|
+
")"
|
|
8604
|
+
] })
|
|
8605
|
+
] }) : item.timestamp });
|
|
8606
|
+
}
|
|
8107
8607
|
function VerticalLayout({ items, className }) {
|
|
8108
8608
|
return /* @__PURE__ */ jsx("div", { className: cn("relative", className), children: items.map((item, i) => /* @__PURE__ */ jsxs("div", { className: "flex gap-ds-4", children: [
|
|
8109
8609
|
/* @__PURE__ */ jsxs("div", { className: "flex flex-col items-center", children: [
|
|
@@ -8113,7 +8613,7 @@ function VerticalLayout({ items, className }) {
|
|
|
8113
8613
|
/* @__PURE__ */ jsxs("div", { className: cn("pb-ds-6 min-w-0", i === items.length - 1 && "pb-0"), style: item.icon ? { paddingTop: ICON_TEXT_OFFSET } : void 0, children: [
|
|
8114
8614
|
/* @__PURE__ */ jsx("p", { className: "text-sm font-medium text-[var(--ds-text-primary)]", children: item.title }),
|
|
8115
8615
|
item.description && /* @__PURE__ */ jsx(ExpandableDescription, { children: item.description }),
|
|
8116
|
-
|
|
8616
|
+
/* @__PURE__ */ jsx(ItemTime, { item })
|
|
8117
8617
|
] })
|
|
8118
8618
|
] }, i)) });
|
|
8119
8619
|
}
|
|
@@ -8585,6 +9085,7 @@ function Carousel({
|
|
|
8585
9085
|
/* @__PURE__ */ jsx(
|
|
8586
9086
|
"button",
|
|
8587
9087
|
{
|
|
9088
|
+
type: "button",
|
|
8588
9089
|
onClick: prev,
|
|
8589
9090
|
disabled: !canPrev,
|
|
8590
9091
|
"aria-label": "Previous slide",
|
|
@@ -8604,6 +9105,7 @@ function Carousel({
|
|
|
8604
9105
|
/* @__PURE__ */ jsx(
|
|
8605
9106
|
"button",
|
|
8606
9107
|
{
|
|
9108
|
+
type: "button",
|
|
8607
9109
|
onClick: next,
|
|
8608
9110
|
disabled: !canNext,
|
|
8609
9111
|
"aria-label": "Next slide",
|
|
@@ -8624,6 +9126,7 @@ function Carousel({
|
|
|
8624
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(
|
|
8625
9127
|
"button",
|
|
8626
9128
|
{
|
|
9129
|
+
type: "button",
|
|
8627
9130
|
onClick: () => goTo(i),
|
|
8628
9131
|
"aria-label": `Go to slide ${i + 1}`,
|
|
8629
9132
|
className: cn(
|
|
@@ -9496,7 +9999,7 @@ var StackedList = forwardRef(function StackedList2({
|
|
|
9496
9999
|
});
|
|
9497
10000
|
var TIME_ZOOMS = ["day", "week", "month", "quarter"];
|
|
9498
10001
|
var DAY_MS = 864e5;
|
|
9499
|
-
var
|
|
10002
|
+
var DATE_ONLY2 = /^(\d{4})-(\d{2})-(\d{2})$/;
|
|
9500
10003
|
var utcDay = (y, m, d) => Math.round(Date.UTC(y, m, d) / DAY_MS);
|
|
9501
10004
|
function dayOfDate(d) {
|
|
9502
10005
|
const t = d.getTime();
|
|
@@ -9512,7 +10015,7 @@ function dayOf(value) {
|
|
|
9512
10015
|
if (typeof value === "number") return Number.isFinite(value) ? value : NaN;
|
|
9513
10016
|
if (value instanceof Date) return dayOfDate(value);
|
|
9514
10017
|
if (typeof value !== "string") return NaN;
|
|
9515
|
-
const m =
|
|
10018
|
+
const m = DATE_ONLY2.exec(value.trim());
|
|
9516
10019
|
if (!m) return dayOfDate(new Date(value));
|
|
9517
10020
|
const [y, mo, d] = [Number(m[1]), Number(m[2]) - 1, Number(m[3])];
|
|
9518
10021
|
const day = utcDay(y, mo, d);
|
|
@@ -9525,7 +10028,7 @@ function dateOfDay(day) {
|
|
|
9525
10028
|
return new Date(u.getUTCFullYear(), u.getUTCMonth(), u.getUTCDate(), 0, 0, 0, Math.round((day - whole) * DAY_MS));
|
|
9526
10029
|
}
|
|
9527
10030
|
function isWholeDay(value) {
|
|
9528
|
-
return typeof value === "string" ?
|
|
10031
|
+
return typeof value === "string" ? DATE_ONLY2.test(value.trim()) : Number.isInteger(dayOf(value));
|
|
9529
10032
|
}
|
|
9530
10033
|
function endDayOf(value) {
|
|
9531
10034
|
const day = dayOf(value);
|
|
@@ -11372,6 +11875,7 @@ function TabButton({
|
|
|
11372
11875
|
const btn2 = /* @__PURE__ */ jsxs(
|
|
11373
11876
|
"button",
|
|
11374
11877
|
{
|
|
11878
|
+
type: "button",
|
|
11375
11879
|
id: tabId,
|
|
11376
11880
|
role: "tab",
|
|
11377
11881
|
"aria-selected": isActive,
|
|
@@ -11407,6 +11911,7 @@ function TabButton({
|
|
|
11407
11911
|
const btn = /* @__PURE__ */ jsx(
|
|
11408
11912
|
"button",
|
|
11409
11913
|
{
|
|
11914
|
+
type: "button",
|
|
11410
11915
|
id: tabId,
|
|
11411
11916
|
role: "tab",
|
|
11412
11917
|
"aria-selected": isActive,
|
|
@@ -11780,6 +12285,7 @@ var Breadcrumbs = forwardRef(function Breadcrumbs2({
|
|
|
11780
12285
|
/* @__PURE__ */ jsx(
|
|
11781
12286
|
"button",
|
|
11782
12287
|
{
|
|
12288
|
+
type: "button",
|
|
11783
12289
|
ref: ellipsisBtnRef,
|
|
11784
12290
|
onClick: () => {
|
|
11785
12291
|
if (!dropdownOpen) setActiveIdx(0);
|
|
@@ -11830,6 +12336,7 @@ var Breadcrumbs = forwardRef(function Breadcrumbs2({
|
|
|
11830
12336
|
children: collapsedItems.map((ci, idx) => /* @__PURE__ */ jsxs(
|
|
11831
12337
|
"button",
|
|
11832
12338
|
{
|
|
12339
|
+
type: "button",
|
|
11833
12340
|
"data-index": idx,
|
|
11834
12341
|
role: "menuitem",
|
|
11835
12342
|
tabIndex: idx === activeIdx ? 0 : -1,
|
|
@@ -12025,6 +12532,7 @@ function PageNumbers({ currentPage, totalPages, onPageChange, pageSize: pageSize
|
|
|
12025
12532
|
/* @__PURE__ */ jsx(
|
|
12026
12533
|
"button",
|
|
12027
12534
|
{
|
|
12535
|
+
type: "button",
|
|
12028
12536
|
onClick: () => onPageChange(currentPage - 1),
|
|
12029
12537
|
disabled: currentPage <= 1,
|
|
12030
12538
|
"aria-label": "Previous page",
|
|
@@ -12044,6 +12552,7 @@ function PageNumbers({ currentPage, totalPages, onPageChange, pageSize: pageSize
|
|
|
12044
12552
|
(p, i) => p === "..." ? /* @__PURE__ */ jsx(EllipsisJumper, { totalPages, onPageChange }, `ellipsis-${i}`) : /* @__PURE__ */ jsx(
|
|
12045
12553
|
"button",
|
|
12046
12554
|
{
|
|
12555
|
+
type: "button",
|
|
12047
12556
|
onClick: () => onPageChange(p),
|
|
12048
12557
|
"aria-current": p === currentPage ? "page" : void 0,
|
|
12049
12558
|
className: cn(
|
|
@@ -12061,6 +12570,7 @@ function PageNumbers({ currentPage, totalPages, onPageChange, pageSize: pageSize
|
|
|
12061
12570
|
/* @__PURE__ */ jsx(
|
|
12062
12571
|
"button",
|
|
12063
12572
|
{
|
|
12573
|
+
type: "button",
|
|
12064
12574
|
onClick: () => onPageChange(currentPage + 1),
|
|
12065
12575
|
disabled: currentPage >= totalPages,
|
|
12066
12576
|
"aria-label": "Next page",
|
|
@@ -12323,6 +12833,7 @@ function StepCircle({ status, index, onClick, clickable }) {
|
|
|
12323
12833
|
return /* @__PURE__ */ jsx(
|
|
12324
12834
|
"button",
|
|
12325
12835
|
{
|
|
12836
|
+
type: "button",
|
|
12326
12837
|
onClick,
|
|
12327
12838
|
disabled: !clickable,
|
|
12328
12839
|
"aria-current": status === "current" ? "step" : void 0,
|
|
@@ -12517,7 +13028,7 @@ var Sidebar = forwardRef(function Sidebar2({
|
|
|
12517
13028
|
position = "flush",
|
|
12518
13029
|
navbarFloating: navbarFloatingProp,
|
|
12519
13030
|
navSize = "md",
|
|
12520
|
-
fill = false,
|
|
13031
|
+
fill: fill2 = false,
|
|
12521
13032
|
className
|
|
12522
13033
|
}, ref) {
|
|
12523
13034
|
const [internalCollapsed, setInternalCollapsed] = useState(defaultCollapsed ?? false);
|
|
@@ -12527,10 +13038,10 @@ var Sidebar = forwardRef(function Sidebar2({
|
|
|
12527
13038
|
const appShell = useAppShell();
|
|
12528
13039
|
const navbarFloating = navbarFloatingProp ?? appShell?.navbarFloating;
|
|
12529
13040
|
useLayoutEffect(() => {
|
|
12530
|
-
if (
|
|
13041
|
+
if (fill2 || !appShell) return;
|
|
12531
13042
|
return appShell.registerChrome("sidebar", position);
|
|
12532
|
-
}, [appShell?.registerChrome,
|
|
12533
|
-
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";
|
|
12534
13045
|
const uncontrolledCollapsed = usesShellState ? appShell.sidebarCollapsed : internalCollapsed;
|
|
12535
13046
|
const collapsed = mini || (isControlled ? controlledCollapsed : uncontrolledCollapsed);
|
|
12536
13047
|
const handleCollapsedChange = (value) => {
|
|
@@ -12549,11 +13060,11 @@ var Sidebar = forwardRef(function Sidebar2({
|
|
|
12549
13060
|
effectiveDarkMode = false;
|
|
12550
13061
|
}
|
|
12551
13062
|
const isDark = effectiveDarkMode ?? variant === "dark";
|
|
12552
|
-
const showCollapse = type === "traditional" && !mini && !
|
|
13063
|
+
const showCollapse = type === "traditional" && !mini && !fill2;
|
|
12553
13064
|
const isMinimal = type === "minimal";
|
|
12554
13065
|
const isCompact = type === "compact";
|
|
12555
|
-
const isFloating = position === "floating" && !
|
|
12556
|
-
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)";
|
|
12557
13068
|
const aside = /* @__PURE__ */ jsxs(
|
|
12558
13069
|
"aside",
|
|
12559
13070
|
{
|
|
@@ -12591,6 +13102,7 @@ var Sidebar = forwardRef(function Sidebar2({
|
|
|
12591
13102
|
const collapseButton = /* @__PURE__ */ jsxs(
|
|
12592
13103
|
"button",
|
|
12593
13104
|
{
|
|
13105
|
+
type: "button",
|
|
12594
13106
|
onClick: () => handleCollapsedChange(!collapsed),
|
|
12595
13107
|
"aria-expanded": !collapsed,
|
|
12596
13108
|
"aria-label": collapsed ? "Expand sidebar" : "Collapse sidebar",
|
|
@@ -12943,6 +13455,7 @@ function SidebarNav({
|
|
|
12943
13455
|
/* @__PURE__ */ jsxs(
|
|
12944
13456
|
"button",
|
|
12945
13457
|
{
|
|
13458
|
+
type: "button",
|
|
12946
13459
|
onClick: () => {
|
|
12947
13460
|
toggleExpand(key);
|
|
12948
13461
|
onItemClick?.(item, index);
|
|
@@ -13077,6 +13590,7 @@ function SidebarNav({
|
|
|
13077
13590
|
collapsible && /* @__PURE__ */ jsxs(
|
|
13078
13591
|
"button",
|
|
13079
13592
|
{
|
|
13593
|
+
type: "button",
|
|
13080
13594
|
onClick: () => onCollapsedChange(!collapsed),
|
|
13081
13595
|
title: collapsed ? "Expand sidebar" : "Collapse sidebar",
|
|
13082
13596
|
className: cn(
|
|
@@ -13143,6 +13657,7 @@ function CompactNavItem({
|
|
|
13143
13657
|
/* @__PURE__ */ jsxs(
|
|
13144
13658
|
"button",
|
|
13145
13659
|
{
|
|
13660
|
+
type: "button",
|
|
13146
13661
|
ref: setTriggerEl,
|
|
13147
13662
|
onMouseEnter: !mobile && hasChildren ? handleMouseEnter : void 0,
|
|
13148
13663
|
onMouseLeave: !mobile && hasChildren && isOpen ? handleMouseLeave : void 0,
|
|
@@ -13205,6 +13720,7 @@ function CompactNavItem({
|
|
|
13205
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(
|
|
13206
13721
|
"button",
|
|
13207
13722
|
{
|
|
13723
|
+
type: "button",
|
|
13208
13724
|
onClick: () => onItemClick?.(child, ci),
|
|
13209
13725
|
className: cn(
|
|
13210
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",
|
|
@@ -13219,7 +13735,473 @@ function CompactNavItem({
|
|
|
13219
13735
|
)) })
|
|
13220
13736
|
] });
|
|
13221
13737
|
}
|
|
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]);
|
|
13792
|
+
useEffect(() => {
|
|
13793
|
+
if (!visible) return;
|
|
13794
|
+
remaining.current = total;
|
|
13795
|
+
if (timer.current) {
|
|
13796
|
+
clearTimeout(timer.current);
|
|
13797
|
+
timer.current = void 0;
|
|
13798
|
+
}
|
|
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
|
+
}
|
|
13222
14202
|
function BottomNav({ items, onItemClick, maxVisible = 5, className, ref }) {
|
|
14203
|
+
const registerWithToasts = useContext(BottomNavPresenceCtx);
|
|
14204
|
+
useEffect(() => registerWithToasts?.(), [registerWithToasts]);
|
|
13223
14205
|
const needsOverflow = items.length > maxVisible;
|
|
13224
14206
|
const visibleItems = needsOverflow ? items.slice(0, maxVisible - 1) : items;
|
|
13225
14207
|
const overflowItems = needsOverflow ? items.slice(maxVisible - 1) : [];
|
|
@@ -13254,6 +14236,7 @@ function BottomNav({ items, onItemClick, maxVisible = 5, className, ref }) {
|
|
|
13254
14236
|
/* @__PURE__ */ jsxs(
|
|
13255
14237
|
"button",
|
|
13256
14238
|
{
|
|
14239
|
+
type: "button",
|
|
13257
14240
|
onClick: () => setOverflowOpen(!overflowOpen),
|
|
13258
14241
|
"aria-expanded": overflowOpen,
|
|
13259
14242
|
"aria-haspopup": "true",
|
|
@@ -13281,6 +14264,7 @@ function BottomNav({ items, onItemClick, maxVisible = 5, className, ref }) {
|
|
|
13281
14264
|
children: overflowItems.map((item, i) => /* @__PURE__ */ jsxs(
|
|
13282
14265
|
"button",
|
|
13283
14266
|
{
|
|
14267
|
+
type: "button",
|
|
13284
14268
|
role: "menuitem",
|
|
13285
14269
|
onClick: () => {
|
|
13286
14270
|
onItemClick?.(item, maxVisible - 1 + i);
|
|
@@ -13310,6 +14294,7 @@ function NavButton({ item, onClick }) {
|
|
|
13310
14294
|
return /* @__PURE__ */ jsxs(
|
|
13311
14295
|
"button",
|
|
13312
14296
|
{
|
|
14297
|
+
type: "button",
|
|
13313
14298
|
onClick,
|
|
13314
14299
|
className: cn(
|
|
13315
14300
|
"flex flex-col items-center justify-center gap-ds-0.5 flex-1 h-full",
|
|
@@ -14712,6 +15697,7 @@ function NavMenu({
|
|
|
14712
15697
|
/* @__PURE__ */ jsxs(
|
|
14713
15698
|
"button",
|
|
14714
15699
|
{
|
|
15700
|
+
type: "button",
|
|
14715
15701
|
ref: triggerRef,
|
|
14716
15702
|
onClick: () => setOpen(!open),
|
|
14717
15703
|
"aria-expanded": open,
|
|
@@ -14908,7 +15894,8 @@ var sizeClasses = {
|
|
|
14908
15894
|
full: "max-w-[calc(100vw-2rem)]"
|
|
14909
15895
|
};
|
|
14910
15896
|
function Dialog({ open, onClose: onCloseProp, title, description, children, footer, variant = "default", size = "md", alert = false, container, onSubmit, dirty, onDiscard }) {
|
|
14911
|
-
const
|
|
15897
|
+
const { marked, mark } = useOverlayMark(open);
|
|
15898
|
+
const guard = useDirtyGuard(dirty ?? marked, onCloseProp, onDiscard);
|
|
14912
15899
|
const onClose = guard.requestClose;
|
|
14913
15900
|
const titleId = useId();
|
|
14914
15901
|
const descriptionId = useId();
|
|
@@ -15013,7 +16000,8 @@ function Dialog({ open, onClose: onCloseProp, title, description, children, foot
|
|
|
15013
16000
|
className: cn(
|
|
15014
16001
|
"relative z-10 w-full",
|
|
15015
16002
|
isMobile ? "max-w-none h-full" : sizeClasses[size],
|
|
15016
|
-
|
|
16003
|
+
OVERLAY_SURFACE,
|
|
16004
|
+
"text-[var(--ds-text-primary)]",
|
|
15017
16005
|
GLASS_OVERLAY,
|
|
15018
16006
|
"border-[length:var(--ds-border-width)] border-[var(--ds-border-default)]",
|
|
15019
16007
|
isMobile ? "rounded-none" : "rounded-[var(--ds-radius-xl)]",
|
|
@@ -15044,7 +16032,7 @@ function Dialog({ open, onClose: onCloseProp, title, description, children, foot
|
|
|
15044
16032
|
}
|
|
15045
16033
|
),
|
|
15046
16034
|
description && /* @__PURE__ */ jsx("p", { id: descriptionId, className: "mt-ds-2 text-sm text-[var(--ds-text-muted)]", children: description }),
|
|
15047
|
-
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 }) }) })
|
|
15048
16036
|
] })
|
|
15049
16037
|
] }) }),
|
|
15050
16038
|
/* @__PURE__ */ jsx(DiscardConfirm, { open: guard.confirming, onKeep: guard.keep, onDiscard: guard.discard }),
|
|
@@ -15070,6 +16058,7 @@ function HamburgerButton({ onClick, open, className: cls }) {
|
|
|
15070
16058
|
return /* @__PURE__ */ jsx(
|
|
15071
16059
|
"button",
|
|
15072
16060
|
{
|
|
16061
|
+
type: "button",
|
|
15073
16062
|
onClick,
|
|
15074
16063
|
"aria-label": open ? "Close navigation menu" : "Open navigation menu",
|
|
15075
16064
|
"aria-expanded": open ?? void 0,
|
|
@@ -15372,6 +16361,7 @@ function MobileMenuItem({
|
|
|
15372
16361
|
return /* @__PURE__ */ jsxs(
|
|
15373
16362
|
"button",
|
|
15374
16363
|
{
|
|
16364
|
+
type: "button",
|
|
15375
16365
|
onClick,
|
|
15376
16366
|
className: cn(
|
|
15377
16367
|
"flex items-center gap-ds-3 px-ds-3 py-ds-3 text-sm relative cursor-pointer w-full text-left",
|
|
@@ -15396,6 +16386,7 @@ function MobileMenuItem({
|
|
|
15396
16386
|
return /* @__PURE__ */ jsxs(
|
|
15397
16387
|
"button",
|
|
15398
16388
|
{
|
|
16389
|
+
type: "button",
|
|
15399
16390
|
onClick,
|
|
15400
16391
|
className: cn(
|
|
15401
16392
|
"flex items-center gap-ds-3 px-ds-3 py-ds-2.5 text-sm cursor-pointer w-full text-left",
|
|
@@ -15413,6 +16404,7 @@ function MobileMenuItem({
|
|
|
15413
16404
|
return /* @__PURE__ */ jsxs(
|
|
15414
16405
|
"button",
|
|
15415
16406
|
{
|
|
16407
|
+
type: "button",
|
|
15416
16408
|
onClick,
|
|
15417
16409
|
className: cn(
|
|
15418
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",
|
|
@@ -15429,6 +16421,7 @@ function MobileMenuItem({
|
|
|
15429
16421
|
return /* @__PURE__ */ jsxs(
|
|
15430
16422
|
"button",
|
|
15431
16423
|
{
|
|
16424
|
+
type: "button",
|
|
15432
16425
|
onClick,
|
|
15433
16426
|
className: cn(
|
|
15434
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",
|
|
@@ -15532,7 +16525,8 @@ function CommandPalette({ open, onOpenChange, commands, placeholder = "Type a co
|
|
|
15532
16525
|
"aria-label": "Command palette",
|
|
15533
16526
|
className: cn(
|
|
15534
16527
|
"relative z-10 w-full max-w-lg",
|
|
15535
|
-
|
|
16528
|
+
OVERLAY_SURFACE,
|
|
16529
|
+
"text-[var(--ds-text-primary)]",
|
|
15536
16530
|
"[backdrop-filter:var(--ds-glass-filter)] [-webkit-backdrop-filter:var(--ds-glass-filter)]",
|
|
15537
16531
|
"border-[length:var(--ds-border-width)] border-[var(--ds-border-default)]",
|
|
15538
16532
|
"rounded-[var(--ds-radius-xl)] overflow-hidden",
|
|
@@ -15589,6 +16583,7 @@ function CommandPalette({ open, onOpenChange, commands, placeholder = "Type a co
|
|
|
15589
16583
|
return /* @__PURE__ */ jsxs(
|
|
15590
16584
|
"button",
|
|
15591
16585
|
{
|
|
16586
|
+
type: "button",
|
|
15592
16587
|
id: `${listboxId}-opt-${myIdx}`,
|
|
15593
16588
|
role: "option",
|
|
15594
16589
|
tabIndex: -1,
|
|
@@ -15777,6 +16772,7 @@ function ContextMenu({ items, children, className, ref, container }) {
|
|
|
15777
16772
|
return /* @__PURE__ */ jsxs(
|
|
15778
16773
|
"button",
|
|
15779
16774
|
{
|
|
16775
|
+
type: "button",
|
|
15780
16776
|
role: "menuitem",
|
|
15781
16777
|
disabled: item.disabled,
|
|
15782
16778
|
onClick: () => {
|
|
@@ -15887,6 +16883,7 @@ function NotificationCenter({
|
|
|
15887
16883
|
/* @__PURE__ */ jsx("div", { className: "flex items-center gap-ds-3", children: unreadCount > 0 && /* @__PURE__ */ jsx(
|
|
15888
16884
|
"button",
|
|
15889
16885
|
{
|
|
16886
|
+
type: "button",
|
|
15890
16887
|
onClick: onMarkAllRead,
|
|
15891
16888
|
className: "text-sm text-[var(--ds-accent-primary)] hover:underline cursor-pointer",
|
|
15892
16889
|
children: "Mark all read"
|
|
@@ -15897,6 +16894,7 @@ function NotificationCenter({
|
|
|
15897
16894
|
/* @__PURE__ */ jsx(
|
|
15898
16895
|
"button",
|
|
15899
16896
|
{
|
|
16897
|
+
type: "button",
|
|
15900
16898
|
onClick: () => setFilter("all"),
|
|
15901
16899
|
className: cn(
|
|
15902
16900
|
"px-ds-3 py-ds-1.5 text-sm rounded-[var(--ds-radius-md)] transition-colors cursor-pointer",
|
|
@@ -15908,6 +16906,7 @@ function NotificationCenter({
|
|
|
15908
16906
|
/* @__PURE__ */ jsxs(
|
|
15909
16907
|
"button",
|
|
15910
16908
|
{
|
|
16909
|
+
type: "button",
|
|
15911
16910
|
onClick: () => setFilter("unread"),
|
|
15912
16911
|
className: cn(
|
|
15913
16912
|
"px-ds-3 py-ds-1.5 text-sm rounded-[var(--ds-radius-md)] transition-colors cursor-pointer",
|
|
@@ -15957,6 +16956,7 @@ function NotificationCenter({
|
|
|
15957
16956
|
!n.read && onMarkRead && /* @__PURE__ */ jsx(
|
|
15958
16957
|
"button",
|
|
15959
16958
|
{
|
|
16959
|
+
type: "button",
|
|
15960
16960
|
onClick: () => onMarkRead(n.id),
|
|
15961
16961
|
"aria-label": "Mark as read",
|
|
15962
16962
|
className: "text-[var(--ds-text-muted)] hover:text-[var(--ds-text-primary)] transition-colors cursor-pointer p-ds-0.5",
|
|
@@ -15966,6 +16966,7 @@ function NotificationCenter({
|
|
|
15966
16966
|
onDismiss && /* @__PURE__ */ jsx(
|
|
15967
16967
|
"button",
|
|
15968
16968
|
{
|
|
16969
|
+
type: "button",
|
|
15969
16970
|
onClick: () => onDismiss(n.id),
|
|
15970
16971
|
"aria-label": "Dismiss",
|
|
15971
16972
|
className: "text-[var(--ds-text-muted)] hover:text-[var(--ds-text-primary)] transition-colors cursor-pointer p-ds-0.5",
|
|
@@ -15984,6 +16985,7 @@ function NotificationCenter({
|
|
|
15984
16985
|
/* @__PURE__ */ jsxs(
|
|
15985
16986
|
"button",
|
|
15986
16987
|
{
|
|
16988
|
+
type: "button",
|
|
15987
16989
|
ref: triggerRef,
|
|
15988
16990
|
onClick: () => setOpen(!open),
|
|
15989
16991
|
"aria-label": `Notifications${unreadCount ? ` (${unreadCount} unread)` : ""}`,
|
|
@@ -16023,6 +17025,7 @@ function NotificationCenter({
|
|
|
16023
17025
|
unreadCount > 0 && /* @__PURE__ */ jsx(
|
|
16024
17026
|
"button",
|
|
16025
17027
|
{
|
|
17028
|
+
type: "button",
|
|
16026
17029
|
onClick: onMarkAllRead,
|
|
16027
17030
|
className: "text-xs text-[var(--ds-accent-primary)] hover:underline cursor-pointer",
|
|
16028
17031
|
children: "Mark all read"
|
|
@@ -16067,6 +17070,7 @@ function NotificationCenter({
|
|
|
16067
17070
|
!n.read && onMarkRead && /* @__PURE__ */ jsx(
|
|
16068
17071
|
"button",
|
|
16069
17072
|
{
|
|
17073
|
+
type: "button",
|
|
16070
17074
|
onClick: () => onMarkRead(n.id),
|
|
16071
17075
|
"aria-label": "Mark as read",
|
|
16072
17076
|
className: "text-[var(--ds-text-muted)] hover:text-[var(--ds-text-primary)] transition-colors cursor-pointer p-ds-0.5",
|
|
@@ -16076,6 +17080,7 @@ function NotificationCenter({
|
|
|
16076
17080
|
onDismiss && /* @__PURE__ */ jsx(
|
|
16077
17081
|
"button",
|
|
16078
17082
|
{
|
|
17083
|
+
type: "button",
|
|
16079
17084
|
onClick: () => onDismiss(n.id),
|
|
16080
17085
|
"aria-label": "Dismiss",
|
|
16081
17086
|
className: "text-[var(--ds-text-muted)] hover:text-[var(--ds-text-primary)] transition-colors cursor-pointer p-ds-0.5",
|
|
@@ -16239,6 +17244,7 @@ function Tour({ steps, open, onClose, onComplete, container }) {
|
|
|
16239
17244
|
/* @__PURE__ */ jsx(
|
|
16240
17245
|
"button",
|
|
16241
17246
|
{
|
|
17247
|
+
type: "button",
|
|
16242
17248
|
onClick: onClose,
|
|
16243
17249
|
className: "shrink-0 text-[var(--ds-text-muted)] hover:text-[var(--ds-text-primary)] transition-colors cursor-pointer -mt-ds-0.5",
|
|
16244
17250
|
"aria-label": "Close tour",
|
|
@@ -16258,6 +17264,7 @@ function Tour({ steps, open, onClose, onComplete, container }) {
|
|
|
16258
17264
|
current > 0 && /* @__PURE__ */ jsx(
|
|
16259
17265
|
"button",
|
|
16260
17266
|
{
|
|
17267
|
+
type: "button",
|
|
16261
17268
|
onClick: handlePrev,
|
|
16262
17269
|
className: cn(
|
|
16263
17270
|
"px-ds-3 py-ds-1.5 text-xs font-medium rounded-[var(--ds-radius-sm)]",
|
|
@@ -16271,6 +17278,7 @@ function Tour({ steps, open, onClose, onComplete, container }) {
|
|
|
16271
17278
|
/* @__PURE__ */ jsx(
|
|
16272
17279
|
"button",
|
|
16273
17280
|
{
|
|
17281
|
+
type: "button",
|
|
16274
17282
|
ref: nextRef,
|
|
16275
17283
|
onClick: handleNext,
|
|
16276
17284
|
className: cn(
|
|
@@ -16319,223 +17327,6 @@ function getPopoverPosition(rect, placement, padding) {
|
|
|
16319
17327
|
top = Math.max(8, Math.min(top, window.innerHeight - popH - 8));
|
|
16320
17328
|
return { top, left };
|
|
16321
17329
|
}
|
|
16322
|
-
var variantStyles4 = {
|
|
16323
|
-
default: "border-[var(--ds-border-default)] bg-[var(--ds-bg-surface)]",
|
|
16324
|
-
success: "border-[var(--ds-status-success)] bg-[var(--ds-status-success-bg)]",
|
|
16325
|
-
warning: "border-[var(--ds-status-warning)] bg-[var(--ds-status-warning-bg)]",
|
|
16326
|
-
error: "border-[var(--ds-status-error)] bg-[var(--ds-status-error-bg)]"
|
|
16327
|
-
};
|
|
16328
|
-
var variantIcons = {
|
|
16329
|
-
default: { name: "info", className: "text-[var(--ds-text-muted)]" },
|
|
16330
|
-
success: { name: "check", className: "text-[var(--ds-status-success)]" },
|
|
16331
|
-
warning: { name: "warning", className: "text-[var(--ds-status-warning)]" },
|
|
16332
|
-
error: { name: "error", className: "text-[var(--ds-status-error)]" }
|
|
16333
|
-
};
|
|
16334
|
-
var TOAST_POSITION_CLASSES = {
|
|
16335
|
-
"top-right": "top-[var(--ds-toast-inset-top)] right-[var(--ds-toast-inset-right)]",
|
|
16336
|
-
"top-left": "top-[var(--ds-toast-inset-top)] left-[var(--ds-toast-inset-left)]",
|
|
16337
|
-
"bottom-right": "bottom-[var(--ds-toast-inset-bottom-right)] right-[var(--ds-toast-inset-right)]",
|
|
16338
|
-
"bottom-left": "bottom-[var(--ds-toast-inset-bottom-left)] left-[var(--ds-toast-inset-left)]",
|
|
16339
|
-
"top-center": "top-[var(--ds-toast-inset-top)] left-1/2 -translate-x-1/2",
|
|
16340
|
-
"bottom-center": "bottom-ds-4 left-1/2 -translate-x-1/2"
|
|
16341
|
-
};
|
|
16342
|
-
function Toast({ variant = "default", message, visible, onDismiss, duration = 5e3, pauseOnHover = false, action, position = "bottom-right", mode, container, inline = false }) {
|
|
16343
|
-
const isMobile = useBreakpoint("sm");
|
|
16344
|
-
const isCentered = position === "top-center" || position === "bottom-center";
|
|
16345
|
-
const timerRef = useRef(void 0);
|
|
16346
|
-
const startedAtRef = useRef(0);
|
|
16347
|
-
const remainingRef = useRef(duration);
|
|
16348
|
-
const onDismissRef = useLatest(onDismiss);
|
|
16349
|
-
const startTimer = useCallback((ms) => {
|
|
16350
|
-
const delay = ms ?? remainingRef.current;
|
|
16351
|
-
remainingRef.current = delay;
|
|
16352
|
-
startedAtRef.current = Date.now();
|
|
16353
|
-
if (!Number.isFinite(delay) || delay <= 0) return;
|
|
16354
|
-
timerRef.current = setTimeout(() => onDismissRef.current(), delay);
|
|
16355
|
-
}, [onDismissRef]);
|
|
16356
|
-
const clearTimer = useCallback(() => {
|
|
16357
|
-
if (timerRef.current) {
|
|
16358
|
-
clearTimeout(timerRef.current);
|
|
16359
|
-
remainingRef.current -= Date.now() - startedAtRef.current;
|
|
16360
|
-
}
|
|
16361
|
-
}, []);
|
|
16362
|
-
useEffect(() => {
|
|
16363
|
-
if (!visible) return;
|
|
16364
|
-
remainingRef.current = duration;
|
|
16365
|
-
startTimer(duration);
|
|
16366
|
-
return () => {
|
|
16367
|
-
if (timerRef.current) clearTimeout(timerRef.current);
|
|
16368
|
-
};
|
|
16369
|
-
}, [visible, duration, startTimer]);
|
|
16370
|
-
const handleMouseEnter = pauseOnHover ? () => {
|
|
16371
|
-
clearTimer();
|
|
16372
|
-
} : void 0;
|
|
16373
|
-
const handleMouseLeave = pauseOnHover ? () => {
|
|
16374
|
-
startTimer();
|
|
16375
|
-
} : void 0;
|
|
16376
|
-
if (!visible) return null;
|
|
16377
|
-
const icon = variantIcons[variant];
|
|
16378
|
-
const card = /* @__PURE__ */ jsxs(
|
|
16379
|
-
"div",
|
|
16380
|
-
{
|
|
16381
|
-
role: variant === "error" ? "alert" : "status",
|
|
16382
|
-
"aria-live": variant === "error" ? "assertive" : "polite",
|
|
16383
|
-
"data-mode": inline ? mode : void 0,
|
|
16384
|
-
onMouseEnter: inline ? handleMouseEnter : void 0,
|
|
16385
|
-
onMouseLeave: inline ? handleMouseLeave : void 0,
|
|
16386
|
-
className: cn(
|
|
16387
|
-
"flex items-center gap-ds-3 px-ds-4 py-ds-3",
|
|
16388
|
-
isCentered ? "min-w-[360px] max-w-[560px]" : "min-w-[280px] max-w-[420px]",
|
|
16389
|
-
"border-[length:var(--ds-border-width)]",
|
|
16390
|
-
GLASS_DROPDOWN,
|
|
16391
|
-
"rounded-[var(--ds-radius-md)]",
|
|
16392
|
-
"text-sm text-[var(--ds-text-primary)]",
|
|
16393
|
-
variantStyles4[variant]
|
|
16394
|
-
),
|
|
16395
|
-
children: [
|
|
16396
|
-
/* @__PURE__ */ jsx(Icon, { name: icon.name, size: 18, className: cn("shrink-0", icon.className) }),
|
|
16397
|
-
/* @__PURE__ */ jsx("span", { className: "flex-1", children: message }),
|
|
16398
|
-
action && /* @__PURE__ */ jsx(
|
|
16399
|
-
"button",
|
|
16400
|
-
{
|
|
16401
|
-
type: "button",
|
|
16402
|
-
onClick: action.onClick,
|
|
16403
|
-
className: "shrink-0 text-xs font-semibold text-[var(--ds-accent-primary)] hover:underline cursor-pointer",
|
|
16404
|
-
children: action.label
|
|
16405
|
-
}
|
|
16406
|
-
),
|
|
16407
|
-
/* @__PURE__ */ jsx(
|
|
16408
|
-
"button",
|
|
16409
|
-
{
|
|
16410
|
-
type: "button",
|
|
16411
|
-
onClick: onDismiss,
|
|
16412
|
-
"aria-label": "Dismiss notification",
|
|
16413
|
-
className: "text-[var(--ds-text-muted)] hover:text-[var(--ds-text-primary)] transition-colors cursor-pointer shrink-0",
|
|
16414
|
-
children: /* @__PURE__ */ jsx(Icon, { name: "close", size: 16 })
|
|
16415
|
-
}
|
|
16416
|
-
)
|
|
16417
|
-
]
|
|
16418
|
-
}
|
|
16419
|
-
);
|
|
16420
|
-
if (inline) return card;
|
|
16421
|
-
return createPortal(
|
|
16422
|
-
/* @__PURE__ */ jsx(
|
|
16423
|
-
"div",
|
|
16424
|
-
{
|
|
16425
|
-
"data-mode": mode,
|
|
16426
|
-
onMouseEnter: handleMouseEnter,
|
|
16427
|
-
onMouseLeave: handleMouseLeave,
|
|
16428
|
-
className: cn(
|
|
16429
|
-
"fixed z-[var(--ds-z-toast)]",
|
|
16430
|
-
isMobile ? "bottom-ds-4 left-ds-4 right-ds-4" : TOAST_POSITION_CLASSES[position]
|
|
16431
|
-
),
|
|
16432
|
-
children: card
|
|
16433
|
-
}
|
|
16434
|
-
),
|
|
16435
|
-
container ?? document.body
|
|
16436
|
-
);
|
|
16437
|
-
}
|
|
16438
|
-
var ToastContext = createContext(null);
|
|
16439
|
-
function useToast() {
|
|
16440
|
-
const ctx = useContext(ToastContext);
|
|
16441
|
-
if (!ctx) {
|
|
16442
|
-
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.");
|
|
16443
|
-
}
|
|
16444
|
-
return ctx;
|
|
16445
|
-
}
|
|
16446
|
-
function useToastOptional() {
|
|
16447
|
-
return useContext(ToastContext);
|
|
16448
|
-
}
|
|
16449
|
-
var toastSeq = 0;
|
|
16450
|
-
function ToastProvider({ children, maxVisible = 1, position = "bottom-right", duration = 5e3, mode, pauseOnHover = true, coalesce = true }) {
|
|
16451
|
-
const [queue, setQueue] = useState([]);
|
|
16452
|
-
const isMobile = useBreakpoint("sm");
|
|
16453
|
-
const dismiss = useCallback((id) => {
|
|
16454
|
-
setQueue((q) => q.filter((t) => t.id !== id));
|
|
16455
|
-
}, []);
|
|
16456
|
-
const dismissAll = useCallback(() => setQueue([]), []);
|
|
16457
|
-
const update = useCallback((id, message, options = {}) => {
|
|
16458
|
-
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));
|
|
16459
|
-
}, []);
|
|
16460
|
-
const toast = useCallback((message, options = {}) => {
|
|
16461
|
-
const id = options.id ?? `toast-${++toastSeq}`;
|
|
16462
|
-
const entry = {
|
|
16463
|
-
id,
|
|
16464
|
-
message,
|
|
16465
|
-
variant: options.variant ?? "default",
|
|
16466
|
-
duration: options.duration ?? duration,
|
|
16467
|
-
action: options.action,
|
|
16468
|
-
key: options.key ?? options.variant ?? "default"
|
|
16469
|
-
};
|
|
16470
|
-
const slots = Math.max(1, maxVisible);
|
|
16471
|
-
setQueue((q) => {
|
|
16472
|
-
if (q.some((t) => t.id === id)) return q.map((t) => t.id === id ? entry : t);
|
|
16473
|
-
if (coalesce && q.length >= slots) {
|
|
16474
|
-
const waiting = q.findIndex((t, i) => i >= slots && t.key === entry.key);
|
|
16475
|
-
if (waiting >= 0) {
|
|
16476
|
-
const next = [...q];
|
|
16477
|
-
next[waiting] = entry;
|
|
16478
|
-
return next;
|
|
16479
|
-
}
|
|
16480
|
-
}
|
|
16481
|
-
return [...q, entry];
|
|
16482
|
-
});
|
|
16483
|
-
return id;
|
|
16484
|
-
}, [duration, maxVisible, coalesce]);
|
|
16485
|
-
const api = useMemo(() => ({
|
|
16486
|
-
toast,
|
|
16487
|
-
success: (m, o) => toast(m, { ...o, variant: "success" }),
|
|
16488
|
-
warning: (m, o) => toast(m, { ...o, variant: "warning" }),
|
|
16489
|
-
error: (m, o) => toast(m, { ...o, variant: "error" }),
|
|
16490
|
-
update,
|
|
16491
|
-
dismiss,
|
|
16492
|
-
dismissAll,
|
|
16493
|
-
promise: async (promise, messages, options = {}) => {
|
|
16494
|
-
const id = toast(messages.loading, { ...options, variant: "default", duration: Infinity });
|
|
16495
|
-
try {
|
|
16496
|
-
const value = await promise;
|
|
16497
|
-
update(id, typeof messages.success === "function" ? messages.success(value) : messages.success, { variant: "success", duration });
|
|
16498
|
-
return value;
|
|
16499
|
-
} catch (err) {
|
|
16500
|
-
update(id, typeof messages.error === "function" ? messages.error(err) : messages.error, { variant: "error", duration });
|
|
16501
|
-
throw err;
|
|
16502
|
-
}
|
|
16503
|
-
}
|
|
16504
|
-
}), [toast, update, dismiss, dismissAll, duration]);
|
|
16505
|
-
const visible = queue.slice(0, Math.max(1, maxVisible));
|
|
16506
|
-
const isTop = position.startsWith("top");
|
|
16507
|
-
return /* @__PURE__ */ jsxs(ToastContext.Provider, { value: api, children: [
|
|
16508
|
-
children,
|
|
16509
|
-
visible.length > 0 && createPortal(
|
|
16510
|
-
/* @__PURE__ */ jsx(
|
|
16511
|
-
"div",
|
|
16512
|
-
{
|
|
16513
|
-
"data-mode": mode,
|
|
16514
|
-
className: cn(
|
|
16515
|
-
"fixed z-[var(--ds-z-toast)] flex gap-ds-2 pointer-events-none",
|
|
16516
|
-
isTop ? "flex-col" : "flex-col-reverse",
|
|
16517
|
-
isMobile ? "bottom-ds-4 left-ds-4 right-ds-4" : TOAST_POSITION_CLASSES[position]
|
|
16518
|
-
),
|
|
16519
|
-
children: visible.map((t) => /* @__PURE__ */ jsx("div", { className: "pointer-events-auto", children: /* @__PURE__ */ jsx(
|
|
16520
|
-
Toast,
|
|
16521
|
-
{
|
|
16522
|
-
inline: true,
|
|
16523
|
-
visible: true,
|
|
16524
|
-
variant: t.variant,
|
|
16525
|
-
message: t.message,
|
|
16526
|
-
duration: t.duration,
|
|
16527
|
-
pauseOnHover,
|
|
16528
|
-
action: t.action,
|
|
16529
|
-
mode,
|
|
16530
|
-
onDismiss: () => dismiss(t.id)
|
|
16531
|
-
}
|
|
16532
|
-
) }, t.id))
|
|
16533
|
-
}
|
|
16534
|
-
),
|
|
16535
|
-
document.body
|
|
16536
|
-
)
|
|
16537
|
-
] });
|
|
16538
|
-
}
|
|
16539
17330
|
function firstKey(item) {
|
|
16540
17331
|
if (item !== null && typeof item === "object") return "id" in item ? item.id : void 0;
|
|
16541
17332
|
return item;
|
|
@@ -16598,9 +17389,10 @@ function usePagination(list, options = {}) {
|
|
|
16598
17389
|
};
|
|
16599
17390
|
}
|
|
16600
17391
|
function useDestructiveAction(options) {
|
|
16601
|
-
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;
|
|
16602
17393
|
const preferences = useShellPreferences();
|
|
16603
17394
|
const toast = useToastOptional();
|
|
17395
|
+
const ledger = useContext(ToastLedgerCtx);
|
|
16604
17396
|
const [open, setOpen] = useState(false);
|
|
16605
17397
|
const [typed, setTyped] = useState("");
|
|
16606
17398
|
const [busy, setBusy] = useState(false);
|
|
@@ -16617,20 +17409,32 @@ function useDestructiveAction(options) {
|
|
|
16617
17409
|
setTyped("");
|
|
16618
17410
|
};
|
|
16619
17411
|
const failureMessage = (err) => err instanceof Error && err.message ? err.message : `${title.replace(/\?$/, "")} failed. Try again.`;
|
|
17412
|
+
const done = doneMessage ?? undoMessage ?? pastTenseOf(label);
|
|
16620
17413
|
const confirm = async () => {
|
|
16621
17414
|
setBusy(true);
|
|
17415
|
+
const before = ledger?.created() ?? 0;
|
|
16622
17416
|
try {
|
|
16623
17417
|
await onConfirm();
|
|
16624
17418
|
close();
|
|
17419
|
+
if (toast && (ledger?.created() ?? 0) === before) toast.success(done);
|
|
16625
17420
|
} catch (err) {
|
|
16626
17421
|
toast?.error(failureMessage(err));
|
|
16627
17422
|
} finally {
|
|
16628
17423
|
setBusy(false);
|
|
16629
17424
|
}
|
|
16630
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
|
+
};
|
|
16631
17434
|
const run = () => {
|
|
16632
17435
|
if (undoable) {
|
|
16633
17436
|
void (async () => {
|
|
17437
|
+
const before = ledger?.created() ?? 0;
|
|
16634
17438
|
try {
|
|
16635
17439
|
await onConfirm();
|
|
16636
17440
|
} catch (err) {
|
|
@@ -16638,7 +17442,10 @@ function useDestructiveAction(options) {
|
|
|
16638
17442
|
return;
|
|
16639
17443
|
}
|
|
16640
17444
|
const seconds = preferences.undoWindowSeconds ?? 5;
|
|
16641
|
-
|
|
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 });
|
|
16642
17449
|
})();
|
|
16643
17450
|
return;
|
|
16644
17451
|
}
|
|
@@ -16666,6 +17473,61 @@ function useDestructiveAction(options) {
|
|
|
16666
17473
|
) : null;
|
|
16667
17474
|
return { run, element, open };
|
|
16668
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
|
+
}
|
|
16669
17531
|
var SectionHeading = forwardRef(function SectionHeading2({
|
|
16670
17532
|
title,
|
|
16671
17533
|
description,
|
|
@@ -16806,6 +17668,6 @@ var TextOverflow = forwardRef(function TextOverflow2({
|
|
|
16806
17668
|
return /* @__PURE__ */ jsx(Tooltip, { content: resolvedTooltipContent, children: content });
|
|
16807
17669
|
});
|
|
16808
17670
|
|
|
16809
|
-
export { Accordion, ActionPanel, ActionPanelGroup, Alert, AsidePanel, Avatar, AvatarGroup, BottomNav, Breadcrumbs, BulkActionBar, Calendar, Card, CardContent, CardDescription, CardFooter, 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 };
|
|
16810
17672
|
//# sourceMappingURL=index.js.map
|
|
16811
17673
|
//# sourceMappingURL=index.js.map
|