gridsmith-ui 0.21.0 → 0.23.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-3BRQRKDO.js +72 -0
- package/dist/chunk-3BRQRKDO.js.map +1 -0
- package/dist/{chunk-GGVASDXT.js → chunk-6PL7FXYH.js} +284 -521
- package/dist/chunk-6PL7FXYH.js.map +1 -0
- package/dist/chunk-7TOJ4G7S.js +197 -0
- package/dist/chunk-7TOJ4G7S.js.map +1 -0
- package/dist/chunk-CKWITUSH.js +40 -0
- package/dist/chunk-CKWITUSH.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-ICNWPNMM.js +1363 -0
- package/dist/chunk-ICNWPNMM.js.map +1 -0
- package/dist/chunk-IVCVNAXG.js +115 -0
- package/dist/chunk-IVCVNAXG.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 +305 -264
- package/dist/data-grid.js.map +1 -1
- package/dist/editor.js +10 -3
- package/dist/editor.js.map +1 -1
- package/dist/index.d.ts +122 -146
- package/dist/index.js +1091 -1885
- package/dist/index.js.map +1 -1
- package/dist/kanban.js +4 -2
- package/dist/kanban.js.map +1 -1
- package/dist/resizable.d.ts +1 -1
- package/dist/resizable.js +26 -14
- package/dist/resizable.js.map +1 -1
- package/dist/roots.css +24 -4
- package/dist/{table-utils-GounRE6s.d.ts → table-utils-BkjNEWts.d.ts} +5 -1
- package/dist/tokens.css +20 -3
- package/dist/use-pagination-DiJo0aW5.d.ts +153 -0
- package/dist/virtualized.d.ts +11 -1
- package/dist/virtualized.js +69 -18
- package/dist/virtualized.js.map +1 -1
- package/dist-static/tokens.css +20 -3
- package/package.json +1 -1
- package/dist/chunk-GGVASDXT.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-TKVTZWBN.js +0 -50
- package/dist/chunk-TKVTZWBN.js.map +0 -1
- package/dist/chunk-XYDIBW3J.js.map +0 -1
package/dist/index.js
CHANGED
|
@@ -1,25 +1,29 @@
|
|
|
1
|
-
import {
|
|
2
|
-
export { AppShell,
|
|
1
|
+
import { useAppShell, REACT_VERSION_PROBLEM, useOverlayMark, useDirtyGuard, useScrollbarInset, DrawerFooterCtx, OverlayMarkScope, OverlayCloseCtx, insetLessScrollbar, DiscardConfirm, OVERLAY_ROOT_ATTR, OverlayMarkCtx, useCompact, useElementWidth, DrawerPanel, useCloseSettle, Drawer, useRememberedWidth, pxOf, ResizeEdge, defaultMaxWidth } from './chunk-6PL7FXYH.js';
|
|
2
|
+
export { AppShell, Drawer, SkipLink, useAppShell, useUnsavedChanges } from './chunk-6PL7FXYH.js';
|
|
3
3
|
import { Skeleton, TITLE_TEXT } from './chunk-NCIZQYXQ.js';
|
|
4
4
|
export { Skeleton } from './chunk-NCIZQYXQ.js';
|
|
5
|
-
import {
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
import {
|
|
12
|
-
|
|
13
|
-
|
|
5
|
+
import { useScrollEdges, EDGE_FADE } from './chunk-3BRQRKDO.js';
|
|
6
|
+
import { Link } from './chunk-EYMGLK4M.js';
|
|
7
|
+
export { CodeBlock, Divider, Link } from './chunk-EYMGLK4M.js';
|
|
8
|
+
import { Badge } from './chunk-SBTBMAIU.js';
|
|
9
|
+
export { Badge } from './chunk-SBTBMAIU.js';
|
|
10
|
+
import { inferColumnKinds, useCardsSwitch, CARDS_BELOW, kindOfRenderedText, CardValue } from './chunk-IVCVNAXG.js';
|
|
11
|
+
import { useWholeListCheck, pagerPart, Pagination, CHECK_FILL, Dropdown, FilterRowContext, SWITCH_KNOB_ON, SWITCH_KNOB_OFF, SWITCH_KNOB_MOTION, SWITCH_TRACK_ON, SWITCH_TRACK_OFF, useFieldControl, useField, warnOnce, Label, InlineFieldError, AddAnotherRowCtx, Input, Field } from './chunk-ICNWPNMM.js';
|
|
12
|
+
export { Dropdown, Field, InlineFieldError, Input, Label, NumberInput, Pagination, Popover, Textarea, Toggle, usePagination } from './chunk-ICNWPNMM.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';
|
|
14
15
|
import { useBreakpoint, readBreakpointPx } from './chunk-CRQ6KCRD.js';
|
|
15
16
|
export { BreakpointWidthProvider, useBreakpoint } from './chunk-CRQ6KCRD.js';
|
|
16
|
-
import {
|
|
17
|
-
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 { CardSurfaceCtx, useScrollsInside, SplitPaneCtx, SurfaceBoundary, useFramesItself, TableCardCtx } from './chunk-CKWITUSH.js';
|
|
20
|
+
import { useTextOverflow, Tooltip, usePosition } from './chunk-CXMV7SXJ.js';
|
|
21
|
+
export { Tooltip, useTextOverflow } from './chunk-CXMV7SXJ.js';
|
|
18
22
|
import { mergeRefs, Slot } from './chunk-7Q46JXSK.js';
|
|
19
23
|
import { useLatest } from './chunk-WH2FUFAC.js';
|
|
20
24
|
import { Icon } from './chunk-4LDYR7QP.js';
|
|
21
|
-
import { cn, GLASS_SURFACE, GLASS_BACKDROP, GLASS_DROPDOWN, lockBodyScroll, unlockBodyScroll, OVERLAY_SURFACE, GLASS_OVERLAY,
|
|
22
|
-
import { createContext, forwardRef, useState, useRef, useCallback, useLayoutEffect, useMemo, useContext,
|
|
25
|
+
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';
|
|
26
|
+
import { createContext, forwardRef, useState, useRef, useCallback, useLayoutEffect, useMemo, useContext, isValidElement, useId, memo, useEffect, useImperativeHandle, Children, Fragment as Fragment$1, cloneElement, useSyncExternalStore } from 'react';
|
|
23
27
|
import { createPortal, flushSync } from 'react-dom';
|
|
24
28
|
import { jsxs, jsx, Fragment } from 'react/jsx-runtime';
|
|
25
29
|
|
|
@@ -83,6 +87,8 @@ function DropdownMenu({ trigger, items, align = "end", className, container }) {
|
|
|
83
87
|
Slot,
|
|
84
88
|
{
|
|
85
89
|
...triggerType(trigger),
|
|
90
|
+
"aria-haspopup": "menu",
|
|
91
|
+
"aria-expanded": open,
|
|
86
92
|
ref: triggerRef,
|
|
87
93
|
onClick: () => {
|
|
88
94
|
setOpen(!open);
|
|
@@ -208,733 +214,6 @@ function BulkActionBar({ selectedCount, actions, onClearSelection, className })
|
|
|
208
214
|
}
|
|
209
215
|
);
|
|
210
216
|
}
|
|
211
|
-
var UNCONTROLLED = /* @__PURE__ */ Symbol("uncontrolled");
|
|
212
|
-
var valueOf = (e) => {
|
|
213
|
-
const t = e.target;
|
|
214
|
-
if (!t) return void 0;
|
|
215
|
-
return t instanceof HTMLInputElement && (t.type === "checkbox" || t.type === "radio") ? t.checked : t.value;
|
|
216
|
-
};
|
|
217
|
-
var INPUT_HEIGHT = {
|
|
218
|
-
sm: "h-[var(--ds-control-height-sm)]",
|
|
219
|
-
md: "h-[var(--ds-control-height-md)]",
|
|
220
|
-
lg: "h-[var(--ds-control-height-lg)]"
|
|
221
|
-
};
|
|
222
|
-
var INPUT_TEXT = {
|
|
223
|
-
sm: "px-ds-2 py-ds-1 text-xs",
|
|
224
|
-
md: "px-ds-3 py-ds-2 text-sm",
|
|
225
|
-
lg: "px-ds-4 py-ds-3 text-base"
|
|
226
|
-
};
|
|
227
|
-
function Input({ className, size: sizeProp, error = false, prefix, suffix, ...props }) {
|
|
228
|
-
const contextSize = useContext(ControlSizeContext);
|
|
229
|
-
const size = sizeProp ?? contextSize ?? "md";
|
|
230
|
-
const onChange = useReportedChange(props.onChange, props.value === void 0 ? UNCONTROLLED : props.value, valueOf);
|
|
231
|
-
const borderColor = error ? "border-[var(--ds-status-error)]" : "border-[var(--ds-input-border)]";
|
|
232
|
-
const hoverBorder = !error && !props.disabled && !props.readOnly ? "hover:border-[var(--ds-input-border-hover)]" : "";
|
|
233
|
-
if (prefix || suffix) {
|
|
234
|
-
return /* @__PURE__ */ jsxs(
|
|
235
|
-
"div",
|
|
236
|
-
{
|
|
237
|
-
className: cn(
|
|
238
|
-
"flex items-center w-full",
|
|
239
|
-
INPUT_HEIGHT[size],
|
|
240
|
-
"bg-[var(--ds-input-bg)]",
|
|
241
|
-
"border-[length:var(--ds-border-width)]",
|
|
242
|
-
borderColor,
|
|
243
|
-
"rounded-[var(--ds-radius-md)]",
|
|
244
|
-
"shadow-[var(--ds-input-shadow)]",
|
|
245
|
-
hoverBorder,
|
|
246
|
-
error ? ERROR_HAS_FOCUS_RING : HAS_FOCUS_RING,
|
|
247
|
-
"transition-colors duration-[var(--ds-transition-speed)]",
|
|
248
|
-
props.disabled && "cursor-not-allowed opacity-disabled",
|
|
249
|
-
props.readOnly && "bg-[var(--ds-bg-muted)] cursor-default",
|
|
250
|
-
className
|
|
251
|
-
),
|
|
252
|
-
children: [
|
|
253
|
-
prefix && /* @__PURE__ */ jsx("span", { className: "shrink-0 pl-ds-3 text-[var(--ds-text-muted)] flex items-center", children: prefix }),
|
|
254
|
-
/* @__PURE__ */ jsx(
|
|
255
|
-
"input",
|
|
256
|
-
{
|
|
257
|
-
"aria-invalid": error || void 0,
|
|
258
|
-
className: cn(
|
|
259
|
-
"flex-1 min-w-0 bg-transparent outline-none",
|
|
260
|
-
INPUT_TEXT[size],
|
|
261
|
-
"text-[var(--ds-text-primary)]",
|
|
262
|
-
"placeholder:text-[var(--ds-text-muted)]",
|
|
263
|
-
"disabled:cursor-not-allowed",
|
|
264
|
-
"read-only:text-[var(--ds-text-secondary)] read-only:cursor-default"
|
|
265
|
-
),
|
|
266
|
-
...props,
|
|
267
|
-
onChange: props.onChange || props.value === void 0 ? onChange : void 0
|
|
268
|
-
}
|
|
269
|
-
),
|
|
270
|
-
suffix && /* @__PURE__ */ jsx("span", { className: "shrink-0 pr-ds-3 text-[var(--ds-text-muted)] flex items-center", children: suffix })
|
|
271
|
-
]
|
|
272
|
-
}
|
|
273
|
-
);
|
|
274
|
-
}
|
|
275
|
-
return /* @__PURE__ */ jsx(
|
|
276
|
-
"input",
|
|
277
|
-
{
|
|
278
|
-
"aria-invalid": error || void 0,
|
|
279
|
-
className: cn(
|
|
280
|
-
"flex w-full",
|
|
281
|
-
INPUT_TEXT[size],
|
|
282
|
-
INPUT_HEIGHT[size],
|
|
283
|
-
"bg-[var(--ds-input-bg)] text-[var(--ds-text-primary)]",
|
|
284
|
-
"border-[length:var(--ds-border-width)]",
|
|
285
|
-
borderColor,
|
|
286
|
-
"rounded-[var(--ds-radius-md)]",
|
|
287
|
-
"shadow-[var(--ds-input-shadow)]",
|
|
288
|
-
"placeholder:text-[var(--ds-text-muted)]",
|
|
289
|
-
hoverBorder,
|
|
290
|
-
error ? ERROR_FOCUS_RING : FOCUS_RING,
|
|
291
|
-
"disabled:cursor-not-allowed disabled:opacity-disabled",
|
|
292
|
-
"read-only:bg-[var(--ds-bg-muted)] read-only:text-[var(--ds-text-secondary)] read-only:cursor-default",
|
|
293
|
-
"transition-colors duration-[var(--ds-transition-speed)]",
|
|
294
|
-
className
|
|
295
|
-
),
|
|
296
|
-
...props,
|
|
297
|
-
onChange: props.onChange || props.value === void 0 ? onChange : void 0
|
|
298
|
-
}
|
|
299
|
-
);
|
|
300
|
-
}
|
|
301
|
-
function Textarea({ className, autoResize, maxRows, error = false, ref, ...props }) {
|
|
302
|
-
const onChange = useReportedChange(props.onChange, props.value === void 0 ? UNCONTROLLED : props.value, valueOf);
|
|
303
|
-
const internalRef = useRef(null);
|
|
304
|
-
const textareaRef = ref ?? internalRef;
|
|
305
|
-
const resize = useCallback(() => {
|
|
306
|
-
const el = textareaRef.current;
|
|
307
|
-
if (!el || !autoResize) return;
|
|
308
|
-
el.style.height = "auto";
|
|
309
|
-
let target = el.scrollHeight;
|
|
310
|
-
if (maxRows) {
|
|
311
|
-
const lineHeight = parseFloat(getComputedStyle(el).lineHeight) || 20;
|
|
312
|
-
const maxHeight = lineHeight * maxRows + parseFloat(getComputedStyle(el).paddingTop) + parseFloat(getComputedStyle(el).paddingBottom);
|
|
313
|
-
target = Math.min(target, maxHeight);
|
|
314
|
-
}
|
|
315
|
-
el.style.height = `${target}px`;
|
|
316
|
-
}, [autoResize, maxRows, textareaRef]);
|
|
317
|
-
useEffect(() => {
|
|
318
|
-
resize();
|
|
319
|
-
}, [resize, props.value, props.defaultValue]);
|
|
320
|
-
return /* @__PURE__ */ jsx(
|
|
321
|
-
"textarea",
|
|
322
|
-
{
|
|
323
|
-
ref: textareaRef,
|
|
324
|
-
"aria-invalid": error || void 0,
|
|
325
|
-
className: cn(
|
|
326
|
-
"flex min-h-[var(--ds-control-height-md)] w-full px-ds-3 py-ds-2 text-sm",
|
|
327
|
-
"bg-[var(--ds-input-bg)] text-[var(--ds-text-primary)]",
|
|
328
|
-
"border-[length:var(--ds-border-width)]",
|
|
329
|
-
error ? "border-[var(--ds-status-error)]" : "border-[var(--ds-input-border)] hover:border-[var(--ds-input-border-hover)]",
|
|
330
|
-
"rounded-[var(--ds-radius-md)]",
|
|
331
|
-
"shadow-[var(--ds-input-shadow)]",
|
|
332
|
-
"placeholder:text-[var(--ds-text-muted)]",
|
|
333
|
-
error ? ERROR_FOCUS_RING : FOCUS_RING,
|
|
334
|
-
"disabled:cursor-not-allowed disabled:opacity-disabled disabled:hover:border-[var(--ds-input-border)]",
|
|
335
|
-
"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)]",
|
|
336
|
-
"transition-colors duration-[var(--ds-transition-speed)]",
|
|
337
|
-
autoResize && "resize-none overflow-hidden",
|
|
338
|
-
className
|
|
339
|
-
),
|
|
340
|
-
onInput: autoResize ? resize : void 0,
|
|
341
|
-
...props,
|
|
342
|
-
onChange: props.onChange || props.value === void 0 ? onChange : void 0
|
|
343
|
-
}
|
|
344
|
-
);
|
|
345
|
-
}
|
|
346
|
-
function Label({ className, children, ...props }) {
|
|
347
|
-
return /* @__PURE__ */ jsx(
|
|
348
|
-
"label",
|
|
349
|
-
{
|
|
350
|
-
className: cn(
|
|
351
|
-
"text-sm font-medium leading-none text-[var(--ds-text-secondary)]",
|
|
352
|
-
"peer-disabled:cursor-not-allowed peer-disabled:opacity-disabled",
|
|
353
|
-
className
|
|
354
|
-
),
|
|
355
|
-
...props,
|
|
356
|
-
children
|
|
357
|
-
}
|
|
358
|
-
);
|
|
359
|
-
}
|
|
360
|
-
var TOGGLE_SIZES = {
|
|
361
|
-
sm: { w: 32, h: 18, thumb: 12 },
|
|
362
|
-
md: { w: 44, h: 24, thumb: 16 }
|
|
363
|
-
};
|
|
364
|
-
function Toggle({ checked, onChange, label, disabled, error = false, layout = "full", size = "md", "aria-labelledby": ariaLabelledBy, ...rest }) {
|
|
365
|
-
const change = useReportedChange(onChange, checked);
|
|
366
|
-
const dims = TOGGLE_SIZES[size];
|
|
367
|
-
const travel = dims.w - dims.thumb - 3;
|
|
368
|
-
const switchButton = /* @__PURE__ */ jsx(
|
|
369
|
-
"button",
|
|
370
|
-
{
|
|
371
|
-
type: "button",
|
|
372
|
-
role: "switch",
|
|
373
|
-
"aria-checked": checked,
|
|
374
|
-
"aria-label": !label && !ariaLabelledBy ? "Toggle" : void 0,
|
|
375
|
-
"aria-labelledby": ariaLabelledBy,
|
|
376
|
-
"aria-invalid": error || void 0,
|
|
377
|
-
disabled,
|
|
378
|
-
onClick: () => !disabled && change(!checked),
|
|
379
|
-
...rest,
|
|
380
|
-
className: cn(
|
|
381
|
-
"relative inline-flex shrink-0 items-center overflow-hidden",
|
|
382
|
-
"border-[length:var(--ds-border-width)]",
|
|
383
|
-
"rounded-[var(--ds-radius-full)]",
|
|
384
|
-
"transition-colors duration-[var(--ds-transition-speed)]",
|
|
385
|
-
"focus-visible:outline-none focus-visible:shadow-[var(--ds-shadow-focus)]",
|
|
386
|
-
disabled ? "cursor-not-allowed" : "cursor-pointer",
|
|
387
|
-
checked ? "bg-[var(--ds-accent-primary)]" : "bg-[var(--ds-bg-muted)]",
|
|
388
|
-
error ? "border-[var(--ds-status-error)]" : checked ? "border-transparent" : "border-[var(--ds-border-default)]"
|
|
389
|
-
),
|
|
390
|
-
style: { width: dims.w, height: dims.h },
|
|
391
|
-
children: /* @__PURE__ */ jsx(
|
|
392
|
-
"span",
|
|
393
|
-
{
|
|
394
|
-
className: cn(
|
|
395
|
-
"pointer-events-none inline-block shrink-0",
|
|
396
|
-
"bg-[var(--ds-bg-surface)]",
|
|
397
|
-
"border-[length:var(--ds-border-width)] border-transparent",
|
|
398
|
-
"rounded-[var(--ds-radius-full)]",
|
|
399
|
-
"transition-transform"
|
|
400
|
-
),
|
|
401
|
-
style: {
|
|
402
|
-
width: dims.thumb,
|
|
403
|
-
height: dims.thumb,
|
|
404
|
-
transform: checked ? `translateX(calc(${travel}px - var(--ds-border-width)))` : "translateX(calc(1px + var(--ds-border-width)))"
|
|
405
|
-
}
|
|
406
|
-
}
|
|
407
|
-
)
|
|
408
|
-
}
|
|
409
|
-
);
|
|
410
|
-
if (!label) {
|
|
411
|
-
return /* @__PURE__ */ jsx("div", { className: cn(disabled && "opacity-disabled"), children: switchButton });
|
|
412
|
-
}
|
|
413
|
-
return /* @__PURE__ */ jsxs(
|
|
414
|
-
"label",
|
|
415
|
-
{
|
|
416
|
-
className: cn(
|
|
417
|
-
layout === "full" ? "flex items-center justify-between gap-ds-4" : "inline-flex items-center gap-ds-3",
|
|
418
|
-
disabled ? "cursor-not-allowed opacity-disabled" : "cursor-pointer"
|
|
419
|
-
),
|
|
420
|
-
children: [
|
|
421
|
-
/* @__PURE__ */ jsx("span", { className: "text-sm font-medium text-[var(--ds-text-primary)]", children: label }),
|
|
422
|
-
switchButton
|
|
423
|
-
]
|
|
424
|
-
}
|
|
425
|
-
);
|
|
426
|
-
}
|
|
427
|
-
function InlineFieldError({ message, id, className }) {
|
|
428
|
-
return /* @__PURE__ */ jsxs(
|
|
429
|
-
"p",
|
|
430
|
-
{
|
|
431
|
-
id,
|
|
432
|
-
role: "alert",
|
|
433
|
-
className: cn(
|
|
434
|
-
"flex items-center gap-ds-1.5 text-xs text-[var(--ds-status-error)]",
|
|
435
|
-
"mt-ds-1.5",
|
|
436
|
-
className
|
|
437
|
-
),
|
|
438
|
-
children: [
|
|
439
|
-
/* @__PURE__ */ jsx(Icon, { name: "error", size: 14, className: "shrink-0" }),
|
|
440
|
-
/* @__PURE__ */ jsx("span", { children: message })
|
|
441
|
-
]
|
|
442
|
-
}
|
|
443
|
-
);
|
|
444
|
-
}
|
|
445
|
-
var FieldContext = createContext(null);
|
|
446
|
-
function useField() {
|
|
447
|
-
return useContext(FieldContext);
|
|
448
|
-
}
|
|
449
|
-
function useFieldControl(own, options = {}) {
|
|
450
|
-
const field = useField();
|
|
451
|
-
const id = own.id ?? field?.controlId;
|
|
452
|
-
const invalid = !!own.error || own["aria-invalid"] === true || own["aria-invalid"] === "true" || !!field?.invalid;
|
|
453
|
-
const required = !!own.required || own["aria-required"] === true || own["aria-required"] === "true" || !!field?.required;
|
|
454
|
-
const noteId = options.requiredInDescription && required && id ? `${id}-required` : void 0;
|
|
455
|
-
const ids = [own["aria-describedby"], field?.describedBy, noteId].filter(Boolean).join(" ").split(/\s+/).filter(Boolean);
|
|
456
|
-
return {
|
|
457
|
-
id,
|
|
458
|
-
labelId: own["aria-labelledby"] ?? field?.labelId,
|
|
459
|
-
describedBy: [...new Set(ids)].join(" ") || void 0,
|
|
460
|
-
invalid,
|
|
461
|
-
required,
|
|
462
|
-
requiredNote: noteId ? /* @__PURE__ */ jsx("span", { id: noteId, hidden: true, children: "Required" }) : null
|
|
463
|
-
};
|
|
464
|
-
}
|
|
465
|
-
var AddAnotherRowCtx = createContext(false);
|
|
466
|
-
function Field({ label, children, hint, error, required, labelAction, hideLabel = false, id: idProp, validate, className }) {
|
|
467
|
-
const inGroupRow = useContext(AddAnotherRowCtx);
|
|
468
|
-
const generated = useId();
|
|
469
|
-
const id = idProp ?? `field-${generated}`;
|
|
470
|
-
const hintId = `${id}-hint`;
|
|
471
|
-
const errorId = `${id}-error`;
|
|
472
|
-
const form = useOptionalFormContext();
|
|
473
|
-
const mode = form?.validationMode ?? "onBlur";
|
|
474
|
-
const [localError, setLocalError] = useState(void 0);
|
|
475
|
-
const [left, setLeft] = useState(false);
|
|
476
|
-
const checkError = validate ? form ? form.errors[id] : localError : void 0;
|
|
477
|
-
const child = typeof children === "function" ? null : Children.only(children);
|
|
478
|
-
const childProps = child && isValidElement(child) ? child.props : null;
|
|
479
|
-
const latest = useLatest({ validate, childProps, id, mode, left, showing: !!checkError, form });
|
|
480
|
-
const check = useCallback(() => {
|
|
481
|
-
const { validate: fn, childProps: props, id: controlId } = latest.current;
|
|
482
|
-
if (!fn) return void 0;
|
|
483
|
-
const value = props && "value" in props ? props.value : props && "checked" in props ? props.checked : document.getElementById(controlId)?.value;
|
|
484
|
-
const message = fn(value);
|
|
485
|
-
return typeof message === "string" && message.length > 0 ? message : void 0;
|
|
486
|
-
}, [latest]);
|
|
487
|
-
const show = useCallback((message) => {
|
|
488
|
-
const { form: f, id: controlId } = latest.current;
|
|
489
|
-
if (f) f.setError(controlId, message);
|
|
490
|
-
else setLocalError(message);
|
|
491
|
-
}, [latest]);
|
|
492
|
-
const register = form?.register;
|
|
493
|
-
const checks = !!validate;
|
|
494
|
-
useEffect(() => register && checks ? register(id, check) : void 0, [register, checks, id, check]);
|
|
495
|
-
const leaving = useRef(null);
|
|
496
|
-
useEffect(() => () => {
|
|
497
|
-
if (leaving.current) clearTimeout(leaving.current);
|
|
498
|
-
}, []);
|
|
499
|
-
const onFocusCapture = () => {
|
|
500
|
-
if (leaving.current) {
|
|
501
|
-
clearTimeout(leaving.current);
|
|
502
|
-
leaving.current = null;
|
|
503
|
-
}
|
|
504
|
-
};
|
|
505
|
-
const onBlurCapture = () => {
|
|
506
|
-
if (!validate) return;
|
|
507
|
-
if (leaving.current) clearTimeout(leaving.current);
|
|
508
|
-
leaving.current = setTimeout(() => {
|
|
509
|
-
leaving.current = null;
|
|
510
|
-
setLeft(true);
|
|
511
|
-
if (latest.current.mode !== "onSubmit" || latest.current.showing) show(check());
|
|
512
|
-
}, 0);
|
|
513
|
-
};
|
|
514
|
-
const recheck = () => {
|
|
515
|
-
if (!validate) return;
|
|
516
|
-
setTimeout(() => {
|
|
517
|
-
const { mode: m, left: wasLeft, showing } = latest.current;
|
|
518
|
-
if (m === "onChange" && wasLeft || showing) show(check());
|
|
519
|
-
}, 0);
|
|
520
|
-
};
|
|
521
|
-
const shownError = typeof error === "string" && error.length > 0 ? error : checkError;
|
|
522
|
-
const hasError = typeof shownError === "string" && shownError.length > 0;
|
|
523
|
-
const describedBy = [hint ? hintId : null, hasError ? errorId : null].filter(Boolean).join(" ") || void 0;
|
|
524
|
-
const labelId = `${id}-label`;
|
|
525
|
-
const fieldContext = useMemo(() => ({ controlId: id, labelId, describedBy, invalid: hasError, required: !!required }), [id, labelId, describedBy, hasError, required]);
|
|
526
|
-
const controlProps = {
|
|
527
|
-
id,
|
|
528
|
-
"aria-describedby": describedBy,
|
|
529
|
-
...hasError ? { "aria-invalid": true, error: true } : {},
|
|
530
|
-
...required ? { "aria-required": true, required: true } : {}
|
|
531
|
-
};
|
|
532
|
-
let control;
|
|
533
|
-
if (typeof children === "function") {
|
|
534
|
-
control = children(controlProps);
|
|
535
|
-
} else {
|
|
536
|
-
if (!child || !isValidElement(child)) throw new Error("Field expects a single form control as its child");
|
|
537
|
-
const isNative = typeof child.type === "string";
|
|
538
|
-
const { error: errorFlag, ...ariaOnly } = controlProps;
|
|
539
|
-
const ownOnChange = childProps?.onChange;
|
|
540
|
-
const onChange = validate && !isNative ? { onChange: (...args) => {
|
|
541
|
-
ownOnChange?.(...args);
|
|
542
|
-
recheck();
|
|
543
|
-
} } : {};
|
|
544
|
-
control = cloneElement(child, isNative ? ariaOnly : { ...ariaOnly, ...errorFlag ? { error: true } : {}, ...onChange });
|
|
545
|
-
}
|
|
546
|
-
const labelNode = /* @__PURE__ */ jsxs(Label, { id: labelId, htmlFor: id, className: cn(hideLabel && "sr-only", hideLabel && inGroupRow && "@max-[30rem]:not-sr-only"), children: [
|
|
547
|
-
label,
|
|
548
|
-
required && /* @__PURE__ */ jsx("span", { "aria-hidden": "true", className: "ml-ds-0.5 text-[var(--ds-status-error)]", children: "*" })
|
|
549
|
-
] });
|
|
550
|
-
return (
|
|
551
|
-
// In a settings panel a field keeps the narrow reading width however wide the page is (--ds-form-max, Sprint 25.9 A4)
|
|
552
|
-
/* @__PURE__ */ jsxs(
|
|
553
|
-
"div",
|
|
554
|
-
{
|
|
555
|
-
className: cn("flex flex-col gap-ds-1.5 max-w-[var(--ds-form-max,none)]", className),
|
|
556
|
-
...validate ? { onFocusCapture, onBlurCapture, onInputCapture: recheck } : {},
|
|
557
|
-
children: [
|
|
558
|
-
hideLabel && !labelAction ? labelNode : /* @__PURE__ */ jsxs("div", { className: "flex items-center justify-between gap-ds-2", children: [
|
|
559
|
-
labelNode,
|
|
560
|
-
labelAction
|
|
561
|
-
] }),
|
|
562
|
-
/* @__PURE__ */ jsx(FieldContext.Provider, { value: fieldContext, children: control }),
|
|
563
|
-
hint && /* @__PURE__ */ jsx("p", { id: hintId, className: "text-xs text-[var(--ds-text-muted)]", children: hint }),
|
|
564
|
-
hasError && /* @__PURE__ */ jsx(InlineFieldError, { id: errorId, message: shownError, className: "mt-0" })
|
|
565
|
-
]
|
|
566
|
-
}
|
|
567
|
-
)
|
|
568
|
-
);
|
|
569
|
-
}
|
|
570
|
-
var DROPDOWN_HEIGHT = {
|
|
571
|
-
sm: "px-ds-2 py-ds-1 text-xs h-[var(--ds-control-height-sm)]",
|
|
572
|
-
md: "px-ds-3 py-ds-2 text-sm h-[var(--ds-control-height-md)]",
|
|
573
|
-
lg: "px-ds-4 py-ds-3 text-base h-[var(--ds-control-height-lg)]"
|
|
574
|
-
};
|
|
575
|
-
function Dropdown({
|
|
576
|
-
options,
|
|
577
|
-
value,
|
|
578
|
-
onChange: onChangeProp,
|
|
579
|
-
label,
|
|
580
|
-
disabled,
|
|
581
|
-
placeholder = "Select...",
|
|
582
|
-
multiple,
|
|
583
|
-
searchable,
|
|
584
|
-
size: sizeProp,
|
|
585
|
-
className,
|
|
586
|
-
ref,
|
|
587
|
-
container,
|
|
588
|
-
error = false,
|
|
589
|
-
showChips = true,
|
|
590
|
-
"aria-label": ariaLabel,
|
|
591
|
-
...wiring
|
|
592
|
-
}) {
|
|
593
|
-
const onChange = useReportedChange(onChangeProp, value);
|
|
594
|
-
const contextSize = useContext(ControlSizeContext);
|
|
595
|
-
const generatedId = useId();
|
|
596
|
-
const control = useFieldControl({ ...wiring, error: error || void 0 }, { requiredInDescription: true });
|
|
597
|
-
const triggerId = control.id ?? generatedId;
|
|
598
|
-
const labelSpanId = `${triggerId}-label`;
|
|
599
|
-
const labelledBy = control.labelId ? `${control.labelId} ${triggerId}` : label && !ariaLabel ? `${labelSpanId} ${triggerId}` : void 0;
|
|
600
|
-
const invalid = control.invalid;
|
|
601
|
-
const size = sizeProp ?? contextSize ?? "md";
|
|
602
|
-
const [open, setOpen] = useState(false);
|
|
603
|
-
const [search, setSearch] = useState("");
|
|
604
|
-
const [positioned, setPositioned] = useState(false);
|
|
605
|
-
const triggerRef = useRef(null);
|
|
606
|
-
const menuRef = useRef(null);
|
|
607
|
-
const searchRef = useRef(null);
|
|
608
|
-
const [pos, setPos] = useState({ top: 0, left: 0, width: 0 });
|
|
609
|
-
const selectedValues = Array.isArray(value) ? value : [value].filter(Boolean);
|
|
610
|
-
const updatePos = useCallback(() => {
|
|
611
|
-
if (!triggerRef.current) return;
|
|
612
|
-
const rect = triggerRef.current.getBoundingClientRect();
|
|
613
|
-
let top = rect.bottom + 4;
|
|
614
|
-
let left = rect.left;
|
|
615
|
-
const width = rect.width;
|
|
616
|
-
if (menuRef.current) {
|
|
617
|
-
const menuRect = menuRef.current.getBoundingClientRect();
|
|
618
|
-
const vw = window.innerWidth;
|
|
619
|
-
const vh = window.innerHeight;
|
|
620
|
-
if (left + menuRect.width > vw) left = Math.max(0, vw - menuRect.width - 8);
|
|
621
|
-
if (top + menuRect.height > vh) {
|
|
622
|
-
const above = rect.top - 4 - menuRect.height;
|
|
623
|
-
if (above >= 0) top = above;
|
|
624
|
-
else top = Math.max(0, vh - menuRect.height - 8);
|
|
625
|
-
}
|
|
626
|
-
}
|
|
627
|
-
setPos({ top, left, width });
|
|
628
|
-
}, []);
|
|
629
|
-
const [prevOpen, setPrevOpen] = useState(open);
|
|
630
|
-
if (open !== prevOpen) {
|
|
631
|
-
setPrevOpen(open);
|
|
632
|
-
if (open) setSearch("");
|
|
633
|
-
else setPositioned(false);
|
|
634
|
-
}
|
|
635
|
-
useEffect(() => {
|
|
636
|
-
if (!open) return;
|
|
637
|
-
updatePos();
|
|
638
|
-
const raf = requestAnimationFrame(() => {
|
|
639
|
-
updatePos();
|
|
640
|
-
setPositioned(true);
|
|
641
|
-
});
|
|
642
|
-
const onScroll = () => updatePos();
|
|
643
|
-
window.addEventListener("scroll", onScroll, true);
|
|
644
|
-
window.addEventListener("resize", updatePos);
|
|
645
|
-
return () => {
|
|
646
|
-
cancelAnimationFrame(raf);
|
|
647
|
-
window.removeEventListener("scroll", onScroll, true);
|
|
648
|
-
window.removeEventListener("resize", updatePos);
|
|
649
|
-
};
|
|
650
|
-
}, [open, updatePos]);
|
|
651
|
-
const moved = useRef(false);
|
|
652
|
-
useLayoutEffect(() => {
|
|
653
|
-
if (!open || !positioned) return;
|
|
654
|
-
moved.current = false;
|
|
655
|
-
if (searchRef.current) {
|
|
656
|
-
searchRef.current.focus();
|
|
657
|
-
return;
|
|
658
|
-
}
|
|
659
|
-
const els = Array.from(menuRef.current?.querySelectorAll('[role="option"]') ?? []);
|
|
660
|
-
(els.find((el) => el.getAttribute("aria-selected") === "true") ?? els[0])?.focus();
|
|
661
|
-
}, [open, positioned]);
|
|
662
|
-
useEffect(() => {
|
|
663
|
-
if (!open) return;
|
|
664
|
-
const handler = (e) => {
|
|
665
|
-
const target = e.target;
|
|
666
|
-
if (triggerRef.current?.contains(target) || menuRef.current?.contains(target)) return;
|
|
667
|
-
setOpen(false);
|
|
668
|
-
};
|
|
669
|
-
document.addEventListener("mousedown", handler);
|
|
670
|
-
return () => document.removeEventListener("mousedown", handler);
|
|
671
|
-
}, [open]);
|
|
672
|
-
const commitMoved = () => {
|
|
673
|
-
if (multiple || !moved.current) return;
|
|
674
|
-
const el = document.activeElement;
|
|
675
|
-
const id = el instanceof HTMLElement && menuRef.current?.contains(el) ? el.getAttribute("data-option-id") : null;
|
|
676
|
-
if (id) onChange(id);
|
|
677
|
-
};
|
|
678
|
-
const { isTop: isTopLayer, returnFocus } = usePopupFocus(open, { trigger: triggerRef, panel: menuRef, close: () => setOpen(false), tabExits: "any", onTabOut: commitMoved });
|
|
679
|
-
const typeahead = useRef({ buffer: "", at: 0 });
|
|
680
|
-
useEffect(() => {
|
|
681
|
-
if (!open) return;
|
|
682
|
-
const optionButtons = () => Array.from(menuRef.current?.querySelectorAll('[role="option"]') ?? []);
|
|
683
|
-
const focusOption = (idx) => {
|
|
684
|
-
const els = optionButtons();
|
|
685
|
-
if (els.length === 0) return;
|
|
686
|
-
els[(idx % els.length + els.length) % els.length].focus();
|
|
687
|
-
moved.current = true;
|
|
688
|
-
};
|
|
689
|
-
const onKey = (e) => {
|
|
690
|
-
const inMenu = menuRef.current?.contains(document.activeElement) || triggerRef.current === document.activeElement;
|
|
691
|
-
if (!inMenu) return;
|
|
692
|
-
const els = optionButtons();
|
|
693
|
-
const current = els.findIndex((el) => el === document.activeElement);
|
|
694
|
-
if (e.key === "Escape") {
|
|
695
|
-
if (e.defaultPrevented || !isTopLayer()) return;
|
|
696
|
-
e.preventDefault();
|
|
697
|
-
returnFocus();
|
|
698
|
-
setOpen(false);
|
|
699
|
-
return;
|
|
700
|
-
}
|
|
701
|
-
if (e.key === "ArrowDown") {
|
|
702
|
-
e.preventDefault();
|
|
703
|
-
focusOption(current < 0 ? 0 : current + 1);
|
|
704
|
-
return;
|
|
705
|
-
}
|
|
706
|
-
if (e.key === "ArrowUp") {
|
|
707
|
-
e.preventDefault();
|
|
708
|
-
focusOption(current < 0 ? els.length - 1 : current - 1);
|
|
709
|
-
return;
|
|
710
|
-
}
|
|
711
|
-
const inSearch = document.activeElement === searchRef.current;
|
|
712
|
-
if (e.key === "Home" && !inSearch) {
|
|
713
|
-
e.preventDefault();
|
|
714
|
-
focusOption(0);
|
|
715
|
-
return;
|
|
716
|
-
}
|
|
717
|
-
if (e.key === "End" && !inSearch) {
|
|
718
|
-
e.preventDefault();
|
|
719
|
-
focusOption(els.length - 1);
|
|
720
|
-
return;
|
|
721
|
-
}
|
|
722
|
-
if (!searchable && e.key.length === 1 && !e.metaKey && !e.ctrlKey && !e.altKey) {
|
|
723
|
-
const now = Date.now();
|
|
724
|
-
typeahead.current.buffer = now - typeahead.current.at > 700 ? e.key : typeahead.current.buffer + e.key;
|
|
725
|
-
typeahead.current.at = now;
|
|
726
|
-
const q = typeahead.current.buffer.toLowerCase();
|
|
727
|
-
const hit = els.findIndex((el) => (el.textContent ?? "").trim().toLowerCase().startsWith(q));
|
|
728
|
-
if (hit >= 0) {
|
|
729
|
-
e.preventDefault();
|
|
730
|
-
focusOption(hit);
|
|
731
|
-
}
|
|
732
|
-
}
|
|
733
|
-
};
|
|
734
|
-
document.addEventListener("keydown", onKey);
|
|
735
|
-
return () => document.removeEventListener("keydown", onKey);
|
|
736
|
-
}, [open, searchable, isTopLayer, returnFocus]);
|
|
737
|
-
const filtered = searchable && search ? options.filter((o) => o.label.toLowerCase().includes(search.toLowerCase())) : options;
|
|
738
|
-
const groups = /* @__PURE__ */ new Map();
|
|
739
|
-
for (const opt of filtered) {
|
|
740
|
-
const g = opt.group ?? "";
|
|
741
|
-
if (!groups.has(g)) groups.set(g, []);
|
|
742
|
-
groups.get(g).push(opt);
|
|
743
|
-
}
|
|
744
|
-
const hasGroups = Array.from(groups.keys()).some((k) => k !== "");
|
|
745
|
-
const handleSelect = (id) => {
|
|
746
|
-
if (multiple) {
|
|
747
|
-
const arr = selectedValues.includes(id) ? selectedValues.filter((v) => v !== id) : [...selectedValues, id];
|
|
748
|
-
onChange(arr);
|
|
749
|
-
} else {
|
|
750
|
-
returnFocus();
|
|
751
|
-
onChange(id);
|
|
752
|
-
setOpen(false);
|
|
753
|
-
}
|
|
754
|
-
};
|
|
755
|
-
const chipsRef = useRef(null);
|
|
756
|
-
const pendingChipFocus = useRef(null);
|
|
757
|
-
useLayoutEffect(() => {
|
|
758
|
-
const pending = pendingChipFocus.current;
|
|
759
|
-
if (pending === null) return;
|
|
760
|
-
pendingChipFocus.current = null;
|
|
761
|
-
if (selectedValues.includes(pending.value)) return;
|
|
762
|
-
const chips = Array.from(chipsRef.current?.querySelectorAll("[data-chip-remove]") ?? []);
|
|
763
|
-
focusAfterRemoval(chips, pending.index, triggerRef.current);
|
|
764
|
-
});
|
|
765
|
-
const displayLabel = multiple ? selectedValues.length > 0 ? `${selectedValues.length} selected` : placeholder : options.find((o) => o.id === selectedValues[0])?.label ?? placeholder;
|
|
766
|
-
const { ref: overflowRef, isTruncated } = useTextOverflow({ lines: 1, content: displayLabel });
|
|
767
|
-
return /* @__PURE__ */ jsxs("div", { ref, className: cn("relative", className), children: [
|
|
768
|
-
label && /* @__PURE__ */ jsx("span", { id: labelSpanId, className: "block mb-ds-1.5 text-sm font-medium text-[var(--ds-text-secondary)]", children: label }),
|
|
769
|
-
control.requiredNote,
|
|
770
|
-
/* @__PURE__ */ jsxs(
|
|
771
|
-
"button",
|
|
772
|
-
{
|
|
773
|
-
ref: triggerRef,
|
|
774
|
-
id: triggerId,
|
|
775
|
-
type: "button",
|
|
776
|
-
onClick: () => !disabled && setOpen(!open),
|
|
777
|
-
onKeyDown: (e) => {
|
|
778
|
-
if (disabled || open) return;
|
|
779
|
-
if (e.key === "ArrowDown" || e.key === "ArrowUp") {
|
|
780
|
-
e.preventDefault();
|
|
781
|
-
setOpen(true);
|
|
782
|
-
}
|
|
783
|
-
},
|
|
784
|
-
disabled,
|
|
785
|
-
"aria-invalid": invalid || void 0,
|
|
786
|
-
"aria-haspopup": "listbox",
|
|
787
|
-
"aria-expanded": open,
|
|
788
|
-
"aria-label": labelledBy ? void 0 : ariaLabel,
|
|
789
|
-
"aria-labelledby": labelledBy,
|
|
790
|
-
"aria-describedby": control.describedBy,
|
|
791
|
-
className: cn(
|
|
792
|
-
"w-full flex items-center justify-between gap-ds-2",
|
|
793
|
-
DROPDOWN_HEIGHT[size],
|
|
794
|
-
"bg-[var(--ds-input-bg)] text-[var(--ds-text-primary)]",
|
|
795
|
-
"border-[length:var(--ds-border-width)]",
|
|
796
|
-
invalid ? "border-[var(--ds-status-error)]" : "border-[var(--ds-input-border)]",
|
|
797
|
-
"rounded-[var(--ds-radius-md)]",
|
|
798
|
-
"shadow-[var(--ds-input-shadow)]",
|
|
799
|
-
"transition-colors",
|
|
800
|
-
!invalid && !disabled && !open && "hover:border-[var(--ds-input-border-hover)]",
|
|
801
|
-
open && (invalid ? ERROR_ACTIVE_RING : ACTIVE_RING),
|
|
802
|
-
invalid ? ERROR_FOCUS_RING : FOCUS_RING,
|
|
803
|
-
"cursor-pointer disabled:cursor-not-allowed disabled:opacity-disabled",
|
|
804
|
-
!selectedValues.length && "text-[var(--ds-text-muted)]"
|
|
805
|
-
),
|
|
806
|
-
children: [
|
|
807
|
-
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 }),
|
|
808
|
-
/* @__PURE__ */ jsx("span", { className: cn("transition-transform", open && "rotate-180"), children: /* @__PURE__ */ jsx(Icon, { name: "chevron-right", size: 14, className: "rotate-90" }) })
|
|
809
|
-
]
|
|
810
|
-
}
|
|
811
|
-
),
|
|
812
|
-
open && createPortal(
|
|
813
|
-
/* @__PURE__ */ jsxs(
|
|
814
|
-
"div",
|
|
815
|
-
{
|
|
816
|
-
ref: menuRef,
|
|
817
|
-
tabIndex: -1,
|
|
818
|
-
onClick: (e) => e.stopPropagation(),
|
|
819
|
-
className: cn(
|
|
820
|
-
"fixed z-[var(--ds-z-popover)] outline-none",
|
|
821
|
-
"bg-[var(--ds-bg-surface-elevated)]",
|
|
822
|
-
"[backdrop-filter:var(--ds-glass-filter)] [-webkit-backdrop-filter:var(--ds-glass-filter)]",
|
|
823
|
-
"border-[length:var(--ds-border-width)] border-[var(--ds-border-default)]",
|
|
824
|
-
"rounded-[var(--ds-radius-md)] overflow-hidden",
|
|
825
|
-
"shadow-[var(--ds-shadow-dropdown),var(--ds-glass-inset)]"
|
|
826
|
-
),
|
|
827
|
-
style: { top: pos.top, left: pos.left, minWidth: pos.width, width: "max-content", maxWidth: "calc(100vw - 16px)", visibility: positioned ? "visible" : "hidden" },
|
|
828
|
-
children: [
|
|
829
|
-
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(
|
|
830
|
-
"input",
|
|
831
|
-
{
|
|
832
|
-
ref: searchRef,
|
|
833
|
-
type: "text",
|
|
834
|
-
value: search,
|
|
835
|
-
onChange: (e) => setSearch(e.target.value),
|
|
836
|
-
placeholder: "Search\u2026",
|
|
837
|
-
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")
|
|
838
|
-
}
|
|
839
|
-
) }),
|
|
840
|
-
/* @__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: [
|
|
841
|
-
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 }),
|
|
842
|
-
opts.map((opt) => /* @__PURE__ */ jsx(
|
|
843
|
-
OptionButton,
|
|
844
|
-
{
|
|
845
|
-
opt,
|
|
846
|
-
isSelected: selectedValues.includes(opt.id),
|
|
847
|
-
multiple,
|
|
848
|
-
onSelect: handleSelect,
|
|
849
|
-
size
|
|
850
|
-
},
|
|
851
|
-
opt.id
|
|
852
|
-
))
|
|
853
|
-
] }, group)) : filtered.map((opt) => /* @__PURE__ */ jsx(
|
|
854
|
-
OptionButton,
|
|
855
|
-
{
|
|
856
|
-
opt,
|
|
857
|
-
isSelected: selectedValues.includes(opt.id),
|
|
858
|
-
multiple,
|
|
859
|
-
onSelect: handleSelect,
|
|
860
|
-
size
|
|
861
|
-
},
|
|
862
|
-
opt.id
|
|
863
|
-
)) })
|
|
864
|
-
]
|
|
865
|
-
}
|
|
866
|
-
),
|
|
867
|
-
container ?? document.body
|
|
868
|
-
),
|
|
869
|
-
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) => {
|
|
870
|
-
const opt = options.find((o) => o.id === v);
|
|
871
|
-
return opt ? /* @__PURE__ */ jsxs(
|
|
872
|
-
"span",
|
|
873
|
-
{
|
|
874
|
-
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",
|
|
875
|
-
children: [
|
|
876
|
-
opt.label,
|
|
877
|
-
/* @__PURE__ */ jsx(
|
|
878
|
-
"button",
|
|
879
|
-
{
|
|
880
|
-
type: "button",
|
|
881
|
-
"data-chip-remove": "",
|
|
882
|
-
onClick: () => {
|
|
883
|
-
pendingChipFocus.current = { index: i, value: v };
|
|
884
|
-
handleSelect(v);
|
|
885
|
-
},
|
|
886
|
-
className: "hover:text-[var(--ds-text-primary)] cursor-pointer",
|
|
887
|
-
"aria-label": `Remove ${opt.label}`,
|
|
888
|
-
children: /* @__PURE__ */ jsx(Icon, { name: "close", size: 10 })
|
|
889
|
-
}
|
|
890
|
-
)
|
|
891
|
-
]
|
|
892
|
-
},
|
|
893
|
-
v
|
|
894
|
-
) : null;
|
|
895
|
-
}) })
|
|
896
|
-
] });
|
|
897
|
-
}
|
|
898
|
-
function OptionButton({
|
|
899
|
-
opt,
|
|
900
|
-
isSelected,
|
|
901
|
-
multiple,
|
|
902
|
-
onSelect,
|
|
903
|
-
size = "md"
|
|
904
|
-
}) {
|
|
905
|
-
return /* @__PURE__ */ jsxs(
|
|
906
|
-
"button",
|
|
907
|
-
{
|
|
908
|
-
type: "button",
|
|
909
|
-
role: "option",
|
|
910
|
-
"data-option-id": opt.id,
|
|
911
|
-
"aria-selected": isSelected,
|
|
912
|
-
tabIndex: -1,
|
|
913
|
-
onClick: () => onSelect(opt.id),
|
|
914
|
-
className: cn(
|
|
915
|
-
"w-full text-left cursor-pointer rounded-[var(--ds-radius-sm)]",
|
|
916
|
-
"transition-colors flex items-center gap-ds-2",
|
|
917
|
-
"focus-visible:outline-none focus-visible:shadow-[var(--ds-shadow-focus)]",
|
|
918
|
-
size === "sm" ? "px-ds-2 py-ds-1 text-xs" : "px-ds-2 py-ds-1.5 text-sm",
|
|
919
|
-
isSelected && !multiple ? "bg-[var(--ds-accent-primary)] text-[var(--ds-text-on-primary)]" : "text-[var(--ds-text-primary)] hover:bg-[var(--ds-bg-emphasis)]"
|
|
920
|
-
),
|
|
921
|
-
children: [
|
|
922
|
-
multiple && /* @__PURE__ */ jsx(
|
|
923
|
-
"span",
|
|
924
|
-
{
|
|
925
|
-
className: cn(
|
|
926
|
-
"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",
|
|
927
|
-
isSelected ? "bg-[var(--ds-accent-primary)] border-[var(--ds-accent-primary)]" : "border-[var(--ds-border-default)]"
|
|
928
|
-
),
|
|
929
|
-
children: isSelected && /* @__PURE__ */ jsx(Icon, { name: "check", size: 10, className: "text-[var(--ds-text-on-primary)]" })
|
|
930
|
-
}
|
|
931
|
-
),
|
|
932
|
-
/* @__PURE__ */ jsx("span", { className: "flex-1", children: opt.label }),
|
|
933
|
-
isSelected && !multiple && /* @__PURE__ */ jsx(Icon, { name: "check", size: size === "sm" ? 12 : 14 })
|
|
934
|
-
]
|
|
935
|
-
}
|
|
936
|
-
);
|
|
937
|
-
}
|
|
938
217
|
var CONTROL_HEIGHT = {
|
|
939
218
|
sm: "h-[var(--ds-control-height-sm)]",
|
|
940
219
|
md: "h-[var(--ds-control-height-md)]",
|
|
@@ -1230,7 +509,7 @@ function Checkbox({ checked, onChange: onChangeProp, label, size = "md", disable
|
|
|
1230
509
|
"border-[2px]",
|
|
1231
510
|
"transition-all",
|
|
1232
511
|
"peer-focus-visible:shadow-[var(--ds-shadow-focus)]",
|
|
1233
|
-
filled ?
|
|
512
|
+
filled ? cn(CHECK_FILL, "border-[var(--ds-check-border)]") : "bg-[var(--ds-input-bg)] border-[var(--ds-input-border)]",
|
|
1234
513
|
disabled && "pointer-events-none"
|
|
1235
514
|
),
|
|
1236
515
|
children: /* @__PURE__ */ jsx(
|
|
@@ -1351,7 +630,8 @@ function RadioGroup({ value, onChange: onChangeProp, options, orientation = "ver
|
|
|
1351
630
|
selected && "border-[var(--ds-check-border)]",
|
|
1352
631
|
"group-focus-visible:shadow-[var(--ds-shadow-focus)]"
|
|
1353
632
|
),
|
|
1354
|
-
children: selected &&
|
|
633
|
+
children: selected && // Sprint 25.14 A20: the checked colour, as a checkbox's fill (a preset whose accent falls short of 3:1 sets it)
|
|
634
|
+
/* @__PURE__ */ jsx("span", { className: cn("h-2.5 w-2.5 rounded-[var(--ds-radius-full)]", CHECK_FILL) })
|
|
1355
635
|
}
|
|
1356
636
|
),
|
|
1357
637
|
/* @__PURE__ */ jsx("span", { className: "text-sm text-[var(--ds-text-primary)]", children: option.label })
|
|
@@ -2488,21 +1768,6 @@ function Progress({ value, max = 100, variant = "default", size = "md", indeterm
|
|
|
2488
1768
|
] })
|
|
2489
1769
|
] });
|
|
2490
1770
|
}
|
|
2491
|
-
|
|
2492
|
-
// ../../showcase/src/lib/dev-warn.ts
|
|
2493
|
-
var warned = /* @__PURE__ */ new Set();
|
|
2494
|
-
function warnOnce(component, message) {
|
|
2495
|
-
let dev = false;
|
|
2496
|
-
try {
|
|
2497
|
-
dev = process.env.NODE_ENV !== "production";
|
|
2498
|
-
} catch {
|
|
2499
|
-
dev = false;
|
|
2500
|
-
}
|
|
2501
|
-
const text = `${component}: ${message}`;
|
|
2502
|
-
if (!dev || warned.has(text)) return;
|
|
2503
|
-
warned.add(text);
|
|
2504
|
-
console.warn(text);
|
|
2505
|
-
}
|
|
2506
1771
|
function TruncFileName({ children, className }) {
|
|
2507
1772
|
const { ref, isTruncated } = useTextOverflow({ lines: 1 });
|
|
2508
1773
|
const el = /* @__PURE__ */ jsx("p", { ref, className: cn("truncate", className), children });
|
|
@@ -2631,9 +1896,9 @@ function FileUpload({ onFiles, files, upload, onCancel, onRetry, onRemove, accep
|
|
|
2631
1896
|
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).");
|
|
2632
1897
|
}, [controlled, onFiles, upload, onRemove, shown]);
|
|
2633
1898
|
const [heard, setHeard] = useState({ text: "", n: 0 });
|
|
2634
|
-
const
|
|
2635
|
-
const [seen, setSeen] = useState(() => ({ signature
|
|
2636
|
-
if (
|
|
1899
|
+
const signature = shown.map((i) => `${i.id}\0${i.status}`).join("");
|
|
1900
|
+
const [seen, setSeen] = useState(() => ({ signature, statuses: new Map(shown.map((i) => [i.id, i.status])) }));
|
|
1901
|
+
if (signature !== seen.signature) {
|
|
2637
1902
|
const said = [];
|
|
2638
1903
|
for (const item of shown) {
|
|
2639
1904
|
const before = seen.statuses.get(item.id);
|
|
@@ -2641,7 +1906,7 @@ function FileUpload({ onFiles, files, upload, onCancel, onRetry, onRemove, accep
|
|
|
2641
1906
|
if (item.status === "done") said.push(`${item.name} uploaded`);
|
|
2642
1907
|
else if (item.status === "error") said.push(`${item.name} didn't upload: ${item.error ?? "the upload failed"}`);
|
|
2643
1908
|
}
|
|
2644
|
-
setSeen({ signature
|
|
1909
|
+
setSeen({ signature, statuses: new Map(shown.map((i) => [i.id, i.status])) });
|
|
2645
1910
|
if (said.length) setHeard((h) => ({ text: said.join(". "), n: h.n + 1 }));
|
|
2646
1911
|
}
|
|
2647
1912
|
const pendingFocus = useRef(null);
|
|
@@ -2728,7 +1993,7 @@ function FileUpload({ onFiles, files, upload, onCancel, onRetry, onRemove, accep
|
|
|
2728
1993
|
// The real file input is visually hidden inside; Tab lands on it and
|
|
2729
1994
|
// Enter/Space open the picker natively, so the zone shows its focus.
|
|
2730
1995
|
invalid ? ERROR_HAS_FOCUS_RING : HAS_FOCUS_RING,
|
|
2731
|
-
dragOver ? `${ACTIVE_RING} bg-[var(--ds-accent-whisper)]` : invalid ? "border-[var(--ds-status-error)]" : "border-[var(--ds-border
|
|
1996
|
+
dragOver ? `${ACTIVE_RING} bg-[var(--ds-accent-whisper)]` : invalid ? "border-[var(--ds-status-error)]" : "border-[var(--ds-input-border)] hover:border-[var(--ds-accent-primary)] hover:bg-[var(--ds-accent-whisper)]"
|
|
2732
1997
|
),
|
|
2733
1998
|
style: { padding: "var(--ds-space-8) var(--ds-space-4)" },
|
|
2734
1999
|
children: [
|
|
@@ -2902,7 +2167,7 @@ function SliderRange({
|
|
|
2902
2167
|
!trackStyle && /* @__PURE__ */ jsx(
|
|
2903
2168
|
"div",
|
|
2904
2169
|
{
|
|
2905
|
-
className: "absolute h-1.5 rounded-[var(--ds-radius-full)]
|
|
2170
|
+
className: cn("absolute h-1.5 rounded-[var(--ds-radius-full)]", CHECK_FILL),
|
|
2906
2171
|
style: {
|
|
2907
2172
|
left: `${isRange ? pct(low) : 0}%`,
|
|
2908
2173
|
width: `${isRange ? pct(high) - pct(low) : pct(low)}%`
|
|
@@ -2926,7 +2191,7 @@ function SliderRange({
|
|
|
2926
2191
|
className: cn(
|
|
2927
2192
|
"absolute w-ds-4 h-ds-4 -translate-x-1/2 rounded-[var(--ds-radius-full)]",
|
|
2928
2193
|
"bg-[var(--ds-bg-surface)] border-2",
|
|
2929
|
-
error ? "border-[var(--ds-status-error)]" : "border-[var(--ds-
|
|
2194
|
+
error ? "border-[var(--ds-status-error)]" : "border-[var(--ds-check-border)]",
|
|
2930
2195
|
"shadow-[var(--ds-shadow-sm)]",
|
|
2931
2196
|
"transition-[shadow,transform] duration-200 ease-out",
|
|
2932
2197
|
"focus-visible:shadow-[var(--ds-shadow-focus)]",
|
|
@@ -2952,7 +2217,7 @@ function SliderRange({
|
|
|
2952
2217
|
className: cn(
|
|
2953
2218
|
"absolute w-ds-4 h-ds-4 -translate-x-1/2 rounded-[var(--ds-radius-full)]",
|
|
2954
2219
|
"bg-[var(--ds-bg-surface)] border-2",
|
|
2955
|
-
error ? "border-[var(--ds-status-error)]" : "border-[var(--ds-
|
|
2220
|
+
error ? "border-[var(--ds-status-error)]" : "border-[var(--ds-check-border)]",
|
|
2956
2221
|
"shadow-[var(--ds-shadow-sm)]",
|
|
2957
2222
|
"transition-[shadow,transform] duration-200 ease-out",
|
|
2958
2223
|
"focus-visible:shadow-[var(--ds-shadow-focus)]",
|
|
@@ -3372,259 +2637,43 @@ function TimePicker({
|
|
|
3372
2637
|
onFocus: () => holdStop("minute", i),
|
|
3373
2638
|
"data-selected": m === parsed.minute,
|
|
3374
2639
|
onMouseDown: (e) => e.preventDefault(),
|
|
3375
|
-
onClick: () => emitChange(parsed.hour, m, parsed.period),
|
|
3376
|
-
className: cn(
|
|
3377
|
-
"w-full text-center text-sm py-ds-1 rounded-[var(--ds-radius-sm)] cursor-pointer",
|
|
3378
|
-
"transition-colors focus-visible:outline-none focus-visible:shadow-[var(--ds-shadow-focus)]",
|
|
3379
|
-
m === parsed.minute ? "bg-[var(--ds-accent-primary)] text-[var(--ds-text-on-primary)]" : "text-[var(--ds-text-secondary)] hover:bg-[var(--ds-bg-emphasis)]"
|
|
3380
|
-
),
|
|
3381
|
-
children: pad(m)
|
|
3382
|
-
},
|
|
3383
|
-
m
|
|
3384
|
-
)) }),
|
|
3385
|
-
!use24Hour && /* @__PURE__ */ jsxs(Fragment, { children: [
|
|
3386
|
-
/* @__PURE__ */ jsx("div", { className: "w-px bg-[var(--ds-border-subtle)]" }),
|
|
3387
|
-
/* @__PURE__ */ jsx("div", { "data-column": true, className: "flex flex-col gap-ds-1 w-ds-10", children: ["AM", "PM"].map((p, i) => /* @__PURE__ */ jsx(
|
|
3388
|
-
"button",
|
|
3389
|
-
{
|
|
3390
|
-
type: "button",
|
|
3391
|
-
tabIndex: i === stopOf("period", chosenPeriod) ? 0 : -1,
|
|
3392
|
-
onFocus: () => holdStop("period", i),
|
|
3393
|
-
"data-selected": p === parsed.period,
|
|
3394
|
-
onMouseDown: (e) => e.preventDefault(),
|
|
3395
|
-
onClick: () => emitChange(parsed.hour, parsed.minute, p),
|
|
3396
|
-
className: cn(
|
|
3397
|
-
"text-xs font-medium py-ds-1 rounded-[var(--ds-radius-sm)] cursor-pointer",
|
|
3398
|
-
"transition-colors text-center focus-visible:outline-none focus-visible:shadow-[var(--ds-shadow-focus)]",
|
|
3399
|
-
p === parsed.period ? "bg-[var(--ds-accent-primary)] text-[var(--ds-text-on-primary)]" : "text-[var(--ds-text-secondary)] hover:bg-[var(--ds-bg-emphasis)]"
|
|
3400
|
-
),
|
|
3401
|
-
children: p
|
|
3402
|
-
},
|
|
3403
|
-
p
|
|
3404
|
-
)) })
|
|
3405
|
-
] })
|
|
3406
|
-
] })
|
|
3407
|
-
}
|
|
3408
|
-
),
|
|
3409
|
-
container ?? document.body
|
|
3410
|
-
)
|
|
3411
|
-
] });
|
|
3412
|
-
}
|
|
3413
|
-
var sizes = {
|
|
3414
|
-
sm: { box: "h-[var(--ds-control-height-sm)]", input: "text-xs self-stretch", btn: "w-7 text-xs" },
|
|
3415
|
-
md: { box: "h-[var(--ds-control-height-md)]", input: "text-sm self-stretch", btn: "w-9 text-sm" },
|
|
3416
|
-
lg: { box: "h-[var(--ds-control-height-lg)]", input: "text-base self-stretch", btn: "w-10 text-base" }
|
|
3417
|
-
};
|
|
3418
|
-
function NumberInput({
|
|
3419
|
-
value,
|
|
3420
|
-
onChange: onChangeProp,
|
|
3421
|
-
min = -Infinity,
|
|
3422
|
-
max = Infinity,
|
|
3423
|
-
step = 1,
|
|
3424
|
-
disabled = false,
|
|
3425
|
-
placeholder = "0",
|
|
3426
|
-
prefix,
|
|
3427
|
-
suffix,
|
|
3428
|
-
size: sizeProp,
|
|
3429
|
-
className,
|
|
3430
|
-
error = false,
|
|
3431
|
-
allowDecimals,
|
|
3432
|
-
id
|
|
3433
|
-
}) {
|
|
3434
|
-
const onChange = useReportedChange(onChangeProp, value);
|
|
3435
|
-
const contextSize = useContext(ControlSizeContext);
|
|
3436
|
-
const size = sizeProp ?? contextSize ?? "md";
|
|
3437
|
-
const intervalRef = useRef(void 0);
|
|
3438
|
-
const timeoutRef = useRef(void 0);
|
|
3439
|
-
const inputRef = useRef(null);
|
|
3440
|
-
const [focused, setFocused] = useState(false);
|
|
3441
|
-
const [draft, setDraft] = useState(String(value));
|
|
3442
|
-
const decimals = allowDecimals ?? step % 1 !== 0;
|
|
3443
|
-
const [prevSync, setPrevSync] = useState({ value, focused });
|
|
3444
|
-
if (value !== prevSync.value || focused !== prevSync.focused) {
|
|
3445
|
-
setPrevSync({ value, focused });
|
|
3446
|
-
if (!focused) setDraft(String(value));
|
|
3447
|
-
}
|
|
3448
|
-
const clamp = useCallback(
|
|
3449
|
-
(v) => Math.min(max, Math.max(min, v)),
|
|
3450
|
-
[min, max]
|
|
3451
|
-
);
|
|
3452
|
-
const valueRef = useLatest(value);
|
|
3453
|
-
const commitValue = useCallback((v, own = false) => {
|
|
3454
|
-
const clamped = clamp(v);
|
|
3455
|
-
valueRef.current = clamped;
|
|
3456
|
-
setDraft(String(clamped));
|
|
3457
|
-
(own ? onChangeProp : onChange)(clamped);
|
|
3458
|
-
return clamped;
|
|
3459
|
-
}, [onChange, onChangeProp, clamp, valueRef]);
|
|
3460
|
-
const increment = useCallback(() => commitValue(valueRef.current + step), [commitValue, step, valueRef]);
|
|
3461
|
-
const decrement = useCallback(() => commitValue(valueRef.current - step), [commitValue, step, valueRef]);
|
|
3462
|
-
const startRepeat = useCallback(
|
|
3463
|
-
(fn) => {
|
|
3464
|
-
fn();
|
|
3465
|
-
timeoutRef.current = setTimeout(() => {
|
|
3466
|
-
intervalRef.current = setInterval(fn, 75);
|
|
3467
|
-
}, 400);
|
|
3468
|
-
},
|
|
3469
|
-
[]
|
|
3470
|
-
);
|
|
3471
|
-
const stopRepeat = useCallback(() => {
|
|
3472
|
-
clearTimeout(timeoutRef.current);
|
|
3473
|
-
clearInterval(intervalRef.current);
|
|
3474
|
-
}, []);
|
|
3475
|
-
const handleInput = useCallback(
|
|
3476
|
-
(e) => {
|
|
3477
|
-
const raw = e.target.value;
|
|
3478
|
-
if (raw === "" || raw === "-") {
|
|
3479
|
-
setDraft(raw);
|
|
3480
|
-
return;
|
|
3481
|
-
}
|
|
3482
|
-
if (!decimals && raw.includes(".")) return;
|
|
3483
|
-
const validPattern = decimals ? /^-?\d*\.?\d*$/ : /^-?\d*$/;
|
|
3484
|
-
if (!validPattern.test(raw)) return;
|
|
3485
|
-
setDraft(raw);
|
|
3486
|
-
const parsed = parseFloat(raw);
|
|
3487
|
-
if (!isNaN(parsed) && isFinite(parsed)) {
|
|
3488
|
-
onChange(clamp(parsed));
|
|
3489
|
-
}
|
|
3490
|
-
},
|
|
3491
|
-
[onChange, clamp, decimals]
|
|
3492
|
-
);
|
|
3493
|
-
const handleBlur = useCallback(() => {
|
|
3494
|
-
setFocused(false);
|
|
3495
|
-
const parsed = parseFloat(draft);
|
|
3496
|
-
if (!isNaN(parsed) && isFinite(parsed)) {
|
|
3497
|
-
const committed = commitValue(parsed, draft === String(value));
|
|
3498
|
-
setDraft(String(committed));
|
|
3499
|
-
} else {
|
|
3500
|
-
const fallback = isFinite(min) ? min : 0;
|
|
3501
|
-
const committed = commitValue(value !== void 0 ? value : fallback, true);
|
|
3502
|
-
setDraft(String(committed));
|
|
3503
|
-
}
|
|
3504
|
-
}, [draft, commitValue, min, value]);
|
|
3505
|
-
const handleFocus = useCallback(() => {
|
|
3506
|
-
setFocused(true);
|
|
3507
|
-
}, []);
|
|
3508
|
-
const handleKeyDown = useCallback(
|
|
3509
|
-
(e) => {
|
|
3510
|
-
if (e.key === "ArrowUp") {
|
|
3511
|
-
e.preventDefault();
|
|
3512
|
-
increment();
|
|
3513
|
-
}
|
|
3514
|
-
if (e.key === "ArrowDown") {
|
|
3515
|
-
e.preventDefault();
|
|
3516
|
-
decrement();
|
|
3517
|
-
}
|
|
3518
|
-
},
|
|
3519
|
-
[increment, decrement]
|
|
3520
|
-
);
|
|
3521
|
-
const s = sizes[size];
|
|
3522
|
-
const atMin = value <= min;
|
|
3523
|
-
const atMax = value >= max;
|
|
3524
|
-
return /* @__PURE__ */ jsxs(
|
|
3525
|
-
"div",
|
|
3526
|
-
{
|
|
3527
|
-
className: cn(
|
|
3528
|
-
"flex items-center w-full",
|
|
3529
|
-
s.box,
|
|
3530
|
-
"border-[length:var(--ds-border-width)]",
|
|
3531
|
-
error ? "border-[var(--ds-status-error)]" : "border-[var(--ds-input-border)]",
|
|
3532
|
-
"rounded-[var(--ds-radius-md)]",
|
|
3533
|
-
"shadow-[var(--ds-input-shadow)]",
|
|
3534
|
-
"bg-[var(--ds-input-bg)]",
|
|
3535
|
-
"transition-colors duration-[var(--ds-transition-speed)]",
|
|
3536
|
-
!error && !disabled && "hover:border-[var(--ds-input-border-hover)]",
|
|
3537
|
-
error ? ERROR_FOCUS_WITHIN_RING : cn(FOCUS_WITHIN_RING, "focus-within:hover:border-[var(--ds-border-focus)]"),
|
|
3538
|
-
disabled && "opacity-disabled cursor-not-allowed",
|
|
3539
|
-
className
|
|
3540
|
-
),
|
|
3541
|
-
children: [
|
|
3542
|
-
/* @__PURE__ */ jsx(
|
|
3543
|
-
"button",
|
|
3544
|
-
{
|
|
3545
|
-
type: "button",
|
|
3546
|
-
tabIndex: -1,
|
|
3547
|
-
disabled: disabled || atMin,
|
|
3548
|
-
onMouseDown: (e) => {
|
|
3549
|
-
e.preventDefault();
|
|
3550
|
-
inputRef.current?.focus();
|
|
3551
|
-
if (!disabled && !atMin) startRepeat(decrement);
|
|
3552
|
-
},
|
|
3553
|
-
onMouseUp: stopRepeat,
|
|
3554
|
-
onMouseLeave: stopRepeat,
|
|
3555
|
-
className: cn(
|
|
3556
|
-
"inline-flex items-center justify-center shrink-0",
|
|
3557
|
-
"border-r-[length:var(--ds-border-width)] border-[var(--ds-border-default)]",
|
|
3558
|
-
"text-[var(--ds-text-muted)] hover:text-[var(--ds-text-primary)] hover:bg-[var(--ds-bg-muted)]",
|
|
3559
|
-
"transition-colors cursor-pointer",
|
|
3560
|
-
"rounded-l-[var(--ds-radius-md)]",
|
|
3561
|
-
s.btn,
|
|
3562
|
-
s.input,
|
|
3563
|
-
(disabled || atMin) && "opacity-disabled cursor-not-allowed hover:bg-transparent hover:text-[var(--ds-text-muted)]"
|
|
3564
|
-
),
|
|
3565
|
-
"aria-label": "Decrease",
|
|
3566
|
-
children: "\u2212"
|
|
3567
|
-
}
|
|
3568
|
-
),
|
|
3569
|
-
/* @__PURE__ */ jsxs("div", { className: cn("flex items-center flex-1 min-w-0 px-ds-2 gap-ds-1", s.input), children: [
|
|
3570
|
-
prefix && /* @__PURE__ */ jsx("span", { className: "text-[var(--ds-text-muted)] shrink-0 text-xs", children: prefix }),
|
|
3571
|
-
/* @__PURE__ */ jsx(
|
|
3572
|
-
"input",
|
|
3573
|
-
{
|
|
3574
|
-
ref: inputRef,
|
|
3575
|
-
id,
|
|
3576
|
-
type: "text",
|
|
3577
|
-
inputMode: decimals ? "decimal" : "numeric",
|
|
3578
|
-
"aria-invalid": error || void 0,
|
|
3579
|
-
value: focused ? draft : String(value),
|
|
3580
|
-
onChange: handleInput,
|
|
3581
|
-
onFocus: handleFocus,
|
|
3582
|
-
onBlur: handleBlur,
|
|
3583
|
-
onKeyDown: handleKeyDown,
|
|
3584
|
-
disabled,
|
|
3585
|
-
placeholder,
|
|
3586
|
-
className: cn(
|
|
3587
|
-
"w-full min-w-0 bg-transparent text-center outline-none",
|
|
3588
|
-
"text-[var(--ds-text-primary)]",
|
|
3589
|
-
"placeholder:text-[var(--ds-text-muted)]",
|
|
3590
|
-
"font-[family-name:var(--ds-font-mono)]",
|
|
3591
|
-
s.input,
|
|
3592
|
-
disabled && "cursor-not-allowed"
|
|
3593
|
-
)
|
|
3594
|
-
}
|
|
3595
|
-
),
|
|
3596
|
-
suffix && /* @__PURE__ */ jsx("span", { className: "text-[var(--ds-text-muted)] shrink-0 text-xs", children: suffix })
|
|
3597
|
-
] }),
|
|
3598
|
-
/* @__PURE__ */ jsx(
|
|
3599
|
-
"button",
|
|
3600
|
-
{
|
|
3601
|
-
type: "button",
|
|
3602
|
-
tabIndex: -1,
|
|
3603
|
-
disabled: disabled || atMax,
|
|
3604
|
-
onMouseDown: (e) => {
|
|
3605
|
-
e.preventDefault();
|
|
3606
|
-
inputRef.current?.focus();
|
|
3607
|
-
if (!disabled && !atMax) startRepeat(increment);
|
|
3608
|
-
},
|
|
3609
|
-
onMouseUp: stopRepeat,
|
|
3610
|
-
onMouseLeave: stopRepeat,
|
|
3611
|
-
className: cn(
|
|
3612
|
-
"inline-flex items-center justify-center shrink-0",
|
|
3613
|
-
"border-l-[length:var(--ds-border-width)] border-[var(--ds-border-default)]",
|
|
3614
|
-
"text-[var(--ds-text-muted)] hover:text-[var(--ds-text-primary)] hover:bg-[var(--ds-bg-muted)]",
|
|
3615
|
-
"transition-colors cursor-pointer",
|
|
3616
|
-
"rounded-r-[var(--ds-radius-md)]",
|
|
3617
|
-
s.btn,
|
|
3618
|
-
s.input,
|
|
3619
|
-
(disabled || atMax) && "opacity-disabled cursor-not-allowed hover:bg-transparent hover:text-[var(--ds-text-muted)]"
|
|
3620
|
-
),
|
|
3621
|
-
"aria-label": "Increase",
|
|
3622
|
-
children: "+"
|
|
3623
|
-
}
|
|
3624
|
-
)
|
|
3625
|
-
]
|
|
3626
|
-
}
|
|
3627
|
-
);
|
|
2640
|
+
onClick: () => emitChange(parsed.hour, m, parsed.period),
|
|
2641
|
+
className: cn(
|
|
2642
|
+
"w-full text-center text-sm py-ds-1 rounded-[var(--ds-radius-sm)] cursor-pointer",
|
|
2643
|
+
"transition-colors focus-visible:outline-none focus-visible:shadow-[var(--ds-shadow-focus)]",
|
|
2644
|
+
m === parsed.minute ? "bg-[var(--ds-accent-primary)] text-[var(--ds-text-on-primary)]" : "text-[var(--ds-text-secondary)] hover:bg-[var(--ds-bg-emphasis)]"
|
|
2645
|
+
),
|
|
2646
|
+
children: pad(m)
|
|
2647
|
+
},
|
|
2648
|
+
m
|
|
2649
|
+
)) }),
|
|
2650
|
+
!use24Hour && /* @__PURE__ */ jsxs(Fragment, { children: [
|
|
2651
|
+
/* @__PURE__ */ jsx("div", { className: "w-px bg-[var(--ds-border-subtle)]" }),
|
|
2652
|
+
/* @__PURE__ */ jsx("div", { "data-column": true, className: "flex flex-col gap-ds-1 w-ds-10", children: ["AM", "PM"].map((p, i) => /* @__PURE__ */ jsx(
|
|
2653
|
+
"button",
|
|
2654
|
+
{
|
|
2655
|
+
type: "button",
|
|
2656
|
+
tabIndex: i === stopOf("period", chosenPeriod) ? 0 : -1,
|
|
2657
|
+
onFocus: () => holdStop("period", i),
|
|
2658
|
+
"data-selected": p === parsed.period,
|
|
2659
|
+
onMouseDown: (e) => e.preventDefault(),
|
|
2660
|
+
onClick: () => emitChange(parsed.hour, parsed.minute, p),
|
|
2661
|
+
className: cn(
|
|
2662
|
+
"text-xs font-medium py-ds-1 rounded-[var(--ds-radius-sm)] cursor-pointer",
|
|
2663
|
+
"transition-colors text-center focus-visible:outline-none focus-visible:shadow-[var(--ds-shadow-focus)]",
|
|
2664
|
+
p === parsed.period ? "bg-[var(--ds-accent-primary)] text-[var(--ds-text-on-primary)]" : "text-[var(--ds-text-secondary)] hover:bg-[var(--ds-bg-emphasis)]"
|
|
2665
|
+
),
|
|
2666
|
+
children: p
|
|
2667
|
+
},
|
|
2668
|
+
p
|
|
2669
|
+
)) })
|
|
2670
|
+
] })
|
|
2671
|
+
] })
|
|
2672
|
+
}
|
|
2673
|
+
),
|
|
2674
|
+
container ?? document.body
|
|
2675
|
+
)
|
|
2676
|
+
] });
|
|
3628
2677
|
}
|
|
3629
2678
|
var variantStyles = {
|
|
3630
2679
|
default: "bg-[var(--ds-bg-emphasis)] text-[var(--ds-text-primary)]",
|
|
@@ -3867,7 +2916,7 @@ function TagInput({
|
|
|
3867
2916
|
}
|
|
3868
2917
|
);
|
|
3869
2918
|
}
|
|
3870
|
-
var
|
|
2919
|
+
var sizes = {
|
|
3871
2920
|
sm: "w-[var(--ds-control-height-sm)] h-[var(--ds-control-height-sm)] text-sm",
|
|
3872
2921
|
md: "w-[var(--ds-control-height-md)] h-[var(--ds-control-height-md)] text-base",
|
|
3873
2922
|
lg: "w-[var(--ds-control-height-lg)] h-[var(--ds-control-height-lg)] text-lg"
|
|
@@ -3941,7 +2990,7 @@ function PinInput({
|
|
|
3941
2990
|
role: "group",
|
|
3942
2991
|
"aria-label": "PIN input",
|
|
3943
2992
|
"aria-invalid": error || void 0,
|
|
3944
|
-
className: cn("inline-flex items-center gap-ds-2", className),
|
|
2993
|
+
className: cn("inline-flex w-fit items-center gap-ds-2", className),
|
|
3945
2994
|
children: digits.map((digit, i) => /* @__PURE__ */ jsx(
|
|
3946
2995
|
"input",
|
|
3947
2996
|
{
|
|
@@ -3971,7 +3020,7 @@ function PinInput({
|
|
|
3971
3020
|
!error && !disabled && "hover:border-[var(--ds-input-border-hover)]",
|
|
3972
3021
|
error ? ERROR_FOCUS_RING : FOCUS_RING,
|
|
3973
3022
|
"placeholder:text-[var(--ds-text-muted)]",
|
|
3974
|
-
|
|
3023
|
+
sizes[size],
|
|
3975
3024
|
disabled && "opacity-disabled cursor-not-allowed"
|
|
3976
3025
|
)
|
|
3977
3026
|
},
|
|
@@ -4106,7 +3155,9 @@ function Rating({
|
|
|
4106
3155
|
"aria-required": readOnly ? void 0 : control.required || void 0,
|
|
4107
3156
|
onKeyDown: readOnly ? void 0 : handleKeyDown,
|
|
4108
3157
|
className: cn(
|
|
4109
|
-
|
|
3158
|
+
// Sprint 25.14 A21: its own width in a Field's column, not the field's; w-fit, not self-start, so a row or a
|
|
3159
|
+
// centred column still aligns it (the review of 30 September)
|
|
3160
|
+
"inline-flex w-fit items-center gap-ds-0.5",
|
|
4110
3161
|
error && "border-[length:var(--ds-border-width)] border-[var(--ds-status-error)] rounded-[var(--ds-radius-sm)] p-ds-0.5",
|
|
4111
3162
|
className
|
|
4112
3163
|
),
|
|
@@ -5312,46 +4363,20 @@ function MentionInput({
|
|
|
5312
4363
|
)
|
|
5313
4364
|
] });
|
|
5314
4365
|
}
|
|
5315
|
-
var
|
|
5316
|
-
|
|
5317
|
-
|
|
5318
|
-
|
|
5319
|
-
|
|
5320
|
-
|
|
5321
|
-
|
|
5322
|
-
|
|
5323
|
-
|
|
5324
|
-
|
|
5325
|
-
|
|
5326
|
-
const row = rowRef.current;
|
|
5327
|
-
if (!active || !row) return;
|
|
5328
|
-
const measure = () => {
|
|
5329
|
-
const title = row.querySelector("h1, h2, h3, h4, h5, h6");
|
|
5330
|
-
if (!title) return;
|
|
5331
|
-
const width = title.style.width;
|
|
5332
|
-
title.style.width = "min-content";
|
|
5333
|
-
const longest = title.getBoundingClientRect().width;
|
|
5334
|
-
title.style.width = width;
|
|
5335
|
-
if (longest === 0) return;
|
|
5336
|
-
const next = longest <= row.clientWidth + 0.5;
|
|
5337
|
-
setFits((was) => was === next ? was : next);
|
|
5338
|
-
};
|
|
5339
|
-
measure();
|
|
5340
|
-
if (typeof ResizeObserver === "undefined") return;
|
|
5341
|
-
const observer = new ResizeObserver(measure);
|
|
5342
|
-
observer.observe(row);
|
|
5343
|
-
return () => observer.disconnect();
|
|
5344
|
-
}, [rowRef, active]);
|
|
5345
|
-
return fits;
|
|
5346
|
-
}
|
|
5347
|
-
function actionsAreBadges(actions) {
|
|
5348
|
-
const items = Children.toArray(actions);
|
|
5349
|
-
return items.length > 0 && items.every((item) => isValidElement(item) && (item.type === Fragment$1 ? actionsAreBadges(item.props.children) : item.type === Badge));
|
|
4366
|
+
var CardRowCtx = createContext(null);
|
|
4367
|
+
var TITLE_LINE = "h-[calc(var(--ds-font-size-lg)*var(--ds-line-height-lg))]";
|
|
4368
|
+
var HeaderRowCtx = createContext(false);
|
|
4369
|
+
function holdsHeader(children) {
|
|
4370
|
+
let found = false;
|
|
4371
|
+
Children.forEach(children, (child) => {
|
|
4372
|
+
if (found || !isValidElement(child)) return;
|
|
4373
|
+
if (child.type === Fragment$1) found = holdsHeader(child.props.children);
|
|
4374
|
+
else if (child.type === CardHeader) found = true;
|
|
4375
|
+
});
|
|
4376
|
+
return found;
|
|
5350
4377
|
}
|
|
5351
|
-
var CardCtx = createContext(false);
|
|
5352
4378
|
var CardActionCtx = createContext(null);
|
|
5353
4379
|
var CARD_ACTION_ATTR = "data-card-action";
|
|
5354
|
-
var CardSurfaceCtx = createContext(false);
|
|
5355
4380
|
var variantStyles3 = {
|
|
5356
4381
|
default: `bg-[var(--ds-bg-surface)] border-[length:var(--ds-border-width)] border-[var(--ds-border-subtle)] ${GLASS_SURFACE}`,
|
|
5357
4382
|
featured: [
|
|
@@ -5387,7 +4412,8 @@ function RadioIndicator({ checked, disabled }) {
|
|
|
5387
4412
|
{
|
|
5388
4413
|
className: cn(
|
|
5389
4414
|
"h-2.5 w-2.5 rounded-[var(--ds-radius-full)] transition-transform duration-[var(--ds-transition-speed)]",
|
|
5390
|
-
|
|
4415
|
+
// Sprint 25.14 A20: the radio's selected dot (lib/control-looks.ts)
|
|
4416
|
+
checked ? cn(CHECK_FILL, "scale-100") : "scale-0"
|
|
5391
4417
|
)
|
|
5392
4418
|
}
|
|
5393
4419
|
)
|
|
@@ -5405,7 +4431,8 @@ function CheckboxIndicator({ checked, indeterminate, disabled }) {
|
|
|
5405
4431
|
"rounded-[calc(var(--ds-radius-sm)*0.6)]",
|
|
5406
4432
|
"border-[2px] transition-all duration-[var(--ds-transition-speed)]",
|
|
5407
4433
|
disabled && "opacity-disabled",
|
|
5408
|
-
|
|
4434
|
+
// Sprint 25.14 A20: the checkbox's checked fill (lib/control-looks.ts)
|
|
4435
|
+
filled ? cn(CHECK_FILL, "border-[var(--ds-check-border)]") : "bg-[var(--ds-input-bg)] border-[var(--ds-input-border)]"
|
|
5409
4436
|
),
|
|
5410
4437
|
children: /* @__PURE__ */ jsx(
|
|
5411
4438
|
"svg",
|
|
@@ -5433,13 +4460,14 @@ function ToggleIndicator({ checked, disabled }) {
|
|
|
5433
4460
|
"border-[length:var(--ds-border-width)] rounded-[var(--ds-radius-full)]",
|
|
5434
4461
|
"transition-colors duration-[var(--ds-transition-speed)]",
|
|
5435
4462
|
disabled && "opacity-disabled",
|
|
5436
|
-
|
|
4463
|
+
// Sprint 25.14 A20: the Toggle's track and knob, on and off (lib/control-looks.ts)
|
|
4464
|
+
checked ? SWITCH_TRACK_ON : SWITCH_TRACK_OFF
|
|
5437
4465
|
),
|
|
5438
4466
|
style: { width: 44, height: 24 },
|
|
5439
4467
|
children: /* @__PURE__ */ jsx(
|
|
5440
4468
|
"span",
|
|
5441
4469
|
{
|
|
5442
|
-
className: "pointer-events-none inline-block shrink-0
|
|
4470
|
+
className: cn("pointer-events-none inline-block shrink-0 rounded-[var(--ds-radius-full)]", checked ? SWITCH_KNOB_ON : SWITCH_KNOB_OFF, SWITCH_KNOB_MOTION),
|
|
5443
4471
|
style: {
|
|
5444
4472
|
width: 16,
|
|
5445
4473
|
height: 16,
|
|
@@ -5499,7 +4527,7 @@ var Card = forwardRef(function Card2({
|
|
|
5499
4527
|
const handleKeyDown = isSelectable && !disabled ? (e) => {
|
|
5500
4528
|
if (e.key === "Enter" || e.key === " ") {
|
|
5501
4529
|
e.preventDefault();
|
|
5502
|
-
onSelectedChange?.(!selected);
|
|
4530
|
+
if (!e.repeat) onSelectedChange?.(!selected);
|
|
5503
4531
|
}
|
|
5504
4532
|
} : isAction && !disabled ? (e) => {
|
|
5505
4533
|
if (e.target !== e.currentTarget) return;
|
|
@@ -5516,13 +4544,84 @@ var Card = forwardRef(function Card2({
|
|
|
5516
4544
|
} : void 0;
|
|
5517
4545
|
const handleCheckableClick = (e) => {
|
|
5518
4546
|
e.stopPropagation();
|
|
5519
|
-
onSelectedChange?.(!selected);
|
|
4547
|
+
if (!disabled) onSelectedChange?.(!selected);
|
|
5520
4548
|
};
|
|
5521
4549
|
const isButton = isSelectable || isAction && !holdsControls;
|
|
5522
4550
|
const role = selectType === "radio" ? "radio" : selectType === "checkbox" ? "checkbox" : selectType === "toggle" ? "switch" : isButton ? "button" : void 0;
|
|
5523
4551
|
const ariaAttr = selectType === "radio" || selectType === "checkbox" || selectType === "toggle" ? { "aria-checked": !!selected } : isSelectable ? { "aria-pressed": !!selected } : {};
|
|
5524
4552
|
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;
|
|
5525
|
-
const defaultCheckBadge = !hasSelectType && !checkable && selected && !loading ? /* @__PURE__ */ jsx("
|
|
4553
|
+
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;
|
|
4554
|
+
const checkboxes = useRef(/* @__PURE__ */ new Set());
|
|
4555
|
+
const checkboxFocused = useRef(false);
|
|
4556
|
+
const checkboxRef = useCallback((node) => {
|
|
4557
|
+
if (!node) return;
|
|
4558
|
+
checkboxes.current.add(node);
|
|
4559
|
+
return () => {
|
|
4560
|
+
checkboxes.current.delete(node);
|
|
4561
|
+
};
|
|
4562
|
+
}, []);
|
|
4563
|
+
useLayoutEffect(() => {
|
|
4564
|
+
if (!checkboxFocused.current) return;
|
|
4565
|
+
const active = document.activeElement;
|
|
4566
|
+
if (active && active !== document.body) return;
|
|
4567
|
+
for (const node of checkboxes.current) {
|
|
4568
|
+
if (node.isConnected) {
|
|
4569
|
+
node.focus({ preventScroll: true });
|
|
4570
|
+
return;
|
|
4571
|
+
}
|
|
4572
|
+
}
|
|
4573
|
+
});
|
|
4574
|
+
const checkbox = checkable ? /* @__PURE__ */ jsx(
|
|
4575
|
+
"div",
|
|
4576
|
+
{
|
|
4577
|
+
ref: checkboxRef,
|
|
4578
|
+
"data-card-checkbox": "",
|
|
4579
|
+
className: cn(
|
|
4580
|
+
"rounded-[calc(var(--ds-radius-sm)*0.6)] focus-visible:outline-none focus-visible:shadow-[var(--ds-shadow-focus)]",
|
|
4581
|
+
disabled ? "cursor-not-allowed" : "cursor-pointer"
|
|
4582
|
+
),
|
|
4583
|
+
onClick: handleCheckableClick,
|
|
4584
|
+
role: "checkbox",
|
|
4585
|
+
"aria-checked": !!selected,
|
|
4586
|
+
"aria-disabled": disabled || void 0,
|
|
4587
|
+
...inner.titleId ? { "aria-labelledby": inner.titleId } : { "aria-label": "Select" },
|
|
4588
|
+
tabIndex: 0,
|
|
4589
|
+
onFocus: () => {
|
|
4590
|
+
checkboxFocused.current = true;
|
|
4591
|
+
},
|
|
4592
|
+
onBlur: (e) => {
|
|
4593
|
+
const node = e.currentTarget;
|
|
4594
|
+
queueMicrotask(() => {
|
|
4595
|
+
if (node.isConnected) checkboxFocused.current = false;
|
|
4596
|
+
});
|
|
4597
|
+
},
|
|
4598
|
+
onKeyDown: (e) => {
|
|
4599
|
+
if (e.key !== " ") return;
|
|
4600
|
+
e.preventDefault();
|
|
4601
|
+
e.stopPropagation();
|
|
4602
|
+
if (!e.repeat && !disabled) onSelectedChange?.(!selected);
|
|
4603
|
+
},
|
|
4604
|
+
children: /* @__PURE__ */ jsx(CheckboxIndicator, { checked: !!selected, disabled })
|
|
4605
|
+
}
|
|
4606
|
+
) : null;
|
|
4607
|
+
const check = indicator ?? defaultCheckBadge;
|
|
4608
|
+
const headers = useRef([]);
|
|
4609
|
+
const [owner, setOwner] = useState(null);
|
|
4610
|
+
const [guess, setGuess] = useState(() => holdsHeader(children));
|
|
4611
|
+
const register = useCallback((header) => {
|
|
4612
|
+
headers.current = [...headers.current, header];
|
|
4613
|
+
setOwner(headers.current[0]);
|
|
4614
|
+
return () => {
|
|
4615
|
+
headers.current = headers.current.filter((h) => h !== header);
|
|
4616
|
+
setOwner(headers.current[0] ?? null);
|
|
4617
|
+
setGuess(false);
|
|
4618
|
+
};
|
|
4619
|
+
}, []);
|
|
4620
|
+
useLayoutEffect(() => {
|
|
4621
|
+
if (headers.current.length === 0) setGuess(false);
|
|
4622
|
+
}, []);
|
|
4623
|
+
const hasHeader = owner !== null || guess;
|
|
4624
|
+
const rowParts = { checkbox, check, owner, register };
|
|
5526
4625
|
return /* @__PURE__ */ jsxs(
|
|
5527
4626
|
"div",
|
|
5528
4627
|
{
|
|
@@ -5553,32 +4652,22 @@ var Card = forwardRef(function Card2({
|
|
|
5553
4652
|
...ariaAttr,
|
|
5554
4653
|
...props,
|
|
5555
4654
|
children: [
|
|
5556
|
-
|
|
5557
|
-
|
|
5558
|
-
|
|
5559
|
-
|
|
5560
|
-
|
|
5561
|
-
|
|
5562
|
-
|
|
5563
|
-
role: "checkbox",
|
|
5564
|
-
"aria-checked": !!selected,
|
|
5565
|
-
...inner.titleId ? { "aria-labelledby": inner.titleId } : { "aria-label": "Select" },
|
|
5566
|
-
tabIndex: 0,
|
|
5567
|
-
onKeyDown: (e) => {
|
|
5568
|
-
if (e.key === "Enter" || e.key === " ") {
|
|
5569
|
-
e.preventDefault();
|
|
5570
|
-
e.stopPropagation();
|
|
5571
|
-
onSelectedChange?.(!selected);
|
|
5572
|
-
}
|
|
5573
|
-
},
|
|
5574
|
-
children: /* @__PURE__ */ jsx(CheckboxIndicator, { checked: !!selected })
|
|
5575
|
-
}
|
|
5576
|
-
),
|
|
5577
|
-
/* @__PURE__ */ jsx(CardSurfaceCtx, { value: true, children: /* @__PURE__ */ jsx(CardActionCtx, { value: action, children: /* @__PURE__ */ jsx(CardCtx, { value: checkable, children: loading ? (
|
|
4655
|
+
!loading && !hasHeader && checkbox && /* @__PURE__ */ jsxs("div", { "data-card-header-row": "", className: "flex items-center gap-ds-2 px-ds-5 pt-ds-4", children: [
|
|
4656
|
+
/* @__PURE__ */ jsx("span", { "aria-hidden": "true", className: "grow" }),
|
|
4657
|
+
check && /* @__PURE__ */ jsx("span", { "data-card-selection": "", className: "shrink-0 flex", children: check }),
|
|
4658
|
+
checkbox
|
|
4659
|
+
] }),
|
|
4660
|
+
!loading && !hasHeader && !checkbox && check && /* @__PURE__ */ jsx("div", { "data-card-selection": "", className: "absolute top-ds-3 right-ds-3 z-[1] flex", children: check }),
|
|
4661
|
+
/* @__PURE__ */ jsx(CardSurfaceCtx, { value: true, children: /* @__PURE__ */ jsx(CardActionCtx, { value: action, children: /* @__PURE__ */ jsx(CardRowCtx, { value: rowParts, children: loading ? (
|
|
5578
4662
|
// Round 15 (the owner's 52.1): a placeholder stands where the content will stand — inside the card's
|
|
5579
4663
|
// content inset (CardContent's padding), a title-height line then two body lines — never flush against the border.
|
|
5580
|
-
|
|
5581
|
-
|
|
4664
|
+
// Its header holds a badge-sized block (A2), so a grid of item cards keeps its columns when they load.
|
|
4665
|
+
/* @__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: [
|
|
4666
|
+
/* @__PURE__ */ jsxs("div", { "data-card-header-row": "", className: "flex items-center gap-ds-2", children: [
|
|
4667
|
+
checkbox,
|
|
4668
|
+
/* @__PURE__ */ jsx(Skeleton, { variant: "custom", className: "h-5 w-1/3" }),
|
|
4669
|
+
/* @__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)]" }) }) })
|
|
4670
|
+
] }),
|
|
5582
4671
|
/* @__PURE__ */ jsx(Skeleton, { variant: "custom", className: "h-3 w-full" }),
|
|
5583
4672
|
/* @__PURE__ */ jsx(Skeleton, { variant: "custom", className: "h-3 w-2/3" })
|
|
5584
4673
|
] }) })
|
|
@@ -5587,60 +4676,95 @@ var Card = forwardRef(function Card2({
|
|
|
5587
4676
|
}
|
|
5588
4677
|
);
|
|
5589
4678
|
});
|
|
5590
|
-
|
|
5591
|
-
const
|
|
5592
|
-
const
|
|
5593
|
-
|
|
5594
|
-
|
|
5595
|
-
|
|
5596
|
-
|
|
5597
|
-
|
|
5598
|
-
|
|
5599
|
-
|
|
5600
|
-
|
|
4679
|
+
function partsOf(children) {
|
|
4680
|
+
const parts = [];
|
|
4681
|
+
const open = (node) => Children.toArray(node).forEach((child) => {
|
|
4682
|
+
if (isValidElement(child) && child.type === Fragment$1) open(child.props.children);
|
|
4683
|
+
else if (child !== "") parts.push(child);
|
|
4684
|
+
});
|
|
4685
|
+
open(children);
|
|
4686
|
+
return parts;
|
|
4687
|
+
}
|
|
4688
|
+
function splitTitle(children) {
|
|
4689
|
+
const parts = partsOf(children);
|
|
4690
|
+
const at = parts.findIndex((p) => isValidElement(p) && p.type === CardTitle);
|
|
4691
|
+
if (at < 0) return { lead: [], title: parts[0] ?? null, rest: parts.slice(1) };
|
|
4692
|
+
return { lead: parts.slice(0, at), title: parts[at], rest: parts.slice(at + 1) };
|
|
4693
|
+
}
|
|
4694
|
+
var TITLE_FLOOR = "basis-[calc(var(--ds-font-size-lg)*4.5)]";
|
|
4695
|
+
var TITLE_ROW = cn(
|
|
4696
|
+
"flex flex-wrap items-start justify-end gap-x-ds-2 gap-y-ds-2 min-w-0 grow basis-0",
|
|
4697
|
+
"[&>[data-header-actions]>*]:order-5",
|
|
4698
|
+
"[&>[data-header-actions]>:has([data-gs-badge]):not(:has(a,button,input,select,textarea,[role=button],[tabindex]:not([tabindex='-1'])))]:order-2",
|
|
4699
|
+
"[&>[data-header-actions]>:has([aria-haspopup])]:order-6"
|
|
4700
|
+
);
|
|
4701
|
+
var CardHeader = forwardRef(function CardHeader2(allProps, ref) {
|
|
4702
|
+
const { className, children, actions, icon, menuItems, ...props } = allProps;
|
|
4703
|
+
const row = useContext(CardRowCtx);
|
|
4704
|
+
const [self] = useState(() => ({}));
|
|
4705
|
+
const register = row?.register;
|
|
4706
|
+
useLayoutEffect(() => register?.(self), [register, self]);
|
|
4707
|
+
const owns = !!row && row.owner === self;
|
|
4708
|
+
const iconBlock = icon ? (
|
|
4709
|
+
// the icon stays where it was, a tile above the title (28 of 66 headers with actions have one)
|
|
4710
|
+
/* @__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)]" }) })
|
|
4711
|
+
) : null;
|
|
4712
|
+
const menu = menuItems ? /* @__PURE__ */ jsx(
|
|
4713
|
+
DropdownMenu,
|
|
4714
|
+
{
|
|
4715
|
+
trigger: /* @__PURE__ */ jsx(
|
|
4716
|
+
"button",
|
|
4717
|
+
{
|
|
4718
|
+
type: "button",
|
|
4719
|
+
"aria-label": "More actions",
|
|
4720
|
+
className: cn(
|
|
4721
|
+
"inline-flex items-center justify-center h-8 w-8 rounded-[var(--ds-radius-md)]",
|
|
4722
|
+
"text-[var(--ds-text-muted)] hover:text-[var(--ds-text-primary)] hover:bg-[var(--ds-bg-muted)]",
|
|
4723
|
+
"transition-colors duration-[var(--ds-transition-speed)]"
|
|
4724
|
+
),
|
|
4725
|
+
onClick: (e) => e.stopPropagation(),
|
|
4726
|
+
children: /* @__PURE__ */ jsx(Icon, { name: "more-horizontal", size: 16 })
|
|
4727
|
+
}
|
|
4728
|
+
),
|
|
4729
|
+
items: menuItems
|
|
4730
|
+
}
|
|
4731
|
+
) : null;
|
|
4732
|
+
const band = (order) => cn("shrink-0 self-start flex items-center", TITLE_LINE, order);
|
|
4733
|
+
const checkbox = owns && row.checkbox ? /* @__PURE__ */ jsx("span", { className: band("order-5"), children: row.checkbox }) : null;
|
|
4734
|
+
const check = owns && row.check ? /* @__PURE__ */ jsx("span", { "data-card-selection": "", className: band("order-4"), children: row.check }) : null;
|
|
4735
|
+
const menuPart = menu ? /* @__PURE__ */ jsx("span", { className: band("order-6"), children: menu }) : null;
|
|
4736
|
+
const { lead, title, rest } = splitTitle(children);
|
|
4737
|
+
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;
|
|
4738
|
+
const topLine = iconBlock ?? leadBlock;
|
|
4739
|
+
const ownBlock = title !== null && !(isValidElement(title) && title.type === CardTitle);
|
|
4740
|
+
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;
|
|
4741
|
+
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: [
|
|
4742
|
+
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: [
|
|
4743
|
+
topLine,
|
|
4744
|
+
iconBlock && /* @__PURE__ */ jsx("span", { "aria-hidden": "true", className: "grow -ml-ds-2" }),
|
|
4745
|
+
check,
|
|
4746
|
+
checkbox,
|
|
4747
|
+
menuPart
|
|
4748
|
+
] }),
|
|
4749
|
+
iconBlock && leadBlock && /* @__PURE__ */ jsx("div", { className: "flex mb-ds-1.5", children: leadBlock }),
|
|
4750
|
+
/* @__PURE__ */ jsxs("div", { "data-card-header-row": "", className: "flex items-start gap-ds-2 min-w-0", children: [
|
|
4751
|
+
/* @__PURE__ */ jsxs("div", { "data-card-title-line": "", className: TITLE_ROW, children: [
|
|
4752
|
+
title && /* @__PURE__ */ jsx(
|
|
4753
|
+
"div",
|
|
5601
4754
|
{
|
|
5602
|
-
|
|
5603
|
-
"
|
|
5604
|
-
|
|
5605
|
-
"inline-flex items-center justify-center h-8 w-8 rounded-[var(--ds-radius-md)]",
|
|
5606
|
-
"text-[var(--ds-text-muted)] hover:text-[var(--ds-text-primary)] hover:bg-[var(--ds-bg-muted)]",
|
|
5607
|
-
"transition-colors duration-[var(--ds-transition-speed)]"
|
|
5608
|
-
),
|
|
5609
|
-
onClick: (e) => e.stopPropagation(),
|
|
5610
|
-
children: /* @__PURE__ */ jsx(Icon, { name: "more-horizontal", size: 16 })
|
|
4755
|
+
"data-card-title-row": "",
|
|
4756
|
+
className: cn("order-1 min-w-0 me-auto", TITLE_FLOOR, ownBlock ? "grow" : "grow-[999] max-w-max"),
|
|
4757
|
+
children: /* @__PURE__ */ jsx(HeaderRowCtx, { value: true, children: title })
|
|
5611
4758
|
}
|
|
5612
4759
|
),
|
|
5613
|
-
|
|
5614
|
-
|
|
5615
|
-
)
|
|
5616
|
-
] }) : null;
|
|
5617
|
-
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;
|
|
5618
|
-
const parts = Children.toArray(children);
|
|
5619
|
-
const titleLeads = !!hasActions && !iconBlock && !menuItems && actionsAreBadges(actions) && parts.length > 0 && isValidElement(parts[0]) && parts[0].type === CardTitle;
|
|
5620
|
-
const leadRowRef = useRef(null);
|
|
5621
|
-
const leadFloorFits = useTitleFloorFits(leadRowRef, titleLeads);
|
|
5622
|
-
if (hasActions) {
|
|
5623
|
-
if (titleLeads) {
|
|
5624
|
-
const below = parts.slice(1);
|
|
5625
|
-
return /* @__PURE__ */ jsxs("div", { ref, className: cn(pl, "pr-ds-5 pt-ds-4 last:pb-ds-4", className), ...props, children: [
|
|
5626
|
-
/* @__PURE__ */ jsxs("div", { ref: leadRowRef, className: HEADER_LAYOUT.row, children: [
|
|
5627
|
-
/* @__PURE__ */ jsx("div", { "data-card-title-row": "", className: cn(HEADER_LAYOUT.titleLeads, !leadFloorFits && HEADER_LAYOUT.floorOff), children: parts[0] }),
|
|
5628
|
-
actionsBlock
|
|
5629
|
-
] }),
|
|
5630
|
-
below.length > 0 && /* @__PURE__ */ jsx("div", { className: cn("flex flex-col space-y-ds-1.5 break-words", HEADER_LAYOUT.below), children: below })
|
|
5631
|
-
] });
|
|
5632
|
-
}
|
|
5633
|
-
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: [
|
|
5634
|
-
/* @__PURE__ */ jsxs("div", { className: HEADER_LAYOUT.block, children: [
|
|
5635
|
-
iconBlock,
|
|
5636
|
-
children
|
|
4760
|
+
actionsSlot,
|
|
4761
|
+
!ownBlock && /* @__PURE__ */ jsx("span", { "aria-hidden": "true", className: "order-3 grow basis-0 -ml-ds-2" })
|
|
5637
4762
|
] }),
|
|
5638
|
-
|
|
5639
|
-
|
|
5640
|
-
|
|
5641
|
-
|
|
5642
|
-
|
|
5643
|
-
children
|
|
4763
|
+
!topLine && check,
|
|
4764
|
+
!topLine && checkbox,
|
|
4765
|
+
!topLine && menuPart
|
|
4766
|
+
] }),
|
|
4767
|
+
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 })
|
|
5644
4768
|
] });
|
|
5645
4769
|
});
|
|
5646
4770
|
var cardLineClampClasses = {
|
|
@@ -5651,7 +4775,10 @@ var cardLineClampClasses = {
|
|
|
5651
4775
|
5: "line-clamp-5",
|
|
5652
4776
|
6: "line-clamp-6"
|
|
5653
4777
|
};
|
|
5654
|
-
var
|
|
4778
|
+
var WHOLE_ON_KEYBOARD = "[[data-card]:has(:focus-visible)_&]:whitespace-normal [[data-card]:has(:focus-visible)_&]:line-clamp-none";
|
|
4779
|
+
var CardTitle = forwardRef(function CardTitle2({ className, children, lines: linesProp, id, ...props }, forwardedRef) {
|
|
4780
|
+
const inHeaderRow = useContext(HeaderRowCtx);
|
|
4781
|
+
const lines = linesProp ?? (inHeaderRow ? 1 : 2);
|
|
5655
4782
|
const action = useContext(CardActionCtx);
|
|
5656
4783
|
const generatedId = useId();
|
|
5657
4784
|
const { ref: overflowRef, isTruncated } = useTextOverflow({ lines, disabled: lines === 0 });
|
|
@@ -5667,7 +4794,7 @@ var CardTitle = forwardRef(function CardTitle2({ className, children, lines = 2,
|
|
|
5667
4794
|
id: id ?? generatedId,
|
|
5668
4795
|
"data-card-title": "",
|
|
5669
4796
|
...lines === 1 ? { "data-title-one-line": "" } : {},
|
|
5670
|
-
className: cn(TITLE_TEXT, !action && lines > 0 && lineClampClass, action && lines === 1 && "text-ellipsis", className),
|
|
4797
|
+
className: cn(TITLE_TEXT, !action && lines > 0 && [lineClampClass, WHOLE_ON_KEYBOARD], action && lines === 1 && "text-ellipsis", className),
|
|
5671
4798
|
...props,
|
|
5672
4799
|
children: action ? (
|
|
5673
4800
|
// The card's action when the card holds controls of its own (Sprint 25.7): a real button, which a click
|
|
@@ -5684,14 +4811,13 @@ var CardTitle = forwardRef(function CardTitle2({ className, children, lines = 2,
|
|
|
5684
4811
|
"block w-full text-left cursor-pointer [text-overflow:inherit] focus-visible:outline-none disabled:cursor-not-allowed",
|
|
5685
4812
|
"after:absolute after:inset-0 after:rounded-[var(--ds-radius-md)] after:pointer-events-none focus-visible:after:shadow-[var(--ds-shadow-focus)]"
|
|
5686
4813
|
),
|
|
5687
|
-
children: /* @__PURE__ */ jsx("span", { ref: (node) => overflowRef(lines > 0 ? node : null), className: cn("block [text-overflow:inherit]", lines > 0 && lineClampClass), children })
|
|
4814
|
+
children: /* @__PURE__ */ jsx("span", { ref: (node) => overflowRef(lines > 0 ? node : null), className: cn("block [text-overflow:inherit]", lines > 0 && [lineClampClass, WHOLE_ON_KEYBOARD]), children })
|
|
5688
4815
|
}
|
|
5689
4816
|
)
|
|
5690
4817
|
) : children
|
|
5691
4818
|
}
|
|
5692
4819
|
);
|
|
5693
|
-
|
|
5694
|
-
return /* @__PURE__ */ jsx(Tooltip, { content: children, children: heading });
|
|
4820
|
+
return /* @__PURE__ */ jsx(Tooltip, { content: children, disabled: !isTruncated, children: heading });
|
|
5695
4821
|
});
|
|
5696
4822
|
var CardDescription = forwardRef(function CardDescription2({ className, children, lines = 2, ...props }, forwardedRef) {
|
|
5697
4823
|
const { ref: overflowRef, isTruncated } = useTextOverflow({ lines, disabled: lines === 0 });
|
|
@@ -5709,23 +4835,20 @@ var CardDescription = forwardRef(function CardDescription2({ className, children
|
|
|
5709
4835
|
children
|
|
5710
4836
|
}
|
|
5711
4837
|
);
|
|
5712
|
-
|
|
5713
|
-
return /* @__PURE__ */ jsx(Tooltip, { content: children, children: el });
|
|
4838
|
+
return /* @__PURE__ */ jsx(Tooltip, { content: children, disabled: !isTruncated, children: el });
|
|
5714
4839
|
});
|
|
5715
4840
|
var CardContent = forwardRef(function CardContent2({ className, children, ...props }, ref) {
|
|
5716
|
-
|
|
5717
|
-
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 });
|
|
4841
|
+
return /* @__PURE__ */ jsx("div", { ref, className: cn("flex-1 px-ds-5 py-ds-4", className), ...props, children });
|
|
5718
4842
|
});
|
|
5719
4843
|
var CardFooter = forwardRef(function CardFooter2({ className, children, ...props }, ref) {
|
|
5720
|
-
const isCheckable = useContext(CardCtx);
|
|
5721
4844
|
return (
|
|
5722
4845
|
// a footer that holds only buttons puts them at the end (round 11: a lone Save sat on the left); text keeps the start
|
|
5723
|
-
/* @__PURE__ */ jsx("div", { ref, className: cn("flex items-center gap-ds-2
|
|
4846
|
+
/* @__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 })
|
|
5724
4847
|
);
|
|
5725
4848
|
});
|
|
5726
4849
|
function TruncLabel({ children }) {
|
|
5727
4850
|
const { ref, isTruncated } = useTextOverflow({ lines: 1 });
|
|
5728
|
-
const el = /* @__PURE__ */ jsx("span", { ref, className: "text-xs font-medium text-[var(--ds-text-muted)] uppercase tracking-wider truncate min-w-0", children });
|
|
4851
|
+
const el = /* @__PURE__ */ jsx("span", { ref, className: "block text-xs font-medium text-[var(--ds-text-muted)] uppercase tracking-wider truncate min-w-0", children });
|
|
5729
4852
|
if (!isTruncated) return el;
|
|
5730
4853
|
return /* @__PURE__ */ jsx(Tooltip, { content: children, children: el });
|
|
5731
4854
|
}
|
|
@@ -5770,13 +4893,15 @@ function StatsCard({ value, label, trend, icon, layout = "card", interactive, on
|
|
|
5770
4893
|
} : void 0,
|
|
5771
4894
|
children: [
|
|
5772
4895
|
/* @__PURE__ */ jsxs("div", { className: "flex items-start justify-between gap-ds-2 min-w-0", children: [
|
|
5773
|
-
/* @__PURE__ */
|
|
4896
|
+
/* @__PURE__ */ jsxs("div", { className: "min-w-0 flex-1", children: [
|
|
4897
|
+
/* @__PURE__ */ jsx(TruncLabel, { children: label }),
|
|
4898
|
+
/* @__PURE__ */ jsxs("div", { className: "flex items-baseline gap-ds-2 mt-ds-2 flex-wrap", children: [
|
|
4899
|
+
/* @__PURE__ */ jsx("span", { className: "font-[family-name:var(--ds-font-display)] text-2xl font-[var(--ds-weight-heading)] text-[var(--ds-text-primary)] leading-none tabular-nums", children: value }),
|
|
4900
|
+
trend && /* @__PURE__ */ jsx(TrendBadge, { trend })
|
|
4901
|
+
] })
|
|
4902
|
+
] }),
|
|
5774
4903
|
icon && /* @__PURE__ */ jsx("div", { className: "shrink-0 flex items-center justify-center w-8 h-8 rounded-[var(--ds-radius-sm)] bg-[var(--ds-bg-muted)]", children: /* @__PURE__ */ jsx(Icon, { name: icon, size: 16, className: "text-[var(--ds-text-muted)]" }) })
|
|
5775
4904
|
] }),
|
|
5776
|
-
/* @__PURE__ */ jsxs("div", { className: "flex items-baseline gap-ds-2 mt-ds-2 flex-wrap", children: [
|
|
5777
|
-
/* @__PURE__ */ jsx("span", { className: "font-[family-name:var(--ds-font-display)] text-2xl font-[var(--ds-weight-heading)] text-[var(--ds-text-primary)] leading-none tabular-nums", children: value }),
|
|
5778
|
-
trend && /* @__PURE__ */ jsx(TrendBadge, { trend })
|
|
5779
|
-
] }),
|
|
5780
4905
|
children && /* @__PURE__ */ jsx("div", { className: "mt-ds-3 text-xs text-[var(--ds-text-muted)]", children })
|
|
5781
4906
|
]
|
|
5782
4907
|
}
|
|
@@ -5836,6 +4961,9 @@ function DataList({ items, columns = 1, className }) {
|
|
|
5836
4961
|
);
|
|
5837
4962
|
}
|
|
5838
4963
|
var COUNT_FROM_PAGE = [
|
|
4964
|
+
// one card counts too: a lone card fell back to React's count, which counts components that draw nothing, and a grid
|
|
4965
|
+
// with one card inside another took the outer grid's count (the review of 30 September)
|
|
4966
|
+
"[&:has(>:only-child)]:[--gs-cards:1]",
|
|
5839
4967
|
"[&:has(>:nth-child(2):last-child)]:[--gs-cards:2]",
|
|
5840
4968
|
"[&:has(>:nth-child(3):last-child)]:[--gs-cards:3]",
|
|
5841
4969
|
"[&:has(>:nth-child(4):last-child)]:[--gs-cards:4]",
|
|
@@ -5848,6 +4976,7 @@ var COUNT_FROM_PAGE = [
|
|
|
5848
4976
|
"[&:has(>:nth-child(11):last-child)]:[--gs-cards:11]",
|
|
5849
4977
|
"[&:has(>:nth-child(12))]:[--gs-cards:12]"
|
|
5850
4978
|
].join(" ");
|
|
4979
|
+
var MIN_FROM_HEADERS = "[--gs-card-min:14rem] has-[[data-header-actions]]:[--gs-card-min:20rem]";
|
|
5851
4980
|
function countCards(children) {
|
|
5852
4981
|
let n = 0;
|
|
5853
4982
|
Children.forEach(children, (child) => {
|
|
@@ -5856,14 +4985,19 @@ function countCards(children) {
|
|
|
5856
4985
|
});
|
|
5857
4986
|
return n;
|
|
5858
4987
|
}
|
|
5859
|
-
function CardGrid({ minWidth
|
|
4988
|
+
function CardGrid({ minWidth, maxColumns = 4, compare = false, gap = "var(--ds-space-4)", fill: fill2 = true, className, style, children, ref, ...props }) {
|
|
4989
|
+
useFramesItself();
|
|
5860
4990
|
const most = Math.max(1, Math.floor(maxColumns));
|
|
5861
|
-
const
|
|
5862
|
-
const
|
|
5863
|
-
const
|
|
4991
|
+
const drawn = "var(--gs-cards, var(--gs-cards-counted))";
|
|
4992
|
+
const min = "var(--gs-card-min)";
|
|
4993
|
+
const shareOf = (n) => `calc((100% - (${n} - 1) * var(--gs-card-gap)) / ${n})`;
|
|
4994
|
+
const collection = `max(min(${min}, 100%), ${shareOf(String(most))})`;
|
|
4995
|
+
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;
|
|
5864
4996
|
const template = {
|
|
5865
4997
|
"--gs-card-gap": gap,
|
|
5866
|
-
|
|
4998
|
+
// A2: a width passed wins; a comparison keeps 14rem; a collection's comes from its headers (MIN_FROM_HEADERS)
|
|
4999
|
+
...minWidth ? { "--gs-card-min": minWidth } : compare ? { "--gs-card-min": "14rem" } : {},
|
|
5000
|
+
...compare || fill2 ? { "--gs-cards-counted": Math.max(1, countCards(children)) } : {},
|
|
5867
5001
|
gap: "var(--gs-card-gap)",
|
|
5868
5002
|
gridTemplateColumns: `repeat(auto-fill, minmax(${column}, 1fr))`,
|
|
5869
5003
|
// a comparison's cards share their rows: the headers, the contents and the footers line up across the row
|
|
@@ -5876,7 +5010,8 @@ function CardGrid({ minWidth = "14rem", maxColumns = 4, compare = false, gap = "
|
|
|
5876
5010
|
"data-card-grid": compare ? "compare" : "",
|
|
5877
5011
|
className: cn(
|
|
5878
5012
|
"grid",
|
|
5879
|
-
compare &&
|
|
5013
|
+
!minWidth && !compare && MIN_FROM_HEADERS,
|
|
5014
|
+
(compare || fill2) && COUNT_FROM_PAGE,
|
|
5880
5015
|
// each card spans its three rows and lays its parts in them; anything else just fills them
|
|
5881
5016
|
compare && "[&>*]:row-span-3 [&>[data-card]]:grid [&>[data-card]]:grid-rows-subgrid [&>[data-card]]:gap-y-0",
|
|
5882
5017
|
className
|
|
@@ -6160,68 +5295,41 @@ function Accordion({ items, type = "single", defaultOpen = [], open: controlledO
|
|
|
6160
5295
|
] }, i);
|
|
6161
5296
|
}) });
|
|
6162
5297
|
}
|
|
6163
|
-
var
|
|
6164
|
-
|
|
6165
|
-
|
|
6166
|
-
|
|
6167
|
-
|
|
6168
|
-
|
|
6169
|
-
|
|
6170
|
-
|
|
6171
|
-
|
|
6172
|
-
const
|
|
6173
|
-
|
|
6174
|
-
|
|
6175
|
-
|
|
6176
|
-
|
|
6177
|
-
|
|
6178
|
-
|
|
6179
|
-
|
|
6180
|
-
|
|
5298
|
+
var HEADER_LAYOUT = {
|
|
5299
|
+
row: "flex flex-wrap items-start justify-between gap-ds-4",
|
|
5300
|
+
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",
|
|
5301
|
+
titleLeads: "grow basis-1/2 max-w-max break-words has-[[data-title-one-line]]:min-w-0",
|
|
5302
|
+
floorOff: "min-w-0",
|
|
5303
|
+
actions: "flex items-center gap-ds-2 shrink-0 ml-auto",
|
|
5304
|
+
below: "mt-ds-1.5"
|
|
5305
|
+
};
|
|
5306
|
+
function useTitleFloorFits(rowRef, active) {
|
|
5307
|
+
const [fits, setFits] = useState(true);
|
|
5308
|
+
useLayoutEffect(() => {
|
|
5309
|
+
const row = rowRef.current;
|
|
5310
|
+
if (!active || !row) return;
|
|
5311
|
+
const measure = () => {
|
|
5312
|
+
const title = row.querySelector("h1, h2, h3, h4, h5, h6");
|
|
5313
|
+
if (!title) return;
|
|
5314
|
+
const width = title.style.width;
|
|
5315
|
+
title.style.width = "min-content";
|
|
5316
|
+
const longest = title.getBoundingClientRect().width;
|
|
5317
|
+
title.style.width = width;
|
|
5318
|
+
if (longest === 0) return;
|
|
5319
|
+
const next = longest <= row.clientWidth + 0.5;
|
|
5320
|
+
setFits((was) => was === next ? was : next);
|
|
6181
5321
|
};
|
|
6182
|
-
setState((prev) => same(prev, next) ? prev : next);
|
|
6183
|
-
}, []);
|
|
6184
|
-
const ref = useCallback((el) => {
|
|
6185
|
-
observer.current?.disconnect();
|
|
6186
|
-
observer.current = null;
|
|
6187
|
-
elRef.current = el;
|
|
6188
|
-
if (!el || !enabled) return;
|
|
6189
|
-
const style = getComputedStyle(el);
|
|
6190
|
-
const px = (v) => parseFloat(v) || 0;
|
|
6191
|
-
borders.current = { x: px(style.borderLeftWidth) + px(style.borderRightWidth), y: px(style.borderTopWidth) + px(style.borderBottomWidth) };
|
|
6192
5322
|
measure();
|
|
6193
5323
|
if (typeof ResizeObserver === "undefined") return;
|
|
6194
|
-
const
|
|
6195
|
-
|
|
6196
|
-
|
|
6197
|
-
|
|
6198
|
-
|
|
6199
|
-
|
|
6200
|
-
|
|
6201
|
-
const
|
|
6202
|
-
|
|
6203
|
-
const mask = shown ? {
|
|
6204
|
-
image: [fadeLayer, ...gutters.map(() => "linear-gradient(black, black)")].join(", "),
|
|
6205
|
-
size: ["100% 100%", ...gutters.map((g) => g.size)].join(", "),
|
|
6206
|
-
position: ["0 0", ...gutters.map((g) => g.position)].join(", ")
|
|
6207
|
-
} : void 0;
|
|
6208
|
-
return {
|
|
6209
|
-
/** The scroller's ref (a callback). */
|
|
6210
|
-
ref,
|
|
6211
|
-
/** The scroller itself, for code that moves it. */
|
|
6212
|
-
elRef,
|
|
6213
|
-
measure,
|
|
6214
|
-
/** Content hides past a side edge: the scroller moves sideways, and its edges fade. */
|
|
6215
|
-
overflowing: shown,
|
|
6216
|
-
/** It scrolls either way, sideways or up and down: a keyboard needs to reach it. */
|
|
6217
|
-
scrollable: enabled && (state.left || state.right || state.vertical),
|
|
6218
|
-
edges: { left: state.left, right: state.right },
|
|
6219
|
-
/** For the scroller: `data-fade` names the faded edges ("left", "right" or "left right"), the style masks them. */
|
|
6220
|
-
fadeProps: {
|
|
6221
|
-
"data-fade": shown ? [state.left && "left", state.right && "right"].filter(Boolean).join(" ") : void 0,
|
|
6222
|
-
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
|
|
6223
|
-
}
|
|
6224
|
-
};
|
|
5324
|
+
const observer = new ResizeObserver(measure);
|
|
5325
|
+
observer.observe(row);
|
|
5326
|
+
return () => observer.disconnect();
|
|
5327
|
+
}, [rowRef, active]);
|
|
5328
|
+
return fits;
|
|
5329
|
+
}
|
|
5330
|
+
function actionsAreBadges(actions) {
|
|
5331
|
+
const items = Children.toArray(actions);
|
|
5332
|
+
return items.length > 0 && items.every((item) => isValidElement(item) && (item.type === Fragment$1 ? actionsAreBadges(item.props.children) : item.type === Badge));
|
|
6225
5333
|
}
|
|
6226
5334
|
function TruncCell({ children, lines }) {
|
|
6227
5335
|
const { ref, isTruncated } = useTextOverflow({ lines });
|
|
@@ -6237,6 +5345,95 @@ var FRAME_CLASSES = cn(
|
|
|
6237
5345
|
GLASS_SURFACE,
|
|
6238
5346
|
"bg-[var(--ds-bg-surface)]"
|
|
6239
5347
|
);
|
|
5348
|
+
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)";
|
|
5349
|
+
var PINNED_LAYERS = cn(
|
|
5350
|
+
"[--gs-pinned-surface:var(--ds-bg-surface)] [--gs-pinned-canvas:var(--ds-bg-canvas)]",
|
|
5351
|
+
"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)))]",
|
|
5352
|
+
"supports-[color:oklch(from_red_l_c_h)]:[--gs-pinned-canvas:oklch(from_var(--ds-bg-canvas)_l_c_h_/_1)]"
|
|
5353
|
+
);
|
|
5354
|
+
var PIN_SHADOW = "oklch(0 0 0 / 0.18)";
|
|
5355
|
+
var ROW_CONTROL = `${FOCUSABLE}, label, [role="button"], [role="checkbox"], [role="switch"], [role="menuitem"], [role="link"]`;
|
|
5356
|
+
function clickIsRows(e) {
|
|
5357
|
+
const target = e.target;
|
|
5358
|
+
if (!(target instanceof Element) || !e.currentTarget.contains(target)) return false;
|
|
5359
|
+
const selection = typeof window !== "undefined" ? window.getSelection() : null;
|
|
5360
|
+
if (selection && !selection.isCollapsed && selection.anchorNode && e.currentTarget.contains(selection.anchorNode)) return false;
|
|
5361
|
+
const control = target.closest(ROW_CONTROL);
|
|
5362
|
+
return !control || control === e.currentTarget || !e.currentTarget.contains(control);
|
|
5363
|
+
}
|
|
5364
|
+
function sortableValue(v) {
|
|
5365
|
+
if (v === null || v === void 0 || v === "") return void 0;
|
|
5366
|
+
if (v instanceof Date) return v.getTime();
|
|
5367
|
+
if (typeof v === "string" || typeof v === "number") return v;
|
|
5368
|
+
if (typeof v === "boolean") return v ? 1 : 0;
|
|
5369
|
+
return isValidElement(v) || typeof v === "object" ? null : String(v);
|
|
5370
|
+
}
|
|
5371
|
+
var COLLATOR = new Intl.Collator(void 0, { numeric: true });
|
|
5372
|
+
function compareValues(a, b) {
|
|
5373
|
+
if (typeof a === "number" && typeof b === "number") return a - b;
|
|
5374
|
+
return COLLATOR.compare(String(a), String(b));
|
|
5375
|
+
}
|
|
5376
|
+
var UNIT_SCALE = {
|
|
5377
|
+
"": 1,
|
|
5378
|
+
"%": 1,
|
|
5379
|
+
b: 1,
|
|
5380
|
+
byte: 1,
|
|
5381
|
+
bytes: 1,
|
|
5382
|
+
kb: 1e3,
|
|
5383
|
+
kib: 1024,
|
|
5384
|
+
mb: 1e6,
|
|
5385
|
+
mib: 1024 ** 2,
|
|
5386
|
+
gb: 1e9,
|
|
5387
|
+
gib: 1024 ** 3,
|
|
5388
|
+
tb: 1e12,
|
|
5389
|
+
tib: 1024 ** 4,
|
|
5390
|
+
pb: 1e15,
|
|
5391
|
+
pib: 1024 ** 5,
|
|
5392
|
+
ms: 1,
|
|
5393
|
+
s: 1e3,
|
|
5394
|
+
sec: 1e3,
|
|
5395
|
+
min: 6e4,
|
|
5396
|
+
h: 36e5,
|
|
5397
|
+
hr: 36e5,
|
|
5398
|
+
hrs: 36e5,
|
|
5399
|
+
g: 1,
|
|
5400
|
+
kg: 1e3,
|
|
5401
|
+
m: 1,
|
|
5402
|
+
km: 1e3,
|
|
5403
|
+
"\xB0c": 1,
|
|
5404
|
+
"\xB0f": 1
|
|
5405
|
+
};
|
|
5406
|
+
function numberOf(text) {
|
|
5407
|
+
const m = /^\s*([-\u2212])?\s*[$€£¥]?\s*([-\u2212])?\s*(\d[\d,]*\.?\d*|\.\d+)\s*(%|°[CF]|[a-z]*)\s*$/i.exec(text);
|
|
5408
|
+
const scale = m ? UNIT_SCALE[m[4].toLowerCase()] : void 0;
|
|
5409
|
+
if (!m || scale === void 0) return void 0;
|
|
5410
|
+
const n = parseFloat(m[3].replace(/,/g, ""));
|
|
5411
|
+
return Number.isFinite(n) ? (m[1] || m[2] ? -1 : 1) * n * scale : void 0;
|
|
5412
|
+
}
|
|
5413
|
+
function timeOf(text) {
|
|
5414
|
+
const t = Date.parse(text);
|
|
5415
|
+
return Number.isNaN(t) ? void 0 : t;
|
|
5416
|
+
}
|
|
5417
|
+
function rowIdsOf(data, field) {
|
|
5418
|
+
const seen = /* @__PURE__ */ new Set();
|
|
5419
|
+
let repeated = null;
|
|
5420
|
+
const ids = data.map((row, index) => {
|
|
5421
|
+
const v = row[field];
|
|
5422
|
+
if (typeof v !== "string" && typeof v !== "number") return index;
|
|
5423
|
+
if (!seen.has(String(v))) {
|
|
5424
|
+
seen.add(String(v));
|
|
5425
|
+
return v;
|
|
5426
|
+
}
|
|
5427
|
+
repeated ??= String(v);
|
|
5428
|
+
return `${v}~${index}`;
|
|
5429
|
+
});
|
|
5430
|
+
return { ids, repeated };
|
|
5431
|
+
}
|
|
5432
|
+
function rowMarks(row, index, field, id) {
|
|
5433
|
+
const v = row[field];
|
|
5434
|
+
return typeof v === "string" || typeof v === "number" ? { "data-row-key": String(id) } : { "data-row-index": String(index) };
|
|
5435
|
+
}
|
|
5436
|
+
var idPart = (id) => String(id).replace(/\s+/g, "_");
|
|
6240
5437
|
function TableHeading({ title, description, actions, titleId, descriptionId, inset }) {
|
|
6241
5438
|
const heading = /* @__PURE__ */ jsx("h3", { id: titleId, className: TITLE_CLASSES, children: title });
|
|
6242
5439
|
const actionsBlock = actions ? /* @__PURE__ */ jsx("div", { className: HEADER_LAYOUT.actions, children: actions }) : null;
|
|
@@ -6258,8 +5455,13 @@ function TableHeading({ title, description, actions, titleId, descriptionId, ins
|
|
|
6258
5455
|
descriptionText(HEADER_LAYOUT.below)
|
|
6259
5456
|
] }) });
|
|
6260
5457
|
}
|
|
5458
|
+
var NO_PINS = { start: [], end: [], nameFits: false, frame: 0, panel: null };
|
|
5459
|
+
var samePins = (a, b) => a.nameFits === b.nameFits && a.frame === b.frame && a.start.join() === b.start.join() && a.end.join() === b.end.join() && a.panel?.join() === b.panel?.join();
|
|
5460
|
+
function PanelContent({ children }) {
|
|
5461
|
+
return /* @__PURE__ */ jsx(SurfaceBoundary, { children });
|
|
5462
|
+
}
|
|
6261
5463
|
function Table({
|
|
6262
|
-
columns,
|
|
5464
|
+
columns: columnsProp,
|
|
6263
5465
|
data,
|
|
6264
5466
|
className,
|
|
6265
5467
|
sortable,
|
|
@@ -6271,6 +5473,10 @@ function Table({
|
|
|
6271
5473
|
onSelectionChange,
|
|
6272
5474
|
expandable,
|
|
6273
5475
|
renderExpanded,
|
|
5476
|
+
rowKey = "id",
|
|
5477
|
+
expandedRows: expandedRowsProp,
|
|
5478
|
+
defaultExpandedRows,
|
|
5479
|
+
onExpandedChange,
|
|
6274
5480
|
density = "default",
|
|
6275
5481
|
stickyHeader = false,
|
|
6276
5482
|
striped = false,
|
|
@@ -6278,18 +5484,24 @@ function Table({
|
|
|
6278
5484
|
emptyState,
|
|
6279
5485
|
onRowClick,
|
|
6280
5486
|
mobileBreakpoint: mobileBreakpointProp,
|
|
5487
|
+
cardsBelow = CARDS_BELOW,
|
|
5488
|
+
pager,
|
|
6281
5489
|
title,
|
|
6282
5490
|
description,
|
|
6283
5491
|
actions,
|
|
6284
5492
|
"aria-label": ariaLabel,
|
|
6285
5493
|
ref
|
|
6286
5494
|
}) {
|
|
5495
|
+
useFramesItself();
|
|
6287
5496
|
const headingId = useId();
|
|
6288
5497
|
const titleId = `${headingId}-title`;
|
|
6289
5498
|
const descriptionId = `${headingId}-description`;
|
|
6290
5499
|
const [internalSortKey, setInternalSortKey] = useState(null);
|
|
6291
5500
|
const [internalSortDir, setInternalSortDir] = useState(null);
|
|
6292
|
-
const
|
|
5501
|
+
const columns = useMemo(
|
|
5502
|
+
() => [...columnsProp.filter((c) => c.pin === "start"), ...columnsProp.filter((c) => !c.pin), ...columnsProp.filter((c) => c.pin === "end")],
|
|
5503
|
+
[columnsProp]
|
|
5504
|
+
);
|
|
6293
5505
|
const isControlled = controlledSortKey !== void 0;
|
|
6294
5506
|
const sortKey = isControlled ? controlledSortKey : internalSortKey;
|
|
6295
5507
|
const sortDir = isControlled ? controlledSortDir ?? null : internalSortDir;
|
|
@@ -6309,6 +5521,7 @@ function Table({
|
|
|
6309
5521
|
nextKey = key;
|
|
6310
5522
|
nextDir = "asc";
|
|
6311
5523
|
}
|
|
5524
|
+
pager?.setPage(1);
|
|
6312
5525
|
if (onSortChange) {
|
|
6313
5526
|
onSortChange(nextKey, nextDir);
|
|
6314
5527
|
} else {
|
|
@@ -6316,139 +5529,351 @@ function Table({
|
|
|
6316
5529
|
setInternalSortDir(nextDir);
|
|
6317
5530
|
}
|
|
6318
5531
|
},
|
|
6319
|
-
[sortKey, sortDir, onSortChange]
|
|
5532
|
+
[sortKey, sortDir, onSortChange, pager]
|
|
5533
|
+
);
|
|
5534
|
+
const columnKeys = useMemo(() => columns.map((c) => c.key), [columns]);
|
|
5535
|
+
const inferredKinds = useMemo(() => inferColumnKinds(data, columnKeys), [data, columnKeys]);
|
|
5536
|
+
const kindOf = useCallback(
|
|
5537
|
+
(col) => col.kind ?? inferredKinds.get(col.key),
|
|
5538
|
+
[inferredKinds]
|
|
6320
5539
|
);
|
|
6321
|
-
const
|
|
6322
|
-
|
|
6323
|
-
|
|
6324
|
-
|
|
6325
|
-
|
|
6326
|
-
|
|
6327
|
-
|
|
5540
|
+
const sortColumn = sortKey ? columns.find((c) => c.key === sortKey) : void 0;
|
|
5541
|
+
const sortKind = sortColumn ? kindOf(sortColumn) : void 0;
|
|
5542
|
+
const { sortedAll, unsortable } = useMemo(() => {
|
|
5543
|
+
const indexed = data.map((row, i) => ({ row, originalIdx: i }));
|
|
5544
|
+
if (!sortKey || !sortDir) return { sortedAll: indexed, unsortable: null };
|
|
5545
|
+
const read = (row) => {
|
|
5546
|
+
if (sortColumn?.sortValue) return sortableValue(sortColumn.sortValue(row));
|
|
5547
|
+
const v = sortableValue(row[sortKey]);
|
|
5548
|
+
if (typeof v !== "string") return v;
|
|
5549
|
+
return (sortKind === "number" ? numberOf(v) : sortKind === "date" ? timeOf(v) : void 0) ?? v;
|
|
5550
|
+
};
|
|
5551
|
+
const valued = indexed.map((entry) => ({ ...entry, value: read(entry.row) }));
|
|
5552
|
+
const elements = valued.some((v) => v.value === null);
|
|
5553
|
+
const sorted = elements ? indexed : valued.sort((a, b) => {
|
|
5554
|
+
if (a.value === void 0 || b.value === void 0) return a.value === b.value ? 0 : a.value === void 0 ? 1 : -1;
|
|
5555
|
+
const cmp = compareValues(a.value, b.value);
|
|
5556
|
+
return sortDir === "asc" ? cmp : -cmp;
|
|
5557
|
+
});
|
|
5558
|
+
return { sortedAll: sorted, unsortable: elements ? sortKey : null };
|
|
5559
|
+
}, [data, sortKey, sortDir, sortColumn, sortKind]);
|
|
5560
|
+
const canSort = useMemo(() => {
|
|
5561
|
+
const can = /* @__PURE__ */ new Set();
|
|
5562
|
+
for (const col of columns) if (col.sortValue || data.every((row) => sortableValue(row[col.key]) !== null)) can.add(col.key);
|
|
5563
|
+
return can;
|
|
5564
|
+
}, [columns, data]);
|
|
5565
|
+
useEffect(() => {
|
|
5566
|
+
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).`);
|
|
5567
|
+
}, [unsortable]);
|
|
5568
|
+
useEffect(() => {
|
|
5569
|
+
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).`);
|
|
5570
|
+
}, [pager, data.length]);
|
|
5571
|
+
const rangeStart = pager ? pager.range[0] : null;
|
|
5572
|
+
const rangeEnd2 = pager ? pager.range[1] : null;
|
|
5573
|
+
const drawn = useMemo(
|
|
5574
|
+
() => rangeStart === null ? sortedAll : rangeStart === 0 ? [] : sortedAll.slice(rangeStart - 1, rangeEnd2 ?? void 0),
|
|
5575
|
+
[sortedAll, rangeStart, rangeEnd2]
|
|
5576
|
+
);
|
|
5577
|
+
const drawnStart = rangeStart ? rangeStart - 1 : 0;
|
|
6328
5578
|
const selectedSet = new Set(selectedRows);
|
|
6329
|
-
const
|
|
6330
|
-
const
|
|
5579
|
+
const drawnIdx = drawn.map((d) => d.originalIdx);
|
|
5580
|
+
const allSelected = drawnIdx.length > 0 && drawnIdx.every((i) => selectedSet.has(i));
|
|
5581
|
+
const someSelected = !allSelected && drawnIdx.some((i) => selectedSet.has(i));
|
|
6331
5582
|
const toggleAll = () => {
|
|
6332
|
-
|
|
6333
|
-
|
|
5583
|
+
const shown = new Set(drawnIdx);
|
|
5584
|
+
if (allSelected) onSelectionChange?.(selectedRows.filter((r) => !shown.has(r)));
|
|
5585
|
+
else onSelectionChange?.([...selectedRows.filter((r) => !shown.has(r)), ...drawnIdx]);
|
|
6334
5586
|
};
|
|
6335
5587
|
const toggleRow = (idx) => {
|
|
6336
5588
|
if (selectedSet.has(idx)) onSelectionChange?.(selectedRows.filter((r) => r !== idx));
|
|
6337
5589
|
else onSelectionChange?.([...selectedRows, idx]);
|
|
6338
5590
|
};
|
|
6339
|
-
const
|
|
6340
|
-
|
|
6341
|
-
|
|
6342
|
-
|
|
6343
|
-
|
|
6344
|
-
|
|
6345
|
-
});
|
|
5591
|
+
const expandControlled = expandedRowsProp !== void 0;
|
|
5592
|
+
const [ownExpanded, setOwnExpanded] = useState(defaultExpandedRows ?? []);
|
|
5593
|
+
const expanded = expandControlled ? expandedRowsProp : ownExpanded;
|
|
5594
|
+
const expandedSet = new Set(expanded.map(String));
|
|
5595
|
+
const { ids: rowIds, repeated } = useMemo(() => rowIdsOf(data, rowKey), [data, rowKey]);
|
|
5596
|
+
useEffect(() => {
|
|
5597
|
+
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.`);
|
|
5598
|
+
}, [repeated, rowKey]);
|
|
5599
|
+
const idOf = (_row, index) => rowIds[index] ?? index;
|
|
5600
|
+
const marksOf = (row, index) => rowMarks(row, index, rowKey, idOf(row, index));
|
|
5601
|
+
const openedHere = useRef(null);
|
|
5602
|
+
const toggleExpand = (id) => {
|
|
5603
|
+
const opening = !expandedSet.has(String(id));
|
|
5604
|
+
const next = opening ? [...expanded, id] : expanded.filter((x) => String(x) !== String(id));
|
|
5605
|
+
openedHere.current = opening ? String(id) : null;
|
|
5606
|
+
if (!expandControlled) setOwnExpanded(next);
|
|
5607
|
+
onExpandedChange?.(next);
|
|
6346
5608
|
};
|
|
6347
|
-
const
|
|
6348
|
-
const inferredKinds = useMemo(() => inferColumnKinds(data, columnKeys), [data, columnKeys]);
|
|
6349
|
-
const kindOf = useCallback(
|
|
6350
|
-
(col) => col.kind ?? inferredKinds.get(col.key),
|
|
6351
|
-
[inferredKinds]
|
|
6352
|
-
);
|
|
5609
|
+
const canOpenByClick = !!expandable && !!renderExpanded && !onRowClick;
|
|
6353
5610
|
const preferences = useShellPreferences();
|
|
6354
5611
|
const mobileBreakpoint = mobileBreakpointProp ?? preferences.tableToCardsBreakpoint ?? "md";
|
|
6355
|
-
const
|
|
6356
|
-
const {
|
|
5612
|
+
const narrowScreen = useBreakpoint(mobileBreakpoint);
|
|
5613
|
+
const { cards: isMobile, rootRef } = useCardsSwitch(narrowScreen, cardsBelow, title);
|
|
5614
|
+
const setRoot = useCallback((node) => {
|
|
5615
|
+
rootRef.current = node;
|
|
5616
|
+
if (typeof ref === "function") ref(node);
|
|
5617
|
+
else if (ref) ref.current = node;
|
|
5618
|
+
}, [ref, rootRef]);
|
|
5619
|
+
const tableRef = useRef(null);
|
|
5620
|
+
const [pins, setPins] = useState(NO_PINS);
|
|
5621
|
+
const lead = (selectable ? 1 : 0) + (expandable ? 1 : 0);
|
|
5622
|
+
const endCount = columns.filter((c) => c.pin === "end").length;
|
|
5623
|
+
const nameIndex = columns.length > endCount ? lead : -1;
|
|
5624
|
+
const { ref: scrollRef, elRef: scrollEl, measure: measureScroll, scrollable, edges, fadeProps } = useScrollEdges({
|
|
5625
|
+
enabled: !isMobile,
|
|
5626
|
+
noFade: { left: lead + (pins.nameFits ? 1 : 0) > 0, right: endCount > 0 }
|
|
5627
|
+
});
|
|
6357
5628
|
const [regionFocused, setRegionFocused] = useState(false);
|
|
5629
|
+
useLayoutEffect(() => {
|
|
5630
|
+
const table2 = tableRef.current;
|
|
5631
|
+
const scroller = scrollEl.current;
|
|
5632
|
+
if (!table2 || !scroller || isMobile) return;
|
|
5633
|
+
const measure = () => {
|
|
5634
|
+
const cells = Array.from(table2.querySelectorAll(":scope > thead > tr > th"));
|
|
5635
|
+
if (!cells.length) return;
|
|
5636
|
+
const widths = cells.map((c) => c.getBoundingClientRect().width);
|
|
5637
|
+
if (!widths.some((w) => w > 0)) return;
|
|
5638
|
+
const start = [];
|
|
5639
|
+
let at = 0;
|
|
5640
|
+
for (let i = 0; i < lead; i++) {
|
|
5641
|
+
start.push(at);
|
|
5642
|
+
at += widths[i] ?? 0;
|
|
5643
|
+
}
|
|
5644
|
+
const nameWidth = nameIndex >= 0 ? widths[nameIndex] ?? 0 : 0;
|
|
5645
|
+
const end = [];
|
|
5646
|
+
let fromRight = 0;
|
|
5647
|
+
for (let i = cells.length - 1; i >= cells.length - endCount; i--) {
|
|
5648
|
+
end.unshift(fromRight);
|
|
5649
|
+
fromRight += widths[i] ?? 0;
|
|
5650
|
+
}
|
|
5651
|
+
const frame = scroller.clientWidth;
|
|
5652
|
+
const nameFits = nameIndex >= 0 && frame > 0 && at + nameWidth + fromRight <= frame / 2;
|
|
5653
|
+
if (nameFits) start.push(at);
|
|
5654
|
+
const pad3 = (cell, side) => cell ? parseFloat(getComputedStyle(cell)[side]) || 0 : 0;
|
|
5655
|
+
const panel = cells.length > lead ? [at + pad3(cells[lead], "paddingLeft"), pad3(cells[cells.length - 1], "paddingRight")] : null;
|
|
5656
|
+
const next = { start, end, nameFits, frame, panel };
|
|
5657
|
+
setPins((prev) => samePins(prev, next) ? prev : next);
|
|
5658
|
+
};
|
|
5659
|
+
measure();
|
|
5660
|
+
if (typeof ResizeObserver === "undefined") return;
|
|
5661
|
+
const observer = new ResizeObserver(measure);
|
|
5662
|
+
observer.observe(table2);
|
|
5663
|
+
observer.observe(scroller);
|
|
5664
|
+
return () => observer.disconnect();
|
|
5665
|
+
}, [isMobile, lead, endCount, nameIndex, scrollEl, columns, drawn.length]);
|
|
5666
|
+
const pinnedStart = lead + (pins.nameFits ? 1 : 0);
|
|
5667
|
+
const pinStyle = (position, total) => {
|
|
5668
|
+
if (position < pinnedStart && pins.start[position] !== void 0) {
|
|
5669
|
+
const inner = position === pinnedStart - 1;
|
|
5670
|
+
return { position: "sticky", left: pins.start[position], zIndex: 1, background: PINNED_BACKGROUND, boxShadow: inner && edges.left ? `6px 0 6px -6px ${PIN_SHADOW}` : void 0 };
|
|
5671
|
+
}
|
|
5672
|
+
const fromEnd = total - 1 - position;
|
|
5673
|
+
if (fromEnd < endCount && pins.end[endCount - 1 - fromEnd] !== void 0) {
|
|
5674
|
+
const inner = fromEnd === endCount - 1;
|
|
5675
|
+
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 };
|
|
5676
|
+
}
|
|
5677
|
+
return void 0;
|
|
5678
|
+
};
|
|
5679
|
+
const fade = fadeProps;
|
|
5680
|
+
const [renderedKinds, setRenderedKinds] = useState(() => /* @__PURE__ */ new Map());
|
|
5681
|
+
useLayoutEffect(() => {
|
|
5682
|
+
const table2 = tableRef.current;
|
|
5683
|
+
if (!table2 || isMobile) return;
|
|
5684
|
+
const next = /* @__PURE__ */ new Map();
|
|
5685
|
+
for (const col of columns) {
|
|
5686
|
+
if (kindOf(col)) continue;
|
|
5687
|
+
const texts = Array.from(table2.querySelectorAll(`:scope > tbody > tr > td[data-col="${CSS.escape(col.key)}"]`)).slice(0, 50).map((td) => td.textContent ?? "");
|
|
5688
|
+
const kind = texts.length ? kindOfRenderedText(texts) : void 0;
|
|
5689
|
+
if (kind) next.set(col.key, kind);
|
|
5690
|
+
}
|
|
5691
|
+
setRenderedKinds((prev) => prev.size === next.size && [...next].every(([k, v]) => prev.get(k) === v) ? prev : next);
|
|
5692
|
+
}, [columns, kindOf, drawn, isMobile]);
|
|
5693
|
+
const expandedKey = expanded.map(String).join("");
|
|
5694
|
+
const shownBefore = useRef(/* @__PURE__ */ new Set());
|
|
5695
|
+
const pendingScroll = useRef(null);
|
|
5696
|
+
const scrollToRow = useCallback((key) => {
|
|
5697
|
+
const row = rootRef.current?.querySelector(`[data-row-key="${CSS.escape(key)}"], [data-row-index="${CSS.escape(key)}"]`);
|
|
5698
|
+
if (row && typeof row.scrollIntoView === "function") row.scrollIntoView({ block: "nearest" });
|
|
5699
|
+
}, [rootRef]);
|
|
5700
|
+
useEffect(() => {
|
|
5701
|
+
const now = new Set(expanded.map(String));
|
|
5702
|
+
const added = [...now].filter((k) => !shownBefore.current.has(k) && k !== openedHere.current);
|
|
5703
|
+
shownBefore.current = now;
|
|
5704
|
+
openedHere.current = null;
|
|
5705
|
+
if (!expandControlled) return;
|
|
5706
|
+
const key = added[added.length - 1];
|
|
5707
|
+
if (key === void 0) return;
|
|
5708
|
+
if (pager) {
|
|
5709
|
+
const position = sortedAll.findIndex((r) => String(idOf(r.row, r.originalIdx)) === key);
|
|
5710
|
+
if (position >= 0 && (position < drawnStart || position >= drawnStart + drawn.length)) {
|
|
5711
|
+
pendingScroll.current = key;
|
|
5712
|
+
pager.setPage(Math.floor(position / pager.pageSize) + 1);
|
|
5713
|
+
return;
|
|
5714
|
+
}
|
|
5715
|
+
}
|
|
5716
|
+
scrollToRow(key);
|
|
5717
|
+
}, [expandedKey]);
|
|
5718
|
+
useEffect(() => {
|
|
5719
|
+
const key = pendingScroll.current;
|
|
5720
|
+
if (!key || !drawn.some((r) => String(idOf(r.row, r.originalIdx)) === key)) return;
|
|
5721
|
+
pendingScroll.current = null;
|
|
5722
|
+
scrollToRow(key);
|
|
5723
|
+
}, [drawnStart, drawn.length, scrollToRow]);
|
|
6358
5724
|
const cardHeading = title ? /* @__PURE__ */ jsx(TableHeading, { title, description, actions, titleId, descriptionId, inset: false }) : null;
|
|
6359
|
-
const titledCards = (body) => /* @__PURE__ */ jsxs("div", { ref, "data-ds-list": "", "data-gs": "table", className: cn("flex flex-col",
|
|
5725
|
+
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: [
|
|
6360
5726
|
cardHeading,
|
|
6361
5727
|
body
|
|
6362
5728
|
] });
|
|
5729
|
+
const control = pager && !loading && data.length > 0 ? /* @__PURE__ */ jsx(Pagination, { ...pager.props }) : null;
|
|
5730
|
+
const listRoot = control ? void 0 : setRoot;
|
|
5731
|
+
const listClass = control ? void 0 : className;
|
|
5732
|
+
const withControl = (list) => control ? /* @__PURE__ */ jsxs("div", { ref: setRoot, "data-gs-paged": "", className: cn("flex flex-col min-w-0", className), children: [
|
|
5733
|
+
list,
|
|
5734
|
+
control
|
|
5735
|
+
] }) : list;
|
|
5736
|
+
const focusWas = useRef(null);
|
|
5737
|
+
const noteFocus = (e) => {
|
|
5738
|
+
const target = e.target;
|
|
5739
|
+
const row = target.closest("[data-row-key], [data-row-index]");
|
|
5740
|
+
if (!row) {
|
|
5741
|
+
focusWas.current = null;
|
|
5742
|
+
return;
|
|
5743
|
+
}
|
|
5744
|
+
const control2 = target === row ? null : target.getAttribute("aria-labelledby") ?? target.getAttribute("aria-label") ?? target.textContent;
|
|
5745
|
+
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 };
|
|
5746
|
+
};
|
|
5747
|
+
const forgetFocus = (e) => {
|
|
5748
|
+
const node = e.target;
|
|
5749
|
+
queueMicrotask(() => {
|
|
5750
|
+
if (node.isConnected && !rootRef.current?.contains(document.activeElement)) focusWas.current = null;
|
|
5751
|
+
});
|
|
5752
|
+
};
|
|
5753
|
+
useLayoutEffect(() => {
|
|
5754
|
+
const was = focusWas.current;
|
|
5755
|
+
const active = document.activeElement;
|
|
5756
|
+
if (!was || active && active !== document.body) return;
|
|
5757
|
+
const row = rootRef.current?.querySelector(was.row);
|
|
5758
|
+
if (!row) return;
|
|
5759
|
+
const controls = Array.from(row.querySelectorAll(FOCUSABLE));
|
|
5760
|
+
const same = was.control === null ? null : controls.find((el) => (el.getAttribute("aria-labelledby") ?? el.getAttribute("aria-label") ?? el.textContent) === was.control);
|
|
5761
|
+
(same ?? (row.tabIndex >= 0 ? row : controls[0]))?.focus({ preventScroll: true });
|
|
5762
|
+
}, [isMobile, rootRef]);
|
|
6363
5763
|
if (isMobile) {
|
|
6364
5764
|
if (loading) {
|
|
6365
5765
|
if (title) return titledCards(/* @__PURE__ */ jsx("div", { className: "flex items-center justify-center py-ds-10", children: /* @__PURE__ */ jsx(Spinner, { label: "Loading table data" }) }));
|
|
6366
|
-
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" }) });
|
|
5766
|
+
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" }) });
|
|
6367
5767
|
}
|
|
6368
5768
|
if (data.length === 0 && emptyState) {
|
|
6369
5769
|
if (title) return titledCards(/* @__PURE__ */ jsx("div", { className: "py-ds-10 text-center text-sm text-[var(--ds-text-muted)]", children: emptyState }));
|
|
6370
|
-
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 });
|
|
5770
|
+
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 });
|
|
6371
5771
|
}
|
|
6372
|
-
const cards = /* @__PURE__ */ jsx(TableCardCtx, { value: true, children: /* @__PURE__ */
|
|
6373
|
-
|
|
6374
|
-
|
|
6375
|
-
|
|
6376
|
-
|
|
6377
|
-
|
|
6378
|
-
|
|
6379
|
-
|
|
6380
|
-
"
|
|
6381
|
-
|
|
6382
|
-
|
|
6383
|
-
|
|
6384
|
-
|
|
6385
|
-
|
|
6386
|
-
|
|
6387
|
-
|
|
6388
|
-
|
|
6389
|
-
|
|
6390
|
-
e
|
|
6391
|
-
|
|
6392
|
-
|
|
6393
|
-
|
|
6394
|
-
|
|
6395
|
-
|
|
6396
|
-
|
|
6397
|
-
|
|
6398
|
-
|
|
6399
|
-
|
|
6400
|
-
|
|
6401
|
-
|
|
6402
|
-
|
|
6403
|
-
|
|
6404
|
-
|
|
6405
|
-
|
|
6406
|
-
|
|
5772
|
+
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: [
|
|
5773
|
+
selectable && /* @__PURE__ */ jsx("span", { hidden: true, id: `${headingId}-select`, children: "Select" }),
|
|
5774
|
+
drawn.map(({ row, originalIdx }) => {
|
|
5775
|
+
const isSelected = selectedSet.has(originalIdx);
|
|
5776
|
+
const id = idOf(row, originalIdx);
|
|
5777
|
+
return /* @__PURE__ */ jsxs(
|
|
5778
|
+
"div",
|
|
5779
|
+
{
|
|
5780
|
+
"data-row": "",
|
|
5781
|
+
...marksOf(row, originalIdx),
|
|
5782
|
+
className: cn(
|
|
5783
|
+
"border-[length:var(--ds-border-width)] border-[var(--ds-border-subtle)]",
|
|
5784
|
+
"rounded-[var(--ds-radius-md)] bg-[var(--ds-bg-surface)]",
|
|
5785
|
+
"p-ds-4 space-y-ds-3",
|
|
5786
|
+
isSelected && ACTIVE_RING,
|
|
5787
|
+
onRowClick && "cursor-pointer hover:bg-[var(--ds-bg-muted)] focus-visible:outline-none focus-visible:shadow-[var(--ds-shadow-focus)]"
|
|
5788
|
+
),
|
|
5789
|
+
onClick: onRowClick ? (e) => {
|
|
5790
|
+
if (clickIsRows(e)) onRowClick(row, originalIdx);
|
|
5791
|
+
} : void 0,
|
|
5792
|
+
tabIndex: onRowClick ? 0 : void 0,
|
|
5793
|
+
onKeyDown: onRowClick ? (e) => {
|
|
5794
|
+
if (e.target !== e.currentTarget) return;
|
|
5795
|
+
if (e.key === "Enter" || e.key === " ") {
|
|
5796
|
+
e.preventDefault();
|
|
5797
|
+
onRowClick(row, originalIdx);
|
|
5798
|
+
}
|
|
5799
|
+
} : void 0,
|
|
5800
|
+
children: [
|
|
5801
|
+
selectable && // "Select" and the row's name, as in the table (T15)
|
|
5802
|
+
/* @__PURE__ */ jsx(Checkbox, { checked: isSelected, onChange: () => toggleRow(originalIdx), "aria-labelledby": nameIndex >= 0 ? `${headingId}-select ${headingId}-card-name-${idPart(id)}` : `${headingId}-select` }),
|
|
5803
|
+
columns.map((col, c) => /* @__PURE__ */ jsxs("div", { className: "flex justify-between gap-ds-2 text-sm", children: [
|
|
5804
|
+
/* @__PURE__ */ jsx("span", { className: "shrink-0 text-[var(--ds-text-secondary)] font-medium text-xs uppercase tracking-wider", children: col.header }),
|
|
5805
|
+
/* @__PURE__ */ jsx(CardValue, { value: row[col.key], id: lead + c === nameIndex ? `${headingId}-card-name-${idPart(id)}` : void 0 })
|
|
5806
|
+
] }, col.key)),
|
|
5807
|
+
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: /* @__PURE__ */ jsx(PanelContent, { children: renderExpanded(row, originalIdx) }) })
|
|
5808
|
+
]
|
|
5809
|
+
},
|
|
5810
|
+
String(id)
|
|
5811
|
+
);
|
|
5812
|
+
})
|
|
5813
|
+
] }) });
|
|
5814
|
+
return withControl(title ? titledCards(cards) : cards);
|
|
6407
5815
|
}
|
|
6408
|
-
const
|
|
6409
|
-
|
|
6410
|
-
|
|
5816
|
+
const cellCount = columns.length + lead;
|
|
5817
|
+
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: [
|
|
5818
|
+
/* @__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: [
|
|
5819
|
+
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(
|
|
6411
5820
|
Checkbox,
|
|
6412
5821
|
{
|
|
6413
5822
|
checked: allSelected,
|
|
6414
5823
|
indeterminate: someSelected,
|
|
6415
|
-
onChange: toggleAll
|
|
5824
|
+
onChange: toggleAll,
|
|
5825
|
+
"aria-labelledby": `${headingId}-select-all`
|
|
6416
5826
|
}
|
|
6417
5827
|
) }),
|
|
6418
|
-
expandable && /* @__PURE__ */ jsx("th", { className: cn("w-8", density === "compact" ? "px-ds-1 py-ds-2" : "px-ds-2 py-ds-3") }),
|
|
6419
|
-
columns.map((col) => {
|
|
6420
|
-
const isSortable = sortable
|
|
6421
|
-
const isActiveSort = sortKey === col.key;
|
|
5828
|
+
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) }),
|
|
5829
|
+
columns.map((col, c) => {
|
|
5830
|
+
const isSortable = col.header.trim() !== "" && (col.sortable ?? (!!sortable && canSort.has(col.key)));
|
|
5831
|
+
const isActiveSort = sortKey === col.key && !!sortDir && unsortable !== col.key;
|
|
6422
5832
|
const headerKind = kindOf(col);
|
|
6423
5833
|
const headerAlign = col.align ?? (headerKind === "number" ? "right" : "left");
|
|
6424
5834
|
const shrink = (headerKind === "number" || headerKind === "date") && !col.maxWidth;
|
|
5835
|
+
const style = { maxWidth: col.maxWidth, width: col.width, minWidth: col.minWidth, ...pinStyle(lead + c, cellCount) };
|
|
6425
5836
|
return /* @__PURE__ */ jsx(
|
|
6426
5837
|
"th",
|
|
6427
5838
|
{
|
|
5839
|
+
"aria-sort": isSortable && isActiveSort ? sortDir === "asc" ? "ascending" : "descending" : void 0,
|
|
6428
5840
|
className: cn(
|
|
6429
5841
|
density === "compact" ? "px-ds-3 py-ds-2" : "px-ds-4 py-ds-3",
|
|
6430
5842
|
shrink && "w-px whitespace-nowrap",
|
|
6431
5843
|
"font-[var(--ds-weight-heading)] text-[var(--ds-text-secondary)]",
|
|
6432
5844
|
"text-xs uppercase tracking-wider",
|
|
6433
|
-
headerAlign === "right" ? "text-right" : headerAlign === "center" ? "text-center" : "text-left"
|
|
6434
|
-
isSortable && "cursor-pointer select-none hover:text-[var(--ds-text-primary)]"
|
|
5845
|
+
headerAlign === "right" ? "text-right" : headerAlign === "center" ? "text-center" : "text-left"
|
|
6435
5846
|
),
|
|
6436
|
-
style
|
|
6437
|
-
|
|
6438
|
-
|
|
6439
|
-
|
|
6440
|
-
|
|
6441
|
-
Icon,
|
|
5847
|
+
style,
|
|
5848
|
+
children: isSortable ? (
|
|
5849
|
+
// A47: a button with the column's name, reached with Tab and pressed with Enter or Space
|
|
5850
|
+
/* @__PURE__ */ jsxs(
|
|
5851
|
+
"button",
|
|
6442
5852
|
{
|
|
6443
|
-
|
|
6444
|
-
|
|
5853
|
+
type: "button",
|
|
5854
|
+
onClick: () => handleSort(col.key),
|
|
6445
5855
|
className: cn(
|
|
6446
|
-
"
|
|
6447
|
-
|
|
6448
|
-
|
|
5856
|
+
"inline-flex items-center gap-ds-1 uppercase tracking-wider cursor-pointer select-none",
|
|
5857
|
+
"[font:inherit] text-inherit hover:text-[var(--ds-text-primary)]",
|
|
5858
|
+
"rounded-[var(--ds-radius-sm)] focus-visible:outline-none focus-visible:shadow-[var(--ds-shadow-focus)]"
|
|
5859
|
+
),
|
|
5860
|
+
children: [
|
|
5861
|
+
col.header,
|
|
5862
|
+
/* @__PURE__ */ jsx(
|
|
5863
|
+
Icon,
|
|
5864
|
+
{
|
|
5865
|
+
name: "chevron-right",
|
|
5866
|
+
size: 12,
|
|
5867
|
+
className: cn(
|
|
5868
|
+
"transition-transform",
|
|
5869
|
+
!isActiveSort ? "invisible" : sortDir === "asc" ? "-rotate-90" : "rotate-90"
|
|
5870
|
+
)
|
|
5871
|
+
}
|
|
5872
|
+
)
|
|
5873
|
+
]
|
|
6449
5874
|
}
|
|
6450
5875
|
)
|
|
6451
|
-
|
|
5876
|
+
) : /* @__PURE__ */ jsx("span", { className: "inline-flex items-center gap-ds-1", children: col.header })
|
|
6452
5877
|
},
|
|
6453
5878
|
col.key
|
|
6454
5879
|
);
|
|
@@ -6457,31 +5882,45 @@ function Table({
|
|
|
6457
5882
|
/* @__PURE__ */ jsx("tbody", { children: loading ? /* @__PURE__ */ jsx("tr", { children: /* @__PURE__ */ jsx(
|
|
6458
5883
|
"td",
|
|
6459
5884
|
{
|
|
6460
|
-
colSpan:
|
|
5885
|
+
colSpan: cellCount,
|
|
6461
5886
|
className: "px-ds-4 py-ds-10 text-center",
|
|
6462
5887
|
children: /* @__PURE__ */ jsx(Spinner, { label: "Loading table data" })
|
|
6463
5888
|
}
|
|
6464
5889
|
) }) : data.length === 0 && emptyState ? /* @__PURE__ */ jsx("tr", { children: /* @__PURE__ */ jsx(
|
|
6465
5890
|
"td",
|
|
6466
5891
|
{
|
|
6467
|
-
colSpan:
|
|
5892
|
+
colSpan: cellCount,
|
|
6468
5893
|
className: "px-ds-4 py-ds-10 text-center text-sm text-[var(--ds-text-muted)]",
|
|
6469
5894
|
children: emptyState
|
|
6470
5895
|
}
|
|
6471
|
-
) }) :
|
|
5896
|
+
) }) : drawn.map(({ row, originalIdx }, i) => {
|
|
6472
5897
|
const isSelected = selectedSet.has(originalIdx);
|
|
6473
|
-
const
|
|
5898
|
+
const id = idOf(row, originalIdx);
|
|
5899
|
+
const isExpanded = expandedSet.has(String(id));
|
|
5900
|
+
const clickable = !!onRowClick || canOpenByClick;
|
|
6474
5901
|
return /* @__PURE__ */ jsxs(Fragment$1, { children: [
|
|
6475
5902
|
/* @__PURE__ */ jsxs(
|
|
6476
5903
|
"tr",
|
|
6477
5904
|
{
|
|
5905
|
+
...marksOf(row, originalIdx),
|
|
6478
5906
|
className: cn(
|
|
6479
|
-
|
|
6480
|
-
"
|
|
6481
|
-
|
|
6482
|
-
|
|
5907
|
+
// an opened row's divider is under its panel (A6)
|
|
5908
|
+
!(expandable && isExpanded && renderExpanded) && "border-b-[length:var(--ds-divider-width)] border-[var(--ds-border-subtle)] last:border-b-0",
|
|
5909
|
+
// the row's background and its tint change together, so its pinned cells and the rest fade as one
|
|
5910
|
+
// (roots.css registers --gs-row-tint as a colour so it can)
|
|
5911
|
+
"transition-[background-color,--gs-row-tint]",
|
|
5912
|
+
// the row's tint, as a variable too, so its pinned cells draw it over their solid ground (A35)
|
|
5913
|
+
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)]",
|
|
5914
|
+
clickable && "cursor-pointer",
|
|
5915
|
+
// an outline inside the row: it shows over the pinned cells, whose solid ground hid the inset
|
|
5916
|
+
// shadow the row drew before (the review of 30 September)
|
|
5917
|
+
onRowClick && "focus-visible:outline-2 focus-visible:-outline-offset-2 focus-visible:outline-[var(--ds-border-focus)]"
|
|
6483
5918
|
),
|
|
6484
|
-
onClick:
|
|
5919
|
+
onClick: clickable ? (e) => {
|
|
5920
|
+
if (!clickIsRows(e)) return;
|
|
5921
|
+
if (onRowClick) onRowClick(row, originalIdx);
|
|
5922
|
+
else toggleExpand(id);
|
|
5923
|
+
} : void 0,
|
|
6485
5924
|
tabIndex: onRowClick ? 0 : void 0,
|
|
6486
5925
|
onKeyDown: onRowClick ? (e) => {
|
|
6487
5926
|
if (e.target !== e.currentTarget) return;
|
|
@@ -6491,15 +5930,15 @@ function Table({
|
|
|
6491
5930
|
}
|
|
6492
5931
|
} : void 0,
|
|
6493
5932
|
children: [
|
|
6494
|
-
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) }) }),
|
|
6495
|
-
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(
|
|
5933
|
+
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` }) }),
|
|
5934
|
+
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(
|
|
6496
5935
|
"button",
|
|
6497
5936
|
{
|
|
6498
5937
|
type: "button",
|
|
6499
|
-
onClick: () => toggleExpand(
|
|
5938
|
+
onClick: () => toggleExpand(id),
|
|
6500
5939
|
className: "text-[var(--ds-text-muted)] hover:text-[var(--ds-text-primary)] cursor-pointer",
|
|
6501
5940
|
"aria-expanded": isExpanded,
|
|
6502
|
-
"aria-label": "
|
|
5941
|
+
...nameIndex >= 0 ? { "aria-labelledby": `${headingId}-details ${headingId}-name-${idPart(id)}` } : { "aria-label": "Details" },
|
|
6503
5942
|
children: /* @__PURE__ */ jsx(
|
|
6504
5943
|
Icon,
|
|
6505
5944
|
{
|
|
@@ -6510,12 +5949,13 @@ function Table({
|
|
|
6510
5949
|
)
|
|
6511
5950
|
}
|
|
6512
5951
|
) }),
|
|
6513
|
-
columns.map((col) => {
|
|
5952
|
+
columns.map((col, c) => {
|
|
6514
5953
|
const truncLines = col.truncate === true ? 1 : col.truncate ? col.truncate.lines : 0;
|
|
6515
5954
|
const kind = kindOf(col);
|
|
6516
5955
|
const alignClass = col.align ? col.align === "right" ? "text-right" : col.align === "center" ? "text-center" : "text-left" : kind === "number" ? "text-right" : "text-left";
|
|
6517
5956
|
const cellContent = row[col.key];
|
|
6518
5957
|
const shrink = (kind === "number" || kind === "date") && !col.maxWidth;
|
|
5958
|
+
const whole = !kind && renderedKinds.has(col.key);
|
|
6519
5959
|
let inner;
|
|
6520
5960
|
if (truncLines > 0) {
|
|
6521
5961
|
inner = /* @__PURE__ */ jsx(TruncCell, { lines: truncLines, children: cellContent });
|
|
@@ -6531,13 +5971,17 @@ function Table({
|
|
|
6531
5971
|
return /* @__PURE__ */ jsx(
|
|
6532
5972
|
"td",
|
|
6533
5973
|
{
|
|
5974
|
+
id: lead > 0 && lead + c === nameIndex ? `${headingId}-name-${idPart(id)}` : void 0,
|
|
5975
|
+
"data-col": col.key,
|
|
6534
5976
|
className: cn(
|
|
6535
5977
|
density === "compact" ? "px-ds-3 py-ds-2" : "px-ds-4 py-ds-3",
|
|
6536
5978
|
"text-[var(--ds-text-primary)]",
|
|
6537
5979
|
alignClass,
|
|
6538
|
-
shrink && "w-px whitespace-nowrap"
|
|
5980
|
+
shrink && "w-px whitespace-nowrap",
|
|
5981
|
+
whole && "whitespace-nowrap",
|
|
5982
|
+
kind === "identifier" && "[overflow-wrap:anywhere]"
|
|
6539
5983
|
),
|
|
6540
|
-
style: col.maxWidth || col.width || col.minWidth ? { maxWidth: col.maxWidth, width: col.width, minWidth: col.minWidth } : void 0,
|
|
5984
|
+
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,
|
|
6541
5985
|
children: inner
|
|
6542
5986
|
},
|
|
6543
5987
|
col.key
|
|
@@ -6546,53 +5990,69 @@ function Table({
|
|
|
6546
5990
|
]
|
|
6547
5991
|
}
|
|
6548
5992
|
),
|
|
6549
|
-
expandable && isExpanded && renderExpanded && /* @__PURE__ */ jsx("tr", { children: /* @__PURE__ */ jsx(
|
|
5993
|
+
expandable && isExpanded && renderExpanded && /* @__PURE__ */ jsx("tr", { className: "border-b-[length:var(--ds-divider-width)] border-[var(--ds-border-subtle)] last:border-b-0", children: /* @__PURE__ */ jsx(
|
|
6550
5994
|
"td",
|
|
6551
5995
|
{
|
|
6552
|
-
colSpan:
|
|
6553
|
-
className: "
|
|
6554
|
-
|
|
5996
|
+
colSpan: cellCount,
|
|
5997
|
+
className: cn("py-ds-4 text-sm text-[var(--ds-text-primary)]", !pins.panel && (density === "compact" ? "px-ds-3" : "px-ds-4")),
|
|
5998
|
+
style: pins.panel ? { paddingLeft: pins.panel[0], paddingRight: pins.panel[1] } : void 0,
|
|
5999
|
+
children: /* @__PURE__ */ jsx(
|
|
6000
|
+
"div",
|
|
6001
|
+
{
|
|
6002
|
+
"data-row-panel": "",
|
|
6003
|
+
className: "sticky",
|
|
6004
|
+
style: pins.panel ? { left: pins.panel[0], maxWidth: pins.frame ? pins.frame - pins.panel[0] - pins.panel[1] : void 0 } : { left: 0 },
|
|
6005
|
+
children: /* @__PURE__ */ jsx(PanelContent, { children: renderExpanded(row, originalIdx) })
|
|
6006
|
+
}
|
|
6007
|
+
)
|
|
6555
6008
|
}
|
|
6556
6009
|
) })
|
|
6557
|
-
] },
|
|
6010
|
+
] }, String(id));
|
|
6558
6011
|
}) })
|
|
6559
6012
|
] });
|
|
6560
6013
|
const region = scrollable || regionFocused ? { tabIndex: 0, role: "region", ...title ? { "aria-labelledby": titleId } : { "aria-label": ariaLabel ?? "Table" } } : {};
|
|
6561
|
-
return
|
|
6562
|
-
|
|
6563
|
-
|
|
6564
|
-
|
|
6565
|
-
|
|
6566
|
-
|
|
6567
|
-
|
|
6568
|
-
|
|
6569
|
-
|
|
6570
|
-
|
|
6571
|
-
|
|
6572
|
-
{
|
|
6573
|
-
|
|
6574
|
-
|
|
6575
|
-
|
|
6576
|
-
|
|
6577
|
-
|
|
6578
|
-
|
|
6579
|
-
|
|
6580
|
-
|
|
6581
|
-
|
|
6582
|
-
|
|
6583
|
-
|
|
6584
|
-
|
|
6585
|
-
|
|
6586
|
-
|
|
6587
|
-
|
|
6588
|
-
|
|
6589
|
-
|
|
6014
|
+
return withControl(
|
|
6015
|
+
/* @__PURE__ */ jsxs(
|
|
6016
|
+
"div",
|
|
6017
|
+
{
|
|
6018
|
+
ref: listRoot,
|
|
6019
|
+
"data-ds-list": "",
|
|
6020
|
+
"data-gs": "table",
|
|
6021
|
+
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),
|
|
6022
|
+
onFocus: noteFocus,
|
|
6023
|
+
onBlur: forgetFocus,
|
|
6024
|
+
children: [
|
|
6025
|
+
title && /* @__PURE__ */ jsx(TableHeading, { title, description, actions, titleId, descriptionId, inset: true }),
|
|
6026
|
+
selectable && /* @__PURE__ */ jsx("span", { hidden: true, id: `${headingId}-select-all`, children: "Select all rows shown" }),
|
|
6027
|
+
selectable && /* @__PURE__ */ jsx("span", { hidden: true, id: `${headingId}-select`, children: "Select" }),
|
|
6028
|
+
expandable && /* @__PURE__ */ jsx("span", { hidden: true, id: `${headingId}-details`, children: "Details" }),
|
|
6029
|
+
/* @__PURE__ */ jsx(
|
|
6030
|
+
"div",
|
|
6031
|
+
{
|
|
6032
|
+
ref: scrollRef,
|
|
6033
|
+
"data-table-scroll": "",
|
|
6034
|
+
onScroll: measureScroll,
|
|
6035
|
+
onFocus: (e) => {
|
|
6036
|
+
if (e.target === e.currentTarget) setRegionFocused(true);
|
|
6037
|
+
},
|
|
6038
|
+
onBlur: (e) => {
|
|
6039
|
+
if (e.target === e.currentTarget) setRegionFocused(false);
|
|
6040
|
+
},
|
|
6041
|
+
...fade,
|
|
6042
|
+
...region,
|
|
6043
|
+
className: cn("min-h-0 overflow-x-auto focus-visible:outline-none", title ? "rounded-b-[inherit]" : "rounded-[inherit]"),
|
|
6044
|
+
children: table
|
|
6045
|
+
}
|
|
6046
|
+
)
|
|
6047
|
+
]
|
|
6048
|
+
}
|
|
6049
|
+
)
|
|
6590
6050
|
);
|
|
6591
6051
|
}
|
|
6592
6052
|
function optionsKeyForFit(options) {
|
|
6593
6053
|
return options.map((o) => `${o.value}:${o.label}`).join("|");
|
|
6594
6054
|
}
|
|
6595
|
-
var
|
|
6055
|
+
var sizes2 = {
|
|
6596
6056
|
xs: "text-xs px-ds-2",
|
|
6597
6057
|
sm: "text-xs px-ds-3",
|
|
6598
6058
|
md: "text-sm px-ds-3",
|
|
@@ -6745,12 +6205,15 @@ function SegmentedControl({
|
|
|
6745
6205
|
onKeyDown: handleKeyDown,
|
|
6746
6206
|
className: cn(
|
|
6747
6207
|
"relative items-center",
|
|
6748
|
-
|
|
6208
|
+
// Sprint 25.14 A21: in a Field's column a track that isn't full width keeps its own width; w-fit, not self-start,
|
|
6209
|
+
// so a row or a centred column still aligns it (the review of 30 September)
|
|
6210
|
+
fullWidth ? "flex w-full" : "inline-flex w-fit",
|
|
6749
6211
|
containerPadding[size],
|
|
6750
6212
|
containerHeight[size],
|
|
6751
6213
|
"bg-[var(--ds-bg-muted)]",
|
|
6752
6214
|
"rounded-[var(--ds-radius-lg)]",
|
|
6753
|
-
|
|
6215
|
+
// Sprint 25.14 A20: the track's edge is a control's, at 3:1
|
|
6216
|
+
variant === "default" && "border-[length:var(--ds-border-width)] border-[var(--ds-input-border)]",
|
|
6754
6217
|
control.invalid && "border-[length:var(--ds-border-width)] border-[var(--ds-status-error)]",
|
|
6755
6218
|
className
|
|
6756
6219
|
),
|
|
@@ -6794,7 +6257,7 @@ function SegmentedControl({
|
|
|
6794
6257
|
"rounded-[var(--ds-radius-md)]",
|
|
6795
6258
|
"transition-colors cursor-pointer",
|
|
6796
6259
|
"focus-visible:outline-none focus-visible:shadow-[var(--ds-shadow-focus)]",
|
|
6797
|
-
|
|
6260
|
+
sizes2[size],
|
|
6798
6261
|
opt.value === value ? "text-[var(--ds-text-primary)]" : "text-[var(--ds-text-muted)] hover:text-[var(--ds-text-secondary)]",
|
|
6799
6262
|
opt.disabled && "opacity-disabled cursor-not-allowed"
|
|
6800
6263
|
),
|
|
@@ -7237,6 +6700,7 @@ function WeekView({
|
|
|
7237
6700
|
const hasAllDay = allDayEvents.some((d) => d.length > 0);
|
|
7238
6701
|
const containerRef = useRef(null);
|
|
7239
6702
|
const syncingScroll = useRef(false);
|
|
6703
|
+
const { ref: edgesRef, measure: measureEdges, fadeProps: edgeFade } = useScrollEdges();
|
|
7240
6704
|
const handleScroll = useCallback((e) => {
|
|
7241
6705
|
if (syncingScroll.current) return;
|
|
7242
6706
|
syncingScroll.current = true;
|
|
@@ -7262,7 +6726,7 @@ function WeekView({
|
|
|
7262
6726
|
return /* @__PURE__ */ jsxs("div", { ref: containerRef, className: "flex flex-col h-full overflow-hidden", children: [
|
|
7263
6727
|
/* @__PURE__ */ jsxs("div", { className: "flex border-b-[length:var(--ds-divider-width)] border-[var(--ds-border-subtle)]", children: [
|
|
7264
6728
|
/* @__PURE__ */ jsx("div", { className: "w-14 shrink-0 border-r-[length:var(--ds-divider-width)] border-[var(--ds-border-subtle)]" }),
|
|
7265
|
-
/* @__PURE__ */ jsx("div", { className: "flex-1 overflow-x-auto gs-scrollbar-none", "data-week-scroll": true, children: /* @__PURE__ */ jsx(
|
|
6729
|
+
/* @__PURE__ */ jsx("div", { ref: edgesRef, onScroll: measureEdges, ...edgeFade, className: "flex-1 overflow-x-auto gs-scrollbar-none", "data-week-scroll": true, children: /* @__PURE__ */ jsx(
|
|
7266
6730
|
"div",
|
|
7267
6731
|
{
|
|
7268
6732
|
className: "grid",
|
|
@@ -7302,7 +6766,7 @@ function WeekView({
|
|
|
7302
6766
|
] }),
|
|
7303
6767
|
hasAllDay && /* @__PURE__ */ jsxs("div", { className: "flex border-b-[length:var(--ds-divider-width)] border-[var(--ds-border-subtle)] bg-[var(--ds-bg-muted)]/30", children: [
|
|
7304
6768
|
/* @__PURE__ */ jsx("div", { className: "w-14 shrink-0 border-r-[length:var(--ds-divider-width)] border-[var(--ds-border-subtle)] text-2xs text-[var(--ds-text-muted)] px-ds-1 py-ds-1 text-right", children: "all-day" }),
|
|
7305
|
-
/* @__PURE__ */ jsx("div", { className: "flex-1 overflow-x-auto gs-scrollbar-none", "data-week-scroll": true, children: /* @__PURE__ */ jsx(
|
|
6769
|
+
/* @__PURE__ */ jsx("div", { ...edgeFade, className: "flex-1 overflow-x-auto gs-scrollbar-none", "data-week-scroll": true, children: /* @__PURE__ */ jsx(
|
|
7306
6770
|
"div",
|
|
7307
6771
|
{
|
|
7308
6772
|
className: "grid",
|
|
@@ -7339,7 +6803,7 @@ function WeekView({
|
|
|
7339
6803
|
},
|
|
7340
6804
|
h
|
|
7341
6805
|
)) }),
|
|
7342
|
-
/* @__PURE__ */ jsx("div", { className: "flex-1 overflow-x-auto gs-scrollbar-none", "data-week-scroll": true, children: /* @__PURE__ */ jsx(
|
|
6806
|
+
/* @__PURE__ */ jsx("div", { ...edgeFade, className: "flex-1 overflow-x-auto gs-scrollbar-none", "data-week-scroll": true, children: /* @__PURE__ */ jsx(
|
|
7343
6807
|
"div",
|
|
7344
6808
|
{
|
|
7345
6809
|
className: "relative",
|
|
@@ -8383,7 +7847,6 @@ function AvatarGroup({ items, max = 4, size = "sm", ring = "canvas", onOverflowC
|
|
|
8383
7847
|
alt: item.alt ?? item.name ?? initials,
|
|
8384
7848
|
initials,
|
|
8385
7849
|
size,
|
|
8386
|
-
status: item.status,
|
|
8387
7850
|
color: item.color,
|
|
8388
7851
|
className: ringClass
|
|
8389
7852
|
},
|
|
@@ -8701,7 +8164,10 @@ function VerticalLayout({ items, className }) {
|
|
|
8701
8164
|
] })
|
|
8702
8165
|
] }, i)) });
|
|
8703
8166
|
}
|
|
8704
|
-
function Timeline({ items, orientation = "vertical", minItemWidth = 200, className, ref }) {
|
|
8167
|
+
function Timeline({ items: allItems, orientation = "vertical", minItemWidth = 200, className, ref, pager }) {
|
|
8168
|
+
useScrollsInside();
|
|
8169
|
+
useWholeListCheck("Timeline", allItems.length, pager);
|
|
8170
|
+
const items = pagerPart(allItems, pager);
|
|
8705
8171
|
const measureRef = useRef(null);
|
|
8706
8172
|
const width = useElementWidth(measureRef);
|
|
8707
8173
|
const setRefs = useCallback((node) => {
|
|
@@ -8711,7 +8177,12 @@ function Timeline({ items, orientation = "vertical", minItemWidth = 200, classNa
|
|
|
8711
8177
|
}, [ref]);
|
|
8712
8178
|
const fits = width === 0 || width >= items.length * minItemWidth;
|
|
8713
8179
|
const horizontal = orientation === "horizontal" || orientation === "responsive" && fits;
|
|
8714
|
-
|
|
8180
|
+
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 }) });
|
|
8181
|
+
if (!pager) return list;
|
|
8182
|
+
return /* @__PURE__ */ jsxs("div", { "data-gs-paged": "", className: cn("flex flex-col min-w-0", className), children: [
|
|
8183
|
+
list,
|
|
8184
|
+
allItems.length > 0 && /* @__PURE__ */ jsx(Pagination, { ...pager.props })
|
|
8185
|
+
] });
|
|
8715
8186
|
}
|
|
8716
8187
|
var CollapsibleContext = createContext(null);
|
|
8717
8188
|
function useCollapsible() {
|
|
@@ -8781,12 +8252,27 @@ var Collapsible = Object.assign(CollapsibleRoot, {
|
|
|
8781
8252
|
Trigger: CollapsibleTrigger,
|
|
8782
8253
|
Content: CollapsibleContent
|
|
8783
8254
|
});
|
|
8255
|
+
var SYMBOL = /[⌘⇧⌥⌃⎋⏎↵⌫⌦⇥↑↓←→]/u;
|
|
8256
|
+
function keyParts(text) {
|
|
8257
|
+
const parts = [];
|
|
8258
|
+
let run = "";
|
|
8259
|
+
for (const ch of Array.from(text)) {
|
|
8260
|
+
if (SYMBOL.test(ch)) {
|
|
8261
|
+
if (run.trim()) parts.push(run.trim());
|
|
8262
|
+
run = "";
|
|
8263
|
+
parts.push(ch);
|
|
8264
|
+
} else run += ch;
|
|
8265
|
+
}
|
|
8266
|
+
if (run.trim()) parts.push(run.trim());
|
|
8267
|
+
return parts;
|
|
8268
|
+
}
|
|
8784
8269
|
function Kbd({ children, className }) {
|
|
8270
|
+
const parts = typeof children === "string" ? keyParts(children) : null;
|
|
8785
8271
|
return /* @__PURE__ */ jsx(
|
|
8786
8272
|
"kbd",
|
|
8787
8273
|
{
|
|
8788
8274
|
className: cn(
|
|
8789
|
-
"inline-flex items-center justify-center min-w-[2.5em] px-ds-1.5 py-ds-0.5",
|
|
8275
|
+
"inline-flex items-center justify-center gap-[0.25em] min-w-[2.5em] px-ds-1.5 py-ds-0.5",
|
|
8790
8276
|
"text-xs leading-none font-[family-name:var(--ds-font-mono)]",
|
|
8791
8277
|
"text-[var(--ds-text-secondary)]",
|
|
8792
8278
|
"bg-[var(--ds-bg-surface)]",
|
|
@@ -8795,7 +8281,7 @@ function Kbd({ children, className }) {
|
|
|
8795
8281
|
"rounded-[var(--ds-radius-sm)]",
|
|
8796
8282
|
className
|
|
8797
8283
|
),
|
|
8798
|
-
children
|
|
8284
|
+
children: parts && parts.length > 1 ? parts.map((p, i) => /* @__PURE__ */ jsx("span", { children: p }, i)) : children
|
|
8799
8285
|
}
|
|
8800
8286
|
);
|
|
8801
8287
|
}
|
|
@@ -9392,7 +8878,8 @@ function ChatInputBar({ onSend, busy, onStop, onAttach, onVoice, placeholder })
|
|
|
9392
8878
|
className: cn(
|
|
9393
8879
|
"flex flex-col",
|
|
9394
8880
|
"rounded-[var(--ds-radius-lg)]",
|
|
9395
|
-
|
|
8881
|
+
// Sprint 25.14 A20: the composer is a field, its edge at 3:1 like every other control's
|
|
8882
|
+
"border-[length:var(--ds-border-width)] border-[var(--ds-input-border)]",
|
|
9396
8883
|
"bg-[var(--ds-input-bg)]",
|
|
9397
8884
|
"shadow-[var(--ds-input-shadow)]",
|
|
9398
8885
|
FOCUS_WITHIN_RING,
|
|
@@ -9685,6 +9172,28 @@ function useCornerInset(corner, inset, priority, target) {
|
|
|
9685
9172
|
return claimCornerInset(corner, inset, priority, el);
|
|
9686
9173
|
}, [corner, inset, priority, target]);
|
|
9687
9174
|
}
|
|
9175
|
+
function Sheet({ open, onClose: onCloseProp, title, children, footer, dirty, onDiscard, snapPoints = [0.5, 0.92], container, flush, keepMounted = false, id, labelledBy }) {
|
|
9176
|
+
const { marked, mark } = useOverlayMark(open);
|
|
9177
|
+
const guard = useDirtyGuard(dirty ?? marked, onCloseProp, onDiscard);
|
|
9178
|
+
return /* @__PURE__ */ jsx(
|
|
9179
|
+
DrawerPanel,
|
|
9180
|
+
{
|
|
9181
|
+
form: "sheet",
|
|
9182
|
+
open,
|
|
9183
|
+
onClose: guard.requestClose,
|
|
9184
|
+
title,
|
|
9185
|
+
footer,
|
|
9186
|
+
container,
|
|
9187
|
+
flush,
|
|
9188
|
+
snapPoints,
|
|
9189
|
+
keepMounted,
|
|
9190
|
+
id,
|
|
9191
|
+
labelledBy,
|
|
9192
|
+
confirm: /* @__PURE__ */ jsx(DiscardConfirm, { open: guard.confirming, onKeep: guard.keep, onDiscard: guard.discard }),
|
|
9193
|
+
children: /* @__PURE__ */ jsx(DrawerFooterCtx, { value: null, children: /* @__PURE__ */ jsx(OverlayCloseCtx, { value: guard.requestClose, children: /* @__PURE__ */ jsx(OverlayMarkScope, { mark, children }) }) })
|
|
9194
|
+
}
|
|
9195
|
+
);
|
|
9196
|
+
}
|
|
9688
9197
|
var DEFAULT_OFFSET = "var(--ds-space-4)";
|
|
9689
9198
|
var CORNER_PANEL_ANCHOR_INSET = "calc(var(--ds-space-12) + var(--ds-space-3))";
|
|
9690
9199
|
function CornerPanel({
|
|
@@ -9966,8 +9475,10 @@ var StackedList = forwardRef(function StackedList2({
|
|
|
9966
9475
|
selectedId,
|
|
9967
9476
|
className,
|
|
9968
9477
|
flush,
|
|
9969
|
-
hover
|
|
9478
|
+
hover,
|
|
9479
|
+
pager
|
|
9970
9480
|
}, ref) {
|
|
9481
|
+
useScrollsInside();
|
|
9971
9482
|
const isPhone = useBreakpoint("sm");
|
|
9972
9483
|
const inCard = useContext(CardSurfaceCtx);
|
|
9973
9484
|
const inPane = useContext(SplitPaneCtx);
|
|
@@ -9979,20 +9490,22 @@ var StackedList = forwardRef(function StackedList2({
|
|
|
9979
9490
|
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.');
|
|
9980
9491
|
}, [legacy]);
|
|
9981
9492
|
const articles = variant === "articles";
|
|
9493
|
+
useWholeListCheck("StackedList", items.length, pager);
|
|
9494
|
+
const shown = pagerPart(items, pager);
|
|
9982
9495
|
const stackMeta = isPhone && articles;
|
|
9983
9496
|
const selectable = selectedId !== void 0 || items.some((i) => i.selected !== void 0);
|
|
9984
9497
|
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";
|
|
9985
|
-
|
|
9498
|
+
const list = /* @__PURE__ */ jsx(
|
|
9986
9499
|
"ul",
|
|
9987
9500
|
{
|
|
9988
9501
|
ref,
|
|
9989
9502
|
"data-ds-list": "",
|
|
9990
9503
|
className: cn(
|
|
9991
9504
|
divided && "divide-y-[length:var(--ds-border-width)] divide-[var(--ds-border-subtle)]",
|
|
9992
|
-
className
|
|
9505
|
+
!pager && className
|
|
9993
9506
|
),
|
|
9994
9507
|
role: "list",
|
|
9995
|
-
children:
|
|
9508
|
+
children: shown.map((item) => {
|
|
9996
9509
|
const isSelected = item.selected ?? (selectedId !== void 0 && item.id === selectedId);
|
|
9997
9510
|
const interactive = !!item.onClick;
|
|
9998
9511
|
const hasEmphasis = item.unread !== void 0;
|
|
@@ -10084,6 +9597,11 @@ var StackedList = forwardRef(function StackedList2({
|
|
|
10084
9597
|
})
|
|
10085
9598
|
}
|
|
10086
9599
|
);
|
|
9600
|
+
if (!pager) return list;
|
|
9601
|
+
return /* @__PURE__ */ jsxs("div", { "data-gs-paged": "", className: cn("flex flex-col min-w-0", className), children: [
|
|
9602
|
+
list,
|
|
9603
|
+
items.length > 0 && /* @__PURE__ */ jsx(Pagination, { ...pager.props })
|
|
9604
|
+
] });
|
|
10087
9605
|
});
|
|
10088
9606
|
var TIME_ZOOMS = ["day", "week", "month", "quarter"];
|
|
10089
9607
|
var DAY_MS = 864e5;
|
|
@@ -11119,7 +10637,7 @@ var SELECTED = "outline-solid outline-2 outline-offset-2 outline-[var(--ds-text-
|
|
|
11119
10637
|
var UNDATED_INSET = 16;
|
|
11120
10638
|
var NO_GROUPS = [];
|
|
11121
10639
|
var NO_STATUSES = {};
|
|
11122
|
-
var
|
|
10640
|
+
var warned = /* @__PURE__ */ new Set();
|
|
11123
10641
|
function warnOnce2(message) {
|
|
11124
10642
|
let dev = false;
|
|
11125
10643
|
try {
|
|
@@ -11127,8 +10645,8 @@ function warnOnce2(message) {
|
|
|
11127
10645
|
} catch {
|
|
11128
10646
|
dev = false;
|
|
11129
10647
|
}
|
|
11130
|
-
if (!dev ||
|
|
11131
|
-
|
|
10648
|
+
if (!dev || warned.has(message)) return;
|
|
10649
|
+
warned.add(message);
|
|
11132
10650
|
console.warn(`Gantt: ${message}`);
|
|
11133
10651
|
}
|
|
11134
10652
|
function GanttArrows({ arrows, width, height }) {
|
|
@@ -11192,6 +10710,7 @@ function Gantt({
|
|
|
11192
10710
|
"aria-label": ariaLabel,
|
|
11193
10711
|
className
|
|
11194
10712
|
}) {
|
|
10713
|
+
useScrollsInside();
|
|
11195
10714
|
const [zoomState, setZoomState] = useState(defaultZoom);
|
|
11196
10715
|
const zoom = zoomProp ?? zoomState;
|
|
11197
10716
|
const changeZoom = (next) => {
|
|
@@ -12009,14 +11528,17 @@ function TabButton({
|
|
|
12009
11528
|
onClick: disabled ? void 0 : () => onTabChange(id),
|
|
12010
11529
|
onKeyDown,
|
|
12011
11530
|
className: cn(
|
|
12012
|
-
|
|
11531
|
+
// Sprint 25.14 A38: a flex box, so the label sits in the middle of the tab. On a text line an icon's baseline
|
|
11532
|
+
// pushed the line 3 px taller and the label to its top (R28-72); a tab with an icon is now as tall as one
|
|
11533
|
+
// without, as a truncating tab (flex already) always was.
|
|
11534
|
+
"flex items-center justify-center px-ds-4 py-ds-2.5 text-sm font-medium",
|
|
12013
11535
|
// never wrap: the strip scrolls when the tabs do not fit (round 17, 54.4)
|
|
12014
11536
|
!fullWidth && !truncate && "shrink-0 whitespace-nowrap",
|
|
12015
11537
|
disabled ? "cursor-not-allowed opacity-disabled" : "cursor-pointer",
|
|
12016
11538
|
"transition-colors duration-[var(--ds-transition-speed)]",
|
|
12017
11539
|
"focus-visible:outline-none focus-visible:shadow-[var(--ds-shadow-focus)]",
|
|
12018
11540
|
fullWidth && "flex-1",
|
|
12019
|
-
truncate && "flex-1 min-w-0
|
|
11541
|
+
truncate && "flex-1 min-w-0 justify-start",
|
|
12020
11542
|
"rounded-[var(--ds-nav-h-item-radius)]",
|
|
12021
11543
|
isActive ? "bg-[var(--ds-nav-h-active-bg)] text-[var(--ds-nav-h-active-text)] border-[var(--ds-accent-primary)]" : "text-[var(--ds-nav-h-inactive-text)] hover:text-[var(--ds-text-primary)] hover:bg-[var(--ds-nav-h-hover-bg)]",
|
|
12022
11544
|
className
|
|
@@ -12429,337 +11951,62 @@ var Breadcrumbs = forwardRef(function Breadcrumbs2({
|
|
|
12429
11951
|
{
|
|
12430
11952
|
type: "button",
|
|
12431
11953
|
"data-index": idx,
|
|
12432
|
-
role: "menuitem",
|
|
12433
|
-
tabIndex: idx === activeIdx ? 0 : -1,
|
|
12434
|
-
className: cn(
|
|
12435
|
-
"flex items-center w-full text-left text-sm cursor-pointer",
|
|
12436
|
-
"px-ds-3 py-ds-1.5 transition-colors",
|
|
12437
|
-
"text-[var(--ds-text-secondary)]",
|
|
12438
|
-
"hover:bg-[var(--ds-bg-muted)] hover:text-[var(--ds-text-primary)]",
|
|
12439
|
-
"focus-visible:outline-none focus-visible:bg-[var(--ds-bg-muted)] focus-visible:text-[var(--ds-text-primary)] focus-visible:shadow-[inset_var(--ds-shadow-focus)]",
|
|
12440
|
-
gapClass
|
|
12441
|
-
),
|
|
12442
|
-
onClick: () => {
|
|
12443
|
-
setDropdownOpen(false);
|
|
12444
|
-
ci.onClick?.();
|
|
12445
|
-
},
|
|
12446
|
-
children: [
|
|
12447
|
-
showIcons && ci.icon && /* @__PURE__ */ jsx(Icon, { name: ci.icon, size: iconSize, className: "shrink-0" }),
|
|
12448
|
-
ci.label
|
|
12449
|
-
]
|
|
12450
|
-
},
|
|
12451
|
-
idx
|
|
12452
|
-
))
|
|
12453
|
-
}
|
|
12454
|
-
),
|
|
12455
|
-
container ?? document.body
|
|
12456
|
-
);
|
|
12457
|
-
if (isContainedBleed) {
|
|
12458
|
-
return /* @__PURE__ */ jsxs(
|
|
12459
|
-
"nav",
|
|
12460
|
-
{
|
|
12461
|
-
ref,
|
|
12462
|
-
"aria-label": "Breadcrumb",
|
|
12463
|
-
className: cn(
|
|
12464
|
-
"w-full bg-[var(--ds-bg-muted)]",
|
|
12465
|
-
// Hairline under the band: it sits within ~1.2:1 of both canvas and a tinted header, so the edge needs a line.
|
|
12466
|
-
"border-b-[length:var(--ds-border-width)] border-[var(--ds-border-subtle)]",
|
|
12467
|
-
className
|
|
12468
|
-
),
|
|
12469
|
-
children: [
|
|
12470
|
-
/* @__PURE__ */ jsx(
|
|
12471
|
-
"div",
|
|
12472
|
-
{
|
|
12473
|
-
className: cn("w-full mx-auto px-ds-6", size === "sm" ? "py-ds-1" : "py-ds-1.5"),
|
|
12474
|
-
style: { maxWidth: contentMaxWidth ?? "var(--ds-bp-xl)" },
|
|
12475
|
-
children: listContent
|
|
12476
|
-
}
|
|
12477
|
-
),
|
|
12478
|
-
dropdown
|
|
12479
|
-
]
|
|
12480
|
-
}
|
|
12481
|
-
);
|
|
12482
|
-
}
|
|
12483
|
-
return /* @__PURE__ */ jsxs("nav", { ref, "aria-label": "Breadcrumb", className: wrapperClasses, children: [
|
|
12484
|
-
listContent,
|
|
12485
|
-
dropdown
|
|
12486
|
-
] });
|
|
12487
|
-
});
|
|
12488
|
-
function Popover({ open, onOpenChange, trigger, children, side = "bottom", align = "center", width, className, container }) {
|
|
12489
|
-
const triggerRef = useRef(null);
|
|
12490
|
-
const floatingRef = useRef(null);
|
|
12491
|
-
const [triggerWidth, setTriggerWidth] = useState(void 0);
|
|
12492
|
-
const setTriggerNode = useCallback((node) => {
|
|
12493
|
-
triggerRef.current = node;
|
|
12494
|
-
setTriggerWidth(node?.offsetWidth);
|
|
12495
|
-
}, []);
|
|
12496
|
-
const pos = usePosition(triggerRef, floatingRef, open, { side, align, offset: 8, flip: true });
|
|
12497
|
-
const onOpenChangeRef = useLatest(onOpenChange);
|
|
12498
|
-
const { props: pressMarks, marked } = usePressMarks();
|
|
12499
|
-
const { isTop: isTopLayer, returnFocus } = usePopupFocus(open, { trigger: triggerRef, panel: floatingRef, close: () => onOpenChangeRef.current(false), tabExits: "edges", marked });
|
|
12500
|
-
useEffect(() => {
|
|
12501
|
-
if (!open) return;
|
|
12502
|
-
const onKeyDown = (e) => {
|
|
12503
|
-
if (e.key !== "Escape" || e.defaultPrevented || !isTopLayer()) return;
|
|
12504
|
-
const active = document.activeElement;
|
|
12505
|
-
if (active && active !== document.body && !triggerRef.current?.contains(active) && !floatingRef.current?.contains(active)) return;
|
|
12506
|
-
e.preventDefault();
|
|
12507
|
-
returnFocus();
|
|
12508
|
-
onOpenChangeRef.current(false);
|
|
12509
|
-
};
|
|
12510
|
-
const onPress = (e) => {
|
|
12511
|
-
const target = e.target;
|
|
12512
|
-
if (marked(e) || triggerRef.current?.contains(target) || floatingRef.current?.contains(target)) return;
|
|
12513
|
-
onOpenChangeRef.current(false);
|
|
12514
|
-
};
|
|
12515
|
-
document.addEventListener("keydown", onKeyDown);
|
|
12516
|
-
document.addEventListener("mousedown", onPress);
|
|
12517
|
-
return () => {
|
|
12518
|
-
document.removeEventListener("keydown", onKeyDown);
|
|
12519
|
-
document.removeEventListener("mousedown", onPress);
|
|
12520
|
-
};
|
|
12521
|
-
}, [open, onOpenChangeRef, isTopLayer, returnFocus, marked]);
|
|
12522
|
-
useEffect(() => {
|
|
12523
|
-
if (open) focusInitial(floatingRef.current);
|
|
12524
|
-
}, [open]);
|
|
12525
|
-
return /* @__PURE__ */ jsxs(Fragment, { children: [
|
|
12526
|
-
/* @__PURE__ */ jsx(
|
|
12527
|
-
Slot,
|
|
12528
|
-
{
|
|
12529
|
-
...triggerType(trigger),
|
|
12530
|
-
ref: setTriggerNode,
|
|
12531
|
-
onClick: () => {
|
|
12532
|
-
setTriggerWidth(triggerRef.current?.offsetWidth);
|
|
12533
|
-
onOpenChange(!open);
|
|
12534
|
-
},
|
|
12535
|
-
children: trigger
|
|
12536
|
-
}
|
|
12537
|
-
),
|
|
12538
|
-
open && createPortal(
|
|
12539
|
-
/* @__PURE__ */ jsx(
|
|
12540
|
-
"div",
|
|
12541
|
-
{
|
|
12542
|
-
ref: floatingRef,
|
|
12543
|
-
"data-gs": "popover",
|
|
12544
|
-
...pressMarks,
|
|
12545
|
-
onClick: (e) => e.stopPropagation(),
|
|
12546
|
-
className: cn(
|
|
12547
|
-
"fixed z-[var(--ds-z-popover)]",
|
|
12548
|
-
"bg-[var(--ds-bg-surface-elevated)]",
|
|
12549
|
-
GLASS_DROPDOWN,
|
|
12550
|
-
"border-[length:var(--ds-border-width)] border-[var(--ds-border-default)]",
|
|
12551
|
-
"rounded-[var(--ds-radius-md)]",
|
|
12552
|
-
className
|
|
12553
|
-
),
|
|
12554
|
-
style: {
|
|
12555
|
-
top: pos.top,
|
|
12556
|
-
left: pos.left,
|
|
12557
|
-
width: width === "trigger" ? triggerWidth : width === "auto" ? void 0 : width
|
|
12558
|
-
},
|
|
12559
|
-
children
|
|
12560
|
-
}
|
|
12561
|
-
),
|
|
12562
|
-
container ?? document.body
|
|
12563
|
-
)
|
|
12564
|
-
] });
|
|
12565
|
-
}
|
|
12566
|
-
function Pagination(props) {
|
|
12567
|
-
if ((props.mode === "load-more" || props.mode === "infinite-scroll") && props.onLoadMore) return /* @__PURE__ */ jsx(LoadMore, { ...props, onLoadMore: props.onLoadMore, scroll: props.mode === "infinite-scroll" });
|
|
12568
|
-
return /* @__PURE__ */ jsx(PageNumbers, { ...props });
|
|
12569
|
-
}
|
|
12570
|
-
function contentTop(el) {
|
|
12571
|
-
let top = el.getBoundingClientRect().top + window.scrollY;
|
|
12572
|
-
for (let n = el.parentElement; n && n !== document.documentElement; n = n.parentElement) top += n.scrollTop;
|
|
12573
|
-
return top;
|
|
12574
|
-
}
|
|
12575
|
-
function LoadMore({ hasMore, onLoadMore, loadMoreLabel, currentPage, scroll, className }) {
|
|
12576
|
-
const marker = useRef(null);
|
|
12577
|
-
const load = useLatest(onLoadMore);
|
|
12578
|
-
const loadedAt = useRef(null);
|
|
12579
|
-
useEffect(() => {
|
|
12580
|
-
const el = marker.current;
|
|
12581
|
-
if (!scroll || !hasMore || !el || typeof IntersectionObserver === "undefined") return;
|
|
12582
|
-
const observer = new IntersectionObserver((entries) => {
|
|
12583
|
-
if (!entries.some((e) => e.isIntersecting)) return;
|
|
12584
|
-
const at = contentTop(el);
|
|
12585
|
-
if (loadedAt.current !== null && Math.abs(at - loadedAt.current) < 1) return;
|
|
12586
|
-
loadedAt.current = at;
|
|
12587
|
-
load.current();
|
|
12588
|
-
}, { rootMargin: "200px 0px" });
|
|
12589
|
-
observer.observe(el);
|
|
12590
|
-
const rearm = () => {
|
|
12591
|
-
loadedAt.current = null;
|
|
12592
|
-
};
|
|
12593
|
-
window.addEventListener("scroll", rearm, { capture: true, passive: true });
|
|
12594
|
-
return () => {
|
|
12595
|
-
observer.disconnect();
|
|
12596
|
-
window.removeEventListener("scroll", rearm, { capture: true });
|
|
12597
|
-
};
|
|
12598
|
-
}, [scroll, hasMore, currentPage, load]);
|
|
12599
|
-
if (!hasMore) return null;
|
|
12600
|
-
return /* @__PURE__ */ jsxs("div", { "data-ds-pager": "", "data-pagination-mode": scroll ? "infinite-scroll" : "load-more", className: cn("flex flex-col items-center", className), children: [
|
|
12601
|
-
scroll && /* @__PURE__ */ jsx("div", { ref: marker, "data-load-more-trigger": "", "aria-hidden": "true", className: "h-px w-full" }),
|
|
12602
|
-
/* @__PURE__ */ jsx(Button, { type: "button", variant: "secondary", onClick: onLoadMore, children: loadMoreLabel ?? "Load more" })
|
|
12603
|
-
] });
|
|
12604
|
-
}
|
|
12605
|
-
function PageNumbers({ currentPage, totalPages, onPageChange, pageSize: pageSizeProp, pageSizeOptions, onPageSizeChange, className }) {
|
|
12606
|
-
const pages = buildPageRange(currentPage, totalPages);
|
|
12607
|
-
const preferences = useShellPreferences();
|
|
12608
|
-
const pageSize = pageSizeProp ?? preferences.itemsPerPage;
|
|
12609
|
-
return /* @__PURE__ */ jsxs("nav", { "aria-label": "Pagination", "data-ds-pager": "", className: cn("flex flex-wrap items-center gap-ds-3", className), children: [
|
|
12610
|
-
pageSizeOptions && pageSize != null && onPageSizeChange && /* @__PURE__ */ jsxs("div", { className: "flex items-center gap-ds-2", children: [
|
|
12611
|
-
/* @__PURE__ */ jsx("span", { className: "text-sm text-[var(--ds-text-muted)] whitespace-nowrap", children: "Rows per page" }),
|
|
12612
|
-
/* @__PURE__ */ jsx(FormChangeCtx, { value: null, children: /* @__PURE__ */ jsx(
|
|
12613
|
-
Dropdown,
|
|
12614
|
-
{
|
|
12615
|
-
options: pageSizeOptions.map((n) => ({ id: String(n), label: String(n) })),
|
|
12616
|
-
value: String(pageSize),
|
|
12617
|
-
onChange: (v) => onPageSizeChange(Number(v)),
|
|
12618
|
-
size: "sm",
|
|
12619
|
-
className: "w-[4.5rem]"
|
|
12620
|
-
}
|
|
12621
|
-
) })
|
|
12622
|
-
] }),
|
|
12623
|
-
/* @__PURE__ */ jsxs("div", { className: "flex items-center gap-ds-1", children: [
|
|
12624
|
-
/* @__PURE__ */ jsx(
|
|
12625
|
-
"button",
|
|
12626
|
-
{
|
|
12627
|
-
type: "button",
|
|
12628
|
-
onClick: () => onPageChange(currentPage - 1),
|
|
12629
|
-
disabled: currentPage <= 1,
|
|
12630
|
-
"aria-label": "Previous page",
|
|
12631
|
-
className: cn(
|
|
12632
|
-
"inline-flex items-center justify-center h-[var(--ds-control-height-sm)] w-[var(--ds-control-height-sm)] text-sm cursor-pointer",
|
|
12633
|
-
"rounded-[var(--ds-radius-md)]",
|
|
12634
|
-
"border-[length:var(--ds-border-width)] border-[var(--ds-border-default)]",
|
|
12635
|
-
"bg-[var(--ds-bg-surface)] text-[var(--ds-text-secondary)]",
|
|
12636
|
-
"transition-colors duration-[var(--ds-transition-speed)]",
|
|
12637
|
-
"hover:bg-[var(--ds-bg-muted)] hover:text-[var(--ds-text-primary)]",
|
|
12638
|
-
"disabled:opacity-disabled disabled:cursor-not-allowed"
|
|
12639
|
-
),
|
|
12640
|
-
children: /* @__PURE__ */ jsx(Icon, { name: "chevron-right", size: 16, className: "rotate-180" })
|
|
12641
|
-
}
|
|
12642
|
-
),
|
|
12643
|
-
pages.map(
|
|
12644
|
-
(p, i) => p === "..." ? /* @__PURE__ */ jsx(EllipsisJumper, { totalPages, onPageChange }, `ellipsis-${i}`) : /* @__PURE__ */ jsx(
|
|
12645
|
-
"button",
|
|
12646
|
-
{
|
|
12647
|
-
type: "button",
|
|
12648
|
-
onClick: () => onPageChange(p),
|
|
12649
|
-
"aria-current": p === currentPage ? "page" : void 0,
|
|
11954
|
+
role: "menuitem",
|
|
11955
|
+
tabIndex: idx === activeIdx ? 0 : -1,
|
|
12650
11956
|
className: cn(
|
|
12651
|
-
"
|
|
12652
|
-
"
|
|
12653
|
-
"
|
|
12654
|
-
"
|
|
12655
|
-
|
|
11957
|
+
"flex items-center w-full text-left text-sm cursor-pointer",
|
|
11958
|
+
"px-ds-3 py-ds-1.5 transition-colors",
|
|
11959
|
+
"text-[var(--ds-text-secondary)]",
|
|
11960
|
+
"hover:bg-[var(--ds-bg-muted)] hover:text-[var(--ds-text-primary)]",
|
|
11961
|
+
"focus-visible:outline-none focus-visible:bg-[var(--ds-bg-muted)] focus-visible:text-[var(--ds-text-primary)] focus-visible:shadow-[inset_var(--ds-shadow-focus)]",
|
|
11962
|
+
gapClass
|
|
12656
11963
|
),
|
|
12657
|
-
|
|
11964
|
+
onClick: () => {
|
|
11965
|
+
setDropdownOpen(false);
|
|
11966
|
+
ci.onClick?.();
|
|
11967
|
+
},
|
|
11968
|
+
children: [
|
|
11969
|
+
showIcons && ci.icon && /* @__PURE__ */ jsx(Icon, { name: ci.icon, size: iconSize, className: "shrink-0" }),
|
|
11970
|
+
ci.label
|
|
11971
|
+
]
|
|
12658
11972
|
},
|
|
12659
|
-
|
|
12660
|
-
)
|
|
12661
|
-
|
|
12662
|
-
|
|
12663
|
-
|
|
12664
|
-
|
|
12665
|
-
|
|
12666
|
-
|
|
12667
|
-
|
|
12668
|
-
|
|
12669
|
-
|
|
12670
|
-
|
|
12671
|
-
|
|
12672
|
-
|
|
12673
|
-
|
|
12674
|
-
|
|
12675
|
-
|
|
12676
|
-
|
|
12677
|
-
|
|
12678
|
-
children: /* @__PURE__ */ jsx(Icon, { name: "chevron-right", size: 16 })
|
|
12679
|
-
}
|
|
12680
|
-
)
|
|
12681
|
-
] })
|
|
12682
|
-
] });
|
|
12683
|
-
}
|
|
12684
|
-
function buildPageRange(current, total) {
|
|
12685
|
-
if (total <= 7) return Array.from({ length: total }, (_, i) => i + 1);
|
|
12686
|
-
const pages = [1];
|
|
12687
|
-
if (current > 3) pages.push("...");
|
|
12688
|
-
const start = Math.max(2, current - 1);
|
|
12689
|
-
const end = Math.min(total - 1, current + 1);
|
|
12690
|
-
for (let i = start; i <= end; i++) pages.push(i);
|
|
12691
|
-
if (current < total - 2) pages.push("...");
|
|
12692
|
-
pages.push(total);
|
|
12693
|
-
return pages;
|
|
12694
|
-
}
|
|
12695
|
-
function EllipsisJumper({ totalPages, onPageChange }) {
|
|
12696
|
-
const [open, setOpen] = useState(false);
|
|
12697
|
-
const [jumpPage, setJumpPage] = useState(1);
|
|
12698
|
-
const handleOpenChange = (next) => {
|
|
12699
|
-
if (next) setJumpPage(1);
|
|
12700
|
-
setOpen(next);
|
|
12701
|
-
};
|
|
12702
|
-
const handleGo = () => {
|
|
12703
|
-
const clamped = Math.min(totalPages, Math.max(1, jumpPage));
|
|
12704
|
-
onPageChange(clamped);
|
|
12705
|
-
setOpen(false);
|
|
12706
|
-
};
|
|
12707
|
-
return /* @__PURE__ */ jsx(
|
|
12708
|
-
Popover,
|
|
12709
|
-
{
|
|
12710
|
-
open,
|
|
12711
|
-
onOpenChange: handleOpenChange,
|
|
12712
|
-
trigger: /* @__PURE__ */ jsx(
|
|
12713
|
-
"button",
|
|
12714
|
-
{
|
|
12715
|
-
type: "button",
|
|
12716
|
-
"aria-label": "Go to page",
|
|
12717
|
-
onClick: () => handleOpenChange(true),
|
|
12718
|
-
className: cn(
|
|
12719
|
-
"inline-flex items-center justify-center h-[var(--ds-control-height-sm)] w-[var(--ds-control-height-sm)] text-sm cursor-pointer",
|
|
12720
|
-
"rounded-[var(--ds-radius-md)]",
|
|
12721
|
-
"text-[var(--ds-text-muted)]",
|
|
12722
|
-
"transition-colors duration-[var(--ds-transition-speed)]",
|
|
12723
|
-
"hover:bg-[var(--ds-bg-muted)] hover:text-[var(--ds-text-primary)]"
|
|
12724
|
-
),
|
|
12725
|
-
children: "\u2026"
|
|
12726
|
-
}
|
|
12727
|
-
),
|
|
12728
|
-
children: /* @__PURE__ */ jsxs("div", { className: "flex flex-col gap-ds-2 p-ds-3", children: [
|
|
12729
|
-
/* @__PURE__ */ jsx("label", { className: "text-xs font-medium text-[var(--ds-text-secondary)]", children: "Go to page" }),
|
|
12730
|
-
/* @__PURE__ */ jsxs("div", { className: "flex items-center gap-ds-2", children: [
|
|
11973
|
+
idx
|
|
11974
|
+
))
|
|
11975
|
+
}
|
|
11976
|
+
),
|
|
11977
|
+
container ?? document.body
|
|
11978
|
+
);
|
|
11979
|
+
if (isContainedBleed) {
|
|
11980
|
+
return /* @__PURE__ */ jsxs(
|
|
11981
|
+
"nav",
|
|
11982
|
+
{
|
|
11983
|
+
ref,
|
|
11984
|
+
"aria-label": "Breadcrumb",
|
|
11985
|
+
className: cn(
|
|
11986
|
+
"w-full bg-[var(--ds-bg-muted)]",
|
|
11987
|
+
// Hairline under the band: it sits within ~1.2:1 of both canvas and a tinted header, so the edge needs a line.
|
|
11988
|
+
"border-b-[length:var(--ds-border-width)] border-[var(--ds-border-subtle)]",
|
|
11989
|
+
className
|
|
11990
|
+
),
|
|
11991
|
+
children: [
|
|
12731
11992
|
/* @__PURE__ */ jsx(
|
|
12732
|
-
|
|
11993
|
+
"div",
|
|
12733
11994
|
{
|
|
12734
|
-
|
|
12735
|
-
|
|
12736
|
-
|
|
12737
|
-
max: totalPages,
|
|
12738
|
-
step: 1,
|
|
12739
|
-
size: "sm",
|
|
12740
|
-
className: "w-[5rem]"
|
|
11995
|
+
className: cn("w-full mx-auto px-ds-6", size === "sm" ? "py-ds-1" : "py-ds-1.5"),
|
|
11996
|
+
style: { maxWidth: contentMaxWidth ?? "var(--ds-bp-xl)" },
|
|
11997
|
+
children: listContent
|
|
12741
11998
|
}
|
|
12742
11999
|
),
|
|
12743
|
-
|
|
12744
|
-
|
|
12745
|
-
|
|
12746
|
-
|
|
12747
|
-
|
|
12748
|
-
|
|
12749
|
-
|
|
12750
|
-
|
|
12751
|
-
|
|
12752
|
-
|
|
12753
|
-
"hover:opacity-90"
|
|
12754
|
-
),
|
|
12755
|
-
children: "Go"
|
|
12756
|
-
}
|
|
12757
|
-
)
|
|
12758
|
-
] })
|
|
12759
|
-
] })
|
|
12760
|
-
}
|
|
12761
|
-
);
|
|
12762
|
-
}
|
|
12000
|
+
dropdown
|
|
12001
|
+
]
|
|
12002
|
+
}
|
|
12003
|
+
);
|
|
12004
|
+
}
|
|
12005
|
+
return /* @__PURE__ */ jsxs("nav", { ref, "aria-label": "Breadcrumb", className: wrapperClasses, children: [
|
|
12006
|
+
listContent,
|
|
12007
|
+
dropdown
|
|
12008
|
+
] });
|
|
12009
|
+
});
|
|
12763
12010
|
var HeaderTabRowContext = createContext(null);
|
|
12764
12011
|
function useHeaderTabRow() {
|
|
12765
12012
|
return useContext(HeaderTabRowContext);
|
|
@@ -14498,7 +13745,8 @@ function pageMaxWidth(resolved) {
|
|
|
14498
13745
|
}
|
|
14499
13746
|
var paddingClasses = {
|
|
14500
13747
|
none: "",
|
|
14501
|
-
|
|
13748
|
+
// the page's gutter, which an overlay's header, body and footer share (Sprint 25.14 A36)
|
|
13749
|
+
default: "px-[var(--ds-page-gutter)]",
|
|
14502
13750
|
wide: "px-ds-10"
|
|
14503
13751
|
};
|
|
14504
13752
|
var verticalPaddingClasses = {
|
|
@@ -14826,10 +14074,18 @@ function Caption({ children, onLight, onTint }) {
|
|
|
14826
14074
|
onLight ? "text-[var(--ds-text-on-primary)]/80" : onTint ? "text-[var(--ds-text-muted-on-tint)]" : "text-[var(--ds-text-secondary)]"
|
|
14827
14075
|
), children });
|
|
14828
14076
|
}
|
|
14077
|
+
var ON_BAND_STRIP = cn(
|
|
14078
|
+
"rounded-[var(--ds-radius-md)] px-ds-3 py-ds-2 border-[length:var(--ds-border-width)] border-[var(--ds-border-subtle)]",
|
|
14079
|
+
"bg-[var(--ds-bg-surface)] supports-[color:oklch(from_red_l_c_h)]:bg-[oklch(from_var(--ds-bg-surface)_l_c_h_/_max(alpha,min(1,alpha*1000)*0.6))]",
|
|
14080
|
+
GLASS_SURFACE
|
|
14081
|
+
);
|
|
14829
14082
|
function TabRow({ children, hasCaption, className, onBand }) {
|
|
14830
14083
|
const [row, setRow] = useState(null);
|
|
14831
14084
|
const value = useMemo(() => ({ row, hasCaption }), [row, hasCaption]);
|
|
14832
|
-
return /* @__PURE__ */ jsx("div", { ref: setRow, className: cn(className, onBand && "mx-0
|
|
14085
|
+
return /* @__PURE__ */ jsx("div", { ref: setRow, className: cn(className, onBand && cn("mx-0", ON_BAND_STRIP)), children: /* @__PURE__ */ jsx(HeaderTabRowContext.Provider, { value, children }) });
|
|
14086
|
+
}
|
|
14087
|
+
function FilterRow({ children, className, onBand }) {
|
|
14088
|
+
return /* @__PURE__ */ jsx(ControlSizeContext.Provider, { value: "sm", children: /* @__PURE__ */ jsx(FilterRowContext.Provider, { value: true, children: /* @__PURE__ */ jsx("div", { "data-gs": "filter-row", className: cn("flex items-center flex-wrap gap-ds-3", className, onBand && cn("w-fit max-w-full", ON_BAND_STRIP)), children }) }) });
|
|
14833
14089
|
}
|
|
14834
14090
|
var FLOATING_HEADER = cn(
|
|
14835
14091
|
"rounded-[var(--ds-radius-md)]",
|
|
@@ -15117,7 +14373,7 @@ function DefaultHeader({
|
|
|
15117
14373
|
] }),
|
|
15118
14374
|
actions && /* @__PURE__ */ jsx("div", { className: "flex items-center gap-ds-2 shrink-0", children: actions })
|
|
15119
14375
|
] }),
|
|
15120
|
-
filters && /* @__PURE__ */ jsx(
|
|
14376
|
+
filters && /* @__PURE__ */ jsx(FilterRow, { className: "mt-ds-4", children: filters }),
|
|
15121
14377
|
tabs && /* @__PURE__ */ jsx(TabRow, { hasCaption: !!caption, className: "mt-ds-4 -mx-ds-1", children: tabs })
|
|
15122
14378
|
] })
|
|
15123
14379
|
]
|
|
@@ -15229,7 +14485,9 @@ function ColourfulHeader({
|
|
|
15229
14485
|
style: {
|
|
15230
14486
|
maxWidth: gutter ? contentMaxWidth ?? "var(--ds-bp-xl)" : void 0,
|
|
15231
14487
|
containerType: "inline-size",
|
|
15232
|
-
|
|
14488
|
+
// under the overlap, the gap from the header's last row to the cards is the page's own (space-6): the band's
|
|
14489
|
+
// bottom edge counts in it (the owner, 30 September: 26 px above the cards, 24 below)
|
|
14490
|
+
...overlapActive ? { paddingBottom: `calc(var(--ds-space-6) + var(--ds-overlap, 0px) - ${isBold && !isFloating ? "2px" : "var(--ds-border-width)"})` } : {}
|
|
15233
14491
|
},
|
|
15234
14492
|
children: [
|
|
15235
14493
|
focusBack && /* @__PURE__ */ jsx(BackLink, { onClick: focusBack, onLight: isBold }),
|
|
@@ -15258,7 +14516,7 @@ function ColourfulHeader({
|
|
|
15258
14516
|
] }),
|
|
15259
14517
|
actions && /* @__PURE__ */ jsx("div", { className: "flex items-center gap-ds-2 shrink-0", children: actions })
|
|
15260
14518
|
] }),
|
|
15261
|
-
filters && /* @__PURE__ */ jsx(
|
|
14519
|
+
filters && /* @__PURE__ */ jsx(FilterRow, { className: "mt-ds-4", onBand: isBold, children: filters }),
|
|
15262
14520
|
tabs && /* @__PURE__ */ jsx(TabRow, { hasCaption: !!caption, className: "mt-ds-4 -mx-ds-1", onBand: isBold, children: tabs })
|
|
15263
14521
|
]
|
|
15264
14522
|
}
|
|
@@ -15444,7 +14702,7 @@ function SnappingHeader({
|
|
|
15444
14702
|
actions && /* @__PURE__ */ jsx(ControlSizeContext.Provider, { value: "sm", children: /* @__PURE__ */ jsx("div", { className: "flex items-center gap-ds-2 shrink-0", children: actions }) })
|
|
15445
14703
|
] }),
|
|
15446
14704
|
description && /* @__PURE__ */ jsx(ClampedText, { className: "mt-ds-1 text-sm text-[var(--ds-text-secondary)]", children: description }),
|
|
15447
|
-
filters && /* @__PURE__ */ jsx(
|
|
14705
|
+
filters && /* @__PURE__ */ jsx(FilterRow, { className: "mt-ds-3", children: filters }),
|
|
15448
14706
|
expandedContent && /* @__PURE__ */ jsx("div", { className: "mt-ds-3", children: expandedContent }),
|
|
15449
14707
|
tabs && /* @__PURE__ */ jsx(TabRow, { hasCaption: !!caption, className: "mt-ds-3 -mx-ds-1", children: tabs })
|
|
15450
14708
|
] }) : /* @__PURE__ */ jsxs(
|
|
@@ -15458,7 +14716,7 @@ function SnappingHeader({
|
|
|
15458
14716
|
hasBreadcrumbs && !hideExpandedBreadcrumbs ? "pt-ds-3" : "pt-ds-6"
|
|
15459
14717
|
]
|
|
15460
14718
|
),
|
|
15461
|
-
style: !collapsed && isColourful && overlapActive ? { paddingBottom: `calc(var(--ds-space-6) + var(--ds-overlap, 0px))` } : void 0,
|
|
14719
|
+
style: !collapsed && isColourful && overlapActive ? { paddingBottom: `calc(var(--ds-space-6) + var(--ds-overlap, 0px) - ${isBoldColourful && !(isFloating && !wrapperHasCard) ? "2px" : "var(--ds-border-width)"})` } : void 0,
|
|
15462
14720
|
children: [
|
|
15463
14721
|
!collapsed && focusBack && /* @__PURE__ */ jsx(BackLink, { onClick: focusBack, onLight }),
|
|
15464
14722
|
!collapsed && hasBreadcrumbs && !hideExpandedBreadcrumbs && /* @__PURE__ */ jsx(Breadcrumbs3, { items: breadcrumbs, onLight, onTint, pill: breadcrumbPill, separator: breadcrumbSeparator }),
|
|
@@ -15513,7 +14771,7 @@ function SnappingHeader({
|
|
|
15513
14771
|
] }),
|
|
15514
14772
|
actions && (collapsed ? /* @__PURE__ */ jsx(ControlSizeContext.Provider, { value: "sm", children: /* @__PURE__ */ jsx("div", { className: "flex items-center gap-ds-2 shrink-0", children: actions }) }) : /* @__PURE__ */ jsx("div", { className: "flex items-center gap-ds-2 shrink-0", children: actions }))
|
|
15515
14773
|
] }),
|
|
15516
|
-
!collapsed && filters && /* @__PURE__ */ jsx(
|
|
14774
|
+
!collapsed && filters && /* @__PURE__ */ jsx(FilterRow, { className: "mt-ds-4", onBand: isBoldColourful, children: filters }),
|
|
15517
14775
|
!collapsed && expandedContent && /* @__PURE__ */ jsx("div", { className: "mt-ds-4", children: expandedContent }),
|
|
15518
14776
|
!collapsed && tabs && /* @__PURE__ */ jsx(TabRow, { hasCaption: !!caption, className: "mt-ds-4 -mx-ds-1", onBand: isBoldColourful, children: tabs })
|
|
15519
14777
|
]
|
|
@@ -15750,6 +15008,73 @@ function Dock({
|
|
|
15750
15008
|
}
|
|
15751
15009
|
);
|
|
15752
15010
|
}
|
|
15011
|
+
function resolveNavItemType(type) {
|
|
15012
|
+
return type === "default" ? "tint" : type;
|
|
15013
|
+
}
|
|
15014
|
+
var NavbarTypeContext = createContext("tint");
|
|
15015
|
+
var NavItem = forwardRef(function NavItem2({ label, icon, active = false, href, onClick, type: typeProp, className, children }, ref) {
|
|
15016
|
+
const contextType = useContext(NavbarTypeContext);
|
|
15017
|
+
const type = resolveNavItemType(typeProp ?? contextType);
|
|
15018
|
+
const baseClasses = cn(
|
|
15019
|
+
"inline-flex items-center gap-ds-2 cursor-pointer select-none whitespace-nowrap",
|
|
15020
|
+
// one line: the navbar measures each link (round 12)
|
|
15021
|
+
"transition-colors duration-[var(--ds-transition-speed)] ease-[var(--ds-transition-ease)]",
|
|
15022
|
+
"focus-visible:outline-none focus-visible:shadow-[var(--ds-shadow-focus)]",
|
|
15023
|
+
"text-[length:var(--ds-font-size-sm)]"
|
|
15024
|
+
);
|
|
15025
|
+
const typeClasses = getTypeClasses(type, active);
|
|
15026
|
+
return /* @__PURE__ */ jsxs(
|
|
15027
|
+
"a",
|
|
15028
|
+
{
|
|
15029
|
+
ref,
|
|
15030
|
+
href: href ?? "#",
|
|
15031
|
+
onClick,
|
|
15032
|
+
"aria-current": active ? "page" : void 0,
|
|
15033
|
+
className: cn(baseClasses, typeClasses, className),
|
|
15034
|
+
children: [
|
|
15035
|
+
icon && /* @__PURE__ */ jsx(Icon, { name: icon, size: 16 }),
|
|
15036
|
+
children ?? label,
|
|
15037
|
+
type === "underline" && active && /* @__PURE__ */ jsx(NavUnderline, {})
|
|
15038
|
+
]
|
|
15039
|
+
}
|
|
15040
|
+
);
|
|
15041
|
+
});
|
|
15042
|
+
function getTypeClasses(type, active) {
|
|
15043
|
+
switch (type) {
|
|
15044
|
+
case "pill":
|
|
15045
|
+
return cn(
|
|
15046
|
+
"px-ds-2 py-ds-1 rounded-[var(--ds-radius-sm)]",
|
|
15047
|
+
active ? "bg-[var(--ds-accent-primary)] text-[var(--ds-text-on-primary)] font-[var(--ds-weight-heading)]" : "text-[var(--ds-text-secondary)] hover:text-[var(--ds-text-primary)] hover:bg-[var(--ds-bg-muted)]"
|
|
15048
|
+
);
|
|
15049
|
+
case "underline":
|
|
15050
|
+
return cn(
|
|
15051
|
+
"px-ds-2 py-ds-2 relative",
|
|
15052
|
+
active ? "text-[var(--ds-text-primary)] font-[var(--ds-weight-heading)]" : "text-[var(--ds-text-muted)] hover:text-[var(--ds-text-primary)]"
|
|
15053
|
+
);
|
|
15054
|
+
case "minimal":
|
|
15055
|
+
return cn(
|
|
15056
|
+
"px-ds-2 py-ds-1",
|
|
15057
|
+
active ? "text-[var(--ds-accent-primary)] font-medium" : "text-[var(--ds-text-muted)] hover:text-[var(--ds-text-secondary)]"
|
|
15058
|
+
);
|
|
15059
|
+
case "tint":
|
|
15060
|
+
return cn(
|
|
15061
|
+
"px-ds-2 py-ds-1 rounded-[var(--ds-radius-sm)]",
|
|
15062
|
+
active ? "bg-[var(--ds-accent-subtle)] text-[var(--ds-accent-primary)] font-[var(--ds-weight-heading)]" : "text-[var(--ds-text-secondary)] hover:text-[var(--ds-text-primary)] hover:bg-[var(--ds-bg-muted)]"
|
|
15063
|
+
);
|
|
15064
|
+
}
|
|
15065
|
+
}
|
|
15066
|
+
function NavUnderline() {
|
|
15067
|
+
return /* @__PURE__ */ jsx(
|
|
15068
|
+
"span",
|
|
15069
|
+
{
|
|
15070
|
+
className: "absolute bottom-0 left-ds-1 right-ds-1 rounded-t-full bg-[var(--ds-accent-primary)]",
|
|
15071
|
+
style: { height: "2px" }
|
|
15072
|
+
}
|
|
15073
|
+
);
|
|
15074
|
+
}
|
|
15075
|
+
function navItemClasses(type, active) {
|
|
15076
|
+
return cn("text-[length:var(--ds-font-size-sm)]", getTypeClasses(type, active));
|
|
15077
|
+
}
|
|
15753
15078
|
function TruncSpan({ children, className }) {
|
|
15754
15079
|
const { ref, isTruncated } = useTextOverflow({ lines: 1 });
|
|
15755
15080
|
const el = /* @__PURE__ */ jsx("span", { ref, className: cn("truncate", className), children });
|
|
@@ -15760,7 +15085,7 @@ function NavMenu({
|
|
|
15760
15085
|
label,
|
|
15761
15086
|
items,
|
|
15762
15087
|
active = false,
|
|
15763
|
-
type
|
|
15088
|
+
type: typeProp,
|
|
15764
15089
|
onItemClick,
|
|
15765
15090
|
className
|
|
15766
15091
|
}) {
|
|
@@ -15808,27 +15133,14 @@ function NavMenu({
|
|
|
15808
15133
|
const hasActiveChild = active || items.some(
|
|
15809
15134
|
(it) => it.active || it.children?.some((c) => c.active)
|
|
15810
15135
|
);
|
|
15136
|
+
const contextType = useContext(NavbarTypeContext);
|
|
15137
|
+
const type = resolveNavItemType(typeProp ?? contextType);
|
|
15811
15138
|
const isUnderline = type === "underline";
|
|
15812
|
-
const isMinimal = type === "minimal";
|
|
15813
|
-
const isPill = type === "pill";
|
|
15814
15139
|
const triggerClasses = cn(
|
|
15815
|
-
"inline-flex items-center gap-ds-1 cursor-pointer
|
|
15140
|
+
"inline-flex items-center gap-ds-1 cursor-pointer select-none whitespace-nowrap",
|
|
15141
|
+
"transition-colors duration-[var(--ds-transition-speed)] ease-[var(--ds-transition-ease)]",
|
|
15816
15142
|
"focus-visible:outline-none focus-visible:shadow-[var(--ds-shadow-focus)]",
|
|
15817
|
-
|
|
15818
|
-
"px-ds-3 py-ds-2 text-sm border-b-2 -mb-[2px]",
|
|
15819
|
-
hasActiveChild ? "border-[var(--ds-accent-primary)] text-[var(--ds-text-primary)] font-medium" : "border-transparent text-[var(--ds-text-secondary)] hover:text-[var(--ds-text-primary)] hover:border-[var(--ds-border-default)]"
|
|
15820
|
-
) : isMinimal ? cn(
|
|
15821
|
-
"px-ds-2 py-ds-1 text-sm",
|
|
15822
|
-
hasActiveChild ? "text-[var(--ds-text-primary)] font-medium" : "text-[var(--ds-text-secondary)] hover:text-[var(--ds-text-primary)]"
|
|
15823
|
-
) : isPill ? cn(
|
|
15824
|
-
"px-ds-3 py-ds-1.5 text-sm rounded-[var(--ds-radius-md)]",
|
|
15825
|
-
hasActiveChild ? "bg-[var(--ds-accent-primary)] text-[var(--ds-text-on-primary)] font-medium" : "text-[var(--ds-text-secondary)] hover:bg-[var(--ds-bg-muted)] hover:text-[var(--ds-text-primary)]"
|
|
15826
|
-
) : cn(
|
|
15827
|
-
// tint (and the deprecated `default` alias) — the same soft accent fill
|
|
15828
|
-
// NavItem uses, so a menu trigger and a link read as one row (decision 30).
|
|
15829
|
-
"px-ds-3 py-ds-1.5 text-sm rounded-[var(--ds-radius-md)]",
|
|
15830
|
-
hasActiveChild ? "bg-[var(--ds-accent-subtle)] text-[var(--ds-accent-primary)] font-medium" : "text-[var(--ds-text-secondary)] hover:bg-[var(--ds-bg-muted)] hover:text-[var(--ds-text-primary)]"
|
|
15831
|
-
),
|
|
15143
|
+
navItemClasses(type, hasActiveChild),
|
|
15832
15144
|
className
|
|
15833
15145
|
);
|
|
15834
15146
|
return /* @__PURE__ */ jsxs(Fragment, { children: [
|
|
@@ -15850,7 +15162,8 @@ function NavMenu({
|
|
|
15850
15162
|
size: 12,
|
|
15851
15163
|
className: cn("transition-transform", open && "rotate-180")
|
|
15852
15164
|
}
|
|
15853
|
-
)
|
|
15165
|
+
),
|
|
15166
|
+
isUnderline && hasActiveChild && /* @__PURE__ */ jsx(NavUnderline, {})
|
|
15854
15167
|
]
|
|
15855
15168
|
}
|
|
15856
15169
|
),
|
|
@@ -15961,67 +15274,6 @@ function NavMenuGroup({
|
|
|
15961
15274
|
)) })
|
|
15962
15275
|
] });
|
|
15963
15276
|
}
|
|
15964
|
-
function resolveNavItemType(type) {
|
|
15965
|
-
return type === "default" ? "tint" : type;
|
|
15966
|
-
}
|
|
15967
|
-
var NavbarTypeContext = createContext("tint");
|
|
15968
|
-
var NavItem = forwardRef(function NavItem2({ label, icon, active = false, href, onClick, type: typeProp, className, children }, ref) {
|
|
15969
|
-
const contextType = useContext(NavbarTypeContext);
|
|
15970
|
-
const type = resolveNavItemType(typeProp ?? contextType);
|
|
15971
|
-
const baseClasses = cn(
|
|
15972
|
-
"inline-flex items-center gap-ds-2 cursor-pointer select-none whitespace-nowrap",
|
|
15973
|
-
// one line: the navbar measures each link (round 12)
|
|
15974
|
-
"transition-colors duration-[var(--ds-transition-speed)] ease-[var(--ds-transition-ease)]",
|
|
15975
|
-
"focus-visible:outline-none focus-visible:shadow-[var(--ds-shadow-focus)]",
|
|
15976
|
-
"text-[length:var(--ds-font-size-sm)]"
|
|
15977
|
-
);
|
|
15978
|
-
const typeClasses = getTypeClasses(type, active);
|
|
15979
|
-
return /* @__PURE__ */ jsxs(
|
|
15980
|
-
"a",
|
|
15981
|
-
{
|
|
15982
|
-
ref,
|
|
15983
|
-
href: href ?? "#",
|
|
15984
|
-
onClick,
|
|
15985
|
-
"aria-current": active ? "page" : void 0,
|
|
15986
|
-
className: cn(baseClasses, typeClasses, className),
|
|
15987
|
-
children: [
|
|
15988
|
-
icon && /* @__PURE__ */ jsx(Icon, { name: icon, size: 16 }),
|
|
15989
|
-
children ?? label,
|
|
15990
|
-
type === "underline" && active && /* @__PURE__ */ jsx(
|
|
15991
|
-
"span",
|
|
15992
|
-
{
|
|
15993
|
-
className: "absolute bottom-0 left-ds-1 right-ds-1 rounded-t-full bg-[var(--ds-accent-primary)]",
|
|
15994
|
-
style: { height: "2px" }
|
|
15995
|
-
}
|
|
15996
|
-
)
|
|
15997
|
-
]
|
|
15998
|
-
}
|
|
15999
|
-
);
|
|
16000
|
-
});
|
|
16001
|
-
function getTypeClasses(type, active) {
|
|
16002
|
-
switch (type) {
|
|
16003
|
-
case "pill":
|
|
16004
|
-
return cn(
|
|
16005
|
-
"px-ds-2 py-ds-1 rounded-[var(--ds-radius-sm)]",
|
|
16006
|
-
active ? "bg-[var(--ds-accent-primary)] text-[var(--ds-text-on-primary)] font-[var(--ds-weight-heading)]" : "text-[var(--ds-text-secondary)] hover:text-[var(--ds-text-primary)] hover:bg-[var(--ds-bg-muted)]"
|
|
16007
|
-
);
|
|
16008
|
-
case "underline":
|
|
16009
|
-
return cn(
|
|
16010
|
-
"px-ds-2 py-ds-2 relative",
|
|
16011
|
-
active ? "text-[var(--ds-text-primary)] font-[var(--ds-weight-heading)]" : "text-[var(--ds-text-muted)] hover:text-[var(--ds-text-primary)]"
|
|
16012
|
-
);
|
|
16013
|
-
case "minimal":
|
|
16014
|
-
return cn(
|
|
16015
|
-
"px-ds-2 py-ds-1",
|
|
16016
|
-
active ? "text-[var(--ds-accent-primary)] font-medium" : "text-[var(--ds-text-muted)] hover:text-[var(--ds-text-secondary)]"
|
|
16017
|
-
);
|
|
16018
|
-
case "tint":
|
|
16019
|
-
return cn(
|
|
16020
|
-
"px-ds-2 py-ds-1 rounded-[var(--ds-radius-sm)]",
|
|
16021
|
-
active ? "bg-[var(--ds-accent-subtle)] text-[var(--ds-accent-primary)] font-[var(--ds-weight-heading)]" : "text-[var(--ds-text-secondary)] hover:text-[var(--ds-text-primary)] hover:bg-[var(--ds-bg-muted)]"
|
|
16022
|
-
);
|
|
16023
|
-
}
|
|
16024
|
-
}
|
|
16025
15277
|
var DEFAULT_BUTTON_ATTR = "data-dialog-default-button";
|
|
16026
15278
|
var sizeClasses = {
|
|
16027
15279
|
// round 16 (the owner's item 5): the small dialog is 448 px, not 384 — a delete confirmation with a typed field was cramped
|
|
@@ -16042,6 +15294,7 @@ function Dialog({ open, onClose: onCloseProp, title, description, children, foot
|
|
|
16042
15294
|
const dialogRef = useRef(null);
|
|
16043
15295
|
const opener = useRef(null);
|
|
16044
15296
|
const defaultButtonRef = useRef(null);
|
|
15297
|
+
const bodyRef = useScrollbarInset();
|
|
16045
15298
|
const onCloseRef = useLatest(onClose);
|
|
16046
15299
|
const onSubmitRef = useLatest(onSubmit);
|
|
16047
15300
|
const isTopLayer = useOverlayLayer(open);
|
|
@@ -16087,7 +15340,7 @@ function Dialog({ open, onClose: onCloseProp, title, description, children, foot
|
|
|
16087
15340
|
"div",
|
|
16088
15341
|
{
|
|
16089
15342
|
ref: overlayRef,
|
|
16090
|
-
className: "fixed inset-0 z-[var(--ds-z-modal)] flex items-center justify-center p-ds-4",
|
|
15343
|
+
className: cn("fixed inset-0 z-[var(--ds-z-modal)] flex items-center justify-center", !isMobile && "p-ds-4"),
|
|
16091
15344
|
children: [
|
|
16092
15345
|
/* @__PURE__ */ jsx(
|
|
16093
15346
|
"div",
|
|
@@ -16139,29 +15392,20 @@ function Dialog({ open, onClose: onCloseProp, title, description, children, foot
|
|
|
16139
15392
|
"aria-describedby": description ? descriptionId : void 0,
|
|
16140
15393
|
style: { containerType: "inline-size" },
|
|
16141
15394
|
className: cn(
|
|
16142
|
-
|
|
15395
|
+
// a column: the title row, a body that scrolls when it is taller than the room, and the footer (Sprint 25.14,
|
|
15396
|
+
// with A36's full-screen phone dialog: its content ran past the screen with the footer cut off)
|
|
15397
|
+
"relative z-10 w-full flex flex-col max-h-full",
|
|
16143
15398
|
isMobile ? "max-w-none h-full" : sizeClasses[size],
|
|
16144
15399
|
OVERLAY_SURFACE,
|
|
16145
15400
|
"text-[var(--ds-text-primary)]",
|
|
16146
15401
|
GLASS_OVERLAY,
|
|
16147
|
-
|
|
16148
|
-
isMobile ? "rounded-none" : "rounded-[var(--ds-radius-xl)]",
|
|
15402
|
+
// full screen on a phone: no edge to draw, so the content sits at the gutter from the screen's edge
|
|
15403
|
+
isMobile ? "rounded-none" : "rounded-[var(--ds-radius-xl)] border-[length:var(--ds-border-width)] border-[var(--ds-border-default)]",
|
|
16149
15404
|
"overflow-hidden",
|
|
16150
15405
|
"animate-in fade-in-0 zoom-in-95"
|
|
16151
15406
|
),
|
|
16152
15407
|
children: [
|
|
16153
|
-
/* @__PURE__ */
|
|
16154
|
-
"button",
|
|
16155
|
-
{
|
|
16156
|
-
type: "button",
|
|
16157
|
-
onClick: onClose,
|
|
16158
|
-
...{ [OVERLAY_CLOSE_ATTR]: "" },
|
|
16159
|
-
className: "absolute right-4 top-4 text-[var(--ds-text-muted)] hover:text-[var(--ds-text-primary)] transition-colors cursor-pointer",
|
|
16160
|
-
"aria-label": "Close",
|
|
16161
|
-
children: /* @__PURE__ */ jsx(Icon, { name: "close", size: 18 })
|
|
16162
|
-
}
|
|
16163
|
-
),
|
|
16164
|
-
/* @__PURE__ */ jsx("div", { className: "p-ds-6", children: /* @__PURE__ */ jsxs("div", { className: "flex items-start gap-ds-3", children: [
|
|
15408
|
+
/* @__PURE__ */ jsxs("div", { className: cn("shrink-0 flex items-start gap-ds-3 pt-ds-6 px-[var(--ds-page-gutter)]", children ? "pb-ds-4" : "pb-ds-6"), children: [
|
|
16165
15409
|
variant === "destructive" && /* @__PURE__ */ jsx("div", { className: "flex items-center justify-center shrink-0 w-10 h-10 rounded-[var(--ds-radius-full)] bg-[var(--ds-status-error-bg)]", children: /* @__PURE__ */ jsx(Icon, { name: "warning", size: 20, className: "text-[var(--ds-status-error)]" }) }),
|
|
16166
15410
|
/* @__PURE__ */ jsxs("div", { className: "flex-1 min-w-0", children: [
|
|
16167
15411
|
/* @__PURE__ */ jsx(
|
|
@@ -16172,16 +15416,39 @@ function Dialog({ open, onClose: onCloseProp, title, description, children, foot
|
|
|
16172
15416
|
children: title
|
|
16173
15417
|
}
|
|
16174
15418
|
),
|
|
16175
|
-
description && /* @__PURE__ */ jsx("p", { id: descriptionId, className: "mt-ds-2 text-sm text-[var(--ds-text-muted)]", children: description })
|
|
16176
|
-
|
|
16177
|
-
|
|
16178
|
-
|
|
15419
|
+
description && /* @__PURE__ */ jsx("p", { id: descriptionId, className: "mt-ds-2 text-sm text-[var(--ds-text-muted)]", children: description })
|
|
15420
|
+
] }),
|
|
15421
|
+
/* @__PURE__ */ jsx(
|
|
15422
|
+
"button",
|
|
15423
|
+
{
|
|
15424
|
+
type: "button",
|
|
15425
|
+
onClick: onClose,
|
|
15426
|
+
...{ [OVERLAY_CLOSE_ATTR]: "" },
|
|
15427
|
+
className: "shrink-0 text-[var(--ds-text-muted)] hover:text-[var(--ds-text-primary)] transition-colors cursor-pointer",
|
|
15428
|
+
"aria-label": "Close",
|
|
15429
|
+
children: /* @__PURE__ */ jsx(Icon, { name: "close", size: 18 })
|
|
15430
|
+
}
|
|
15431
|
+
)
|
|
15432
|
+
] }),
|
|
15433
|
+
children && /* @__PURE__ */ jsx(
|
|
15434
|
+
"div",
|
|
15435
|
+
{
|
|
15436
|
+
ref: bodyRef,
|
|
15437
|
+
className: "min-h-0 flex-[0_1_auto] overflow-y-auto pb-ds-6",
|
|
15438
|
+
style: {
|
|
15439
|
+
paddingLeft: variant === "destructive" ? "calc(var(--ds-page-gutter) + 2.5rem + var(--ds-space-3))" : "var(--ds-page-gutter)",
|
|
15440
|
+
paddingRight: insetLessScrollbar("var(--ds-page-gutter)")
|
|
15441
|
+
},
|
|
15442
|
+
children: /* @__PURE__ */ jsx(SurfaceBoundary, { children: /* @__PURE__ */ jsx(DrawerFooterCtx, { value: null, children: /* @__PURE__ */ jsx(OverlayMarkScope, { mark, children: /* @__PURE__ */ jsx(OverlayCloseCtx, { value: onClose, children }) }) }) })
|
|
15443
|
+
}
|
|
15444
|
+
),
|
|
15445
|
+
isMobile && /* @__PURE__ */ jsx("div", { "aria-hidden": true, className: "flex-1 min-h-0" }),
|
|
16179
15446
|
/* @__PURE__ */ jsx(DiscardConfirm, { open: guard.confirming, onKeep: guard.keep, onDiscard: guard.discard }),
|
|
16180
15447
|
footer && /* @__PURE__ */ jsx("div", { className: cn(
|
|
16181
|
-
"flex justify-end gap-ds-2
|
|
15448
|
+
"shrink-0 flex justify-end gap-ds-2 py-ds-4 px-[var(--ds-page-gutter)]",
|
|
16182
15449
|
"border-t-[length:var(--ds-border-width)] border-[var(--ds-border-subtle)]",
|
|
16183
15450
|
"bg-[var(--ds-bg-muted)]",
|
|
16184
|
-
"rounded-b-[var(--ds-radius-xl)]"
|
|
15451
|
+
!isMobile && "rounded-b-[var(--ds-radius-xl)]"
|
|
16185
15452
|
), children: footer })
|
|
16186
15453
|
]
|
|
16187
15454
|
}
|
|
@@ -17468,67 +16735,6 @@ function getPopoverPosition(rect, placement, padding) {
|
|
|
17468
16735
|
top = Math.max(8, Math.min(top, window.innerHeight - popH - 8));
|
|
17469
16736
|
return { top, left };
|
|
17470
16737
|
}
|
|
17471
|
-
function firstKey(item) {
|
|
17472
|
-
if (item !== null && typeof item === "object") return "id" in item ? item.id : void 0;
|
|
17473
|
-
return item;
|
|
17474
|
-
}
|
|
17475
|
-
function signature(list, resetOn) {
|
|
17476
|
-
let reset = "";
|
|
17477
|
-
try {
|
|
17478
|
-
reset = JSON.stringify(resetOn ?? null);
|
|
17479
|
-
} catch {
|
|
17480
|
-
reset = String(resetOn);
|
|
17481
|
-
}
|
|
17482
|
-
let first = "";
|
|
17483
|
-
try {
|
|
17484
|
-
first = JSON.stringify(firstKey(list[0]) ?? null);
|
|
17485
|
-
} catch {
|
|
17486
|
-
first = "";
|
|
17487
|
-
}
|
|
17488
|
-
return `${list.length}|${first}|${reset}`;
|
|
17489
|
-
}
|
|
17490
|
-
function usePagination(list, options = {}) {
|
|
17491
|
-
const shell = useShellPreferences();
|
|
17492
|
-
const style = options.style ?? shell.paginationStyle ?? PREFERENCE_HOUSE_DEFAULTS.paginationStyle;
|
|
17493
|
-
const [chosenSize, setChosenSize] = useState(null);
|
|
17494
|
-
const pageSize = Math.max(1, Math.floor(chosenSize ?? options.pageSize ?? shell.itemsPerPage ?? PREFERENCE_HOUSE_DEFAULTS.itemsPerPage));
|
|
17495
|
-
const [page, setPageState] = useState(1);
|
|
17496
|
-
const sig = signature(list, options.resetOn);
|
|
17497
|
-
const [seen, setSeen] = useState(sig);
|
|
17498
|
-
if (seen !== sig) {
|
|
17499
|
-
setSeen(sig);
|
|
17500
|
-
if (page !== 1) setPageState(1);
|
|
17501
|
-
}
|
|
17502
|
-
const totalItems = list.length;
|
|
17503
|
-
const totalPages = Math.max(1, Math.ceil(totalItems / pageSize));
|
|
17504
|
-
const current = Math.min(Math.max(1, seen !== sig ? 1 : page), totalPages);
|
|
17505
|
-
const grows = style !== "pagination";
|
|
17506
|
-
const start = grows ? 0 : (current - 1) * pageSize;
|
|
17507
|
-
const items = list.slice(start, current * pageSize);
|
|
17508
|
-
const range2 = items.length === 0 ? [0, 0] : [start + 1, start + items.length];
|
|
17509
|
-
const hasMore = current < totalPages;
|
|
17510
|
-
const setPage = (next) => setPageState(Math.min(Math.max(1, Math.floor(next)), totalPages));
|
|
17511
|
-
const loadMore = () => setPageState((p) => Math.min(p + 1, totalPages));
|
|
17512
|
-
const setPageSize = (size) => {
|
|
17513
|
-
setChosenSize(Math.max(1, Math.floor(size)));
|
|
17514
|
-
setPageState(1);
|
|
17515
|
-
};
|
|
17516
|
-
return {
|
|
17517
|
-
style,
|
|
17518
|
-
items,
|
|
17519
|
-
page: current,
|
|
17520
|
-
pageSize,
|
|
17521
|
-
totalItems,
|
|
17522
|
-
totalPages,
|
|
17523
|
-
range: range2,
|
|
17524
|
-
shown: items.length,
|
|
17525
|
-
hasMore,
|
|
17526
|
-
loadMore,
|
|
17527
|
-
setPage,
|
|
17528
|
-
setPageSize,
|
|
17529
|
-
props: { currentPage: current, totalPages, onPageChange: setPage, pageSize, onPageSizeChange: setPageSize, mode: style, hasMore, onLoadMore: loadMore }
|
|
17530
|
-
};
|
|
17531
|
-
}
|
|
17532
16738
|
function useDestructiveAction(options) {
|
|
17533
16739
|
const { action, title, description, confirmLabel, typeToConfirm, onConfirm, onUndo, doneMessage, undoMessage, restoredMessage, severity } = options;
|
|
17534
16740
|
const preferences = useShellPreferences();
|
|
@@ -17675,7 +16881,7 @@ var PAST_TENSE = {
|
|
|
17675
16881
|
reject: "Rejected",
|
|
17676
16882
|
decline: "Declined"
|
|
17677
16883
|
};
|
|
17678
|
-
var
|
|
16884
|
+
var warned2 = /* @__PURE__ */ new Set();
|
|
17679
16885
|
function pastTenseOf(label) {
|
|
17680
16886
|
const words = label.trim().toLowerCase().split(/\s+/);
|
|
17681
16887
|
const found = PAST_TENSE[words.slice(0, 2).join(" ")] ?? PAST_TENSE[words[0] ?? ""];
|
|
@@ -17686,8 +16892,8 @@ function pastTenseOf(label) {
|
|
|
17686
16892
|
} catch {
|
|
17687
16893
|
dev = false;
|
|
17688
16894
|
}
|
|
17689
|
-
if (dev && !
|
|
17690
|
-
|
|
16895
|
+
if (dev && !warned2.has(label)) {
|
|
16896
|
+
warned2.add(label);
|
|
17691
16897
|
console.warn(`useDestructiveAction: "${label}" isn't a verb the hook knows; pass doneMessage so the confirmation says what happened.`);
|
|
17692
16898
|
}
|
|
17693
16899
|
return "Done";
|
|
@@ -17832,6 +17038,6 @@ var TextOverflow = forwardRef(function TextOverflow2({
|
|
|
17832
17038
|
return /* @__PURE__ */ jsx(Tooltip, { content: resolvedTooltipContent, children: content });
|
|
17833
17039
|
});
|
|
17834
17040
|
|
|
17835
|
-
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,
|
|
17041
|
+
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, Sheet, 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 };
|
|
17836
17042
|
//# sourceMappingURL=index.js.map
|
|
17837
17043
|
//# sourceMappingURL=index.js.map
|