gridsmith-ui 0.21.0 → 0.22.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/chat.js +3 -3
- package/dist/chunk-2RV23OBK.js +1349 -0
- package/dist/chunk-2RV23OBK.js.map +1 -0
- package/dist/chunk-7TOJ4G7S.js +197 -0
- package/dist/chunk-7TOJ4G7S.js.map +1 -0
- package/dist/{chunk-GGVASDXT.js → chunk-AAYCQXZQ.js} +8 -155
- package/dist/chunk-AAYCQXZQ.js.map +1 -0
- package/dist/{chunk-ILIODA7W.js → chunk-CXMV7SXJ.js} +4 -3
- package/dist/chunk-CXMV7SXJ.js.map +1 -0
- package/dist/{chunk-EQDR57AM.js → chunk-EYMGLK4M.js} +3 -3
- package/dist/{chunk-EQDR57AM.js.map → chunk-EYMGLK4M.js.map} +1 -1
- package/dist/chunk-IVCVNAXG.js +115 -0
- package/dist/chunk-IVCVNAXG.js.map +1 -0
- package/dist/chunk-RG4KUCRS.js +9 -0
- package/dist/chunk-RG4KUCRS.js.map +1 -0
- package/dist/{chunk-XYDIBW3J.js → chunk-SBTBMAIU.js} +4 -3
- package/dist/chunk-SBTBMAIU.js.map +1 -0
- package/dist/data-grid.d.ts +38 -4
- package/dist/data-grid.js +304 -264
- package/dist/data-grid.js.map +1 -1
- package/dist/editor.js +1 -1
- package/dist/index.d.ts +94 -139
- package/dist/index.js +794 -1616
- package/dist/index.js.map +1 -1
- package/dist/kanban.js +2 -2
- package/dist/resizable.js +5 -4
- package/dist/resizable.js.map +1 -1
- package/dist/roots.css +10 -0
- package/dist/{table-utils-GounRE6s.d.ts → table-utils-BkjNEWts.d.ts} +5 -1
- package/dist/use-pagination-DiJo0aW5.d.ts +153 -0
- package/dist/virtualized.d.ts +11 -1
- package/dist/virtualized.js +67 -18
- package/dist/virtualized.js.map +1 -1
- package/package.json +1 -1
- package/dist/chunk-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,28 @@
|
|
|
1
|
-
import {
|
|
2
|
-
export { AppShell,
|
|
1
|
+
import { useAppShell, REACT_VERSION_PROBLEM, useOverlayMark, useDirtyGuard, OverlayMarkScope, OverlayCloseCtx, DiscardConfirm, OVERLAY_ROOT_ATTR, OverlayMarkCtx, DrawerFooterCtx, useCompact, useElementWidth, Sheet, useCloseSettle, Drawer, useRememberedWidth, pxOf, ResizeEdge, defaultMaxWidth } from './chunk-AAYCQXZQ.js';
|
|
2
|
+
export { AppShell, Drawer, Sheet, SkipLink, useAppShell, useUnsavedChanges } from './chunk-AAYCQXZQ.js';
|
|
3
3
|
import { Skeleton, TITLE_TEXT } from './chunk-NCIZQYXQ.js';
|
|
4
4
|
export { Skeleton } from './chunk-NCIZQYXQ.js';
|
|
5
|
-
import {
|
|
6
|
-
export {
|
|
7
|
-
import {
|
|
8
|
-
export {
|
|
9
|
-
import {
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
import { SplitPaneCtx,
|
|
13
|
-
|
|
5
|
+
import { Link } from './chunk-EYMGLK4M.js';
|
|
6
|
+
export { CodeBlock, Divider, Link } from './chunk-EYMGLK4M.js';
|
|
7
|
+
import { Badge } from './chunk-SBTBMAIU.js';
|
|
8
|
+
export { Badge } from './chunk-SBTBMAIU.js';
|
|
9
|
+
import { inferColumnKinds, useCardsSwitch, CARDS_BELOW, kindOfRenderedText, CardValue } from './chunk-IVCVNAXG.js';
|
|
10
|
+
import { useWholeListCheck, pagerPart, Pagination, Dropdown, useFieldControl, useField, warnOnce, Label, InlineFieldError, AddAnotherRowCtx, Input, Field } from './chunk-2RV23OBK.js';
|
|
11
|
+
export { Dropdown, Field, InlineFieldError, Input, Label, NumberInput, Pagination, Popover, Textarea, Toggle, usePagination } from './chunk-2RV23OBK.js';
|
|
12
|
+
import { SplitPaneCtx, TableCardCtx } from './chunk-RG4KUCRS.js';
|
|
13
|
+
import { Button, ControlSizeContext, triggerType, Spinner, useShellPreferences, preferenceActionKey } from './chunk-7TOJ4G7S.js';
|
|
14
|
+
export { Button, ButtonSizeContext, ControlSizeContext, PreferencesContext, Spinner, preferenceActionKey, usePreferences } from './chunk-7TOJ4G7S.js';
|
|
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 { useTextOverflow, Tooltip, usePosition } from './chunk-CXMV7SXJ.js';
|
|
20
|
+
export { Tooltip, useTextOverflow } from './chunk-CXMV7SXJ.js';
|
|
18
21
|
import { mergeRefs, Slot } from './chunk-7Q46JXSK.js';
|
|
19
22
|
import { useLatest } from './chunk-WH2FUFAC.js';
|
|
20
23
|
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,
|
|
24
|
+
import { cn, GLASS_SURFACE, GLASS_BACKDROP, GLASS_DROPDOWN, lockBodyScroll, unlockBodyScroll, OVERLAY_SURFACE, GLASS_OVERLAY, ERROR_HAS_FOCUS_RING, HAS_FOCUS_RING, ACTIVE_RING, ERROR_ACTIVE_RING, ERROR_FOCUS_RING, FOCUS_RING, FOCUS_WITHIN_RING } from './chunk-M2QRNBDQ.js';
|
|
25
|
+
import { createContext, forwardRef, useState, useRef, useCallback, useLayoutEffect, useMemo, useContext, isValidElement, useId, memo, useEffect, useImperativeHandle, Children, Fragment as Fragment$1, cloneElement, useSyncExternalStore } from 'react';
|
|
23
26
|
import { createPortal, flushSync } from 'react-dom';
|
|
24
27
|
import { jsxs, jsx, Fragment } from 'react/jsx-runtime';
|
|
25
28
|
|
|
@@ -83,6 +86,8 @@ function DropdownMenu({ trigger, items, align = "end", className, container }) {
|
|
|
83
86
|
Slot,
|
|
84
87
|
{
|
|
85
88
|
...triggerType(trigger),
|
|
89
|
+
"aria-haspopup": "menu",
|
|
90
|
+
"aria-expanded": open,
|
|
86
91
|
ref: triggerRef,
|
|
87
92
|
onClick: () => {
|
|
88
93
|
setOpen(!open);
|
|
@@ -208,733 +213,6 @@ function BulkActionBar({ selectedCount, actions, onClearSelection, className })
|
|
|
208
213
|
}
|
|
209
214
|
);
|
|
210
215
|
}
|
|
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
216
|
var CONTROL_HEIGHT = {
|
|
939
217
|
sm: "h-[var(--ds-control-height-sm)]",
|
|
940
218
|
md: "h-[var(--ds-control-height-md)]",
|
|
@@ -2488,21 +1766,6 @@ function Progress({ value, max = 100, variant = "default", size = "md", indeterm
|
|
|
2488
1766
|
] })
|
|
2489
1767
|
] });
|
|
2490
1768
|
}
|
|
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
1769
|
function TruncFileName({ children, className }) {
|
|
2507
1770
|
const { ref, isTruncated } = useTextOverflow({ lines: 1 });
|
|
2508
1771
|
const el = /* @__PURE__ */ jsx("p", { ref, className: cn("truncate", className), children });
|
|
@@ -2631,9 +1894,9 @@ function FileUpload({ onFiles, files, upload, onCancel, onRetry, onRemove, accep
|
|
|
2631
1894
|
if (new Set(ids).size !== ids.length) warnOnce("FileUpload", "two files in the list share an id: give each file its own (the same file picked twice is two files).");
|
|
2632
1895
|
}, [controlled, onFiles, upload, onRemove, shown]);
|
|
2633
1896
|
const [heard, setHeard] = useState({ text: "", n: 0 });
|
|
2634
|
-
const
|
|
2635
|
-
const [seen, setSeen] = useState(() => ({ signature
|
|
2636
|
-
if (
|
|
1897
|
+
const signature = shown.map((i) => `${i.id}\0${i.status}`).join("");
|
|
1898
|
+
const [seen, setSeen] = useState(() => ({ signature, statuses: new Map(shown.map((i) => [i.id, i.status])) }));
|
|
1899
|
+
if (signature !== seen.signature) {
|
|
2637
1900
|
const said = [];
|
|
2638
1901
|
for (const item of shown) {
|
|
2639
1902
|
const before = seen.statuses.get(item.id);
|
|
@@ -2641,7 +1904,7 @@ function FileUpload({ onFiles, files, upload, onCancel, onRetry, onRemove, accep
|
|
|
2641
1904
|
if (item.status === "done") said.push(`${item.name} uploaded`);
|
|
2642
1905
|
else if (item.status === "error") said.push(`${item.name} didn't upload: ${item.error ?? "the upload failed"}`);
|
|
2643
1906
|
}
|
|
2644
|
-
setSeen({ signature
|
|
1907
|
+
setSeen({ signature, statuses: new Map(shown.map((i) => [i.id, i.status])) });
|
|
2645
1908
|
if (said.length) setHeard((h) => ({ text: said.join(". "), n: h.n + 1 }));
|
|
2646
1909
|
}
|
|
2647
1910
|
const pendingFocus = useRef(null);
|
|
@@ -3394,237 +2657,21 @@ function TimePicker({
|
|
|
3394
2657
|
onMouseDown: (e) => e.preventDefault(),
|
|
3395
2658
|
onClick: () => emitChange(parsed.hour, parsed.minute, p),
|
|
3396
2659
|
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
|
|
2660
|
+
"text-xs font-medium py-ds-1 rounded-[var(--ds-radius-sm)] cursor-pointer",
|
|
2661
|
+
"transition-colors text-center focus-visible:outline-none focus-visible:shadow-[var(--ds-shadow-focus)]",
|
|
2662
|
+
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)]"
|
|
2663
|
+
),
|
|
2664
|
+
children: p
|
|
2665
|
+
},
|
|
2666
|
+
p
|
|
2667
|
+
)) })
|
|
2668
|
+
] })
|
|
2669
|
+
] })
|
|
2670
|
+
}
|
|
3540
2671
|
),
|
|
3541
|
-
|
|
3542
|
-
|
|
3543
|
-
|
|
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
|
-
);
|
|
2672
|
+
container ?? document.body
|
|
2673
|
+
)
|
|
2674
|
+
] });
|
|
3628
2675
|
}
|
|
3629
2676
|
var variantStyles = {
|
|
3630
2677
|
default: "bg-[var(--ds-bg-emphasis)] text-[var(--ds-text-primary)]",
|
|
@@ -3867,7 +2914,7 @@ function TagInput({
|
|
|
3867
2914
|
}
|
|
3868
2915
|
);
|
|
3869
2916
|
}
|
|
3870
|
-
var
|
|
2917
|
+
var sizes = {
|
|
3871
2918
|
sm: "w-[var(--ds-control-height-sm)] h-[var(--ds-control-height-sm)] text-sm",
|
|
3872
2919
|
md: "w-[var(--ds-control-height-md)] h-[var(--ds-control-height-md)] text-base",
|
|
3873
2920
|
lg: "w-[var(--ds-control-height-lg)] h-[var(--ds-control-height-lg)] text-lg"
|
|
@@ -3971,7 +3018,7 @@ function PinInput({
|
|
|
3971
3018
|
!error && !disabled && "hover:border-[var(--ds-input-border-hover)]",
|
|
3972
3019
|
error ? ERROR_FOCUS_RING : FOCUS_RING,
|
|
3973
3020
|
"placeholder:text-[var(--ds-text-muted)]",
|
|
3974
|
-
|
|
3021
|
+
sizes[size],
|
|
3975
3022
|
disabled && "opacity-disabled cursor-not-allowed"
|
|
3976
3023
|
)
|
|
3977
3024
|
},
|
|
@@ -5312,43 +4359,18 @@ function MentionInput({
|
|
|
5312
4359
|
)
|
|
5313
4360
|
] });
|
|
5314
4361
|
}
|
|
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));
|
|
4362
|
+
var CardRowCtx = createContext(null);
|
|
4363
|
+
var TITLE_LINE = "h-[calc(var(--ds-font-size-lg)*var(--ds-line-height-lg))]";
|
|
4364
|
+
var HeaderRowCtx = createContext(false);
|
|
4365
|
+
function holdsHeader(children) {
|
|
4366
|
+
let found = false;
|
|
4367
|
+
Children.forEach(children, (child) => {
|
|
4368
|
+
if (found || !isValidElement(child)) return;
|
|
4369
|
+
if (child.type === Fragment$1) found = holdsHeader(child.props.children);
|
|
4370
|
+
else if (child.type === CardHeader) found = true;
|
|
4371
|
+
});
|
|
4372
|
+
return found;
|
|
5350
4373
|
}
|
|
5351
|
-
var CardCtx = createContext(false);
|
|
5352
4374
|
var CardActionCtx = createContext(null);
|
|
5353
4375
|
var CARD_ACTION_ATTR = "data-card-action";
|
|
5354
4376
|
var CardSurfaceCtx = createContext(false);
|
|
@@ -5499,7 +4521,7 @@ var Card = forwardRef(function Card2({
|
|
|
5499
4521
|
const handleKeyDown = isSelectable && !disabled ? (e) => {
|
|
5500
4522
|
if (e.key === "Enter" || e.key === " ") {
|
|
5501
4523
|
e.preventDefault();
|
|
5502
|
-
onSelectedChange?.(!selected);
|
|
4524
|
+
if (!e.repeat) onSelectedChange?.(!selected);
|
|
5503
4525
|
}
|
|
5504
4526
|
} : isAction && !disabled ? (e) => {
|
|
5505
4527
|
if (e.target !== e.currentTarget) return;
|
|
@@ -5516,13 +4538,84 @@ var Card = forwardRef(function Card2({
|
|
|
5516
4538
|
} : void 0;
|
|
5517
4539
|
const handleCheckableClick = (e) => {
|
|
5518
4540
|
e.stopPropagation();
|
|
5519
|
-
onSelectedChange?.(!selected);
|
|
4541
|
+
if (!disabled) onSelectedChange?.(!selected);
|
|
5520
4542
|
};
|
|
5521
4543
|
const isButton = isSelectable || isAction && !holdsControls;
|
|
5522
4544
|
const role = selectType === "radio" ? "radio" : selectType === "checkbox" ? "checkbox" : selectType === "toggle" ? "switch" : isButton ? "button" : void 0;
|
|
5523
4545
|
const ariaAttr = selectType === "radio" || selectType === "checkbox" || selectType === "toggle" ? { "aria-checked": !!selected } : isSelectable ? { "aria-pressed": !!selected } : {};
|
|
5524
4546
|
const indicator = selectType === "radio" ? /* @__PURE__ */ jsx(RadioIndicator, { checked: !!selected, disabled }) : selectType === "checkbox" ? /* @__PURE__ */ jsx(CheckboxIndicator, { checked: !!selected, indeterminate, disabled }) : selectType === "toggle" ? /* @__PURE__ */ jsx(ToggleIndicator, { checked: !!selected, disabled }) : null;
|
|
5525
|
-
const defaultCheckBadge = !hasSelectType && !checkable && selected && !loading ? /* @__PURE__ */ jsx("
|
|
4547
|
+
const defaultCheckBadge = !hasSelectType && !checkable && selected && !loading ? /* @__PURE__ */ jsx("span", { "data-card-check": "", className: "w-5 h-5 rounded-[var(--ds-radius-full)] bg-[var(--ds-accent-primary)] flex items-center justify-center", children: /* @__PURE__ */ jsx(Icon, { name: "check", size: 12, className: "text-[var(--ds-text-on-primary)]" }) }) : null;
|
|
4548
|
+
const checkboxes = useRef(/* @__PURE__ */ new Set());
|
|
4549
|
+
const checkboxFocused = useRef(false);
|
|
4550
|
+
const checkboxRef = useCallback((node) => {
|
|
4551
|
+
if (!node) return;
|
|
4552
|
+
checkboxes.current.add(node);
|
|
4553
|
+
return () => {
|
|
4554
|
+
checkboxes.current.delete(node);
|
|
4555
|
+
};
|
|
4556
|
+
}, []);
|
|
4557
|
+
useLayoutEffect(() => {
|
|
4558
|
+
if (!checkboxFocused.current) return;
|
|
4559
|
+
const active = document.activeElement;
|
|
4560
|
+
if (active && active !== document.body) return;
|
|
4561
|
+
for (const node of checkboxes.current) {
|
|
4562
|
+
if (node.isConnected) {
|
|
4563
|
+
node.focus({ preventScroll: true });
|
|
4564
|
+
return;
|
|
4565
|
+
}
|
|
4566
|
+
}
|
|
4567
|
+
});
|
|
4568
|
+
const checkbox = checkable ? /* @__PURE__ */ jsx(
|
|
4569
|
+
"div",
|
|
4570
|
+
{
|
|
4571
|
+
ref: checkboxRef,
|
|
4572
|
+
"data-card-checkbox": "",
|
|
4573
|
+
className: cn(
|
|
4574
|
+
"rounded-[calc(var(--ds-radius-sm)*0.6)] focus-visible:outline-none focus-visible:shadow-[var(--ds-shadow-focus)]",
|
|
4575
|
+
disabled ? "cursor-not-allowed" : "cursor-pointer"
|
|
4576
|
+
),
|
|
4577
|
+
onClick: handleCheckableClick,
|
|
4578
|
+
role: "checkbox",
|
|
4579
|
+
"aria-checked": !!selected,
|
|
4580
|
+
"aria-disabled": disabled || void 0,
|
|
4581
|
+
...inner.titleId ? { "aria-labelledby": inner.titleId } : { "aria-label": "Select" },
|
|
4582
|
+
tabIndex: 0,
|
|
4583
|
+
onFocus: () => {
|
|
4584
|
+
checkboxFocused.current = true;
|
|
4585
|
+
},
|
|
4586
|
+
onBlur: (e) => {
|
|
4587
|
+
const node = e.currentTarget;
|
|
4588
|
+
queueMicrotask(() => {
|
|
4589
|
+
if (node.isConnected) checkboxFocused.current = false;
|
|
4590
|
+
});
|
|
4591
|
+
},
|
|
4592
|
+
onKeyDown: (e) => {
|
|
4593
|
+
if (e.key !== " ") return;
|
|
4594
|
+
e.preventDefault();
|
|
4595
|
+
e.stopPropagation();
|
|
4596
|
+
if (!e.repeat && !disabled) onSelectedChange?.(!selected);
|
|
4597
|
+
},
|
|
4598
|
+
children: /* @__PURE__ */ jsx(CheckboxIndicator, { checked: !!selected, disabled })
|
|
4599
|
+
}
|
|
4600
|
+
) : null;
|
|
4601
|
+
const check = indicator ?? defaultCheckBadge;
|
|
4602
|
+
const headers = useRef([]);
|
|
4603
|
+
const [owner, setOwner] = useState(null);
|
|
4604
|
+
const [guess, setGuess] = useState(() => holdsHeader(children));
|
|
4605
|
+
const register = useCallback((header) => {
|
|
4606
|
+
headers.current = [...headers.current, header];
|
|
4607
|
+
setOwner(headers.current[0]);
|
|
4608
|
+
return () => {
|
|
4609
|
+
headers.current = headers.current.filter((h) => h !== header);
|
|
4610
|
+
setOwner(headers.current[0] ?? null);
|
|
4611
|
+
setGuess(false);
|
|
4612
|
+
};
|
|
4613
|
+
}, []);
|
|
4614
|
+
useLayoutEffect(() => {
|
|
4615
|
+
if (headers.current.length === 0) setGuess(false);
|
|
4616
|
+
}, []);
|
|
4617
|
+
const hasHeader = owner !== null || guess;
|
|
4618
|
+
const rowParts = { checkbox, check, owner, register };
|
|
5526
4619
|
return /* @__PURE__ */ jsxs(
|
|
5527
4620
|
"div",
|
|
5528
4621
|
{
|
|
@@ -5553,32 +4646,22 @@ var Card = forwardRef(function Card2({
|
|
|
5553
4646
|
...ariaAttr,
|
|
5554
4647
|
...props,
|
|
5555
4648
|
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 ? (
|
|
4649
|
+
!loading && !hasHeader && checkbox && /* @__PURE__ */ jsxs("div", { "data-card-header-row": "", className: "flex items-center gap-ds-2 px-ds-5 pt-ds-4", children: [
|
|
4650
|
+
checkbox,
|
|
4651
|
+
/* @__PURE__ */ jsx("span", { "aria-hidden": "true", className: "grow" }),
|
|
4652
|
+
check && /* @__PURE__ */ jsx("span", { "data-card-selection": "", className: "shrink-0 flex", children: check })
|
|
4653
|
+
] }),
|
|
4654
|
+
!loading && !hasHeader && !checkbox && check && /* @__PURE__ */ jsx("div", { "data-card-selection": "", className: "absolute top-ds-3 right-ds-3 z-[1] flex", children: check }),
|
|
4655
|
+
/* @__PURE__ */ jsx(CardSurfaceCtx, { value: true, children: /* @__PURE__ */ jsx(CardActionCtx, { value: action, children: /* @__PURE__ */ jsx(CardRowCtx, { value: rowParts, children: loading ? (
|
|
5578
4656
|
// Round 15 (the owner's 52.1): a placeholder stands where the content will stand — inside the card's
|
|
5579
4657
|
// content inset (CardContent's padding), a title-height line then two body lines — never flush against the border.
|
|
5580
|
-
|
|
5581
|
-
|
|
4658
|
+
// Its header holds a badge-sized block (A2), so a grid of item cards keeps its columns when they load.
|
|
4659
|
+
/* @__PURE__ */ jsx("div", { "data-card-loading": "", "aria-busy": "true", className: "px-ds-5 py-ds-4", children: /* @__PURE__ */ jsxs("div", { className: "space-y-ds-3", children: [
|
|
4660
|
+
/* @__PURE__ */ jsxs("div", { "data-card-header-row": "", className: "flex items-center gap-ds-2", children: [
|
|
4661
|
+
checkbox,
|
|
4662
|
+
/* @__PURE__ */ jsx(Skeleton, { variant: "custom", className: "h-5 w-1/3" }),
|
|
4663
|
+
/* @__PURE__ */ jsx("div", { "data-header-actions": "", className: "contents", children: /* @__PURE__ */ jsx("div", { "data-gs-badge": "", className: "shrink-0", children: /* @__PURE__ */ jsx(Skeleton, { variant: "custom", className: "h-5 w-14 rounded-[var(--ds-radius-full)]" }) }) })
|
|
4664
|
+
] }),
|
|
5582
4665
|
/* @__PURE__ */ jsx(Skeleton, { variant: "custom", className: "h-3 w-full" }),
|
|
5583
4666
|
/* @__PURE__ */ jsx(Skeleton, { variant: "custom", className: "h-3 w-2/3" })
|
|
5584
4667
|
] }) })
|
|
@@ -5587,60 +4670,95 @@ var Card = forwardRef(function Card2({
|
|
|
5587
4670
|
}
|
|
5588
4671
|
);
|
|
5589
4672
|
});
|
|
5590
|
-
|
|
5591
|
-
const
|
|
5592
|
-
const
|
|
5593
|
-
|
|
5594
|
-
|
|
5595
|
-
|
|
5596
|
-
|
|
5597
|
-
|
|
5598
|
-
|
|
5599
|
-
|
|
5600
|
-
|
|
4673
|
+
function partsOf(children) {
|
|
4674
|
+
const parts = [];
|
|
4675
|
+
const open = (node) => Children.toArray(node).forEach((child) => {
|
|
4676
|
+
if (isValidElement(child) && child.type === Fragment$1) open(child.props.children);
|
|
4677
|
+
else if (child !== "") parts.push(child);
|
|
4678
|
+
});
|
|
4679
|
+
open(children);
|
|
4680
|
+
return parts;
|
|
4681
|
+
}
|
|
4682
|
+
function splitTitle(children) {
|
|
4683
|
+
const parts = partsOf(children);
|
|
4684
|
+
const at = parts.findIndex((p) => isValidElement(p) && p.type === CardTitle);
|
|
4685
|
+
if (at < 0) return { lead: [], title: parts[0] ?? null, rest: parts.slice(1) };
|
|
4686
|
+
return { lead: parts.slice(0, at), title: parts[at], rest: parts.slice(at + 1) };
|
|
4687
|
+
}
|
|
4688
|
+
var TITLE_FLOOR = "basis-[calc(var(--ds-font-size-lg)*4.5)]";
|
|
4689
|
+
var TITLE_ROW = cn(
|
|
4690
|
+
"flex flex-wrap items-start justify-end gap-x-ds-2 gap-y-ds-2 min-w-0 grow basis-0",
|
|
4691
|
+
"[&>[data-header-actions]>*]:order-5",
|
|
4692
|
+
"[&>[data-header-actions]>:has([data-gs-badge]):not(:has(a,button,input,select,textarea,[role=button],[tabindex]:not([tabindex='-1'])))]:order-2",
|
|
4693
|
+
"[&>[data-header-actions]>:has([aria-haspopup])]:order-6"
|
|
4694
|
+
);
|
|
4695
|
+
var CardHeader = forwardRef(function CardHeader2(allProps, ref) {
|
|
4696
|
+
const { className, children, actions, icon, menuItems, ...props } = allProps;
|
|
4697
|
+
const row = useContext(CardRowCtx);
|
|
4698
|
+
const [self] = useState(() => ({}));
|
|
4699
|
+
const register = row?.register;
|
|
4700
|
+
useLayoutEffect(() => register?.(self), [register, self]);
|
|
4701
|
+
const owns = !!row && row.owner === self;
|
|
4702
|
+
const iconBlock = icon ? (
|
|
4703
|
+
// the icon stays where it was, a tile above the title (28 of 66 headers with actions have one)
|
|
4704
|
+
/* @__PURE__ */ jsx("span", { className: "shrink-0 h-10 w-10 rounded-[var(--ds-radius-md)] bg-[var(--ds-bg-muted)] flex items-center justify-center", children: /* @__PURE__ */ jsx(Icon, { name: icon, size: 20, className: "text-[var(--ds-text-secondary)]" }) })
|
|
4705
|
+
) : null;
|
|
4706
|
+
const menu = menuItems ? /* @__PURE__ */ jsx(
|
|
4707
|
+
DropdownMenu,
|
|
4708
|
+
{
|
|
4709
|
+
trigger: /* @__PURE__ */ jsx(
|
|
4710
|
+
"button",
|
|
4711
|
+
{
|
|
4712
|
+
type: "button",
|
|
4713
|
+
"aria-label": "More actions",
|
|
4714
|
+
className: cn(
|
|
4715
|
+
"inline-flex items-center justify-center h-8 w-8 rounded-[var(--ds-radius-md)]",
|
|
4716
|
+
"text-[var(--ds-text-muted)] hover:text-[var(--ds-text-primary)] hover:bg-[var(--ds-bg-muted)]",
|
|
4717
|
+
"transition-colors duration-[var(--ds-transition-speed)]"
|
|
4718
|
+
),
|
|
4719
|
+
onClick: (e) => e.stopPropagation(),
|
|
4720
|
+
children: /* @__PURE__ */ jsx(Icon, { name: "more-horizontal", size: 16 })
|
|
4721
|
+
}
|
|
4722
|
+
),
|
|
4723
|
+
items: menuItems
|
|
4724
|
+
}
|
|
4725
|
+
) : null;
|
|
4726
|
+
const band = (order) => cn("shrink-0 self-start flex items-center", TITLE_LINE, order);
|
|
4727
|
+
const checkbox = owns && row.checkbox ? /* @__PURE__ */ jsx("span", { className: band("order-0"), children: row.checkbox }) : null;
|
|
4728
|
+
const check = owns && row.check ? /* @__PURE__ */ jsx("span", { "data-card-selection": "", className: band("order-4"), children: row.check }) : null;
|
|
4729
|
+
const menuPart = menu ? /* @__PURE__ */ jsx("span", { className: band("order-6"), children: menu }) : null;
|
|
4730
|
+
const { lead, title, rest } = splitTitle(children);
|
|
4731
|
+
const leadBlock = lead.length > 0 ? /* @__PURE__ */ jsx("div", { "data-card-lead": "", className: "flex flex-col space-y-ds-1.5 min-w-0 grow", children: lead }) : null;
|
|
4732
|
+
const topLine = iconBlock ?? leadBlock;
|
|
4733
|
+
const ownBlock = title !== null && !(isValidElement(title) && title.type === CardTitle);
|
|
4734
|
+
const actionsSlot = "actions" in allProps ? /* @__PURE__ */ jsx("div", { "data-header-actions": "", className: "contents", children: partsOf(actions).map((item, i) => /* @__PURE__ */ jsx("span", { className: cn("flex items-center shrink-0", TITLE_LINE), children: item }, isValidElement(item) && item.key !== null ? item.key : i)) }) : null;
|
|
4735
|
+
return /* @__PURE__ */ jsxs("div", { ref, "data-card-header": "", className: cn("flex flex-col px-ds-5 pt-ds-4 last:pb-ds-4 min-w-0", className), ...props, children: [
|
|
4736
|
+
topLine && /* @__PURE__ */ jsxs("div", { "data-card-icon-row": iconBlock ? "" : void 0, "data-card-lead-row": iconBlock ? void 0 : "", className: cn("flex items-start gap-ds-2", iconBlock ? "mb-ds-2.5" : "mb-ds-1.5"), children: [
|
|
4737
|
+
checkbox,
|
|
4738
|
+
topLine,
|
|
4739
|
+
iconBlock && /* @__PURE__ */ jsx("span", { "aria-hidden": "true", className: "grow -ml-ds-2" }),
|
|
4740
|
+
check,
|
|
4741
|
+
menuPart
|
|
4742
|
+
] }),
|
|
4743
|
+
iconBlock && leadBlock && /* @__PURE__ */ jsx("div", { className: "flex mb-ds-1.5", children: leadBlock }),
|
|
4744
|
+
/* @__PURE__ */ jsxs("div", { "data-card-header-row": "", className: "flex items-start gap-ds-2 min-w-0", children: [
|
|
4745
|
+
!topLine && checkbox,
|
|
4746
|
+
/* @__PURE__ */ jsxs("div", { "data-card-title-line": "", className: TITLE_ROW, children: [
|
|
4747
|
+
title && /* @__PURE__ */ jsx(
|
|
4748
|
+
"div",
|
|
5601
4749
|
{
|
|
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 })
|
|
4750
|
+
"data-card-title-row": "",
|
|
4751
|
+
className: cn("order-1 min-w-0 me-auto", TITLE_FLOOR, ownBlock ? "grow" : "grow-[999] max-w-max"),
|
|
4752
|
+
children: /* @__PURE__ */ jsx(HeaderRowCtx, { value: true, children: title })
|
|
5611
4753
|
}
|
|
5612
4754
|
),
|
|
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
|
|
4755
|
+
actionsSlot,
|
|
4756
|
+
!ownBlock && /* @__PURE__ */ jsx("span", { "aria-hidden": "true", className: "order-3 grow basis-0 -ml-ds-2" })
|
|
5637
4757
|
] }),
|
|
5638
|
-
|
|
5639
|
-
|
|
5640
|
-
|
|
5641
|
-
|
|
5642
|
-
iconBlock,
|
|
5643
|
-
children
|
|
4758
|
+
!topLine && check,
|
|
4759
|
+
!topLine && menuPart
|
|
4760
|
+
] }),
|
|
4761
|
+
rest.length > 0 && /* @__PURE__ */ jsx("div", { className: "flex flex-col space-y-ds-1.5 break-words mt-ds-1.5 min-w-0", children: rest })
|
|
5644
4762
|
] });
|
|
5645
4763
|
});
|
|
5646
4764
|
var cardLineClampClasses = {
|
|
@@ -5651,7 +4769,10 @@ var cardLineClampClasses = {
|
|
|
5651
4769
|
5: "line-clamp-5",
|
|
5652
4770
|
6: "line-clamp-6"
|
|
5653
4771
|
};
|
|
5654
|
-
var
|
|
4772
|
+
var WHOLE_ON_KEYBOARD = "[[data-card]:has(:focus-visible)_&]:whitespace-normal [[data-card]:has(:focus-visible)_&]:line-clamp-none";
|
|
4773
|
+
var CardTitle = forwardRef(function CardTitle2({ className, children, lines: linesProp, id, ...props }, forwardedRef) {
|
|
4774
|
+
const inHeaderRow = useContext(HeaderRowCtx);
|
|
4775
|
+
const lines = linesProp ?? (inHeaderRow ? 1 : 2);
|
|
5655
4776
|
const action = useContext(CardActionCtx);
|
|
5656
4777
|
const generatedId = useId();
|
|
5657
4778
|
const { ref: overflowRef, isTruncated } = useTextOverflow({ lines, disabled: lines === 0 });
|
|
@@ -5667,7 +4788,7 @@ var CardTitle = forwardRef(function CardTitle2({ className, children, lines = 2,
|
|
|
5667
4788
|
id: id ?? generatedId,
|
|
5668
4789
|
"data-card-title": "",
|
|
5669
4790
|
...lines === 1 ? { "data-title-one-line": "" } : {},
|
|
5670
|
-
className: cn(TITLE_TEXT, !action && lines > 0 && lineClampClass, action && lines === 1 && "text-ellipsis", className),
|
|
4791
|
+
className: cn(TITLE_TEXT, !action && lines > 0 && [lineClampClass, WHOLE_ON_KEYBOARD], action && lines === 1 && "text-ellipsis", className),
|
|
5671
4792
|
...props,
|
|
5672
4793
|
children: action ? (
|
|
5673
4794
|
// The card's action when the card holds controls of its own (Sprint 25.7): a real button, which a click
|
|
@@ -5684,14 +4805,13 @@ var CardTitle = forwardRef(function CardTitle2({ className, children, lines = 2,
|
|
|
5684
4805
|
"block w-full text-left cursor-pointer [text-overflow:inherit] focus-visible:outline-none disabled:cursor-not-allowed",
|
|
5685
4806
|
"after:absolute after:inset-0 after:rounded-[var(--ds-radius-md)] after:pointer-events-none focus-visible:after:shadow-[var(--ds-shadow-focus)]"
|
|
5686
4807
|
),
|
|
5687
|
-
children: /* @__PURE__ */ jsx("span", { ref: (node) => overflowRef(lines > 0 ? node : null), className: cn("block [text-overflow:inherit]", lines > 0 && lineClampClass), children })
|
|
4808
|
+
children: /* @__PURE__ */ jsx("span", { ref: (node) => overflowRef(lines > 0 ? node : null), className: cn("block [text-overflow:inherit]", lines > 0 && [lineClampClass, WHOLE_ON_KEYBOARD]), children })
|
|
5688
4809
|
}
|
|
5689
4810
|
)
|
|
5690
4811
|
) : children
|
|
5691
4812
|
}
|
|
5692
4813
|
);
|
|
5693
|
-
|
|
5694
|
-
return /* @__PURE__ */ jsx(Tooltip, { content: children, children: heading });
|
|
4814
|
+
return /* @__PURE__ */ jsx(Tooltip, { content: children, disabled: !isTruncated, children: heading });
|
|
5695
4815
|
});
|
|
5696
4816
|
var CardDescription = forwardRef(function CardDescription2({ className, children, lines = 2, ...props }, forwardedRef) {
|
|
5697
4817
|
const { ref: overflowRef, isTruncated } = useTextOverflow({ lines, disabled: lines === 0 });
|
|
@@ -5709,18 +4829,15 @@ var CardDescription = forwardRef(function CardDescription2({ className, children
|
|
|
5709
4829
|
children
|
|
5710
4830
|
}
|
|
5711
4831
|
);
|
|
5712
|
-
|
|
5713
|
-
return /* @__PURE__ */ jsx(Tooltip, { content: children, children: el });
|
|
4832
|
+
return /* @__PURE__ */ jsx(Tooltip, { content: children, disabled: !isTruncated, children: el });
|
|
5714
4833
|
});
|
|
5715
4834
|
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 });
|
|
4835
|
+
return /* @__PURE__ */ jsx("div", { ref, className: cn("flex-1 px-ds-5 py-ds-4", className), ...props, children });
|
|
5718
4836
|
});
|
|
5719
4837
|
var CardFooter = forwardRef(function CardFooter2({ className, children, ...props }, ref) {
|
|
5720
|
-
const isCheckable = useContext(CardCtx);
|
|
5721
4838
|
return (
|
|
5722
4839
|
// a footer that holds only buttons puts them at the end (round 11: a lone Save sat on the left); text keeps the start
|
|
5723
|
-
/* @__PURE__ */ jsx("div", { ref, className: cn("flex items-center gap-ds-2
|
|
4840
|
+
/* @__PURE__ */ jsx("div", { ref, className: cn("flex items-center gap-ds-2 px-ds-5 pb-ds-4 pt-ds-2 mt-auto min-w-0 [&:not(:has(>:not(button)))]:justify-end", className), ...props, children })
|
|
5724
4841
|
);
|
|
5725
4842
|
});
|
|
5726
4843
|
function TruncLabel({ children }) {
|
|
@@ -5836,6 +4953,9 @@ function DataList({ items, columns = 1, className }) {
|
|
|
5836
4953
|
);
|
|
5837
4954
|
}
|
|
5838
4955
|
var COUNT_FROM_PAGE = [
|
|
4956
|
+
// one card counts too: a lone card fell back to React's count, which counts components that draw nothing, and a grid
|
|
4957
|
+
// with one card inside another took the outer grid's count (the review of 30 September)
|
|
4958
|
+
"[&:has(>:only-child)]:[--gs-cards:1]",
|
|
5839
4959
|
"[&:has(>:nth-child(2):last-child)]:[--gs-cards:2]",
|
|
5840
4960
|
"[&:has(>:nth-child(3):last-child)]:[--gs-cards:3]",
|
|
5841
4961
|
"[&:has(>:nth-child(4):last-child)]:[--gs-cards:4]",
|
|
@@ -5848,6 +4968,7 @@ var COUNT_FROM_PAGE = [
|
|
|
5848
4968
|
"[&:has(>:nth-child(11):last-child)]:[--gs-cards:11]",
|
|
5849
4969
|
"[&:has(>:nth-child(12))]:[--gs-cards:12]"
|
|
5850
4970
|
].join(" ");
|
|
4971
|
+
var MIN_FROM_HEADERS = "[--gs-card-min:14rem] has-[[data-header-actions]]:[--gs-card-min:20rem]";
|
|
5851
4972
|
function countCards(children) {
|
|
5852
4973
|
let n = 0;
|
|
5853
4974
|
Children.forEach(children, (child) => {
|
|
@@ -5856,14 +4977,18 @@ function countCards(children) {
|
|
|
5856
4977
|
});
|
|
5857
4978
|
return n;
|
|
5858
4979
|
}
|
|
5859
|
-
function CardGrid({ minWidth
|
|
4980
|
+
function CardGrid({ minWidth, maxColumns = 4, compare = false, gap = "var(--ds-space-4)", fill: fill2 = true, className, style, children, ref, ...props }) {
|
|
5860
4981
|
const most = Math.max(1, Math.floor(maxColumns));
|
|
5861
|
-
const
|
|
5862
|
-
const
|
|
5863
|
-
const
|
|
4982
|
+
const drawn = "var(--gs-cards, var(--gs-cards-counted))";
|
|
4983
|
+
const min = "var(--gs-card-min)";
|
|
4984
|
+
const shareOf = (n) => `calc((100% - (${n} - 1) * var(--gs-card-gap)) / ${n})`;
|
|
4985
|
+
const collection = `max(min(${min}, 100%), ${shareOf(String(most))})`;
|
|
4986
|
+
const column = compare ? `max(${shareOf(drawn)}, min(100%, calc((${drawn} * ${min} + (${drawn} - 1) * var(--gs-card-gap) - 100%) * 999)))` : fill2 ? `max(${shareOf(`max(${drawn}, 2)`)}, ${collection})` : collection;
|
|
5864
4987
|
const template = {
|
|
5865
4988
|
"--gs-card-gap": gap,
|
|
5866
|
-
|
|
4989
|
+
// A2: a width passed wins; a comparison keeps 14rem; a collection's comes from its headers (MIN_FROM_HEADERS)
|
|
4990
|
+
...minWidth ? { "--gs-card-min": minWidth } : compare ? { "--gs-card-min": "14rem" } : {},
|
|
4991
|
+
...compare || fill2 ? { "--gs-cards-counted": Math.max(1, countCards(children)) } : {},
|
|
5867
4992
|
gap: "var(--gs-card-gap)",
|
|
5868
4993
|
gridTemplateColumns: `repeat(auto-fill, minmax(${column}, 1fr))`,
|
|
5869
4994
|
// a comparison's cards share their rows: the headers, the contents and the footers line up across the row
|
|
@@ -5876,7 +5001,8 @@ function CardGrid({ minWidth = "14rem", maxColumns = 4, compare = false, gap = "
|
|
|
5876
5001
|
"data-card-grid": compare ? "compare" : "",
|
|
5877
5002
|
className: cn(
|
|
5878
5003
|
"grid",
|
|
5879
|
-
compare &&
|
|
5004
|
+
!minWidth && !compare && MIN_FROM_HEADERS,
|
|
5005
|
+
(compare || fill2) && COUNT_FROM_PAGE,
|
|
5880
5006
|
// each card spans its three rows and lays its parts in them; anything else just fills them
|
|
5881
5007
|
compare && "[&>*]:row-span-3 [&>[data-card]]:grid [&>[data-card]]:grid-rows-subgrid [&>[data-card]]:gap-y-0",
|
|
5882
5008
|
className
|
|
@@ -6164,7 +5290,7 @@ var EDGE_FADE = 24;
|
|
|
6164
5290
|
var NONE = { left: false, right: false, vertical: false, gutterRight: 0, gutterBottom: 0 };
|
|
6165
5291
|
var same = (a, b) => a.left === b.left && a.right === b.right && a.vertical === b.vertical && a.gutterRight === b.gutterRight && a.gutterBottom === b.gutterBottom;
|
|
6166
5292
|
function useScrollEdges(options = {}) {
|
|
6167
|
-
const { enabled = true, fade = EDGE_FADE } = options;
|
|
5293
|
+
const { enabled = true, fade = EDGE_FADE, noFade } = options;
|
|
6168
5294
|
const elRef = useRef(null);
|
|
6169
5295
|
const observer = useRef(null);
|
|
6170
5296
|
const borders = useRef({ x: 0, y: 0 });
|
|
@@ -6196,9 +5322,11 @@ function useScrollEdges(options = {}) {
|
|
|
6196
5322
|
for (const child of Array.from(el.children)) o.observe(child);
|
|
6197
5323
|
observer.current = o;
|
|
6198
5324
|
}, [enabled, measure]);
|
|
6199
|
-
const
|
|
5325
|
+
const fadeLeft = state.left && !noFade?.left;
|
|
5326
|
+
const fadeRight = state.right && !noFade?.right;
|
|
5327
|
+
const shown = enabled && (fadeLeft || fadeRight);
|
|
6200
5328
|
const { gutterRight: gr, gutterBottom: gb } = state;
|
|
6201
|
-
const fadeLayer = `linear-gradient(to right, ${
|
|
5329
|
+
const fadeLayer = `linear-gradient(to right, ${fadeLeft ? `transparent 0, black ${fade}px` : "black 0"}, ${fadeRight ? `black calc(100% - ${gr + fade}px), transparent calc(100% - ${gr}px)` : "black 100%"})`;
|
|
6202
5330
|
const gutters = [gb > 0 && { size: `100% ${gb}px`, position: "0 100%" }, gr > 0 && { size: `${gr}px 100%`, position: "100% 0" }].filter(Boolean);
|
|
6203
5331
|
const mask = shown ? {
|
|
6204
5332
|
image: [fadeLayer, ...gutters.map(() => "linear-gradient(black, black)")].join(", "),
|
|
@@ -6211,18 +5339,54 @@ function useScrollEdges(options = {}) {
|
|
|
6211
5339
|
/** The scroller itself, for code that moves it. */
|
|
6212
5340
|
elRef,
|
|
6213
5341
|
measure,
|
|
6214
|
-
/** Content hides past a side edge: the scroller moves sideways, and its edges fade. */
|
|
6215
|
-
overflowing:
|
|
5342
|
+
/** Content hides past a side edge: the scroller moves sideways, and its edges fade (but those in `noFade`). */
|
|
5343
|
+
overflowing: enabled && (state.left || state.right),
|
|
6216
5344
|
/** It scrolls either way, sideways or up and down: a keyboard needs to reach it. */
|
|
6217
5345
|
scrollable: enabled && (state.left || state.right || state.vertical),
|
|
6218
5346
|
edges: { left: state.left, right: state.right },
|
|
6219
5347
|
/** For the scroller: `data-fade` names the faded edges ("left", "right" or "left right"), the style masks them. */
|
|
6220
5348
|
fadeProps: {
|
|
6221
|
-
"data-fade": shown ? [
|
|
5349
|
+
"data-fade": shown ? [fadeLeft && "left", fadeRight && "right"].filter(Boolean).join(" ") : void 0,
|
|
6222
5350
|
style: mask ? { maskImage: mask.image, WebkitMaskImage: mask.image, maskSize: mask.size, WebkitMaskSize: mask.size, maskPosition: mask.position, WebkitMaskPosition: mask.position, maskRepeat: "no-repeat", WebkitMaskRepeat: "no-repeat" } : void 0
|
|
6223
5351
|
}
|
|
6224
5352
|
};
|
|
6225
5353
|
}
|
|
5354
|
+
var HEADER_LAYOUT = {
|
|
5355
|
+
row: "flex flex-wrap items-start justify-between gap-ds-4",
|
|
5356
|
+
block: "flex flex-col space-y-ds-1.5 grow basis-1/2 break-words max-w-full has-[[data-title-one-line]]:min-w-0",
|
|
5357
|
+
titleLeads: "grow basis-1/2 max-w-max break-words has-[[data-title-one-line]]:min-w-0",
|
|
5358
|
+
floorOff: "min-w-0",
|
|
5359
|
+
actions: "flex items-center gap-ds-2 shrink-0 ml-auto",
|
|
5360
|
+
below: "mt-ds-1.5"
|
|
5361
|
+
};
|
|
5362
|
+
function useTitleFloorFits(rowRef, active) {
|
|
5363
|
+
const [fits, setFits] = useState(true);
|
|
5364
|
+
useLayoutEffect(() => {
|
|
5365
|
+
const row = rowRef.current;
|
|
5366
|
+
if (!active || !row) return;
|
|
5367
|
+
const measure = () => {
|
|
5368
|
+
const title = row.querySelector("h1, h2, h3, h4, h5, h6");
|
|
5369
|
+
if (!title) return;
|
|
5370
|
+
const width = title.style.width;
|
|
5371
|
+
title.style.width = "min-content";
|
|
5372
|
+
const longest = title.getBoundingClientRect().width;
|
|
5373
|
+
title.style.width = width;
|
|
5374
|
+
if (longest === 0) return;
|
|
5375
|
+
const next = longest <= row.clientWidth + 0.5;
|
|
5376
|
+
setFits((was) => was === next ? was : next);
|
|
5377
|
+
};
|
|
5378
|
+
measure();
|
|
5379
|
+
if (typeof ResizeObserver === "undefined") return;
|
|
5380
|
+
const observer = new ResizeObserver(measure);
|
|
5381
|
+
observer.observe(row);
|
|
5382
|
+
return () => observer.disconnect();
|
|
5383
|
+
}, [rowRef, active]);
|
|
5384
|
+
return fits;
|
|
5385
|
+
}
|
|
5386
|
+
function actionsAreBadges(actions) {
|
|
5387
|
+
const items = Children.toArray(actions);
|
|
5388
|
+
return items.length > 0 && items.every((item) => isValidElement(item) && (item.type === Fragment$1 ? actionsAreBadges(item.props.children) : item.type === Badge));
|
|
5389
|
+
}
|
|
6226
5390
|
function TruncCell({ children, lines }) {
|
|
6227
5391
|
const { ref, isTruncated } = useTextOverflow({ lines });
|
|
6228
5392
|
const clampClass = lines === 1 ? "truncate" : `line-clamp-${lines}`;
|
|
@@ -6237,6 +5401,95 @@ var FRAME_CLASSES = cn(
|
|
|
6237
5401
|
GLASS_SURFACE,
|
|
6238
5402
|
"bg-[var(--ds-bg-surface)]"
|
|
6239
5403
|
);
|
|
5404
|
+
var PINNED_BACKGROUND = "linear-gradient(var(--gs-row-tint, transparent), var(--gs-row-tint, transparent)), linear-gradient(var(--gs-pinned-surface), var(--gs-pinned-surface)), var(--gs-pinned-canvas)";
|
|
5405
|
+
var PINNED_LAYERS = cn(
|
|
5406
|
+
"[--gs-pinned-surface:var(--ds-bg-surface)] [--gs-pinned-canvas:var(--ds-bg-canvas)]",
|
|
5407
|
+
"supports-[color:oklch(from_red_l_c_h)]:[--gs-pinned-surface:oklch(from_var(--ds-bg-surface)_l_c_h_/_max(alpha,min(1,alpha*1000)))]",
|
|
5408
|
+
"supports-[color:oklch(from_red_l_c_h)]:[--gs-pinned-canvas:oklch(from_var(--ds-bg-canvas)_l_c_h_/_1)]"
|
|
5409
|
+
);
|
|
5410
|
+
var PIN_SHADOW = "oklch(0 0 0 / 0.18)";
|
|
5411
|
+
var ROW_CONTROL = `${FOCUSABLE}, label, [role="button"], [role="checkbox"], [role="switch"], [role="menuitem"], [role="link"]`;
|
|
5412
|
+
function clickIsRows(e) {
|
|
5413
|
+
const target = e.target;
|
|
5414
|
+
if (!(target instanceof Element) || !e.currentTarget.contains(target)) return false;
|
|
5415
|
+
const selection = typeof window !== "undefined" ? window.getSelection() : null;
|
|
5416
|
+
if (selection && !selection.isCollapsed && selection.anchorNode && e.currentTarget.contains(selection.anchorNode)) return false;
|
|
5417
|
+
const control = target.closest(ROW_CONTROL);
|
|
5418
|
+
return !control || control === e.currentTarget || !e.currentTarget.contains(control);
|
|
5419
|
+
}
|
|
5420
|
+
function sortableValue(v) {
|
|
5421
|
+
if (v === null || v === void 0 || v === "") return void 0;
|
|
5422
|
+
if (v instanceof Date) return v.getTime();
|
|
5423
|
+
if (typeof v === "string" || typeof v === "number") return v;
|
|
5424
|
+
if (typeof v === "boolean") return v ? 1 : 0;
|
|
5425
|
+
return isValidElement(v) || typeof v === "object" ? null : String(v);
|
|
5426
|
+
}
|
|
5427
|
+
var COLLATOR = new Intl.Collator(void 0, { numeric: true });
|
|
5428
|
+
function compareValues(a, b) {
|
|
5429
|
+
if (typeof a === "number" && typeof b === "number") return a - b;
|
|
5430
|
+
return COLLATOR.compare(String(a), String(b));
|
|
5431
|
+
}
|
|
5432
|
+
var UNIT_SCALE = {
|
|
5433
|
+
"": 1,
|
|
5434
|
+
"%": 1,
|
|
5435
|
+
b: 1,
|
|
5436
|
+
byte: 1,
|
|
5437
|
+
bytes: 1,
|
|
5438
|
+
kb: 1e3,
|
|
5439
|
+
kib: 1024,
|
|
5440
|
+
mb: 1e6,
|
|
5441
|
+
mib: 1024 ** 2,
|
|
5442
|
+
gb: 1e9,
|
|
5443
|
+
gib: 1024 ** 3,
|
|
5444
|
+
tb: 1e12,
|
|
5445
|
+
tib: 1024 ** 4,
|
|
5446
|
+
pb: 1e15,
|
|
5447
|
+
pib: 1024 ** 5,
|
|
5448
|
+
ms: 1,
|
|
5449
|
+
s: 1e3,
|
|
5450
|
+
sec: 1e3,
|
|
5451
|
+
min: 6e4,
|
|
5452
|
+
h: 36e5,
|
|
5453
|
+
hr: 36e5,
|
|
5454
|
+
hrs: 36e5,
|
|
5455
|
+
g: 1,
|
|
5456
|
+
kg: 1e3,
|
|
5457
|
+
m: 1,
|
|
5458
|
+
km: 1e3,
|
|
5459
|
+
"\xB0c": 1,
|
|
5460
|
+
"\xB0f": 1
|
|
5461
|
+
};
|
|
5462
|
+
function numberOf(text) {
|
|
5463
|
+
const m = /^\s*([-\u2212])?\s*[$€£¥]?\s*([-\u2212])?\s*(\d[\d,]*\.?\d*|\.\d+)\s*(%|°[CF]|[a-z]*)\s*$/i.exec(text);
|
|
5464
|
+
const scale = m ? UNIT_SCALE[m[4].toLowerCase()] : void 0;
|
|
5465
|
+
if (!m || scale === void 0) return void 0;
|
|
5466
|
+
const n = parseFloat(m[3].replace(/,/g, ""));
|
|
5467
|
+
return Number.isFinite(n) ? (m[1] || m[2] ? -1 : 1) * n * scale : void 0;
|
|
5468
|
+
}
|
|
5469
|
+
function timeOf(text) {
|
|
5470
|
+
const t = Date.parse(text);
|
|
5471
|
+
return Number.isNaN(t) ? void 0 : t;
|
|
5472
|
+
}
|
|
5473
|
+
function rowIdsOf(data, field) {
|
|
5474
|
+
const seen = /* @__PURE__ */ new Set();
|
|
5475
|
+
let repeated = null;
|
|
5476
|
+
const ids = data.map((row, index) => {
|
|
5477
|
+
const v = row[field];
|
|
5478
|
+
if (typeof v !== "string" && typeof v !== "number") return index;
|
|
5479
|
+
if (!seen.has(String(v))) {
|
|
5480
|
+
seen.add(String(v));
|
|
5481
|
+
return v;
|
|
5482
|
+
}
|
|
5483
|
+
repeated ??= String(v);
|
|
5484
|
+
return `${v}~${index}`;
|
|
5485
|
+
});
|
|
5486
|
+
return { ids, repeated };
|
|
5487
|
+
}
|
|
5488
|
+
function rowMarks(row, index, field, id) {
|
|
5489
|
+
const v = row[field];
|
|
5490
|
+
return typeof v === "string" || typeof v === "number" ? { "data-row-key": String(id) } : { "data-row-index": String(index) };
|
|
5491
|
+
}
|
|
5492
|
+
var idPart = (id) => String(id).replace(/\s+/g, "_");
|
|
6240
5493
|
function TableHeading({ title, description, actions, titleId, descriptionId, inset }) {
|
|
6241
5494
|
const heading = /* @__PURE__ */ jsx("h3", { id: titleId, className: TITLE_CLASSES, children: title });
|
|
6242
5495
|
const actionsBlock = actions ? /* @__PURE__ */ jsx("div", { className: HEADER_LAYOUT.actions, children: actions }) : null;
|
|
@@ -6258,8 +5511,10 @@ function TableHeading({ title, description, actions, titleId, descriptionId, ins
|
|
|
6258
5511
|
descriptionText(HEADER_LAYOUT.below)
|
|
6259
5512
|
] }) });
|
|
6260
5513
|
}
|
|
5514
|
+
var NO_PINS = { start: [], end: [], nameFits: false, frame: 0 };
|
|
5515
|
+
var samePins = (a, b) => a.nameFits === b.nameFits && a.frame === b.frame && a.start.join() === b.start.join() && a.end.join() === b.end.join();
|
|
6261
5516
|
function Table({
|
|
6262
|
-
columns,
|
|
5517
|
+
columns: columnsProp,
|
|
6263
5518
|
data,
|
|
6264
5519
|
className,
|
|
6265
5520
|
sortable,
|
|
@@ -6271,6 +5526,10 @@ function Table({
|
|
|
6271
5526
|
onSelectionChange,
|
|
6272
5527
|
expandable,
|
|
6273
5528
|
renderExpanded,
|
|
5529
|
+
rowKey = "id",
|
|
5530
|
+
expandedRows: expandedRowsProp,
|
|
5531
|
+
defaultExpandedRows,
|
|
5532
|
+
onExpandedChange,
|
|
6274
5533
|
density = "default",
|
|
6275
5534
|
stickyHeader = false,
|
|
6276
5535
|
striped = false,
|
|
@@ -6278,6 +5537,8 @@ function Table({
|
|
|
6278
5537
|
emptyState,
|
|
6279
5538
|
onRowClick,
|
|
6280
5539
|
mobileBreakpoint: mobileBreakpointProp,
|
|
5540
|
+
cardsBelow = CARDS_BELOW,
|
|
5541
|
+
pager,
|
|
6281
5542
|
title,
|
|
6282
5543
|
description,
|
|
6283
5544
|
actions,
|
|
@@ -6289,7 +5550,10 @@ function Table({
|
|
|
6289
5550
|
const descriptionId = `${headingId}-description`;
|
|
6290
5551
|
const [internalSortKey, setInternalSortKey] = useState(null);
|
|
6291
5552
|
const [internalSortDir, setInternalSortDir] = useState(null);
|
|
6292
|
-
const
|
|
5553
|
+
const columns = useMemo(
|
|
5554
|
+
() => [...columnsProp.filter((c) => c.pin === "start"), ...columnsProp.filter((c) => !c.pin), ...columnsProp.filter((c) => c.pin === "end")],
|
|
5555
|
+
[columnsProp]
|
|
5556
|
+
);
|
|
6293
5557
|
const isControlled = controlledSortKey !== void 0;
|
|
6294
5558
|
const sortKey = isControlled ? controlledSortKey : internalSortKey;
|
|
6295
5559
|
const sortDir = isControlled ? controlledSortDir ?? null : internalSortDir;
|
|
@@ -6309,6 +5573,7 @@ function Table({
|
|
|
6309
5573
|
nextKey = key;
|
|
6310
5574
|
nextDir = "asc";
|
|
6311
5575
|
}
|
|
5576
|
+
pager?.setPage(1);
|
|
6312
5577
|
if (onSortChange) {
|
|
6313
5578
|
onSortChange(nextKey, nextDir);
|
|
6314
5579
|
} else {
|
|
@@ -6316,139 +5581,348 @@ function Table({
|
|
|
6316
5581
|
setInternalSortDir(nextDir);
|
|
6317
5582
|
}
|
|
6318
5583
|
},
|
|
6319
|
-
[sortKey, sortDir, onSortChange]
|
|
5584
|
+
[sortKey, sortDir, onSortChange, pager]
|
|
5585
|
+
);
|
|
5586
|
+
const columnKeys = useMemo(() => columns.map((c) => c.key), [columns]);
|
|
5587
|
+
const inferredKinds = useMemo(() => inferColumnKinds(data, columnKeys), [data, columnKeys]);
|
|
5588
|
+
const kindOf = useCallback(
|
|
5589
|
+
(col) => col.kind ?? inferredKinds.get(col.key),
|
|
5590
|
+
[inferredKinds]
|
|
5591
|
+
);
|
|
5592
|
+
const sortColumn = sortKey ? columns.find((c) => c.key === sortKey) : void 0;
|
|
5593
|
+
const sortKind = sortColumn ? kindOf(sortColumn) : void 0;
|
|
5594
|
+
const { sortedAll, unsortable } = useMemo(() => {
|
|
5595
|
+
const indexed = data.map((row, i) => ({ row, originalIdx: i }));
|
|
5596
|
+
if (!sortKey || !sortDir) return { sortedAll: indexed, unsortable: null };
|
|
5597
|
+
const read = (row) => {
|
|
5598
|
+
if (sortColumn?.sortValue) return sortableValue(sortColumn.sortValue(row));
|
|
5599
|
+
const v = sortableValue(row[sortKey]);
|
|
5600
|
+
if (typeof v !== "string") return v;
|
|
5601
|
+
return (sortKind === "number" ? numberOf(v) : sortKind === "date" ? timeOf(v) : void 0) ?? v;
|
|
5602
|
+
};
|
|
5603
|
+
const valued = indexed.map((entry) => ({ ...entry, value: read(entry.row) }));
|
|
5604
|
+
const elements = valued.some((v) => v.value === null);
|
|
5605
|
+
const sorted = elements ? indexed : valued.sort((a, b) => {
|
|
5606
|
+
if (a.value === void 0 || b.value === void 0) return a.value === b.value ? 0 : a.value === void 0 ? 1 : -1;
|
|
5607
|
+
const cmp = compareValues(a.value, b.value);
|
|
5608
|
+
return sortDir === "asc" ? cmp : -cmp;
|
|
5609
|
+
});
|
|
5610
|
+
return { sortedAll: sorted, unsortable: elements ? sortKey : null };
|
|
5611
|
+
}, [data, sortKey, sortDir, sortColumn, sortKind]);
|
|
5612
|
+
const canSort = useMemo(() => {
|
|
5613
|
+
const can = /* @__PURE__ */ new Set();
|
|
5614
|
+
for (const col of columns) if (col.sortValue || data.every((row) => sortableValue(row[col.key]) !== null)) can.add(col.key);
|
|
5615
|
+
return can;
|
|
5616
|
+
}, [columns, data]);
|
|
5617
|
+
useEffect(() => {
|
|
5618
|
+
if (unsortable) warnOnce("Table", `the column "${unsortable}" is sortable, but its cells are elements, which can't be compared: give it a sortValue, (row) => the name, number or date it shows (data_display#1).`);
|
|
5619
|
+
}, [unsortable]);
|
|
5620
|
+
useEffect(() => {
|
|
5621
|
+
if (pager && data.length !== pager.totalItems) warnOnce("Table", `the pager counts ${pager.totalItems} rows but data holds ${data.length}: give the table and usePagination the same rows, every row of the list, and the table draws the pager's part (Sprint 25.13 A3).`);
|
|
5622
|
+
}, [pager, data.length]);
|
|
5623
|
+
const rangeStart = pager ? pager.range[0] : null;
|
|
5624
|
+
const rangeEnd2 = pager ? pager.range[1] : null;
|
|
5625
|
+
const drawn = useMemo(
|
|
5626
|
+
() => rangeStart === null ? sortedAll : rangeStart === 0 ? [] : sortedAll.slice(rangeStart - 1, rangeEnd2 ?? void 0),
|
|
5627
|
+
[sortedAll, rangeStart, rangeEnd2]
|
|
6320
5628
|
);
|
|
6321
|
-
const
|
|
6322
|
-
const aVal = a.row[sortKey];
|
|
6323
|
-
const bVal = b.row[sortKey];
|
|
6324
|
-
if (aVal == null || bVal == null) return 0;
|
|
6325
|
-
const cmp = String(aVal).localeCompare(String(bVal), void 0, { numeric: true });
|
|
6326
|
-
return sortDir === "asc" ? cmp : -cmp;
|
|
6327
|
-
}) : data.map((row, i) => ({ row, originalIdx: i }));
|
|
5629
|
+
const drawnStart = rangeStart ? rangeStart - 1 : 0;
|
|
6328
5630
|
const selectedSet = new Set(selectedRows);
|
|
6329
|
-
const
|
|
6330
|
-
const
|
|
5631
|
+
const drawnIdx = drawn.map((d) => d.originalIdx);
|
|
5632
|
+
const allSelected = drawnIdx.length > 0 && drawnIdx.every((i) => selectedSet.has(i));
|
|
5633
|
+
const someSelected = !allSelected && drawnIdx.some((i) => selectedSet.has(i));
|
|
6331
5634
|
const toggleAll = () => {
|
|
6332
|
-
|
|
6333
|
-
|
|
5635
|
+
const shown = new Set(drawnIdx);
|
|
5636
|
+
if (allSelected) onSelectionChange?.(selectedRows.filter((r) => !shown.has(r)));
|
|
5637
|
+
else onSelectionChange?.([...selectedRows.filter((r) => !shown.has(r)), ...drawnIdx]);
|
|
6334
5638
|
};
|
|
6335
5639
|
const toggleRow = (idx) => {
|
|
6336
5640
|
if (selectedSet.has(idx)) onSelectionChange?.(selectedRows.filter((r) => r !== idx));
|
|
6337
5641
|
else onSelectionChange?.([...selectedRows, idx]);
|
|
6338
5642
|
};
|
|
6339
|
-
const
|
|
6340
|
-
|
|
6341
|
-
|
|
6342
|
-
|
|
6343
|
-
|
|
6344
|
-
|
|
6345
|
-
});
|
|
5643
|
+
const expandControlled = expandedRowsProp !== void 0;
|
|
5644
|
+
const [ownExpanded, setOwnExpanded] = useState(defaultExpandedRows ?? []);
|
|
5645
|
+
const expanded = expandControlled ? expandedRowsProp : ownExpanded;
|
|
5646
|
+
const expandedSet = new Set(expanded.map(String));
|
|
5647
|
+
const { ids: rowIds, repeated } = useMemo(() => rowIdsOf(data, rowKey), [data, rowKey]);
|
|
5648
|
+
useEffect(() => {
|
|
5649
|
+
if (repeated !== null) warnOnce("Table", `two rows share the ${rowKey} "${repeated}": give each row its own, or name a field that is one (rowKey), so an opened row and focus stay on their row.`);
|
|
5650
|
+
}, [repeated, rowKey]);
|
|
5651
|
+
const idOf = (_row, index) => rowIds[index] ?? index;
|
|
5652
|
+
const marksOf = (row, index) => rowMarks(row, index, rowKey, idOf(row, index));
|
|
5653
|
+
const openedHere = useRef(null);
|
|
5654
|
+
const toggleExpand = (id) => {
|
|
5655
|
+
const opening = !expandedSet.has(String(id));
|
|
5656
|
+
const next = opening ? [...expanded, id] : expanded.filter((x) => String(x) !== String(id));
|
|
5657
|
+
openedHere.current = opening ? String(id) : null;
|
|
5658
|
+
if (!expandControlled) setOwnExpanded(next);
|
|
5659
|
+
onExpandedChange?.(next);
|
|
6346
5660
|
};
|
|
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
|
-
);
|
|
5661
|
+
const canOpenByClick = !!expandable && !!renderExpanded && !onRowClick;
|
|
6353
5662
|
const preferences = useShellPreferences();
|
|
6354
5663
|
const mobileBreakpoint = mobileBreakpointProp ?? preferences.tableToCardsBreakpoint ?? "md";
|
|
6355
|
-
const
|
|
6356
|
-
const {
|
|
5664
|
+
const narrowScreen = useBreakpoint(mobileBreakpoint);
|
|
5665
|
+
const { cards: isMobile, rootRef } = useCardsSwitch(narrowScreen, cardsBelow, title);
|
|
5666
|
+
const setRoot = useCallback((node) => {
|
|
5667
|
+
rootRef.current = node;
|
|
5668
|
+
if (typeof ref === "function") ref(node);
|
|
5669
|
+
else if (ref) ref.current = node;
|
|
5670
|
+
}, [ref, rootRef]);
|
|
5671
|
+
const tableRef = useRef(null);
|
|
5672
|
+
const [pins, setPins] = useState(NO_PINS);
|
|
5673
|
+
const lead = (selectable ? 1 : 0) + (expandable ? 1 : 0);
|
|
5674
|
+
const endCount = columns.filter((c) => c.pin === "end").length;
|
|
5675
|
+
const nameIndex = columns.length > endCount ? lead : -1;
|
|
5676
|
+
const { ref: scrollRef, elRef: scrollEl, measure: measureScroll, scrollable, edges, fadeProps } = useScrollEdges({
|
|
5677
|
+
enabled: !isMobile,
|
|
5678
|
+
noFade: { left: lead + (pins.nameFits ? 1 : 0) > 0, right: endCount > 0 }
|
|
5679
|
+
});
|
|
6357
5680
|
const [regionFocused, setRegionFocused] = useState(false);
|
|
5681
|
+
useLayoutEffect(() => {
|
|
5682
|
+
const table2 = tableRef.current;
|
|
5683
|
+
const scroller = scrollEl.current;
|
|
5684
|
+
if (!table2 || !scroller || isMobile) return;
|
|
5685
|
+
const measure = () => {
|
|
5686
|
+
const cells = Array.from(table2.querySelectorAll(":scope > thead > tr > th"));
|
|
5687
|
+
if (!cells.length) return;
|
|
5688
|
+
const widths = cells.map((c) => c.getBoundingClientRect().width);
|
|
5689
|
+
const start = [];
|
|
5690
|
+
let at = 0;
|
|
5691
|
+
for (let i = 0; i < lead; i++) {
|
|
5692
|
+
start.push(at);
|
|
5693
|
+
at += widths[i] ?? 0;
|
|
5694
|
+
}
|
|
5695
|
+
const nameWidth = nameIndex >= 0 ? widths[nameIndex] ?? 0 : 0;
|
|
5696
|
+
const end = [];
|
|
5697
|
+
let fromRight = 0;
|
|
5698
|
+
for (let i = cells.length - 1; i >= cells.length - endCount; i--) {
|
|
5699
|
+
end.unshift(fromRight);
|
|
5700
|
+
fromRight += widths[i] ?? 0;
|
|
5701
|
+
}
|
|
5702
|
+
const frame = scroller.clientWidth;
|
|
5703
|
+
const nameFits = nameIndex >= 0 && frame > 0 && at + nameWidth + fromRight <= frame / 2;
|
|
5704
|
+
if (nameFits) start.push(at);
|
|
5705
|
+
const next = { start, end, nameFits, frame };
|
|
5706
|
+
setPins((prev) => samePins(prev, next) ? prev : next);
|
|
5707
|
+
};
|
|
5708
|
+
measure();
|
|
5709
|
+
if (typeof ResizeObserver === "undefined") return;
|
|
5710
|
+
const observer = new ResizeObserver(measure);
|
|
5711
|
+
observer.observe(table2);
|
|
5712
|
+
observer.observe(scroller);
|
|
5713
|
+
return () => observer.disconnect();
|
|
5714
|
+
}, [isMobile, lead, endCount, nameIndex, scrollEl, columns, drawn.length]);
|
|
5715
|
+
const pinnedStart = lead + (pins.nameFits ? 1 : 0);
|
|
5716
|
+
const pinStyle = (position, total) => {
|
|
5717
|
+
if (position < pinnedStart && pins.start[position] !== void 0) {
|
|
5718
|
+
const inner = position === pinnedStart - 1;
|
|
5719
|
+
return { position: "sticky", left: pins.start[position], zIndex: 1, background: PINNED_BACKGROUND, boxShadow: inner && edges.left ? `6px 0 6px -6px ${PIN_SHADOW}` : void 0 };
|
|
5720
|
+
}
|
|
5721
|
+
const fromEnd = total - 1 - position;
|
|
5722
|
+
if (fromEnd < endCount && pins.end[endCount - 1 - fromEnd] !== void 0) {
|
|
5723
|
+
const inner = fromEnd === endCount - 1;
|
|
5724
|
+
return { position: "sticky", right: pins.end[endCount - 1 - fromEnd], zIndex: 1, background: PINNED_BACKGROUND, boxShadow: inner && edges.right ? `-6px 0 6px -6px ${PIN_SHADOW}` : void 0 };
|
|
5725
|
+
}
|
|
5726
|
+
return void 0;
|
|
5727
|
+
};
|
|
5728
|
+
const fade = fadeProps;
|
|
5729
|
+
const [renderedKinds, setRenderedKinds] = useState(() => /* @__PURE__ */ new Map());
|
|
5730
|
+
useLayoutEffect(() => {
|
|
5731
|
+
const table2 = tableRef.current;
|
|
5732
|
+
if (!table2 || isMobile) return;
|
|
5733
|
+
const next = /* @__PURE__ */ new Map();
|
|
5734
|
+
for (const col of columns) {
|
|
5735
|
+
if (kindOf(col)) continue;
|
|
5736
|
+
const texts = Array.from(table2.querySelectorAll(`:scope > tbody > tr > td[data-col="${CSS.escape(col.key)}"]`)).slice(0, 50).map((td) => td.textContent ?? "");
|
|
5737
|
+
const kind = texts.length ? kindOfRenderedText(texts) : void 0;
|
|
5738
|
+
if (kind) next.set(col.key, kind);
|
|
5739
|
+
}
|
|
5740
|
+
setRenderedKinds((prev) => prev.size === next.size && [...next].every(([k, v]) => prev.get(k) === v) ? prev : next);
|
|
5741
|
+
}, [columns, kindOf, drawn, isMobile]);
|
|
5742
|
+
const expandedKey = expanded.map(String).join("");
|
|
5743
|
+
const shownBefore = useRef(/* @__PURE__ */ new Set());
|
|
5744
|
+
const pendingScroll = useRef(null);
|
|
5745
|
+
const scrollToRow = useCallback((key) => {
|
|
5746
|
+
const row = rootRef.current?.querySelector(`[data-row-key="${CSS.escape(key)}"], [data-row-index="${CSS.escape(key)}"]`);
|
|
5747
|
+
if (row && typeof row.scrollIntoView === "function") row.scrollIntoView({ block: "nearest" });
|
|
5748
|
+
}, [rootRef]);
|
|
5749
|
+
useEffect(() => {
|
|
5750
|
+
const now = new Set(expanded.map(String));
|
|
5751
|
+
const added = [...now].filter((k) => !shownBefore.current.has(k) && k !== openedHere.current);
|
|
5752
|
+
shownBefore.current = now;
|
|
5753
|
+
openedHere.current = null;
|
|
5754
|
+
if (!expandControlled) return;
|
|
5755
|
+
const key = added[added.length - 1];
|
|
5756
|
+
if (key === void 0) return;
|
|
5757
|
+
if (pager) {
|
|
5758
|
+
const position = sortedAll.findIndex((r) => String(idOf(r.row, r.originalIdx)) === key);
|
|
5759
|
+
if (position >= 0 && (position < drawnStart || position >= drawnStart + drawn.length)) {
|
|
5760
|
+
pendingScroll.current = key;
|
|
5761
|
+
pager.setPage(Math.floor(position / pager.pageSize) + 1);
|
|
5762
|
+
return;
|
|
5763
|
+
}
|
|
5764
|
+
}
|
|
5765
|
+
scrollToRow(key);
|
|
5766
|
+
}, [expandedKey]);
|
|
5767
|
+
useEffect(() => {
|
|
5768
|
+
const key = pendingScroll.current;
|
|
5769
|
+
if (!key || !drawn.some((r) => String(idOf(r.row, r.originalIdx)) === key)) return;
|
|
5770
|
+
pendingScroll.current = null;
|
|
5771
|
+
scrollToRow(key);
|
|
5772
|
+
}, [drawnStart, drawn.length, scrollToRow]);
|
|
6358
5773
|
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",
|
|
5774
|
+
const titledCards = (body) => /* @__PURE__ */ jsxs("div", { ref: listRoot, "data-ds-list": "", "data-gs": "table", className: cn("flex flex-col", listClass), onFocus: noteFocus, onBlur: forgetFocus, children: [
|
|
6360
5775
|
cardHeading,
|
|
6361
5776
|
body
|
|
6362
5777
|
] });
|
|
5778
|
+
const control = pager && !loading && data.length > 0 ? /* @__PURE__ */ jsx(Pagination, { ...pager.props }) : null;
|
|
5779
|
+
const listRoot = control ? void 0 : setRoot;
|
|
5780
|
+
const listClass = control ? void 0 : className;
|
|
5781
|
+
const withControl = (list) => control ? /* @__PURE__ */ jsxs("div", { ref: setRoot, "data-gs-paged": "", className: cn("flex flex-col min-w-0", className), children: [
|
|
5782
|
+
list,
|
|
5783
|
+
control
|
|
5784
|
+
] }) : list;
|
|
5785
|
+
const focusWas = useRef(null);
|
|
5786
|
+
const noteFocus = (e) => {
|
|
5787
|
+
const target = e.target;
|
|
5788
|
+
const row = target.closest("[data-row-key], [data-row-index]");
|
|
5789
|
+
if (!row) {
|
|
5790
|
+
focusWas.current = null;
|
|
5791
|
+
return;
|
|
5792
|
+
}
|
|
5793
|
+
const control2 = target === row ? null : target.getAttribute("aria-labelledby") ?? target.getAttribute("aria-label") ?? target.textContent;
|
|
5794
|
+
focusWas.current = { row: row.hasAttribute("data-row-key") ? `[data-row-key="${CSS.escape(row.getAttribute("data-row-key"))}"]` : `[data-row-index="${CSS.escape(row.getAttribute("data-row-index"))}"]`, control: control2 };
|
|
5795
|
+
};
|
|
5796
|
+
const forgetFocus = (e) => {
|
|
5797
|
+
const node = e.target;
|
|
5798
|
+
queueMicrotask(() => {
|
|
5799
|
+
if (node.isConnected && !rootRef.current?.contains(document.activeElement)) focusWas.current = null;
|
|
5800
|
+
});
|
|
5801
|
+
};
|
|
5802
|
+
useLayoutEffect(() => {
|
|
5803
|
+
const was = focusWas.current;
|
|
5804
|
+
const active = document.activeElement;
|
|
5805
|
+
if (!was || active && active !== document.body) return;
|
|
5806
|
+
const row = rootRef.current?.querySelector(was.row);
|
|
5807
|
+
if (!row) return;
|
|
5808
|
+
const controls = Array.from(row.querySelectorAll(FOCUSABLE));
|
|
5809
|
+
const same2 = was.control === null ? null : controls.find((el) => (el.getAttribute("aria-labelledby") ?? el.getAttribute("aria-label") ?? el.textContent) === was.control);
|
|
5810
|
+
(same2 ?? (row.tabIndex >= 0 ? row : controls[0]))?.focus({ preventScroll: true });
|
|
5811
|
+
}, [isMobile, rootRef]);
|
|
6363
5812
|
if (isMobile) {
|
|
6364
5813
|
if (loading) {
|
|
6365
5814
|
if (title) return titledCards(/* @__PURE__ */ jsx("div", { className: "flex items-center justify-center py-ds-10", children: /* @__PURE__ */ jsx(Spinner, { label: "Loading table data" }) }));
|
|
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" }) });
|
|
5815
|
+
return /* @__PURE__ */ jsx("div", { ref: setRoot, "data-ds-list": "", "data-gs": "table", className: cn("flex items-center justify-center py-ds-10", className), children: /* @__PURE__ */ jsx(Spinner, { label: "Loading table data" }) });
|
|
6367
5816
|
}
|
|
6368
5817
|
if (data.length === 0 && emptyState) {
|
|
6369
5818
|
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 });
|
|
5819
|
+
return /* @__PURE__ */ jsx("div", { ref: setRoot, "data-ds-list": "", "data-gs": "table", className: cn("py-ds-10 text-center text-sm text-[var(--ds-text-muted)]", className), children: emptyState });
|
|
6371
5820
|
}
|
|
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
|
-
|
|
5821
|
+
const cards = /* @__PURE__ */ jsx(TableCardCtx, { value: true, children: /* @__PURE__ */ jsxs("div", { ref: title ? void 0 : listRoot, "data-ds-list": title ? void 0 : "", "data-gs": title ? void 0 : "table", className: cn("flex flex-col gap-ds-3 overflow-y-auto", title ? "min-h-0" : listClass), onFocus: title ? void 0 : noteFocus, onBlur: title ? void 0 : forgetFocus, children: [
|
|
5822
|
+
selectable && /* @__PURE__ */ jsx("span", { hidden: true, id: `${headingId}-select`, children: "Select" }),
|
|
5823
|
+
drawn.map(({ row, originalIdx }) => {
|
|
5824
|
+
const isSelected = selectedSet.has(originalIdx);
|
|
5825
|
+
const id = idOf(row, originalIdx);
|
|
5826
|
+
return /* @__PURE__ */ jsxs(
|
|
5827
|
+
"div",
|
|
5828
|
+
{
|
|
5829
|
+
"data-row": "",
|
|
5830
|
+
...marksOf(row, originalIdx),
|
|
5831
|
+
className: cn(
|
|
5832
|
+
"border-[length:var(--ds-border-width)] border-[var(--ds-border-subtle)]",
|
|
5833
|
+
"rounded-[var(--ds-radius-md)] bg-[var(--ds-bg-surface)]",
|
|
5834
|
+
"p-ds-4 space-y-ds-3",
|
|
5835
|
+
isSelected && ACTIVE_RING,
|
|
5836
|
+
onRowClick && "cursor-pointer hover:bg-[var(--ds-bg-muted)] focus-visible:outline-none focus-visible:shadow-[var(--ds-shadow-focus)]"
|
|
5837
|
+
),
|
|
5838
|
+
onClick: onRowClick ? (e) => {
|
|
5839
|
+
if (clickIsRows(e)) onRowClick(row, originalIdx);
|
|
5840
|
+
} : void 0,
|
|
5841
|
+
tabIndex: onRowClick ? 0 : void 0,
|
|
5842
|
+
onKeyDown: onRowClick ? (e) => {
|
|
5843
|
+
if (e.target !== e.currentTarget) return;
|
|
5844
|
+
if (e.key === "Enter" || e.key === " ") {
|
|
5845
|
+
e.preventDefault();
|
|
5846
|
+
onRowClick(row, originalIdx);
|
|
5847
|
+
}
|
|
5848
|
+
} : void 0,
|
|
5849
|
+
children: [
|
|
5850
|
+
selectable && // "Select" and the row's name, as in the table (T15)
|
|
5851
|
+
/* @__PURE__ */ jsx(Checkbox, { checked: isSelected, onChange: () => toggleRow(originalIdx), "aria-labelledby": nameIndex >= 0 ? `${headingId}-select ${headingId}-card-name-${idPart(id)}` : `${headingId}-select` }),
|
|
5852
|
+
columns.map((col, c) => /* @__PURE__ */ jsxs("div", { className: "flex justify-between gap-ds-2 text-sm", children: [
|
|
5853
|
+
/* @__PURE__ */ jsx("span", { className: "shrink-0 text-[var(--ds-text-secondary)] font-medium text-xs uppercase tracking-wider", children: col.header }),
|
|
5854
|
+
/* @__PURE__ */ jsx(CardValue, { value: row[col.key], id: lead + c === nameIndex ? `${headingId}-card-name-${idPart(id)}` : void 0 })
|
|
5855
|
+
] }, col.key)),
|
|
5856
|
+
expandable && renderExpanded && /* @__PURE__ */ jsx("div", { className: "pt-ds-2 border-t-[length:var(--ds-divider-width)] border-[var(--ds-border-subtle)] text-sm text-[var(--ds-text-secondary)]", children: renderExpanded(row, originalIdx) })
|
|
5857
|
+
]
|
|
5858
|
+
},
|
|
5859
|
+
String(id)
|
|
5860
|
+
);
|
|
5861
|
+
})
|
|
5862
|
+
] }) });
|
|
5863
|
+
return withControl(title ? titledCards(cards) : cards);
|
|
6407
5864
|
}
|
|
6408
|
-
const
|
|
6409
|
-
|
|
6410
|
-
|
|
5865
|
+
const cellCount = columns.length + lead;
|
|
5866
|
+
const table = /* @__PURE__ */ jsxs("table", { ref: tableRef, className: cn("w-full text-sm", PINNED_LAYERS), ...title ? { "aria-labelledby": titleId, "aria-describedby": description ? descriptionId : void 0 } : ariaLabel ? { "aria-label": ariaLabel } : {}, children: [
|
|
5867
|
+
/* @__PURE__ */ jsx("thead", { className: cn("bg-[var(--ds-bg-muted)]", stickyHeader && "sticky top-0 z-10"), children: /* @__PURE__ */ jsxs("tr", { className: "border-b-[length:var(--ds-divider-width)] border-[var(--ds-border-subtle)] [--gs-row-tint:var(--ds-bg-muted)]", children: [
|
|
5868
|
+
selectable && /* @__PURE__ */ jsx("th", { className: cn("w-10", density === "compact" ? "px-ds-2 py-ds-2" : "px-ds-3 py-ds-3"), style: pinStyle(0, cellCount), children: /* @__PURE__ */ jsx(
|
|
6411
5869
|
Checkbox,
|
|
6412
5870
|
{
|
|
6413
5871
|
checked: allSelected,
|
|
6414
5872
|
indeterminate: someSelected,
|
|
6415
|
-
onChange: toggleAll
|
|
5873
|
+
onChange: toggleAll,
|
|
5874
|
+
"aria-labelledby": `${headingId}-select-all`
|
|
6416
5875
|
}
|
|
6417
5876
|
) }),
|
|
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;
|
|
5877
|
+
expandable && /* @__PURE__ */ jsx("th", { className: cn("w-8", density === "compact" ? "px-ds-1 py-ds-2" : "px-ds-2 py-ds-3"), style: pinStyle(selectable ? 1 : 0, cellCount) }),
|
|
5878
|
+
columns.map((col, c) => {
|
|
5879
|
+
const isSortable = col.header.trim() !== "" && (col.sortable ?? (!!sortable && canSort.has(col.key)));
|
|
5880
|
+
const isActiveSort = sortKey === col.key && !!sortDir && unsortable !== col.key;
|
|
6422
5881
|
const headerKind = kindOf(col);
|
|
6423
5882
|
const headerAlign = col.align ?? (headerKind === "number" ? "right" : "left");
|
|
6424
5883
|
const shrink = (headerKind === "number" || headerKind === "date") && !col.maxWidth;
|
|
5884
|
+
const style = { maxWidth: col.maxWidth, width: col.width, minWidth: col.minWidth, ...pinStyle(lead + c, cellCount) };
|
|
6425
5885
|
return /* @__PURE__ */ jsx(
|
|
6426
5886
|
"th",
|
|
6427
5887
|
{
|
|
5888
|
+
"aria-sort": isSortable && isActiveSort ? sortDir === "asc" ? "ascending" : "descending" : void 0,
|
|
6428
5889
|
className: cn(
|
|
6429
5890
|
density === "compact" ? "px-ds-3 py-ds-2" : "px-ds-4 py-ds-3",
|
|
6430
5891
|
shrink && "w-px whitespace-nowrap",
|
|
6431
5892
|
"font-[var(--ds-weight-heading)] text-[var(--ds-text-secondary)]",
|
|
6432
5893
|
"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)]"
|
|
5894
|
+
headerAlign === "right" ? "text-right" : headerAlign === "center" ? "text-center" : "text-left"
|
|
6435
5895
|
),
|
|
6436
|
-
style
|
|
6437
|
-
|
|
6438
|
-
|
|
6439
|
-
|
|
6440
|
-
|
|
6441
|
-
Icon,
|
|
5896
|
+
style,
|
|
5897
|
+
children: isSortable ? (
|
|
5898
|
+
// A47: a button with the column's name, reached with Tab and pressed with Enter or Space
|
|
5899
|
+
/* @__PURE__ */ jsxs(
|
|
5900
|
+
"button",
|
|
6442
5901
|
{
|
|
6443
|
-
|
|
6444
|
-
|
|
5902
|
+
type: "button",
|
|
5903
|
+
onClick: () => handleSort(col.key),
|
|
6445
5904
|
className: cn(
|
|
6446
|
-
"
|
|
6447
|
-
|
|
6448
|
-
|
|
5905
|
+
"inline-flex items-center gap-ds-1 uppercase tracking-wider cursor-pointer select-none",
|
|
5906
|
+
"[font:inherit] text-inherit hover:text-[var(--ds-text-primary)]",
|
|
5907
|
+
"rounded-[var(--ds-radius-sm)] focus-visible:outline-none focus-visible:shadow-[var(--ds-shadow-focus)]"
|
|
5908
|
+
),
|
|
5909
|
+
children: [
|
|
5910
|
+
col.header,
|
|
5911
|
+
/* @__PURE__ */ jsx(
|
|
5912
|
+
Icon,
|
|
5913
|
+
{
|
|
5914
|
+
name: "chevron-right",
|
|
5915
|
+
size: 12,
|
|
5916
|
+
className: cn(
|
|
5917
|
+
"transition-transform",
|
|
5918
|
+
!isActiveSort ? "invisible" : sortDir === "asc" ? "-rotate-90" : "rotate-90"
|
|
5919
|
+
)
|
|
5920
|
+
}
|
|
5921
|
+
)
|
|
5922
|
+
]
|
|
6449
5923
|
}
|
|
6450
5924
|
)
|
|
6451
|
-
|
|
5925
|
+
) : /* @__PURE__ */ jsx("span", { className: "inline-flex items-center gap-ds-1", children: col.header })
|
|
6452
5926
|
},
|
|
6453
5927
|
col.key
|
|
6454
5928
|
);
|
|
@@ -6457,31 +5931,44 @@ function Table({
|
|
|
6457
5931
|
/* @__PURE__ */ jsx("tbody", { children: loading ? /* @__PURE__ */ jsx("tr", { children: /* @__PURE__ */ jsx(
|
|
6458
5932
|
"td",
|
|
6459
5933
|
{
|
|
6460
|
-
colSpan:
|
|
5934
|
+
colSpan: cellCount,
|
|
6461
5935
|
className: "px-ds-4 py-ds-10 text-center",
|
|
6462
5936
|
children: /* @__PURE__ */ jsx(Spinner, { label: "Loading table data" })
|
|
6463
5937
|
}
|
|
6464
5938
|
) }) : data.length === 0 && emptyState ? /* @__PURE__ */ jsx("tr", { children: /* @__PURE__ */ jsx(
|
|
6465
5939
|
"td",
|
|
6466
5940
|
{
|
|
6467
|
-
colSpan:
|
|
5941
|
+
colSpan: cellCount,
|
|
6468
5942
|
className: "px-ds-4 py-ds-10 text-center text-sm text-[var(--ds-text-muted)]",
|
|
6469
5943
|
children: emptyState
|
|
6470
5944
|
}
|
|
6471
|
-
) }) :
|
|
5945
|
+
) }) : drawn.map(({ row, originalIdx }, i) => {
|
|
6472
5946
|
const isSelected = selectedSet.has(originalIdx);
|
|
6473
|
-
const
|
|
5947
|
+
const id = idOf(row, originalIdx);
|
|
5948
|
+
const isExpanded = expandedSet.has(String(id));
|
|
5949
|
+
const clickable = !!onRowClick || canOpenByClick;
|
|
6474
5950
|
return /* @__PURE__ */ jsxs(Fragment$1, { children: [
|
|
6475
5951
|
/* @__PURE__ */ jsxs(
|
|
6476
5952
|
"tr",
|
|
6477
5953
|
{
|
|
5954
|
+
...marksOf(row, originalIdx),
|
|
6478
5955
|
className: cn(
|
|
6479
5956
|
"border-b-[length:var(--ds-divider-width)] border-[var(--ds-border-subtle)] last:border-b-0",
|
|
6480
|
-
|
|
6481
|
-
|
|
6482
|
-
|
|
5957
|
+
// the row's background and its tint change together, so its pinned cells and the rest fade as one
|
|
5958
|
+
// (roots.css registers --gs-row-tint as a colour so it can)
|
|
5959
|
+
"transition-[background-color,--gs-row-tint]",
|
|
5960
|
+
// the row's tint, as a variable too, so its pinned cells draw it over their solid ground (A35)
|
|
5961
|
+
isSelected ? "bg-[var(--ds-accent-subtle)] [--gs-row-tint:var(--ds-accent-subtle)]" : striped && i % 2 === 1 ? "bg-[var(--ds-bg-muted)]/50 [--gs-row-tint:color-mix(in_oklab,var(--ds-bg-muted)_50%,transparent)]" : "hover:bg-[var(--ds-bg-muted)] hover:[--gs-row-tint:var(--ds-bg-muted)]",
|
|
5962
|
+
clickable && "cursor-pointer",
|
|
5963
|
+
// an outline inside the row: it shows over the pinned cells, whose solid ground hid the inset
|
|
5964
|
+
// shadow the row drew before (the review of 30 September)
|
|
5965
|
+
onRowClick && "focus-visible:outline-2 focus-visible:-outline-offset-2 focus-visible:outline-[var(--ds-border-focus)]"
|
|
6483
5966
|
),
|
|
6484
|
-
onClick:
|
|
5967
|
+
onClick: clickable ? (e) => {
|
|
5968
|
+
if (!clickIsRows(e)) return;
|
|
5969
|
+
if (onRowClick) onRowClick(row, originalIdx);
|
|
5970
|
+
else toggleExpand(id);
|
|
5971
|
+
} : void 0,
|
|
6485
5972
|
tabIndex: onRowClick ? 0 : void 0,
|
|
6486
5973
|
onKeyDown: onRowClick ? (e) => {
|
|
6487
5974
|
if (e.target !== e.currentTarget) return;
|
|
@@ -6491,15 +5978,15 @@ function Table({
|
|
|
6491
5978
|
}
|
|
6492
5979
|
} : void 0,
|
|
6493
5980
|
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(
|
|
5981
|
+
selectable && /* @__PURE__ */ jsx("td", { className: cn("w-10", density === "compact" ? "px-ds-2 py-ds-2" : "px-ds-3 py-ds-3"), style: pinStyle(0, cellCount), children: /* @__PURE__ */ jsx(Checkbox, { checked: isSelected, onChange: () => toggleRow(originalIdx), "aria-labelledby": nameIndex >= 0 ? `${headingId}-select ${headingId}-name-${idPart(id)}` : `${headingId}-select` }) }),
|
|
5982
|
+
expandable && /* @__PURE__ */ jsx("td", { className: cn("w-8", density === "compact" ? "px-ds-1 py-ds-2" : "px-ds-2 py-ds-3"), style: pinStyle(selectable ? 1 : 0, cellCount), children: /* @__PURE__ */ jsx(
|
|
6496
5983
|
"button",
|
|
6497
5984
|
{
|
|
6498
5985
|
type: "button",
|
|
6499
|
-
onClick: () => toggleExpand(
|
|
5986
|
+
onClick: () => toggleExpand(id),
|
|
6500
5987
|
className: "text-[var(--ds-text-muted)] hover:text-[var(--ds-text-primary)] cursor-pointer",
|
|
6501
5988
|
"aria-expanded": isExpanded,
|
|
6502
|
-
"aria-label": "
|
|
5989
|
+
...nameIndex >= 0 ? { "aria-labelledby": `${headingId}-details ${headingId}-name-${idPart(id)}` } : { "aria-label": "Details" },
|
|
6503
5990
|
children: /* @__PURE__ */ jsx(
|
|
6504
5991
|
Icon,
|
|
6505
5992
|
{
|
|
@@ -6510,12 +5997,13 @@ function Table({
|
|
|
6510
5997
|
)
|
|
6511
5998
|
}
|
|
6512
5999
|
) }),
|
|
6513
|
-
columns.map((col) => {
|
|
6000
|
+
columns.map((col, c) => {
|
|
6514
6001
|
const truncLines = col.truncate === true ? 1 : col.truncate ? col.truncate.lines : 0;
|
|
6515
6002
|
const kind = kindOf(col);
|
|
6516
6003
|
const alignClass = col.align ? col.align === "right" ? "text-right" : col.align === "center" ? "text-center" : "text-left" : kind === "number" ? "text-right" : "text-left";
|
|
6517
6004
|
const cellContent = row[col.key];
|
|
6518
6005
|
const shrink = (kind === "number" || kind === "date") && !col.maxWidth;
|
|
6006
|
+
const whole = !kind && renderedKinds.has(col.key);
|
|
6519
6007
|
let inner;
|
|
6520
6008
|
if (truncLines > 0) {
|
|
6521
6009
|
inner = /* @__PURE__ */ jsx(TruncCell, { lines: truncLines, children: cellContent });
|
|
@@ -6531,13 +6019,17 @@ function Table({
|
|
|
6531
6019
|
return /* @__PURE__ */ jsx(
|
|
6532
6020
|
"td",
|
|
6533
6021
|
{
|
|
6022
|
+
id: lead > 0 && lead + c === nameIndex ? `${headingId}-name-${idPart(id)}` : void 0,
|
|
6023
|
+
"data-col": col.key,
|
|
6534
6024
|
className: cn(
|
|
6535
6025
|
density === "compact" ? "px-ds-3 py-ds-2" : "px-ds-4 py-ds-3",
|
|
6536
6026
|
"text-[var(--ds-text-primary)]",
|
|
6537
6027
|
alignClass,
|
|
6538
|
-
shrink && "w-px whitespace-nowrap"
|
|
6028
|
+
shrink && "w-px whitespace-nowrap",
|
|
6029
|
+
whole && "whitespace-nowrap",
|
|
6030
|
+
kind === "identifier" && "[overflow-wrap:anywhere]"
|
|
6539
6031
|
),
|
|
6540
|
-
style: col.maxWidth || col.width || col.minWidth ? { maxWidth: col.maxWidth, width: col.width, minWidth: col.minWidth } : void 0,
|
|
6032
|
+
style: col.maxWidth || col.width || col.minWidth || c + lead < pinnedStart || c >= columns.length - endCount ? { maxWidth: col.maxWidth, width: col.width, minWidth: col.minWidth, ...pinStyle(lead + c, cellCount) } : void 0,
|
|
6541
6033
|
children: inner
|
|
6542
6034
|
},
|
|
6543
6035
|
col.key
|
|
@@ -6549,50 +6041,57 @@ function Table({
|
|
|
6549
6041
|
expandable && isExpanded && renderExpanded && /* @__PURE__ */ jsx("tr", { children: /* @__PURE__ */ jsx(
|
|
6550
6042
|
"td",
|
|
6551
6043
|
{
|
|
6552
|
-
colSpan:
|
|
6044
|
+
colSpan: cellCount,
|
|
6553
6045
|
className: "bg-[var(--ds-bg-muted)] px-ds-6 py-ds-4 text-sm text-[var(--ds-text-primary)]",
|
|
6554
|
-
children: renderExpanded(row,
|
|
6046
|
+
children: /* @__PURE__ */ jsx("div", { "data-row-panel": "", className: "sticky left-ds-6", style: pins.frame ? { maxWidth: `calc(${pins.frame}px - 2 * var(--ds-space-6))` } : void 0, children: renderExpanded(row, originalIdx) })
|
|
6555
6047
|
}
|
|
6556
6048
|
) })
|
|
6557
|
-
] },
|
|
6049
|
+
] }, String(id));
|
|
6558
6050
|
}) })
|
|
6559
6051
|
] });
|
|
6560
6052
|
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
|
-
|
|
6053
|
+
return withControl(
|
|
6054
|
+
/* @__PURE__ */ jsxs(
|
|
6055
|
+
"div",
|
|
6056
|
+
{
|
|
6057
|
+
ref: listRoot,
|
|
6058
|
+
"data-ds-list": "",
|
|
6059
|
+
"data-gs": "table",
|
|
6060
|
+
className: cn("w-full min-w-0 flex flex-col", FRAME_CLASSES, "has-[>[data-table-scroll]:focus-visible]:shadow-[var(--ds-shadow-focus)]", control && "min-h-0", listClass),
|
|
6061
|
+
onFocus: noteFocus,
|
|
6062
|
+
onBlur: forgetFocus,
|
|
6063
|
+
children: [
|
|
6064
|
+
title && /* @__PURE__ */ jsx(TableHeading, { title, description, actions, titleId, descriptionId, inset: true }),
|
|
6065
|
+
selectable && /* @__PURE__ */ jsx("span", { hidden: true, id: `${headingId}-select-all`, children: "Select all rows shown" }),
|
|
6066
|
+
selectable && /* @__PURE__ */ jsx("span", { hidden: true, id: `${headingId}-select`, children: "Select" }),
|
|
6067
|
+
expandable && /* @__PURE__ */ jsx("span", { hidden: true, id: `${headingId}-details`, children: "Details" }),
|
|
6068
|
+
/* @__PURE__ */ jsx(
|
|
6069
|
+
"div",
|
|
6070
|
+
{
|
|
6071
|
+
ref: scrollRef,
|
|
6072
|
+
"data-table-scroll": "",
|
|
6073
|
+
onScroll: measureScroll,
|
|
6074
|
+
onFocus: (e) => {
|
|
6075
|
+
if (e.target === e.currentTarget) setRegionFocused(true);
|
|
6076
|
+
},
|
|
6077
|
+
onBlur: (e) => {
|
|
6078
|
+
if (e.target === e.currentTarget) setRegionFocused(false);
|
|
6079
|
+
},
|
|
6080
|
+
...fade,
|
|
6081
|
+
...region,
|
|
6082
|
+
className: cn("min-h-0 overflow-x-auto focus-visible:outline-none", title ? "rounded-b-[inherit]" : "rounded-[inherit]"),
|
|
6083
|
+
children: table
|
|
6084
|
+
}
|
|
6085
|
+
)
|
|
6086
|
+
]
|
|
6087
|
+
}
|
|
6088
|
+
)
|
|
6590
6089
|
);
|
|
6591
6090
|
}
|
|
6592
6091
|
function optionsKeyForFit(options) {
|
|
6593
6092
|
return options.map((o) => `${o.value}:${o.label}`).join("|");
|
|
6594
6093
|
}
|
|
6595
|
-
var
|
|
6094
|
+
var sizes2 = {
|
|
6596
6095
|
xs: "text-xs px-ds-2",
|
|
6597
6096
|
sm: "text-xs px-ds-3",
|
|
6598
6097
|
md: "text-sm px-ds-3",
|
|
@@ -6794,7 +6293,7 @@ function SegmentedControl({
|
|
|
6794
6293
|
"rounded-[var(--ds-radius-md)]",
|
|
6795
6294
|
"transition-colors cursor-pointer",
|
|
6796
6295
|
"focus-visible:outline-none focus-visible:shadow-[var(--ds-shadow-focus)]",
|
|
6797
|
-
|
|
6296
|
+
sizes2[size],
|
|
6798
6297
|
opt.value === value ? "text-[var(--ds-text-primary)]" : "text-[var(--ds-text-muted)] hover:text-[var(--ds-text-secondary)]",
|
|
6799
6298
|
opt.disabled && "opacity-disabled cursor-not-allowed"
|
|
6800
6299
|
),
|
|
@@ -8701,7 +8200,9 @@ function VerticalLayout({ items, className }) {
|
|
|
8701
8200
|
] })
|
|
8702
8201
|
] }, i)) });
|
|
8703
8202
|
}
|
|
8704
|
-
function Timeline({ items, orientation = "vertical", minItemWidth = 200, className, ref }) {
|
|
8203
|
+
function Timeline({ items: allItems, orientation = "vertical", minItemWidth = 200, className, ref, pager }) {
|
|
8204
|
+
useWholeListCheck("Timeline", allItems.length, pager);
|
|
8205
|
+
const items = pagerPart(allItems, pager);
|
|
8705
8206
|
const measureRef = useRef(null);
|
|
8706
8207
|
const width = useElementWidth(measureRef);
|
|
8707
8208
|
const setRefs = useCallback((node) => {
|
|
@@ -8711,7 +8212,12 @@ function Timeline({ items, orientation = "vertical", minItemWidth = 200, classNa
|
|
|
8711
8212
|
}, [ref]);
|
|
8712
8213
|
const fits = width === 0 || width >= items.length * minItemWidth;
|
|
8713
8214
|
const horizontal = orientation === "horizontal" || orientation === "responsive" && fits;
|
|
8714
|
-
|
|
8215
|
+
const list = /* @__PURE__ */ jsx("div", { ref: setRefs, "data-ds-list": "", "data-timeline-orientation": horizontal ? "horizontal" : "vertical", className: pager ? void 0 : className, children: horizontal ? /* @__PURE__ */ jsx(HorizontalLayout, { items, minItemWidth }) : /* @__PURE__ */ jsx(VerticalLayout, { items }) });
|
|
8216
|
+
if (!pager) return list;
|
|
8217
|
+
return /* @__PURE__ */ jsxs("div", { "data-gs-paged": "", className: cn("flex flex-col min-w-0", className), children: [
|
|
8218
|
+
list,
|
|
8219
|
+
allItems.length > 0 && /* @__PURE__ */ jsx(Pagination, { ...pager.props })
|
|
8220
|
+
] });
|
|
8715
8221
|
}
|
|
8716
8222
|
var CollapsibleContext = createContext(null);
|
|
8717
8223
|
function useCollapsible() {
|
|
@@ -9966,7 +9472,8 @@ var StackedList = forwardRef(function StackedList2({
|
|
|
9966
9472
|
selectedId,
|
|
9967
9473
|
className,
|
|
9968
9474
|
flush,
|
|
9969
|
-
hover
|
|
9475
|
+
hover,
|
|
9476
|
+
pager
|
|
9970
9477
|
}, ref) {
|
|
9971
9478
|
const isPhone = useBreakpoint("sm");
|
|
9972
9479
|
const inCard = useContext(CardSurfaceCtx);
|
|
@@ -9979,20 +9486,22 @@ var StackedList = forwardRef(function StackedList2({
|
|
|
9979
9486
|
console.warn('StackedList: `flush` and `hover` are deprecated \u2014 pass variant="articles" for an article list; the default variant takes its inset from the pane or card it sits in.');
|
|
9980
9487
|
}, [legacy]);
|
|
9981
9488
|
const articles = variant === "articles";
|
|
9489
|
+
useWholeListCheck("StackedList", items.length, pager);
|
|
9490
|
+
const shown = pagerPart(items, pager);
|
|
9982
9491
|
const stackMeta = isPhone && articles;
|
|
9983
9492
|
const selectable = selectedId !== void 0 || items.some((i) => i.selected !== void 0);
|
|
9984
9493
|
const inset = articles ? inCard ? "px-ds-5" : "px-0" : inCard ? "px-ds-5" : inPane ? "pl-ds-3 pr-ds-4" : selectable ? "pl-ds-3 pr-0" : "px-0";
|
|
9985
|
-
|
|
9494
|
+
const list = /* @__PURE__ */ jsx(
|
|
9986
9495
|
"ul",
|
|
9987
9496
|
{
|
|
9988
9497
|
ref,
|
|
9989
9498
|
"data-ds-list": "",
|
|
9990
9499
|
className: cn(
|
|
9991
9500
|
divided && "divide-y-[length:var(--ds-border-width)] divide-[var(--ds-border-subtle)]",
|
|
9992
|
-
className
|
|
9501
|
+
!pager && className
|
|
9993
9502
|
),
|
|
9994
9503
|
role: "list",
|
|
9995
|
-
children:
|
|
9504
|
+
children: shown.map((item) => {
|
|
9996
9505
|
const isSelected = item.selected ?? (selectedId !== void 0 && item.id === selectedId);
|
|
9997
9506
|
const interactive = !!item.onClick;
|
|
9998
9507
|
const hasEmphasis = item.unread !== void 0;
|
|
@@ -10084,6 +9593,11 @@ var StackedList = forwardRef(function StackedList2({
|
|
|
10084
9593
|
})
|
|
10085
9594
|
}
|
|
10086
9595
|
);
|
|
9596
|
+
if (!pager) return list;
|
|
9597
|
+
return /* @__PURE__ */ jsxs("div", { "data-gs-paged": "", className: cn("flex flex-col min-w-0", className), children: [
|
|
9598
|
+
list,
|
|
9599
|
+
items.length > 0 && /* @__PURE__ */ jsx(Pagination, { ...pager.props })
|
|
9600
|
+
] });
|
|
10087
9601
|
});
|
|
10088
9602
|
var TIME_ZOOMS = ["day", "week", "month", "quarter"];
|
|
10089
9603
|
var DAY_MS = 864e5;
|
|
@@ -11119,7 +10633,7 @@ var SELECTED = "outline-solid outline-2 outline-offset-2 outline-[var(--ds-text-
|
|
|
11119
10633
|
var UNDATED_INSET = 16;
|
|
11120
10634
|
var NO_GROUPS = [];
|
|
11121
10635
|
var NO_STATUSES = {};
|
|
11122
|
-
var
|
|
10636
|
+
var warned = /* @__PURE__ */ new Set();
|
|
11123
10637
|
function warnOnce2(message) {
|
|
11124
10638
|
let dev = false;
|
|
11125
10639
|
try {
|
|
@@ -11127,8 +10641,8 @@ function warnOnce2(message) {
|
|
|
11127
10641
|
} catch {
|
|
11128
10642
|
dev = false;
|
|
11129
10643
|
}
|
|
11130
|
-
if (!dev ||
|
|
11131
|
-
|
|
10644
|
+
if (!dev || warned.has(message)) return;
|
|
10645
|
+
warned.add(message);
|
|
11132
10646
|
console.warn(`Gantt: ${message}`);
|
|
11133
10647
|
}
|
|
11134
10648
|
function GanttArrows({ arrows, width, height }) {
|
|
@@ -12485,281 +11999,6 @@ var Breadcrumbs = forwardRef(function Breadcrumbs2({
|
|
|
12485
11999
|
dropdown
|
|
12486
12000
|
] });
|
|
12487
12001
|
});
|
|
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,
|
|
12650
|
-
className: cn(
|
|
12651
|
-
"inline-flex items-center justify-center h-[var(--ds-control-height-sm)] w-[var(--ds-control-height-sm)] text-sm font-medium cursor-pointer",
|
|
12652
|
-
"rounded-[var(--ds-radius-md)]",
|
|
12653
|
-
"border-[length:var(--ds-border-width)]",
|
|
12654
|
-
"transition-colors duration-[var(--ds-transition-speed)]",
|
|
12655
|
-
p === currentPage ? "bg-[var(--ds-accent-primary)] [background-image:var(--ds-gradient)] text-[var(--ds-text-on-primary)] border-[var(--ds-accent-primary)]" : "bg-[var(--ds-bg-surface)] text-[var(--ds-text-secondary)] border-[var(--ds-border-default)] hover:bg-[var(--ds-bg-muted)] hover:text-[var(--ds-text-primary)]"
|
|
12656
|
-
),
|
|
12657
|
-
children: p
|
|
12658
|
-
},
|
|
12659
|
-
p
|
|
12660
|
-
)
|
|
12661
|
-
),
|
|
12662
|
-
/* @__PURE__ */ jsx(
|
|
12663
|
-
"button",
|
|
12664
|
-
{
|
|
12665
|
-
type: "button",
|
|
12666
|
-
onClick: () => onPageChange(currentPage + 1),
|
|
12667
|
-
disabled: currentPage >= totalPages,
|
|
12668
|
-
"aria-label": "Next page",
|
|
12669
|
-
className: cn(
|
|
12670
|
-
"inline-flex items-center justify-center h-[var(--ds-control-height-sm)] w-[var(--ds-control-height-sm)] text-sm cursor-pointer",
|
|
12671
|
-
"rounded-[var(--ds-radius-md)]",
|
|
12672
|
-
"border-[length:var(--ds-border-width)] border-[var(--ds-border-default)]",
|
|
12673
|
-
"bg-[var(--ds-bg-surface)] text-[var(--ds-text-secondary)]",
|
|
12674
|
-
"transition-colors duration-[var(--ds-transition-speed)]",
|
|
12675
|
-
"hover:bg-[var(--ds-bg-muted)] hover:text-[var(--ds-text-primary)]",
|
|
12676
|
-
"disabled:opacity-disabled disabled:cursor-not-allowed"
|
|
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: [
|
|
12731
|
-
/* @__PURE__ */ jsx(
|
|
12732
|
-
NumberInput,
|
|
12733
|
-
{
|
|
12734
|
-
value: jumpPage,
|
|
12735
|
-
onChange: setJumpPage,
|
|
12736
|
-
min: 1,
|
|
12737
|
-
max: totalPages,
|
|
12738
|
-
step: 1,
|
|
12739
|
-
size: "sm",
|
|
12740
|
-
className: "w-[5rem]"
|
|
12741
|
-
}
|
|
12742
|
-
),
|
|
12743
|
-
/* @__PURE__ */ jsx(
|
|
12744
|
-
"button",
|
|
12745
|
-
{
|
|
12746
|
-
type: "button",
|
|
12747
|
-
onClick: handleGo,
|
|
12748
|
-
className: cn(
|
|
12749
|
-
"px-ds-2.5 h-[var(--ds-control-height-sm)] text-xs font-medium cursor-pointer",
|
|
12750
|
-
"rounded-[var(--ds-radius-md)]",
|
|
12751
|
-
"bg-[var(--ds-accent-primary)] text-[var(--ds-text-on-primary)]",
|
|
12752
|
-
"transition-colors duration-[var(--ds-transition-speed)]",
|
|
12753
|
-
"hover:opacity-90"
|
|
12754
|
-
),
|
|
12755
|
-
children: "Go"
|
|
12756
|
-
}
|
|
12757
|
-
)
|
|
12758
|
-
] })
|
|
12759
|
-
] })
|
|
12760
|
-
}
|
|
12761
|
-
);
|
|
12762
|
-
}
|
|
12763
12002
|
var HeaderTabRowContext = createContext(null);
|
|
12764
12003
|
function useHeaderTabRow() {
|
|
12765
12004
|
return useContext(HeaderTabRowContext);
|
|
@@ -17468,67 +16707,6 @@ function getPopoverPosition(rect, placement, padding) {
|
|
|
17468
16707
|
top = Math.max(8, Math.min(top, window.innerHeight - popH - 8));
|
|
17469
16708
|
return { top, left };
|
|
17470
16709
|
}
|
|
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
16710
|
function useDestructiveAction(options) {
|
|
17533
16711
|
const { action, title, description, confirmLabel, typeToConfirm, onConfirm, onUndo, doneMessage, undoMessage, restoredMessage, severity } = options;
|
|
17534
16712
|
const preferences = useShellPreferences();
|
|
@@ -17675,7 +16853,7 @@ var PAST_TENSE = {
|
|
|
17675
16853
|
reject: "Rejected",
|
|
17676
16854
|
decline: "Declined"
|
|
17677
16855
|
};
|
|
17678
|
-
var
|
|
16856
|
+
var warned2 = /* @__PURE__ */ new Set();
|
|
17679
16857
|
function pastTenseOf(label) {
|
|
17680
16858
|
const words = label.trim().toLowerCase().split(/\s+/);
|
|
17681
16859
|
const found = PAST_TENSE[words.slice(0, 2).join(" ")] ?? PAST_TENSE[words[0] ?? ""];
|
|
@@ -17686,8 +16864,8 @@ function pastTenseOf(label) {
|
|
|
17686
16864
|
} catch {
|
|
17687
16865
|
dev = false;
|
|
17688
16866
|
}
|
|
17689
|
-
if (dev && !
|
|
17690
|
-
|
|
16867
|
+
if (dev && !warned2.has(label)) {
|
|
16868
|
+
warned2.add(label);
|
|
17691
16869
|
console.warn(`useDestructiveAction: "${label}" isn't a verb the hook knows; pass doneMessage so the confirmation says what happened.`);
|
|
17692
16870
|
}
|
|
17693
16871
|
return "Done";
|
|
@@ -17832,6 +17010,6 @@ var TextOverflow = forwardRef(function TextOverflow2({
|
|
|
17832
17010
|
return /* @__PURE__ */ jsx(Tooltip, { content: resolvedTooltipContent, children: content });
|
|
17833
17011
|
});
|
|
17834
17012
|
|
|
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,
|
|
17013
|
+
export { Accordion, ActionPanel, ActionPanelGroup, AddAnother, Alert, AsidePanel, Avatar, AvatarGroup, BottomNav, Breadcrumbs, BulkActionBar, Calendar, Card, CardContent, CardDescription, CardFooter, CardGrid, CardHeader, CardTitle, Carousel, ChatMessageList, ChatPanel, Checkbox, CheckboxGroup, CheckboxGroupItem, Collapsible, ColorPicker, Combobox, CommandPalette, ContextMenu, CornerPanel, DEFAULT_DATE_RANGE_PRESETS, DataList, DatePicker, DateRangePicker, DescriptionList, Dialog, Dock, DropdownMenu, EmptyState, EntityCell, FileUpload, FormWrapper, Gantt, HoverCard, Kbd, Launcher, MentionInput, MobileHeaderMenu, NavItem, NavMenu, Navbar, NotificationCenter, PageContainer, PageHeader, PinInput, Progress, RadioGroup, Rating, ScrollArea, SectionHeading, SegmentedControl, SettingsLayout, Sidebar, SidebarNav, SliderRange, StackedList, StatsCard, StatusDot, Stepper, TIME_ZOOMS, Table, TableToolbar, Tabs, Tag, TagInput, TextOverflow, TimeBar, TimePicker, TimeRow, TimeScaleHeader, TimeViewport, Timeline, Toast, ToastProvider, Tour, TransferList, TreeView, dateOfDay, dayOf, endDayOf, fitLabel, fitLabels, formatDateRange, timeExtent, useContentWidth, useDestructiveAction, useFittedLabels, useSidebar, useTextMeasure, useTimeScale, useTimeViewport, useTimeViewportLayout, useToast, useToastOptional };
|
|
17836
17014
|
//# sourceMappingURL=index.js.map
|
|
17837
17015
|
//# sourceMappingURL=index.js.map
|