gridsmith-ui 0.20.0 → 0.22.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/chat.js +3 -3
- package/dist/chunk-2RV23OBK.js +1349 -0
- package/dist/chunk-2RV23OBK.js.map +1 -0
- package/dist/chunk-7TOJ4G7S.js +197 -0
- package/dist/chunk-7TOJ4G7S.js.map +1 -0
- package/dist/{chunk-6MXHGH3D.js → chunk-AAYCQXZQ.js} +90 -161
- package/dist/chunk-AAYCQXZQ.js.map +1 -0
- package/dist/{chunk-ILIODA7W.js → chunk-CXMV7SXJ.js} +4 -3
- package/dist/chunk-CXMV7SXJ.js.map +1 -0
- package/dist/{chunk-EQDR57AM.js → chunk-EYMGLK4M.js} +3 -3
- package/dist/{chunk-EQDR57AM.js.map → chunk-EYMGLK4M.js.map} +1 -1
- package/dist/chunk-IVCVNAXG.js +115 -0
- package/dist/chunk-IVCVNAXG.js.map +1 -0
- package/dist/chunk-RG4KUCRS.js +9 -0
- package/dist/chunk-RG4KUCRS.js.map +1 -0
- package/dist/{chunk-JXANCXK6.js → chunk-RT7RYGC3.js} +39 -4
- package/dist/chunk-RT7RYGC3.js.map +1 -0
- package/dist/{chunk-XYDIBW3J.js → chunk-SBTBMAIU.js} +4 -3
- package/dist/chunk-SBTBMAIU.js.map +1 -0
- package/dist/data-grid.d.ts +38 -4
- package/dist/data-grid.js +304 -264
- package/dist/data-grid.js.map +1 -1
- package/dist/editor.d.ts +6 -5
- package/dist/editor.js +47 -11
- package/dist/editor.js.map +1 -1
- package/dist/index.d.ts +120 -153
- package/dist/index.js +1156 -1814
- package/dist/index.js.map +1 -1
- package/dist/kanban.js +2 -2
- package/dist/resizable.js +9 -8
- package/dist/resizable.js.map +1 -1
- package/dist/roots.css +10 -0
- package/dist/{table-utils-GounRE6s.d.ts → table-utils-BkjNEWts.d.ts} +5 -1
- package/dist/use-pagination-DiJo0aW5.d.ts +153 -0
- package/dist/virtualized.d.ts +11 -1
- package/dist/virtualized.js +67 -18
- package/dist/virtualized.js.map +1 -1
- package/package.json +1 -1
- package/dist/chunk-6MXHGH3D.js.map +0 -1
- package/dist/chunk-ILIODA7W.js.map +0 -1
- package/dist/chunk-JN37OVTP.js +0 -67
- package/dist/chunk-JN37OVTP.js.map +0 -1
- package/dist/chunk-JXANCXK6.js.map +0 -1
- package/dist/chunk-TKVTZWBN.js +0 -50
- package/dist/chunk-TKVTZWBN.js.map +0 -1
- package/dist/chunk-XVB55M3N.js +0 -42
- package/dist/chunk-XVB55M3N.js.map +0 -1
- package/dist/chunk-XYDIBW3J.js.map +0 -1
package/dist/index.js
CHANGED
|
@@ -1,27 +1,28 @@
|
|
|
1
|
-
import {
|
|
2
|
-
export { AppShell,
|
|
1
|
+
import { useAppShell, REACT_VERSION_PROBLEM, useOverlayMark, useDirtyGuard, OverlayMarkScope, OverlayCloseCtx, DiscardConfirm, OVERLAY_ROOT_ATTR, OverlayMarkCtx, DrawerFooterCtx, useCompact, useElementWidth, Sheet, useCloseSettle, Drawer, useRememberedWidth, pxOf, ResizeEdge, defaultMaxWidth } from './chunk-AAYCQXZQ.js';
|
|
2
|
+
export { AppShell, Drawer, Sheet, SkipLink, useAppShell, useUnsavedChanges } from './chunk-AAYCQXZQ.js';
|
|
3
3
|
import { Skeleton, TITLE_TEXT } from './chunk-NCIZQYXQ.js';
|
|
4
4
|
export { Skeleton } from './chunk-NCIZQYXQ.js';
|
|
5
|
-
import {
|
|
6
|
-
export {
|
|
7
|
-
import {
|
|
8
|
-
export {
|
|
9
|
-
import {
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
import {
|
|
14
|
-
|
|
15
|
-
export { PreferencesContext, preferenceActionKey, usePreferences } from './chunk-TKVTZWBN.js';
|
|
5
|
+
import { Link } from './chunk-EYMGLK4M.js';
|
|
6
|
+
export { CodeBlock, Divider, Link } from './chunk-EYMGLK4M.js';
|
|
7
|
+
import { Badge } from './chunk-SBTBMAIU.js';
|
|
8
|
+
export { Badge } from './chunk-SBTBMAIU.js';
|
|
9
|
+
import { inferColumnKinds, useCardsSwitch, CARDS_BELOW, kindOfRenderedText, CardValue } from './chunk-IVCVNAXG.js';
|
|
10
|
+
import { useWholeListCheck, pagerPart, Pagination, Dropdown, useFieldControl, useField, warnOnce, Label, InlineFieldError, AddAnotherRowCtx, Input, Field } from './chunk-2RV23OBK.js';
|
|
11
|
+
export { Dropdown, Field, InlineFieldError, Input, Label, NumberInput, Pagination, Popover, Textarea, Toggle, usePagination } from './chunk-2RV23OBK.js';
|
|
12
|
+
import { SplitPaneCtx, TableCardCtx } from './chunk-RG4KUCRS.js';
|
|
13
|
+
import { Button, ControlSizeContext, triggerType, Spinner, useShellPreferences, preferenceActionKey } from './chunk-7TOJ4G7S.js';
|
|
14
|
+
export { Button, ButtonSizeContext, ControlSizeContext, PreferencesContext, Spinner, preferenceActionKey, usePreferences } from './chunk-7TOJ4G7S.js';
|
|
16
15
|
import { useBreakpoint, readBreakpointPx } from './chunk-CRQ6KCRD.js';
|
|
17
16
|
export { BreakpointWidthProvider, useBreakpoint } from './chunk-CRQ6KCRD.js';
|
|
18
|
-
import {
|
|
19
|
-
export {
|
|
17
|
+
import { FOCUSABLE, usePopupFocus, FIELD, ZOOM_KEYS, FormChangeCtx, useOverlayLayer, useFocusTrap, useFocusBeforeOpen, rememberFocus, focusInitial, OVERLAY_CLOSE_ATTR, useReportedChange, rovingTabStop, useGridKeyboard, useOptionalFormContext, focusAfterRemoval, FormCtx, useNonModalDialog, useReturnFocus, useCloseOnFocusOut } from './chunk-RT7RYGC3.js';
|
|
18
|
+
export { useFormContext, useGridKeyboard } from './chunk-RT7RYGC3.js';
|
|
19
|
+
import { useTextOverflow, Tooltip, usePosition } from './chunk-CXMV7SXJ.js';
|
|
20
|
+
export { Tooltip, useTextOverflow } from './chunk-CXMV7SXJ.js';
|
|
20
21
|
import { mergeRefs, Slot } from './chunk-7Q46JXSK.js';
|
|
21
22
|
import { useLatest } from './chunk-WH2FUFAC.js';
|
|
22
23
|
import { Icon } from './chunk-4LDYR7QP.js';
|
|
23
|
-
import { cn, GLASS_SURFACE, GLASS_BACKDROP, GLASS_DROPDOWN, lockBodyScroll, unlockBodyScroll, OVERLAY_SURFACE, GLASS_OVERLAY,
|
|
24
|
-
import { createContext, forwardRef, useState, useRef, useCallback, useLayoutEffect, useMemo, useContext,
|
|
24
|
+
import { cn, GLASS_SURFACE, GLASS_BACKDROP, GLASS_DROPDOWN, lockBodyScroll, unlockBodyScroll, OVERLAY_SURFACE, GLASS_OVERLAY, ERROR_HAS_FOCUS_RING, HAS_FOCUS_RING, ACTIVE_RING, ERROR_ACTIVE_RING, ERROR_FOCUS_RING, FOCUS_RING, FOCUS_WITHIN_RING } from './chunk-M2QRNBDQ.js';
|
|
25
|
+
import { createContext, forwardRef, useState, useRef, useCallback, useLayoutEffect, useMemo, useContext, isValidElement, useId, memo, useEffect, useImperativeHandle, Children, Fragment as Fragment$1, cloneElement, useSyncExternalStore } from 'react';
|
|
25
26
|
import { createPortal, flushSync } from 'react-dom';
|
|
26
27
|
import { jsxs, jsx, Fragment } from 'react/jsx-runtime';
|
|
27
28
|
|
|
@@ -84,6 +85,9 @@ function DropdownMenu({ trigger, items, align = "end", className, container }) {
|
|
|
84
85
|
/* @__PURE__ */ jsx(
|
|
85
86
|
Slot,
|
|
86
87
|
{
|
|
88
|
+
...triggerType(trigger),
|
|
89
|
+
"aria-haspopup": "menu",
|
|
90
|
+
"aria-expanded": open,
|
|
87
91
|
ref: triggerRef,
|
|
88
92
|
onClick: () => {
|
|
89
93
|
setOpen(!open);
|
|
@@ -180,13 +184,14 @@ function BulkActionBar({ selectedCount, actions, onClearSelection, className })
|
|
|
180
184
|
isMobile ? /* @__PURE__ */ jsx(
|
|
181
185
|
DropdownMenu,
|
|
182
186
|
{
|
|
183
|
-
trigger: /* @__PURE__ */ jsx(Button, { variant: "secondary", size: "sm", iconLeft: /* @__PURE__ */ jsx(Icon, { name: "more-vertical", size: 14 }), children: "Actions" }),
|
|
187
|
+
trigger: /* @__PURE__ */ jsx(Button, { type: "button", variant: "secondary", size: "sm", iconLeft: /* @__PURE__ */ jsx(Icon, { name: "more-vertical", size: 14 }), children: "Actions" }),
|
|
184
188
|
items: dropdownItems,
|
|
185
189
|
align: "start"
|
|
186
190
|
}
|
|
187
191
|
) : /* @__PURE__ */ jsx("div", { className: "flex items-center gap-ds-2", children: actions.map((action, i) => /* @__PURE__ */ jsx(
|
|
188
192
|
Button,
|
|
189
193
|
{
|
|
194
|
+
type: "button",
|
|
190
195
|
variant: "secondary",
|
|
191
196
|
size: "sm",
|
|
192
197
|
onClick: action.onClick,
|
|
@@ -208,732 +213,6 @@ function BulkActionBar({ selectedCount, actions, onClearSelection, className })
|
|
|
208
213
|
}
|
|
209
214
|
);
|
|
210
215
|
}
|
|
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
|
-
};
|
|
216
|
-
var INPUT_HEIGHT = {
|
|
217
|
-
sm: "h-[var(--ds-control-height-sm)]",
|
|
218
|
-
md: "h-[var(--ds-control-height-md)]",
|
|
219
|
-
lg: "h-[var(--ds-control-height-lg)]"
|
|
220
|
-
};
|
|
221
|
-
var INPUT_TEXT = {
|
|
222
|
-
sm: "px-ds-2 py-ds-1 text-xs",
|
|
223
|
-
md: "px-ds-3 py-ds-2 text-sm",
|
|
224
|
-
lg: "px-ds-4 py-ds-3 text-base"
|
|
225
|
-
};
|
|
226
|
-
function Input({ className, size: sizeProp, error = false, prefix, suffix, ...props }) {
|
|
227
|
-
const contextSize = useContext(ControlSizeContext);
|
|
228
|
-
const size = sizeProp ?? contextSize ?? "md";
|
|
229
|
-
const onChange = useReportedChange(props.onChange, props.value, valueOf);
|
|
230
|
-
const borderColor = error ? "border-[var(--ds-status-error)]" : "border-[var(--ds-input-border)]";
|
|
231
|
-
const hoverBorder = !error && !props.disabled && !props.readOnly ? "hover:border-[var(--ds-input-border-hover)]" : "";
|
|
232
|
-
if (prefix || suffix) {
|
|
233
|
-
return /* @__PURE__ */ jsxs(
|
|
234
|
-
"div",
|
|
235
|
-
{
|
|
236
|
-
className: cn(
|
|
237
|
-
"flex items-center w-full",
|
|
238
|
-
INPUT_HEIGHT[size],
|
|
239
|
-
"bg-[var(--ds-input-bg)]",
|
|
240
|
-
"border-[length:var(--ds-border-width)]",
|
|
241
|
-
borderColor,
|
|
242
|
-
"rounded-[var(--ds-radius-md)]",
|
|
243
|
-
"shadow-[var(--ds-input-shadow)]",
|
|
244
|
-
hoverBorder,
|
|
245
|
-
error ? ERROR_HAS_FOCUS_RING : HAS_FOCUS_RING,
|
|
246
|
-
"transition-colors duration-[var(--ds-transition-speed)]",
|
|
247
|
-
props.disabled && "cursor-not-allowed opacity-disabled",
|
|
248
|
-
props.readOnly && "bg-[var(--ds-bg-muted)] cursor-default",
|
|
249
|
-
className
|
|
250
|
-
),
|
|
251
|
-
children: [
|
|
252
|
-
prefix && /* @__PURE__ */ jsx("span", { className: "shrink-0 pl-ds-3 text-[var(--ds-text-muted)] flex items-center", children: prefix }),
|
|
253
|
-
/* @__PURE__ */ jsx(
|
|
254
|
-
"input",
|
|
255
|
-
{
|
|
256
|
-
"aria-invalid": error || void 0,
|
|
257
|
-
className: cn(
|
|
258
|
-
"flex-1 min-w-0 bg-transparent outline-none",
|
|
259
|
-
INPUT_TEXT[size],
|
|
260
|
-
"text-[var(--ds-text-primary)]",
|
|
261
|
-
"placeholder:text-[var(--ds-text-muted)]",
|
|
262
|
-
"disabled:cursor-not-allowed",
|
|
263
|
-
"read-only:text-[var(--ds-text-secondary)] read-only:cursor-default"
|
|
264
|
-
),
|
|
265
|
-
...props,
|
|
266
|
-
onChange: props.onChange || props.value === void 0 ? onChange : void 0
|
|
267
|
-
}
|
|
268
|
-
),
|
|
269
|
-
suffix && /* @__PURE__ */ jsx("span", { className: "shrink-0 pr-ds-3 text-[var(--ds-text-muted)] flex items-center", children: suffix })
|
|
270
|
-
]
|
|
271
|
-
}
|
|
272
|
-
);
|
|
273
|
-
}
|
|
274
|
-
return /* @__PURE__ */ jsx(
|
|
275
|
-
"input",
|
|
276
|
-
{
|
|
277
|
-
"aria-invalid": error || void 0,
|
|
278
|
-
className: cn(
|
|
279
|
-
"flex w-full",
|
|
280
|
-
INPUT_TEXT[size],
|
|
281
|
-
INPUT_HEIGHT[size],
|
|
282
|
-
"bg-[var(--ds-input-bg)] text-[var(--ds-text-primary)]",
|
|
283
|
-
"border-[length:var(--ds-border-width)]",
|
|
284
|
-
borderColor,
|
|
285
|
-
"rounded-[var(--ds-radius-md)]",
|
|
286
|
-
"shadow-[var(--ds-input-shadow)]",
|
|
287
|
-
"placeholder:text-[var(--ds-text-muted)]",
|
|
288
|
-
hoverBorder,
|
|
289
|
-
error ? ERROR_FOCUS_RING : FOCUS_RING,
|
|
290
|
-
"disabled:cursor-not-allowed disabled:opacity-disabled",
|
|
291
|
-
"read-only:bg-[var(--ds-bg-muted)] read-only:text-[var(--ds-text-secondary)] read-only:cursor-default",
|
|
292
|
-
"transition-colors duration-[var(--ds-transition-speed)]",
|
|
293
|
-
className
|
|
294
|
-
),
|
|
295
|
-
...props,
|
|
296
|
-
onChange: props.onChange || props.value === void 0 ? onChange : void 0
|
|
297
|
-
}
|
|
298
|
-
);
|
|
299
|
-
}
|
|
300
|
-
function Textarea({ className, autoResize, maxRows, error = false, ref, ...props }) {
|
|
301
|
-
const onChange = useReportedChange(props.onChange, props.value, valueOf);
|
|
302
|
-
const internalRef = useRef(null);
|
|
303
|
-
const textareaRef = ref ?? internalRef;
|
|
304
|
-
const resize = useCallback(() => {
|
|
305
|
-
const el = textareaRef.current;
|
|
306
|
-
if (!el || !autoResize) return;
|
|
307
|
-
el.style.height = "auto";
|
|
308
|
-
let target = el.scrollHeight;
|
|
309
|
-
if (maxRows) {
|
|
310
|
-
const lineHeight = parseFloat(getComputedStyle(el).lineHeight) || 20;
|
|
311
|
-
const maxHeight = lineHeight * maxRows + parseFloat(getComputedStyle(el).paddingTop) + parseFloat(getComputedStyle(el).paddingBottom);
|
|
312
|
-
target = Math.min(target, maxHeight);
|
|
313
|
-
}
|
|
314
|
-
el.style.height = `${target}px`;
|
|
315
|
-
}, [autoResize, maxRows, textareaRef]);
|
|
316
|
-
useEffect(() => {
|
|
317
|
-
resize();
|
|
318
|
-
}, [resize, props.value, props.defaultValue]);
|
|
319
|
-
return /* @__PURE__ */ jsx(
|
|
320
|
-
"textarea",
|
|
321
|
-
{
|
|
322
|
-
ref: textareaRef,
|
|
323
|
-
"aria-invalid": error || void 0,
|
|
324
|
-
className: cn(
|
|
325
|
-
"flex min-h-[var(--ds-control-height-md)] w-full px-ds-3 py-ds-2 text-sm",
|
|
326
|
-
"bg-[var(--ds-input-bg)] text-[var(--ds-text-primary)]",
|
|
327
|
-
"border-[length:var(--ds-border-width)]",
|
|
328
|
-
error ? "border-[var(--ds-status-error)]" : "border-[var(--ds-input-border)] hover:border-[var(--ds-input-border-hover)]",
|
|
329
|
-
"rounded-[var(--ds-radius-md)]",
|
|
330
|
-
"shadow-[var(--ds-input-shadow)]",
|
|
331
|
-
"placeholder:text-[var(--ds-text-muted)]",
|
|
332
|
-
error ? ERROR_FOCUS_RING : FOCUS_RING,
|
|
333
|
-
"disabled:cursor-not-allowed disabled:opacity-disabled disabled:hover:border-[var(--ds-input-border)]",
|
|
334
|
-
"read-only:bg-[var(--ds-bg-muted)] read-only:text-[var(--ds-text-secondary)] read-only:cursor-default read-only:hover:border-[var(--ds-input-border)]",
|
|
335
|
-
"transition-colors duration-[var(--ds-transition-speed)]",
|
|
336
|
-
autoResize && "resize-none overflow-hidden",
|
|
337
|
-
className
|
|
338
|
-
),
|
|
339
|
-
onInput: autoResize ? resize : void 0,
|
|
340
|
-
...props,
|
|
341
|
-
onChange: props.onChange || props.value === void 0 ? onChange : void 0
|
|
342
|
-
}
|
|
343
|
-
);
|
|
344
|
-
}
|
|
345
|
-
function Label({ className, children, ...props }) {
|
|
346
|
-
return /* @__PURE__ */ jsx(
|
|
347
|
-
"label",
|
|
348
|
-
{
|
|
349
|
-
className: cn(
|
|
350
|
-
"text-sm font-medium leading-none text-[var(--ds-text-secondary)]",
|
|
351
|
-
"peer-disabled:cursor-not-allowed peer-disabled:opacity-disabled",
|
|
352
|
-
className
|
|
353
|
-
),
|
|
354
|
-
...props,
|
|
355
|
-
children
|
|
356
|
-
}
|
|
357
|
-
);
|
|
358
|
-
}
|
|
359
|
-
var TOGGLE_SIZES = {
|
|
360
|
-
sm: { w: 32, h: 18, thumb: 12 },
|
|
361
|
-
md: { w: 44, h: 24, thumb: 16 }
|
|
362
|
-
};
|
|
363
|
-
function Toggle({ checked, onChange, label, disabled, error = false, layout = "full", size = "md", "aria-labelledby": ariaLabelledBy, ...rest }) {
|
|
364
|
-
const change = useReportedChange(onChange, checked);
|
|
365
|
-
const dims = TOGGLE_SIZES[size];
|
|
366
|
-
const travel = dims.w - dims.thumb - 3;
|
|
367
|
-
const switchButton = /* @__PURE__ */ jsx(
|
|
368
|
-
"button",
|
|
369
|
-
{
|
|
370
|
-
type: "button",
|
|
371
|
-
role: "switch",
|
|
372
|
-
"aria-checked": checked,
|
|
373
|
-
"aria-label": !label && !ariaLabelledBy ? "Toggle" : void 0,
|
|
374
|
-
"aria-labelledby": ariaLabelledBy,
|
|
375
|
-
"aria-invalid": error || void 0,
|
|
376
|
-
disabled,
|
|
377
|
-
onClick: () => !disabled && change(!checked),
|
|
378
|
-
...rest,
|
|
379
|
-
className: cn(
|
|
380
|
-
"relative inline-flex shrink-0 items-center overflow-hidden",
|
|
381
|
-
"border-[length:var(--ds-border-width)]",
|
|
382
|
-
"rounded-[var(--ds-radius-full)]",
|
|
383
|
-
"transition-colors duration-[var(--ds-transition-speed)]",
|
|
384
|
-
"focus-visible:outline-none focus-visible:shadow-[var(--ds-shadow-focus)]",
|
|
385
|
-
disabled ? "cursor-not-allowed" : "cursor-pointer",
|
|
386
|
-
checked ? "bg-[var(--ds-accent-primary)]" : "bg-[var(--ds-bg-muted)]",
|
|
387
|
-
error ? "border-[var(--ds-status-error)]" : checked ? "border-transparent" : "border-[var(--ds-border-default)]"
|
|
388
|
-
),
|
|
389
|
-
style: { width: dims.w, height: dims.h },
|
|
390
|
-
children: /* @__PURE__ */ jsx(
|
|
391
|
-
"span",
|
|
392
|
-
{
|
|
393
|
-
className: cn(
|
|
394
|
-
"pointer-events-none inline-block shrink-0",
|
|
395
|
-
"bg-[var(--ds-bg-surface)]",
|
|
396
|
-
"border-[length:var(--ds-border-width)] border-transparent",
|
|
397
|
-
"rounded-[var(--ds-radius-full)]",
|
|
398
|
-
"transition-transform"
|
|
399
|
-
),
|
|
400
|
-
style: {
|
|
401
|
-
width: dims.thumb,
|
|
402
|
-
height: dims.thumb,
|
|
403
|
-
transform: checked ? `translateX(calc(${travel}px - var(--ds-border-width)))` : "translateX(calc(1px + var(--ds-border-width)))"
|
|
404
|
-
}
|
|
405
|
-
}
|
|
406
|
-
)
|
|
407
|
-
}
|
|
408
|
-
);
|
|
409
|
-
if (!label) {
|
|
410
|
-
return /* @__PURE__ */ jsx("div", { className: cn(disabled && "opacity-disabled"), children: switchButton });
|
|
411
|
-
}
|
|
412
|
-
return /* @__PURE__ */ jsxs(
|
|
413
|
-
"label",
|
|
414
|
-
{
|
|
415
|
-
className: cn(
|
|
416
|
-
layout === "full" ? "flex items-center justify-between gap-ds-4" : "inline-flex items-center gap-ds-3",
|
|
417
|
-
disabled ? "cursor-not-allowed opacity-disabled" : "cursor-pointer"
|
|
418
|
-
),
|
|
419
|
-
children: [
|
|
420
|
-
/* @__PURE__ */ jsx("span", { className: "text-sm font-medium text-[var(--ds-text-primary)]", children: label }),
|
|
421
|
-
switchButton
|
|
422
|
-
]
|
|
423
|
-
}
|
|
424
|
-
);
|
|
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
|
-
}
|
|
569
|
-
var DROPDOWN_HEIGHT = {
|
|
570
|
-
sm: "px-ds-2 py-ds-1 text-xs h-[var(--ds-control-height-sm)]",
|
|
571
|
-
md: "px-ds-3 py-ds-2 text-sm h-[var(--ds-control-height-md)]",
|
|
572
|
-
lg: "px-ds-4 py-ds-3 text-base h-[var(--ds-control-height-lg)]"
|
|
573
|
-
};
|
|
574
|
-
function Dropdown({
|
|
575
|
-
options,
|
|
576
|
-
value,
|
|
577
|
-
onChange: onChangeProp,
|
|
578
|
-
label,
|
|
579
|
-
disabled,
|
|
580
|
-
placeholder = "Select...",
|
|
581
|
-
multiple,
|
|
582
|
-
searchable,
|
|
583
|
-
size: sizeProp,
|
|
584
|
-
className,
|
|
585
|
-
ref,
|
|
586
|
-
container,
|
|
587
|
-
error = false,
|
|
588
|
-
showChips = true,
|
|
589
|
-
"aria-label": ariaLabel,
|
|
590
|
-
...wiring
|
|
591
|
-
}) {
|
|
592
|
-
const onChange = useReportedChange(onChangeProp, value);
|
|
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;
|
|
600
|
-
const size = sizeProp ?? contextSize ?? "md";
|
|
601
|
-
const [open, setOpen] = useState(false);
|
|
602
|
-
const [search, setSearch] = useState("");
|
|
603
|
-
const [positioned, setPositioned] = useState(false);
|
|
604
|
-
const triggerRef = useRef(null);
|
|
605
|
-
const menuRef = useRef(null);
|
|
606
|
-
const searchRef = useRef(null);
|
|
607
|
-
const [pos, setPos] = useState({ top: 0, left: 0, width: 0 });
|
|
608
|
-
const selectedValues = Array.isArray(value) ? value : [value].filter(Boolean);
|
|
609
|
-
const updatePos = useCallback(() => {
|
|
610
|
-
if (!triggerRef.current) return;
|
|
611
|
-
const rect = triggerRef.current.getBoundingClientRect();
|
|
612
|
-
let top = rect.bottom + 4;
|
|
613
|
-
let left = rect.left;
|
|
614
|
-
const width = rect.width;
|
|
615
|
-
if (menuRef.current) {
|
|
616
|
-
const menuRect = menuRef.current.getBoundingClientRect();
|
|
617
|
-
const vw = window.innerWidth;
|
|
618
|
-
const vh = window.innerHeight;
|
|
619
|
-
if (left + menuRect.width > vw) left = Math.max(0, vw - menuRect.width - 8);
|
|
620
|
-
if (top + menuRect.height > vh) {
|
|
621
|
-
const above = rect.top - 4 - menuRect.height;
|
|
622
|
-
if (above >= 0) top = above;
|
|
623
|
-
else top = Math.max(0, vh - menuRect.height - 8);
|
|
624
|
-
}
|
|
625
|
-
}
|
|
626
|
-
setPos({ top, left, width });
|
|
627
|
-
}, []);
|
|
628
|
-
const [prevOpen, setPrevOpen] = useState(open);
|
|
629
|
-
if (open !== prevOpen) {
|
|
630
|
-
setPrevOpen(open);
|
|
631
|
-
if (open) setSearch("");
|
|
632
|
-
else setPositioned(false);
|
|
633
|
-
}
|
|
634
|
-
useEffect(() => {
|
|
635
|
-
if (!open) return;
|
|
636
|
-
updatePos();
|
|
637
|
-
const raf = requestAnimationFrame(() => {
|
|
638
|
-
updatePos();
|
|
639
|
-
setPositioned(true);
|
|
640
|
-
});
|
|
641
|
-
const onScroll = () => updatePos();
|
|
642
|
-
window.addEventListener("scroll", onScroll, true);
|
|
643
|
-
window.addEventListener("resize", updatePos);
|
|
644
|
-
return () => {
|
|
645
|
-
cancelAnimationFrame(raf);
|
|
646
|
-
window.removeEventListener("scroll", onScroll, true);
|
|
647
|
-
window.removeEventListener("resize", updatePos);
|
|
648
|
-
};
|
|
649
|
-
}, [open, updatePos]);
|
|
650
|
-
const moved = useRef(false);
|
|
651
|
-
useLayoutEffect(() => {
|
|
652
|
-
if (!open || !positioned) return;
|
|
653
|
-
moved.current = false;
|
|
654
|
-
if (searchRef.current) {
|
|
655
|
-
searchRef.current.focus();
|
|
656
|
-
return;
|
|
657
|
-
}
|
|
658
|
-
const els = Array.from(menuRef.current?.querySelectorAll('[role="option"]') ?? []);
|
|
659
|
-
(els.find((el) => el.getAttribute("aria-selected") === "true") ?? els[0])?.focus();
|
|
660
|
-
}, [open, positioned]);
|
|
661
|
-
useEffect(() => {
|
|
662
|
-
if (!open) return;
|
|
663
|
-
const handler = (e) => {
|
|
664
|
-
const target = e.target;
|
|
665
|
-
if (triggerRef.current?.contains(target) || menuRef.current?.contains(target)) return;
|
|
666
|
-
setOpen(false);
|
|
667
|
-
};
|
|
668
|
-
document.addEventListener("mousedown", handler);
|
|
669
|
-
return () => document.removeEventListener("mousedown", handler);
|
|
670
|
-
}, [open]);
|
|
671
|
-
const commitMoved = () => {
|
|
672
|
-
if (multiple || !moved.current) return;
|
|
673
|
-
const el = document.activeElement;
|
|
674
|
-
const id = el instanceof HTMLElement && menuRef.current?.contains(el) ? el.getAttribute("data-option-id") : null;
|
|
675
|
-
if (id) onChange(id);
|
|
676
|
-
};
|
|
677
|
-
const { isTop: isTopLayer, returnFocus } = usePopupFocus(open, { trigger: triggerRef, panel: menuRef, close: () => setOpen(false), tabExits: "any", onTabOut: commitMoved });
|
|
678
|
-
const typeahead = useRef({ buffer: "", at: 0 });
|
|
679
|
-
useEffect(() => {
|
|
680
|
-
if (!open) return;
|
|
681
|
-
const optionButtons = () => Array.from(menuRef.current?.querySelectorAll('[role="option"]') ?? []);
|
|
682
|
-
const focusOption = (idx) => {
|
|
683
|
-
const els = optionButtons();
|
|
684
|
-
if (els.length === 0) return;
|
|
685
|
-
els[(idx % els.length + els.length) % els.length].focus();
|
|
686
|
-
moved.current = true;
|
|
687
|
-
};
|
|
688
|
-
const onKey = (e) => {
|
|
689
|
-
const inMenu = menuRef.current?.contains(document.activeElement) || triggerRef.current === document.activeElement;
|
|
690
|
-
if (!inMenu) return;
|
|
691
|
-
const els = optionButtons();
|
|
692
|
-
const current = els.findIndex((el) => el === document.activeElement);
|
|
693
|
-
if (e.key === "Escape") {
|
|
694
|
-
if (e.defaultPrevented || !isTopLayer()) return;
|
|
695
|
-
e.preventDefault();
|
|
696
|
-
returnFocus();
|
|
697
|
-
setOpen(false);
|
|
698
|
-
return;
|
|
699
|
-
}
|
|
700
|
-
if (e.key === "ArrowDown") {
|
|
701
|
-
e.preventDefault();
|
|
702
|
-
focusOption(current < 0 ? 0 : current + 1);
|
|
703
|
-
return;
|
|
704
|
-
}
|
|
705
|
-
if (e.key === "ArrowUp") {
|
|
706
|
-
e.preventDefault();
|
|
707
|
-
focusOption(current < 0 ? els.length - 1 : current - 1);
|
|
708
|
-
return;
|
|
709
|
-
}
|
|
710
|
-
const inSearch = document.activeElement === searchRef.current;
|
|
711
|
-
if (e.key === "Home" && !inSearch) {
|
|
712
|
-
e.preventDefault();
|
|
713
|
-
focusOption(0);
|
|
714
|
-
return;
|
|
715
|
-
}
|
|
716
|
-
if (e.key === "End" && !inSearch) {
|
|
717
|
-
e.preventDefault();
|
|
718
|
-
focusOption(els.length - 1);
|
|
719
|
-
return;
|
|
720
|
-
}
|
|
721
|
-
if (!searchable && e.key.length === 1 && !e.metaKey && !e.ctrlKey && !e.altKey) {
|
|
722
|
-
const now = Date.now();
|
|
723
|
-
typeahead.current.buffer = now - typeahead.current.at > 700 ? e.key : typeahead.current.buffer + e.key;
|
|
724
|
-
typeahead.current.at = now;
|
|
725
|
-
const q = typeahead.current.buffer.toLowerCase();
|
|
726
|
-
const hit = els.findIndex((el) => (el.textContent ?? "").trim().toLowerCase().startsWith(q));
|
|
727
|
-
if (hit >= 0) {
|
|
728
|
-
e.preventDefault();
|
|
729
|
-
focusOption(hit);
|
|
730
|
-
}
|
|
731
|
-
}
|
|
732
|
-
};
|
|
733
|
-
document.addEventListener("keydown", onKey);
|
|
734
|
-
return () => document.removeEventListener("keydown", onKey);
|
|
735
|
-
}, [open, searchable, isTopLayer, returnFocus]);
|
|
736
|
-
const filtered = searchable && search ? options.filter((o) => o.label.toLowerCase().includes(search.toLowerCase())) : options;
|
|
737
|
-
const groups = /* @__PURE__ */ new Map();
|
|
738
|
-
for (const opt of filtered) {
|
|
739
|
-
const g = opt.group ?? "";
|
|
740
|
-
if (!groups.has(g)) groups.set(g, []);
|
|
741
|
-
groups.get(g).push(opt);
|
|
742
|
-
}
|
|
743
|
-
const hasGroups = Array.from(groups.keys()).some((k) => k !== "");
|
|
744
|
-
const handleSelect = (id) => {
|
|
745
|
-
if (multiple) {
|
|
746
|
-
const arr = selectedValues.includes(id) ? selectedValues.filter((v) => v !== id) : [...selectedValues, id];
|
|
747
|
-
onChange(arr);
|
|
748
|
-
} else {
|
|
749
|
-
returnFocus();
|
|
750
|
-
onChange(id);
|
|
751
|
-
setOpen(false);
|
|
752
|
-
}
|
|
753
|
-
};
|
|
754
|
-
const chipsRef = useRef(null);
|
|
755
|
-
const pendingChipFocus = useRef(null);
|
|
756
|
-
useLayoutEffect(() => {
|
|
757
|
-
const pending = pendingChipFocus.current;
|
|
758
|
-
if (pending === null) return;
|
|
759
|
-
pendingChipFocus.current = null;
|
|
760
|
-
if (selectedValues.includes(pending.value)) return;
|
|
761
|
-
const chips = Array.from(chipsRef.current?.querySelectorAll("[data-chip-remove]") ?? []);
|
|
762
|
-
focusAfterRemoval(chips, pending.index, triggerRef.current);
|
|
763
|
-
});
|
|
764
|
-
const displayLabel = multiple ? selectedValues.length > 0 ? `${selectedValues.length} selected` : placeholder : options.find((o) => o.id === selectedValues[0])?.label ?? placeholder;
|
|
765
|
-
const { ref: overflowRef, isTruncated } = useTextOverflow({ lines: 1, content: displayLabel });
|
|
766
|
-
return /* @__PURE__ */ jsxs("div", { ref, className: cn("relative", className), children: [
|
|
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,
|
|
769
|
-
/* @__PURE__ */ jsxs(
|
|
770
|
-
"button",
|
|
771
|
-
{
|
|
772
|
-
ref: triggerRef,
|
|
773
|
-
id: triggerId,
|
|
774
|
-
type: "button",
|
|
775
|
-
onClick: () => !disabled && setOpen(!open),
|
|
776
|
-
onKeyDown: (e) => {
|
|
777
|
-
if (disabled || open) return;
|
|
778
|
-
if (e.key === "ArrowDown" || e.key === "ArrowUp") {
|
|
779
|
-
e.preventDefault();
|
|
780
|
-
setOpen(true);
|
|
781
|
-
}
|
|
782
|
-
},
|
|
783
|
-
disabled,
|
|
784
|
-
"aria-invalid": invalid || void 0,
|
|
785
|
-
"aria-haspopup": "listbox",
|
|
786
|
-
"aria-expanded": open,
|
|
787
|
-
"aria-label": labelledBy ? void 0 : ariaLabel,
|
|
788
|
-
"aria-labelledby": labelledBy,
|
|
789
|
-
"aria-describedby": control.describedBy,
|
|
790
|
-
className: cn(
|
|
791
|
-
"w-full flex items-center justify-between gap-ds-2",
|
|
792
|
-
DROPDOWN_HEIGHT[size],
|
|
793
|
-
"bg-[var(--ds-input-bg)] text-[var(--ds-text-primary)]",
|
|
794
|
-
"border-[length:var(--ds-border-width)]",
|
|
795
|
-
invalid ? "border-[var(--ds-status-error)]" : "border-[var(--ds-input-border)]",
|
|
796
|
-
"rounded-[var(--ds-radius-md)]",
|
|
797
|
-
"shadow-[var(--ds-input-shadow)]",
|
|
798
|
-
"transition-colors",
|
|
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,
|
|
802
|
-
"cursor-pointer disabled:cursor-not-allowed disabled:opacity-disabled",
|
|
803
|
-
!selectedValues.length && "text-[var(--ds-text-muted)]"
|
|
804
|
-
),
|
|
805
|
-
children: [
|
|
806
|
-
isTruncated ? /* @__PURE__ */ jsx(Tooltip, { content: displayLabel, children: /* @__PURE__ */ jsx("span", { ref: overflowRef, className: "truncate", children: displayLabel }) }) : /* @__PURE__ */ jsx("span", { ref: overflowRef, className: "truncate", children: displayLabel }),
|
|
807
|
-
/* @__PURE__ */ jsx("span", { className: cn("transition-transform", open && "rotate-180"), children: /* @__PURE__ */ jsx(Icon, { name: "chevron-right", size: 14, className: "rotate-90" }) })
|
|
808
|
-
]
|
|
809
|
-
}
|
|
810
|
-
),
|
|
811
|
-
open && createPortal(
|
|
812
|
-
/* @__PURE__ */ jsxs(
|
|
813
|
-
"div",
|
|
814
|
-
{
|
|
815
|
-
ref: menuRef,
|
|
816
|
-
tabIndex: -1,
|
|
817
|
-
onClick: (e) => e.stopPropagation(),
|
|
818
|
-
className: cn(
|
|
819
|
-
"fixed z-[var(--ds-z-popover)] outline-none",
|
|
820
|
-
"bg-[var(--ds-bg-surface-elevated)]",
|
|
821
|
-
"[backdrop-filter:var(--ds-glass-filter)] [-webkit-backdrop-filter:var(--ds-glass-filter)]",
|
|
822
|
-
"border-[length:var(--ds-border-width)] border-[var(--ds-border-default)]",
|
|
823
|
-
"rounded-[var(--ds-radius-md)] overflow-hidden",
|
|
824
|
-
"shadow-[var(--ds-shadow-dropdown),var(--ds-glass-inset)]"
|
|
825
|
-
),
|
|
826
|
-
style: { top: pos.top, left: pos.left, minWidth: pos.width, width: "max-content", maxWidth: "calc(100vw - 16px)", visibility: positioned ? "visible" : "hidden" },
|
|
827
|
-
children: [
|
|
828
|
-
searchable && /* @__PURE__ */ jsx("div", { className: "border-b-[length:var(--ds-border-width)] border-[var(--ds-border-subtle)]", style: { padding: "var(--ds-space-2)" }, children: /* @__PURE__ */ jsx(
|
|
829
|
-
"input",
|
|
830
|
-
{
|
|
831
|
-
ref: searchRef,
|
|
832
|
-
type: "text",
|
|
833
|
-
value: search,
|
|
834
|
-
onChange: (e) => setSearch(e.target.value),
|
|
835
|
-
placeholder: "Search\u2026",
|
|
836
|
-
className: cn("w-full bg-transparent text-[var(--ds-text-primary)] placeholder:text-[var(--ds-text-muted)] outline-none", size === "sm" ? "text-xs" : "text-sm")
|
|
837
|
-
}
|
|
838
|
-
) }),
|
|
839
|
-
/* @__PURE__ */ jsx("div", { role: "listbox", className: "overflow-y-auto", style: { padding: "var(--ds-space-1)", maxHeight: "var(--ds-dropdown-max-height)" }, children: filtered.length === 0 ? /* @__PURE__ */ jsx("p", { className: cn("text-[var(--ds-text-muted)] text-center py-ds-4", size === "sm" ? "text-xs" : "text-sm"), children: "No options found" }) : hasGroups ? Array.from(groups.entries()).map(([group, opts]) => /* @__PURE__ */ jsxs("div", { children: [
|
|
840
|
-
group && /* @__PURE__ */ jsx("p", { className: "text-2xs font-medium uppercase tracking-wider text-[var(--ds-text-muted)] px-ds-2 pt-ds-2 pb-ds-1", children: group }),
|
|
841
|
-
opts.map((opt) => /* @__PURE__ */ jsx(
|
|
842
|
-
OptionButton,
|
|
843
|
-
{
|
|
844
|
-
opt,
|
|
845
|
-
isSelected: selectedValues.includes(opt.id),
|
|
846
|
-
multiple,
|
|
847
|
-
onSelect: handleSelect,
|
|
848
|
-
size
|
|
849
|
-
},
|
|
850
|
-
opt.id
|
|
851
|
-
))
|
|
852
|
-
] }, group)) : filtered.map((opt) => /* @__PURE__ */ jsx(
|
|
853
|
-
OptionButton,
|
|
854
|
-
{
|
|
855
|
-
opt,
|
|
856
|
-
isSelected: selectedValues.includes(opt.id),
|
|
857
|
-
multiple,
|
|
858
|
-
onSelect: handleSelect,
|
|
859
|
-
size
|
|
860
|
-
},
|
|
861
|
-
opt.id
|
|
862
|
-
)) })
|
|
863
|
-
]
|
|
864
|
-
}
|
|
865
|
-
),
|
|
866
|
-
container ?? document.body
|
|
867
|
-
),
|
|
868
|
-
multiple && showChips && selectedValues.length > 0 && /* @__PURE__ */ jsx("div", { ref: chipsRef, className: "flex flex-wrap gap-ds-1 mt-ds-1.5", children: selectedValues.map((v, i) => {
|
|
869
|
-
const opt = options.find((o) => o.id === v);
|
|
870
|
-
return opt ? /* @__PURE__ */ jsxs(
|
|
871
|
-
"span",
|
|
872
|
-
{
|
|
873
|
-
className: "inline-flex items-center gap-ds-1 text-xs rounded-[var(--ds-radius-sm)] bg-[var(--ds-bg-muted)] text-[var(--ds-text-secondary)] px-ds-1.5 py-ds-0.5",
|
|
874
|
-
children: [
|
|
875
|
-
opt.label,
|
|
876
|
-
/* @__PURE__ */ jsx(
|
|
877
|
-
"button",
|
|
878
|
-
{
|
|
879
|
-
type: "button",
|
|
880
|
-
"data-chip-remove": "",
|
|
881
|
-
onClick: () => {
|
|
882
|
-
pendingChipFocus.current = { index: i, value: v };
|
|
883
|
-
handleSelect(v);
|
|
884
|
-
},
|
|
885
|
-
className: "hover:text-[var(--ds-text-primary)] cursor-pointer",
|
|
886
|
-
"aria-label": `Remove ${opt.label}`,
|
|
887
|
-
children: /* @__PURE__ */ jsx(Icon, { name: "close", size: 10 })
|
|
888
|
-
}
|
|
889
|
-
)
|
|
890
|
-
]
|
|
891
|
-
},
|
|
892
|
-
v
|
|
893
|
-
) : null;
|
|
894
|
-
}) })
|
|
895
|
-
] });
|
|
896
|
-
}
|
|
897
|
-
function OptionButton({
|
|
898
|
-
opt,
|
|
899
|
-
isSelected,
|
|
900
|
-
multiple,
|
|
901
|
-
onSelect,
|
|
902
|
-
size = "md"
|
|
903
|
-
}) {
|
|
904
|
-
return /* @__PURE__ */ jsxs(
|
|
905
|
-
"button",
|
|
906
|
-
{
|
|
907
|
-
type: "button",
|
|
908
|
-
role: "option",
|
|
909
|
-
"data-option-id": opt.id,
|
|
910
|
-
"aria-selected": isSelected,
|
|
911
|
-
tabIndex: -1,
|
|
912
|
-
onClick: () => onSelect(opt.id),
|
|
913
|
-
className: cn(
|
|
914
|
-
"w-full text-left cursor-pointer rounded-[var(--ds-radius-sm)]",
|
|
915
|
-
"transition-colors flex items-center gap-ds-2",
|
|
916
|
-
"focus-visible:outline-none focus-visible:shadow-[var(--ds-shadow-focus)]",
|
|
917
|
-
size === "sm" ? "px-ds-2 py-ds-1 text-xs" : "px-ds-2 py-ds-1.5 text-sm",
|
|
918
|
-
isSelected && !multiple ? "bg-[var(--ds-accent-primary)] text-[var(--ds-text-on-primary)]" : "text-[var(--ds-text-primary)] hover:bg-[var(--ds-bg-emphasis)]"
|
|
919
|
-
),
|
|
920
|
-
children: [
|
|
921
|
-
multiple && /* @__PURE__ */ jsx(
|
|
922
|
-
"span",
|
|
923
|
-
{
|
|
924
|
-
className: cn(
|
|
925
|
-
"w-[var(--ds-icon-size-sm)] h-[var(--ds-icon-size-sm)] rounded-[var(--ds-radius-sm)] border-[length:var(--ds-border-width)] shrink-0 flex items-center justify-center",
|
|
926
|
-
isSelected ? "bg-[var(--ds-accent-primary)] border-[var(--ds-accent-primary)]" : "border-[var(--ds-border-default)]"
|
|
927
|
-
),
|
|
928
|
-
children: isSelected && /* @__PURE__ */ jsx(Icon, { name: "check", size: 10, className: "text-[var(--ds-text-on-primary)]" })
|
|
929
|
-
}
|
|
930
|
-
),
|
|
931
|
-
/* @__PURE__ */ jsx("span", { className: "flex-1", children: opt.label }),
|
|
932
|
-
isSelected && !multiple && /* @__PURE__ */ jsx(Icon, { name: "check", size: size === "sm" ? 12 : 14 })
|
|
933
|
-
]
|
|
934
|
-
}
|
|
935
|
-
);
|
|
936
|
-
}
|
|
937
216
|
var CONTROL_HEIGHT = {
|
|
938
217
|
sm: "h-[var(--ds-control-height-sm)]",
|
|
939
218
|
md: "h-[var(--ds-control-height-md)]",
|
|
@@ -1175,10 +454,11 @@ var CHECKBOX_SIZES = {
|
|
|
1175
454
|
sm: { box: "h-[16px] w-[16px]", glyph: 10, label: "text-xs" },
|
|
1176
455
|
md: { box: "h-[18px] w-[18px]", glyph: 12, label: "text-sm" }
|
|
1177
456
|
};
|
|
1178
|
-
function Checkbox({ checked, onChange: onChangeProp, label, size = "md", disabled = false, indeterminate = false, className, ref }) {
|
|
457
|
+
function Checkbox({ checked, onChange: onChangeProp, label, size = "md", disabled = false, indeterminate = false, className, ref, ...wiring }) {
|
|
1179
458
|
const onChange = useReportedChange(onChangeProp, checked);
|
|
1180
459
|
const internalRef = useRef(null);
|
|
1181
460
|
const dims = CHECKBOX_SIZES[size];
|
|
461
|
+
const control = useFieldControl(wiring);
|
|
1182
462
|
const mergedRef = useCallback(
|
|
1183
463
|
(node) => {
|
|
1184
464
|
internalRef.current = node;
|
|
@@ -1206,6 +486,11 @@ function Checkbox({ checked, onChange: onChangeProp, label, size = "md", disable
|
|
|
1206
486
|
{
|
|
1207
487
|
ref: mergedRef,
|
|
1208
488
|
type: "checkbox",
|
|
489
|
+
id: control.id,
|
|
490
|
+
"aria-labelledby": wiring["aria-labelledby"],
|
|
491
|
+
"aria-describedby": control.describedBy,
|
|
492
|
+
"aria-invalid": control.invalid || void 0,
|
|
493
|
+
required: control.required || void 0,
|
|
1209
494
|
checked,
|
|
1210
495
|
disabled,
|
|
1211
496
|
onChange: (e) => onChange(e.target.checked),
|
|
@@ -1268,10 +553,11 @@ function CheckboxGroupItem({ value, label, disabled, groupValue, onGroupChange }
|
|
|
1268
553
|
}
|
|
1269
554
|
);
|
|
1270
555
|
}
|
|
1271
|
-
function RadioGroup({ value, onChange: onChangeProp, options, orientation = "vertical", className, label }) {
|
|
556
|
+
function RadioGroup({ value, onChange: onChangeProp, options, orientation = "vertical", className, label, ...wiring }) {
|
|
1272
557
|
const onChange = useReportedChange(onChangeProp, value);
|
|
1273
558
|
const groupRef = useRef(null);
|
|
1274
559
|
const groupId = useId();
|
|
560
|
+
const control = useFieldControl(wiring);
|
|
1275
561
|
const enabledOptions = options.filter((o) => !o.disabled);
|
|
1276
562
|
const tabStop = rovingTabStop(options, (o) => o.value === value, (o) => !!o.disabled);
|
|
1277
563
|
function handleKeyDown(e) {
|
|
@@ -1301,7 +587,11 @@ function RadioGroup({ value, onChange: onChangeProp, options, orientation = "ver
|
|
|
1301
587
|
{
|
|
1302
588
|
ref: groupRef,
|
|
1303
589
|
role: "radiogroup",
|
|
1304
|
-
|
|
590
|
+
id: control.id,
|
|
591
|
+
"aria-labelledby": label ? groupId : control.labelId,
|
|
592
|
+
"aria-describedby": control.describedBy,
|
|
593
|
+
"aria-invalid": control.invalid || void 0,
|
|
594
|
+
"aria-required": control.required || void 0,
|
|
1305
595
|
className: cn(
|
|
1306
596
|
"flex",
|
|
1307
597
|
orientation === "vertical" ? "flex-col gap-ds-2" : "flex-row flex-wrap gap-ds-3"
|
|
@@ -1796,13 +1086,13 @@ function DatePicker({ value, onChange: onChangeProp, placeholder = "Pick a date"
|
|
|
1796
1086
|
className: "flex items-center justify-between bg-[var(--ds-bg-muted)] rounded-t-[var(--ds-radius-md)]",
|
|
1797
1087
|
style: { padding: "var(--ds-space-2) var(--ds-space-3)" },
|
|
1798
1088
|
children: [
|
|
1799
|
-
/* @__PURE__ */ jsx(Button, { variant: "ghost", size: "icon-sm", onClick: prevMonth, "aria-label": "Previous month", children: /* @__PURE__ */ jsx(Icon, { name: "chevron-right", size: 14, className: "rotate-180" }) }),
|
|
1089
|
+
/* @__PURE__ */ jsx(Button, { type: "button", variant: "ghost", size: "icon-sm", onClick: prevMonth, "aria-label": "Previous month", children: /* @__PURE__ */ jsx(Icon, { name: "chevron-right", size: 14, className: "rotate-180" }) }),
|
|
1800
1090
|
/* @__PURE__ */ jsxs("span", { className: "text-sm font-medium text-[var(--ds-text-primary)]", children: [
|
|
1801
1091
|
MONTHS[month],
|
|
1802
1092
|
" ",
|
|
1803
1093
|
year
|
|
1804
1094
|
] }),
|
|
1805
|
-
/* @__PURE__ */ jsx(Button, { variant: "ghost", size: "icon-sm", onClick: nextMonth, "aria-label": "Next month", children: /* @__PURE__ */ jsx(Icon, { name: "chevron-right", size: 14 }) })
|
|
1095
|
+
/* @__PURE__ */ jsx(Button, { type: "button", variant: "ghost", size: "icon-sm", onClick: nextMonth, "aria-label": "Next month", children: /* @__PURE__ */ jsx(Icon, { name: "chevron-right", size: 14 }) })
|
|
1806
1096
|
]
|
|
1807
1097
|
}
|
|
1808
1098
|
),
|
|
@@ -1865,6 +1155,7 @@ function DatePicker({ value, onChange: onChangeProp, placeholder = "Pick a date"
|
|
|
1865
1155
|
/* @__PURE__ */ jsx(
|
|
1866
1156
|
Button,
|
|
1867
1157
|
{
|
|
1158
|
+
type: "button",
|
|
1868
1159
|
variant: "ghost",
|
|
1869
1160
|
size: "sm",
|
|
1870
1161
|
onClick: () => {
|
|
@@ -1878,6 +1169,7 @@ function DatePicker({ value, onChange: onChangeProp, placeholder = "Pick a date"
|
|
|
1878
1169
|
value && /* @__PURE__ */ jsx(
|
|
1879
1170
|
Button,
|
|
1880
1171
|
{
|
|
1172
|
+
type: "button",
|
|
1881
1173
|
variant: "ghost",
|
|
1882
1174
|
size: "sm",
|
|
1883
1175
|
onClick: () => choose(null),
|
|
@@ -2264,7 +1556,7 @@ function DateRangePicker({
|
|
|
2264
1556
|
),
|
|
2265
1557
|
style: { top: pos.top, left: pos.left },
|
|
2266
1558
|
children: [
|
|
2267
|
-
presets.length > 0 && /* @__PURE__ */ jsx("div", { className: "flex flex-col gap-ds-0.5 p-ds-2 border-r-[length:var(--ds-border-width)] border-[var(--ds-border-subtle)] min-w-[140px]", children: presets.map((p) => /* @__PURE__ */ jsx(Button, { variant: "ghost", size: "sm", className: "justify-start", onClick: () => {
|
|
1559
|
+
presets.length > 0 && /* @__PURE__ */ jsx("div", { className: "flex flex-col gap-ds-0.5 p-ds-2 border-r-[length:var(--ds-border-width)] border-[var(--ds-border-subtle)] min-w-[140px]", children: presets.map((p) => /* @__PURE__ */ jsx(Button, { type: "button", variant: "ghost", size: "sm", className: "justify-start", onClick: () => {
|
|
2268
1560
|
const r = p.range();
|
|
2269
1561
|
returnFocus();
|
|
2270
1562
|
onChange(r);
|
|
@@ -2273,7 +1565,7 @@ function DateRangePicker({
|
|
|
2273
1565
|
}, children: p.label }, p.label)) }),
|
|
2274
1566
|
/* @__PURE__ */ jsxs("div", { className: "flex flex-col", children: [
|
|
2275
1567
|
/* @__PURE__ */ jsxs("div", { className: "flex items-center justify-between bg-[var(--ds-bg-muted)] rounded-tr-[var(--ds-radius-md)] px-ds-3 py-ds-2", children: [
|
|
2276
|
-
/* @__PURE__ */ jsx(Button, { variant: "ghost", size: "icon-sm", onClick: () => pageMonths(-1), "aria-label": "Previous month", children: /* @__PURE__ */ jsx(Icon, { name: "chevron-right", size: 14, className: "rotate-180" }) }),
|
|
1568
|
+
/* @__PURE__ */ jsx(Button, { type: "button", variant: "ghost", size: "icon-sm", onClick: () => pageMonths(-1), "aria-label": "Previous month", children: /* @__PURE__ */ jsx(Icon, { name: "chevron-right", size: 14, className: "rotate-180" }) }),
|
|
2277
1569
|
/* @__PURE__ */ jsxs("span", { className: "text-sm font-medium text-[var(--ds-text-primary)]", children: [
|
|
2278
1570
|
MONTHS2[months[0].getMonth()],
|
|
2279
1571
|
" ",
|
|
@@ -2283,7 +1575,7 @@ function DateRangePicker({
|
|
|
2283
1575
|
" ",
|
|
2284
1576
|
months[1].getFullYear()
|
|
2285
1577
|
] }),
|
|
2286
|
-
/* @__PURE__ */ jsx(Button, { variant: "ghost", size: "icon-sm", onClick: () => pageMonths(1), "aria-label": "Next month", children: /* @__PURE__ */ jsx(Icon, { name: "chevron-right", size: 14 }) })
|
|
1578
|
+
/* @__PURE__ */ jsx(Button, { type: "button", variant: "ghost", size: "icon-sm", onClick: () => pageMonths(1), "aria-label": "Next month", children: /* @__PURE__ */ jsx(Icon, { name: "chevron-right", size: 14 }) })
|
|
2287
1579
|
] }),
|
|
2288
1580
|
/* @__PURE__ */ jsx("div", { ref: gridRef, onKeyDown: grid.onKeyDown, className: "flex gap-ds-4 px-ds-3 py-ds-2", onMouseLeave: () => setHover(null), children: months.map((m) => /* @__PURE__ */ jsxs("div", { role: "grid", "aria-label": `${MONTHS2[m.getMonth()]} ${m.getFullYear()}`, className: "w-[224px] flex flex-col gap-ds-0.5", children: [
|
|
2289
1581
|
/* @__PURE__ */ jsx("div", { role: "row", className: "grid grid-cols-7 gap-ds-0.5 mb-ds-0.5", children: dayNames.map((d) => /* @__PURE__ */ jsx("div", { role: "columnheader", className: "text-center text-2xs font-medium text-[var(--ds-text-muted)] py-ds-1", children: d }, d)) }),
|
|
@@ -2324,7 +1616,7 @@ function DateRangePicker({
|
|
|
2324
1616
|
] }, `${m.getFullYear()}-${m.getMonth()}`)) }),
|
|
2325
1617
|
/* @__PURE__ */ jsxs("div", { className: "flex justify-between items-center bg-[var(--ds-bg-muted)] border-t-[length:var(--ds-border-width)] border-[var(--ds-border-subtle)] rounded-br-[var(--ds-radius-md)] px-ds-3 py-ds-2", children: [
|
|
2326
1618
|
/* @__PURE__ */ jsx("span", { className: "text-xs text-[var(--ds-text-muted)]", children: value.start && !value.end ? "Now pick an end date" : summary ?? "Pick a start date" }),
|
|
2327
|
-
(value.start || value.end) && /* @__PURE__ */ jsx(Button, { variant: "ghost", size: "sm", onClick: () => {
|
|
1619
|
+
(value.start || value.end) && /* @__PURE__ */ jsx(Button, { type: "button", variant: "ghost", size: "sm", onClick: () => {
|
|
2328
1620
|
onChange({ start: null, end: null });
|
|
2329
1621
|
setHover(null);
|
|
2330
1622
|
}, children: "Clear" })
|
|
@@ -2488,6 +1780,8 @@ function formatSize(bytes) {
|
|
|
2488
1780
|
}
|
|
2489
1781
|
var running = (item) => item.status === "queued" || item.status === "uploading";
|
|
2490
1782
|
var failureOf = (err) => err instanceof Error && err.message ? err.message : "The upload didn't work.";
|
|
1783
|
+
var percentOf = (value) => typeof value === "number" && Number.isFinite(value) ? Math.max(0, Math.min(100, value)) : 0;
|
|
1784
|
+
var STILL_UPLOADING = "Wait for your files to finish uploading";
|
|
2491
1785
|
function FileUpload({ onFiles, files, upload, onCancel, onRetry, onRemove, accept, multiple = true, maxSize, className, error = false, label, id }) {
|
|
2492
1786
|
const controlled = files !== void 0;
|
|
2493
1787
|
const [own, setOwn] = useState([]);
|
|
@@ -2508,8 +1802,6 @@ function FileUpload({ onFiles, files, upload, onCancel, onRetry, onRemove, accep
|
|
|
2508
1802
|
const rejectedId = `${ownId}-rejected`;
|
|
2509
1803
|
const showLabel = label != null && !field;
|
|
2510
1804
|
const constraints = fileConstraints(accept, maxSize, multiple);
|
|
2511
|
-
const invalid = error || rejected != null;
|
|
2512
|
-
const describedBy = [constraints ? constraintsId : null, field?.describedBy, rejected ? rejectedId : null].filter(Boolean).join(" ") || void 0;
|
|
2513
1805
|
const patch = (itemId, change) => setOwn((prev) => prev.map((i) => i.id === itemId ? { ...i, ...change } : i));
|
|
2514
1806
|
const stop = (itemId) => {
|
|
2515
1807
|
controllers.current.get(itemId)?.abort();
|
|
@@ -2531,7 +1823,7 @@ function FileUpload({ onFiles, files, upload, onCancel, onRetry, onRemove, accep
|
|
|
2531
1823
|
attempt = Promise.resolve(run(item.file, {
|
|
2532
1824
|
signal: controller.signal,
|
|
2533
1825
|
onProgress: (percent) => {
|
|
2534
|
-
if (!controller.signal.aborted) patch(item.id, { progress:
|
|
1826
|
+
if (!controller.signal.aborted) patch(item.id, { progress: percentOf(percent) });
|
|
2535
1827
|
}
|
|
2536
1828
|
}));
|
|
2537
1829
|
} catch (err) {
|
|
@@ -2539,6 +1831,11 @@ function FileUpload({ onFiles, files, upload, onCancel, onRetry, onRemove, accep
|
|
|
2539
1831
|
}
|
|
2540
1832
|
attempt.then(() => settle({ status: "done", progress: 100 }), (err) => settle({ status: "error", error: failureOf(err) }));
|
|
2541
1833
|
};
|
|
1834
|
+
const [hadUpload, setHadUpload] = useState(!!upload);
|
|
1835
|
+
if (!controlled && !!upload !== hadUpload) {
|
|
1836
|
+
setHadUpload(!!upload);
|
|
1837
|
+
setOwn((prev) => prev.map((i) => upload ? i.status === "added" && i.file ? { ...i, status: "queued" } : i : i.status === "queued" ? { ...i, status: "error", error: "The upload couldn't start." } : i));
|
|
1838
|
+
}
|
|
2542
1839
|
useEffect(() => {
|
|
2543
1840
|
if (controlled || !upload) return;
|
|
2544
1841
|
let active = own.filter((i) => i.status === "uploading" && controllers.current.has(i.id)).length;
|
|
@@ -2564,31 +1861,67 @@ function FileUpload({ onFiles, files, upload, onCancel, onRetry, onRemove, accep
|
|
|
2564
1861
|
useEffect(() => {
|
|
2565
1862
|
if (!overlayOpen && !controlled) stopAll();
|
|
2566
1863
|
}, [overlayOpen, controlled, stopAll]);
|
|
2567
|
-
const busy = shown.some(
|
|
1864
|
+
const busy = shown.some((i) => i.status === "uploading" || i.status === "queued" && (controlled || !!upload));
|
|
2568
1865
|
useEffect(() => {
|
|
2569
1866
|
if (!busy || !overlayMark) return;
|
|
2570
1867
|
return overlayMark.hold();
|
|
2571
1868
|
}, [busy, overlayMark]);
|
|
2572
|
-
const
|
|
2573
|
-
const
|
|
2574
|
-
|
|
1869
|
+
const form = useOptionalFormContext();
|
|
1870
|
+
const waitingKey = `${inputId}-uploads`;
|
|
1871
|
+
const waitingId = `${ownId}-waiting`;
|
|
1872
|
+
const busyRef = useLatest(busy);
|
|
1873
|
+
const registerCheck = form?.register;
|
|
1874
|
+
useEffect(() => registerCheck?.(waitingKey, () => busyRef.current ? STILL_UPLOADING : void 0), [registerCheck, waitingKey, busyRef]);
|
|
1875
|
+
const waiting = form?.errors[waitingKey];
|
|
1876
|
+
const clearWaiting = form?.setError;
|
|
1877
|
+
useEffect(() => {
|
|
1878
|
+
if (!busy && waiting) clearWaiting?.(waitingKey, void 0);
|
|
1879
|
+
}, [busy, waiting, clearWaiting, waitingKey]);
|
|
1880
|
+
useEffect(() => {
|
|
1881
|
+
const owner = inputRef.current?.form;
|
|
1882
|
+
if (!owner) return;
|
|
1883
|
+
const clear = () => setRejected(null);
|
|
1884
|
+
owner.addEventListener("submit", clear);
|
|
1885
|
+
return () => owner.removeEventListener("submit", clear);
|
|
1886
|
+
}, []);
|
|
1887
|
+
const invalid = error || rejected != null || !!waiting;
|
|
1888
|
+
const describedBy = [constraints ? constraintsId : null, field?.describedBy, rejected ? rejectedId : null, waiting ? waitingId : null].filter(Boolean).join(" ") || void 0;
|
|
1889
|
+
useEffect(() => {
|
|
1890
|
+
if (controlled && !onFiles) warnOnce("FileUpload", "`files` without `onFiles`: the page's list never gets the files the user picks. Add them in onFiles.");
|
|
1891
|
+
if (controlled && upload) warnOnce("FileUpload", "pass `files` or `upload`, not both: with `files` the page runs the uploads and FileUpload shows them.");
|
|
1892
|
+
if (!onRemove) warnOnce("FileUpload", "no `onRemove`: Remove shows only on a failed file, since the page would still have a file the user removed.");
|
|
1893
|
+
const ids = shown.map((i) => i.id);
|
|
1894
|
+
if (new Set(ids).size !== ids.length) warnOnce("FileUpload", "two files in the list share an id: give each file its own (the same file picked twice is two files).");
|
|
1895
|
+
}, [controlled, onFiles, upload, onRemove, shown]);
|
|
1896
|
+
const [heard, setHeard] = useState({ text: "", n: 0 });
|
|
1897
|
+
const signature = shown.map((i) => `${i.id}\0${i.status}`).join("");
|
|
1898
|
+
const [seen, setSeen] = useState(() => ({ signature, statuses: new Map(shown.map((i) => [i.id, i.status])) }));
|
|
1899
|
+
if (signature !== seen.signature) {
|
|
2575
1900
|
const said = [];
|
|
2576
1901
|
for (const item of shown) {
|
|
2577
|
-
const before = seen.get(item.id);
|
|
1902
|
+
const before = seen.statuses.get(item.id);
|
|
2578
1903
|
if (!before || before === item.status) continue;
|
|
2579
1904
|
if (item.status === "done") said.push(`${item.name} uploaded`);
|
|
2580
1905
|
else if (item.status === "error") said.push(`${item.name} didn't upload: ${item.error ?? "the upload failed"}`);
|
|
2581
1906
|
}
|
|
2582
|
-
setSeen(new Map(shown.map((i) => [i.id, i.status])));
|
|
2583
|
-
if (said.length) setHeard(said.join(". "));
|
|
1907
|
+
setSeen({ signature, statuses: new Map(shown.map((i) => [i.id, i.status])) });
|
|
1908
|
+
if (said.length) setHeard((h) => ({ text: said.join(". "), n: h.n + 1 }));
|
|
2584
1909
|
}
|
|
2585
1910
|
const pendingFocus = useRef(null);
|
|
1911
|
+
const lastAction = useRef(null);
|
|
2586
1912
|
useEffect(() => {
|
|
2587
|
-
const
|
|
2588
|
-
if (
|
|
2589
|
-
|
|
2590
|
-
|
|
2591
|
-
|
|
1913
|
+
const gone = pendingFocus.current;
|
|
1914
|
+
if (gone && !shown.some((i) => i.id === gone.id)) {
|
|
1915
|
+
pendingFocus.current = null;
|
|
1916
|
+
const rows = Array.from(listRef.current?.querySelectorAll(":scope > li") ?? []).map((row2) => row2.querySelector("button")).filter((b) => !!b);
|
|
1917
|
+
focusAfterRemoval(rows, gone.index, inputRef.current);
|
|
1918
|
+
return;
|
|
1919
|
+
}
|
|
1920
|
+
const last = lastAction.current;
|
|
1921
|
+
const active = document.activeElement;
|
|
1922
|
+
if (!last || last.el.isConnected || active && active !== document.body) return;
|
|
1923
|
+
const row = Array.from(listRef.current?.querySelectorAll(":scope > li") ?? []).find((li) => li.dataset.uploadId === last.id);
|
|
1924
|
+
row?.querySelector("button")?.focus();
|
|
2592
1925
|
}, [shown]);
|
|
2593
1926
|
const addFiles = useCallback(
|
|
2594
1927
|
(fileList) => {
|
|
@@ -2615,7 +1948,7 @@ function FileUpload({ onFiles, files, upload, onCancel, onRetry, onRemove, accep
|
|
|
2615
1948
|
);
|
|
2616
1949
|
const indexOf = (item) => shown.findIndex((i) => i.id === item.id);
|
|
2617
1950
|
const cancel = (item) => {
|
|
2618
|
-
pendingFocus.current = indexOf(item);
|
|
1951
|
+
pendingFocus.current = { id: item.id, index: indexOf(item) };
|
|
2619
1952
|
if (!controlled) {
|
|
2620
1953
|
stop(item.id);
|
|
2621
1954
|
setOwn((prev) => prev.filter((i) => i.id !== item.id));
|
|
@@ -2627,7 +1960,7 @@ function FileUpload({ onFiles, files, upload, onCancel, onRetry, onRemove, accep
|
|
|
2627
1960
|
onRetry?.(item);
|
|
2628
1961
|
};
|
|
2629
1962
|
const remove = (item) => {
|
|
2630
|
-
pendingFocus.current = indexOf(item);
|
|
1963
|
+
pendingFocus.current = { id: item.id, index: indexOf(item) };
|
|
2631
1964
|
reportChange?.();
|
|
2632
1965
|
if (!controlled) {
|
|
2633
1966
|
stop(item.id);
|
|
@@ -2637,7 +1970,7 @@ function FileUpload({ onFiles, files, upload, onCancel, onRetry, onRemove, accep
|
|
|
2637
1970
|
};
|
|
2638
1971
|
const canCancel = !controlled || !!onCancel;
|
|
2639
1972
|
const canRetry = !controlled || !!onRetry;
|
|
2640
|
-
const canRemove = !controlled
|
|
1973
|
+
const canRemove = (item) => !!onRemove || !controlled && item.status === "error";
|
|
2641
1974
|
return /* @__PURE__ */ jsxs("div", { className: cn("space-y-ds-3", className), children: [
|
|
2642
1975
|
/* @__PURE__ */ jsxs("div", { className: "flex flex-col gap-ds-1.5", children: [
|
|
2643
1976
|
showLabel && /* @__PURE__ */ jsx(Label, { htmlFor: inputId, children: label }),
|
|
@@ -2691,14 +2024,20 @@ function FileUpload({ onFiles, files, upload, onCancel, onRetry, onRemove, accep
|
|
|
2691
2024
|
]
|
|
2692
2025
|
}
|
|
2693
2026
|
),
|
|
2694
|
-
rejected && /* @__PURE__ */ jsx(InlineFieldError, { id: rejectedId, message: rejected, className: "mt-0" })
|
|
2027
|
+
rejected && /* @__PURE__ */ jsx(InlineFieldError, { id: rejectedId, message: rejected, className: "mt-0" }),
|
|
2028
|
+
waiting && /* @__PURE__ */ jsx(InlineFieldError, { id: waitingId, message: waiting, className: "mt-0" })
|
|
2695
2029
|
] }),
|
|
2696
2030
|
shown.length > 0 && /* @__PURE__ */ jsx("ul", { ref: listRef, className: "space-y-ds-2", children: shown.map((item) => {
|
|
2697
|
-
const
|
|
2031
|
+
const progress = percentOf(item.progress);
|
|
2032
|
+
const words = item.status === "queued" ? "Waiting" : item.status === "uploading" ? `${Math.round(progress)}%` : item.status === "done" ? "Uploaded" : item.status === "error" ? "Failed" : null;
|
|
2698
2033
|
return /* @__PURE__ */ jsxs(
|
|
2699
2034
|
"li",
|
|
2700
2035
|
{
|
|
2036
|
+
"data-upload-id": item.id,
|
|
2701
2037
|
"data-upload-status": item.status,
|
|
2038
|
+
onFocus: (e) => {
|
|
2039
|
+
if (e.target instanceof HTMLButtonElement) lastAction.current = { id: item.id, el: e.target };
|
|
2040
|
+
},
|
|
2702
2041
|
className: cn(
|
|
2703
2042
|
"flex items-center gap-ds-3 text-sm",
|
|
2704
2043
|
"border-[length:var(--ds-border-width)]",
|
|
@@ -2711,20 +2050,20 @@ function FileUpload({ onFiles, files, upload, onCancel, onRetry, onRemove, accep
|
|
|
2711
2050
|
/* @__PURE__ */ jsxs("div", { className: "flex-1 min-w-0", children: [
|
|
2712
2051
|
/* @__PURE__ */ jsx(TruncFileName, { className: "text-[var(--ds-text-primary)]", children: item.name }),
|
|
2713
2052
|
(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:
|
|
2053
|
+
item.status === "uploading" && /* @__PURE__ */ jsx(Progress, { value: progress, size: "sm", label: `Uploading ${item.name}`, className: "mt-ds-1" }),
|
|
2715
2054
|
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
2055
|
] }),
|
|
2717
2056
|
item.status === "done" && /* @__PURE__ */ jsx(Icon, { name: "check", size: 16, className: "text-[var(--ds-status-success)] shrink-0", "aria-hidden": "true" }),
|
|
2718
2057
|
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 }) })
|
|
2058
|
+
/* @__PURE__ */ jsx(Button, { type: "button", variant: "ghost", size: "sm", onClick: () => cancel(item), "aria-label": `Cancel ${item.name}`, children: "Cancel" }),
|
|
2059
|
+
item.status === "error" && canRetry && /* @__PURE__ */ jsx(Button, { type: "button", variant: "ghost", size: "sm", onClick: () => retry(item), "aria-label": `Retry ${item.name}`, children: "Retry" }),
|
|
2060
|
+
!running(item) && canRemove(item) && /* @__PURE__ */ jsx(Button, { type: "button", variant: "ghost", size: "icon-sm", onClick: () => remove(item), "aria-label": `Remove ${item.name}`, children: /* @__PURE__ */ jsx(Icon, { name: "close", size: 14 }) })
|
|
2722
2061
|
]
|
|
2723
2062
|
},
|
|
2724
2063
|
item.id
|
|
2725
2064
|
);
|
|
2726
2065
|
}) }),
|
|
2727
|
-
/* @__PURE__ */ jsx("
|
|
2066
|
+
/* @__PURE__ */ jsx("div", { role: "status", className: "sr-only", children: /* @__PURE__ */ jsx("span", { children: heard.text }, heard.n) })
|
|
2728
2067
|
] });
|
|
2729
2068
|
}
|
|
2730
2069
|
function SliderRange({
|
|
@@ -3334,222 +2673,6 @@ function TimePicker({
|
|
|
3334
2673
|
)
|
|
3335
2674
|
] });
|
|
3336
2675
|
}
|
|
3337
|
-
var sizes = {
|
|
3338
|
-
sm: { box: "h-[var(--ds-control-height-sm)]", input: "text-xs self-stretch", btn: "w-7 text-xs" },
|
|
3339
|
-
md: { box: "h-[var(--ds-control-height-md)]", input: "text-sm self-stretch", btn: "w-9 text-sm" },
|
|
3340
|
-
lg: { box: "h-[var(--ds-control-height-lg)]", input: "text-base self-stretch", btn: "w-10 text-base" }
|
|
3341
|
-
};
|
|
3342
|
-
function NumberInput({
|
|
3343
|
-
value,
|
|
3344
|
-
onChange: onChangeProp,
|
|
3345
|
-
min = -Infinity,
|
|
3346
|
-
max = Infinity,
|
|
3347
|
-
step = 1,
|
|
3348
|
-
disabled = false,
|
|
3349
|
-
placeholder = "0",
|
|
3350
|
-
prefix,
|
|
3351
|
-
suffix,
|
|
3352
|
-
size: sizeProp,
|
|
3353
|
-
className,
|
|
3354
|
-
error = false,
|
|
3355
|
-
allowDecimals,
|
|
3356
|
-
id
|
|
3357
|
-
}) {
|
|
3358
|
-
const onChange = useReportedChange(onChangeProp, value);
|
|
3359
|
-
const contextSize = useContext(ControlSizeContext);
|
|
3360
|
-
const size = sizeProp ?? contextSize ?? "md";
|
|
3361
|
-
const intervalRef = useRef(void 0);
|
|
3362
|
-
const timeoutRef = useRef(void 0);
|
|
3363
|
-
const inputRef = useRef(null);
|
|
3364
|
-
const [focused, setFocused] = useState(false);
|
|
3365
|
-
const [draft, setDraft] = useState(String(value));
|
|
3366
|
-
const decimals = allowDecimals ?? step % 1 !== 0;
|
|
3367
|
-
const [prevSync, setPrevSync] = useState({ value, focused });
|
|
3368
|
-
if (value !== prevSync.value || focused !== prevSync.focused) {
|
|
3369
|
-
setPrevSync({ value, focused });
|
|
3370
|
-
if (!focused) setDraft(String(value));
|
|
3371
|
-
}
|
|
3372
|
-
const clamp = useCallback(
|
|
3373
|
-
(v) => Math.min(max, Math.max(min, v)),
|
|
3374
|
-
[min, max]
|
|
3375
|
-
);
|
|
3376
|
-
const valueRef = useLatest(value);
|
|
3377
|
-
const commitValue = useCallback((v, own = false) => {
|
|
3378
|
-
const clamped = clamp(v);
|
|
3379
|
-
valueRef.current = clamped;
|
|
3380
|
-
setDraft(String(clamped));
|
|
3381
|
-
(own ? onChangeProp : onChange)(clamped);
|
|
3382
|
-
return clamped;
|
|
3383
|
-
}, [onChange, onChangeProp, clamp, valueRef]);
|
|
3384
|
-
const increment = useCallback(() => commitValue(valueRef.current + step), [commitValue, step, valueRef]);
|
|
3385
|
-
const decrement = useCallback(() => commitValue(valueRef.current - step), [commitValue, step, valueRef]);
|
|
3386
|
-
const startRepeat = useCallback(
|
|
3387
|
-
(fn) => {
|
|
3388
|
-
fn();
|
|
3389
|
-
timeoutRef.current = setTimeout(() => {
|
|
3390
|
-
intervalRef.current = setInterval(fn, 75);
|
|
3391
|
-
}, 400);
|
|
3392
|
-
},
|
|
3393
|
-
[]
|
|
3394
|
-
);
|
|
3395
|
-
const stopRepeat = useCallback(() => {
|
|
3396
|
-
clearTimeout(timeoutRef.current);
|
|
3397
|
-
clearInterval(intervalRef.current);
|
|
3398
|
-
}, []);
|
|
3399
|
-
const handleInput = useCallback(
|
|
3400
|
-
(e) => {
|
|
3401
|
-
const raw = e.target.value;
|
|
3402
|
-
if (raw === "" || raw === "-") {
|
|
3403
|
-
setDraft(raw);
|
|
3404
|
-
return;
|
|
3405
|
-
}
|
|
3406
|
-
if (!decimals && raw.includes(".")) return;
|
|
3407
|
-
const validPattern = decimals ? /^-?\d*\.?\d*$/ : /^-?\d*$/;
|
|
3408
|
-
if (!validPattern.test(raw)) return;
|
|
3409
|
-
setDraft(raw);
|
|
3410
|
-
const parsed = parseFloat(raw);
|
|
3411
|
-
if (!isNaN(parsed) && isFinite(parsed)) {
|
|
3412
|
-
onChange(clamp(parsed));
|
|
3413
|
-
}
|
|
3414
|
-
},
|
|
3415
|
-
[onChange, clamp, decimals]
|
|
3416
|
-
);
|
|
3417
|
-
const handleBlur = useCallback(() => {
|
|
3418
|
-
setFocused(false);
|
|
3419
|
-
const parsed = parseFloat(draft);
|
|
3420
|
-
if (!isNaN(parsed) && isFinite(parsed)) {
|
|
3421
|
-
const committed = commitValue(parsed);
|
|
3422
|
-
setDraft(String(committed));
|
|
3423
|
-
} else {
|
|
3424
|
-
const fallback = isFinite(min) ? min : 0;
|
|
3425
|
-
const committed = commitValue(value !== void 0 ? value : fallback, true);
|
|
3426
|
-
setDraft(String(committed));
|
|
3427
|
-
}
|
|
3428
|
-
}, [draft, commitValue, min, value]);
|
|
3429
|
-
const handleFocus = useCallback(() => {
|
|
3430
|
-
setFocused(true);
|
|
3431
|
-
}, []);
|
|
3432
|
-
const handleKeyDown = useCallback(
|
|
3433
|
-
(e) => {
|
|
3434
|
-
if (e.key === "ArrowUp") {
|
|
3435
|
-
e.preventDefault();
|
|
3436
|
-
increment();
|
|
3437
|
-
}
|
|
3438
|
-
if (e.key === "ArrowDown") {
|
|
3439
|
-
e.preventDefault();
|
|
3440
|
-
decrement();
|
|
3441
|
-
}
|
|
3442
|
-
},
|
|
3443
|
-
[increment, decrement]
|
|
3444
|
-
);
|
|
3445
|
-
const s = sizes[size];
|
|
3446
|
-
const atMin = value <= min;
|
|
3447
|
-
const atMax = value >= max;
|
|
3448
|
-
return /* @__PURE__ */ jsxs(
|
|
3449
|
-
"div",
|
|
3450
|
-
{
|
|
3451
|
-
className: cn(
|
|
3452
|
-
"flex items-center w-full",
|
|
3453
|
-
s.box,
|
|
3454
|
-
"border-[length:var(--ds-border-width)]",
|
|
3455
|
-
error ? "border-[var(--ds-status-error)]" : "border-[var(--ds-input-border)]",
|
|
3456
|
-
"rounded-[var(--ds-radius-md)]",
|
|
3457
|
-
"shadow-[var(--ds-input-shadow)]",
|
|
3458
|
-
"bg-[var(--ds-input-bg)]",
|
|
3459
|
-
"transition-colors duration-[var(--ds-transition-speed)]",
|
|
3460
|
-
!error && !disabled && "hover:border-[var(--ds-input-border-hover)]",
|
|
3461
|
-
error ? ERROR_FOCUS_WITHIN_RING : cn(FOCUS_WITHIN_RING, "focus-within:hover:border-[var(--ds-border-focus)]"),
|
|
3462
|
-
disabled && "opacity-disabled cursor-not-allowed",
|
|
3463
|
-
className
|
|
3464
|
-
),
|
|
3465
|
-
children: [
|
|
3466
|
-
/* @__PURE__ */ jsx(
|
|
3467
|
-
"button",
|
|
3468
|
-
{
|
|
3469
|
-
type: "button",
|
|
3470
|
-
tabIndex: -1,
|
|
3471
|
-
disabled: disabled || atMin,
|
|
3472
|
-
onMouseDown: (e) => {
|
|
3473
|
-
e.preventDefault();
|
|
3474
|
-
inputRef.current?.focus();
|
|
3475
|
-
if (!disabled && !atMin) startRepeat(decrement);
|
|
3476
|
-
},
|
|
3477
|
-
onMouseUp: stopRepeat,
|
|
3478
|
-
onMouseLeave: stopRepeat,
|
|
3479
|
-
className: cn(
|
|
3480
|
-
"inline-flex items-center justify-center shrink-0",
|
|
3481
|
-
"border-r-[length:var(--ds-border-width)] border-[var(--ds-border-default)]",
|
|
3482
|
-
"text-[var(--ds-text-muted)] hover:text-[var(--ds-text-primary)] hover:bg-[var(--ds-bg-muted)]",
|
|
3483
|
-
"transition-colors cursor-pointer",
|
|
3484
|
-
"rounded-l-[var(--ds-radius-md)]",
|
|
3485
|
-
s.btn,
|
|
3486
|
-
s.input,
|
|
3487
|
-
(disabled || atMin) && "opacity-disabled cursor-not-allowed hover:bg-transparent hover:text-[var(--ds-text-muted)]"
|
|
3488
|
-
),
|
|
3489
|
-
"aria-label": "Decrease",
|
|
3490
|
-
children: "\u2212"
|
|
3491
|
-
}
|
|
3492
|
-
),
|
|
3493
|
-
/* @__PURE__ */ jsxs("div", { className: cn("flex items-center flex-1 min-w-0 px-ds-2 gap-ds-1", s.input), children: [
|
|
3494
|
-
prefix && /* @__PURE__ */ jsx("span", { className: "text-[var(--ds-text-muted)] shrink-0 text-xs", children: prefix }),
|
|
3495
|
-
/* @__PURE__ */ jsx(
|
|
3496
|
-
"input",
|
|
3497
|
-
{
|
|
3498
|
-
ref: inputRef,
|
|
3499
|
-
id,
|
|
3500
|
-
type: "text",
|
|
3501
|
-
inputMode: decimals ? "decimal" : "numeric",
|
|
3502
|
-
"aria-invalid": error || void 0,
|
|
3503
|
-
value: focused ? draft : String(value),
|
|
3504
|
-
onChange: handleInput,
|
|
3505
|
-
onFocus: handleFocus,
|
|
3506
|
-
onBlur: handleBlur,
|
|
3507
|
-
onKeyDown: handleKeyDown,
|
|
3508
|
-
disabled,
|
|
3509
|
-
placeholder,
|
|
3510
|
-
className: cn(
|
|
3511
|
-
"w-full min-w-0 bg-transparent text-center outline-none",
|
|
3512
|
-
"text-[var(--ds-text-primary)]",
|
|
3513
|
-
"placeholder:text-[var(--ds-text-muted)]",
|
|
3514
|
-
"font-[family-name:var(--ds-font-mono)]",
|
|
3515
|
-
s.input,
|
|
3516
|
-
disabled && "cursor-not-allowed"
|
|
3517
|
-
)
|
|
3518
|
-
}
|
|
3519
|
-
),
|
|
3520
|
-
suffix && /* @__PURE__ */ jsx("span", { className: "text-[var(--ds-text-muted)] shrink-0 text-xs", children: suffix })
|
|
3521
|
-
] }),
|
|
3522
|
-
/* @__PURE__ */ jsx(
|
|
3523
|
-
"button",
|
|
3524
|
-
{
|
|
3525
|
-
type: "button",
|
|
3526
|
-
tabIndex: -1,
|
|
3527
|
-
disabled: disabled || atMax,
|
|
3528
|
-
onMouseDown: (e) => {
|
|
3529
|
-
e.preventDefault();
|
|
3530
|
-
inputRef.current?.focus();
|
|
3531
|
-
if (!disabled && !atMax) startRepeat(increment);
|
|
3532
|
-
},
|
|
3533
|
-
onMouseUp: stopRepeat,
|
|
3534
|
-
onMouseLeave: stopRepeat,
|
|
3535
|
-
className: cn(
|
|
3536
|
-
"inline-flex items-center justify-center shrink-0",
|
|
3537
|
-
"border-l-[length:var(--ds-border-width)] border-[var(--ds-border-default)]",
|
|
3538
|
-
"text-[var(--ds-text-muted)] hover:text-[var(--ds-text-primary)] hover:bg-[var(--ds-bg-muted)]",
|
|
3539
|
-
"transition-colors cursor-pointer",
|
|
3540
|
-
"rounded-r-[var(--ds-radius-md)]",
|
|
3541
|
-
s.btn,
|
|
3542
|
-
s.input,
|
|
3543
|
-
(disabled || atMax) && "opacity-disabled cursor-not-allowed hover:bg-transparent hover:text-[var(--ds-text-muted)]"
|
|
3544
|
-
),
|
|
3545
|
-
"aria-label": "Increase",
|
|
3546
|
-
children: "+"
|
|
3547
|
-
}
|
|
3548
|
-
)
|
|
3549
|
-
]
|
|
3550
|
-
}
|
|
3551
|
-
);
|
|
3552
|
-
}
|
|
3553
2676
|
var variantStyles = {
|
|
3554
2677
|
default: "bg-[var(--ds-bg-emphasis)] text-[var(--ds-text-primary)]",
|
|
3555
2678
|
subtle: "bg-[var(--ds-bg-muted)] text-[var(--ds-text-secondary)]",
|
|
@@ -3791,7 +2914,7 @@ function TagInput({
|
|
|
3791
2914
|
}
|
|
3792
2915
|
);
|
|
3793
2916
|
}
|
|
3794
|
-
var
|
|
2917
|
+
var sizes = {
|
|
3795
2918
|
sm: "w-[var(--ds-control-height-sm)] h-[var(--ds-control-height-sm)] text-sm",
|
|
3796
2919
|
md: "w-[var(--ds-control-height-md)] h-[var(--ds-control-height-md)] text-base",
|
|
3797
2920
|
lg: "w-[var(--ds-control-height-lg)] h-[var(--ds-control-height-lg)] text-lg"
|
|
@@ -3895,7 +3018,7 @@ function PinInput({
|
|
|
3895
3018
|
!error && !disabled && "hover:border-[var(--ds-input-border-hover)]",
|
|
3896
3019
|
error ? ERROR_FOCUS_RING : FOCUS_RING,
|
|
3897
3020
|
"placeholder:text-[var(--ds-text-muted)]",
|
|
3898
|
-
|
|
3021
|
+
sizes[size],
|
|
3899
3022
|
disabled && "opacity-disabled cursor-not-allowed"
|
|
3900
3023
|
)
|
|
3901
3024
|
},
|
|
@@ -3949,11 +3072,13 @@ function Rating({
|
|
|
3949
3072
|
readOnly = false,
|
|
3950
3073
|
size = "md",
|
|
3951
3074
|
className,
|
|
3952
|
-
error = false
|
|
3075
|
+
error = false,
|
|
3076
|
+
...wiring
|
|
3953
3077
|
}) {
|
|
3954
3078
|
const onChange = useReportedChange(onChangeProp, value);
|
|
3955
3079
|
const [hoverValue, setHoverValue] = useState(null);
|
|
3956
3080
|
const displayValue = hoverValue ?? value;
|
|
3081
|
+
const control = useFieldControl({ ...wiring, error: error || void 0 });
|
|
3957
3082
|
const handleClick = useCallback(
|
|
3958
3083
|
(starIdx, isLeftHalf) => {
|
|
3959
3084
|
if (readOnly || !onChangeProp) return;
|
|
@@ -4020,8 +3145,12 @@ function Rating({
|
|
|
4020
3145
|
"div",
|
|
4021
3146
|
{
|
|
4022
3147
|
role: readOnly ? "img" : "radiogroup",
|
|
4023
|
-
|
|
4024
|
-
"aria-
|
|
3148
|
+
id: control.id,
|
|
3149
|
+
"aria-label": readOnly || !control.labelId ? `Rating: ${value} out of ${max}` : void 0,
|
|
3150
|
+
"aria-labelledby": readOnly ? void 0 : control.labelId,
|
|
3151
|
+
"aria-describedby": control.describedBy,
|
|
3152
|
+
"aria-invalid": readOnly ? void 0 : control.invalid || void 0,
|
|
3153
|
+
"aria-required": readOnly ? void 0 : control.required || void 0,
|
|
4025
3154
|
onKeyDown: readOnly ? void 0 : handleKeyDown,
|
|
4026
3155
|
className: cn(
|
|
4027
3156
|
"inline-flex items-center gap-ds-0.5",
|
|
@@ -4431,11 +3560,6 @@ var Alert = forwardRef(function Alert2({
|
|
|
4431
3560
|
}
|
|
4432
3561
|
);
|
|
4433
3562
|
});
|
|
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
3563
|
var isThenable = (value) => !!value && typeof value.then === "function";
|
|
4440
3564
|
function stampFormId(node, formId) {
|
|
4441
3565
|
return Children.map(node, (child) => {
|
|
@@ -4494,29 +3618,18 @@ function FormWrapper({ onSubmit, validationMode: validationModeProp, children, a
|
|
|
4494
3618
|
const pendingFocus = useRef(false);
|
|
4495
3619
|
const onSubmitRef = useLatest(onSubmit);
|
|
4496
3620
|
const overlayMark = useContext(OverlayMarkCtx);
|
|
4497
|
-
const reportChange = overlayMark ? overlayMark.report : null;
|
|
4498
|
-
|
|
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]);
|
|
3621
|
+
const reportChange = useMemo(() => overlayMark ? () => overlayMark.report(formId) : null, [overlayMark, formId]);
|
|
3622
|
+
useEffect(() => overlayMark?.attach(formId), [overlayMark, formId]);
|
|
4504
3623
|
useEffect(() => {
|
|
4505
3624
|
if (pendingSubmit.current && submitted) {
|
|
4506
3625
|
pendingSubmit.current = false;
|
|
4507
|
-
const
|
|
4508
|
-
const passed = Object.keys(errorsRef.current).length === 0 && !form?.querySelector("[aria-invalid='true']");
|
|
4509
|
-
const controls = controlsOf(form);
|
|
3626
|
+
const answer = overlayMark?.submit(formId, { element: () => formRef.current, failing: () => Object.keys(errorsRef.current).length > 0 });
|
|
4510
3627
|
const result = onSubmitRef.current(errorsRef.current);
|
|
4511
|
-
if (!
|
|
4512
|
-
if (isThenable(result))
|
|
4513
|
-
|
|
4514
|
-
});
|
|
4515
|
-
} else {
|
|
4516
|
-
setSavedCheck({ controls });
|
|
4517
|
-
}
|
|
3628
|
+
if (!answer) return;
|
|
3629
|
+
if (isThenable(result)) void result.then(() => answer.settle("resolved"));
|
|
3630
|
+
else answer.settle("returned");
|
|
4518
3631
|
}
|
|
4519
|
-
}, [submitted, submitCount, errors, errorsRef, onSubmitRef, overlayMark]);
|
|
3632
|
+
}, [submitted, submitCount, errors, errorsRef, onSubmitRef, overlayMark, formId]);
|
|
4520
3633
|
const submittedRef = useLatest(submitted);
|
|
4521
3634
|
const errorSummaryRef = useLatest(errorSummary);
|
|
4522
3635
|
const summaryRef = useRef(null);
|
|
@@ -4601,7 +3714,9 @@ function FormWrapper({ onSubmit, validationMode: validationModeProp, children, a
|
|
|
4601
3714
|
}, []);
|
|
4602
3715
|
const handleSubmit = useCallback(
|
|
4603
3716
|
(e) => {
|
|
3717
|
+
if (e.target !== e.currentTarget) return;
|
|
4604
3718
|
e.preventDefault();
|
|
3719
|
+
e.stopPropagation();
|
|
4605
3720
|
if (checks.current.size > 0) {
|
|
4606
3721
|
const found = /* @__PURE__ */ new Map();
|
|
4607
3722
|
for (const [field, check] of checks.current) found.set(field, check());
|
|
@@ -4645,16 +3760,26 @@ var FOCUSABLE2 = "input:not([disabled]):not([type='hidden']), select:not([disabl
|
|
|
4645
3760
|
function AddAnother({ items, getId, itemName, columns, renderRow, onAdd, onRemove, addLabel = "Add another", label, minItems = 1, maxItems, className }) {
|
|
4646
3761
|
const listRef = useRef(null);
|
|
4647
3762
|
const addRef = useRef(null);
|
|
3763
|
+
const reportChange = useContext(FormChangeCtx);
|
|
3764
|
+
const getIdRef = useLatest(getId);
|
|
4648
3765
|
const pending = useRef(null);
|
|
4649
|
-
const firstFields = () => Array.from(listRef.current?.querySelectorAll(":scope > li") ?? []).map((row) => row.querySelector(FOCUSABLE2)).filter((el) => !!el);
|
|
4650
3766
|
useEffect(() => {
|
|
4651
3767
|
const next = pending.current;
|
|
4652
3768
|
if (!next) return;
|
|
3769
|
+
const rows = () => Array.from(listRef.current?.querySelectorAll(":scope > li") ?? []);
|
|
3770
|
+
const firstFields = () => rows().map((row) => row.querySelector(FOCUSABLE2)).filter((el) => !!el);
|
|
3771
|
+
const ids = items.map((item) => getIdRef.current(item));
|
|
3772
|
+
if (next.kind === "remove") {
|
|
3773
|
+
if (ids.includes(next.id)) return;
|
|
3774
|
+
pending.current = null;
|
|
3775
|
+
focusAfterRemoval(firstFields(), next.index, addRef.current);
|
|
3776
|
+
return;
|
|
3777
|
+
}
|
|
3778
|
+
const added = ids.findIndex((id) => !next.before.has(id));
|
|
3779
|
+
if (added === -1) return;
|
|
4653
3780
|
pending.current = null;
|
|
4654
|
-
|
|
4655
|
-
|
|
4656
|
-
else focusAfterRemoval(fields, next.index, addRef.current);
|
|
4657
|
-
}, [items]);
|
|
3781
|
+
rows()[added]?.querySelector(FOCUSABLE2)?.focus();
|
|
3782
|
+
}, [items, getIdRef]);
|
|
4658
3783
|
const canRemove = items.length > minItems;
|
|
4659
3784
|
const canAdd = maxItems === void 0 || items.length < maxItems;
|
|
4660
3785
|
const grid = { "--gs-add-another-cols": `repeat(${columns.length}, minmax(0, 1fr)) max-content` };
|
|
@@ -4669,13 +3794,15 @@ function AddAnother({ items, getId, itemName, columns, renderRow, onAdd, onRemov
|
|
|
4669
3794
|
/* @__PURE__ */ jsx(AddAnotherRowCtx.Provider, { value: true, children: renderRow(item, index, (column) => `${column}, ${itemName(index)}`) }),
|
|
4670
3795
|
canRemove && // the visible "Remove" starts its name, which says whose row it removes (WCAG 2.5.3 label in name)
|
|
4671
3796
|
/* @__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 };
|
|
3797
|
+
pending.current = { kind: "remove", id, index };
|
|
3798
|
+
reportChange?.();
|
|
4673
3799
|
onRemove(id);
|
|
4674
3800
|
}, children: "Remove" })
|
|
4675
3801
|
] }, id);
|
|
4676
3802
|
}) }),
|
|
4677
3803
|
canAdd && /* @__PURE__ */ jsx("div", { children: /* @__PURE__ */ jsx(Button, { ref: addRef, type: "button", variant: "secondary", onClick: () => {
|
|
4678
|
-
pending.current = { kind: "add" };
|
|
3804
|
+
pending.current = { kind: "add", before: new Set(items.map(getId)) };
|
|
3805
|
+
reportChange?.();
|
|
4679
3806
|
onAdd();
|
|
4680
3807
|
}, children: addLabel }) })
|
|
4681
3808
|
] });
|
|
@@ -4695,7 +3822,7 @@ function TransferList({
|
|
|
4695
3822
|
className,
|
|
4696
3823
|
ref
|
|
4697
3824
|
}) {
|
|
4698
|
-
const onChange = useReportedChange(onChangeProp, selected);
|
|
3825
|
+
const onChange = useReportedChange(onChangeProp, selected, (_available, chosen) => chosen);
|
|
4699
3826
|
const [checkedAvailable, setCheckedAvailable] = useState(/* @__PURE__ */ new Set());
|
|
4700
3827
|
const [checkedSelected, setCheckedSelected] = useState(/* @__PURE__ */ new Set());
|
|
4701
3828
|
const [searchLeft, setSearchLeft] = useState("");
|
|
@@ -5225,50 +4352,25 @@ function MentionInput({
|
|
|
5225
4352
|
]
|
|
5226
4353
|
},
|
|
5227
4354
|
s.id
|
|
5228
|
-
))
|
|
5229
|
-
}
|
|
5230
|
-
),
|
|
5231
|
-
document.body
|
|
5232
|
-
)
|
|
5233
|
-
] });
|
|
5234
|
-
}
|
|
5235
|
-
var HEADER_LAYOUT = {
|
|
5236
|
-
row: "flex flex-wrap items-start justify-between gap-ds-4",
|
|
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",
|
|
5240
|
-
actions: "flex items-center gap-ds-2 shrink-0 ml-auto",
|
|
5241
|
-
below: "mt-ds-1.5"
|
|
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;
|
|
4355
|
+
))
|
|
4356
|
+
}
|
|
4357
|
+
),
|
|
4358
|
+
document.body
|
|
4359
|
+
)
|
|
4360
|
+
] });
|
|
5266
4361
|
}
|
|
5267
|
-
|
|
5268
|
-
|
|
5269
|
-
|
|
4362
|
+
var CardRowCtx = createContext(null);
|
|
4363
|
+
var TITLE_LINE = "h-[calc(var(--ds-font-size-lg)*var(--ds-line-height-lg))]";
|
|
4364
|
+
var HeaderRowCtx = createContext(false);
|
|
4365
|
+
function holdsHeader(children) {
|
|
4366
|
+
let found = false;
|
|
4367
|
+
Children.forEach(children, (child) => {
|
|
4368
|
+
if (found || !isValidElement(child)) return;
|
|
4369
|
+
if (child.type === Fragment$1) found = holdsHeader(child.props.children);
|
|
4370
|
+
else if (child.type === CardHeader) found = true;
|
|
4371
|
+
});
|
|
4372
|
+
return found;
|
|
5270
4373
|
}
|
|
5271
|
-
var CardCtx = createContext(false);
|
|
5272
4374
|
var CardActionCtx = createContext(null);
|
|
5273
4375
|
var CARD_ACTION_ATTR = "data-card-action";
|
|
5274
4376
|
var CardSurfaceCtx = createContext(false);
|
|
@@ -5419,7 +4521,7 @@ var Card = forwardRef(function Card2({
|
|
|
5419
4521
|
const handleKeyDown = isSelectable && !disabled ? (e) => {
|
|
5420
4522
|
if (e.key === "Enter" || e.key === " ") {
|
|
5421
4523
|
e.preventDefault();
|
|
5422
|
-
onSelectedChange?.(!selected);
|
|
4524
|
+
if (!e.repeat) onSelectedChange?.(!selected);
|
|
5423
4525
|
}
|
|
5424
4526
|
} : isAction && !disabled ? (e) => {
|
|
5425
4527
|
if (e.target !== e.currentTarget) return;
|
|
@@ -5436,13 +4538,84 @@ var Card = forwardRef(function Card2({
|
|
|
5436
4538
|
} : void 0;
|
|
5437
4539
|
const handleCheckableClick = (e) => {
|
|
5438
4540
|
e.stopPropagation();
|
|
5439
|
-
onSelectedChange?.(!selected);
|
|
4541
|
+
if (!disabled) onSelectedChange?.(!selected);
|
|
5440
4542
|
};
|
|
5441
4543
|
const isButton = isSelectable || isAction && !holdsControls;
|
|
5442
4544
|
const role = selectType === "radio" ? "radio" : selectType === "checkbox" ? "checkbox" : selectType === "toggle" ? "switch" : isButton ? "button" : void 0;
|
|
5443
4545
|
const ariaAttr = selectType === "radio" || selectType === "checkbox" || selectType === "toggle" ? { "aria-checked": !!selected } : isSelectable ? { "aria-pressed": !!selected } : {};
|
|
5444
4546
|
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;
|
|
5445
|
-
const defaultCheckBadge = !hasSelectType && !checkable && selected && !loading ? /* @__PURE__ */ jsx("
|
|
4547
|
+
const defaultCheckBadge = !hasSelectType && !checkable && selected && !loading ? /* @__PURE__ */ jsx("span", { "data-card-check": "", className: "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;
|
|
4548
|
+
const checkboxes = useRef(/* @__PURE__ */ new Set());
|
|
4549
|
+
const checkboxFocused = useRef(false);
|
|
4550
|
+
const checkboxRef = useCallback((node) => {
|
|
4551
|
+
if (!node) return;
|
|
4552
|
+
checkboxes.current.add(node);
|
|
4553
|
+
return () => {
|
|
4554
|
+
checkboxes.current.delete(node);
|
|
4555
|
+
};
|
|
4556
|
+
}, []);
|
|
4557
|
+
useLayoutEffect(() => {
|
|
4558
|
+
if (!checkboxFocused.current) return;
|
|
4559
|
+
const active = document.activeElement;
|
|
4560
|
+
if (active && active !== document.body) return;
|
|
4561
|
+
for (const node of checkboxes.current) {
|
|
4562
|
+
if (node.isConnected) {
|
|
4563
|
+
node.focus({ preventScroll: true });
|
|
4564
|
+
return;
|
|
4565
|
+
}
|
|
4566
|
+
}
|
|
4567
|
+
});
|
|
4568
|
+
const checkbox = checkable ? /* @__PURE__ */ jsx(
|
|
4569
|
+
"div",
|
|
4570
|
+
{
|
|
4571
|
+
ref: checkboxRef,
|
|
4572
|
+
"data-card-checkbox": "",
|
|
4573
|
+
className: cn(
|
|
4574
|
+
"rounded-[calc(var(--ds-radius-sm)*0.6)] focus-visible:outline-none focus-visible:shadow-[var(--ds-shadow-focus)]",
|
|
4575
|
+
disabled ? "cursor-not-allowed" : "cursor-pointer"
|
|
4576
|
+
),
|
|
4577
|
+
onClick: handleCheckableClick,
|
|
4578
|
+
role: "checkbox",
|
|
4579
|
+
"aria-checked": !!selected,
|
|
4580
|
+
"aria-disabled": disabled || void 0,
|
|
4581
|
+
...inner.titleId ? { "aria-labelledby": inner.titleId } : { "aria-label": "Select" },
|
|
4582
|
+
tabIndex: 0,
|
|
4583
|
+
onFocus: () => {
|
|
4584
|
+
checkboxFocused.current = true;
|
|
4585
|
+
},
|
|
4586
|
+
onBlur: (e) => {
|
|
4587
|
+
const node = e.currentTarget;
|
|
4588
|
+
queueMicrotask(() => {
|
|
4589
|
+
if (node.isConnected) checkboxFocused.current = false;
|
|
4590
|
+
});
|
|
4591
|
+
},
|
|
4592
|
+
onKeyDown: (e) => {
|
|
4593
|
+
if (e.key !== " ") return;
|
|
4594
|
+
e.preventDefault();
|
|
4595
|
+
e.stopPropagation();
|
|
4596
|
+
if (!e.repeat && !disabled) onSelectedChange?.(!selected);
|
|
4597
|
+
},
|
|
4598
|
+
children: /* @__PURE__ */ jsx(CheckboxIndicator, { checked: !!selected, disabled })
|
|
4599
|
+
}
|
|
4600
|
+
) : null;
|
|
4601
|
+
const check = indicator ?? defaultCheckBadge;
|
|
4602
|
+
const headers = useRef([]);
|
|
4603
|
+
const [owner, setOwner] = useState(null);
|
|
4604
|
+
const [guess, setGuess] = useState(() => holdsHeader(children));
|
|
4605
|
+
const register = useCallback((header) => {
|
|
4606
|
+
headers.current = [...headers.current, header];
|
|
4607
|
+
setOwner(headers.current[0]);
|
|
4608
|
+
return () => {
|
|
4609
|
+
headers.current = headers.current.filter((h) => h !== header);
|
|
4610
|
+
setOwner(headers.current[0] ?? null);
|
|
4611
|
+
setGuess(false);
|
|
4612
|
+
};
|
|
4613
|
+
}, []);
|
|
4614
|
+
useLayoutEffect(() => {
|
|
4615
|
+
if (headers.current.length === 0) setGuess(false);
|
|
4616
|
+
}, []);
|
|
4617
|
+
const hasHeader = owner !== null || guess;
|
|
4618
|
+
const rowParts = { checkbox, check, owner, register };
|
|
5446
4619
|
return /* @__PURE__ */ jsxs(
|
|
5447
4620
|
"div",
|
|
5448
4621
|
{
|
|
@@ -5473,32 +4646,22 @@ var Card = forwardRef(function Card2({
|
|
|
5473
4646
|
...ariaAttr,
|
|
5474
4647
|
...props,
|
|
5475
4648
|
children: [
|
|
5476
|
-
|
|
5477
|
-
|
|
5478
|
-
|
|
5479
|
-
"
|
|
5480
|
-
|
|
5481
|
-
|
|
5482
|
-
|
|
5483
|
-
role: "checkbox",
|
|
5484
|
-
"aria-checked": !!selected,
|
|
5485
|
-
...inner.titleId ? { "aria-labelledby": inner.titleId } : { "aria-label": "Select" },
|
|
5486
|
-
tabIndex: 0,
|
|
5487
|
-
onKeyDown: (e) => {
|
|
5488
|
-
if (e.key === "Enter" || e.key === " ") {
|
|
5489
|
-
e.preventDefault();
|
|
5490
|
-
e.stopPropagation();
|
|
5491
|
-
onSelectedChange?.(!selected);
|
|
5492
|
-
}
|
|
5493
|
-
},
|
|
5494
|
-
children: /* @__PURE__ */ jsx(CheckboxIndicator, { checked: !!selected })
|
|
5495
|
-
}
|
|
5496
|
-
),
|
|
5497
|
-
/* @__PURE__ */ jsx(CardSurfaceCtx, { value: true, children: /* @__PURE__ */ jsx(CardActionCtx, { value: action, children: /* @__PURE__ */ jsx(CardCtx, { value: checkable, children: loading ? (
|
|
4649
|
+
!loading && !hasHeader && checkbox && /* @__PURE__ */ jsxs("div", { "data-card-header-row": "", className: "flex items-center gap-ds-2 px-ds-5 pt-ds-4", children: [
|
|
4650
|
+
checkbox,
|
|
4651
|
+
/* @__PURE__ */ jsx("span", { "aria-hidden": "true", className: "grow" }),
|
|
4652
|
+
check && /* @__PURE__ */ jsx("span", { "data-card-selection": "", className: "shrink-0 flex", children: check })
|
|
4653
|
+
] }),
|
|
4654
|
+
!loading && !hasHeader && !checkbox && check && /* @__PURE__ */ jsx("div", { "data-card-selection": "", className: "absolute top-ds-3 right-ds-3 z-[1] flex", children: check }),
|
|
4655
|
+
/* @__PURE__ */ jsx(CardSurfaceCtx, { value: true, children: /* @__PURE__ */ jsx(CardActionCtx, { value: action, children: /* @__PURE__ */ jsx(CardRowCtx, { value: rowParts, children: loading ? (
|
|
5498
4656
|
// Round 15 (the owner's 52.1): a placeholder stands where the content will stand — inside the card's
|
|
5499
4657
|
// content inset (CardContent's padding), a title-height line then two body lines — never flush against the border.
|
|
5500
|
-
|
|
5501
|
-
|
|
4658
|
+
// Its header holds a badge-sized block (A2), so a grid of item cards keeps its columns when they load.
|
|
4659
|
+
/* @__PURE__ */ jsx("div", { "data-card-loading": "", "aria-busy": "true", className: "px-ds-5 py-ds-4", children: /* @__PURE__ */ jsxs("div", { className: "space-y-ds-3", children: [
|
|
4660
|
+
/* @__PURE__ */ jsxs("div", { "data-card-header-row": "", className: "flex items-center gap-ds-2", children: [
|
|
4661
|
+
checkbox,
|
|
4662
|
+
/* @__PURE__ */ jsx(Skeleton, { variant: "custom", className: "h-5 w-1/3" }),
|
|
4663
|
+
/* @__PURE__ */ jsx("div", { "data-header-actions": "", className: "contents", children: /* @__PURE__ */ jsx("div", { "data-gs-badge": "", className: "shrink-0", children: /* @__PURE__ */ jsx(Skeleton, { variant: "custom", className: "h-5 w-14 rounded-[var(--ds-radius-full)]" }) }) })
|
|
4664
|
+
] }),
|
|
5502
4665
|
/* @__PURE__ */ jsx(Skeleton, { variant: "custom", className: "h-3 w-full" }),
|
|
5503
4666
|
/* @__PURE__ */ jsx(Skeleton, { variant: "custom", className: "h-3 w-2/3" })
|
|
5504
4667
|
] }) })
|
|
@@ -5507,60 +4670,95 @@ var Card = forwardRef(function Card2({
|
|
|
5507
4670
|
}
|
|
5508
4671
|
);
|
|
5509
4672
|
});
|
|
5510
|
-
|
|
5511
|
-
const
|
|
5512
|
-
const
|
|
5513
|
-
|
|
5514
|
-
|
|
5515
|
-
|
|
5516
|
-
|
|
5517
|
-
|
|
5518
|
-
|
|
5519
|
-
|
|
5520
|
-
|
|
4673
|
+
function partsOf(children) {
|
|
4674
|
+
const parts = [];
|
|
4675
|
+
const open = (node) => Children.toArray(node).forEach((child) => {
|
|
4676
|
+
if (isValidElement(child) && child.type === Fragment$1) open(child.props.children);
|
|
4677
|
+
else if (child !== "") parts.push(child);
|
|
4678
|
+
});
|
|
4679
|
+
open(children);
|
|
4680
|
+
return parts;
|
|
4681
|
+
}
|
|
4682
|
+
function splitTitle(children) {
|
|
4683
|
+
const parts = partsOf(children);
|
|
4684
|
+
const at = parts.findIndex((p) => isValidElement(p) && p.type === CardTitle);
|
|
4685
|
+
if (at < 0) return { lead: [], title: parts[0] ?? null, rest: parts.slice(1) };
|
|
4686
|
+
return { lead: parts.slice(0, at), title: parts[at], rest: parts.slice(at + 1) };
|
|
4687
|
+
}
|
|
4688
|
+
var TITLE_FLOOR = "basis-[calc(var(--ds-font-size-lg)*4.5)]";
|
|
4689
|
+
var TITLE_ROW = cn(
|
|
4690
|
+
"flex flex-wrap items-start justify-end gap-x-ds-2 gap-y-ds-2 min-w-0 grow basis-0",
|
|
4691
|
+
"[&>[data-header-actions]>*]:order-5",
|
|
4692
|
+
"[&>[data-header-actions]>:has([data-gs-badge]):not(:has(a,button,input,select,textarea,[role=button],[tabindex]:not([tabindex='-1'])))]:order-2",
|
|
4693
|
+
"[&>[data-header-actions]>:has([aria-haspopup])]:order-6"
|
|
4694
|
+
);
|
|
4695
|
+
var CardHeader = forwardRef(function CardHeader2(allProps, ref) {
|
|
4696
|
+
const { className, children, actions, icon, menuItems, ...props } = allProps;
|
|
4697
|
+
const row = useContext(CardRowCtx);
|
|
4698
|
+
const [self] = useState(() => ({}));
|
|
4699
|
+
const register = row?.register;
|
|
4700
|
+
useLayoutEffect(() => register?.(self), [register, self]);
|
|
4701
|
+
const owns = !!row && row.owner === self;
|
|
4702
|
+
const iconBlock = icon ? (
|
|
4703
|
+
// the icon stays where it was, a tile above the title (28 of 66 headers with actions have one)
|
|
4704
|
+
/* @__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", children: /* @__PURE__ */ jsx(Icon, { name: icon, size: 20, className: "text-[var(--ds-text-secondary)]" }) })
|
|
4705
|
+
) : null;
|
|
4706
|
+
const menu = menuItems ? /* @__PURE__ */ jsx(
|
|
4707
|
+
DropdownMenu,
|
|
4708
|
+
{
|
|
4709
|
+
trigger: /* @__PURE__ */ jsx(
|
|
4710
|
+
"button",
|
|
4711
|
+
{
|
|
4712
|
+
type: "button",
|
|
4713
|
+
"aria-label": "More actions",
|
|
4714
|
+
className: cn(
|
|
4715
|
+
"inline-flex items-center justify-center h-8 w-8 rounded-[var(--ds-radius-md)]",
|
|
4716
|
+
"text-[var(--ds-text-muted)] hover:text-[var(--ds-text-primary)] hover:bg-[var(--ds-bg-muted)]",
|
|
4717
|
+
"transition-colors duration-[var(--ds-transition-speed)]"
|
|
4718
|
+
),
|
|
4719
|
+
onClick: (e) => e.stopPropagation(),
|
|
4720
|
+
children: /* @__PURE__ */ jsx(Icon, { name: "more-horizontal", size: 16 })
|
|
4721
|
+
}
|
|
4722
|
+
),
|
|
4723
|
+
items: menuItems
|
|
4724
|
+
}
|
|
4725
|
+
) : null;
|
|
4726
|
+
const band = (order) => cn("shrink-0 self-start flex items-center", TITLE_LINE, order);
|
|
4727
|
+
const checkbox = owns && row.checkbox ? /* @__PURE__ */ jsx("span", { className: band("order-0"), children: row.checkbox }) : null;
|
|
4728
|
+
const check = owns && row.check ? /* @__PURE__ */ jsx("span", { "data-card-selection": "", className: band("order-4"), children: row.check }) : null;
|
|
4729
|
+
const menuPart = menu ? /* @__PURE__ */ jsx("span", { className: band("order-6"), children: menu }) : null;
|
|
4730
|
+
const { lead, title, rest } = splitTitle(children);
|
|
4731
|
+
const leadBlock = lead.length > 0 ? /* @__PURE__ */ jsx("div", { "data-card-lead": "", className: "flex flex-col space-y-ds-1.5 min-w-0 grow", children: lead }) : null;
|
|
4732
|
+
const topLine = iconBlock ?? leadBlock;
|
|
4733
|
+
const ownBlock = title !== null && !(isValidElement(title) && title.type === CardTitle);
|
|
4734
|
+
const actionsSlot = "actions" in allProps ? /* @__PURE__ */ jsx("div", { "data-header-actions": "", className: "contents", children: partsOf(actions).map((item, i) => /* @__PURE__ */ jsx("span", { className: cn("flex items-center shrink-0", TITLE_LINE), children: item }, isValidElement(item) && item.key !== null ? item.key : i)) }) : null;
|
|
4735
|
+
return /* @__PURE__ */ jsxs("div", { ref, "data-card-header": "", className: cn("flex flex-col px-ds-5 pt-ds-4 last:pb-ds-4 min-w-0", className), ...props, children: [
|
|
4736
|
+
topLine && /* @__PURE__ */ jsxs("div", { "data-card-icon-row": iconBlock ? "" : void 0, "data-card-lead-row": iconBlock ? void 0 : "", className: cn("flex items-start gap-ds-2", iconBlock ? "mb-ds-2.5" : "mb-ds-1.5"), children: [
|
|
4737
|
+
checkbox,
|
|
4738
|
+
topLine,
|
|
4739
|
+
iconBlock && /* @__PURE__ */ jsx("span", { "aria-hidden": "true", className: "grow -ml-ds-2" }),
|
|
4740
|
+
check,
|
|
4741
|
+
menuPart
|
|
4742
|
+
] }),
|
|
4743
|
+
iconBlock && leadBlock && /* @__PURE__ */ jsx("div", { className: "flex mb-ds-1.5", children: leadBlock }),
|
|
4744
|
+
/* @__PURE__ */ jsxs("div", { "data-card-header-row": "", className: "flex items-start gap-ds-2 min-w-0", children: [
|
|
4745
|
+
!topLine && checkbox,
|
|
4746
|
+
/* @__PURE__ */ jsxs("div", { "data-card-title-line": "", className: TITLE_ROW, children: [
|
|
4747
|
+
title && /* @__PURE__ */ jsx(
|
|
4748
|
+
"div",
|
|
5521
4749
|
{
|
|
5522
|
-
|
|
5523
|
-
"
|
|
5524
|
-
|
|
5525
|
-
"inline-flex items-center justify-center h-8 w-8 rounded-[var(--ds-radius-md)]",
|
|
5526
|
-
"text-[var(--ds-text-muted)] hover:text-[var(--ds-text-primary)] hover:bg-[var(--ds-bg-muted)]",
|
|
5527
|
-
"transition-colors duration-[var(--ds-transition-speed)]"
|
|
5528
|
-
),
|
|
5529
|
-
onClick: (e) => e.stopPropagation(),
|
|
5530
|
-
children: /* @__PURE__ */ jsx(Icon, { name: "more-horizontal", size: 16 })
|
|
4750
|
+
"data-card-title-row": "",
|
|
4751
|
+
className: cn("order-1 min-w-0 me-auto", TITLE_FLOOR, ownBlock ? "grow" : "grow-[999] max-w-max"),
|
|
4752
|
+
children: /* @__PURE__ */ jsx(HeaderRowCtx, { value: true, children: title })
|
|
5531
4753
|
}
|
|
5532
4754
|
),
|
|
5533
|
-
|
|
5534
|
-
|
|
5535
|
-
)
|
|
5536
|
-
] }) : null;
|
|
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);
|
|
5542
|
-
if (hasActions) {
|
|
5543
|
-
if (titleLeads) {
|
|
5544
|
-
const below = parts.slice(1);
|
|
5545
|
-
return /* @__PURE__ */ jsxs("div", { ref, className: cn(pl, "pr-ds-5 pt-ds-4 last:pb-ds-4", className), ...props, children: [
|
|
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] }),
|
|
5548
|
-
actionsBlock
|
|
5549
|
-
] }),
|
|
5550
|
-
below.length > 0 && /* @__PURE__ */ jsx("div", { className: cn("flex flex-col space-y-ds-1.5 break-words", HEADER_LAYOUT.below), children: below })
|
|
5551
|
-
] });
|
|
5552
|
-
}
|
|
5553
|
-
return /* @__PURE__ */ jsx("div", { ref, className: cn(pl, "pr-ds-5 pt-ds-4 last:pb-ds-4", className), ...props, children: /* @__PURE__ */ jsxs("div", { className: HEADER_LAYOUT.row, children: [
|
|
5554
|
-
/* @__PURE__ */ jsxs("div", { className: HEADER_LAYOUT.block, children: [
|
|
5555
|
-
iconBlock,
|
|
5556
|
-
children
|
|
4755
|
+
actionsSlot,
|
|
4756
|
+
!ownBlock && /* @__PURE__ */ jsx("span", { "aria-hidden": "true", className: "order-3 grow basis-0 -ml-ds-2" })
|
|
5557
4757
|
] }),
|
|
5558
|
-
|
|
5559
|
-
|
|
5560
|
-
|
|
5561
|
-
|
|
5562
|
-
iconBlock,
|
|
5563
|
-
children
|
|
4758
|
+
!topLine && check,
|
|
4759
|
+
!topLine && menuPart
|
|
4760
|
+
] }),
|
|
4761
|
+
rest.length > 0 && /* @__PURE__ */ jsx("div", { className: "flex flex-col space-y-ds-1.5 break-words mt-ds-1.5 min-w-0", children: rest })
|
|
5564
4762
|
] });
|
|
5565
4763
|
});
|
|
5566
4764
|
var cardLineClampClasses = {
|
|
@@ -5571,7 +4769,10 @@ var cardLineClampClasses = {
|
|
|
5571
4769
|
5: "line-clamp-5",
|
|
5572
4770
|
6: "line-clamp-6"
|
|
5573
4771
|
};
|
|
5574
|
-
var
|
|
4772
|
+
var WHOLE_ON_KEYBOARD = "[[data-card]:has(:focus-visible)_&]:whitespace-normal [[data-card]:has(:focus-visible)_&]:line-clamp-none";
|
|
4773
|
+
var CardTitle = forwardRef(function CardTitle2({ className, children, lines: linesProp, id, ...props }, forwardedRef) {
|
|
4774
|
+
const inHeaderRow = useContext(HeaderRowCtx);
|
|
4775
|
+
const lines = linesProp ?? (inHeaderRow ? 1 : 2);
|
|
5575
4776
|
const action = useContext(CardActionCtx);
|
|
5576
4777
|
const generatedId = useId();
|
|
5577
4778
|
const { ref: overflowRef, isTruncated } = useTextOverflow({ lines, disabled: lines === 0 });
|
|
@@ -5587,7 +4788,7 @@ var CardTitle = forwardRef(function CardTitle2({ className, children, lines = 2,
|
|
|
5587
4788
|
id: id ?? generatedId,
|
|
5588
4789
|
"data-card-title": "",
|
|
5589
4790
|
...lines === 1 ? { "data-title-one-line": "" } : {},
|
|
5590
|
-
className: cn(TITLE_TEXT, !action && lines > 0 && lineClampClass, action && lines === 1 && "text-ellipsis", className),
|
|
4791
|
+
className: cn(TITLE_TEXT, !action && lines > 0 && [lineClampClass, WHOLE_ON_KEYBOARD], action && lines === 1 && "text-ellipsis", className),
|
|
5591
4792
|
...props,
|
|
5592
4793
|
children: action ? (
|
|
5593
4794
|
// The card's action when the card holds controls of its own (Sprint 25.7): a real button, which a click
|
|
@@ -5604,14 +4805,13 @@ var CardTitle = forwardRef(function CardTitle2({ className, children, lines = 2,
|
|
|
5604
4805
|
"block w-full text-left cursor-pointer [text-overflow:inherit] focus-visible:outline-none disabled:cursor-not-allowed",
|
|
5605
4806
|
"after:absolute after:inset-0 after:rounded-[var(--ds-radius-md)] after:pointer-events-none focus-visible:after:shadow-[var(--ds-shadow-focus)]"
|
|
5606
4807
|
),
|
|
5607
|
-
children: /* @__PURE__ */ jsx("span", { ref: (node) => overflowRef(lines > 0 ? node : null), className: cn("block [text-overflow:inherit]", lines > 0 && lineClampClass), children })
|
|
4808
|
+
children: /* @__PURE__ */ jsx("span", { ref: (node) => overflowRef(lines > 0 ? node : null), className: cn("block [text-overflow:inherit]", lines > 0 && [lineClampClass, WHOLE_ON_KEYBOARD]), children })
|
|
5608
4809
|
}
|
|
5609
4810
|
)
|
|
5610
4811
|
) : children
|
|
5611
4812
|
}
|
|
5612
4813
|
);
|
|
5613
|
-
|
|
5614
|
-
return /* @__PURE__ */ jsx(Tooltip, { content: children, children: heading });
|
|
4814
|
+
return /* @__PURE__ */ jsx(Tooltip, { content: children, disabled: !isTruncated, children: heading });
|
|
5615
4815
|
});
|
|
5616
4816
|
var CardDescription = forwardRef(function CardDescription2({ className, children, lines = 2, ...props }, forwardedRef) {
|
|
5617
4817
|
const { ref: overflowRef, isTruncated } = useTextOverflow({ lines, disabled: lines === 0 });
|
|
@@ -5629,18 +4829,15 @@ var CardDescription = forwardRef(function CardDescription2({ className, children
|
|
|
5629
4829
|
children
|
|
5630
4830
|
}
|
|
5631
4831
|
);
|
|
5632
|
-
|
|
5633
|
-
return /* @__PURE__ */ jsx(Tooltip, { content: children, children: el });
|
|
4832
|
+
return /* @__PURE__ */ jsx(Tooltip, { content: children, disabled: !isTruncated, children: el });
|
|
5634
4833
|
});
|
|
5635
4834
|
var CardContent = forwardRef(function CardContent2({ className, children, ...props }, ref) {
|
|
5636
|
-
|
|
5637
|
-
return /* @__PURE__ */ jsx("div", { ref, className: cn("flex-1 pr-ds-5 py-ds-4", isCheckable ? "pl-ds-10" : "pl-ds-5", className), ...props, children });
|
|
4835
|
+
return /* @__PURE__ */ jsx("div", { ref, className: cn("flex-1 px-ds-5 py-ds-4", className), ...props, children });
|
|
5638
4836
|
});
|
|
5639
4837
|
var CardFooter = forwardRef(function CardFooter2({ className, children, ...props }, ref) {
|
|
5640
|
-
const isCheckable = useContext(CardCtx);
|
|
5641
4838
|
return (
|
|
5642
4839
|
// a footer that holds only buttons puts them at the end (round 11: a lone Save sat on the left); text keeps the start
|
|
5643
|
-
/* @__PURE__ */ jsx("div", { ref, className: cn("flex items-center gap-ds-2
|
|
4840
|
+
/* @__PURE__ */ jsx("div", { ref, className: cn("flex items-center gap-ds-2 px-ds-5 pb-ds-4 pt-ds-2 mt-auto min-w-0 [&:not(:has(>:not(button)))]:justify-end", className), ...props, children })
|
|
5644
4841
|
);
|
|
5645
4842
|
});
|
|
5646
4843
|
function TruncLabel({ children }) {
|
|
@@ -5756,6 +4953,9 @@ function DataList({ items, columns = 1, className }) {
|
|
|
5756
4953
|
);
|
|
5757
4954
|
}
|
|
5758
4955
|
var COUNT_FROM_PAGE = [
|
|
4956
|
+
// one card counts too: a lone card fell back to React's count, which counts components that draw nothing, and a grid
|
|
4957
|
+
// with one card inside another took the outer grid's count (the review of 30 September)
|
|
4958
|
+
"[&:has(>:only-child)]:[--gs-cards:1]",
|
|
5759
4959
|
"[&:has(>:nth-child(2):last-child)]:[--gs-cards:2]",
|
|
5760
4960
|
"[&:has(>:nth-child(3):last-child)]:[--gs-cards:3]",
|
|
5761
4961
|
"[&:has(>:nth-child(4):last-child)]:[--gs-cards:4]",
|
|
@@ -5768,6 +4968,7 @@ var COUNT_FROM_PAGE = [
|
|
|
5768
4968
|
"[&:has(>:nth-child(11):last-child)]:[--gs-cards:11]",
|
|
5769
4969
|
"[&:has(>:nth-child(12))]:[--gs-cards:12]"
|
|
5770
4970
|
].join(" ");
|
|
4971
|
+
var MIN_FROM_HEADERS = "[--gs-card-min:14rem] has-[[data-header-actions]]:[--gs-card-min:20rem]";
|
|
5771
4972
|
function countCards(children) {
|
|
5772
4973
|
let n = 0;
|
|
5773
4974
|
Children.forEach(children, (child) => {
|
|
@@ -5776,14 +4977,18 @@ function countCards(children) {
|
|
|
5776
4977
|
});
|
|
5777
4978
|
return n;
|
|
5778
4979
|
}
|
|
5779
|
-
function CardGrid({ minWidth
|
|
4980
|
+
function CardGrid({ minWidth, maxColumns = 4, compare = false, gap = "var(--ds-space-4)", fill: fill2 = true, className, style, children, ref, ...props }) {
|
|
5780
4981
|
const most = Math.max(1, Math.floor(maxColumns));
|
|
5781
|
-
const
|
|
5782
|
-
const
|
|
5783
|
-
const
|
|
4982
|
+
const drawn = "var(--gs-cards, var(--gs-cards-counted))";
|
|
4983
|
+
const min = "var(--gs-card-min)";
|
|
4984
|
+
const shareOf = (n) => `calc((100% - (${n} - 1) * var(--gs-card-gap)) / ${n})`;
|
|
4985
|
+
const collection = `max(min(${min}, 100%), ${shareOf(String(most))})`;
|
|
4986
|
+
const column = compare ? `max(${shareOf(drawn)}, min(100%, calc((${drawn} * ${min} + (${drawn} - 1) * var(--gs-card-gap) - 100%) * 999)))` : fill2 ? `max(${shareOf(`max(${drawn}, 2)`)}, ${collection})` : collection;
|
|
5784
4987
|
const template = {
|
|
5785
4988
|
"--gs-card-gap": gap,
|
|
5786
|
-
|
|
4989
|
+
// A2: a width passed wins; a comparison keeps 14rem; a collection's comes from its headers (MIN_FROM_HEADERS)
|
|
4990
|
+
...minWidth ? { "--gs-card-min": minWidth } : compare ? { "--gs-card-min": "14rem" } : {},
|
|
4991
|
+
...compare || fill2 ? { "--gs-cards-counted": Math.max(1, countCards(children)) } : {},
|
|
5787
4992
|
gap: "var(--gs-card-gap)",
|
|
5788
4993
|
gridTemplateColumns: `repeat(auto-fill, minmax(${column}, 1fr))`,
|
|
5789
4994
|
// a comparison's cards share their rows: the headers, the contents and the footers line up across the row
|
|
@@ -5796,7 +5001,8 @@ function CardGrid({ minWidth = "14rem", maxColumns = 4, compare = false, gap = "
|
|
|
5796
5001
|
"data-card-grid": compare ? "compare" : "",
|
|
5797
5002
|
className: cn(
|
|
5798
5003
|
"grid",
|
|
5799
|
-
compare &&
|
|
5004
|
+
!minWidth && !compare && MIN_FROM_HEADERS,
|
|
5005
|
+
(compare || fill2) && COUNT_FROM_PAGE,
|
|
5800
5006
|
// each card spans its three rows and lays its parts in them; anything else just fills them
|
|
5801
5007
|
compare && "[&>*]:row-span-3 [&>[data-card]]:grid [&>[data-card]]:grid-rows-subgrid [&>[data-card]]:gap-y-0",
|
|
5802
5008
|
className
|
|
@@ -6084,7 +5290,7 @@ var EDGE_FADE = 24;
|
|
|
6084
5290
|
var NONE = { left: false, right: false, vertical: false, gutterRight: 0, gutterBottom: 0 };
|
|
6085
5291
|
var same = (a, b) => a.left === b.left && a.right === b.right && a.vertical === b.vertical && a.gutterRight === b.gutterRight && a.gutterBottom === b.gutterBottom;
|
|
6086
5292
|
function useScrollEdges(options = {}) {
|
|
6087
|
-
const { enabled = true, fade = EDGE_FADE } = options;
|
|
5293
|
+
const { enabled = true, fade = EDGE_FADE, noFade } = options;
|
|
6088
5294
|
const elRef = useRef(null);
|
|
6089
5295
|
const observer = useRef(null);
|
|
6090
5296
|
const borders = useRef({ x: 0, y: 0 });
|
|
@@ -6116,9 +5322,11 @@ function useScrollEdges(options = {}) {
|
|
|
6116
5322
|
for (const child of Array.from(el.children)) o.observe(child);
|
|
6117
5323
|
observer.current = o;
|
|
6118
5324
|
}, [enabled, measure]);
|
|
6119
|
-
const
|
|
5325
|
+
const fadeLeft = state.left && !noFade?.left;
|
|
5326
|
+
const fadeRight = state.right && !noFade?.right;
|
|
5327
|
+
const shown = enabled && (fadeLeft || fadeRight);
|
|
6120
5328
|
const { gutterRight: gr, gutterBottom: gb } = state;
|
|
6121
|
-
const fadeLayer = `linear-gradient(to right, ${
|
|
5329
|
+
const fadeLayer = `linear-gradient(to right, ${fadeLeft ? `transparent 0, black ${fade}px` : "black 0"}, ${fadeRight ? `black calc(100% - ${gr + fade}px), transparent calc(100% - ${gr}px)` : "black 100%"})`;
|
|
6122
5330
|
const gutters = [gb > 0 && { size: `100% ${gb}px`, position: "0 100%" }, gr > 0 && { size: `${gr}px 100%`, position: "100% 0" }].filter(Boolean);
|
|
6123
5331
|
const mask = shown ? {
|
|
6124
5332
|
image: [fadeLayer, ...gutters.map(() => "linear-gradient(black, black)")].join(", "),
|
|
@@ -6131,18 +5339,54 @@ function useScrollEdges(options = {}) {
|
|
|
6131
5339
|
/** The scroller itself, for code that moves it. */
|
|
6132
5340
|
elRef,
|
|
6133
5341
|
measure,
|
|
6134
|
-
/** Content hides past a side edge: the scroller moves sideways, and its edges fade. */
|
|
6135
|
-
overflowing:
|
|
5342
|
+
/** Content hides past a side edge: the scroller moves sideways, and its edges fade (but those in `noFade`). */
|
|
5343
|
+
overflowing: enabled && (state.left || state.right),
|
|
6136
5344
|
/** It scrolls either way, sideways or up and down: a keyboard needs to reach it. */
|
|
6137
5345
|
scrollable: enabled && (state.left || state.right || state.vertical),
|
|
6138
5346
|
edges: { left: state.left, right: state.right },
|
|
6139
5347
|
/** For the scroller: `data-fade` names the faded edges ("left", "right" or "left right"), the style masks them. */
|
|
6140
5348
|
fadeProps: {
|
|
6141
|
-
"data-fade": shown ? [
|
|
5349
|
+
"data-fade": shown ? [fadeLeft && "left", fadeRight && "right"].filter(Boolean).join(" ") : void 0,
|
|
6142
5350
|
style: mask ? { maskImage: mask.image, WebkitMaskImage: mask.image, maskSize: mask.size, WebkitMaskSize: mask.size, maskPosition: mask.position, WebkitMaskPosition: mask.position, maskRepeat: "no-repeat", WebkitMaskRepeat: "no-repeat" } : void 0
|
|
6143
5351
|
}
|
|
6144
5352
|
};
|
|
6145
5353
|
}
|
|
5354
|
+
var HEADER_LAYOUT = {
|
|
5355
|
+
row: "flex flex-wrap items-start justify-between gap-ds-4",
|
|
5356
|
+
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",
|
|
5357
|
+
titleLeads: "grow basis-1/2 max-w-max break-words has-[[data-title-one-line]]:min-w-0",
|
|
5358
|
+
floorOff: "min-w-0",
|
|
5359
|
+
actions: "flex items-center gap-ds-2 shrink-0 ml-auto",
|
|
5360
|
+
below: "mt-ds-1.5"
|
|
5361
|
+
};
|
|
5362
|
+
function useTitleFloorFits(rowRef, active) {
|
|
5363
|
+
const [fits, setFits] = useState(true);
|
|
5364
|
+
useLayoutEffect(() => {
|
|
5365
|
+
const row = rowRef.current;
|
|
5366
|
+
if (!active || !row) return;
|
|
5367
|
+
const measure = () => {
|
|
5368
|
+
const title = row.querySelector("h1, h2, h3, h4, h5, h6");
|
|
5369
|
+
if (!title) return;
|
|
5370
|
+
const width = title.style.width;
|
|
5371
|
+
title.style.width = "min-content";
|
|
5372
|
+
const longest = title.getBoundingClientRect().width;
|
|
5373
|
+
title.style.width = width;
|
|
5374
|
+
if (longest === 0) return;
|
|
5375
|
+
const next = longest <= row.clientWidth + 0.5;
|
|
5376
|
+
setFits((was) => was === next ? was : next);
|
|
5377
|
+
};
|
|
5378
|
+
measure();
|
|
5379
|
+
if (typeof ResizeObserver === "undefined") return;
|
|
5380
|
+
const observer = new ResizeObserver(measure);
|
|
5381
|
+
observer.observe(row);
|
|
5382
|
+
return () => observer.disconnect();
|
|
5383
|
+
}, [rowRef, active]);
|
|
5384
|
+
return fits;
|
|
5385
|
+
}
|
|
5386
|
+
function actionsAreBadges(actions) {
|
|
5387
|
+
const items = Children.toArray(actions);
|
|
5388
|
+
return items.length > 0 && items.every((item) => isValidElement(item) && (item.type === Fragment$1 ? actionsAreBadges(item.props.children) : item.type === Badge));
|
|
5389
|
+
}
|
|
6146
5390
|
function TruncCell({ children, lines }) {
|
|
6147
5391
|
const { ref, isTruncated } = useTextOverflow({ lines });
|
|
6148
5392
|
const clampClass = lines === 1 ? "truncate" : `line-clamp-${lines}`;
|
|
@@ -6157,6 +5401,95 @@ var FRAME_CLASSES = cn(
|
|
|
6157
5401
|
GLASS_SURFACE,
|
|
6158
5402
|
"bg-[var(--ds-bg-surface)]"
|
|
6159
5403
|
);
|
|
5404
|
+
var PINNED_BACKGROUND = "linear-gradient(var(--gs-row-tint, transparent), var(--gs-row-tint, transparent)), linear-gradient(var(--gs-pinned-surface), var(--gs-pinned-surface)), var(--gs-pinned-canvas)";
|
|
5405
|
+
var PINNED_LAYERS = cn(
|
|
5406
|
+
"[--gs-pinned-surface:var(--ds-bg-surface)] [--gs-pinned-canvas:var(--ds-bg-canvas)]",
|
|
5407
|
+
"supports-[color:oklch(from_red_l_c_h)]:[--gs-pinned-surface:oklch(from_var(--ds-bg-surface)_l_c_h_/_max(alpha,min(1,alpha*1000)))]",
|
|
5408
|
+
"supports-[color:oklch(from_red_l_c_h)]:[--gs-pinned-canvas:oklch(from_var(--ds-bg-canvas)_l_c_h_/_1)]"
|
|
5409
|
+
);
|
|
5410
|
+
var PIN_SHADOW = "oklch(0 0 0 / 0.18)";
|
|
5411
|
+
var ROW_CONTROL = `${FOCUSABLE}, label, [role="button"], [role="checkbox"], [role="switch"], [role="menuitem"], [role="link"]`;
|
|
5412
|
+
function clickIsRows(e) {
|
|
5413
|
+
const target = e.target;
|
|
5414
|
+
if (!(target instanceof Element) || !e.currentTarget.contains(target)) return false;
|
|
5415
|
+
const selection = typeof window !== "undefined" ? window.getSelection() : null;
|
|
5416
|
+
if (selection && !selection.isCollapsed && selection.anchorNode && e.currentTarget.contains(selection.anchorNode)) return false;
|
|
5417
|
+
const control = target.closest(ROW_CONTROL);
|
|
5418
|
+
return !control || control === e.currentTarget || !e.currentTarget.contains(control);
|
|
5419
|
+
}
|
|
5420
|
+
function sortableValue(v) {
|
|
5421
|
+
if (v === null || v === void 0 || v === "") return void 0;
|
|
5422
|
+
if (v instanceof Date) return v.getTime();
|
|
5423
|
+
if (typeof v === "string" || typeof v === "number") return v;
|
|
5424
|
+
if (typeof v === "boolean") return v ? 1 : 0;
|
|
5425
|
+
return isValidElement(v) || typeof v === "object" ? null : String(v);
|
|
5426
|
+
}
|
|
5427
|
+
var COLLATOR = new Intl.Collator(void 0, { numeric: true });
|
|
5428
|
+
function compareValues(a, b) {
|
|
5429
|
+
if (typeof a === "number" && typeof b === "number") return a - b;
|
|
5430
|
+
return COLLATOR.compare(String(a), String(b));
|
|
5431
|
+
}
|
|
5432
|
+
var UNIT_SCALE = {
|
|
5433
|
+
"": 1,
|
|
5434
|
+
"%": 1,
|
|
5435
|
+
b: 1,
|
|
5436
|
+
byte: 1,
|
|
5437
|
+
bytes: 1,
|
|
5438
|
+
kb: 1e3,
|
|
5439
|
+
kib: 1024,
|
|
5440
|
+
mb: 1e6,
|
|
5441
|
+
mib: 1024 ** 2,
|
|
5442
|
+
gb: 1e9,
|
|
5443
|
+
gib: 1024 ** 3,
|
|
5444
|
+
tb: 1e12,
|
|
5445
|
+
tib: 1024 ** 4,
|
|
5446
|
+
pb: 1e15,
|
|
5447
|
+
pib: 1024 ** 5,
|
|
5448
|
+
ms: 1,
|
|
5449
|
+
s: 1e3,
|
|
5450
|
+
sec: 1e3,
|
|
5451
|
+
min: 6e4,
|
|
5452
|
+
h: 36e5,
|
|
5453
|
+
hr: 36e5,
|
|
5454
|
+
hrs: 36e5,
|
|
5455
|
+
g: 1,
|
|
5456
|
+
kg: 1e3,
|
|
5457
|
+
m: 1,
|
|
5458
|
+
km: 1e3,
|
|
5459
|
+
"\xB0c": 1,
|
|
5460
|
+
"\xB0f": 1
|
|
5461
|
+
};
|
|
5462
|
+
function numberOf(text) {
|
|
5463
|
+
const m = /^\s*([-\u2212])?\s*[$€£¥]?\s*([-\u2212])?\s*(\d[\d,]*\.?\d*|\.\d+)\s*(%|°[CF]|[a-z]*)\s*$/i.exec(text);
|
|
5464
|
+
const scale = m ? UNIT_SCALE[m[4].toLowerCase()] : void 0;
|
|
5465
|
+
if (!m || scale === void 0) return void 0;
|
|
5466
|
+
const n = parseFloat(m[3].replace(/,/g, ""));
|
|
5467
|
+
return Number.isFinite(n) ? (m[1] || m[2] ? -1 : 1) * n * scale : void 0;
|
|
5468
|
+
}
|
|
5469
|
+
function timeOf(text) {
|
|
5470
|
+
const t = Date.parse(text);
|
|
5471
|
+
return Number.isNaN(t) ? void 0 : t;
|
|
5472
|
+
}
|
|
5473
|
+
function rowIdsOf(data, field) {
|
|
5474
|
+
const seen = /* @__PURE__ */ new Set();
|
|
5475
|
+
let repeated = null;
|
|
5476
|
+
const ids = data.map((row, index) => {
|
|
5477
|
+
const v = row[field];
|
|
5478
|
+
if (typeof v !== "string" && typeof v !== "number") return index;
|
|
5479
|
+
if (!seen.has(String(v))) {
|
|
5480
|
+
seen.add(String(v));
|
|
5481
|
+
return v;
|
|
5482
|
+
}
|
|
5483
|
+
repeated ??= String(v);
|
|
5484
|
+
return `${v}~${index}`;
|
|
5485
|
+
});
|
|
5486
|
+
return { ids, repeated };
|
|
5487
|
+
}
|
|
5488
|
+
function rowMarks(row, index, field, id) {
|
|
5489
|
+
const v = row[field];
|
|
5490
|
+
return typeof v === "string" || typeof v === "number" ? { "data-row-key": String(id) } : { "data-row-index": String(index) };
|
|
5491
|
+
}
|
|
5492
|
+
var idPart = (id) => String(id).replace(/\s+/g, "_");
|
|
6160
5493
|
function TableHeading({ title, description, actions, titleId, descriptionId, inset }) {
|
|
6161
5494
|
const heading = /* @__PURE__ */ jsx("h3", { id: titleId, className: TITLE_CLASSES, children: title });
|
|
6162
5495
|
const actionsBlock = actions ? /* @__PURE__ */ jsx("div", { className: HEADER_LAYOUT.actions, children: actions }) : null;
|
|
@@ -6178,8 +5511,10 @@ function TableHeading({ title, description, actions, titleId, descriptionId, ins
|
|
|
6178
5511
|
descriptionText(HEADER_LAYOUT.below)
|
|
6179
5512
|
] }) });
|
|
6180
5513
|
}
|
|
5514
|
+
var NO_PINS = { start: [], end: [], nameFits: false, frame: 0 };
|
|
5515
|
+
var samePins = (a, b) => a.nameFits === b.nameFits && a.frame === b.frame && a.start.join() === b.start.join() && a.end.join() === b.end.join();
|
|
6181
5516
|
function Table({
|
|
6182
|
-
columns,
|
|
5517
|
+
columns: columnsProp,
|
|
6183
5518
|
data,
|
|
6184
5519
|
className,
|
|
6185
5520
|
sortable,
|
|
@@ -6191,6 +5526,10 @@ function Table({
|
|
|
6191
5526
|
onSelectionChange,
|
|
6192
5527
|
expandable,
|
|
6193
5528
|
renderExpanded,
|
|
5529
|
+
rowKey = "id",
|
|
5530
|
+
expandedRows: expandedRowsProp,
|
|
5531
|
+
defaultExpandedRows,
|
|
5532
|
+
onExpandedChange,
|
|
6194
5533
|
density = "default",
|
|
6195
5534
|
stickyHeader = false,
|
|
6196
5535
|
striped = false,
|
|
@@ -6198,6 +5537,8 @@ function Table({
|
|
|
6198
5537
|
emptyState,
|
|
6199
5538
|
onRowClick,
|
|
6200
5539
|
mobileBreakpoint: mobileBreakpointProp,
|
|
5540
|
+
cardsBelow = CARDS_BELOW,
|
|
5541
|
+
pager,
|
|
6201
5542
|
title,
|
|
6202
5543
|
description,
|
|
6203
5544
|
actions,
|
|
@@ -6209,7 +5550,10 @@ function Table({
|
|
|
6209
5550
|
const descriptionId = `${headingId}-description`;
|
|
6210
5551
|
const [internalSortKey, setInternalSortKey] = useState(null);
|
|
6211
5552
|
const [internalSortDir, setInternalSortDir] = useState(null);
|
|
6212
|
-
const
|
|
5553
|
+
const columns = useMemo(
|
|
5554
|
+
() => [...columnsProp.filter((c) => c.pin === "start"), ...columnsProp.filter((c) => !c.pin), ...columnsProp.filter((c) => c.pin === "end")],
|
|
5555
|
+
[columnsProp]
|
|
5556
|
+
);
|
|
6213
5557
|
const isControlled = controlledSortKey !== void 0;
|
|
6214
5558
|
const sortKey = isControlled ? controlledSortKey : internalSortKey;
|
|
6215
5559
|
const sortDir = isControlled ? controlledSortDir ?? null : internalSortDir;
|
|
@@ -6229,6 +5573,7 @@ function Table({
|
|
|
6229
5573
|
nextKey = key;
|
|
6230
5574
|
nextDir = "asc";
|
|
6231
5575
|
}
|
|
5576
|
+
pager?.setPage(1);
|
|
6232
5577
|
if (onSortChange) {
|
|
6233
5578
|
onSortChange(nextKey, nextDir);
|
|
6234
5579
|
} else {
|
|
@@ -6236,139 +5581,348 @@ function Table({
|
|
|
6236
5581
|
setInternalSortDir(nextDir);
|
|
6237
5582
|
}
|
|
6238
5583
|
},
|
|
6239
|
-
[sortKey, sortDir, onSortChange]
|
|
5584
|
+
[sortKey, sortDir, onSortChange, pager]
|
|
5585
|
+
);
|
|
5586
|
+
const columnKeys = useMemo(() => columns.map((c) => c.key), [columns]);
|
|
5587
|
+
const inferredKinds = useMemo(() => inferColumnKinds(data, columnKeys), [data, columnKeys]);
|
|
5588
|
+
const kindOf = useCallback(
|
|
5589
|
+
(col) => col.kind ?? inferredKinds.get(col.key),
|
|
5590
|
+
[inferredKinds]
|
|
5591
|
+
);
|
|
5592
|
+
const sortColumn = sortKey ? columns.find((c) => c.key === sortKey) : void 0;
|
|
5593
|
+
const sortKind = sortColumn ? kindOf(sortColumn) : void 0;
|
|
5594
|
+
const { sortedAll, unsortable } = useMemo(() => {
|
|
5595
|
+
const indexed = data.map((row, i) => ({ row, originalIdx: i }));
|
|
5596
|
+
if (!sortKey || !sortDir) return { sortedAll: indexed, unsortable: null };
|
|
5597
|
+
const read = (row) => {
|
|
5598
|
+
if (sortColumn?.sortValue) return sortableValue(sortColumn.sortValue(row));
|
|
5599
|
+
const v = sortableValue(row[sortKey]);
|
|
5600
|
+
if (typeof v !== "string") return v;
|
|
5601
|
+
return (sortKind === "number" ? numberOf(v) : sortKind === "date" ? timeOf(v) : void 0) ?? v;
|
|
5602
|
+
};
|
|
5603
|
+
const valued = indexed.map((entry) => ({ ...entry, value: read(entry.row) }));
|
|
5604
|
+
const elements = valued.some((v) => v.value === null);
|
|
5605
|
+
const sorted = elements ? indexed : valued.sort((a, b) => {
|
|
5606
|
+
if (a.value === void 0 || b.value === void 0) return a.value === b.value ? 0 : a.value === void 0 ? 1 : -1;
|
|
5607
|
+
const cmp = compareValues(a.value, b.value);
|
|
5608
|
+
return sortDir === "asc" ? cmp : -cmp;
|
|
5609
|
+
});
|
|
5610
|
+
return { sortedAll: sorted, unsortable: elements ? sortKey : null };
|
|
5611
|
+
}, [data, sortKey, sortDir, sortColumn, sortKind]);
|
|
5612
|
+
const canSort = useMemo(() => {
|
|
5613
|
+
const can = /* @__PURE__ */ new Set();
|
|
5614
|
+
for (const col of columns) if (col.sortValue || data.every((row) => sortableValue(row[col.key]) !== null)) can.add(col.key);
|
|
5615
|
+
return can;
|
|
5616
|
+
}, [columns, data]);
|
|
5617
|
+
useEffect(() => {
|
|
5618
|
+
if (unsortable) warnOnce("Table", `the column "${unsortable}" is sortable, but its cells are elements, which can't be compared: give it a sortValue, (row) => the name, number or date it shows (data_display#1).`);
|
|
5619
|
+
}, [unsortable]);
|
|
5620
|
+
useEffect(() => {
|
|
5621
|
+
if (pager && data.length !== pager.totalItems) warnOnce("Table", `the pager counts ${pager.totalItems} rows but data holds ${data.length}: give the table and usePagination the same rows, every row of the list, and the table draws the pager's part (Sprint 25.13 A3).`);
|
|
5622
|
+
}, [pager, data.length]);
|
|
5623
|
+
const rangeStart = pager ? pager.range[0] : null;
|
|
5624
|
+
const rangeEnd2 = pager ? pager.range[1] : null;
|
|
5625
|
+
const drawn = useMemo(
|
|
5626
|
+
() => rangeStart === null ? sortedAll : rangeStart === 0 ? [] : sortedAll.slice(rangeStart - 1, rangeEnd2 ?? void 0),
|
|
5627
|
+
[sortedAll, rangeStart, rangeEnd2]
|
|
6240
5628
|
);
|
|
6241
|
-
const
|
|
6242
|
-
const aVal = a.row[sortKey];
|
|
6243
|
-
const bVal = b.row[sortKey];
|
|
6244
|
-
if (aVal == null || bVal == null) return 0;
|
|
6245
|
-
const cmp = String(aVal).localeCompare(String(bVal), void 0, { numeric: true });
|
|
6246
|
-
return sortDir === "asc" ? cmp : -cmp;
|
|
6247
|
-
}) : data.map((row, i) => ({ row, originalIdx: i }));
|
|
5629
|
+
const drawnStart = rangeStart ? rangeStart - 1 : 0;
|
|
6248
5630
|
const selectedSet = new Set(selectedRows);
|
|
6249
|
-
const
|
|
6250
|
-
const
|
|
5631
|
+
const drawnIdx = drawn.map((d) => d.originalIdx);
|
|
5632
|
+
const allSelected = drawnIdx.length > 0 && drawnIdx.every((i) => selectedSet.has(i));
|
|
5633
|
+
const someSelected = !allSelected && drawnIdx.some((i) => selectedSet.has(i));
|
|
6251
5634
|
const toggleAll = () => {
|
|
6252
|
-
|
|
6253
|
-
|
|
5635
|
+
const shown = new Set(drawnIdx);
|
|
5636
|
+
if (allSelected) onSelectionChange?.(selectedRows.filter((r) => !shown.has(r)));
|
|
5637
|
+
else onSelectionChange?.([...selectedRows.filter((r) => !shown.has(r)), ...drawnIdx]);
|
|
6254
5638
|
};
|
|
6255
5639
|
const toggleRow = (idx) => {
|
|
6256
5640
|
if (selectedSet.has(idx)) onSelectionChange?.(selectedRows.filter((r) => r !== idx));
|
|
6257
5641
|
else onSelectionChange?.([...selectedRows, idx]);
|
|
6258
5642
|
};
|
|
6259
|
-
const
|
|
6260
|
-
|
|
6261
|
-
|
|
6262
|
-
|
|
6263
|
-
|
|
6264
|
-
|
|
6265
|
-
});
|
|
5643
|
+
const expandControlled = expandedRowsProp !== void 0;
|
|
5644
|
+
const [ownExpanded, setOwnExpanded] = useState(defaultExpandedRows ?? []);
|
|
5645
|
+
const expanded = expandControlled ? expandedRowsProp : ownExpanded;
|
|
5646
|
+
const expandedSet = new Set(expanded.map(String));
|
|
5647
|
+
const { ids: rowIds, repeated } = useMemo(() => rowIdsOf(data, rowKey), [data, rowKey]);
|
|
5648
|
+
useEffect(() => {
|
|
5649
|
+
if (repeated !== null) warnOnce("Table", `two rows share the ${rowKey} "${repeated}": give each row its own, or name a field that is one (rowKey), so an opened row and focus stay on their row.`);
|
|
5650
|
+
}, [repeated, rowKey]);
|
|
5651
|
+
const idOf = (_row, index) => rowIds[index] ?? index;
|
|
5652
|
+
const marksOf = (row, index) => rowMarks(row, index, rowKey, idOf(row, index));
|
|
5653
|
+
const openedHere = useRef(null);
|
|
5654
|
+
const toggleExpand = (id) => {
|
|
5655
|
+
const opening = !expandedSet.has(String(id));
|
|
5656
|
+
const next = opening ? [...expanded, id] : expanded.filter((x) => String(x) !== String(id));
|
|
5657
|
+
openedHere.current = opening ? String(id) : null;
|
|
5658
|
+
if (!expandControlled) setOwnExpanded(next);
|
|
5659
|
+
onExpandedChange?.(next);
|
|
6266
5660
|
};
|
|
6267
|
-
const
|
|
6268
|
-
const inferredKinds = useMemo(() => inferColumnKinds(data, columnKeys), [data, columnKeys]);
|
|
6269
|
-
const kindOf = useCallback(
|
|
6270
|
-
(col) => col.kind ?? inferredKinds.get(col.key),
|
|
6271
|
-
[inferredKinds]
|
|
6272
|
-
);
|
|
5661
|
+
const canOpenByClick = !!expandable && !!renderExpanded && !onRowClick;
|
|
6273
5662
|
const preferences = useShellPreferences();
|
|
6274
5663
|
const mobileBreakpoint = mobileBreakpointProp ?? preferences.tableToCardsBreakpoint ?? "md";
|
|
6275
|
-
const
|
|
6276
|
-
const {
|
|
5664
|
+
const narrowScreen = useBreakpoint(mobileBreakpoint);
|
|
5665
|
+
const { cards: isMobile, rootRef } = useCardsSwitch(narrowScreen, cardsBelow, title);
|
|
5666
|
+
const setRoot = useCallback((node) => {
|
|
5667
|
+
rootRef.current = node;
|
|
5668
|
+
if (typeof ref === "function") ref(node);
|
|
5669
|
+
else if (ref) ref.current = node;
|
|
5670
|
+
}, [ref, rootRef]);
|
|
5671
|
+
const tableRef = useRef(null);
|
|
5672
|
+
const [pins, setPins] = useState(NO_PINS);
|
|
5673
|
+
const lead = (selectable ? 1 : 0) + (expandable ? 1 : 0);
|
|
5674
|
+
const endCount = columns.filter((c) => c.pin === "end").length;
|
|
5675
|
+
const nameIndex = columns.length > endCount ? lead : -1;
|
|
5676
|
+
const { ref: scrollRef, elRef: scrollEl, measure: measureScroll, scrollable, edges, fadeProps } = useScrollEdges({
|
|
5677
|
+
enabled: !isMobile,
|
|
5678
|
+
noFade: { left: lead + (pins.nameFits ? 1 : 0) > 0, right: endCount > 0 }
|
|
5679
|
+
});
|
|
6277
5680
|
const [regionFocused, setRegionFocused] = useState(false);
|
|
5681
|
+
useLayoutEffect(() => {
|
|
5682
|
+
const table2 = tableRef.current;
|
|
5683
|
+
const scroller = scrollEl.current;
|
|
5684
|
+
if (!table2 || !scroller || isMobile) return;
|
|
5685
|
+
const measure = () => {
|
|
5686
|
+
const cells = Array.from(table2.querySelectorAll(":scope > thead > tr > th"));
|
|
5687
|
+
if (!cells.length) return;
|
|
5688
|
+
const widths = cells.map((c) => c.getBoundingClientRect().width);
|
|
5689
|
+
const start = [];
|
|
5690
|
+
let at = 0;
|
|
5691
|
+
for (let i = 0; i < lead; i++) {
|
|
5692
|
+
start.push(at);
|
|
5693
|
+
at += widths[i] ?? 0;
|
|
5694
|
+
}
|
|
5695
|
+
const nameWidth = nameIndex >= 0 ? widths[nameIndex] ?? 0 : 0;
|
|
5696
|
+
const end = [];
|
|
5697
|
+
let fromRight = 0;
|
|
5698
|
+
for (let i = cells.length - 1; i >= cells.length - endCount; i--) {
|
|
5699
|
+
end.unshift(fromRight);
|
|
5700
|
+
fromRight += widths[i] ?? 0;
|
|
5701
|
+
}
|
|
5702
|
+
const frame = scroller.clientWidth;
|
|
5703
|
+
const nameFits = nameIndex >= 0 && frame > 0 && at + nameWidth + fromRight <= frame / 2;
|
|
5704
|
+
if (nameFits) start.push(at);
|
|
5705
|
+
const next = { start, end, nameFits, frame };
|
|
5706
|
+
setPins((prev) => samePins(prev, next) ? prev : next);
|
|
5707
|
+
};
|
|
5708
|
+
measure();
|
|
5709
|
+
if (typeof ResizeObserver === "undefined") return;
|
|
5710
|
+
const observer = new ResizeObserver(measure);
|
|
5711
|
+
observer.observe(table2);
|
|
5712
|
+
observer.observe(scroller);
|
|
5713
|
+
return () => observer.disconnect();
|
|
5714
|
+
}, [isMobile, lead, endCount, nameIndex, scrollEl, columns, drawn.length]);
|
|
5715
|
+
const pinnedStart = lead + (pins.nameFits ? 1 : 0);
|
|
5716
|
+
const pinStyle = (position, total) => {
|
|
5717
|
+
if (position < pinnedStart && pins.start[position] !== void 0) {
|
|
5718
|
+
const inner = position === pinnedStart - 1;
|
|
5719
|
+
return { position: "sticky", left: pins.start[position], zIndex: 1, background: PINNED_BACKGROUND, boxShadow: inner && edges.left ? `6px 0 6px -6px ${PIN_SHADOW}` : void 0 };
|
|
5720
|
+
}
|
|
5721
|
+
const fromEnd = total - 1 - position;
|
|
5722
|
+
if (fromEnd < endCount && pins.end[endCount - 1 - fromEnd] !== void 0) {
|
|
5723
|
+
const inner = fromEnd === endCount - 1;
|
|
5724
|
+
return { position: "sticky", right: pins.end[endCount - 1 - fromEnd], zIndex: 1, background: PINNED_BACKGROUND, boxShadow: inner && edges.right ? `-6px 0 6px -6px ${PIN_SHADOW}` : void 0 };
|
|
5725
|
+
}
|
|
5726
|
+
return void 0;
|
|
5727
|
+
};
|
|
5728
|
+
const fade = fadeProps;
|
|
5729
|
+
const [renderedKinds, setRenderedKinds] = useState(() => /* @__PURE__ */ new Map());
|
|
5730
|
+
useLayoutEffect(() => {
|
|
5731
|
+
const table2 = tableRef.current;
|
|
5732
|
+
if (!table2 || isMobile) return;
|
|
5733
|
+
const next = /* @__PURE__ */ new Map();
|
|
5734
|
+
for (const col of columns) {
|
|
5735
|
+
if (kindOf(col)) continue;
|
|
5736
|
+
const texts = Array.from(table2.querySelectorAll(`:scope > tbody > tr > td[data-col="${CSS.escape(col.key)}"]`)).slice(0, 50).map((td) => td.textContent ?? "");
|
|
5737
|
+
const kind = texts.length ? kindOfRenderedText(texts) : void 0;
|
|
5738
|
+
if (kind) next.set(col.key, kind);
|
|
5739
|
+
}
|
|
5740
|
+
setRenderedKinds((prev) => prev.size === next.size && [...next].every(([k, v]) => prev.get(k) === v) ? prev : next);
|
|
5741
|
+
}, [columns, kindOf, drawn, isMobile]);
|
|
5742
|
+
const expandedKey = expanded.map(String).join("");
|
|
5743
|
+
const shownBefore = useRef(/* @__PURE__ */ new Set());
|
|
5744
|
+
const pendingScroll = useRef(null);
|
|
5745
|
+
const scrollToRow = useCallback((key) => {
|
|
5746
|
+
const row = rootRef.current?.querySelector(`[data-row-key="${CSS.escape(key)}"], [data-row-index="${CSS.escape(key)}"]`);
|
|
5747
|
+
if (row && typeof row.scrollIntoView === "function") row.scrollIntoView({ block: "nearest" });
|
|
5748
|
+
}, [rootRef]);
|
|
5749
|
+
useEffect(() => {
|
|
5750
|
+
const now = new Set(expanded.map(String));
|
|
5751
|
+
const added = [...now].filter((k) => !shownBefore.current.has(k) && k !== openedHere.current);
|
|
5752
|
+
shownBefore.current = now;
|
|
5753
|
+
openedHere.current = null;
|
|
5754
|
+
if (!expandControlled) return;
|
|
5755
|
+
const key = added[added.length - 1];
|
|
5756
|
+
if (key === void 0) return;
|
|
5757
|
+
if (pager) {
|
|
5758
|
+
const position = sortedAll.findIndex((r) => String(idOf(r.row, r.originalIdx)) === key);
|
|
5759
|
+
if (position >= 0 && (position < drawnStart || position >= drawnStart + drawn.length)) {
|
|
5760
|
+
pendingScroll.current = key;
|
|
5761
|
+
pager.setPage(Math.floor(position / pager.pageSize) + 1);
|
|
5762
|
+
return;
|
|
5763
|
+
}
|
|
5764
|
+
}
|
|
5765
|
+
scrollToRow(key);
|
|
5766
|
+
}, [expandedKey]);
|
|
5767
|
+
useEffect(() => {
|
|
5768
|
+
const key = pendingScroll.current;
|
|
5769
|
+
if (!key || !drawn.some((r) => String(idOf(r.row, r.originalIdx)) === key)) return;
|
|
5770
|
+
pendingScroll.current = null;
|
|
5771
|
+
scrollToRow(key);
|
|
5772
|
+
}, [drawnStart, drawn.length, scrollToRow]);
|
|
6278
5773
|
const cardHeading = title ? /* @__PURE__ */ jsx(TableHeading, { title, description, actions, titleId, descriptionId, inset: false }) : null;
|
|
6279
|
-
const titledCards = (body) => /* @__PURE__ */ jsxs("div", { ref, "data-ds-list": "", "data-gs": "table", className: cn("flex flex-col",
|
|
5774
|
+
const titledCards = (body) => /* @__PURE__ */ jsxs("div", { ref: listRoot, "data-ds-list": "", "data-gs": "table", className: cn("flex flex-col", listClass), onFocus: noteFocus, onBlur: forgetFocus, children: [
|
|
6280
5775
|
cardHeading,
|
|
6281
5776
|
body
|
|
6282
5777
|
] });
|
|
5778
|
+
const control = pager && !loading && data.length > 0 ? /* @__PURE__ */ jsx(Pagination, { ...pager.props }) : null;
|
|
5779
|
+
const listRoot = control ? void 0 : setRoot;
|
|
5780
|
+
const listClass = control ? void 0 : className;
|
|
5781
|
+
const withControl = (list) => control ? /* @__PURE__ */ jsxs("div", { ref: setRoot, "data-gs-paged": "", className: cn("flex flex-col min-w-0", className), children: [
|
|
5782
|
+
list,
|
|
5783
|
+
control
|
|
5784
|
+
] }) : list;
|
|
5785
|
+
const focusWas = useRef(null);
|
|
5786
|
+
const noteFocus = (e) => {
|
|
5787
|
+
const target = e.target;
|
|
5788
|
+
const row = target.closest("[data-row-key], [data-row-index]");
|
|
5789
|
+
if (!row) {
|
|
5790
|
+
focusWas.current = null;
|
|
5791
|
+
return;
|
|
5792
|
+
}
|
|
5793
|
+
const control2 = target === row ? null : target.getAttribute("aria-labelledby") ?? target.getAttribute("aria-label") ?? target.textContent;
|
|
5794
|
+
focusWas.current = { row: row.hasAttribute("data-row-key") ? `[data-row-key="${CSS.escape(row.getAttribute("data-row-key"))}"]` : `[data-row-index="${CSS.escape(row.getAttribute("data-row-index"))}"]`, control: control2 };
|
|
5795
|
+
};
|
|
5796
|
+
const forgetFocus = (e) => {
|
|
5797
|
+
const node = e.target;
|
|
5798
|
+
queueMicrotask(() => {
|
|
5799
|
+
if (node.isConnected && !rootRef.current?.contains(document.activeElement)) focusWas.current = null;
|
|
5800
|
+
});
|
|
5801
|
+
};
|
|
5802
|
+
useLayoutEffect(() => {
|
|
5803
|
+
const was = focusWas.current;
|
|
5804
|
+
const active = document.activeElement;
|
|
5805
|
+
if (!was || active && active !== document.body) return;
|
|
5806
|
+
const row = rootRef.current?.querySelector(was.row);
|
|
5807
|
+
if (!row) return;
|
|
5808
|
+
const controls = Array.from(row.querySelectorAll(FOCUSABLE));
|
|
5809
|
+
const same2 = was.control === null ? null : controls.find((el) => (el.getAttribute("aria-labelledby") ?? el.getAttribute("aria-label") ?? el.textContent) === was.control);
|
|
5810
|
+
(same2 ?? (row.tabIndex >= 0 ? row : controls[0]))?.focus({ preventScroll: true });
|
|
5811
|
+
}, [isMobile, rootRef]);
|
|
6283
5812
|
if (isMobile) {
|
|
6284
5813
|
if (loading) {
|
|
6285
5814
|
if (title) return titledCards(/* @__PURE__ */ jsx("div", { className: "flex items-center justify-center py-ds-10", children: /* @__PURE__ */ jsx(Spinner, { label: "Loading table data" }) }));
|
|
6286
|
-
return /* @__PURE__ */ jsx("div", { ref, "data-ds-list": "", "data-gs": "table", className: cn("flex items-center justify-center py-ds-10", className), children: /* @__PURE__ */ jsx(Spinner, { label: "Loading table data" }) });
|
|
5815
|
+
return /* @__PURE__ */ jsx("div", { ref: setRoot, "data-ds-list": "", "data-gs": "table", className: cn("flex items-center justify-center py-ds-10", className), children: /* @__PURE__ */ jsx(Spinner, { label: "Loading table data" }) });
|
|
6287
5816
|
}
|
|
6288
5817
|
if (data.length === 0 && emptyState) {
|
|
6289
5818
|
if (title) return titledCards(/* @__PURE__ */ jsx("div", { className: "py-ds-10 text-center text-sm text-[var(--ds-text-muted)]", children: emptyState }));
|
|
6290
|
-
return /* @__PURE__ */ jsx("div", { ref, "data-ds-list": "", "data-gs": "table", className: cn("py-ds-10 text-center text-sm text-[var(--ds-text-muted)]", className), children: emptyState });
|
|
5819
|
+
return /* @__PURE__ */ jsx("div", { ref: setRoot, "data-ds-list": "", "data-gs": "table", className: cn("py-ds-10 text-center text-sm text-[var(--ds-text-muted)]", className), children: emptyState });
|
|
6291
5820
|
}
|
|
6292
|
-
const cards = /* @__PURE__ */ jsx(TableCardCtx, { value: true, children: /* @__PURE__ */
|
|
6293
|
-
|
|
6294
|
-
|
|
6295
|
-
|
|
6296
|
-
|
|
6297
|
-
|
|
6298
|
-
|
|
6299
|
-
|
|
6300
|
-
"
|
|
6301
|
-
|
|
6302
|
-
|
|
6303
|
-
|
|
6304
|
-
|
|
6305
|
-
|
|
6306
|
-
|
|
6307
|
-
|
|
6308
|
-
|
|
6309
|
-
|
|
6310
|
-
e
|
|
6311
|
-
|
|
6312
|
-
|
|
6313
|
-
|
|
6314
|
-
|
|
6315
|
-
|
|
6316
|
-
|
|
6317
|
-
|
|
6318
|
-
|
|
6319
|
-
|
|
6320
|
-
|
|
6321
|
-
|
|
6322
|
-
|
|
6323
|
-
|
|
6324
|
-
|
|
6325
|
-
|
|
6326
|
-
|
|
5821
|
+
const cards = /* @__PURE__ */ jsx(TableCardCtx, { value: true, children: /* @__PURE__ */ jsxs("div", { ref: title ? void 0 : listRoot, "data-ds-list": title ? void 0 : "", "data-gs": title ? void 0 : "table", className: cn("flex flex-col gap-ds-3 overflow-y-auto", title ? "min-h-0" : listClass), onFocus: title ? void 0 : noteFocus, onBlur: title ? void 0 : forgetFocus, children: [
|
|
5822
|
+
selectable && /* @__PURE__ */ jsx("span", { hidden: true, id: `${headingId}-select`, children: "Select" }),
|
|
5823
|
+
drawn.map(({ row, originalIdx }) => {
|
|
5824
|
+
const isSelected = selectedSet.has(originalIdx);
|
|
5825
|
+
const id = idOf(row, originalIdx);
|
|
5826
|
+
return /* @__PURE__ */ jsxs(
|
|
5827
|
+
"div",
|
|
5828
|
+
{
|
|
5829
|
+
"data-row": "",
|
|
5830
|
+
...marksOf(row, originalIdx),
|
|
5831
|
+
className: cn(
|
|
5832
|
+
"border-[length:var(--ds-border-width)] border-[var(--ds-border-subtle)]",
|
|
5833
|
+
"rounded-[var(--ds-radius-md)] bg-[var(--ds-bg-surface)]",
|
|
5834
|
+
"p-ds-4 space-y-ds-3",
|
|
5835
|
+
isSelected && ACTIVE_RING,
|
|
5836
|
+
onRowClick && "cursor-pointer hover:bg-[var(--ds-bg-muted)] focus-visible:outline-none focus-visible:shadow-[var(--ds-shadow-focus)]"
|
|
5837
|
+
),
|
|
5838
|
+
onClick: onRowClick ? (e) => {
|
|
5839
|
+
if (clickIsRows(e)) onRowClick(row, originalIdx);
|
|
5840
|
+
} : void 0,
|
|
5841
|
+
tabIndex: onRowClick ? 0 : void 0,
|
|
5842
|
+
onKeyDown: onRowClick ? (e) => {
|
|
5843
|
+
if (e.target !== e.currentTarget) return;
|
|
5844
|
+
if (e.key === "Enter" || e.key === " ") {
|
|
5845
|
+
e.preventDefault();
|
|
5846
|
+
onRowClick(row, originalIdx);
|
|
5847
|
+
}
|
|
5848
|
+
} : void 0,
|
|
5849
|
+
children: [
|
|
5850
|
+
selectable && // "Select" and the row's name, as in the table (T15)
|
|
5851
|
+
/* @__PURE__ */ jsx(Checkbox, { checked: isSelected, onChange: () => toggleRow(originalIdx), "aria-labelledby": nameIndex >= 0 ? `${headingId}-select ${headingId}-card-name-${idPart(id)}` : `${headingId}-select` }),
|
|
5852
|
+
columns.map((col, c) => /* @__PURE__ */ jsxs("div", { className: "flex justify-between gap-ds-2 text-sm", children: [
|
|
5853
|
+
/* @__PURE__ */ jsx("span", { className: "shrink-0 text-[var(--ds-text-secondary)] font-medium text-xs uppercase tracking-wider", children: col.header }),
|
|
5854
|
+
/* @__PURE__ */ jsx(CardValue, { value: row[col.key], id: lead + c === nameIndex ? `${headingId}-card-name-${idPart(id)}` : void 0 })
|
|
5855
|
+
] }, col.key)),
|
|
5856
|
+
expandable && renderExpanded && /* @__PURE__ */ jsx("div", { className: "pt-ds-2 border-t-[length:var(--ds-divider-width)] border-[var(--ds-border-subtle)] text-sm text-[var(--ds-text-secondary)]", children: renderExpanded(row, originalIdx) })
|
|
5857
|
+
]
|
|
5858
|
+
},
|
|
5859
|
+
String(id)
|
|
5860
|
+
);
|
|
5861
|
+
})
|
|
5862
|
+
] }) });
|
|
5863
|
+
return withControl(title ? titledCards(cards) : cards);
|
|
6327
5864
|
}
|
|
6328
|
-
const
|
|
6329
|
-
|
|
6330
|
-
|
|
5865
|
+
const cellCount = columns.length + lead;
|
|
5866
|
+
const table = /* @__PURE__ */ jsxs("table", { ref: tableRef, className: cn("w-full text-sm", PINNED_LAYERS), ...title ? { "aria-labelledby": titleId, "aria-describedby": description ? descriptionId : void 0 } : ariaLabel ? { "aria-label": ariaLabel } : {}, children: [
|
|
5867
|
+
/* @__PURE__ */ jsx("thead", { className: cn("bg-[var(--ds-bg-muted)]", stickyHeader && "sticky top-0 z-10"), children: /* @__PURE__ */ jsxs("tr", { className: "border-b-[length:var(--ds-divider-width)] border-[var(--ds-border-subtle)] [--gs-row-tint:var(--ds-bg-muted)]", children: [
|
|
5868
|
+
selectable && /* @__PURE__ */ jsx("th", { className: cn("w-10", density === "compact" ? "px-ds-2 py-ds-2" : "px-ds-3 py-ds-3"), style: pinStyle(0, cellCount), children: /* @__PURE__ */ jsx(
|
|
6331
5869
|
Checkbox,
|
|
6332
5870
|
{
|
|
6333
5871
|
checked: allSelected,
|
|
6334
5872
|
indeterminate: someSelected,
|
|
6335
|
-
onChange: toggleAll
|
|
5873
|
+
onChange: toggleAll,
|
|
5874
|
+
"aria-labelledby": `${headingId}-select-all`
|
|
6336
5875
|
}
|
|
6337
5876
|
) }),
|
|
6338
|
-
expandable && /* @__PURE__ */ jsx("th", { className: cn("w-8", density === "compact" ? "px-ds-1 py-ds-2" : "px-ds-2 py-ds-3") }),
|
|
6339
|
-
columns.map((col) => {
|
|
6340
|
-
const isSortable = sortable
|
|
6341
|
-
const isActiveSort = sortKey === col.key;
|
|
5877
|
+
expandable && /* @__PURE__ */ jsx("th", { className: cn("w-8", density === "compact" ? "px-ds-1 py-ds-2" : "px-ds-2 py-ds-3"), style: pinStyle(selectable ? 1 : 0, cellCount) }),
|
|
5878
|
+
columns.map((col, c) => {
|
|
5879
|
+
const isSortable = col.header.trim() !== "" && (col.sortable ?? (!!sortable && canSort.has(col.key)));
|
|
5880
|
+
const isActiveSort = sortKey === col.key && !!sortDir && unsortable !== col.key;
|
|
6342
5881
|
const headerKind = kindOf(col);
|
|
6343
5882
|
const headerAlign = col.align ?? (headerKind === "number" ? "right" : "left");
|
|
6344
5883
|
const shrink = (headerKind === "number" || headerKind === "date") && !col.maxWidth;
|
|
5884
|
+
const style = { maxWidth: col.maxWidth, width: col.width, minWidth: col.minWidth, ...pinStyle(lead + c, cellCount) };
|
|
6345
5885
|
return /* @__PURE__ */ jsx(
|
|
6346
5886
|
"th",
|
|
6347
5887
|
{
|
|
5888
|
+
"aria-sort": isSortable && isActiveSort ? sortDir === "asc" ? "ascending" : "descending" : void 0,
|
|
6348
5889
|
className: cn(
|
|
6349
5890
|
density === "compact" ? "px-ds-3 py-ds-2" : "px-ds-4 py-ds-3",
|
|
6350
5891
|
shrink && "w-px whitespace-nowrap",
|
|
6351
5892
|
"font-[var(--ds-weight-heading)] text-[var(--ds-text-secondary)]",
|
|
6352
5893
|
"text-xs uppercase tracking-wider",
|
|
6353
|
-
headerAlign === "right" ? "text-right" : headerAlign === "center" ? "text-center" : "text-left"
|
|
6354
|
-
isSortable && "cursor-pointer select-none hover:text-[var(--ds-text-primary)]"
|
|
5894
|
+
headerAlign === "right" ? "text-right" : headerAlign === "center" ? "text-center" : "text-left"
|
|
6355
5895
|
),
|
|
6356
|
-
style
|
|
6357
|
-
|
|
6358
|
-
|
|
6359
|
-
|
|
6360
|
-
|
|
6361
|
-
Icon,
|
|
5896
|
+
style,
|
|
5897
|
+
children: isSortable ? (
|
|
5898
|
+
// A47: a button with the column's name, reached with Tab and pressed with Enter or Space
|
|
5899
|
+
/* @__PURE__ */ jsxs(
|
|
5900
|
+
"button",
|
|
6362
5901
|
{
|
|
6363
|
-
|
|
6364
|
-
|
|
5902
|
+
type: "button",
|
|
5903
|
+
onClick: () => handleSort(col.key),
|
|
6365
5904
|
className: cn(
|
|
6366
|
-
"
|
|
6367
|
-
|
|
6368
|
-
|
|
5905
|
+
"inline-flex items-center gap-ds-1 uppercase tracking-wider cursor-pointer select-none",
|
|
5906
|
+
"[font:inherit] text-inherit hover:text-[var(--ds-text-primary)]",
|
|
5907
|
+
"rounded-[var(--ds-radius-sm)] focus-visible:outline-none focus-visible:shadow-[var(--ds-shadow-focus)]"
|
|
5908
|
+
),
|
|
5909
|
+
children: [
|
|
5910
|
+
col.header,
|
|
5911
|
+
/* @__PURE__ */ jsx(
|
|
5912
|
+
Icon,
|
|
5913
|
+
{
|
|
5914
|
+
name: "chevron-right",
|
|
5915
|
+
size: 12,
|
|
5916
|
+
className: cn(
|
|
5917
|
+
"transition-transform",
|
|
5918
|
+
!isActiveSort ? "invisible" : sortDir === "asc" ? "-rotate-90" : "rotate-90"
|
|
5919
|
+
)
|
|
5920
|
+
}
|
|
5921
|
+
)
|
|
5922
|
+
]
|
|
6369
5923
|
}
|
|
6370
5924
|
)
|
|
6371
|
-
|
|
5925
|
+
) : /* @__PURE__ */ jsx("span", { className: "inline-flex items-center gap-ds-1", children: col.header })
|
|
6372
5926
|
},
|
|
6373
5927
|
col.key
|
|
6374
5928
|
);
|
|
@@ -6377,31 +5931,44 @@ function Table({
|
|
|
6377
5931
|
/* @__PURE__ */ jsx("tbody", { children: loading ? /* @__PURE__ */ jsx("tr", { children: /* @__PURE__ */ jsx(
|
|
6378
5932
|
"td",
|
|
6379
5933
|
{
|
|
6380
|
-
colSpan:
|
|
5934
|
+
colSpan: cellCount,
|
|
6381
5935
|
className: "px-ds-4 py-ds-10 text-center",
|
|
6382
5936
|
children: /* @__PURE__ */ jsx(Spinner, { label: "Loading table data" })
|
|
6383
5937
|
}
|
|
6384
5938
|
) }) : data.length === 0 && emptyState ? /* @__PURE__ */ jsx("tr", { children: /* @__PURE__ */ jsx(
|
|
6385
5939
|
"td",
|
|
6386
5940
|
{
|
|
6387
|
-
colSpan:
|
|
5941
|
+
colSpan: cellCount,
|
|
6388
5942
|
className: "px-ds-4 py-ds-10 text-center text-sm text-[var(--ds-text-muted)]",
|
|
6389
5943
|
children: emptyState
|
|
6390
5944
|
}
|
|
6391
|
-
) }) :
|
|
5945
|
+
) }) : drawn.map(({ row, originalIdx }, i) => {
|
|
6392
5946
|
const isSelected = selectedSet.has(originalIdx);
|
|
6393
|
-
const
|
|
5947
|
+
const id = idOf(row, originalIdx);
|
|
5948
|
+
const isExpanded = expandedSet.has(String(id));
|
|
5949
|
+
const clickable = !!onRowClick || canOpenByClick;
|
|
6394
5950
|
return /* @__PURE__ */ jsxs(Fragment$1, { children: [
|
|
6395
5951
|
/* @__PURE__ */ jsxs(
|
|
6396
5952
|
"tr",
|
|
6397
5953
|
{
|
|
5954
|
+
...marksOf(row, originalIdx),
|
|
6398
5955
|
className: cn(
|
|
6399
5956
|
"border-b-[length:var(--ds-divider-width)] border-[var(--ds-border-subtle)] last:border-b-0",
|
|
6400
|
-
|
|
6401
|
-
|
|
6402
|
-
|
|
5957
|
+
// the row's background and its tint change together, so its pinned cells and the rest fade as one
|
|
5958
|
+
// (roots.css registers --gs-row-tint as a colour so it can)
|
|
5959
|
+
"transition-[background-color,--gs-row-tint]",
|
|
5960
|
+
// the row's tint, as a variable too, so its pinned cells draw it over their solid ground (A35)
|
|
5961
|
+
isSelected ? "bg-[var(--ds-accent-subtle)] [--gs-row-tint:var(--ds-accent-subtle)]" : striped && i % 2 === 1 ? "bg-[var(--ds-bg-muted)]/50 [--gs-row-tint:color-mix(in_oklab,var(--ds-bg-muted)_50%,transparent)]" : "hover:bg-[var(--ds-bg-muted)] hover:[--gs-row-tint:var(--ds-bg-muted)]",
|
|
5962
|
+
clickable && "cursor-pointer",
|
|
5963
|
+
// an outline inside the row: it shows over the pinned cells, whose solid ground hid the inset
|
|
5964
|
+
// shadow the row drew before (the review of 30 September)
|
|
5965
|
+
onRowClick && "focus-visible:outline-2 focus-visible:-outline-offset-2 focus-visible:outline-[var(--ds-border-focus)]"
|
|
6403
5966
|
),
|
|
6404
|
-
onClick:
|
|
5967
|
+
onClick: clickable ? (e) => {
|
|
5968
|
+
if (!clickIsRows(e)) return;
|
|
5969
|
+
if (onRowClick) onRowClick(row, originalIdx);
|
|
5970
|
+
else toggleExpand(id);
|
|
5971
|
+
} : void 0,
|
|
6405
5972
|
tabIndex: onRowClick ? 0 : void 0,
|
|
6406
5973
|
onKeyDown: onRowClick ? (e) => {
|
|
6407
5974
|
if (e.target !== e.currentTarget) return;
|
|
@@ -6411,15 +5978,15 @@ function Table({
|
|
|
6411
5978
|
}
|
|
6412
5979
|
} : void 0,
|
|
6413
5980
|
children: [
|
|
6414
|
-
selectable && /* @__PURE__ */ jsx("td", { className: cn("w-10", density === "compact" ? "px-ds-2 py-ds-2" : "px-ds-3 py-ds-3"), children: /* @__PURE__ */ jsx(Checkbox, { checked: isSelected, onChange: () => toggleRow(originalIdx) }) }),
|
|
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(
|
|
5981
|
+
selectable && /* @__PURE__ */ jsx("td", { className: cn("w-10", density === "compact" ? "px-ds-2 py-ds-2" : "px-ds-3 py-ds-3"), style: pinStyle(0, cellCount), children: /* @__PURE__ */ jsx(Checkbox, { checked: isSelected, onChange: () => toggleRow(originalIdx), "aria-labelledby": nameIndex >= 0 ? `${headingId}-select ${headingId}-name-${idPart(id)}` : `${headingId}-select` }) }),
|
|
5982
|
+
expandable && /* @__PURE__ */ jsx("td", { className: cn("w-8", density === "compact" ? "px-ds-1 py-ds-2" : "px-ds-2 py-ds-3"), style: pinStyle(selectable ? 1 : 0, cellCount), children: /* @__PURE__ */ jsx(
|
|
6416
5983
|
"button",
|
|
6417
5984
|
{
|
|
6418
5985
|
type: "button",
|
|
6419
|
-
onClick: () => toggleExpand(
|
|
5986
|
+
onClick: () => toggleExpand(id),
|
|
6420
5987
|
className: "text-[var(--ds-text-muted)] hover:text-[var(--ds-text-primary)] cursor-pointer",
|
|
6421
5988
|
"aria-expanded": isExpanded,
|
|
6422
|
-
"aria-label": "
|
|
5989
|
+
...nameIndex >= 0 ? { "aria-labelledby": `${headingId}-details ${headingId}-name-${idPart(id)}` } : { "aria-label": "Details" },
|
|
6423
5990
|
children: /* @__PURE__ */ jsx(
|
|
6424
5991
|
Icon,
|
|
6425
5992
|
{
|
|
@@ -6430,12 +5997,13 @@ function Table({
|
|
|
6430
5997
|
)
|
|
6431
5998
|
}
|
|
6432
5999
|
) }),
|
|
6433
|
-
columns.map((col) => {
|
|
6000
|
+
columns.map((col, c) => {
|
|
6434
6001
|
const truncLines = col.truncate === true ? 1 : col.truncate ? col.truncate.lines : 0;
|
|
6435
6002
|
const kind = kindOf(col);
|
|
6436
6003
|
const alignClass = col.align ? col.align === "right" ? "text-right" : col.align === "center" ? "text-center" : "text-left" : kind === "number" ? "text-right" : "text-left";
|
|
6437
6004
|
const cellContent = row[col.key];
|
|
6438
6005
|
const shrink = (kind === "number" || kind === "date") && !col.maxWidth;
|
|
6006
|
+
const whole = !kind && renderedKinds.has(col.key);
|
|
6439
6007
|
let inner;
|
|
6440
6008
|
if (truncLines > 0) {
|
|
6441
6009
|
inner = /* @__PURE__ */ jsx(TruncCell, { lines: truncLines, children: cellContent });
|
|
@@ -6451,13 +6019,17 @@ function Table({
|
|
|
6451
6019
|
return /* @__PURE__ */ jsx(
|
|
6452
6020
|
"td",
|
|
6453
6021
|
{
|
|
6022
|
+
id: lead > 0 && lead + c === nameIndex ? `${headingId}-name-${idPart(id)}` : void 0,
|
|
6023
|
+
"data-col": col.key,
|
|
6454
6024
|
className: cn(
|
|
6455
6025
|
density === "compact" ? "px-ds-3 py-ds-2" : "px-ds-4 py-ds-3",
|
|
6456
6026
|
"text-[var(--ds-text-primary)]",
|
|
6457
6027
|
alignClass,
|
|
6458
|
-
shrink && "w-px whitespace-nowrap"
|
|
6028
|
+
shrink && "w-px whitespace-nowrap",
|
|
6029
|
+
whole && "whitespace-nowrap",
|
|
6030
|
+
kind === "identifier" && "[overflow-wrap:anywhere]"
|
|
6459
6031
|
),
|
|
6460
|
-
style: col.maxWidth || col.width || col.minWidth ? { maxWidth: col.maxWidth, width: col.width, minWidth: col.minWidth } : void 0,
|
|
6032
|
+
style: col.maxWidth || col.width || col.minWidth || c + lead < pinnedStart || c >= columns.length - endCount ? { maxWidth: col.maxWidth, width: col.width, minWidth: col.minWidth, ...pinStyle(lead + c, cellCount) } : void 0,
|
|
6461
6033
|
children: inner
|
|
6462
6034
|
},
|
|
6463
6035
|
col.key
|
|
@@ -6469,50 +6041,57 @@ function Table({
|
|
|
6469
6041
|
expandable && isExpanded && renderExpanded && /* @__PURE__ */ jsx("tr", { children: /* @__PURE__ */ jsx(
|
|
6470
6042
|
"td",
|
|
6471
6043
|
{
|
|
6472
|
-
colSpan:
|
|
6044
|
+
colSpan: cellCount,
|
|
6473
6045
|
className: "bg-[var(--ds-bg-muted)] px-ds-6 py-ds-4 text-sm text-[var(--ds-text-primary)]",
|
|
6474
|
-
children: renderExpanded(row,
|
|
6475
|
-
}
|
|
6476
|
-
) })
|
|
6477
|
-
] },
|
|
6478
|
-
}) })
|
|
6479
|
-
] });
|
|
6480
|
-
const region = scrollable || regionFocused ? { tabIndex: 0, role: "region", ...title ? { "aria-labelledby": titleId } : { "aria-label": ariaLabel ?? "Table" } } : {};
|
|
6481
|
-
return
|
|
6482
|
-
|
|
6483
|
-
|
|
6484
|
-
|
|
6485
|
-
|
|
6486
|
-
|
|
6487
|
-
|
|
6488
|
-
|
|
6489
|
-
|
|
6490
|
-
|
|
6491
|
-
|
|
6492
|
-
{
|
|
6493
|
-
|
|
6494
|
-
|
|
6495
|
-
|
|
6496
|
-
|
|
6497
|
-
|
|
6498
|
-
|
|
6499
|
-
|
|
6500
|
-
|
|
6501
|
-
|
|
6502
|
-
|
|
6503
|
-
|
|
6504
|
-
|
|
6505
|
-
|
|
6506
|
-
|
|
6507
|
-
|
|
6508
|
-
|
|
6509
|
-
|
|
6046
|
+
children: /* @__PURE__ */ jsx("div", { "data-row-panel": "", className: "sticky left-ds-6", style: pins.frame ? { maxWidth: `calc(${pins.frame}px - 2 * var(--ds-space-6))` } : void 0, children: renderExpanded(row, originalIdx) })
|
|
6047
|
+
}
|
|
6048
|
+
) })
|
|
6049
|
+
] }, String(id));
|
|
6050
|
+
}) })
|
|
6051
|
+
] });
|
|
6052
|
+
const region = scrollable || regionFocused ? { tabIndex: 0, role: "region", ...title ? { "aria-labelledby": titleId } : { "aria-label": ariaLabel ?? "Table" } } : {};
|
|
6053
|
+
return withControl(
|
|
6054
|
+
/* @__PURE__ */ jsxs(
|
|
6055
|
+
"div",
|
|
6056
|
+
{
|
|
6057
|
+
ref: listRoot,
|
|
6058
|
+
"data-ds-list": "",
|
|
6059
|
+
"data-gs": "table",
|
|
6060
|
+
className: cn("w-full min-w-0 flex flex-col", FRAME_CLASSES, "has-[>[data-table-scroll]:focus-visible]:shadow-[var(--ds-shadow-focus)]", control && "min-h-0", listClass),
|
|
6061
|
+
onFocus: noteFocus,
|
|
6062
|
+
onBlur: forgetFocus,
|
|
6063
|
+
children: [
|
|
6064
|
+
title && /* @__PURE__ */ jsx(TableHeading, { title, description, actions, titleId, descriptionId, inset: true }),
|
|
6065
|
+
selectable && /* @__PURE__ */ jsx("span", { hidden: true, id: `${headingId}-select-all`, children: "Select all rows shown" }),
|
|
6066
|
+
selectable && /* @__PURE__ */ jsx("span", { hidden: true, id: `${headingId}-select`, children: "Select" }),
|
|
6067
|
+
expandable && /* @__PURE__ */ jsx("span", { hidden: true, id: `${headingId}-details`, children: "Details" }),
|
|
6068
|
+
/* @__PURE__ */ jsx(
|
|
6069
|
+
"div",
|
|
6070
|
+
{
|
|
6071
|
+
ref: scrollRef,
|
|
6072
|
+
"data-table-scroll": "",
|
|
6073
|
+
onScroll: measureScroll,
|
|
6074
|
+
onFocus: (e) => {
|
|
6075
|
+
if (e.target === e.currentTarget) setRegionFocused(true);
|
|
6076
|
+
},
|
|
6077
|
+
onBlur: (e) => {
|
|
6078
|
+
if (e.target === e.currentTarget) setRegionFocused(false);
|
|
6079
|
+
},
|
|
6080
|
+
...fade,
|
|
6081
|
+
...region,
|
|
6082
|
+
className: cn("min-h-0 overflow-x-auto focus-visible:outline-none", title ? "rounded-b-[inherit]" : "rounded-[inherit]"),
|
|
6083
|
+
children: table
|
|
6084
|
+
}
|
|
6085
|
+
)
|
|
6086
|
+
]
|
|
6087
|
+
}
|
|
6088
|
+
)
|
|
6510
6089
|
);
|
|
6511
6090
|
}
|
|
6512
6091
|
function optionsKeyForFit(options) {
|
|
6513
6092
|
return options.map((o) => `${o.value}:${o.label}`).join("|");
|
|
6514
6093
|
}
|
|
6515
|
-
var
|
|
6094
|
+
var sizes2 = {
|
|
6516
6095
|
xs: "text-xs px-ds-2",
|
|
6517
6096
|
sm: "text-xs px-ds-3",
|
|
6518
6097
|
md: "text-sm px-ds-3",
|
|
@@ -6714,7 +6293,7 @@ function SegmentedControl({
|
|
|
6714
6293
|
"rounded-[var(--ds-radius-md)]",
|
|
6715
6294
|
"transition-colors cursor-pointer",
|
|
6716
6295
|
"focus-visible:outline-none focus-visible:shadow-[var(--ds-shadow-focus)]",
|
|
6717
|
-
|
|
6296
|
+
sizes2[size],
|
|
6718
6297
|
opt.value === value ? "text-[var(--ds-text-primary)]" : "text-[var(--ds-text-muted)] hover:text-[var(--ds-text-secondary)]",
|
|
6719
6298
|
opt.disabled && "opacity-disabled cursor-not-allowed"
|
|
6720
6299
|
),
|
|
@@ -8433,66 +8012,70 @@ function TableToolbar({
|
|
|
8433
8012
|
const paged = total !== void 0 && !!pagination && pagination.pageSize > 0 && total > pagination.pageSize;
|
|
8434
8013
|
const countText = total === void 0 ? null : grows ? shown < total ? `Showing ${shown} of ${total} ${noun(total)}` : resultCount !== void 0 ? `${total} ${noun(total)}` : null : paged ? `Showing ${Math.min((pagination.page - 1) * pagination.pageSize + 1, total)}\u2013${Math.min(pagination.page * pagination.pageSize, total)} of ${total} ${noun(total)}` : resultCount !== void 0 ? `${total} ${noun(total)}` : null;
|
|
8435
8014
|
if (!hasControls && countText === null && !hasChips) return null;
|
|
8436
|
-
return
|
|
8437
|
-
|
|
8438
|
-
|
|
8439
|
-
|
|
8440
|
-
|
|
8441
|
-
|
|
8442
|
-
placeholder: search.placeholder ?? search.label,
|
|
8443
|
-
value: search.value,
|
|
8444
|
-
size,
|
|
8445
|
-
onChange: (e) => search.onChange(e.target.value),
|
|
8446
|
-
className: cn("flex-1 min-w-[160px]", !searchFills && "max-w-[280px]")
|
|
8447
|
-
}
|
|
8448
|
-
),
|
|
8449
|
-
primaryFilter && (compact ? /* @__PURE__ */ jsx(
|
|
8450
|
-
Dropdown,
|
|
8451
|
-
{
|
|
8452
|
-
"aria-label": primaryFilter.label,
|
|
8453
|
-
options: primaryFilter.options.map((o) => ({ id: o.value, label: o.label })),
|
|
8454
|
-
value: primaryFilter.value,
|
|
8455
|
-
onChange: (v) => primaryFilter.onChange(v),
|
|
8456
|
-
size,
|
|
8457
|
-
className: "w-[150px]"
|
|
8458
|
-
}
|
|
8459
|
-
) : /* @__PURE__ */ jsx(
|
|
8460
|
-
SegmentedControl,
|
|
8461
|
-
{
|
|
8462
|
-
"aria-label": primaryFilter.label,
|
|
8463
|
-
options: primaryFilter.options,
|
|
8464
|
-
value: primaryFilter.value,
|
|
8465
|
-
size,
|
|
8466
|
-
onChange: primaryFilter.onChange
|
|
8467
|
-
}
|
|
8468
|
-
)),
|
|
8469
|
-
(filters || actions) && /* @__PURE__ */ jsxs("div", { className: cn("flex items-center gap-ds-2 justify-end", inPane ? "flex-none" : "flex-1"), children: [
|
|
8470
|
-
filters && /* @__PURE__ */ jsxs(
|
|
8471
|
-
Button,
|
|
8015
|
+
return (
|
|
8016
|
+
// a list's search and filters are how it's viewed, not a form's data: they never mark an overlay's form (0.21.0)
|
|
8017
|
+
/* @__PURE__ */ jsx(FormChangeCtx, { value: null, children: /* @__PURE__ */ jsx(ControlSizeContext.Provider, { value: size, children: /* @__PURE__ */ jsxs("div", { className: cn("flex flex-col gap-ds-3 min-w-0 mb-ds-3 last:mb-0", className), "data-table-toolbar": "", children: [
|
|
8018
|
+
hasControls && /* @__PURE__ */ jsxs("div", { ref: rowRef, className: "flex items-center gap-ds-2 flex-wrap", children: [
|
|
8019
|
+
search && /* @__PURE__ */ jsx(
|
|
8020
|
+
Input,
|
|
8472
8021
|
{
|
|
8473
|
-
|
|
8022
|
+
"aria-label": search.label,
|
|
8023
|
+
placeholder: search.placeholder ?? search.label,
|
|
8024
|
+
value: search.value,
|
|
8474
8025
|
size,
|
|
8475
|
-
|
|
8476
|
-
|
|
8477
|
-
"aria-expanded": open,
|
|
8478
|
-
"aria-controls": filterRowId,
|
|
8479
|
-
className: "mr-auto",
|
|
8480
|
-
children: [
|
|
8481
|
-
"Filters",
|
|
8482
|
-
count > 0 && !open && /* @__PURE__ */ jsx(Badge, { variant: "default", size: "xs", className: "ml-ds-1", children: count })
|
|
8483
|
-
]
|
|
8026
|
+
onChange: (e) => search.onChange(e.target.value),
|
|
8027
|
+
className: cn("flex-1 min-w-[160px]", !searchFills && "max-w-[280px]")
|
|
8484
8028
|
}
|
|
8485
8029
|
),
|
|
8486
|
-
|
|
8030
|
+
primaryFilter && (compact ? /* @__PURE__ */ jsx(
|
|
8031
|
+
Dropdown,
|
|
8032
|
+
{
|
|
8033
|
+
"aria-label": primaryFilter.label,
|
|
8034
|
+
options: primaryFilter.options.map((o) => ({ id: o.value, label: o.label })),
|
|
8035
|
+
value: primaryFilter.value,
|
|
8036
|
+
onChange: (v) => primaryFilter.onChange(v),
|
|
8037
|
+
size,
|
|
8038
|
+
className: "w-[150px]"
|
|
8039
|
+
}
|
|
8040
|
+
) : /* @__PURE__ */ jsx(
|
|
8041
|
+
SegmentedControl,
|
|
8042
|
+
{
|
|
8043
|
+
"aria-label": primaryFilter.label,
|
|
8044
|
+
options: primaryFilter.options,
|
|
8045
|
+
value: primaryFilter.value,
|
|
8046
|
+
size,
|
|
8047
|
+
onChange: primaryFilter.onChange
|
|
8048
|
+
}
|
|
8049
|
+
)),
|
|
8050
|
+
(filters || actions) && /* @__PURE__ */ jsxs("div", { className: cn("flex items-center gap-ds-2 justify-end", inPane ? "flex-none" : "flex-1"), children: [
|
|
8051
|
+
filters && /* @__PURE__ */ jsxs(
|
|
8052
|
+
Button,
|
|
8053
|
+
{
|
|
8054
|
+
type: "button",
|
|
8055
|
+
variant: open ? "secondary" : "outline",
|
|
8056
|
+
size,
|
|
8057
|
+
iconLeft: /* @__PURE__ */ jsx(Icon, { name: "filter", size: iconSize }),
|
|
8058
|
+
onClick: () => setOpen(!open),
|
|
8059
|
+
"aria-expanded": open,
|
|
8060
|
+
"aria-controls": filterRowId,
|
|
8061
|
+
className: "mr-auto",
|
|
8062
|
+
children: [
|
|
8063
|
+
"Filters",
|
|
8064
|
+
count > 0 && !open && /* @__PURE__ */ jsx(Badge, { variant: "default", size: "xs", className: "ml-ds-1", children: count })
|
|
8065
|
+
]
|
|
8066
|
+
}
|
|
8067
|
+
),
|
|
8068
|
+
actions
|
|
8069
|
+
] })
|
|
8070
|
+
] }),
|
|
8071
|
+
filters && open && /* @__PURE__ */ jsx("div", { id: filterRowId, className: "flex items-center gap-ds-3 flex-wrap", children: filters }),
|
|
8072
|
+
(countText !== null || hasChips) && /* @__PURE__ */ jsxs("div", { className: "flex items-center gap-ds-2 flex-wrap", children: [
|
|
8073
|
+
countText !== null && /* @__PURE__ */ jsx("span", { className: "text-xs text-[var(--ds-text-muted)]", "aria-live": "polite", "data-result-count": "", children: countText }),
|
|
8074
|
+
activeFilters?.map((f) => /* @__PURE__ */ jsx(Tag, { size: "sm", variant: "subtle", onRemove: f.onRemove, children: f.label }, f.id)),
|
|
8075
|
+
hasChips && onClearAll && /* @__PURE__ */ jsx(Button, { type: "button", variant: "ghost", size: "sm", onClick: onClearAll, children: "Clear all" })
|
|
8487
8076
|
] })
|
|
8488
|
-
] })
|
|
8489
|
-
|
|
8490
|
-
(countText !== null || hasChips) && /* @__PURE__ */ jsxs("div", { className: "flex items-center gap-ds-2 flex-wrap", children: [
|
|
8491
|
-
countText !== null && /* @__PURE__ */ jsx("span", { className: "text-xs text-[var(--ds-text-muted)]", "aria-live": "polite", "data-result-count": "", children: countText }),
|
|
8492
|
-
activeFilters?.map((f) => /* @__PURE__ */ jsx(Tag, { size: "sm", variant: "subtle", onRemove: f.onRemove, children: f.label }, f.id)),
|
|
8493
|
-
hasChips && onClearAll && /* @__PURE__ */ jsx(Button, { variant: "ghost", size: "sm", onClick: onClearAll, children: "Clear all" })
|
|
8494
|
-
] })
|
|
8495
|
-
] }) });
|
|
8077
|
+
] }) }) })
|
|
8078
|
+
);
|
|
8496
8079
|
}
|
|
8497
8080
|
var ICON_TEXT_OFFSET = "calc((2rem - 1.25rem) / 2)";
|
|
8498
8081
|
function Marker({ item, vertical }) {
|
|
@@ -8617,7 +8200,9 @@ function VerticalLayout({ items, className }) {
|
|
|
8617
8200
|
] })
|
|
8618
8201
|
] }, i)) });
|
|
8619
8202
|
}
|
|
8620
|
-
function Timeline({ items, orientation = "vertical", minItemWidth = 200, className, ref }) {
|
|
8203
|
+
function Timeline({ items: allItems, orientation = "vertical", minItemWidth = 200, className, ref, pager }) {
|
|
8204
|
+
useWholeListCheck("Timeline", allItems.length, pager);
|
|
8205
|
+
const items = pagerPart(allItems, pager);
|
|
8621
8206
|
const measureRef = useRef(null);
|
|
8622
8207
|
const width = useElementWidth(measureRef);
|
|
8623
8208
|
const setRefs = useCallback((node) => {
|
|
@@ -8627,7 +8212,12 @@ function Timeline({ items, orientation = "vertical", minItemWidth = 200, classNa
|
|
|
8627
8212
|
}, [ref]);
|
|
8628
8213
|
const fits = width === 0 || width >= items.length * minItemWidth;
|
|
8629
8214
|
const horizontal = orientation === "horizontal" || orientation === "responsive" && fits;
|
|
8630
|
-
|
|
8215
|
+
const list = /* @__PURE__ */ jsx("div", { ref: setRefs, "data-ds-list": "", "data-timeline-orientation": horizontal ? "horizontal" : "vertical", className: pager ? void 0 : className, children: horizontal ? /* @__PURE__ */ jsx(HorizontalLayout, { items, minItemWidth }) : /* @__PURE__ */ jsx(VerticalLayout, { items }) });
|
|
8216
|
+
if (!pager) return list;
|
|
8217
|
+
return /* @__PURE__ */ jsxs("div", { "data-gs-paged": "", className: cn("flex flex-col min-w-0", className), children: [
|
|
8218
|
+
list,
|
|
8219
|
+
allItems.length > 0 && /* @__PURE__ */ jsx(Pagination, { ...pager.props })
|
|
8220
|
+
] });
|
|
8631
8221
|
}
|
|
8632
8222
|
var CollapsibleContext = createContext(null);
|
|
8633
8223
|
function useCollapsible() {
|
|
@@ -8657,6 +8247,8 @@ function CollapsibleTrigger({ children, className }) {
|
|
|
8657
8247
|
if (isValidElement(children)) {
|
|
8658
8248
|
const child = children;
|
|
8659
8249
|
return cloneElement(child, {
|
|
8250
|
+
// a Button trigger in a form toggles; it never submits the form (0.21.0)
|
|
8251
|
+
...triggerType(child),
|
|
8660
8252
|
"aria-expanded": isOpen,
|
|
8661
8253
|
className: cn(child.props.className, className),
|
|
8662
8254
|
onClick: (e) => {
|
|
@@ -9206,7 +8798,7 @@ function ActionsRow({ message, onAction }) {
|
|
|
9206
8798
|
),
|
|
9207
8799
|
children: message.actions.map((a) => {
|
|
9208
8800
|
const { id, label, icon } = resolveAction(a);
|
|
9209
|
-
return /* @__PURE__ */ jsx(Tooltip, { content: label, children: /* @__PURE__ */ jsx(Button, { variant: "ghost", size: "icon-xs", "aria-label": label, onClick: () => run(id), children: /* @__PURE__ */ jsx(Icon, { name: icon, size: 14 }) }) }, id);
|
|
8801
|
+
return /* @__PURE__ */ jsx(Tooltip, { content: label, children: /* @__PURE__ */ jsx(Button, { type: "button", variant: "ghost", size: "icon-xs", "aria-label": label, onClick: () => run(id), children: /* @__PURE__ */ jsx(Icon, { name: icon, size: 14 }) }) }, id);
|
|
9210
8802
|
})
|
|
9211
8803
|
}
|
|
9212
8804
|
);
|
|
@@ -9343,12 +8935,13 @@ function ChatInputBar({ onSend, busy, onStop, onAttach, onVoice, placeholder })
|
|
|
9343
8935
|
),
|
|
9344
8936
|
/* @__PURE__ */ jsxs("div", { className: "flex items-center justify-between px-ds-2 pb-ds-1.5", children: [
|
|
9345
8937
|
/* @__PURE__ */ jsxs("div", { className: "flex items-center gap-ds-0.5", children: [
|
|
9346
|
-
onAttach && /* @__PURE__ */ jsx(Button, { variant: "ghost", size: "icon-sm", "aria-label": "Add attachment", onClick: onAttach, className: compact, children: /* @__PURE__ */ jsx(Icon, { name: "paperclip", size: glyph }) }),
|
|
9347
|
-
onVoice && /* @__PURE__ */ jsx(Button, { variant: "ghost", size: "icon-sm", "aria-label": "Voice message", onClick: onVoice, className: compact, children: /* @__PURE__ */ jsx(Icon, { name: "mic", size: glyph }) })
|
|
8938
|
+
onAttach && /* @__PURE__ */ jsx(Button, { type: "button", variant: "ghost", size: "icon-sm", "aria-label": "Add attachment", onClick: onAttach, className: compact, children: /* @__PURE__ */ jsx(Icon, { name: "paperclip", size: glyph }) }),
|
|
8939
|
+
onVoice && /* @__PURE__ */ jsx(Button, { type: "button", variant: "ghost", size: "icon-sm", "aria-label": "Voice message", onClick: onVoice, className: compact, children: /* @__PURE__ */ jsx(Icon, { name: "mic", size: glyph }) })
|
|
9348
8940
|
] }),
|
|
9349
|
-
busy ? /* @__PURE__ */ jsx(Button, { variant: "tertiary", size: "icon-sm", "aria-label": "Stop generating", onClick: onStop, className: compact, children: /* @__PURE__ */ jsx(Icon, { name: "square", size: glyph }) }) : /* @__PURE__ */ jsx(
|
|
8941
|
+
busy ? /* @__PURE__ */ jsx(Button, { type: "button", variant: "tertiary", size: "icon-sm", "aria-label": "Stop generating", onClick: onStop, className: compact, children: /* @__PURE__ */ jsx(Icon, { name: "square", size: glyph }) }) : /* @__PURE__ */ jsx(
|
|
9350
8942
|
Button,
|
|
9351
8943
|
{
|
|
8944
|
+
type: "button",
|
|
9352
8945
|
variant: text.trim() ? "default" : "ghost",
|
|
9353
8946
|
size: "icon-sm",
|
|
9354
8947
|
"aria-label": "Send message",
|
|
@@ -9462,7 +9055,7 @@ function ChatMessageList({
|
|
|
9462
9055
|
}),
|
|
9463
9056
|
typingUser && /* @__PURE__ */ jsx(TypingIndicator, { name: typingUser })
|
|
9464
9057
|
] }) }),
|
|
9465
|
-
showJump && !empty && /* @__PURE__ */ jsx("div", { className: "pointer-events-none absolute inset-x-0 bottom-ds-2 flex justify-center", children: /* @__PURE__ */ jsxs(Button, { variant: "secondary", size: "xs", className: "pointer-events-auto rounded-[var(--ds-radius-full)]", onClick: scrollToBottom, children: [
|
|
9058
|
+
showJump && !empty && /* @__PURE__ */ jsx("div", { className: "pointer-events-none absolute inset-x-0 bottom-ds-2 flex justify-center", children: /* @__PURE__ */ jsxs(Button, { type: "button", variant: "secondary", size: "xs", className: "pointer-events-auto rounded-[var(--ds-radius-full)]", onClick: scrollToBottom, children: [
|
|
9466
9059
|
/* @__PURE__ */ jsx(Icon, { name: "chevron-down", size: 14 }),
|
|
9467
9060
|
"Jump to latest"
|
|
9468
9061
|
] }) })
|
|
@@ -9517,10 +9110,11 @@ function ChatPanel({
|
|
|
9517
9110
|
] }),
|
|
9518
9111
|
/* @__PURE__ */ jsxs("div", { className: "flex shrink-0 items-center gap-ds-1", children: [
|
|
9519
9112
|
actions,
|
|
9520
|
-
onNewConversation && /* @__PURE__ */ jsx(Tooltip, { content: "New conversation", children: /* @__PURE__ */ jsx(Button, { variant: "ghost", size: "icon-sm", "aria-label": "New conversation", onClick: onNewConversation, children: /* @__PURE__ */ jsx(Icon, { name: "plus", size: 16 }) }) }),
|
|
9113
|
+
onNewConversation && /* @__PURE__ */ jsx(Tooltip, { content: "New conversation", children: /* @__PURE__ */ jsx(Button, { type: "button", variant: "ghost", size: "icon-sm", "aria-label": "New conversation", onClick: onNewConversation, children: /* @__PURE__ */ jsx(Icon, { name: "plus", size: 16 }) }) }),
|
|
9521
9114
|
onExpandedChange && /* @__PURE__ */ jsx(Tooltip, { content: expanded ? "Collapse" : "Expand", children: /* @__PURE__ */ jsx(
|
|
9522
9115
|
Button,
|
|
9523
9116
|
{
|
|
9117
|
+
type: "button",
|
|
9524
9118
|
variant: "ghost",
|
|
9525
9119
|
size: "icon-sm",
|
|
9526
9120
|
"aria-label": expanded ? "Collapse" : "Expand",
|
|
@@ -9529,7 +9123,7 @@ function ChatPanel({
|
|
|
9529
9123
|
children: /* @__PURE__ */ jsx(Icon, { name: expanded ? "minimize-2" : "maximize-2", size: 16 })
|
|
9530
9124
|
}
|
|
9531
9125
|
) }),
|
|
9532
|
-
/* @__PURE__ */ jsx(Tooltip, { content: "Close", children: /* @__PURE__ */ jsx(Button, { variant: "ghost", size: "icon-sm", "aria-label": "Close", onClick: onClose, ...{ [OVERLAY_CLOSE_ATTR]: "" }, children: /* @__PURE__ */ jsx(Icon, { name: "close", size: 16 }) }) })
|
|
9126
|
+
/* @__PURE__ */ jsx(Tooltip, { content: "Close", children: /* @__PURE__ */ jsx(Button, { type: "button", variant: "ghost", size: "icon-sm", "aria-label": "Close", onClick: onClose, ...{ [OVERLAY_CLOSE_ATTR]: "" }, children: /* @__PURE__ */ jsx(Icon, { name: "close", size: 16 }) }) })
|
|
9533
9127
|
] })
|
|
9534
9128
|
]
|
|
9535
9129
|
}
|
|
@@ -9878,7 +9472,8 @@ var StackedList = forwardRef(function StackedList2({
|
|
|
9878
9472
|
selectedId,
|
|
9879
9473
|
className,
|
|
9880
9474
|
flush,
|
|
9881
|
-
hover
|
|
9475
|
+
hover,
|
|
9476
|
+
pager
|
|
9882
9477
|
}, ref) {
|
|
9883
9478
|
const isPhone = useBreakpoint("sm");
|
|
9884
9479
|
const inCard = useContext(CardSurfaceCtx);
|
|
@@ -9891,20 +9486,22 @@ var StackedList = forwardRef(function StackedList2({
|
|
|
9891
9486
|
console.warn('StackedList: `flush` and `hover` are deprecated \u2014 pass variant="articles" for an article list; the default variant takes its inset from the pane or card it sits in.');
|
|
9892
9487
|
}, [legacy]);
|
|
9893
9488
|
const articles = variant === "articles";
|
|
9489
|
+
useWholeListCheck("StackedList", items.length, pager);
|
|
9490
|
+
const shown = pagerPart(items, pager);
|
|
9894
9491
|
const stackMeta = isPhone && articles;
|
|
9895
9492
|
const selectable = selectedId !== void 0 || items.some((i) => i.selected !== void 0);
|
|
9896
9493
|
const inset = articles ? inCard ? "px-ds-5" : "px-0" : inCard ? "px-ds-5" : inPane ? "pl-ds-3 pr-ds-4" : selectable ? "pl-ds-3 pr-0" : "px-0";
|
|
9897
|
-
|
|
9494
|
+
const list = /* @__PURE__ */ jsx(
|
|
9898
9495
|
"ul",
|
|
9899
9496
|
{
|
|
9900
9497
|
ref,
|
|
9901
9498
|
"data-ds-list": "",
|
|
9902
9499
|
className: cn(
|
|
9903
9500
|
divided && "divide-y-[length:var(--ds-border-width)] divide-[var(--ds-border-subtle)]",
|
|
9904
|
-
className
|
|
9501
|
+
!pager && className
|
|
9905
9502
|
),
|
|
9906
9503
|
role: "list",
|
|
9907
|
-
children:
|
|
9504
|
+
children: shown.map((item) => {
|
|
9908
9505
|
const isSelected = item.selected ?? (selectedId !== void 0 && item.id === selectedId);
|
|
9909
9506
|
const interactive = !!item.onClick;
|
|
9910
9507
|
const hasEmphasis = item.unread !== void 0;
|
|
@@ -9996,6 +9593,11 @@ var StackedList = forwardRef(function StackedList2({
|
|
|
9996
9593
|
})
|
|
9997
9594
|
}
|
|
9998
9595
|
);
|
|
9596
|
+
if (!pager) return list;
|
|
9597
|
+
return /* @__PURE__ */ jsxs("div", { "data-gs-paged": "", className: cn("flex flex-col min-w-0", className), children: [
|
|
9598
|
+
list,
|
|
9599
|
+
items.length > 0 && /* @__PURE__ */ jsx(Pagination, { ...pager.props })
|
|
9600
|
+
] });
|
|
9999
9601
|
});
|
|
10000
9602
|
var TIME_ZOOMS = ["day", "week", "month", "quarter"];
|
|
10001
9603
|
var DAY_MS = 864e5;
|
|
@@ -10766,15 +10368,15 @@ var TimeViewport = forwardRef(function TimeViewport2({
|
|
|
10766
10368
|
const hasHeader = headerNode != null || labelHeader != null;
|
|
10767
10369
|
const bar = toolbar === false ? null : /* @__PURE__ */ jsxs("div", { className: cn("flex shrink-0 flex-wrap items-center gap-ds-1 px-ds-2 py-ds-1.5 border-b-[length:var(--ds-border-width)]", border), children: [
|
|
10768
10370
|
onZoomChange && levels.length > 1 && /* @__PURE__ */ jsxs(Fragment, { children: [
|
|
10769
|
-
/* @__PURE__ */ jsx(Button, { variant: "ghost", size: "icon-sm", "aria-label": "Zoom out", "aria-disabled": !canZoomOut || void 0, className: "aria-disabled:opacity-disabled aria-disabled:cursor-not-allowed", onClick: () => zoom(1), children: /* @__PURE__ */ jsx(Icon, { name: "minus", size: 14 }) }),
|
|
10371
|
+
/* @__PURE__ */ jsx(Button, { type: "button", variant: "ghost", size: "icon-sm", "aria-label": "Zoom out", "aria-disabled": !canZoomOut || void 0, className: "aria-disabled:opacity-disabled aria-disabled:cursor-not-allowed", onClick: () => zoom(1), children: /* @__PURE__ */ jsx(Icon, { name: "minus", size: 14 }) }),
|
|
10770
10372
|
/* @__PURE__ */ jsx("span", { "aria-live": "polite", className: "min-w-[4.5rem] text-center text-xs text-[var(--ds-text-secondary)]", children: ZOOM_NAMES[scale.zoom] }),
|
|
10771
|
-
/* @__PURE__ */ jsx(Button, { variant: "ghost", size: "icon-sm", "aria-label": "Zoom in", "aria-disabled": !canZoomIn || void 0, className: "aria-disabled:opacity-disabled aria-disabled:cursor-not-allowed", onClick: () => zoom(-1), children: /* @__PURE__ */ jsx(Icon, { name: "plus", size: 14 }) })
|
|
10373
|
+
/* @__PURE__ */ jsx(Button, { type: "button", variant: "ghost", size: "icon-sm", "aria-label": "Zoom in", "aria-disabled": !canZoomIn || void 0, className: "aria-disabled:opacity-disabled aria-disabled:cursor-not-allowed", onClick: () => zoom(-1), children: /* @__PURE__ */ jsx(Icon, { name: "plus", size: 14 }) })
|
|
10772
10374
|
] }),
|
|
10773
|
-
/* @__PURE__ */ jsx(Button, { variant: "ghost", size: "icon-sm", "aria-label": "Previous period", onClick: () => api.page(-1), children: /* @__PURE__ */ jsx(Icon, { name: "chevron-left", size: 14 }) }),
|
|
10774
|
-
/* @__PURE__ */ jsx(Button, { variant: "secondary", size: "sm", disabled: todayAtX === null, onClick: () => {
|
|
10375
|
+
/* @__PURE__ */ jsx(Button, { type: "button", variant: "ghost", size: "icon-sm", "aria-label": "Previous period", onClick: () => api.page(-1), children: /* @__PURE__ */ jsx(Icon, { name: "chevron-left", size: 14 }) }),
|
|
10376
|
+
/* @__PURE__ */ jsx(Button, { type: "button", variant: "secondary", size: "sm", disabled: todayAtX === null, onClick: () => {
|
|
10775
10377
|
if (todayAtX !== null) setLeft(todayAtX - visibleWidth / 2);
|
|
10776
10378
|
}, children: "Today" }),
|
|
10777
|
-
/* @__PURE__ */ jsx(Button, { variant: "ghost", size: "icon-sm", "aria-label": "Next period", onClick: () => api.page(1), children: /* @__PURE__ */ jsx(Icon, { name: "chevron-right", size: 14 }) }),
|
|
10379
|
+
/* @__PURE__ */ jsx(Button, { type: "button", variant: "ghost", size: "icon-sm", "aria-label": "Next period", onClick: () => api.page(1), children: /* @__PURE__ */ jsx(Icon, { name: "chevron-right", size: 14 }) }),
|
|
10778
10380
|
toolbar
|
|
10779
10381
|
] });
|
|
10780
10382
|
return (
|
|
@@ -11032,7 +10634,7 @@ var UNDATED_INSET = 16;
|
|
|
11032
10634
|
var NO_GROUPS = [];
|
|
11033
10635
|
var NO_STATUSES = {};
|
|
11034
10636
|
var warned = /* @__PURE__ */ new Set();
|
|
11035
|
-
function
|
|
10637
|
+
function warnOnce2(message) {
|
|
11036
10638
|
let dev = false;
|
|
11037
10639
|
try {
|
|
11038
10640
|
dev = process.env.NODE_ENV !== "production";
|
|
@@ -11122,7 +10724,7 @@ function Gantt({
|
|
|
11122
10724
|
const selected = isControlled ? selectedId ?? null : selectedState;
|
|
11123
10725
|
useEffect(() => {
|
|
11124
10726
|
if (overridden !== null) {
|
|
11125
|
-
|
|
10727
|
+
warnOnce2("selectedId was given a value after the Gantt had kept a selection of its own. To control the selection, pass selectedId from the first render (null for none); to let the Gantt keep it, leave selectedId out.");
|
|
11126
10728
|
}
|
|
11127
10729
|
}, [overridden]);
|
|
11128
10730
|
const select = (item) => {
|
|
@@ -11134,8 +10736,8 @@ function Gantt({
|
|
|
11134
10736
|
const phases = useMemo(() => uniqueById(groups), [groups]);
|
|
11135
10737
|
useEffect(() => {
|
|
11136
10738
|
const quoted = (ids) => ids.map((id) => `"${id}"`).join(", ");
|
|
11137
|
-
if (plan.repeated.length)
|
|
11138
|
-
if (phases.repeated.length)
|
|
10739
|
+
if (plan.repeated.length) warnOnce2(`more than one item has the id ${quoted(plan.repeated)}; only the first of each is shown.`);
|
|
10740
|
+
if (phases.repeated.length) warnOnce2(`more than one group has the id ${quoted(phases.repeated)}; only the first of each is shown.`);
|
|
11139
10741
|
}, [plan, phases]);
|
|
11140
10742
|
const tasks = plan.unique;
|
|
11141
10743
|
const extent = useMemo(() => itemsExtent(tasks), [tasks]);
|
|
@@ -12032,14 +11634,17 @@ function TabsRoot(props) {
|
|
|
12032
11634
|
const { tabs, mobile = "scroll" } = props;
|
|
12033
11635
|
const collapseToDropdown = isMobile && (orientation === "responsive" || mobile === "dropdown");
|
|
12034
11636
|
if (collapseToDropdown) {
|
|
12035
|
-
return
|
|
12036
|
-
|
|
12037
|
-
{
|
|
12038
|
-
|
|
12039
|
-
|
|
12040
|
-
|
|
12041
|
-
|
|
12042
|
-
|
|
11637
|
+
return (
|
|
11638
|
+
// choosing a tab is navigation, never a change to a form around it (0.21.0)
|
|
11639
|
+
/* @__PURE__ */ jsx(FormChangeCtx, { value: null, children: /* @__PURE__ */ jsx(
|
|
11640
|
+
Dropdown,
|
|
11641
|
+
{
|
|
11642
|
+
options: tabs.filter((t) => !t.disabled).map((t) => ({ id: t.id, label: t.label, group: t.group })),
|
|
11643
|
+
value: activeTab,
|
|
11644
|
+
onChange: (v) => onTabChange(v),
|
|
11645
|
+
className
|
|
11646
|
+
}
|
|
11647
|
+
) })
|
|
12043
11648
|
);
|
|
12044
11649
|
}
|
|
12045
11650
|
if (effectiveOrientation === "vertical") {
|
|
@@ -12141,7 +11746,7 @@ function SettingsLayout({
|
|
|
12141
11746
|
return (
|
|
12142
11747
|
// gap-x-ds-8 is the rail's gap, unused in one column: the threshold reads the same gap as the row (useColumnGap)
|
|
12143
11748
|
/* @__PURE__ */ jsxs("div", { ref: rootRef, "data-settings-layout": "sidebar", "data-collapsed": "true", className: cn("flex flex-col gap-y-ds-6 gap-x-ds-8", className), children: [
|
|
12144
|
-
/* @__PURE__ */ jsx(
|
|
11749
|
+
/* @__PURE__ */ jsx(FormChangeCtx, { value: null, children: /* @__PURE__ */ jsx(
|
|
12145
11750
|
Dropdown,
|
|
12146
11751
|
{
|
|
12147
11752
|
"aria-label": ariaLabel,
|
|
@@ -12149,7 +11754,7 @@ function SettingsLayout({
|
|
|
12149
11754
|
value,
|
|
12150
11755
|
onChange: (v) => onChange(v)
|
|
12151
11756
|
}
|
|
12152
|
-
),
|
|
11757
|
+
) }),
|
|
12153
11758
|
/* @__PURE__ */ jsx("div", { "data-settings-panel": "", className: PANEL_CLASSES, style: PANEL_STYLE, children })
|
|
12154
11759
|
] })
|
|
12155
11760
|
);
|
|
@@ -12394,280 +11999,6 @@ var Breadcrumbs = forwardRef(function Breadcrumbs2({
|
|
|
12394
11999
|
dropdown
|
|
12395
12000
|
] });
|
|
12396
12001
|
});
|
|
12397
|
-
function Popover({ open, onOpenChange, trigger, children, side = "bottom", align = "center", width, className, container }) {
|
|
12398
|
-
const triggerRef = useRef(null);
|
|
12399
|
-
const floatingRef = useRef(null);
|
|
12400
|
-
const [triggerWidth, setTriggerWidth] = useState(void 0);
|
|
12401
|
-
const setTriggerNode = useCallback((node) => {
|
|
12402
|
-
triggerRef.current = node;
|
|
12403
|
-
setTriggerWidth(node?.offsetWidth);
|
|
12404
|
-
}, []);
|
|
12405
|
-
const pos = usePosition(triggerRef, floatingRef, open, { side, align, offset: 8, flip: true });
|
|
12406
|
-
const onOpenChangeRef = useLatest(onOpenChange);
|
|
12407
|
-
const { props: pressMarks, marked } = usePressMarks();
|
|
12408
|
-
const { isTop: isTopLayer, returnFocus } = usePopupFocus(open, { trigger: triggerRef, panel: floatingRef, close: () => onOpenChangeRef.current(false), tabExits: "edges", marked });
|
|
12409
|
-
useEffect(() => {
|
|
12410
|
-
if (!open) return;
|
|
12411
|
-
const onKeyDown = (e) => {
|
|
12412
|
-
if (e.key !== "Escape" || e.defaultPrevented || !isTopLayer()) return;
|
|
12413
|
-
const active = document.activeElement;
|
|
12414
|
-
if (active && active !== document.body && !triggerRef.current?.contains(active) && !floatingRef.current?.contains(active)) return;
|
|
12415
|
-
e.preventDefault();
|
|
12416
|
-
returnFocus();
|
|
12417
|
-
onOpenChangeRef.current(false);
|
|
12418
|
-
};
|
|
12419
|
-
const onPress = (e) => {
|
|
12420
|
-
const target = e.target;
|
|
12421
|
-
if (marked(e) || triggerRef.current?.contains(target) || floatingRef.current?.contains(target)) return;
|
|
12422
|
-
onOpenChangeRef.current(false);
|
|
12423
|
-
};
|
|
12424
|
-
document.addEventListener("keydown", onKeyDown);
|
|
12425
|
-
document.addEventListener("mousedown", onPress);
|
|
12426
|
-
return () => {
|
|
12427
|
-
document.removeEventListener("keydown", onKeyDown);
|
|
12428
|
-
document.removeEventListener("mousedown", onPress);
|
|
12429
|
-
};
|
|
12430
|
-
}, [open, onOpenChangeRef, isTopLayer, returnFocus, marked]);
|
|
12431
|
-
useEffect(() => {
|
|
12432
|
-
if (open) focusInitial(floatingRef.current);
|
|
12433
|
-
}, [open]);
|
|
12434
|
-
return /* @__PURE__ */ jsxs(Fragment, { children: [
|
|
12435
|
-
/* @__PURE__ */ jsx(
|
|
12436
|
-
Slot,
|
|
12437
|
-
{
|
|
12438
|
-
ref: setTriggerNode,
|
|
12439
|
-
onClick: () => {
|
|
12440
|
-
setTriggerWidth(triggerRef.current?.offsetWidth);
|
|
12441
|
-
onOpenChange(!open);
|
|
12442
|
-
},
|
|
12443
|
-
children: trigger
|
|
12444
|
-
}
|
|
12445
|
-
),
|
|
12446
|
-
open && createPortal(
|
|
12447
|
-
/* @__PURE__ */ jsx(
|
|
12448
|
-
"div",
|
|
12449
|
-
{
|
|
12450
|
-
ref: floatingRef,
|
|
12451
|
-
"data-gs": "popover",
|
|
12452
|
-
...pressMarks,
|
|
12453
|
-
onClick: (e) => e.stopPropagation(),
|
|
12454
|
-
className: cn(
|
|
12455
|
-
"fixed z-[var(--ds-z-popover)]",
|
|
12456
|
-
"bg-[var(--ds-bg-surface-elevated)]",
|
|
12457
|
-
GLASS_DROPDOWN,
|
|
12458
|
-
"border-[length:var(--ds-border-width)] border-[var(--ds-border-default)]",
|
|
12459
|
-
"rounded-[var(--ds-radius-md)]",
|
|
12460
|
-
className
|
|
12461
|
-
),
|
|
12462
|
-
style: {
|
|
12463
|
-
top: pos.top,
|
|
12464
|
-
left: pos.left,
|
|
12465
|
-
width: width === "trigger" ? triggerWidth : width === "auto" ? void 0 : width
|
|
12466
|
-
},
|
|
12467
|
-
children
|
|
12468
|
-
}
|
|
12469
|
-
),
|
|
12470
|
-
container ?? document.body
|
|
12471
|
-
)
|
|
12472
|
-
] });
|
|
12473
|
-
}
|
|
12474
|
-
function Pagination(props) {
|
|
12475
|
-
if ((props.mode === "load-more" || props.mode === "infinite-scroll") && props.onLoadMore) return /* @__PURE__ */ jsx(LoadMore, { ...props, onLoadMore: props.onLoadMore, scroll: props.mode === "infinite-scroll" });
|
|
12476
|
-
return /* @__PURE__ */ jsx(PageNumbers, { ...props });
|
|
12477
|
-
}
|
|
12478
|
-
function contentTop(el) {
|
|
12479
|
-
let top = el.getBoundingClientRect().top + window.scrollY;
|
|
12480
|
-
for (let n = el.parentElement; n && n !== document.documentElement; n = n.parentElement) top += n.scrollTop;
|
|
12481
|
-
return top;
|
|
12482
|
-
}
|
|
12483
|
-
function LoadMore({ hasMore, onLoadMore, loadMoreLabel, currentPage, scroll, className }) {
|
|
12484
|
-
const marker = useRef(null);
|
|
12485
|
-
const load = useLatest(onLoadMore);
|
|
12486
|
-
const loadedAt = useRef(null);
|
|
12487
|
-
useEffect(() => {
|
|
12488
|
-
const el = marker.current;
|
|
12489
|
-
if (!scroll || !hasMore || !el || typeof IntersectionObserver === "undefined") return;
|
|
12490
|
-
const observer = new IntersectionObserver((entries) => {
|
|
12491
|
-
if (!entries.some((e) => e.isIntersecting)) return;
|
|
12492
|
-
const at = contentTop(el);
|
|
12493
|
-
if (loadedAt.current !== null && Math.abs(at - loadedAt.current) < 1) return;
|
|
12494
|
-
loadedAt.current = at;
|
|
12495
|
-
load.current();
|
|
12496
|
-
}, { rootMargin: "200px 0px" });
|
|
12497
|
-
observer.observe(el);
|
|
12498
|
-
const rearm = () => {
|
|
12499
|
-
loadedAt.current = null;
|
|
12500
|
-
};
|
|
12501
|
-
window.addEventListener("scroll", rearm, { capture: true, passive: true });
|
|
12502
|
-
return () => {
|
|
12503
|
-
observer.disconnect();
|
|
12504
|
-
window.removeEventListener("scroll", rearm, { capture: true });
|
|
12505
|
-
};
|
|
12506
|
-
}, [scroll, hasMore, currentPage, load]);
|
|
12507
|
-
if (!hasMore) return null;
|
|
12508
|
-
return /* @__PURE__ */ jsxs("div", { "data-ds-pager": "", "data-pagination-mode": scroll ? "infinite-scroll" : "load-more", className: cn("flex flex-col items-center", className), children: [
|
|
12509
|
-
scroll && /* @__PURE__ */ jsx("div", { ref: marker, "data-load-more-trigger": "", "aria-hidden": "true", className: "h-px w-full" }),
|
|
12510
|
-
/* @__PURE__ */ jsx(Button, { variant: "secondary", onClick: onLoadMore, children: loadMoreLabel ?? "Load more" })
|
|
12511
|
-
] });
|
|
12512
|
-
}
|
|
12513
|
-
function PageNumbers({ currentPage, totalPages, onPageChange, pageSize: pageSizeProp, pageSizeOptions, onPageSizeChange, className }) {
|
|
12514
|
-
const pages = buildPageRange(currentPage, totalPages);
|
|
12515
|
-
const preferences = useShellPreferences();
|
|
12516
|
-
const pageSize = pageSizeProp ?? preferences.itemsPerPage;
|
|
12517
|
-
return /* @__PURE__ */ jsxs("nav", { "aria-label": "Pagination", "data-ds-pager": "", className: cn("flex flex-wrap items-center gap-ds-3", className), children: [
|
|
12518
|
-
pageSizeOptions && pageSize != null && onPageSizeChange && /* @__PURE__ */ jsxs("div", { className: "flex items-center gap-ds-2", children: [
|
|
12519
|
-
/* @__PURE__ */ jsx("span", { className: "text-sm text-[var(--ds-text-muted)] whitespace-nowrap", children: "Rows per page" }),
|
|
12520
|
-
/* @__PURE__ */ jsx(
|
|
12521
|
-
Dropdown,
|
|
12522
|
-
{
|
|
12523
|
-
options: pageSizeOptions.map((n) => ({ id: String(n), label: String(n) })),
|
|
12524
|
-
value: String(pageSize),
|
|
12525
|
-
onChange: (v) => onPageSizeChange(Number(v)),
|
|
12526
|
-
size: "sm",
|
|
12527
|
-
className: "w-[4.5rem]"
|
|
12528
|
-
}
|
|
12529
|
-
)
|
|
12530
|
-
] }),
|
|
12531
|
-
/* @__PURE__ */ jsxs("div", { className: "flex items-center gap-ds-1", children: [
|
|
12532
|
-
/* @__PURE__ */ jsx(
|
|
12533
|
-
"button",
|
|
12534
|
-
{
|
|
12535
|
-
type: "button",
|
|
12536
|
-
onClick: () => onPageChange(currentPage - 1),
|
|
12537
|
-
disabled: currentPage <= 1,
|
|
12538
|
-
"aria-label": "Previous page",
|
|
12539
|
-
className: cn(
|
|
12540
|
-
"inline-flex items-center justify-center h-[var(--ds-control-height-sm)] w-[var(--ds-control-height-sm)] text-sm cursor-pointer",
|
|
12541
|
-
"rounded-[var(--ds-radius-md)]",
|
|
12542
|
-
"border-[length:var(--ds-border-width)] border-[var(--ds-border-default)]",
|
|
12543
|
-
"bg-[var(--ds-bg-surface)] text-[var(--ds-text-secondary)]",
|
|
12544
|
-
"transition-colors duration-[var(--ds-transition-speed)]",
|
|
12545
|
-
"hover:bg-[var(--ds-bg-muted)] hover:text-[var(--ds-text-primary)]",
|
|
12546
|
-
"disabled:opacity-disabled disabled:cursor-not-allowed"
|
|
12547
|
-
),
|
|
12548
|
-
children: /* @__PURE__ */ jsx(Icon, { name: "chevron-right", size: 16, className: "rotate-180" })
|
|
12549
|
-
}
|
|
12550
|
-
),
|
|
12551
|
-
pages.map(
|
|
12552
|
-
(p, i) => p === "..." ? /* @__PURE__ */ jsx(EllipsisJumper, { totalPages, onPageChange }, `ellipsis-${i}`) : /* @__PURE__ */ jsx(
|
|
12553
|
-
"button",
|
|
12554
|
-
{
|
|
12555
|
-
type: "button",
|
|
12556
|
-
onClick: () => onPageChange(p),
|
|
12557
|
-
"aria-current": p === currentPage ? "page" : void 0,
|
|
12558
|
-
className: cn(
|
|
12559
|
-
"inline-flex items-center justify-center h-[var(--ds-control-height-sm)] w-[var(--ds-control-height-sm)] text-sm font-medium cursor-pointer",
|
|
12560
|
-
"rounded-[var(--ds-radius-md)]",
|
|
12561
|
-
"border-[length:var(--ds-border-width)]",
|
|
12562
|
-
"transition-colors duration-[var(--ds-transition-speed)]",
|
|
12563
|
-
p === currentPage ? "bg-[var(--ds-accent-primary)] [background-image:var(--ds-gradient)] text-[var(--ds-text-on-primary)] border-[var(--ds-accent-primary)]" : "bg-[var(--ds-bg-surface)] text-[var(--ds-text-secondary)] border-[var(--ds-border-default)] hover:bg-[var(--ds-bg-muted)] hover:text-[var(--ds-text-primary)]"
|
|
12564
|
-
),
|
|
12565
|
-
children: p
|
|
12566
|
-
},
|
|
12567
|
-
p
|
|
12568
|
-
)
|
|
12569
|
-
),
|
|
12570
|
-
/* @__PURE__ */ jsx(
|
|
12571
|
-
"button",
|
|
12572
|
-
{
|
|
12573
|
-
type: "button",
|
|
12574
|
-
onClick: () => onPageChange(currentPage + 1),
|
|
12575
|
-
disabled: currentPage >= totalPages,
|
|
12576
|
-
"aria-label": "Next page",
|
|
12577
|
-
className: cn(
|
|
12578
|
-
"inline-flex items-center justify-center h-[var(--ds-control-height-sm)] w-[var(--ds-control-height-sm)] text-sm cursor-pointer",
|
|
12579
|
-
"rounded-[var(--ds-radius-md)]",
|
|
12580
|
-
"border-[length:var(--ds-border-width)] border-[var(--ds-border-default)]",
|
|
12581
|
-
"bg-[var(--ds-bg-surface)] text-[var(--ds-text-secondary)]",
|
|
12582
|
-
"transition-colors duration-[var(--ds-transition-speed)]",
|
|
12583
|
-
"hover:bg-[var(--ds-bg-muted)] hover:text-[var(--ds-text-primary)]",
|
|
12584
|
-
"disabled:opacity-disabled disabled:cursor-not-allowed"
|
|
12585
|
-
),
|
|
12586
|
-
children: /* @__PURE__ */ jsx(Icon, { name: "chevron-right", size: 16 })
|
|
12587
|
-
}
|
|
12588
|
-
)
|
|
12589
|
-
] })
|
|
12590
|
-
] });
|
|
12591
|
-
}
|
|
12592
|
-
function buildPageRange(current, total) {
|
|
12593
|
-
if (total <= 7) return Array.from({ length: total }, (_, i) => i + 1);
|
|
12594
|
-
const pages = [1];
|
|
12595
|
-
if (current > 3) pages.push("...");
|
|
12596
|
-
const start = Math.max(2, current - 1);
|
|
12597
|
-
const end = Math.min(total - 1, current + 1);
|
|
12598
|
-
for (let i = start; i <= end; i++) pages.push(i);
|
|
12599
|
-
if (current < total - 2) pages.push("...");
|
|
12600
|
-
pages.push(total);
|
|
12601
|
-
return pages;
|
|
12602
|
-
}
|
|
12603
|
-
function EllipsisJumper({ totalPages, onPageChange }) {
|
|
12604
|
-
const [open, setOpen] = useState(false);
|
|
12605
|
-
const [jumpPage, setJumpPage] = useState(1);
|
|
12606
|
-
const handleOpenChange = (next) => {
|
|
12607
|
-
if (next) setJumpPage(1);
|
|
12608
|
-
setOpen(next);
|
|
12609
|
-
};
|
|
12610
|
-
const handleGo = () => {
|
|
12611
|
-
const clamped = Math.min(totalPages, Math.max(1, jumpPage));
|
|
12612
|
-
onPageChange(clamped);
|
|
12613
|
-
setOpen(false);
|
|
12614
|
-
};
|
|
12615
|
-
return /* @__PURE__ */ jsx(
|
|
12616
|
-
Popover,
|
|
12617
|
-
{
|
|
12618
|
-
open,
|
|
12619
|
-
onOpenChange: handleOpenChange,
|
|
12620
|
-
trigger: /* @__PURE__ */ jsx(
|
|
12621
|
-
"button",
|
|
12622
|
-
{
|
|
12623
|
-
type: "button",
|
|
12624
|
-
"aria-label": "Go to page",
|
|
12625
|
-
onClick: () => handleOpenChange(true),
|
|
12626
|
-
className: cn(
|
|
12627
|
-
"inline-flex items-center justify-center h-[var(--ds-control-height-sm)] w-[var(--ds-control-height-sm)] text-sm cursor-pointer",
|
|
12628
|
-
"rounded-[var(--ds-radius-md)]",
|
|
12629
|
-
"text-[var(--ds-text-muted)]",
|
|
12630
|
-
"transition-colors duration-[var(--ds-transition-speed)]",
|
|
12631
|
-
"hover:bg-[var(--ds-bg-muted)] hover:text-[var(--ds-text-primary)]"
|
|
12632
|
-
),
|
|
12633
|
-
children: "\u2026"
|
|
12634
|
-
}
|
|
12635
|
-
),
|
|
12636
|
-
children: /* @__PURE__ */ jsxs("div", { className: "flex flex-col gap-ds-2 p-ds-3", children: [
|
|
12637
|
-
/* @__PURE__ */ jsx("label", { className: "text-xs font-medium text-[var(--ds-text-secondary)]", children: "Go to page" }),
|
|
12638
|
-
/* @__PURE__ */ jsxs("div", { className: "flex items-center gap-ds-2", children: [
|
|
12639
|
-
/* @__PURE__ */ jsx(
|
|
12640
|
-
NumberInput,
|
|
12641
|
-
{
|
|
12642
|
-
value: jumpPage,
|
|
12643
|
-
onChange: setJumpPage,
|
|
12644
|
-
min: 1,
|
|
12645
|
-
max: totalPages,
|
|
12646
|
-
step: 1,
|
|
12647
|
-
size: "sm",
|
|
12648
|
-
className: "w-[5rem]"
|
|
12649
|
-
}
|
|
12650
|
-
),
|
|
12651
|
-
/* @__PURE__ */ jsx(
|
|
12652
|
-
"button",
|
|
12653
|
-
{
|
|
12654
|
-
type: "button",
|
|
12655
|
-
onClick: handleGo,
|
|
12656
|
-
className: cn(
|
|
12657
|
-
"px-ds-2.5 h-[var(--ds-control-height-sm)] text-xs font-medium cursor-pointer",
|
|
12658
|
-
"rounded-[var(--ds-radius-md)]",
|
|
12659
|
-
"bg-[var(--ds-accent-primary)] text-[var(--ds-text-on-primary)]",
|
|
12660
|
-
"transition-colors duration-[var(--ds-transition-speed)]",
|
|
12661
|
-
"hover:opacity-90"
|
|
12662
|
-
),
|
|
12663
|
-
children: "Go"
|
|
12664
|
-
}
|
|
12665
|
-
)
|
|
12666
|
-
] })
|
|
12667
|
-
] })
|
|
12668
|
-
}
|
|
12669
|
-
);
|
|
12670
|
-
}
|
|
12671
12002
|
var HeaderTabRowContext = createContext(null);
|
|
12672
12003
|
function useHeaderTabRow() {
|
|
12673
12004
|
return useContext(HeaderTabRowContext);
|
|
@@ -13898,6 +13229,16 @@ function useToastOptional() {
|
|
|
13898
13229
|
}
|
|
13899
13230
|
var toastSeq = 0;
|
|
13900
13231
|
var heardSeq = 0;
|
|
13232
|
+
var HEARD_MS = 7e3;
|
|
13233
|
+
var RUN_END_MS = 20;
|
|
13234
|
+
var isThenable2 = (value) => !!value && typeof value.then === "function";
|
|
13235
|
+
function textOf(node) {
|
|
13236
|
+
if (node == null || typeof node === "boolean") return "";
|
|
13237
|
+
if (typeof node === "string" || typeof node === "number") return String(node);
|
|
13238
|
+
if (Array.isArray(node)) return node.map(textOf).join("");
|
|
13239
|
+
if (typeof node === "object" && "props" in node) return textOf(node.props.children);
|
|
13240
|
+
return "";
|
|
13241
|
+
}
|
|
13901
13242
|
var mergeable = (e) => !e.action && e.variant !== "error";
|
|
13902
13243
|
function fill(entries, slots) {
|
|
13903
13244
|
let shown = entries.filter((e) => e.shown).length;
|
|
@@ -13917,14 +13258,18 @@ function ToastProvider({ children, maxVisible = 3, position = "bottom-right", du
|
|
|
13917
13258
|
const [list, setList] = useState([]);
|
|
13918
13259
|
const entries = useRef([]);
|
|
13919
13260
|
const isMobile = useBreakpoint("sm");
|
|
13920
|
-
const
|
|
13261
|
+
const shownDuringRuns = useRef([]);
|
|
13262
|
+
const showSeq = useRef(0);
|
|
13263
|
+
const runs = useRef(/* @__PURE__ */ new Map());
|
|
13264
|
+
const runSeq = useRef(0);
|
|
13921
13265
|
const [heard, setHeard] = useState([]);
|
|
13922
13266
|
const [hovered, setHovered] = useState(false);
|
|
13923
13267
|
const [focusInside, setFocusInside] = useState(false);
|
|
13924
13268
|
const paused = pauseOnHover && hovered || focusInside;
|
|
13925
13269
|
const stackRef = useRef(null);
|
|
13926
13270
|
const returnTo = useRef(null);
|
|
13927
|
-
const
|
|
13271
|
+
const pressed = useRef(/* @__PURE__ */ new Set());
|
|
13272
|
+
const pointerAt = useRef(0);
|
|
13928
13273
|
const viaKey = useRef(false);
|
|
13929
13274
|
const refocus = useRef(false);
|
|
13930
13275
|
const pendingHeard = useRef(/* @__PURE__ */ new Map());
|
|
@@ -13943,58 +13288,75 @@ function ToastProvider({ children, maxVisible = 3, position = "bottom-right", du
|
|
|
13943
13288
|
entries.current = fill(next, slots);
|
|
13944
13289
|
setList(entries.current);
|
|
13945
13290
|
}, [slots]);
|
|
13946
|
-
|
|
13947
|
-
if (slots !== slotsSeen) {
|
|
13948
|
-
setSlotsSeen(slots);
|
|
13291
|
+
useEffect(() => {
|
|
13949
13292
|
let kept = 0;
|
|
13950
|
-
|
|
13293
|
+
const reslotted = entries.current.map((e) => e.shown && ++kept > slots ? { ...e, shown: false } : e);
|
|
13294
|
+
const next = fill(reslotted, slots);
|
|
13295
|
+
if (next.length === entries.current.length && next.every((e, i) => e === entries.current[i])) return;
|
|
13296
|
+
commit(next);
|
|
13297
|
+
}, [slots, commit]);
|
|
13298
|
+
if (list.every((t) => !t.shown) && (hovered || focusInside)) {
|
|
13299
|
+
setHovered(false);
|
|
13300
|
+
setFocusInside(false);
|
|
13951
13301
|
}
|
|
13952
|
-
|
|
13953
|
-
entries.current = list;
|
|
13954
|
-
}, [list]);
|
|
13302
|
+
const clearTimers = useRef(/* @__PURE__ */ new Set());
|
|
13955
13303
|
const announce = useCallback((entry) => {
|
|
13956
13304
|
pendingHeard.current.set(entry.id, entry);
|
|
13957
13305
|
if (heardTimer.current) return;
|
|
13958
13306
|
heardTimer.current = setTimeout(() => {
|
|
13959
13307
|
heardTimer.current = void 0;
|
|
13960
|
-
const batch = [...pendingHeard.current.values()]
|
|
13308
|
+
const batch = [...pendingHeard.current.values()].map((e) => {
|
|
13309
|
+
const words = textOf(e.message).trim();
|
|
13310
|
+
const sentence = !words || /[.!?…]$/.test(words) ? words : `${words}.`;
|
|
13311
|
+
return { id: `heard-${++heardSeq}`, assertive: e.variant === "error", text: e.action ? `${sentence} Press F8 to reach ${e.action.label}.`.trim() : sentence };
|
|
13312
|
+
}).filter((h) => h.text);
|
|
13961
13313
|
pendingHeard.current.clear();
|
|
13962
|
-
|
|
13963
|
-
|
|
13964
|
-
|
|
13965
|
-
|
|
13966
|
-
|
|
13967
|
-
|
|
13968
|
-
|
|
13969
|
-
|
|
13314
|
+
if (!batch.length) return;
|
|
13315
|
+
setHeard((list2) => [...list2, ...batch].slice(-5));
|
|
13316
|
+
const ids = new Set(batch.map((h) => h.id));
|
|
13317
|
+
const timer = setTimeout(() => {
|
|
13318
|
+
clearTimers.current.delete(timer);
|
|
13319
|
+
setHeard((list2) => list2.filter((h) => !ids.has(h.id)));
|
|
13320
|
+
}, HEARD_MS);
|
|
13321
|
+
clearTimers.current.add(timer);
|
|
13970
13322
|
}, 0);
|
|
13971
13323
|
}, []);
|
|
13972
13324
|
useEffect(() => () => {
|
|
13973
13325
|
if (heardTimer.current) clearTimeout(heardTimer.current);
|
|
13326
|
+
heardTimer.current = void 0;
|
|
13327
|
+
clearTimers.current.forEach(clearTimeout);
|
|
13328
|
+
clearTimers.current.clear();
|
|
13974
13329
|
}, []);
|
|
13975
|
-
const leaving = useCallback(() => {
|
|
13976
|
-
|
|
13330
|
+
const leaving = useCallback((id) => {
|
|
13331
|
+
const stack = stackRef.current;
|
|
13332
|
+
const holder = id === void 0 ? stack : [...stack?.querySelectorAll("[data-toast-id]") ?? []].find((n) => n.getAttribute("data-toast-id") === id);
|
|
13333
|
+
if (!holder?.contains(document.activeElement)) return;
|
|
13977
13334
|
refocus.current = true;
|
|
13978
13335
|
setFocusInside(false);
|
|
13979
13336
|
}, []);
|
|
13980
13337
|
const remove = useCallback((id) => {
|
|
13981
|
-
leaving();
|
|
13338
|
+
leaving(id);
|
|
13982
13339
|
commit(entries.current.filter((t) => t.id !== id));
|
|
13983
13340
|
}, [commit, leaving]);
|
|
13984
13341
|
const dismissAll = useCallback(() => {
|
|
13985
13342
|
leaving();
|
|
13986
13343
|
commit([]);
|
|
13987
13344
|
}, [commit, leaving]);
|
|
13345
|
+
const noteShown = useCallback((id, variant, action, fresh) => {
|
|
13346
|
+
if (runs.current.size) shownDuringRuns.current.push({ seq: ++showSeq.current, at: Date.now(), id, variant, action, fresh });
|
|
13347
|
+
}, []);
|
|
13988
13348
|
const update = useCallback((id, message, options = {}) => {
|
|
13989
13349
|
const list2 = entries.current;
|
|
13990
13350
|
const at = list2.findIndex((t2) => t2.id === id);
|
|
13991
13351
|
if (at === -1) return;
|
|
13352
|
+
pressed.current.delete(id);
|
|
13992
13353
|
const t = list2[at];
|
|
13993
13354
|
const next = [...list2];
|
|
13994
13355
|
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
13356
|
commit(next);
|
|
13996
13357
|
announce(next[at]);
|
|
13997
|
-
|
|
13358
|
+
noteShown(id, next[at].variant, !!next[at].action, false);
|
|
13359
|
+
}, [commit, announce, noteShown]);
|
|
13998
13360
|
const toast = useCallback((message, options = {}) => {
|
|
13999
13361
|
const list2 = entries.current;
|
|
14000
13362
|
const base = { message, variant: options.variant ?? "default", duration: options.duration ?? duration, action: options.action, actionWindow: options.actionWindow, key: options.key };
|
|
@@ -14003,41 +13365,31 @@ function ToastProvider({ children, maxVisible = 3, position = "bottom-right", du
|
|
|
14003
13365
|
if (at !== -1) {
|
|
14004
13366
|
const next = [...list2];
|
|
14005
13367
|
next[at] = { ...list2[at], ...base, version: list2[at].version + 1 };
|
|
14006
|
-
|
|
13368
|
+
pressed.current.delete(options.id);
|
|
14007
13369
|
commit(next);
|
|
14008
13370
|
announce(next[at]);
|
|
13371
|
+
noteShown(options.id, base.variant, !!base.action, false);
|
|
14009
13372
|
return options.id;
|
|
14010
13373
|
}
|
|
14011
13374
|
}
|
|
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
13375
|
if (coalesce && base.key && mergeable(base)) {
|
|
14024
13376
|
const at = list2.findIndex((t) => t.key === base.key && mergeable(t));
|
|
14025
13377
|
if (at !== -1) {
|
|
14026
13378
|
const next = [...list2];
|
|
14027
13379
|
next[at] = { ...list2[at], ...base, version: list2[at].version + 1 };
|
|
14028
|
-
createdIds.current.push(list2[at].id);
|
|
14029
13380
|
commit(next);
|
|
14030
13381
|
announce(next[at]);
|
|
13382
|
+
noteShown(list2[at].id, base.variant, !!base.action, false);
|
|
14031
13383
|
return list2[at].id;
|
|
14032
13384
|
}
|
|
14033
13385
|
}
|
|
14034
13386
|
const id = options.id ?? `toast-${++toastSeq}`;
|
|
14035
13387
|
const entry = { id, ...base, shown: false, version: 0 };
|
|
14036
|
-
createdIds.current.push(id);
|
|
14037
13388
|
commit([...list2, entry]);
|
|
14038
13389
|
announce(entry);
|
|
13390
|
+
noteShown(id, base.variant, !!base.action, true);
|
|
14039
13391
|
return id;
|
|
14040
|
-
}, [duration, coalesce, commit, announce]);
|
|
13392
|
+
}, [duration, coalesce, commit, announce, noteShown]);
|
|
14041
13393
|
const api = useMemo(() => ({
|
|
14042
13394
|
toast,
|
|
14043
13395
|
success: (m, o) => toast(m, { ...o, variant: "success" }),
|
|
@@ -14059,34 +13411,53 @@ function ToastProvider({ children, maxVisible = 3, position = "bottom-right", du
|
|
|
14059
13411
|
}
|
|
14060
13412
|
}), [toast, update, remove, dismissAll, duration]);
|
|
14061
13413
|
const ledger = useMemo(() => ({
|
|
14062
|
-
|
|
14063
|
-
|
|
14064
|
-
|
|
14065
|
-
|
|
14066
|
-
|
|
14067
|
-
|
|
14068
|
-
|
|
13414
|
+
begin: () => {
|
|
13415
|
+
const run = ++runSeq.current;
|
|
13416
|
+
const overlapped = runs.current.size > 0;
|
|
13417
|
+
if (overlapped) runs.current.forEach((r) => {
|
|
13418
|
+
r.overlapped = true;
|
|
13419
|
+
});
|
|
13420
|
+
runs.current.set(run, { from: showSeq.current, overlapped });
|
|
13421
|
+
return run;
|
|
13422
|
+
},
|
|
13423
|
+
end: (run) => {
|
|
13424
|
+
const watched = runs.current.get(run);
|
|
13425
|
+
runs.current.delete(run);
|
|
13426
|
+
if (!watched) return { problem: false };
|
|
13427
|
+
const during = shownDuringRuns.current.filter((s) => s.seq > watched.from);
|
|
13428
|
+
const oldest = Math.min(...[...runs.current.values()].map((r) => r.from));
|
|
13429
|
+
shownDuringRuns.current = runs.current.size ? shownDuringRuns.current.filter((s) => s.seq > oldest) : [];
|
|
13430
|
+
const problem = during.some((s) => s.variant === "error" || s.variant === "warning");
|
|
13431
|
+
const endedAt = Date.now();
|
|
13432
|
+
const confirmations = during.filter((s) => s.fresh && !s.action && (s.variant === "success" || s.variant === "default"));
|
|
13433
|
+
if (watched.overlapped || confirmations.length !== 1 || endedAt - confirmations[0].at > RUN_END_MS) return { problem };
|
|
13434
|
+
const entry = entries.current.find((t) => t.id === confirmations[0].id);
|
|
13435
|
+
return { problem, own: entry && !entry.action ? { id: entry.id, message: entry.message, variant: entry.variant } : void 0 };
|
|
13436
|
+
},
|
|
13437
|
+
has: (id) => entries.current.some((t) => t.id === id)
|
|
14069
13438
|
}), []);
|
|
14070
13439
|
const pressAction = useCallback((id) => {
|
|
14071
13440
|
const entry = entries.current.find((t) => t.id === id);
|
|
14072
13441
|
if (!entry?.action) return;
|
|
14073
13442
|
const run = entry.action.onClick;
|
|
14074
|
-
leaving();
|
|
13443
|
+
leaving(id);
|
|
14075
13444
|
commit(entries.current.map((t) => t.id === id ? { ...t, action: void 0, actionWindow: void 0, version: t.version + 1 } : t));
|
|
14076
|
-
|
|
13445
|
+
pressed.current.add(id);
|
|
14077
13446
|
const done = () => {
|
|
14078
|
-
|
|
14079
|
-
|
|
14080
|
-
|
|
14081
|
-
|
|
13447
|
+
if (pressed.current.delete(id)) remove(id);
|
|
13448
|
+
};
|
|
13449
|
+
const failed = (err) => {
|
|
13450
|
+
done();
|
|
13451
|
+
console.error(err);
|
|
14082
13452
|
};
|
|
14083
13453
|
let result;
|
|
14084
13454
|
try {
|
|
14085
13455
|
result = run();
|
|
14086
|
-
} catch {
|
|
14087
|
-
|
|
13456
|
+
} catch (err) {
|
|
13457
|
+
failed(err);
|
|
13458
|
+
return;
|
|
14088
13459
|
}
|
|
14089
|
-
if (result
|
|
13460
|
+
if (isThenable2(result)) result.then(done, failed);
|
|
14090
13461
|
else done();
|
|
14091
13462
|
}, [commit, leaving, remove]);
|
|
14092
13463
|
const lapse = useCallback((id) => {
|
|
@@ -14120,8 +13491,11 @@ function ToastProvider({ children, maxVisible = 3, position = "bottom-right", du
|
|
|
14120
13491
|
const back = returnTo.current;
|
|
14121
13492
|
const next = stackRef.current?.querySelector("button");
|
|
14122
13493
|
const main = document.querySelector("main");
|
|
13494
|
+
const byPointer = Date.now() - pointerAt.current < 1e3;
|
|
14123
13495
|
if (back?.isConnected) back.focus();
|
|
14124
|
-
else if (
|
|
13496
|
+
else if (byPointer) {
|
|
13497
|
+
if (stackRef.current?.contains(document.activeElement)) document.activeElement.blur();
|
|
13498
|
+
} else if (next) next.focus();
|
|
14125
13499
|
else if (main) {
|
|
14126
13500
|
if (!main.hasAttribute("tabindex")) {
|
|
14127
13501
|
main.setAttribute("tabindex", "-1");
|
|
@@ -14136,8 +13510,8 @@ function ToastProvider({ children, maxVisible = 3, position = "bottom-right", du
|
|
|
14136
13510
|
const hasBottomNav = isMobile && bottomNavs > 0;
|
|
14137
13511
|
return /* @__PURE__ */ jsx(ToastContext.Provider, { value: api, children: /* @__PURE__ */ jsxs(ToastLedgerCtx.Provider, { value: ledger, children: [
|
|
14138
13512
|
/* @__PURE__ */ jsx(BottomNavPresenceCtx.Provider, { value: registerBottomNav, children }),
|
|
14139
|
-
/* @__PURE__ */ jsx("div", { className: "sr-only",
|
|
14140
|
-
/* @__PURE__ */ jsx("div", { className: "sr-only",
|
|
13513
|
+
/* @__PURE__ */ jsx("div", { className: "sr-only", "aria-live": "polite", "data-toast-announcer": "polite", children: heard.filter((h) => !h.assertive).map((h) => /* @__PURE__ */ jsx("p", { children: h.text }, h.id)) }),
|
|
13514
|
+
/* @__PURE__ */ jsx("div", { className: "sr-only", "aria-live": "assertive", "data-toast-announcer": "assertive", children: heard.filter((h) => h.assertive).map((h) => /* @__PURE__ */ jsx("p", { children: h.text }, h.id)) }),
|
|
14141
13515
|
shown.length > 0 && createPortal(
|
|
14142
13516
|
/* @__PURE__ */ jsxs(
|
|
14143
13517
|
"div",
|
|
@@ -14150,6 +13524,9 @@ function ToastProvider({ children, maxVisible = 3, position = "bottom-right", du
|
|
|
14150
13524
|
"data-toast-stack": "",
|
|
14151
13525
|
onMouseEnter: () => setHovered(true),
|
|
14152
13526
|
onMouseLeave: () => setHovered(false),
|
|
13527
|
+
onPointerDownCapture: () => {
|
|
13528
|
+
pointerAt.current = Date.now();
|
|
13529
|
+
},
|
|
14153
13530
|
onFocusCapture: (e) => {
|
|
14154
13531
|
setFocusInside(true);
|
|
14155
13532
|
const from = e.relatedTarget;
|
|
@@ -14166,7 +13543,7 @@ function ToastProvider({ children, maxVisible = 3, position = "bottom-right", du
|
|
|
14166
13543
|
),
|
|
14167
13544
|
style: hasBottomNav ? { bottom: "calc(var(--ds-space-12) + var(--ds-space-2) + var(--ds-space-4) + env(safe-area-inset-bottom))" } : void 0,
|
|
14168
13545
|
children: [
|
|
14169
|
-
shown.map((t) => /* @__PURE__ */ jsx("div", { className: "pointer-events-auto", children: /* @__PURE__ */ jsx(
|
|
13546
|
+
shown.map((t) => /* @__PURE__ */ jsx("div", { "data-toast-id": t.id, className: "pointer-events-auto", children: /* @__PURE__ */ jsx(
|
|
14170
13547
|
Toast,
|
|
14171
13548
|
{
|
|
14172
13549
|
inline: true,
|
|
@@ -15963,7 +15340,9 @@ function Dialog({ open, onClose: onCloseProp, title, description, children, foot
|
|
|
15963
15340
|
"form",
|
|
15964
15341
|
{
|
|
15965
15342
|
onSubmit: (e) => {
|
|
15343
|
+
if (e.target !== e.currentTarget) return;
|
|
15966
15344
|
e.preventDefault();
|
|
15345
|
+
e.stopPropagation();
|
|
15967
15346
|
if (variant === "destructive") return;
|
|
15968
15347
|
const submitter = e.nativeEvent.submitter;
|
|
15969
15348
|
const implicit = !submitter || submitter === defaultButtonRef.current;
|
|
@@ -15992,6 +15371,7 @@ function Dialog({ open, onClose: onCloseProp, title, description, children, foot
|
|
|
15992
15371
|
{
|
|
15993
15372
|
ref: dialogRef,
|
|
15994
15373
|
role: alert ? "alertdialog" : "dialog",
|
|
15374
|
+
...{ [OVERLAY_ROOT_ATTR]: "" },
|
|
15995
15375
|
"aria-modal": "true",
|
|
15996
15376
|
"data-gs": "dialog",
|
|
15997
15377
|
"aria-labelledby": titleId,
|
|
@@ -16032,7 +15412,7 @@ function Dialog({ open, onClose: onCloseProp, title, description, children, foot
|
|
|
16032
15412
|
}
|
|
16033
15413
|
),
|
|
16034
15414
|
description && /* @__PURE__ */ jsx("p", { id: descriptionId, className: "mt-ds-2 text-sm text-[var(--ds-text-muted)]", children: description }),
|
|
16035
|
-
children && /* @__PURE__ */ jsx("div", { className: "mt-ds-4", children: /* @__PURE__ */ jsx(
|
|
15415
|
+
children && /* @__PURE__ */ jsx("div", { className: "mt-ds-4", children: /* @__PURE__ */ jsx(OverlayMarkScope, { mark, children: /* @__PURE__ */ jsx(OverlayCloseCtx, { value: onClose, children }) }) })
|
|
16036
15416
|
] })
|
|
16037
15417
|
] }) }),
|
|
16038
15418
|
/* @__PURE__ */ jsx(DiscardConfirm, { open: guard.confirming, onKeep: guard.keep, onDiscard: guard.discard }),
|
|
@@ -16193,7 +15573,7 @@ var Navbar = forwardRef(function Navbar2({
|
|
|
16193
15573
|
}
|
|
16194
15574
|
focus.onExit?.();
|
|
16195
15575
|
};
|
|
16196
|
-
const exitControl = focus ? /* @__PURE__ */ jsx(Button, { variant: "secondary", size: "sm", onClick: requestExit, children: focus.exitLabel ?? (focus.kind === "before-app" ? "Save and log out" : "Exit") }) : null;
|
|
15576
|
+
const exitControl = focus ? /* @__PURE__ */ jsx(Button, { type: "button", variant: "secondary", size: "sm", onClick: requestExit, children: focus.exitLabel ?? (focus.kind === "before-app" ? "Save and log out" : "Exit") }) : null;
|
|
16197
15577
|
const shownUserMenu = focus?.kind === "before-app" ? null : userMenu;
|
|
16198
15578
|
const asking = confirmExit && focus?.kind === "in-app" && !!appShell?.hasUnsavedChanges;
|
|
16199
15579
|
if (confirmExit && !asking) setConfirmExit(false);
|
|
@@ -16209,8 +15589,8 @@ var Navbar = forwardRef(function Navbar2({
|
|
|
16209
15589
|
alert: true,
|
|
16210
15590
|
container: shellEl ?? void 0,
|
|
16211
15591
|
footer: /* @__PURE__ */ jsxs(Fragment, { children: [
|
|
16212
|
-
/* @__PURE__ */ jsx(Button, { variant: "secondary", onClick: () => setConfirmExit(false), children: "Keep editing" }),
|
|
16213
|
-
/* @__PURE__ */ jsx(Button, { variant: "destructive", onClick: () => {
|
|
15592
|
+
/* @__PURE__ */ jsx(Button, { type: "button", variant: "secondary", onClick: () => setConfirmExit(false), children: "Keep editing" }),
|
|
15593
|
+
/* @__PURE__ */ jsx(Button, { type: "button", variant: "destructive", onClick: () => {
|
|
16214
15594
|
setConfirmExit(false);
|
|
16215
15595
|
focus.onExit?.();
|
|
16216
15596
|
}, children: "Discard changes" })
|
|
@@ -17327,67 +16707,6 @@ function getPopoverPosition(rect, placement, padding) {
|
|
|
17327
16707
|
top = Math.max(8, Math.min(top, window.innerHeight - popH - 8));
|
|
17328
16708
|
return { top, left };
|
|
17329
16709
|
}
|
|
17330
|
-
function firstKey(item) {
|
|
17331
|
-
if (item !== null && typeof item === "object") return "id" in item ? item.id : void 0;
|
|
17332
|
-
return item;
|
|
17333
|
-
}
|
|
17334
|
-
function signature(list, resetOn) {
|
|
17335
|
-
let reset = "";
|
|
17336
|
-
try {
|
|
17337
|
-
reset = JSON.stringify(resetOn ?? null);
|
|
17338
|
-
} catch {
|
|
17339
|
-
reset = String(resetOn);
|
|
17340
|
-
}
|
|
17341
|
-
let first = "";
|
|
17342
|
-
try {
|
|
17343
|
-
first = JSON.stringify(firstKey(list[0]) ?? null);
|
|
17344
|
-
} catch {
|
|
17345
|
-
first = "";
|
|
17346
|
-
}
|
|
17347
|
-
return `${list.length}|${first}|${reset}`;
|
|
17348
|
-
}
|
|
17349
|
-
function usePagination(list, options = {}) {
|
|
17350
|
-
const shell = useShellPreferences();
|
|
17351
|
-
const style = options.style ?? shell.paginationStyle ?? PREFERENCE_HOUSE_DEFAULTS.paginationStyle;
|
|
17352
|
-
const [chosenSize, setChosenSize] = useState(null);
|
|
17353
|
-
const pageSize = Math.max(1, Math.floor(chosenSize ?? options.pageSize ?? shell.itemsPerPage ?? PREFERENCE_HOUSE_DEFAULTS.itemsPerPage));
|
|
17354
|
-
const [page, setPageState] = useState(1);
|
|
17355
|
-
const sig = signature(list, options.resetOn);
|
|
17356
|
-
const [seen, setSeen] = useState(sig);
|
|
17357
|
-
if (seen !== sig) {
|
|
17358
|
-
setSeen(sig);
|
|
17359
|
-
if (page !== 1) setPageState(1);
|
|
17360
|
-
}
|
|
17361
|
-
const totalItems = list.length;
|
|
17362
|
-
const totalPages = Math.max(1, Math.ceil(totalItems / pageSize));
|
|
17363
|
-
const current = Math.min(Math.max(1, seen !== sig ? 1 : page), totalPages);
|
|
17364
|
-
const grows = style !== "pagination";
|
|
17365
|
-
const start = grows ? 0 : (current - 1) * pageSize;
|
|
17366
|
-
const items = list.slice(start, current * pageSize);
|
|
17367
|
-
const range2 = items.length === 0 ? [0, 0] : [start + 1, start + items.length];
|
|
17368
|
-
const hasMore = current < totalPages;
|
|
17369
|
-
const setPage = (next) => setPageState(Math.min(Math.max(1, Math.floor(next)), totalPages));
|
|
17370
|
-
const loadMore = () => setPageState((p) => Math.min(p + 1, totalPages));
|
|
17371
|
-
const setPageSize = (size) => {
|
|
17372
|
-
setChosenSize(Math.max(1, Math.floor(size)));
|
|
17373
|
-
setPageState(1);
|
|
17374
|
-
};
|
|
17375
|
-
return {
|
|
17376
|
-
style,
|
|
17377
|
-
items,
|
|
17378
|
-
page: current,
|
|
17379
|
-
pageSize,
|
|
17380
|
-
totalItems,
|
|
17381
|
-
totalPages,
|
|
17382
|
-
range: range2,
|
|
17383
|
-
shown: items.length,
|
|
17384
|
-
hasMore,
|
|
17385
|
-
loadMore,
|
|
17386
|
-
setPage,
|
|
17387
|
-
setPageSize,
|
|
17388
|
-
props: { currentPage: current, totalPages, onPageChange: setPage, pageSize, onPageSizeChange: setPageSize, mode: style, hasMore, onLoadMore: loadMore }
|
|
17389
|
-
};
|
|
17390
|
-
}
|
|
17391
16710
|
function useDestructiveAction(options) {
|
|
17392
16711
|
const { action, title, description, confirmLabel, typeToConfirm, onConfirm, onUndo, doneMessage, undoMessage, restoredMessage, severity } = options;
|
|
17393
16712
|
const preferences = useShellPreferences();
|
|
@@ -17410,42 +16729,65 @@ function useDestructiveAction(options) {
|
|
|
17410
16729
|
};
|
|
17411
16730
|
const failureMessage = (err) => err instanceof Error && err.message ? err.message : `${title.replace(/\?$/, "")} failed. Try again.`;
|
|
17412
16731
|
const done = doneMessage ?? undoMessage ?? pastTenseOf(label);
|
|
16732
|
+
const watch = async (step) => {
|
|
16733
|
+
const run2 = ledger?.begin();
|
|
16734
|
+
try {
|
|
16735
|
+
await step();
|
|
16736
|
+
} catch (err) {
|
|
16737
|
+
if (run2 !== void 0) ledger.end(run2);
|
|
16738
|
+
throw err;
|
|
16739
|
+
}
|
|
16740
|
+
return run2 !== void 0 ? ledger.end(run2) : { problem: false };
|
|
16741
|
+
};
|
|
17413
16742
|
const confirm = async () => {
|
|
17414
16743
|
setBusy(true);
|
|
17415
|
-
const before = ledger?.created() ?? 0;
|
|
17416
16744
|
try {
|
|
17417
|
-
await onConfirm
|
|
16745
|
+
const seen = await watch(onConfirm);
|
|
17418
16746
|
close();
|
|
17419
|
-
if (toast &&
|
|
16747
|
+
if (toast && !seen.problem && !seen.own) toast.success(done);
|
|
17420
16748
|
} catch (err) {
|
|
17421
16749
|
toast?.error(failureMessage(err));
|
|
17422
16750
|
} finally {
|
|
17423
16751
|
setBusy(false);
|
|
17424
16752
|
}
|
|
17425
16753
|
};
|
|
17426
|
-
const undo = async () => {
|
|
16754
|
+
const undo = async (id) => {
|
|
16755
|
+
const here = () => !!toast && (ledger?.has(id) ?? false);
|
|
17427
16756
|
try {
|
|
17428
|
-
await onUndo
|
|
17429
|
-
|
|
16757
|
+
const seen = await watch(onUndo);
|
|
16758
|
+
if (seen.problem) {
|
|
16759
|
+
if (here()) toast.dismiss(id);
|
|
16760
|
+
} else if (seen.own) {
|
|
16761
|
+
if (here()) {
|
|
16762
|
+
toast.update(id, seen.own.message, { variant: seen.own.variant });
|
|
16763
|
+
toast.dismiss(seen.own.id);
|
|
16764
|
+
}
|
|
16765
|
+
} else if (here()) toast.update(id, restoredMessage ?? "Restored", { variant: "success" });
|
|
16766
|
+
else toast?.success(restoredMessage ?? "Restored");
|
|
17430
16767
|
} catch (err) {
|
|
17431
|
-
|
|
16768
|
+
const message = err instanceof Error && err.message ? err.message : "Undo didn't work. Try again.";
|
|
16769
|
+
if (here()) toast.update(id, message, { variant: "error" });
|
|
16770
|
+
else toast?.error(message);
|
|
17432
16771
|
}
|
|
17433
16772
|
};
|
|
17434
16773
|
const run = () => {
|
|
17435
16774
|
if (undoable) {
|
|
17436
16775
|
void (async () => {
|
|
17437
|
-
|
|
16776
|
+
let seen;
|
|
17438
16777
|
try {
|
|
17439
|
-
await onConfirm
|
|
16778
|
+
seen = await watch(onConfirm);
|
|
17440
16779
|
} catch (err) {
|
|
17441
16780
|
toast.error(failureMessage(err));
|
|
17442
16781
|
return;
|
|
17443
16782
|
}
|
|
16783
|
+
if (seen.problem) return;
|
|
17444
16784
|
const seconds = preferences.undoWindowSeconds ?? 5;
|
|
17445
|
-
|
|
17446
|
-
const
|
|
17447
|
-
if (
|
|
17448
|
-
|
|
16785
|
+
let id = "";
|
|
16786
|
+
const undoAction = { label: "Undo", onClick: () => undo(id) };
|
|
16787
|
+
if (seen.own) {
|
|
16788
|
+
id = seen.own.id;
|
|
16789
|
+
toast.update(id, seen.own.message, { action: undoAction, actionWindow: seconds * 1e3 });
|
|
16790
|
+
} else id = toast.success(done, { action: undoAction, actionWindow: seconds * 1e3 });
|
|
17449
16791
|
})();
|
|
17450
16792
|
return;
|
|
17451
16793
|
}
|
|
@@ -17461,8 +16803,8 @@ function useDestructiveAction(options) {
|
|
|
17461
16803
|
description,
|
|
17462
16804
|
variant: "destructive",
|
|
17463
16805
|
footer: /* @__PURE__ */ jsxs(Fragment, { children: [
|
|
17464
|
-
/* @__PURE__ */ jsx(Button, { variant: "secondary", onClick: close, disabled: busy, children: "Cancel" }),
|
|
17465
|
-
/* @__PURE__ */ jsx(Button, { variant: "destructive", onClick: () => void confirm(), disabled: !matches2 || busy, loading: busy, children: label })
|
|
16806
|
+
/* @__PURE__ */ jsx(Button, { type: "button", variant: "secondary", onClick: close, disabled: busy, children: "Cancel" }),
|
|
16807
|
+
/* @__PURE__ */ jsx(Button, { type: "button", variant: "destructive", onClick: () => void confirm(), disabled: !matches2 || busy, loading: busy, children: label })
|
|
17466
16808
|
] }),
|
|
17467
16809
|
children: typedRequired && /* @__PURE__ */ jsx(Field, { label: /* @__PURE__ */ jsxs(Fragment, { children: [
|
|
17468
16810
|
"Type ",
|
|
@@ -17668,6 +17010,6 @@ var TextOverflow = forwardRef(function TextOverflow2({
|
|
|
17668
17010
|
return /* @__PURE__ */ jsx(Tooltip, { content: resolvedTooltipContent, children: content });
|
|
17669
17011
|
});
|
|
17670
17012
|
|
|
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,
|
|
17013
|
+
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, DropdownMenu, EmptyState, EntityCell, FileUpload, FormWrapper, Gantt, HoverCard, Kbd, Launcher, MentionInput, MobileHeaderMenu, NavItem, NavMenu, Navbar, NotificationCenter, PageContainer, PageHeader, PinInput, Progress, RadioGroup, Rating, ScrollArea, SectionHeading, SegmentedControl, SettingsLayout, Sidebar, SidebarNav, SliderRange, StackedList, StatsCard, StatusDot, Stepper, TIME_ZOOMS, Table, TableToolbar, Tabs, Tag, TagInput, TextOverflow, TimeBar, TimePicker, TimeRow, TimeScaleHeader, TimeViewport, Timeline, Toast, ToastProvider, Tour, TransferList, TreeView, dateOfDay, dayOf, endDayOf, fitLabel, fitLabels, formatDateRange, timeExtent, useContentWidth, useDestructiveAction, useFittedLabels, useSidebar, useTextMeasure, useTimeScale, useTimeViewport, useTimeViewportLayout, useToast, useToastOptional };
|
|
17672
17014
|
//# sourceMappingURL=index.js.map
|
|
17673
17015
|
//# sourceMappingURL=index.js.map
|