gridsmith-ui 0.30.2 → 0.31.1
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/CHANGELOG.md +71 -1
- package/dist/charts.d.ts +114 -1
- package/dist/charts.js +1113 -206
- package/dist/charts.js.map +1 -1
- package/dist/chat.js +20 -12
- package/dist/chat.js.map +1 -1
- package/dist/{chunk-HVGHGBKV.js → chunk-2TCCSKL3.js} +6 -7
- package/dist/chunk-2TCCSKL3.js.map +1 -0
- package/dist/{chunk-L6HWACK7.js → chunk-53F7GVBQ.js} +6 -3
- package/dist/chunk-53F7GVBQ.js.map +1 -0
- package/dist/chunk-BHTAVJIG.js +285 -0
- package/dist/chunk-BHTAVJIG.js.map +1 -0
- package/dist/{chunk-WWN6CQKI.js → chunk-DR6WEI3A.js} +60 -7
- package/dist/chunk-DR6WEI3A.js.map +1 -0
- package/dist/{chunk-4HJDOZ2M.js → chunk-EZ3ZGFGA.js} +203 -34
- package/dist/chunk-EZ3ZGFGA.js.map +1 -0
- package/dist/{chunk-MIUSSYVE.js → chunk-HQFTP7Y5.js} +27 -52
- package/dist/chunk-HQFTP7Y5.js.map +1 -0
- package/dist/{chunk-SIWERRP2.js → chunk-I6JJ7KKP.js} +14 -15
- package/dist/chunk-I6JJ7KKP.js.map +1 -0
- package/dist/chunk-IOHGE4EW.js +755 -0
- package/dist/chunk-IOHGE4EW.js.map +1 -0
- package/dist/{chunk-USHW523V.js → chunk-IZW5XHKA.js} +73 -699
- package/dist/chunk-IZW5XHKA.js.map +1 -0
- package/dist/{chunk-ZASGFL5D.js → chunk-K3NAFQ4S.js} +3 -4
- package/dist/chunk-K3NAFQ4S.js.map +1 -0
- package/dist/{chunk-ACLKDE5W.js → chunk-KSJTMSYA.js} +23 -11
- package/dist/chunk-KSJTMSYA.js.map +1 -0
- package/dist/{chunk-SQHKC4HA.js → chunk-NDL2JGQ7.js} +8 -7
- package/dist/chunk-NDL2JGQ7.js.map +1 -0
- package/dist/{chunk-TYNDXMBV.js → chunk-QOMP4D6V.js} +3 -3
- package/dist/{chunk-TYNDXMBV.js.map → chunk-QOMP4D6V.js.map} +1 -1
- package/dist/{chunk-BZRZENBS.js → chunk-SLGGZ3MU.js} +6 -6
- package/dist/{chunk-BZRZENBS.js.map → chunk-SLGGZ3MU.js.map} +1 -1
- package/dist/{chunk-K6IDOCGE.js → chunk-TH272DIC.js} +10 -10
- package/dist/{chunk-K6IDOCGE.js.map → chunk-TH272DIC.js.map} +1 -1
- package/dist/chunk-V73LHNRL.js +51 -0
- package/dist/chunk-V73LHNRL.js.map +1 -0
- package/dist/{chunk-ZCDA74RQ.js → chunk-W3GY5ROH.js} +3 -3
- package/dist/{chunk-ZCDA74RQ.js.map → chunk-W3GY5ROH.js.map} +1 -1
- package/dist/data-grid.js +11 -12
- package/dist/data-grid.js.map +1 -1
- package/dist/editor-mentions.js +2 -3
- package/dist/editor-mentions.js.map +1 -1
- package/dist/editor.js +4 -6
- package/dist/editor.js.map +1 -1
- package/dist/icons.js +1 -1
- package/dist/index.d.ts +100 -16
- package/dist/index.js +1177 -660
- package/dist/index.js.map +1 -1
- package/dist/kanban.js +10 -11
- package/dist/kanban.js.map +1 -1
- package/dist/resizable.js +10 -11
- package/dist/resizable.js.map +1 -1
- package/dist/virtualized.js +11 -12
- package/dist/virtualized.js.map +1 -1
- package/package.json +1 -1
- package/dist/chunk-4HJDOZ2M.js.map +0 -1
- package/dist/chunk-6C2IUMY7.js +0 -46
- package/dist/chunk-6C2IUMY7.js.map +0 -1
- package/dist/chunk-7Q46JXSK.js +0 -51
- package/dist/chunk-7Q46JXSK.js.map +0 -1
- package/dist/chunk-ACLKDE5W.js.map +0 -1
- package/dist/chunk-HVGHGBKV.js.map +0 -1
- package/dist/chunk-L6HWACK7.js.map +0 -1
- package/dist/chunk-MIUSSYVE.js.map +0 -1
- package/dist/chunk-NKUCS67T.js +0 -13
- package/dist/chunk-NKUCS67T.js.map +0 -1
- package/dist/chunk-SIWERRP2.js.map +0 -1
- package/dist/chunk-SQHKC4HA.js.map +0 -1
- package/dist/chunk-USHW523V.js.map +0 -1
- package/dist/chunk-WWN6CQKI.js.map +0 -1
- package/dist/chunk-YL5KD5RC.js +0 -49
- package/dist/chunk-YL5KD5RC.js.map +0 -1
- package/dist/chunk-ZASGFL5D.js.map +0 -1
package/dist/index.js
CHANGED
|
@@ -1,46 +1,46 @@
|
|
|
1
1
|
"use client";
|
|
2
|
-
import { useAppShell, REACT_VERSION_PROBLEM, Breadcrumbs, useCrumbFollow, crumbGoes, useCornerInset, NAVBAR_INSET_PRIORITY, useOverlayMark, useDirtyGuard, useScrollbarInset, DrawerFooterCtx, OverlayMarkScope, OverlayCloseCtx, insetLessScrollbar, DiscardConfirm, OVERLAY_ROOT_ATTR, OverlayMarkCtx, useCompact, useElementWidth, DrawerPanel, useCloseSettle, besideRoom, PANEL_INSET_PRIORITY, Drawer, useRememberedWidth, pxOf, ResizeEdge, LAUNCHER_INSET_PRIORITY, defaultMaxWidth } from './chunk-
|
|
3
|
-
export { AppShell, Breadcrumbs, Drawer, SkipLink, useAppShell, useUnsavedChanges } from './chunk-
|
|
4
|
-
import { Skeleton, TITLE_TEXT } from './chunk-
|
|
5
|
-
export { Skeleton } from './chunk-
|
|
2
|
+
import { useAppShell, REACT_VERSION_PROBLEM, Breadcrumbs, useCrumbFollow, crumbGoes, useCornerInset, NAVBAR_INSET_PRIORITY, useOverlayMark, useDirtyGuard, useScrollbarInset, DrawerFooterCtx, OverlayMarkScope, OverlayCloseCtx, insetLessScrollbar, DiscardConfirm, OVERLAY_ROOT_ATTR, OverlayMarkCtx, useCompact, useElementWidth, DrawerPanel, useCloseSettle, besideRoom, PANEL_INSET_PRIORITY, Drawer, useRememberedWidth, pxOf, ResizeEdge, LAUNCHER_INSET_PRIORITY, defaultMaxWidth } from './chunk-TH272DIC.js';
|
|
3
|
+
export { AppShell, Breadcrumbs, Drawer, SkipLink, useAppShell, useUnsavedChanges } from './chunk-TH272DIC.js';
|
|
4
|
+
import { Skeleton, TITLE_TEXT, SegmentedControl } from './chunk-BHTAVJIG.js';
|
|
5
|
+
export { SegmentedControl, Skeleton } from './chunk-BHTAVJIG.js';
|
|
6
6
|
import { useScrollEdges, EDGE_FADE } from './chunk-3BRQRKDO.js';
|
|
7
|
-
import { Avatar, foldForSearch, useActiveOptionInView, shownMentions, matchMentions, mentionOptionId, MentionList, initialsOf } from './chunk-
|
|
8
|
-
export { Avatar } from './chunk-
|
|
9
|
-
import { Link } from './chunk-
|
|
10
|
-
export { CodeBlock, Divider, Link } from './chunk-
|
|
11
|
-
import { DropdownMenu } from './chunk-
|
|
12
|
-
export { DropdownMenu } from './chunk-
|
|
7
|
+
import { Avatar, foldForSearch, useActiveOptionInView, shownMentions, matchMentions, mentionOptionId, MentionList, initialsOf } from './chunk-K3NAFQ4S.js';
|
|
8
|
+
export { Avatar } from './chunk-K3NAFQ4S.js';
|
|
9
|
+
import { Link } from './chunk-NDL2JGQ7.js';
|
|
10
|
+
export { CodeBlock, Divider, Link } from './chunk-NDL2JGQ7.js';
|
|
11
|
+
import { DropdownMenu } from './chunk-2TCCSKL3.js';
|
|
12
|
+
export { DropdownMenu } from './chunk-2TCCSKL3.js';
|
|
13
13
|
import { useFillHeight, FillContext } from './chunk-DBHVJ7Z3.js';
|
|
14
|
-
import { Badge } from './chunk-
|
|
15
|
-
export { Badge } from './chunk-
|
|
16
|
-
import { useKeyboardScroll } from './chunk-
|
|
17
|
-
import { localeCache, startOfDay, addDays, useWeekStart, useDateWords, localeDayFirst, dayKey, moveDay, addMonths, DateSegmentFields, getMonthGrid, isSameMonth, isSameDay, DatePicker, timeSegments, pad2, inferColumnKinds, useCardsSwitch, CARDS_BELOW, kindOfRenderedText, Checkbox, CardValue, SortIndicator, startOfWeek, endOfWeek, addMonthsClamped, isExcludedDay, CutCell, CutEmail, stepValue, separatorMovesOn, TIME_SEPARATORS, typeDigit, getEventsForDay, layoutWeek, isWeekend, getWeekDays, isBarEvent, layoutPieces, dayPieces, groupEventsByDay, timeToFraction } from './chunk-
|
|
18
|
-
export { Checkbox, CheckboxGroup, CheckboxGroupItem, DatePicker, HoverCard, TextOverflow } from './chunk-
|
|
19
|
-
import { useWholeListCheck, pagerPart, Pagination,
|
|
20
|
-
export {
|
|
21
|
-
import { useShellPreferences, PREFERENCE_HOUSE_DEFAULTS, formatRelativeTime, thresholdOf, toMillis, formatFullTime, datedMillis, preferenceActionKey, DAY, HOUR, MINUTE } from './chunk-
|
|
22
|
-
export { PreferencesContext, formatFullTime, formatRelativeTime, preferenceActionKey, usePreferences } from './chunk-
|
|
14
|
+
import { Badge } from './chunk-SLGGZ3MU.js';
|
|
15
|
+
export { Badge } from './chunk-SLGGZ3MU.js';
|
|
16
|
+
import { useKeyboardScroll } from './chunk-KSJTMSYA.js';
|
|
17
|
+
import { localeCache, startOfDay, addDays, useWeekStart, useDateWords, localeDayFirst, dayKey, moveDay, addMonths, DateSegmentFields, getMonthGrid, isSameMonth, isSameDay, DatePicker, timeSegments, pad2, inferColumnKinds, useCardsSwitch, CARDS_BELOW, kindOfRenderedText, Checkbox, CardValue, SortIndicator, startOfWeek, endOfWeek, addMonthsClamped, isExcludedDay, CutCell, CutEmail, stepValue, separatorMovesOn, TIME_SEPARATORS, typeDigit, getEventsForDay, layoutWeek, isWeekend, getWeekDays, isBarEvent, layoutPieces, dayPieces, groupEventsByDay, timeToFraction } from './chunk-I6JJ7KKP.js';
|
|
18
|
+
export { Checkbox, CheckboxGroup, CheckboxGroupItem, DatePicker, HoverCard, TextOverflow } from './chunk-I6JJ7KKP.js';
|
|
19
|
+
import { useWholeListCheck, pagerPart, Pagination, NumberInput } from './chunk-IOHGE4EW.js';
|
|
20
|
+
export { NumberInput, Pagination, Popover, usePagination } from './chunk-IOHGE4EW.js';
|
|
21
|
+
import { useShellPreferences, PREFERENCE_HOUSE_DEFAULTS, formatRelativeTime, thresholdOf, toMillis, formatFullTime, datedMillis, preferenceActionKey, DAY, HOUR, MINUTE } from './chunk-QOMP4D6V.js';
|
|
22
|
+
export { PreferencesContext, formatFullTime, formatRelativeTime, preferenceActionKey, usePreferences } from './chunk-QOMP4D6V.js';
|
|
23
23
|
import { useFormatLocale, useHydrated, useToday, LocaleContext } from './chunk-LJYSVZMI.js';
|
|
24
24
|
export { useFormatLocale, useHydrated } from './chunk-LJYSVZMI.js';
|
|
25
|
+
import { Input, CHECK_FILL, Dropdown, FilterRowContext, SWITCH_KNOB_ON, SWITCH_KNOB_OFF, SWITCH_KNOB_MOTION, SWITCH_TRACK_ON, SWITCH_TRACK_OFF, useFieldControl, useField, OutsideField, InlineFieldError, Label, AddAnotherRowCtx, Field } from './chunk-IZW5XHKA.js';
|
|
26
|
+
export { Dropdown, Field, InlineFieldError, Input, Label, Textarea, Toggle } from './chunk-IZW5XHKA.js';
|
|
25
27
|
import { formatLocale, localeChoice } from './chunk-7QLXYRPD.js';
|
|
26
|
-
import { useInputModality, inputModality } from './chunk-7RKC5C7G.js';
|
|
27
|
-
export { INPUT_MODALITY_ATTR, inputModality, installInputModality, useInputModality } from './chunk-7RKC5C7G.js';
|
|
28
28
|
import { FormChangeCtx, useReportedChange, useOptionalFormContext, FormCtx } from './chunk-72SDAX54.js';
|
|
29
29
|
export { useFormContext } from './chunk-72SDAX54.js';
|
|
30
|
-
import {
|
|
31
|
-
|
|
32
|
-
|
|
30
|
+
import { CardSurfaceCtx, useScrollsInside, SplitPaneCtx, RowsCtx, PageActionsCtx, SurfaceBoundary, useFramesItself, TableCardCtx } from './chunk-V73LHNRL.js';
|
|
31
|
+
import { Button, elementType, ControlSizeContext, triggerType, Spinner } from './chunk-HQFTP7Y5.js';
|
|
32
|
+
export { Button, ButtonSizeContext, ControlSizeContext, Spinner } from './chunk-HQFTP7Y5.js';
|
|
33
33
|
import { useBreakpoint, readBreakpointPx } from './chunk-ZHUVLBCC.js';
|
|
34
34
|
export { BreakpointWidthProvider, useBreakpoint } from './chunk-ZHUVLBCC.js';
|
|
35
|
-
import {
|
|
36
|
-
export {
|
|
37
|
-
import {
|
|
38
|
-
export {
|
|
39
|
-
import {
|
|
40
|
-
|
|
41
|
-
import {
|
|
42
|
-
|
|
43
|
-
|
|
35
|
+
import { useInputModality, inputModality } from './chunk-7RKC5C7G.js';
|
|
36
|
+
export { INPUT_MODALITY_ATTR, inputModality, installInputModality, useInputModality } from './chunk-7RKC5C7G.js';
|
|
37
|
+
import { useTextOverflow } from './chunk-W3GY5ROH.js';
|
|
38
|
+
export { useTextOverflow } from './chunk-W3GY5ROH.js';
|
|
39
|
+
import { AutoTooltip, mergeRefs, useRevealFocus } from './chunk-DR6WEI3A.js';
|
|
40
|
+
export { Tooltip, useRevealFocus } from './chunk-DR6WEI3A.js';
|
|
41
|
+
import { Icon, slotIcon, warnOnce } from './chunk-53F7GVBQ.js';
|
|
42
|
+
import { cn, FOCUS_RING, focusAfterSelfRemoval, FOCUSABLE, GLASS_SURFACE, useFocusKeptInList, FOCUS_INSET, useLatest, PEER_FOCUS_RING, GLASS_BACKDROP, OPEN_TO_FOCUS, focusOutOf, FIELD, ZOOM_KEYS, rovingTabStop, FOCUS_ROOM, useOverlayLayer, useFocusTrap, useFocusBeforeOpen, rememberOpener, focusInitial, lockBodyScroll, unlockBodyScroll, OVERLAY_CLOSE_ATTR, OVERLAY_SURFACE, GLASS_OVERLAY, usePopupFocus, usePosition, ERROR_HAS_FOCUS_RING, FIELD_HAS_FOCUS_RING, CONTROL_ANCESTOR, GROUP_FOCUS_RING, useGridKeyboard, ERROR_ACTIVE_RING, ACTIVE_RING, ERROR_FOCUS_WITHIN_RING, FIELD_FOCUS_WITHIN_RING, focusAfterRemoval, GLASS_DROPDOWN, ERROR_FOCUS_RING, FIELD_FOCUS_RING, openToFocus, atLeastFocusRoom, useNonModalDialog, useReturnFocus } from './chunk-EZ3ZGFGA.js';
|
|
43
|
+
export { useGridKeyboard } from './chunk-EZ3ZGFGA.js';
|
|
44
44
|
import { jsxs, jsx, Fragment } from 'react/jsx-runtime';
|
|
45
45
|
import { forwardRef, useRef, useId, useEffect, useState, createContext, useCallback, useLayoutEffect, useMemo, useContext, isValidElement, memo, useImperativeHandle, useSyncExternalStore, Children, Fragment as Fragment$1, cloneElement, useReducer } from 'react';
|
|
46
46
|
import { createPortal, flushSync } from 'react-dom';
|
|
@@ -130,7 +130,7 @@ function Combobox({ value, onChange: onChangeProp, options, placeholder = "Searc
|
|
|
130
130
|
const onChange = useReportedChange(onChangeProp, value);
|
|
131
131
|
useInputModality();
|
|
132
132
|
const contextSize = useContext(ControlSizeContext);
|
|
133
|
-
const control = useFieldControl({ ...wiring, error: error || void 0 });
|
|
133
|
+
const control = useFieldControl({ ...wiring, "aria-label": ariaLabel, error: error || void 0 }, { component: "Combobox" });
|
|
134
134
|
const size = sizeProp ?? contextSize ?? "md";
|
|
135
135
|
const [open, setOpen] = useState(false);
|
|
136
136
|
useOverlayLayer(open);
|
|
@@ -259,8 +259,8 @@ function Combobox({ value, onChange: onChangeProp, options, placeholder = "Searc
|
|
|
259
259
|
type: "text",
|
|
260
260
|
id: control.id,
|
|
261
261
|
role: "combobox",
|
|
262
|
-
"aria-labelledby": wiring["aria-labelledby"],
|
|
263
|
-
"aria-label": control.labelId ? void 0 :
|
|
262
|
+
"aria-labelledby": control.shown ? void 0 : wiring["aria-labelledby"],
|
|
263
|
+
"aria-label": control.labelId ? void 0 : control.label,
|
|
264
264
|
"aria-describedby": control.describedBy,
|
|
265
265
|
"aria-invalid": control.invalid || void 0,
|
|
266
266
|
"aria-required": control.required || void 0,
|
|
@@ -421,6 +421,8 @@ function zoneOptions(locale) {
|
|
|
421
421
|
return zoneLists(key, build2).options;
|
|
422
422
|
}
|
|
423
423
|
function TimezoneSelect({ value, onChange, placeholder = "Search time zones\u2026", ...rest }) {
|
|
424
|
+
const control = useFieldControl(rest, { component: "TimezoneSelect" });
|
|
425
|
+
const { "aria-label": _pageLabel, "aria-labelledby": pageLabelledBy, ...comboboxRest } = rest;
|
|
424
426
|
const locale = useFormatLocale();
|
|
425
427
|
const zones = zoneOptions(locale);
|
|
426
428
|
const stored = value ? canonicalTimeZone(value) : "";
|
|
@@ -433,7 +435,7 @@ function TimezoneSelect({ value, onChange, placeholder = "Search time zones\u202
|
|
|
433
435
|
}
|
|
434
436
|
return zones.some((o) => o.value === stored) ? zones : [{ value: stored, label: labelOf(stored, /* @__PURE__ */ new Date(), locale), keywords: CITY_OF.get(stored) }, ...zones];
|
|
435
437
|
}, [zones, stored, mine, locale]);
|
|
436
|
-
return /* @__PURE__ */ jsx(Combobox, { value: stored, onChange, options, placeholder, ...
|
|
438
|
+
return /* @__PURE__ */ jsx(Combobox, { value: stored, onChange, options, placeholder, ...comboboxRest, "aria-label": control.shown ? void 0 : control.label, "aria-labelledby": control.shown ? void 0 : pageLabelledBy });
|
|
437
439
|
}
|
|
438
440
|
var LONGEST_WAIT = DAY;
|
|
439
441
|
var noChange = () => () => {
|
|
@@ -508,7 +510,7 @@ function RadioGroup({ value, onChange: onChangeProp, options, orientation = "ver
|
|
|
508
510
|
const onChange = useReportedChange(onChangeProp, value);
|
|
509
511
|
const groupRef = useRef(null);
|
|
510
512
|
const groupId = useId();
|
|
511
|
-
const control = useFieldControl(wiring);
|
|
513
|
+
const control = useFieldControl(wiring, { component: "RadioGroup", ownLabel: label ? groupId : void 0 });
|
|
512
514
|
const enabledOptions = options.filter((o) => !o.disabled);
|
|
513
515
|
const tabStop = rovingTabStop(options, (o) => o.value === value, (o) => !!o.disabled);
|
|
514
516
|
function handleKeyDown(e) {
|
|
@@ -540,8 +542,8 @@ function RadioGroup({ value, onChange: onChangeProp, options, orientation = "ver
|
|
|
540
542
|
ref: groupRef,
|
|
541
543
|
role: "radiogroup",
|
|
542
544
|
id: control.id,
|
|
543
|
-
"aria-label":
|
|
544
|
-
"aria-labelledby":
|
|
545
|
+
"aria-label": control.labelId ? void 0 : control.label,
|
|
546
|
+
"aria-labelledby": control.labelId,
|
|
545
547
|
"aria-describedby": control.describedBy,
|
|
546
548
|
"aria-invalid": control.invalid || void 0,
|
|
547
549
|
"aria-required": control.required || void 0,
|
|
@@ -668,7 +670,7 @@ function DateRangePicker({
|
|
|
668
670
|
const presetEdges = useScrollEdges({ enabled: isPhone });
|
|
669
671
|
useRevealFocus(presetEdges.elRef, isPhone);
|
|
670
672
|
const generatedId = useId();
|
|
671
|
-
const control = useFieldControl({ ...wiring, id, error: error || void 0 }, { requiredInDescription: true });
|
|
673
|
+
const control = useFieldControl({ ...wiring, id, error: error || void 0 }, { requiredInDescription: true, component: "DateRangePicker", ownLabel: label ? true : void 0 });
|
|
672
674
|
useInputModality();
|
|
673
675
|
const triggerId = control.id ?? generatedId;
|
|
674
676
|
const locale = useFormatLocale();
|
|
@@ -1560,6 +1562,8 @@ function RecurrencePicker({ value, onChange: onChangeProp, start, label, weekSta
|
|
|
1560
1562
|
setCustomOpen(false);
|
|
1561
1563
|
onChange(presets[Number(id.slice("preset-".length))].rule);
|
|
1562
1564
|
};
|
|
1565
|
+
const { "aria-label": pageName, "aria-labelledby": pageLabelledBy, ...choiceWiring } = wiring;
|
|
1566
|
+
const named = pageName || pageLabelledBy ? { role: "group", "aria-label": pageName, "aria-labelledby": pageLabelledBy } : {};
|
|
1563
1567
|
const summary = rule && !noDays(rule) ? describeRecurrence(rule, start, locale) : unreadable ? "Repeats by a rule set in another app. Choose another to replace it." : null;
|
|
1564
1568
|
const describedBy = [wiring["aria-describedby"], summary ? ids.summary : void 0].filter(Boolean).join(" ") || void 0;
|
|
1565
1569
|
const order = Array.from({ length: 7 }, (_, i) => (weekStart + i) % 7);
|
|
@@ -1571,17 +1575,17 @@ function RecurrencePicker({ value, onChange: onChangeProp, start, label, weekSta
|
|
|
1571
1575
|
const monthlyOn = custom?.nth ? nthId(custom.nth) : custom?.day === -1 ? "last" : "day";
|
|
1572
1576
|
const ends = custom?.until ? "until" : custom?.count !== void 0 ? "count" : untilPending ? "until" : "never";
|
|
1573
1577
|
if (!hydrated) {
|
|
1574
|
-
return /* @__PURE__ */ jsxs("div", { "data-gs": "recurrence-picker", "data-recurrence-pending": "", "aria-busy": "true", className: cn("space-y-ds-2", className), children: [
|
|
1575
|
-
/* @__PURE__ */ jsx(Dropdown, { ...
|
|
1578
|
+
return /* @__PURE__ */ jsxs("div", { "data-gs": "recurrence-picker", "data-recurrence-pending": "", "aria-busy": "true", ...named, className: cn("space-y-ds-2", className), children: [
|
|
1579
|
+
/* @__PURE__ */ jsx(Dropdown, { ...choiceWiring, label: field ? void 0 : label ?? "Repeat", options: PENDING_OPTIONS, value: "pending", onChange: () => {
|
|
1576
1580
|
} }),
|
|
1577
1581
|
(rule && !noDays(rule) || unreadable) && /* @__PURE__ */ jsx("p", { "aria-hidden": "true", className: "text-xs", children: "\xA0" })
|
|
1578
1582
|
] });
|
|
1579
1583
|
}
|
|
1580
|
-
return /* @__PURE__ */ jsxs("div", { "data-gs": "recurrence-picker", className: cn("space-y-ds-2", className), children: [
|
|
1584
|
+
return /* @__PURE__ */ jsxs("div", { "data-gs": "recurrence-picker", ...named, className: cn("space-y-ds-2", className), children: [
|
|
1581
1585
|
/* @__PURE__ */ jsx(
|
|
1582
1586
|
Dropdown,
|
|
1583
1587
|
{
|
|
1584
|
-
...
|
|
1588
|
+
...choiceWiring,
|
|
1585
1589
|
"aria-describedby": describedBy,
|
|
1586
1590
|
label: field ? void 0 : label ?? "Repeat",
|
|
1587
1591
|
options,
|
|
@@ -2084,7 +2088,7 @@ var running = (item) => item.status === "queued" || item.status === "uploading";
|
|
|
2084
2088
|
var failureOf = (err) => err instanceof Error && err.message ? err.message : "The upload didn't work.";
|
|
2085
2089
|
var percentOf = (value) => typeof value === "number" && Number.isFinite(value) ? Math.max(0, Math.min(100, value)) : 0;
|
|
2086
2090
|
var STILL_UPLOADING = "Wait for your files to finish uploading";
|
|
2087
|
-
function FileUpload({ onFiles, files, upload, onCancel, onRetry, onRemove, accept, multiple = true, maxSize, className, error = false, label, id, "aria-label": ariaLabel }) {
|
|
2091
|
+
function FileUpload({ onFiles, files, upload, onCancel, onRetry, onRemove, accept, multiple = true, maxSize, className, error = false, label, id, "aria-label": ariaLabel, "aria-labelledby": ariaLabelledBy }) {
|
|
2088
2092
|
const controlled = files !== void 0;
|
|
2089
2093
|
const [own, setOwn] = useState([]);
|
|
2090
2094
|
const shown = controlled ? files : own;
|
|
@@ -2104,6 +2108,7 @@ function FileUpload({ onFiles, files, upload, onCancel, onRetry, onRemove, accep
|
|
|
2104
2108
|
const constraintsId = `${ownId}-constraints`;
|
|
2105
2109
|
const rejectedId = `${ownId}-rejected`;
|
|
2106
2110
|
const showLabel = label != null && !field;
|
|
2111
|
+
const control = useFieldControl({ "aria-label": ariaLabel, "aria-labelledby": ariaLabelledBy }, { component: "FileUpload", ownLabel: showLabel ? true : void 0 });
|
|
2107
2112
|
const constraints = fileConstraints(accept, maxSize, multiple);
|
|
2108
2113
|
const patch = (itemId, change) => setOwn((prev) => prev.map((i) => i.id === itemId ? { ...i, ...change } : i));
|
|
2109
2114
|
const stop = (itemId) => {
|
|
@@ -2315,8 +2320,8 @@ function FileUpload({ onFiles, files, upload, onCancel, onRetry, onRemove, accep
|
|
|
2315
2320
|
accept,
|
|
2316
2321
|
multiple,
|
|
2317
2322
|
className: "sr-only",
|
|
2318
|
-
"aria-label":
|
|
2319
|
-
"aria-labelledby":
|
|
2323
|
+
"aria-label": control.labelId ? void 0 : control.label,
|
|
2324
|
+
"aria-labelledby": control.labelId,
|
|
2320
2325
|
"aria-describedby": describedBy,
|
|
2321
2326
|
"aria-invalid": invalid || void 0,
|
|
2322
2327
|
onChange: (e) => {
|
|
@@ -2383,6 +2388,7 @@ function SliderRange({
|
|
|
2383
2388
|
error = false,
|
|
2384
2389
|
label,
|
|
2385
2390
|
"aria-label": ariaLabel,
|
|
2391
|
+
"aria-labelledby": ariaLabelledBy,
|
|
2386
2392
|
"aria-describedby": describedByProp,
|
|
2387
2393
|
trackStyle,
|
|
2388
2394
|
formatValue
|
|
@@ -2391,9 +2397,10 @@ function SliderRange({
|
|
|
2391
2397
|
const field = useField();
|
|
2392
2398
|
const ownId = useId();
|
|
2393
2399
|
const showLabel = label != null && !field;
|
|
2394
|
-
const
|
|
2400
|
+
const control = useFieldControl({ "aria-label": ariaLabel, "aria-labelledby": ariaLabelledBy }, { component: "SliderRange", ownLabel: showLabel ? `${ownId}-label` : void 0 });
|
|
2401
|
+
const nameId = control.labelId;
|
|
2395
2402
|
const describedBy = [...new Set([describedByProp, field?.describedBy].join(" ").split(" ").filter(Boolean))].join(" ") || void 0;
|
|
2396
|
-
const thumbName = (part) => nameId ? { "aria-labelledby": part ? `${nameId} ${ownId}-${part}` : nameId } : { "aria-label":
|
|
2403
|
+
const thumbName = (part) => nameId ? { "aria-labelledby": part ? `${nameId} ${ownId}-${part}` : nameId } : { "aria-label": control.label ? part ? `${control.label} ${part}` : control.label : void 0 };
|
|
2397
2404
|
const isRange = Array.isArray(value);
|
|
2398
2405
|
const low = isRange ? value[0] : value;
|
|
2399
2406
|
const high = isRange ? value[1] : value;
|
|
@@ -2607,7 +2614,7 @@ function TimePicker({
|
|
|
2607
2614
|
}) {
|
|
2608
2615
|
const onChange = useReportedChange(onChangeProp, value);
|
|
2609
2616
|
const contextSize = useContext(ControlSizeContext);
|
|
2610
|
-
const control = useFieldControl({ ...wiring, id, error: error || void 0 }, { requiredInDescription: true });
|
|
2617
|
+
const control = useFieldControl({ ...wiring, id, error: error || void 0 }, { requiredInDescription: true, component: "TimePicker" });
|
|
2611
2618
|
useInputModality();
|
|
2612
2619
|
const size = sizeProp ?? contextSize ?? "md";
|
|
2613
2620
|
const [open, setOpen] = useState(false);
|
|
@@ -3293,6 +3300,7 @@ function PinInput({
|
|
|
3293
3300
|
id,
|
|
3294
3301
|
"aria-label": ariaLabel
|
|
3295
3302
|
}) {
|
|
3303
|
+
const control = useFieldControl({ "aria-label": ariaLabel }, { component: "PinInput" });
|
|
3296
3304
|
const onChange = useReportedChange(onChangeProp, value);
|
|
3297
3305
|
useInputModality();
|
|
3298
3306
|
const contextSize = useContext(ControlSizeContext);
|
|
@@ -3350,7 +3358,8 @@ function PinInput({
|
|
|
3350
3358
|
"div",
|
|
3351
3359
|
{
|
|
3352
3360
|
role: "group",
|
|
3353
|
-
"aria-
|
|
3361
|
+
"aria-labelledby": control.labelId,
|
|
3362
|
+
"aria-label": control.labelId ? void 0 : control.label ?? "PIN input",
|
|
3354
3363
|
"aria-invalid": error || void 0,
|
|
3355
3364
|
className: cn("inline-flex w-fit items-center gap-ds-2", className),
|
|
3356
3365
|
children: digits.map((digit, i) => /* @__PURE__ */ jsx(
|
|
@@ -3442,7 +3451,8 @@ function Rating({
|
|
|
3442
3451
|
const onChange = useReportedChange(onChangeProp, value);
|
|
3443
3452
|
const [hoverValue, setHoverValue] = useState(null);
|
|
3444
3453
|
const displayValue = hoverValue ?? value;
|
|
3445
|
-
const control = useFieldControl({ ...wiring, error: error || void 0 });
|
|
3454
|
+
const control = useFieldControl({ ...wiring, error: error || void 0 }, { component: "Rating" });
|
|
3455
|
+
const valueId = `${useId()}-value`;
|
|
3446
3456
|
const handleClick = useCallback(
|
|
3447
3457
|
(starIdx, isLeftHalf) => {
|
|
3448
3458
|
if (readOnly || !onChangeProp) return;
|
|
@@ -3505,13 +3515,13 @@ function Rating({
|
|
|
3505
3515
|
i
|
|
3506
3516
|
);
|
|
3507
3517
|
});
|
|
3508
|
-
return /* @__PURE__ */
|
|
3518
|
+
return /* @__PURE__ */ jsxs(
|
|
3509
3519
|
"div",
|
|
3510
3520
|
{
|
|
3511
3521
|
role: readOnly ? "img" : "radiogroup",
|
|
3512
3522
|
id: control.id,
|
|
3513
|
-
"aria-label": readOnly ? `${control.label ?? "Rating"}: ${value} out of ${max}` : control.
|
|
3514
|
-
"aria-labelledby": readOnly ?
|
|
3523
|
+
"aria-label": control.labelId ? void 0 : readOnly ? `${control.label ?? "Rating"}: ${value} out of ${max}` : control.label ?? `Rating: ${value} out of ${max}`,
|
|
3524
|
+
"aria-labelledby": readOnly && control.labelId ? `${control.labelId} ${valueId}` : control.labelId,
|
|
3515
3525
|
"aria-describedby": control.describedBy,
|
|
3516
3526
|
"aria-invalid": readOnly ? void 0 : control.invalid || void 0,
|
|
3517
3527
|
"aria-required": readOnly ? void 0 : control.required || void 0,
|
|
@@ -3524,7 +3534,10 @@ function Rating({
|
|
|
3524
3534
|
className
|
|
3525
3535
|
),
|
|
3526
3536
|
onMouseLeave: () => setHoverValue(null),
|
|
3527
|
-
children:
|
|
3537
|
+
children: [
|
|
3538
|
+
readOnly && control.labelId && /* @__PURE__ */ jsx("span", { id: valueId, hidden: true, children: `${value} out of ${max}` }),
|
|
3539
|
+
stars
|
|
3540
|
+
]
|
|
3528
3541
|
}
|
|
3529
3542
|
);
|
|
3530
3543
|
}
|
|
@@ -3591,28 +3604,103 @@ var DEFAULT_SWATCHES = [
|
|
|
3591
3604
|
"#000000",
|
|
3592
3605
|
"#ffffff"
|
|
3593
3606
|
];
|
|
3607
|
+
function parseHex(value) {
|
|
3608
|
+
return /^#?([0-9a-f]{6}|[0-9a-f]{8})$/i.test(value.trim()) ? hexToHsl(value.trim()) : null;
|
|
3609
|
+
}
|
|
3610
|
+
var sameColor = (a, b) => a.trim().toLowerCase() === b.trim().toLowerCase();
|
|
3611
|
+
var NEUTRAL = { h: 0, s: 0, l: 50, a: 1 };
|
|
3594
3612
|
function ColorPicker({
|
|
3595
3613
|
value,
|
|
3596
3614
|
onChange: onChangeProp,
|
|
3597
3615
|
showAlpha = false,
|
|
3598
3616
|
swatches = DEFAULT_SWATCHES,
|
|
3617
|
+
swatchesOnly = false,
|
|
3599
3618
|
disabled = false,
|
|
3600
3619
|
className,
|
|
3601
|
-
|
|
3602
|
-
"aria-label": ariaLabel
|
|
3620
|
+
...wiring
|
|
3603
3621
|
}) {
|
|
3622
|
+
const control = useFieldControl(wiring, { requiredInDescription: !swatchesOnly, component: "ColorPicker" });
|
|
3623
|
+
const named = {
|
|
3624
|
+
id: control.id,
|
|
3625
|
+
"aria-label": control.labelId ? void 0 : control.label,
|
|
3626
|
+
"aria-labelledby": control.labelId,
|
|
3627
|
+
"aria-describedby": control.describedBy,
|
|
3628
|
+
"aria-invalid": control.invalid || void 0
|
|
3629
|
+
};
|
|
3604
3630
|
const onChange = useReportedChange(onChangeProp, value);
|
|
3605
3631
|
useInputModality();
|
|
3606
|
-
const [hsl, setHsl] = useState(() =>
|
|
3632
|
+
const [hsl, setHsl] = useState(() => parseHex(value) ?? NEUTRAL);
|
|
3607
3633
|
const [hexInput, setHexInput] = useState(value);
|
|
3608
3634
|
const satLightRef = useRef(null);
|
|
3609
3635
|
const draggingRef = useRef(false);
|
|
3636
|
+
const swatchRefs = useRef([]);
|
|
3610
3637
|
const [prevValue, setPrevValue] = useState(value);
|
|
3611
3638
|
if (value !== prevValue) {
|
|
3612
3639
|
setPrevValue(value);
|
|
3613
|
-
setHsl(
|
|
3640
|
+
setHsl((was) => parseHex(value) ?? was);
|
|
3614
3641
|
setHexInput(value);
|
|
3615
3642
|
}
|
|
3643
|
+
const items = swatches.map((s) => typeof s === "string" ? { value: s, label: s } : s);
|
|
3644
|
+
const repeated = items.find((s, i) => items.findIndex((o) => sameColor(o.value, s.value)) !== i)?.value;
|
|
3645
|
+
useEffect(() => {
|
|
3646
|
+
if (repeated) warnOnce("ColorPicker", `two swatches share the colour "${repeated}": give each swatch a colour of its own, so the one chosen is the one shown as chosen.`);
|
|
3647
|
+
}, [repeated]);
|
|
3648
|
+
const chosen = items.findIndex((s) => sameColor(s.value, value));
|
|
3649
|
+
const stop = Math.max(0, chosen);
|
|
3650
|
+
const choose = (index) => {
|
|
3651
|
+
const swatch = items[index];
|
|
3652
|
+
if (!swatch || disabled) return;
|
|
3653
|
+
setHsl((was) => parseHex(swatch.value) ?? was);
|
|
3654
|
+
setHexInput(swatch.value);
|
|
3655
|
+
if (!sameColor(swatch.value, value)) onChange(swatch.value);
|
|
3656
|
+
};
|
|
3657
|
+
const onSwatchKey = (e, index) => {
|
|
3658
|
+
const step = e.key === "ArrowRight" || e.key === "ArrowDown" ? 1 : e.key === "ArrowLeft" || e.key === "ArrowUp" ? -1 : 0;
|
|
3659
|
+
const to = step ? (index + step + items.length) % items.length : e.key === "Home" ? 0 : e.key === "End" ? items.length - 1 : -1;
|
|
3660
|
+
if (to < 0) return;
|
|
3661
|
+
e.preventDefault();
|
|
3662
|
+
swatchRefs.current[to]?.focus();
|
|
3663
|
+
choose(to);
|
|
3664
|
+
};
|
|
3665
|
+
const swatchRow = /* @__PURE__ */ jsx(
|
|
3666
|
+
"div",
|
|
3667
|
+
{
|
|
3668
|
+
role: "radiogroup",
|
|
3669
|
+
...swatchesOnly ? { ...named, "aria-required": control.required || void 0 } : { "aria-label": "Swatches" },
|
|
3670
|
+
"aria-disabled": disabled || void 0,
|
|
3671
|
+
className: cn("flex flex-wrap gap-ds-2", swatchesOnly && disabled && "opacity-disabled", swatchesOnly && className),
|
|
3672
|
+
children: items.map((swatch, i) => /* @__PURE__ */ jsx(AutoTooltip, { content: swatch.label, children: /* @__PURE__ */ jsx(
|
|
3673
|
+
"button",
|
|
3674
|
+
{
|
|
3675
|
+
ref: (el) => {
|
|
3676
|
+
swatchRefs.current[i] = el;
|
|
3677
|
+
},
|
|
3678
|
+
type: "button",
|
|
3679
|
+
role: "radio",
|
|
3680
|
+
"aria-checked": i === chosen,
|
|
3681
|
+
"aria-label": swatch.label,
|
|
3682
|
+
tabIndex: i === stop ? 0 : -1,
|
|
3683
|
+
disabled,
|
|
3684
|
+
onClick: () => choose(i),
|
|
3685
|
+
onKeyDown: (e) => onSwatchKey(e, i),
|
|
3686
|
+
className: cn(
|
|
3687
|
+
"w-7 h-7 rounded-[var(--ds-radius-sm)] cursor-pointer disabled:cursor-not-allowed",
|
|
3688
|
+
"flex items-center justify-center",
|
|
3689
|
+
"border-[length:var(--ds-border-width)]",
|
|
3690
|
+
"hover:scale-110 transition-transform",
|
|
3691
|
+
FOCUS_RING,
|
|
3692
|
+
// selected is a choice's look: the accent border, never the halo (that is active's) or an outline
|
|
3693
|
+
i === chosen ? "border-[var(--ds-accent-ink)]" : "border-[var(--ds-border-default)]"
|
|
3694
|
+
),
|
|
3695
|
+
style: { backgroundColor: swatch.value },
|
|
3696
|
+
children: i === chosen && /* @__PURE__ */ jsxs("svg", { "data-swatch-check": "", "aria-hidden": "true", width: 16, height: 16, viewBox: "0 0 24 24", fill: "none", strokeLinecap: "round", strokeLinejoin: "round", className: "pointer-events-none", children: [
|
|
3697
|
+
/* @__PURE__ */ jsx("path", { d: "M20 6 9 17l-5-5", vectorEffect: "non-scaling-stroke", strokeWidth: 6.5, style: { stroke: "var(--ds-text-primary)" } }),
|
|
3698
|
+
/* @__PURE__ */ jsx("path", { d: "M20 6 9 17l-5-5", vectorEffect: "non-scaling-stroke", strokeWidth: 2.5, style: { stroke: "var(--ds-bg-canvas)" } })
|
|
3699
|
+
] })
|
|
3700
|
+
}
|
|
3701
|
+
) }, `${swatch.value}-${i}`))
|
|
3702
|
+
}
|
|
3703
|
+
);
|
|
3616
3704
|
const emitChange = useCallback(
|
|
3617
3705
|
(newHsl) => {
|
|
3618
3706
|
setHsl(newHsl);
|
|
@@ -3661,23 +3749,24 @@ function ColorPicker({
|
|
|
3661
3749
|
},
|
|
3662
3750
|
[onChange]
|
|
3663
3751
|
);
|
|
3752
|
+
if (swatchesOnly) return swatchRow;
|
|
3664
3753
|
return /* @__PURE__ */ jsxs(
|
|
3665
3754
|
"div",
|
|
3666
3755
|
{
|
|
3667
3756
|
role: "group",
|
|
3668
|
-
|
|
3669
|
-
"aria-invalid": error || void 0,
|
|
3757
|
+
...named,
|
|
3670
3758
|
className: cn(
|
|
3671
3759
|
"w-full max-w-64 p-ds-3 space-y-ds-3",
|
|
3672
3760
|
"bg-[var(--ds-bg-surface)] text-[var(--ds-text-primary)]",
|
|
3673
3761
|
"border-[length:var(--ds-border-width)]",
|
|
3674
|
-
|
|
3762
|
+
control.invalid ? "border-[var(--ds-status-error)]" : "border-[var(--ds-border-default)]",
|
|
3675
3763
|
"rounded-[var(--ds-radius-lg)]",
|
|
3676
3764
|
"shadow-[var(--ds-shadow-md)]",
|
|
3677
3765
|
disabled && "opacity-disabled pointer-events-none",
|
|
3678
3766
|
className
|
|
3679
3767
|
),
|
|
3680
3768
|
children: [
|
|
3769
|
+
control.requiredNote,
|
|
3681
3770
|
/* @__PURE__ */ jsx(
|
|
3682
3771
|
"div",
|
|
3683
3772
|
{
|
|
@@ -3710,6 +3799,7 @@ function ColorPicker({
|
|
|
3710
3799
|
{
|
|
3711
3800
|
type: "range",
|
|
3712
3801
|
"aria-label": "Hue",
|
|
3802
|
+
disabled,
|
|
3713
3803
|
min: 0,
|
|
3714
3804
|
max: 360,
|
|
3715
3805
|
value: hsl.h,
|
|
@@ -3725,6 +3815,7 @@ function ColorPicker({
|
|
|
3725
3815
|
{
|
|
3726
3816
|
type: "range",
|
|
3727
3817
|
"aria-label": "Opacity",
|
|
3818
|
+
disabled,
|
|
3728
3819
|
min: 0,
|
|
3729
3820
|
max: 100,
|
|
3730
3821
|
value: Math.round(hsl.a * 100),
|
|
@@ -3740,7 +3831,7 @@ function ColorPicker({
|
|
|
3740
3831
|
"div",
|
|
3741
3832
|
{
|
|
3742
3833
|
className: "w-8 h-8 rounded-[var(--ds-radius-sm)] border-[length:var(--ds-border-width)] border-[var(--ds-border-default)] shrink-0",
|
|
3743
|
-
style: { backgroundColor: hslToHex(hsl) }
|
|
3834
|
+
style: { backgroundColor: parseHex(value) ? hslToHex(hsl) : value }
|
|
3744
3835
|
}
|
|
3745
3836
|
),
|
|
3746
3837
|
/* @__PURE__ */ jsx(
|
|
@@ -3748,6 +3839,7 @@ function ColorPicker({
|
|
|
3748
3839
|
{
|
|
3749
3840
|
type: "text",
|
|
3750
3841
|
"aria-label": "Hex colour",
|
|
3842
|
+
disabled,
|
|
3751
3843
|
value: hexInput,
|
|
3752
3844
|
onChange: (e) => handleHexChange(e.target.value),
|
|
3753
3845
|
className: cn(
|
|
@@ -3761,27 +3853,7 @@ function ColorPicker({
|
|
|
3761
3853
|
}
|
|
3762
3854
|
)
|
|
3763
3855
|
] }),
|
|
3764
|
-
swatches.length > 0 &&
|
|
3765
|
-
"button",
|
|
3766
|
-
{
|
|
3767
|
-
type: "button",
|
|
3768
|
-
onClick: () => {
|
|
3769
|
-
const parsed = hexToHsl(swatch);
|
|
3770
|
-
emitChange(parsed);
|
|
3771
|
-
},
|
|
3772
|
-
className: cn(
|
|
3773
|
-
"w-7 h-7 rounded-[var(--ds-radius-sm)] cursor-pointer",
|
|
3774
|
-
"border-[length:var(--ds-border-width)]",
|
|
3775
|
-
"hover:scale-110 transition-transform",
|
|
3776
|
-
FOCUS_RING,
|
|
3777
|
-
// selected is a choice's look: the accent border, never the halo (that is active's) or an outline
|
|
3778
|
-
swatch.toLowerCase() === value.toLowerCase() ? "border-[var(--ds-accent-ink)]" : "border-[var(--ds-border-default)]"
|
|
3779
|
-
),
|
|
3780
|
-
style: { backgroundColor: swatch },
|
|
3781
|
-
"aria-label": swatch
|
|
3782
|
-
},
|
|
3783
|
-
swatch
|
|
3784
|
-
)) })
|
|
3856
|
+
swatches.length > 0 && swatchRow
|
|
3785
3857
|
]
|
|
3786
3858
|
}
|
|
3787
3859
|
);
|
|
@@ -4079,10 +4151,10 @@ function FormWrapper({ onSubmit, validationMode: validationModeProp, children, a
|
|
|
4079
4151
|
return;
|
|
4080
4152
|
}
|
|
4081
4153
|
const first = form.querySelector("[aria-invalid='true']");
|
|
4082
|
-
if (first) {
|
|
4154
|
+
if (first) openToFocus(first, () => {
|
|
4083
4155
|
if (typeof first.scrollIntoView === "function") first.scrollIntoView({ block: "center", behavior: "smooth" });
|
|
4084
4156
|
focusTarget(first).focus({ preventScroll: true });
|
|
4085
|
-
}
|
|
4157
|
+
});
|
|
4086
4158
|
}
|
|
4087
4159
|
}, [submittedRef, errorSummaryRef, focusSummary]);
|
|
4088
4160
|
useLayoutEffect(() => {
|
|
@@ -4164,10 +4236,10 @@ function FormWrapper({ onSubmit, validationMode: validationModeProp, children, a
|
|
|
4164
4236
|
const focusField = (id) => (e) => {
|
|
4165
4237
|
e.preventDefault();
|
|
4166
4238
|
const el = id ? document.getElementById(id) : null;
|
|
4167
|
-
if (el) {
|
|
4239
|
+
if (el) openToFocus(el, () => {
|
|
4168
4240
|
el.scrollIntoView?.({ block: "center" });
|
|
4169
4241
|
focusTarget(el).focus();
|
|
4170
|
-
}
|
|
4242
|
+
});
|
|
4171
4243
|
};
|
|
4172
4244
|
const summaryNode = errorSummary && summary.length >= 2 ? typeof errorSummary === "function" ? errorSummary(summary) : /* @__PURE__ */ jsx(Alert, { variant: "error", title: `${summary.length} fields need attention`, className: "mb-ds-4", children: /* @__PURE__ */ jsx("ul", { className: "list-disc pl-ds-5 flex flex-col gap-ds-1", children: summary.map((f) => /* @__PURE__ */ jsxs("li", { children: [
|
|
4173
4245
|
/* @__PURE__ */ jsx("a", { href: f.id ? `#${f.id}` : void 0, onClick: focusField(f.id), className: cn("underline underline-offset-2 text-[var(--ds-text-primary)]", FOCUS_RING), children: f.label }),
|
|
@@ -4513,7 +4585,7 @@ function MentionInput({
|
|
|
4513
4585
|
"aria-label": ariaLabel,
|
|
4514
4586
|
...wiring
|
|
4515
4587
|
}) {
|
|
4516
|
-
const control = useFieldControl({ ...wiring, error: error || void 0 });
|
|
4588
|
+
const control = useFieldControl({ ...wiring, "aria-label": ariaLabel, error: error || void 0 }, { component: "MentionInput" });
|
|
4517
4589
|
useInputModality();
|
|
4518
4590
|
const [internalValue, setInternalValue] = useState("");
|
|
4519
4591
|
const value = controlledValue ?? internalValue;
|
|
@@ -4632,8 +4704,8 @@ function MentionInput({
|
|
|
4632
4704
|
{
|
|
4633
4705
|
ref: inputRef,
|
|
4634
4706
|
id: control.id,
|
|
4635
|
-
"aria-labelledby": wiring["aria-labelledby"],
|
|
4636
|
-
"aria-label": control.labelId ? void 0 :
|
|
4707
|
+
"aria-labelledby": control.shown ? void 0 : wiring["aria-labelledby"],
|
|
4708
|
+
"aria-label": control.labelId ? void 0 : control.label,
|
|
4637
4709
|
"aria-describedby": control.describedBy,
|
|
4638
4710
|
"aria-invalid": control.invalid || void 0,
|
|
4639
4711
|
"aria-required": control.required || void 0,
|
|
@@ -5782,6 +5854,131 @@ function rowMarks(row, index, field, id) {
|
|
|
5782
5854
|
return typeof v === "string" || typeof v === "number" ? { "data-row-key": String(id) } : { "data-row-index": String(index) };
|
|
5783
5855
|
}
|
|
5784
5856
|
var idPart = (id) => String(id).replace(/\s+/g, "_");
|
|
5857
|
+
var an = (word) => /^[aeiou]/i.test(word) ? "an" : "a";
|
|
5858
|
+
var MAX_TREE_DEPTH = 64;
|
|
5859
|
+
var MAX_TREE_ROWS = 1e5;
|
|
5860
|
+
var COPY_BUDGET = 1e3;
|
|
5861
|
+
var isPlainObject = (o) => {
|
|
5862
|
+
const proto = Object.getPrototypeOf(o);
|
|
5863
|
+
return proto === Object.prototype || proto === null;
|
|
5864
|
+
};
|
|
5865
|
+
function isCopy(above, row, field) {
|
|
5866
|
+
if (above === row) return true;
|
|
5867
|
+
if (!Object.is(above[field], row[field])) return false;
|
|
5868
|
+
let left = COPY_BUDGET;
|
|
5869
|
+
const alike = (a, b) => {
|
|
5870
|
+
if (Object.is(a, b)) return true;
|
|
5871
|
+
if (typeof a === "function" && typeof b === "function") return true;
|
|
5872
|
+
if (typeof a !== "object" || typeof b !== "object" || a === null || b === null || --left < 0) return false;
|
|
5873
|
+
if (isValidElement(a) || isValidElement(b)) return isValidElement(a) && isValidElement(b) && a.type === b.type && a.key === b.key && alike(a.props, b.props);
|
|
5874
|
+
if (Array.isArray(a) || Array.isArray(b)) return Array.isArray(a) && Array.isArray(b) && a.length === b.length && a.every((v, i) => alike(v, b[i]));
|
|
5875
|
+
if (a instanceof Date && b instanceof Date) return a.getTime() === b.getTime();
|
|
5876
|
+
if (!isPlainObject(a) || !isPlainObject(b)) return false;
|
|
5877
|
+
const keys = Object.keys(a);
|
|
5878
|
+
return keys.length === Object.keys(b).length && keys.every((k) => Object.hasOwn(b, k) && alike(a[k], b[k]));
|
|
5879
|
+
};
|
|
5880
|
+
return alike(above, row);
|
|
5881
|
+
}
|
|
5882
|
+
function treeOf(data, ids, field, childrenOf) {
|
|
5883
|
+
const byKey = /* @__PURE__ */ new Map();
|
|
5884
|
+
const all = [];
|
|
5885
|
+
const own = /* @__PURE__ */ new Set();
|
|
5886
|
+
let unnamed = false;
|
|
5887
|
+
let repeated = null;
|
|
5888
|
+
let looped = null;
|
|
5889
|
+
let tooDeep = false;
|
|
5890
|
+
let tooMany = false;
|
|
5891
|
+
const named = (row) => {
|
|
5892
|
+
const v = row[field];
|
|
5893
|
+
if (typeof v !== "string" && typeof v !== "number") return false;
|
|
5894
|
+
if (own.has(String(v))) repeated ??= String(v);
|
|
5895
|
+
own.add(String(v));
|
|
5896
|
+
return true;
|
|
5897
|
+
};
|
|
5898
|
+
const roots = data.map((row, i) => ({ row, originalIdx: i, id: ids[i] ?? i, level: 1, parent: null, children: [] }));
|
|
5899
|
+
for (const node of roots) {
|
|
5900
|
+
byKey.set(String(node.id), node);
|
|
5901
|
+
if (!named(node.row)) unnamed = true;
|
|
5902
|
+
}
|
|
5903
|
+
const grow = (node, path) => {
|
|
5904
|
+
all.push(node);
|
|
5905
|
+
if (all.length >= MAX_TREE_ROWS) {
|
|
5906
|
+
tooMany = true;
|
|
5907
|
+
return;
|
|
5908
|
+
}
|
|
5909
|
+
const rows = childrenOf(node.row, { level: node.level, parent: node.parent?.row ?? null });
|
|
5910
|
+
if (!rows?.length) return;
|
|
5911
|
+
if (node.level >= MAX_TREE_DEPTH) {
|
|
5912
|
+
tooDeep = true;
|
|
5913
|
+
return;
|
|
5914
|
+
}
|
|
5915
|
+
path.push(node.row);
|
|
5916
|
+
rows.forEach((row, i) => {
|
|
5917
|
+
const place = `${node.id}/${i}`;
|
|
5918
|
+
if (path.some((above) => isCopy(above, row, field))) {
|
|
5919
|
+
looped ??= typeof row[field] === "string" || typeof row[field] === "number" ? String(row[field]) : place;
|
|
5920
|
+
return;
|
|
5921
|
+
}
|
|
5922
|
+
const hasOwn = named(row);
|
|
5923
|
+
if (!hasOwn) unnamed = true;
|
|
5924
|
+
const v = row[field];
|
|
5925
|
+
const id = hasOwn && !byKey.has(String(v)) ? v : hasOwn ? `${v}~${place}` : place;
|
|
5926
|
+
const child = { row, originalIdx: -1, id, level: node.level + 1, parent: node, children: [] };
|
|
5927
|
+
byKey.set(String(id), child);
|
|
5928
|
+
node.children.push(child);
|
|
5929
|
+
grow(child, path);
|
|
5930
|
+
});
|
|
5931
|
+
path.pop();
|
|
5932
|
+
};
|
|
5933
|
+
for (const node of roots) grow(node, []);
|
|
5934
|
+
return { roots, byKey, all, unnamed, repeated, looped, tooDeep, tooMany };
|
|
5935
|
+
}
|
|
5936
|
+
function keysUnder(node, out = []) {
|
|
5937
|
+
out.push(String(node.id));
|
|
5938
|
+
for (const child of node.children) keysUnder(child, out);
|
|
5939
|
+
return out;
|
|
5940
|
+
}
|
|
5941
|
+
function settleSelection(roots, chosen) {
|
|
5942
|
+
const set = new Set(chosen);
|
|
5943
|
+
const partly = /* @__PURE__ */ new Set();
|
|
5944
|
+
const down = (node, on) => {
|
|
5945
|
+
const now = on || set.has(String(node.id));
|
|
5946
|
+
if (now) set.add(String(node.id));
|
|
5947
|
+
for (const child of node.children) down(child, now);
|
|
5948
|
+
};
|
|
5949
|
+
const up = (node) => {
|
|
5950
|
+
const key = String(node.id);
|
|
5951
|
+
if (!node.children.length) return set.has(key) ? "all" : "none";
|
|
5952
|
+
const states = node.children.map(up);
|
|
5953
|
+
const all = states.every((s) => s === "all");
|
|
5954
|
+
if (all) set.add(key);
|
|
5955
|
+
else set.delete(key);
|
|
5956
|
+
if (!all && states.some((s) => s !== "none")) partly.add(key);
|
|
5957
|
+
return all ? "all" : partly.has(key) ? "some" : "none";
|
|
5958
|
+
};
|
|
5959
|
+
for (const root of roots) down(root, false);
|
|
5960
|
+
for (const root of roots) up(root);
|
|
5961
|
+
return { set, partly };
|
|
5962
|
+
}
|
|
5963
|
+
var TREE_TOGGLE = cn(
|
|
5964
|
+
"relative shrink-0 w-4 h-4 flex items-center justify-center cursor-pointer rounded-[var(--ds-radius-sm)]",
|
|
5965
|
+
"text-[var(--ds-text-muted)] hover:text-[var(--ds-text-primary)]",
|
|
5966
|
+
"before:absolute before:left-1/2 before:top-1/2 before:h-6 before:w-6 before:-translate-x-1/2 before:-translate-y-1/2 before:content-['']",
|
|
5967
|
+
FOCUS_RING
|
|
5968
|
+
);
|
|
5969
|
+
function rowsOfKey(body, ownKey, key) {
|
|
5970
|
+
return key === "" ? [] : Array.from(body.querySelectorAll(`:scope > tr[data-grid-key="${CSS.escape(ownKey + key)}"], :scope > tr[data-panel-of="${CSS.escape(key)}"]`));
|
|
5971
|
+
}
|
|
5972
|
+
var HEAD_KEY = "head:";
|
|
5973
|
+
var TreeHeldCtx = createContext(false);
|
|
5974
|
+
var CARD_TOGGLE = cn(
|
|
5975
|
+
// at least 24 px tall: the card around it is a target too, so its own box must meet the size (WCAG 2.5.8)
|
|
5976
|
+
"inline-flex min-h-[24px] items-center gap-ds-1 text-xs font-medium cursor-pointer",
|
|
5977
|
+
"transition-colors duration-[var(--ds-transition-speed)]",
|
|
5978
|
+
"text-[var(--ds-accent-ink)] hover:bg-[var(--ds-accent-muted)]",
|
|
5979
|
+
"rounded-[var(--ds-radius-sm)] px-ds-1.5 py-ds-0.5 -mx-ds-1.5",
|
|
5980
|
+
FOCUS_RING
|
|
5981
|
+
);
|
|
5785
5982
|
function TableHeading({ title, description, actions, titleId, descriptionId, inset }) {
|
|
5786
5983
|
const heading = /* @__PURE__ */ jsx("h3", { id: titleId, className: TITLE_CLASSES, children: title });
|
|
5787
5984
|
const actionsBlock = actions ? /* @__PURE__ */ jsx("div", { className: HEADER_LAYOUT.actions, children: actions }) : null;
|
|
@@ -5819,6 +6016,12 @@ function Table({
|
|
|
5819
6016
|
selectable,
|
|
5820
6017
|
selectedRows = [],
|
|
5821
6018
|
onSelectionChange,
|
|
6019
|
+
selectedKeys,
|
|
6020
|
+
onSelectedKeysChange,
|
|
6021
|
+
getChildRows,
|
|
6022
|
+
openParents: openParentsProp,
|
|
6023
|
+
defaultOpenParents,
|
|
6024
|
+
onOpenParentsChange,
|
|
5822
6025
|
expandable,
|
|
5823
6026
|
renderExpanded,
|
|
5824
6027
|
rowKey = "id",
|
|
@@ -5879,8 +6082,13 @@ function Table({
|
|
|
5879
6082
|
},
|
|
5880
6083
|
[sortKey, sortDir, onSortChange, pager]
|
|
5881
6084
|
);
|
|
6085
|
+
const { ids: rowIds, repeated } = useMemo(() => rowIdsOf(data, rowKey), [data, rowKey]);
|
|
6086
|
+
const tree = useMemo(() => getChildRows ? treeOf(data, rowIds, rowKey, getChildRows) : null, [data, rowIds, rowKey, getChildRows]);
|
|
6087
|
+
const nested = tree;
|
|
6088
|
+
const idOf = (_row, index) => rowIds[index] ?? index;
|
|
5882
6089
|
const columnKeys = useMemo(() => columns.map((c) => c.key), [columns]);
|
|
5883
|
-
const
|
|
6090
|
+
const allRows = useMemo(() => nested ? nested.all.map((n) => n.row) : data, [nested, data]);
|
|
6091
|
+
const inferredKinds = useMemo(() => inferColumnKinds(allRows, columnKeys), [allRows, columnKeys]);
|
|
5884
6092
|
const kindOf2 = useCallback(
|
|
5885
6093
|
(col) => col.kind ?? inferredKinds.get(col.key),
|
|
5886
6094
|
[inferredKinds]
|
|
@@ -5888,9 +6096,9 @@ function Table({
|
|
|
5888
6096
|
const sortColumn = sortKey ? columns.find((c) => c.key === sortKey) : void 0;
|
|
5889
6097
|
const sortKind = sortColumn ? kindOf2(sortColumn) : void 0;
|
|
5890
6098
|
const locale = useFormatLocale();
|
|
5891
|
-
const { sortedAll, unsortable } = useMemo(() => {
|
|
6099
|
+
const { sortedAll, unsortable, childOrder } = useMemo(() => {
|
|
5892
6100
|
const indexed = data.map((row, i) => ({ row, originalIdx: i }));
|
|
5893
|
-
if (!sortKey || !sortDir) return { sortedAll: indexed, unsortable: null };
|
|
6101
|
+
if (!sortKey || !sortDir) return { sortedAll: indexed, unsortable: null, childOrder: null };
|
|
5894
6102
|
const read = (row) => {
|
|
5895
6103
|
if (sortColumn?.sortValue) return sortableValue(sortColumn.sortValue(row));
|
|
5896
6104
|
const v = sortableValue(row[sortKey]);
|
|
@@ -5898,29 +6106,33 @@ function Table({
|
|
|
5898
6106
|
return (sortKind === "number" ? numberOf(v) : sortKind === "date" ? timeOf(v) : void 0) ?? v;
|
|
5899
6107
|
};
|
|
5900
6108
|
const valued = indexed.map((entry) => ({ ...entry, value: read(entry.row) }));
|
|
5901
|
-
const
|
|
5902
|
-
const
|
|
6109
|
+
const levels = nested ? nested.all.filter((n) => n.children.length).map((n) => ({ key: String(n.id), rows: n.children.map((c) => ({ c, value: read(c.row) })) })) : [];
|
|
6110
|
+
const elements = valued.some((v) => v.value === null) || levels.some((l) => l.rows.some((r) => r.value === null));
|
|
6111
|
+
const compare = (a, b) => {
|
|
5903
6112
|
if (a.value === void 0 || b.value === void 0) return a.value === b.value ? 0 : a.value === void 0 ? 1 : -1;
|
|
5904
6113
|
const cmp = compareValues(a.value, b.value, locale);
|
|
5905
6114
|
return sortDir === "asc" ? cmp : -cmp;
|
|
5906
|
-
}
|
|
5907
|
-
|
|
5908
|
-
|
|
6115
|
+
};
|
|
6116
|
+
const sorted = elements ? indexed : valued.sort(compare);
|
|
6117
|
+
const childOrder2 = elements || !nested ? null : new Map(levels.map((l) => [l.key, l.rows.sort(compare).map((r) => r.c)]));
|
|
6118
|
+
return { sortedAll: sorted, unsortable: elements ? sortKey : null, childOrder: childOrder2 };
|
|
6119
|
+
}, [data, sortKey, sortDir, sortColumn, sortKind, locale, nested]);
|
|
5909
6120
|
const canSort = useMemo(() => {
|
|
5910
6121
|
const can = /* @__PURE__ */ new Set();
|
|
5911
|
-
for (const col of columns) if (col.sortValue ||
|
|
6122
|
+
for (const col of columns) if (col.sortValue || allRows.every((row) => sortableValue(row[col.key]) !== null)) can.add(col.key);
|
|
5912
6123
|
return can;
|
|
5913
|
-
}, [columns,
|
|
6124
|
+
}, [columns, allRows]);
|
|
5914
6125
|
useEffect(() => {
|
|
5915
6126
|
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).`);
|
|
5916
6127
|
}, [unsortable]);
|
|
5917
6128
|
const pageSorts = !!onSortChange;
|
|
6129
|
+
const sortsBy = (col) => col.header.trim() !== "" && (pageSorts ? col.sortable ?? (!!sortable && canSort.has(col.key)) : (col.sortable ?? !!sortable) && canSort.has(col.key));
|
|
5918
6130
|
const refused = pageSorts ? "" : columns.filter((col) => col.sortable && !canSort.has(col.key)).map((col) => col.key).join(", ");
|
|
5919
6131
|
useEffect(() => {
|
|
5920
6132
|
if (refused) warnOnce("Table", `the column "${refused}" is marked sortable, but its cells are elements the Table can't compare, so it draws no sort button: give it a sortValue, (row) => the name, number or date it shows, or sort the rows yourself with sortKey and onSortChange (data_display#1).`);
|
|
5921
6133
|
}, [refused]);
|
|
5922
6134
|
useEffect(() => {
|
|
5923
|
-
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
|
|
6135
|
+
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.`);
|
|
5924
6136
|
}, [pager, data.length]);
|
|
5925
6137
|
const rangeStart = pager ? pager.range[0] : null;
|
|
5926
6138
|
const rangeEnd2 = pager ? pager.range[1] : null;
|
|
@@ -5929,14 +6141,65 @@ function Table({
|
|
|
5929
6141
|
[sortedAll, rangeStart, rangeEnd2]
|
|
5930
6142
|
);
|
|
5931
6143
|
const drawnStart = rangeStart ? rangeStart - 1 : 0;
|
|
6144
|
+
const openControlled = openParentsProp !== void 0;
|
|
6145
|
+
const [ownOpen, setOwnOpen] = useState(defaultOpenParents ?? []);
|
|
6146
|
+
const open = openControlled ? openParentsProp : ownOpen;
|
|
6147
|
+
const openSet = new Set(open.map(String));
|
|
6148
|
+
const setOpen = (next) => {
|
|
6149
|
+
if (!openControlled) setOwnOpen(next);
|
|
6150
|
+
onOpenParentsChange?.(next);
|
|
6151
|
+
};
|
|
6152
|
+
const toggleOpen = (id) => setOpen(openSet.has(String(id)) ? open.filter((k) => String(k) !== String(id)) : [...open, id]);
|
|
6153
|
+
const visible = nested ? [] : null;
|
|
6154
|
+
if (nested && visible) {
|
|
6155
|
+
const walk = (nodes, first, size) => nodes.forEach((node, i) => {
|
|
6156
|
+
visible.push({ node, pos: first + i, size });
|
|
6157
|
+
if (!node.children.length || !openSet.has(String(node.id))) return;
|
|
6158
|
+
const under = childOrder?.get(String(node.id)) ?? node.children;
|
|
6159
|
+
walk(under, 1, under.length);
|
|
6160
|
+
});
|
|
6161
|
+
walk(drawn.map((d) => nested.roots[d.originalIdx]), drawnStart + 1, data.length);
|
|
6162
|
+
}
|
|
6163
|
+
const visibleKeys = visible ? visible.map((v) => String(v.node.id)) : [];
|
|
6164
|
+
const reportRows = useReportedChange(onSelectionChange, selectedRows);
|
|
6165
|
+
const reportKeys = useReportedChange(onSelectedKeysChange, selectedKeys);
|
|
5932
6166
|
const selectedSet = new Set(selectedRows);
|
|
5933
6167
|
const drawnIdx = drawn.map((d) => d.originalIdx);
|
|
5934
|
-
const
|
|
5935
|
-
const
|
|
6168
|
+
const keyed = selectedKeys !== void 0 || onSelectedKeysChange !== void 0;
|
|
6169
|
+
const chosen = useMemo(() => {
|
|
6170
|
+
if (!keyed) return null;
|
|
6171
|
+
const keys = (selectedKeys ?? []).map(String);
|
|
6172
|
+
return nested ? settleSelection(nested.roots, keys) : { set: new Set(keys), partly: /* @__PURE__ */ new Set() };
|
|
6173
|
+
}, [keyed, selectedKeys, nested]);
|
|
6174
|
+
const scopeKeys = chosen ? nested ? drawn.flatMap((d) => keysUnder(nested.roots[d.originalIdx])) : drawn.map((d) => String(idOf(d.row, d.originalIdx))) : null;
|
|
6175
|
+
const allSelected = scopeKeys ? scopeKeys.length > 0 && scopeKeys.every((k) => chosen.set.has(k)) : drawnIdx.length > 0 && drawnIdx.every((i) => selectedSet.has(i));
|
|
6176
|
+
const someSelected = !allSelected && (scopeKeys ? scopeKeys.some((k) => chosen.set.has(k)) : drawnIdx.some((i) => selectedSet.has(i)));
|
|
6177
|
+
const emitKeys = (next) => {
|
|
6178
|
+
const settled = nested ? settleSelection(nested.roots, next).set : next;
|
|
6179
|
+
const out = [];
|
|
6180
|
+
const placed = /* @__PURE__ */ new Set();
|
|
6181
|
+
const put = (key) => {
|
|
6182
|
+
if (!settled.has(String(key)) || placed.has(String(key))) return;
|
|
6183
|
+
placed.add(String(key));
|
|
6184
|
+
out.push(key);
|
|
6185
|
+
};
|
|
6186
|
+
for (const key of selectedKeys ?? []) put(key);
|
|
6187
|
+
for (const key of nested ? nested.all.map((n) => n.id) : rowIds) put(key);
|
|
6188
|
+
reportKeys(out);
|
|
6189
|
+
};
|
|
5936
6190
|
const toggleAll = () => {
|
|
6191
|
+
if (chosen && scopeKeys) {
|
|
6192
|
+
const next = new Set(chosen.set);
|
|
6193
|
+
for (const key of scopeKeys) {
|
|
6194
|
+
if (allSelected) next.delete(key);
|
|
6195
|
+
else next.add(key);
|
|
6196
|
+
}
|
|
6197
|
+
emitKeys(next);
|
|
6198
|
+
return;
|
|
6199
|
+
}
|
|
5937
6200
|
const shown = new Set(drawnIdx);
|
|
5938
|
-
if (allSelected)
|
|
5939
|
-
else
|
|
6201
|
+
if (allSelected) reportRows(selectedRows.filter((r) => !shown.has(r)));
|
|
6202
|
+
else reportRows([...selectedRows.filter((r) => !shown.has(r)), ...drawnIdx]);
|
|
5940
6203
|
};
|
|
5941
6204
|
const anchor = useRef(null);
|
|
5942
6205
|
const toggleRow = (idx, shiftKey2 = false) => {
|
|
@@ -5945,22 +6208,81 @@ function Table({
|
|
|
5945
6208
|
anchor.current = idx;
|
|
5946
6209
|
if (shiftKey2 && from >= 0 && to >= 0 && from !== to) {
|
|
5947
6210
|
const run = drawnIdx.slice(Math.min(from, to), Math.max(from, to) + 1);
|
|
5948
|
-
|
|
6211
|
+
reportRows([...selectedRows.filter((r) => !run.includes(r)), ...run]);
|
|
5949
6212
|
return;
|
|
5950
6213
|
}
|
|
5951
|
-
if (selectedSet.has(idx))
|
|
5952
|
-
else
|
|
6214
|
+
if (selectedSet.has(idx)) reportRows(selectedRows.filter((r) => r !== idx));
|
|
6215
|
+
else reportRows([...selectedRows, idx]);
|
|
5953
6216
|
};
|
|
6217
|
+
const anchorKey = useRef(null);
|
|
6218
|
+
const toggleKey = (id, shiftKey2 = false) => {
|
|
6219
|
+
if (!chosen) return;
|
|
6220
|
+
const key = String(id);
|
|
6221
|
+
const node = nested?.byKey.get(key);
|
|
6222
|
+
const order = nested ? visibleKeys : drawn.map((d) => String(idOf(d.row, d.originalIdx)));
|
|
6223
|
+
const from = anchorKey.current === null ? -1 : order.indexOf(anchorKey.current);
|
|
6224
|
+
const to = order.indexOf(key);
|
|
6225
|
+
anchorKey.current = key;
|
|
6226
|
+
const under = (k) => {
|
|
6227
|
+
const n = nested?.byKey.get(k);
|
|
6228
|
+
return n ? keysUnder(n) : [k];
|
|
6229
|
+
};
|
|
6230
|
+
const next = new Set(chosen.set);
|
|
6231
|
+
if (shiftKey2 && from >= 0 && to >= 0 && from !== to) {
|
|
6232
|
+
for (const k of order.slice(Math.min(from, to), Math.max(from, to) + 1)) for (const s of under(k)) next.add(s);
|
|
6233
|
+
} else if (chosen.set.has(key)) {
|
|
6234
|
+
for (const s of under(key)) next.delete(s);
|
|
6235
|
+
for (let p = node?.parent; p; p = p.parent) next.delete(String(p.id));
|
|
6236
|
+
} else {
|
|
6237
|
+
for (const s of under(key)) next.add(s);
|
|
6238
|
+
}
|
|
6239
|
+
emitKeys(next);
|
|
6240
|
+
};
|
|
6241
|
+
const boxOf = (originalIdx, id) => {
|
|
6242
|
+
if (chosen) return { checked: chosen.set.has(String(id)), mixed: chosen.partly.has(String(id)) };
|
|
6243
|
+
return originalIdx < 0 ? null : { checked: selectedSet.has(originalIdx), mixed: false };
|
|
6244
|
+
};
|
|
6245
|
+
const toggleBox = (originalIdx, id, shiftKey2 = false) => chosen ? toggleKey(id, shiftKey2) : toggleRow(originalIdx, shiftKey2);
|
|
6246
|
+
useEffect(() => {
|
|
6247
|
+
if (nested && selectable && !keyed) warnOnce("Table", "a tree table (getChildRows) selects by key: give it selectedKeys and onSelectedKeysChange, as a row under another has no index in data, and selectedRows reaches the top-level rows only.");
|
|
6248
|
+
}, [nested, selectable, keyed]);
|
|
6249
|
+
useEffect(() => {
|
|
6250
|
+
if (nested?.unnamed) warnOnce("Table", `a tree table (getChildRows) names its rows by their ${rowKey}: give every row its own, the rows under a row too (rowKey), so an open row, a selection and focus stay on their row.`);
|
|
6251
|
+
}, [nested, rowKey]);
|
|
6252
|
+
useEffect(() => {
|
|
6253
|
+
if (nested?.looped != null) warnOnce("Table", `a tree table's row "${nested.looped}" is under itself: getChildRows gave it, or a copy of it, among the rows under it or under a row below it, so the tree would never end, and it is left out there. Give getChildRows the rows each row holds, by the level and the parent it gives.`);
|
|
6254
|
+
}, [nested, rowKey]);
|
|
6255
|
+
useEffect(() => {
|
|
6256
|
+
if (nested?.tooMany) warnOnce("Table", `a tree table's rows come to more than ${MAX_TREE_ROWS.toLocaleString("en-GB")}, and the rest are drawn with no rows under them: give getChildRows an end, answering by the level it gives and giving no rows past the last level.`);
|
|
6257
|
+
}, [nested]);
|
|
6258
|
+
useEffect(() => {
|
|
6259
|
+
if (nested?.tooDeep) warnOnce("Table", `a tree table's rows go deeper than ${MAX_TREE_DEPTH} levels, and the last is drawn with no rows under it: give getChildRows's rows an end, answering by the level it gives.`);
|
|
6260
|
+
}, [nested]);
|
|
6261
|
+
useEffect(() => {
|
|
6262
|
+
if (nested?.repeated != null) warnOnce("Table", `a tree table (getChildRows) needs ${an(rowKey)} ${rowKey} of its own for each row, one per row across every level: "${nested.repeated}" names more than one, so an open row, a selection and focus may go to the other. Number the levels' rows apart ("task-3", "task-3/step-1").`);
|
|
6263
|
+
}, [nested, rowKey]);
|
|
5954
6264
|
const expandControlled = expandedRowsProp !== void 0;
|
|
5955
6265
|
const [ownExpanded, setOwnExpanded] = useState(defaultExpandedRows ?? []);
|
|
5956
6266
|
const expanded = expandControlled ? expandedRowsProp : ownExpanded;
|
|
5957
6267
|
const expandedSet = new Set(expanded.map(String));
|
|
5958
|
-
const
|
|
6268
|
+
const expandedKey = expanded.map(String).join("");
|
|
6269
|
+
const [revealed, setRevealed] = useState([]);
|
|
6270
|
+
if (nested && expandControlled) {
|
|
6271
|
+
const fresh = [...expandedSet].filter((key) => !revealed.includes(key) && nested.byKey.has(key));
|
|
6272
|
+
const kept = revealed.filter((key) => expandedSet.has(key));
|
|
6273
|
+
if (fresh.length || kept.length !== revealed.length) {
|
|
6274
|
+
setRevealed([...kept, ...fresh]);
|
|
6275
|
+
const shut = [];
|
|
6276
|
+
for (const key of fresh) {
|
|
6277
|
+
for (let p = nested.byKey.get(key)?.parent; p; p = p.parent) if (!openSet.has(String(p.id)) && !shut.includes(p.id)) shut.push(p.id);
|
|
6278
|
+
}
|
|
6279
|
+
if (shut.length && !openControlled) setOwnOpen([...ownOpen, ...shut]);
|
|
6280
|
+
}
|
|
6281
|
+
}
|
|
5959
6282
|
useEffect(() => {
|
|
5960
|
-
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.`);
|
|
5961
|
-
}, [repeated, rowKey]);
|
|
5962
|
-
const
|
|
5963
|
-
const marksOf = (row, index) => rowMarks(row, index, rowKey, idOf(row, index));
|
|
6283
|
+
if (repeated !== null && !nested) 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.`);
|
|
6284
|
+
}, [repeated, rowKey, nested]);
|
|
6285
|
+
const marksOf = (row, index, id = idOf(row, index)) => rowMarks(row, index < 0 ? String(id) : index, rowKey, id);
|
|
5964
6286
|
const openedHere = useRef(null);
|
|
5965
6287
|
const toggleExpand = (id) => {
|
|
5966
6288
|
const opening = !expandedSet.has(String(id));
|
|
@@ -5985,9 +6307,11 @@ function Table({
|
|
|
5985
6307
|
}, [ref, rootRef]);
|
|
5986
6308
|
const tableRef = useRef(null);
|
|
5987
6309
|
const [pins, setPins] = useState(NO_PINS);
|
|
5988
|
-
const
|
|
5989
|
-
const
|
|
5990
|
-
const
|
|
6310
|
+
const trail = expandable && nested ? 1 : 0;
|
|
6311
|
+
const lead = (selectable ? 1 : 0) + (expandable && !nested ? 1 : 0);
|
|
6312
|
+
const endColumns = columns.filter((c) => c.pin === "end").length;
|
|
6313
|
+
const endCount = endColumns + trail;
|
|
6314
|
+
const nameIndex = columns.length > endColumns ? lead : -1;
|
|
5991
6315
|
const { ref: scrollRef, elRef: scrollEl, measure: measureScroll, scrollable, edges, fadeProps } = useScrollEdges({
|
|
5992
6316
|
enabled: !isMobile,
|
|
5993
6317
|
noFade: { left: lead + (pins.nameFits ? 1 : 0) > 0, right: endCount > 0 }
|
|
@@ -6019,7 +6343,9 @@ function Table({
|
|
|
6019
6343
|
const nameFits = nameIndex >= 0 && frame > 0 && at + nameWidth + fromRight <= frame / 2;
|
|
6020
6344
|
if (nameFits) start.push(at);
|
|
6021
6345
|
const pad4 = (cell, side) => cell ? parseFloat(getComputedStyle(cell)[side]) || 0 : 0;
|
|
6022
|
-
|
|
6346
|
+
let trailing = 0;
|
|
6347
|
+
for (let i = cells.length - trail; i < cells.length; i++) trailing += widths[i] ?? 0;
|
|
6348
|
+
const panel = cells.length > lead ? [at + pad4(cells[lead], "paddingLeft"), trailing + pad4(cells[cells.length - 1 - trail], "paddingRight")] : null;
|
|
6023
6349
|
const next = { start, end, nameFits, frame, panel };
|
|
6024
6350
|
setPins((prev) => samePins(prev, next) ? prev : next);
|
|
6025
6351
|
};
|
|
@@ -6029,7 +6355,7 @@ function Table({
|
|
|
6029
6355
|
observer.observe(table2);
|
|
6030
6356
|
observer.observe(scroller);
|
|
6031
6357
|
return () => observer.disconnect();
|
|
6032
|
-
}, [isMobile, lead, endCount, nameIndex, scrollEl, columns, drawn.length]);
|
|
6358
|
+
}, [isMobile, lead, trail, endCount, nameIndex, scrollEl, columns, drawn.length, visibleKeys.length]);
|
|
6033
6359
|
const pinnedStart = lead + (pins.nameFits ? 1 : 0);
|
|
6034
6360
|
const pinStyle = (position, total) => {
|
|
6035
6361
|
if (position < pinnedStart && pins.start[position] !== void 0) {
|
|
@@ -6044,7 +6370,7 @@ function Table({
|
|
|
6044
6370
|
return void 0;
|
|
6045
6371
|
};
|
|
6046
6372
|
const pinFocus = (position, total) => {
|
|
6047
|
-
if (!onRowClick || !pinStyle(position, total)) return void 0;
|
|
6373
|
+
if (!(onRowClick || nested) || !pinStyle(position, total)) return void 0;
|
|
6048
6374
|
const fromEnd = total - 1 - position;
|
|
6049
6375
|
return cn(PIN_FOCUS, position === 0 && PIN_FOCUS_START, fromEnd === 0 && PIN_FOCUS_END);
|
|
6050
6376
|
};
|
|
@@ -6061,8 +6387,228 @@ function Table({
|
|
|
6061
6387
|
if (kind) next.set(col.key, kind);
|
|
6062
6388
|
}
|
|
6063
6389
|
setRenderedKinds((prev) => prev.size === next.size && [...next].every(([k, v]) => prev.get(k) === v) ? prev : next);
|
|
6064
|
-
}, [columns, kindOf2, drawn, isMobile]);
|
|
6065
|
-
const
|
|
6390
|
+
}, [columns, kindOf2, drawn, isMobile, visibleKeys.length]);
|
|
6391
|
+
const [focusKey, setFocusKey] = useState(null);
|
|
6392
|
+
const visibleSet = new Set(visibleKeys);
|
|
6393
|
+
const ownKey = `${headingId}~`;
|
|
6394
|
+
const gridKey = (key) => ownKey + key;
|
|
6395
|
+
const fromGrid = (attr) => attr !== null && attr.startsWith(ownKey) ? attr.slice(ownKey.length) : null;
|
|
6396
|
+
const heldOuter = useContext(TreeHeldCtx);
|
|
6397
|
+
const headKeys = nested ? [...selectable ? [`${HEAD_KEY}select`] : [], ...columns.filter(sortsBy).map((col) => `${HEAD_KEY}${col.key}`)] : [];
|
|
6398
|
+
const visibleJoined = visibleKeys.join("");
|
|
6399
|
+
const [stood, setStood] = useState({ joined: "", keys: [] });
|
|
6400
|
+
if (nested && focusKey !== null && !focusKey.startsWith(HEAD_KEY) && !nested.byKey.has(focusKey)) {
|
|
6401
|
+
const at = stood.keys.indexOf(focusKey);
|
|
6402
|
+
let next = null;
|
|
6403
|
+
for (let i = at - 1; at >= 0 && i >= 0 && next === null; i--) if (visibleSet.has(stood.keys[i])) next = stood.keys[i];
|
|
6404
|
+
for (let i = at + 1; at >= 0 && i < stood.keys.length && next === null; i++) if (visibleSet.has(stood.keys[i])) next = stood.keys[i];
|
|
6405
|
+
setFocusKey(next);
|
|
6406
|
+
}
|
|
6407
|
+
if (nested && stood.joined !== visibleJoined) setStood({ joined: visibleJoined, keys: visibleKeys });
|
|
6408
|
+
let activeKey = visibleKeys[0] ?? "";
|
|
6409
|
+
if (focusKey !== null && headKeys.includes(focusKey)) activeKey = focusKey;
|
|
6410
|
+
else {
|
|
6411
|
+
for (let n = focusKey === null ? void 0 : nested?.byKey.get(focusKey); n; n = n.parent ?? void 0) {
|
|
6412
|
+
if (visibleSet.has(String(n.id))) {
|
|
6413
|
+
activeKey = String(n.id);
|
|
6414
|
+
break;
|
|
6415
|
+
}
|
|
6416
|
+
}
|
|
6417
|
+
}
|
|
6418
|
+
const grid = useGridKeyboard({
|
|
6419
|
+
container: tableRef,
|
|
6420
|
+
active: activeKey,
|
|
6421
|
+
setActive: setFocusKey,
|
|
6422
|
+
keyOf: gridKey,
|
|
6423
|
+
move: (from, e) => {
|
|
6424
|
+
const node = nested?.byKey.get(from);
|
|
6425
|
+
const at = visibleKeys.indexOf(from);
|
|
6426
|
+
if (!node || at < 0 || e.shiftKey) return null;
|
|
6427
|
+
const isOpen = openSet.has(from);
|
|
6428
|
+
switch (e.key) {
|
|
6429
|
+
case "ArrowDown":
|
|
6430
|
+
return visibleKeys[at + 1] ?? from;
|
|
6431
|
+
case "ArrowUp":
|
|
6432
|
+
return visibleKeys[at - 1] ?? headKeys[0] ?? from;
|
|
6433
|
+
case "Home":
|
|
6434
|
+
return visibleKeys[0];
|
|
6435
|
+
case "End":
|
|
6436
|
+
return visibleKeys[visibleKeys.length - 1];
|
|
6437
|
+
case "ArrowRight":
|
|
6438
|
+
if (!node.children.length) return from;
|
|
6439
|
+
if (!isOpen) {
|
|
6440
|
+
toggleOpen(node.id);
|
|
6441
|
+
return from;
|
|
6442
|
+
}
|
|
6443
|
+
return visibleKeys[at + 1] ?? from;
|
|
6444
|
+
case "ArrowLeft":
|
|
6445
|
+
if (node.children.length && isOpen) {
|
|
6446
|
+
toggleOpen(node.id);
|
|
6447
|
+
return from;
|
|
6448
|
+
}
|
|
6449
|
+
return node.parent ? String(node.parent.id) : from;
|
|
6450
|
+
default:
|
|
6451
|
+
return null;
|
|
6452
|
+
}
|
|
6453
|
+
},
|
|
6454
|
+
// Enter and Space do what a click on the row does, onRowClick, else its Details (the second review, N8: on an
|
|
6455
|
+
// expandable table a click opened Details where Enter showed the rows); on a row a click does nothing on, its
|
|
6456
|
+
// selection, else its rows
|
|
6457
|
+
onActivate: (key, e) => {
|
|
6458
|
+
const node = nested?.byKey.get(key);
|
|
6459
|
+
if (!node) return;
|
|
6460
|
+
if (onRowClick) onRowClick(node.row, node.originalIdx);
|
|
6461
|
+
else if (canOpenByClick) toggleExpand(node.id);
|
|
6462
|
+
else if (selectable && boxOf(node.originalIdx, node.id)) toggleBox(node.originalIdx, node.id, e.shiftKey);
|
|
6463
|
+
else if (node.children.length) toggleOpen(node.id);
|
|
6464
|
+
}
|
|
6465
|
+
});
|
|
6466
|
+
const onTreeKeyDown = (e) => {
|
|
6467
|
+
if (e.target instanceof HTMLElement && e.target.parentElement === e.currentTarget) grid.onKeyDown(e);
|
|
6468
|
+
};
|
|
6469
|
+
const onHeadKeyDown = (e) => {
|
|
6470
|
+
if (e.defaultPrevented || e.altKey || e.ctrlKey || e.metaKey || e.shiftKey) return;
|
|
6471
|
+
const key = e.target instanceof HTMLElement ? fromGrid(e.target.getAttribute("data-grid-key")) : null;
|
|
6472
|
+
const at = key === null ? -1 : headKeys.indexOf(key);
|
|
6473
|
+
if (key === null || at < 0) return;
|
|
6474
|
+
let next;
|
|
6475
|
+
switch (e.key) {
|
|
6476
|
+
case "ArrowLeft":
|
|
6477
|
+
next = headKeys[at - 1] ?? key;
|
|
6478
|
+
break;
|
|
6479
|
+
case "ArrowRight":
|
|
6480
|
+
next = headKeys[at + 1] ?? key;
|
|
6481
|
+
break;
|
|
6482
|
+
case "Home":
|
|
6483
|
+
next = headKeys[0];
|
|
6484
|
+
break;
|
|
6485
|
+
case "End":
|
|
6486
|
+
next = headKeys[headKeys.length - 1];
|
|
6487
|
+
break;
|
|
6488
|
+
case "ArrowDown":
|
|
6489
|
+
next = visibleKeys[0] ?? key;
|
|
6490
|
+
break;
|
|
6491
|
+
case "ArrowUp":
|
|
6492
|
+
next = key;
|
|
6493
|
+
break;
|
|
6494
|
+
default:
|
|
6495
|
+
return;
|
|
6496
|
+
}
|
|
6497
|
+
e.preventDefault();
|
|
6498
|
+
setFocusKey(next);
|
|
6499
|
+
grid.focus(next);
|
|
6500
|
+
};
|
|
6501
|
+
const onHeadFocus = (e) => {
|
|
6502
|
+
const key = fromGrid(e.target.getAttribute("data-grid-key"));
|
|
6503
|
+
if (key !== null && headKeys.includes(key)) setFocusKey(key);
|
|
6504
|
+
};
|
|
6505
|
+
const selectAllRef = useRef(null);
|
|
6506
|
+
useLayoutEffect(() => {
|
|
6507
|
+
const input = selectAllRef.current;
|
|
6508
|
+
if (!input) return;
|
|
6509
|
+
if (nested) {
|
|
6510
|
+
input.setAttribute("data-grid-key", gridKey(`${HEAD_KEY}select`));
|
|
6511
|
+
input.tabIndex = !heldOuter && activeKey === `${HEAD_KEY}select` ? 0 : -1;
|
|
6512
|
+
} else if (input.hasAttribute("data-grid-key")) {
|
|
6513
|
+
input.removeAttribute("data-grid-key");
|
|
6514
|
+
input.removeAttribute("tabindex");
|
|
6515
|
+
}
|
|
6516
|
+
});
|
|
6517
|
+
const [rowsBody, setRowsBody] = useState(null);
|
|
6518
|
+
const [held] = useState(() => /* @__PURE__ */ new WeakMap());
|
|
6519
|
+
const stopRef = useRef("");
|
|
6520
|
+
const holding = useRef(null);
|
|
6521
|
+
const stopKey = heldOuter ? "" : activeKey;
|
|
6522
|
+
useLayoutEffect(() => {
|
|
6523
|
+
const was = stopRef.current;
|
|
6524
|
+
stopRef.current = stopKey;
|
|
6525
|
+
if (was === stopKey || !rowsBody || !holding.current) return;
|
|
6526
|
+
holding.current([...rowsOfKey(rowsBody, ownKey, was), ...rowsOfKey(rowsBody, ownKey, stopKey)]);
|
|
6527
|
+
}, [stopKey, rowsBody, ownKey]);
|
|
6528
|
+
const treeShown = !!nested && !isMobile;
|
|
6529
|
+
useLayoutEffect(() => {
|
|
6530
|
+
const body = rowsBody;
|
|
6531
|
+
if (!treeShown || !body) return;
|
|
6532
|
+
const ours = (el) => el.closest("table[role='treegrid']") === body.parentElement;
|
|
6533
|
+
const release = (el) => {
|
|
6534
|
+
const own = held.get(el) ?? "";
|
|
6535
|
+
held.delete(el);
|
|
6536
|
+
if (own === "") el.removeAttribute("tabindex");
|
|
6537
|
+
else el.setAttribute("tabindex", own);
|
|
6538
|
+
};
|
|
6539
|
+
const settle = (tr) => {
|
|
6540
|
+
const grid2 = tr.getAttribute("data-grid-key");
|
|
6541
|
+
const owner = grid2?.startsWith(ownKey) ? grid2.slice(ownKey.length) : tr.getAttribute("data-panel-of");
|
|
6542
|
+
if (owner === null) return;
|
|
6543
|
+
if (owner === stopRef.current) {
|
|
6544
|
+
for (const el of Array.from(tr.querySelectorAll("[tabindex]"))) if (held.has(el)) release(el);
|
|
6545
|
+
return;
|
|
6546
|
+
}
|
|
6547
|
+
for (const el of Array.from(tr.querySelectorAll(FOCUSABLE))) {
|
|
6548
|
+
if (!ours(el)) continue;
|
|
6549
|
+
if (!held.has(el) || el.getAttribute("tabindex") !== "-1") held.set(el, el.getAttribute("tabindex") ?? "");
|
|
6550
|
+
if (el.getAttribute("tabindex") !== "-1") el.setAttribute("tabindex", "-1");
|
|
6551
|
+
}
|
|
6552
|
+
};
|
|
6553
|
+
const touched = (records) => {
|
|
6554
|
+
const rows = /* @__PURE__ */ new Set();
|
|
6555
|
+
for (const r of records) {
|
|
6556
|
+
const target = r.target instanceof Element ? r.target : r.target.parentElement;
|
|
6557
|
+
if (!target) continue;
|
|
6558
|
+
if (r.type === "attributes" && r.attributeName === "tabindex" && target instanceof HTMLElement && held.has(target)) held.set(target, target.getAttribute("tabindex") ?? "");
|
|
6559
|
+
if (target === body) {
|
|
6560
|
+
r.addedNodes.forEach((n) => {
|
|
6561
|
+
if (n instanceof Element) rows.add(n);
|
|
6562
|
+
});
|
|
6563
|
+
continue;
|
|
6564
|
+
}
|
|
6565
|
+
if (target.parentElement === body) {
|
|
6566
|
+
if (r.type === "childList") rows.add(target);
|
|
6567
|
+
continue;
|
|
6568
|
+
}
|
|
6569
|
+
let tr = target.closest("tr");
|
|
6570
|
+
while (tr && tr.parentElement !== body) tr = tr.parentElement?.closest("tr") ?? null;
|
|
6571
|
+
if (tr) rows.add(tr);
|
|
6572
|
+
}
|
|
6573
|
+
return rows;
|
|
6574
|
+
};
|
|
6575
|
+
const sync = (also = []) => {
|
|
6576
|
+
const rows = touched(observer.takeRecords());
|
|
6577
|
+
for (const tr of also) rows.add(tr);
|
|
6578
|
+
for (const tr of rows) settle(tr);
|
|
6579
|
+
observer.takeRecords();
|
|
6580
|
+
};
|
|
6581
|
+
const observer = new MutationObserver((records) => {
|
|
6582
|
+
for (const tr of touched(records)) settle(tr);
|
|
6583
|
+
observer.takeRecords();
|
|
6584
|
+
});
|
|
6585
|
+
observer.observe(body, { childList: true, subtree: true, attributes: true, attributeFilter: ["tabindex", "disabled"] });
|
|
6586
|
+
holding.current = sync;
|
|
6587
|
+
sync(Array.from(body.rows));
|
|
6588
|
+
return () => {
|
|
6589
|
+
observer.disconnect();
|
|
6590
|
+
holding.current = null;
|
|
6591
|
+
for (const el of Array.from(body.querySelectorAll("[tabindex]"))) if (held.has(el)) release(el);
|
|
6592
|
+
};
|
|
6593
|
+
}, [treeShown, rowsBody, held, ownKey]);
|
|
6594
|
+
const focusIn = useRef(null);
|
|
6595
|
+
useLayoutEffect(() => {
|
|
6596
|
+
const was = focusIn.current;
|
|
6597
|
+
if (!nested || was === null || visibleSet.has(was)) return;
|
|
6598
|
+
focusIn.current = null;
|
|
6599
|
+
const now = document.activeElement;
|
|
6600
|
+
if (now && now !== document.body && now.isConnected) return;
|
|
6601
|
+
grid.focus(activeKey);
|
|
6602
|
+
});
|
|
6603
|
+
const onRowsBlur = (e) => {
|
|
6604
|
+
if (e.target.isConnected && !e.currentTarget.contains(e.relatedTarget)) focusIn.current = null;
|
|
6605
|
+
};
|
|
6606
|
+
const onRowFocus = (e) => {
|
|
6607
|
+
const key = fromGrid(e.currentTarget.getAttribute("data-grid-key")) ?? e.currentTarget.getAttribute("data-panel-of");
|
|
6608
|
+
if (key === null) return;
|
|
6609
|
+
focusIn.current = key;
|
|
6610
|
+
setFocusKey(key);
|
|
6611
|
+
};
|
|
6066
6612
|
const shownBefore = useRef(/* @__PURE__ */ new Set());
|
|
6067
6613
|
const pendingScroll = useRef(null);
|
|
6068
6614
|
const scrollFrame = useRef(0);
|
|
@@ -6076,6 +6622,32 @@ function Table({
|
|
|
6076
6622
|
row.scrollIntoView({ block: "nearest" });
|
|
6077
6623
|
});
|
|
6078
6624
|
}, [rootRef]);
|
|
6625
|
+
const addressRow = (key) => {
|
|
6626
|
+
let top = key;
|
|
6627
|
+
let waits = false;
|
|
6628
|
+
const above = [];
|
|
6629
|
+
for (let p = nested?.byKey.get(key)?.parent; p; p = p.parent) above.unshift(p);
|
|
6630
|
+
if (above.length) {
|
|
6631
|
+
top = String(above[0].id);
|
|
6632
|
+
const shut = above.filter((p) => !openSet.has(String(p.id)));
|
|
6633
|
+
if (shut.length && openControlled) {
|
|
6634
|
+
onOpenParentsChange?.([...open, ...shut.map((p) => p.id)]);
|
|
6635
|
+
pendingScroll.current = key;
|
|
6636
|
+
waits = true;
|
|
6637
|
+
}
|
|
6638
|
+
}
|
|
6639
|
+
if (pager) {
|
|
6640
|
+
const position = sortedAll.findIndex((r) => String(idOf(r.row, r.originalIdx)) === top);
|
|
6641
|
+
if (position >= 0 && (position < drawnStart || position >= drawnStart + drawn.length)) {
|
|
6642
|
+
pendingScroll.current = key;
|
|
6643
|
+
pager.setPage(Math.floor(position / pager.pageSize) + 1);
|
|
6644
|
+
return;
|
|
6645
|
+
}
|
|
6646
|
+
}
|
|
6647
|
+
if (waits) return;
|
|
6648
|
+
scrollToRow(key);
|
|
6649
|
+
};
|
|
6650
|
+
const awaitedRow = useRef(null);
|
|
6079
6651
|
useEffect(() => {
|
|
6080
6652
|
const now = new Set(expanded.map(String));
|
|
6081
6653
|
const added = [...now].filter((k) => !shownBefore.current.has(k) && k !== openedHere.current);
|
|
@@ -6084,22 +6656,25 @@ function Table({
|
|
|
6084
6656
|
if (!expandControlled) return;
|
|
6085
6657
|
const key = added[added.length - 1];
|
|
6086
6658
|
if (key === void 0) return;
|
|
6087
|
-
if (
|
|
6088
|
-
|
|
6089
|
-
|
|
6090
|
-
pendingScroll.current = key;
|
|
6091
|
-
pager.setPage(Math.floor(position / pager.pageSize) + 1);
|
|
6092
|
-
return;
|
|
6093
|
-
}
|
|
6659
|
+
if (tree && !tree.byKey.has(key)) {
|
|
6660
|
+
awaitedRow.current = key;
|
|
6661
|
+
return;
|
|
6094
6662
|
}
|
|
6095
|
-
|
|
6663
|
+
awaitedRow.current = null;
|
|
6664
|
+
addressRow(key);
|
|
6096
6665
|
}, [expandedKey]);
|
|
6666
|
+
useEffect(() => {
|
|
6667
|
+
const key = awaitedRow.current;
|
|
6668
|
+
if (key === null || !tree?.byKey.has(key)) return;
|
|
6669
|
+
awaitedRow.current = null;
|
|
6670
|
+
addressRow(key);
|
|
6671
|
+
}, [tree]);
|
|
6097
6672
|
useEffect(() => {
|
|
6098
6673
|
const key = pendingScroll.current;
|
|
6099
|
-
if (!key || !drawn.some((r) => String(idOf(r.row, r.originalIdx)) === key)) return;
|
|
6674
|
+
if (!key || !(nested ? visibleSet.has(key) : drawn.some((r) => String(idOf(r.row, r.originalIdx)) === key))) return;
|
|
6100
6675
|
pendingScroll.current = null;
|
|
6101
6676
|
scrollToRow(key);
|
|
6102
|
-
}, [drawnStart, drawn.length, scrollToRow]);
|
|
6677
|
+
}, [drawnStart, drawn.length, visibleKeys.length, scrollToRow]);
|
|
6103
6678
|
const cardHeading = title ? /* @__PURE__ */ jsx(TableHeading, { title, description, actions, titleId, descriptionId, inset: false }) : null;
|
|
6104
6679
|
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: [
|
|
6105
6680
|
cardHeading,
|
|
@@ -6143,7 +6718,7 @@ function Table({
|
|
|
6143
6718
|
if (!row) return;
|
|
6144
6719
|
const controls = Array.from(row.querySelectorAll(FOCUSABLE));
|
|
6145
6720
|
const same = was.control === null ? null : controls.find((el) => (el.getAttribute("aria-labelledby") ?? el.getAttribute("aria-label") ?? el.textContent) === was.control);
|
|
6146
|
-
(same ?? (row.tabIndex >= 0 ? row : controls[0]))?.focus({ preventScroll: true });
|
|
6721
|
+
(same ?? (row.tabIndex >= 0 || row.hasAttribute("data-grid-key") ? row : controls[0]))?.focus({ preventScroll: true });
|
|
6147
6722
|
}, [isMobile, rootRef]);
|
|
6148
6723
|
if (isMobile) {
|
|
6149
6724
|
if (loading && data.length === 0) {
|
|
@@ -6164,289 +6739,363 @@ function Table({
|
|
|
6164
6739
|
const cards = /* @__PURE__ */ jsx(TableCardCtx, { value: true, children: /* @__PURE__ */ jsx(RowsCtx, { value: true, children: /* @__PURE__ */ jsxs("div", { ref: setCards, "data-ds-list": title ? void 0 : "", "data-gs": title ? void 0 : "table", className: cn("relative flex flex-col gap-ds-3 overflow-y-auto -m-[4px] p-[4px] scroll-p-[4px]", FOCUS_INSET, title ? "min-h-0" : listClass), onFocus: title ? void 0 : noteFocus, onBlur: title ? void 0 : forgetFocus, children: [
|
|
6165
6740
|
loading && data.length > 0 && /* @__PURE__ */ jsx(RefreshLine, { className: "inset-x-[4px] rounded-full" }),
|
|
6166
6741
|
selectable && /* @__PURE__ */ jsx("span", { hidden: true, id: `${headingId}-select`, children: "Select" }),
|
|
6167
|
-
|
|
6168
|
-
|
|
6169
|
-
|
|
6170
|
-
|
|
6171
|
-
|
|
6172
|
-
|
|
6173
|
-
|
|
6174
|
-
|
|
6175
|
-
|
|
6176
|
-
|
|
6177
|
-
|
|
6178
|
-
|
|
6179
|
-
|
|
6180
|
-
|
|
6181
|
-
|
|
6182
|
-
|
|
6183
|
-
|
|
6184
|
-
|
|
6185
|
-
|
|
6186
|
-
|
|
6187
|
-
|
|
6188
|
-
|
|
6189
|
-
|
|
6190
|
-
|
|
6191
|
-
|
|
6192
|
-
|
|
6193
|
-
|
|
6194
|
-
|
|
6195
|
-
|
|
6196
|
-
|
|
6197
|
-
|
|
6198
|
-
|
|
6199
|
-
|
|
6200
|
-
|
|
6201
|
-
|
|
6202
|
-
|
|
6203
|
-
|
|
6204
|
-
|
|
6742
|
+
nested && /* @__PURE__ */ jsx("span", { hidden: true, id: `${headingId}-under`, children: "under" }),
|
|
6743
|
+
nested && /* @__PURE__ */ jsx("span", { hidden: true, id: `${headingId}-rows-under`, children: "Rows under" }),
|
|
6744
|
+
nested ? drawn.map((d) => treeCards(nested.roots[d.originalIdx])) : drawn.map(({ row, originalIdx }) => cardOf(row, originalIdx))
|
|
6745
|
+
] }) }) });
|
|
6746
|
+
return withControl(title ? titledCards(cards) : cards);
|
|
6747
|
+
}
|
|
6748
|
+
function cardOf(row, originalIdx, node) {
|
|
6749
|
+
const id = node ? node.id : idOf(row, originalIdx);
|
|
6750
|
+
const box = boxOf(originalIdx, id);
|
|
6751
|
+
const isSelected = !!box?.checked;
|
|
6752
|
+
const opens = !!expandable && !!renderExpanded;
|
|
6753
|
+
const isExpanded = opens && expandedSet.has(String(id));
|
|
6754
|
+
const toggleCard = (card) => {
|
|
6755
|
+
const closing = isExpanded;
|
|
6756
|
+
const inDetail = closing && card.querySelector("[data-card-detail]")?.contains(document.activeElement);
|
|
6757
|
+
toggleExpand(id);
|
|
6758
|
+
if (inDetail) card.querySelector("[data-card-toggle]")?.focus();
|
|
6759
|
+
};
|
|
6760
|
+
const under = node?.children.length ?? 0;
|
|
6761
|
+
const isOpen = under > 0 && openSet.has(String(id));
|
|
6762
|
+
return /* @__PURE__ */ jsxs(
|
|
6763
|
+
"div",
|
|
6764
|
+
{
|
|
6765
|
+
"data-row": "",
|
|
6766
|
+
...marksOf(row, originalIdx, id),
|
|
6767
|
+
className: cn(
|
|
6768
|
+
"border-[length:var(--ds-border-width)] border-[var(--ds-border-subtle)]",
|
|
6769
|
+
"rounded-[var(--ds-radius-md)] bg-[var(--ds-bg-surface)]",
|
|
6770
|
+
"p-ds-4 space-y-ds-3",
|
|
6771
|
+
// selected is chosen, not active (D2): the accent border, never the halo
|
|
6772
|
+
isSelected && "border-[var(--ds-accent-ink)]",
|
|
6773
|
+
onRowClick && ["cursor-pointer hover:bg-[var(--ds-bg-muted)]", FOCUS_RING],
|
|
6774
|
+
// with no onRowClick a tap on the card opens and closes it, as a click on the row does; the toggle is the
|
|
6775
|
+
// keyboard's way
|
|
6776
|
+
!onRowClick && canOpenByClick && "cursor-pointer"
|
|
6777
|
+
),
|
|
6778
|
+
onClick: onRowClick ? (e) => {
|
|
6779
|
+
if (clickIsCard(e)) onRowClick(row, originalIdx);
|
|
6780
|
+
} : canOpenByClick ? (e) => {
|
|
6781
|
+
if (clickIsCard(e)) toggleCard(e.currentTarget);
|
|
6782
|
+
} : void 0,
|
|
6783
|
+
tabIndex: onRowClick ? 0 : void 0,
|
|
6784
|
+
onKeyDown: onRowClick ? (e) => {
|
|
6785
|
+
if (e.target !== e.currentTarget) return;
|
|
6786
|
+
if (e.key === "Enter" || e.key === " ") {
|
|
6787
|
+
e.preventDefault();
|
|
6788
|
+
onRowClick(row, originalIdx);
|
|
6789
|
+
}
|
|
6790
|
+
} : void 0,
|
|
6791
|
+
children: [
|
|
6792
|
+
selectable && box && // "Select" and the row's name, as in the table (T15); a parent with some of its rows chosen is mixed
|
|
6793
|
+
/* @__PURE__ */ jsx(Checkbox, { checked: isSelected, indeterminate: box.mixed, onChange: (_, { shiftKey: shiftKey2 }) => toggleBox(originalIdx, id, shiftKey2), "aria-labelledby": nameIndex >= 0 ? `${headingId}-select ${headingId}-card-name-${idPart(id)}` : `${headingId}-select` }),
|
|
6794
|
+
columns.map((col, c) => /* @__PURE__ */ jsxs("div", { className: "flex justify-between gap-ds-2 text-sm", children: [
|
|
6795
|
+
/* @__PURE__ */ jsx("span", { className: "shrink-0 text-[var(--ds-text-secondary)] font-medium text-xs uppercase tracking-wider", children: col.header }),
|
|
6796
|
+
/* @__PURE__ */ jsx(CardValue, { value: row[col.key], id: lead + c === nameIndex ? `${headingId}-card-name-${idPart(id)}` : void 0 })
|
|
6797
|
+
] }, col.key)),
|
|
6798
|
+
under > 0 && // item 14: the rows under it, shown and hidden as the Details are, with how many and the row's name
|
|
6799
|
+
/* @__PURE__ */ jsx("div", { className: "pt-ds-1", children: /* @__PURE__ */ jsxs(
|
|
6800
|
+
"button",
|
|
6801
|
+
{
|
|
6802
|
+
type: "button",
|
|
6803
|
+
"data-card-rows-toggle": "",
|
|
6804
|
+
"aria-expanded": isOpen,
|
|
6805
|
+
"aria-labelledby": nameIndex >= 0 ? `${headingId}-card-rows-${idPart(id)} ${headingId}-under ${headingId}-card-name-${idPart(id)}` : `${headingId}-card-rows-${idPart(id)}`,
|
|
6806
|
+
onClick: (e) => {
|
|
6807
|
+
e.stopPropagation();
|
|
6808
|
+
toggleOpen(id);
|
|
6809
|
+
},
|
|
6810
|
+
className: CARD_TOGGLE,
|
|
6811
|
+
children: [
|
|
6812
|
+
/* @__PURE__ */ jsx(Icon, { name: "chevron-right", size: 12, className: cn("transition-transform duration-[var(--ds-transition-speed)]", isOpen && "rotate-90") }),
|
|
6813
|
+
/* @__PURE__ */ jsx("span", { id: `${headingId}-card-rows-${idPart(id)}`, children: `${isOpen ? "Hide" : "Show"} ${under} ${under === 1 ? "row" : "rows"}` })
|
|
6814
|
+
]
|
|
6815
|
+
}
|
|
6816
|
+
) }),
|
|
6817
|
+
opens && // Alert's disclosure: a button that says whether it is open, at the card's foot, the detail below it, so
|
|
6818
|
+
// the control the user pressed stays where it was. Its name carries the row's (T15).
|
|
6819
|
+
/* @__PURE__ */ jsxs("div", { className: "pt-ds-1", children: [
|
|
6820
|
+
/* @__PURE__ */ jsxs(
|
|
6821
|
+
"button",
|
|
6822
|
+
{
|
|
6823
|
+
type: "button",
|
|
6824
|
+
"data-card-toggle": "",
|
|
6825
|
+
"aria-expanded": isExpanded,
|
|
6826
|
+
...nameIndex >= 0 ? { "aria-labelledby": `${headingId}-card-toggle-${idPart(id)} ${headingId}-card-name-${idPart(id)}` } : {},
|
|
6827
|
+
onClick: (e) => {
|
|
6828
|
+
e.stopPropagation();
|
|
6829
|
+
toggleCard(e.currentTarget.closest("[data-row]"));
|
|
6830
|
+
},
|
|
6831
|
+
className: CARD_TOGGLE,
|
|
6832
|
+
children: [
|
|
6833
|
+
/* @__PURE__ */ jsx(Icon, { name: "chevron-right", size: 12, className: cn("transition-transform duration-[var(--ds-transition-speed)]", isExpanded && "rotate-90") }),
|
|
6834
|
+
/* @__PURE__ */ jsx("span", { id: `${headingId}-card-toggle-${idPart(id)}`, children: isExpanded ? "Hide details" : "Show details" })
|
|
6835
|
+
]
|
|
6205
6836
|
}
|
|
6206
|
-
|
|
6207
|
-
children:
|
|
6208
|
-
|
|
6209
|
-
|
|
6210
|
-
|
|
6211
|
-
|
|
6212
|
-
|
|
6213
|
-
|
|
6214
|
-
|
|
6215
|
-
|
|
6216
|
-
|
|
6837
|
+
),
|
|
6838
|
+
isExpanded && /* @__PURE__ */ jsx("div", { "data-card-detail": "", className: "mt-ds-3 pt-ds-3 border-t-[length:var(--ds-divider-width)] border-[var(--ds-border-subtle)] text-sm text-[var(--ds-text-secondary)]", children: /* @__PURE__ */ jsx(PanelContent, { children: renderExpanded(row, originalIdx) }) })
|
|
6839
|
+
] })
|
|
6840
|
+
]
|
|
6841
|
+
},
|
|
6842
|
+
String(id)
|
|
6843
|
+
);
|
|
6844
|
+
}
|
|
6845
|
+
function treeCards(node) {
|
|
6846
|
+
const key = String(node.id);
|
|
6847
|
+
return /* @__PURE__ */ jsxs(Fragment$1, { children: [
|
|
6848
|
+
cardOf(node.row, node.originalIdx, node),
|
|
6849
|
+
node.children.length > 0 && openSet.has(key) && /* @__PURE__ */ jsx(
|
|
6850
|
+
"div",
|
|
6851
|
+
{
|
|
6852
|
+
role: "group",
|
|
6853
|
+
"data-card-rows": "",
|
|
6854
|
+
"aria-labelledby": nameIndex >= 0 ? `${headingId}-rows-under ${headingId}-card-name-${idPart(node.id)}` : `${headingId}-rows-under`,
|
|
6855
|
+
className: "ml-ds-5 pl-ds-3 border-l-[length:var(--ds-border-width)] border-[var(--ds-border-subtle)] flex flex-col gap-ds-3",
|
|
6856
|
+
children: (childOrder?.get(key) ?? node.children).map(treeCards)
|
|
6857
|
+
}
|
|
6858
|
+
)
|
|
6859
|
+
] }, key);
|
|
6860
|
+
}
|
|
6861
|
+
const cellCount = columns.length + lead + trail;
|
|
6862
|
+
const bodyRows = visible ? visible.map((v) => ({ row: v.node.row, originalIdx: v.node.originalIdx, tree: v })) : drawn;
|
|
6863
|
+
const table = (
|
|
6864
|
+
// a tree table is a treegrid (item 14): its rows have levels, and the arrow keys move between them
|
|
6865
|
+
/* @__PURE__ */ jsxs("table", { ref: tableRef, role: nested ? "treegrid" : void 0, "aria-busy": loading || void 0, className: cn("w-full text-sm", PINNED_LAYERS), ...title ? { "aria-labelledby": titleId, "aria-describedby": description ? descriptionId : void 0 } : ariaLabel ? { "aria-label": ariaLabel } : {}, children: [
|
|
6866
|
+
/* @__PURE__ */ jsx("thead", { className: cn("bg-[var(--ds-bg-muted)]", stickyHeader && "sticky top-0 z-10"), onKeyDown: nested ? onHeadKeyDown : void 0, onFocus: nested ? onHeadFocus : void 0, 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: [
|
|
6867
|
+
selectable && // data-ds-select-all: the selection's own control, where a BulkActionBar's Clear selection sends focus
|
|
6868
|
+
/* @__PURE__ */ jsx("th", { "data-ds-select-all": "", 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(
|
|
6869
|
+
Checkbox,
|
|
6870
|
+
{
|
|
6871
|
+
ref: selectAllRef,
|
|
6872
|
+
checked: allSelected,
|
|
6873
|
+
indeterminate: someSelected,
|
|
6874
|
+
onChange: toggleAll,
|
|
6875
|
+
"aria-labelledby": `${headingId}-select-all`
|
|
6876
|
+
}
|
|
6877
|
+
) }),
|
|
6878
|
+
expandable && !trail && /* @__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) }),
|
|
6879
|
+
columns.map((col, c) => {
|
|
6880
|
+
const isSortable = sortsBy(col);
|
|
6881
|
+
const isActiveSort = sortKey === col.key && !!sortDir && (pageSorts || unsortable !== col.key);
|
|
6882
|
+
const headerKind = kindOf2(col);
|
|
6883
|
+
const headerAlign = col.align ?? (headerKind === "number" ? "right" : "left");
|
|
6884
|
+
const shrink = (headerKind === "number" || headerKind === "date") && !col.maxWidth;
|
|
6885
|
+
const style = { maxWidth: col.maxWidth, width: col.width, minWidth: col.minWidth, ...pinStyle(lead + c, cellCount) };
|
|
6886
|
+
return /* @__PURE__ */ jsx(
|
|
6887
|
+
"th",
|
|
6888
|
+
{
|
|
6889
|
+
"aria-sort": isSortable && isActiveSort ? sortDir === "asc" ? "ascending" : "descending" : void 0,
|
|
6890
|
+
className: cn(
|
|
6891
|
+
density === "compact" ? "px-ds-3 py-ds-2" : "px-ds-4 py-ds-3",
|
|
6892
|
+
shrink && "w-px whitespace-nowrap",
|
|
6893
|
+
"font-[var(--ds-weight-heading)] text-[var(--ds-text-secondary)]",
|
|
6894
|
+
"text-xs uppercase tracking-wider",
|
|
6895
|
+
headerAlign === "right" ? "text-right" : headerAlign === "center" ? "text-center" : "text-left"
|
|
6896
|
+
),
|
|
6897
|
+
style,
|
|
6898
|
+
children: isSortable ? (
|
|
6899
|
+
// A47: a button with the column's name, reached with Tab and pressed with Enter or Space
|
|
6217
6900
|
/* @__PURE__ */ jsxs(
|
|
6218
6901
|
"button",
|
|
6219
6902
|
{
|
|
6220
6903
|
type: "button",
|
|
6221
|
-
|
|
6222
|
-
"
|
|
6223
|
-
...nameIndex >= 0 ? { "aria-labelledby": `${headingId}-card-toggle-${idPart(id)} ${headingId}-card-name-${idPart(id)}` } : {},
|
|
6224
|
-
onClick: (e) => {
|
|
6225
|
-
e.stopPropagation();
|
|
6226
|
-
toggleCard(e.currentTarget.closest("[data-row]"));
|
|
6227
|
-
},
|
|
6904
|
+
onClick: () => handleSort(col.key),
|
|
6905
|
+
...nested ? { "data-grid-key": gridKey(`${HEAD_KEY}${col.key}`), tabIndex: heldOuter ? -1 : grid.tabIndexOf(`${HEAD_KEY}${col.key}`) } : {},
|
|
6228
6906
|
className: cn(
|
|
6229
|
-
|
|
6230
|
-
"
|
|
6231
|
-
"
|
|
6232
|
-
|
|
6233
|
-
|
|
6907
|
+
"inline-flex items-center gap-ds-1 uppercase tracking-wider cursor-pointer select-none",
|
|
6908
|
+
"[font:inherit] text-inherit hover:text-[var(--ds-text-primary)]",
|
|
6909
|
+
"rounded-[var(--ds-radius-sm)]",
|
|
6910
|
+
// in a right-aligned column the indicator goes before the label, so the label ends where the
|
|
6911
|
+
// column's values end; the sorted column's label in full colour (the look check, 14 October).
|
|
6912
|
+
// Set at the line's top, not its baseline: reversed, the button takes its baseline from the
|
|
6913
|
+
// indicator, which has no text, and stood 2 px above the other headers' labels
|
|
6914
|
+
headerAlign === "right" && "flex-row-reverse",
|
|
6915
|
+
"align-top",
|
|
6916
|
+
isActiveSort && "text-[var(--ds-text-primary)]",
|
|
6234
6917
|
FOCUS_RING
|
|
6235
6918
|
),
|
|
6236
6919
|
children: [
|
|
6237
|
-
|
|
6238
|
-
/* @__PURE__ */ jsx(
|
|
6920
|
+
col.header,
|
|
6921
|
+
/* @__PURE__ */ jsx(SortIndicator, { sorted: isActiveSort ? sortDir : false })
|
|
6239
6922
|
]
|
|
6240
6923
|
}
|
|
6241
|
-
)
|
|
6242
|
-
|
|
6243
|
-
|
|
6244
|
-
|
|
6245
|
-
|
|
6246
|
-
|
|
6247
|
-
)
|
|
6248
|
-
})
|
|
6249
|
-
|
|
6250
|
-
|
|
6251
|
-
|
|
6252
|
-
|
|
6253
|
-
|
|
6254
|
-
|
|
6255
|
-
|
|
6256
|
-
|
|
6257
|
-
|
|
6924
|
+
)
|
|
6925
|
+
) : /* @__PURE__ */ jsx("span", { className: "inline-flex items-center gap-ds-1", children: col.header })
|
|
6926
|
+
},
|
|
6927
|
+
col.key
|
|
6928
|
+
);
|
|
6929
|
+
}),
|
|
6930
|
+
trail > 0 && /* @__PURE__ */ jsx("th", { className: cn("w-8", density === "compact" ? "px-ds-1 py-ds-2" : "px-ds-2 py-ds-3"), style: pinStyle(cellCount - 1, cellCount) })
|
|
6931
|
+
] }) }),
|
|
6932
|
+
/* @__PURE__ */ jsx("tbody", { ref: nested ? setRowsBody : void 0, onKeyDown: nested ? onTreeKeyDown : void 0, onBlur: nested ? onRowsBlur : void 0, children: /* @__PURE__ */ jsx(RowsCtx, { value: true, children: loading && data.length === 0 ? (
|
|
6933
|
+
// the rows' shape on a first load (item 16), each cell's bar where its text will be; the rows are hidden
|
|
6934
|
+
// from a screen reader, which hears the status beside the table
|
|
6935
|
+
Array.from({ length: SKELETON_ROWS }, (_, r) => /* @__PURE__ */ jsxs("tr", { "data-table-skeleton": "", className: "border-b-[length:var(--ds-divider-width)] border-[var(--ds-border-subtle)] last:border-b-0", children: [
|
|
6936
|
+
selectable && /* @__PURE__ */ jsx("td", { "aria-hidden": true, className: cn("w-10", density === "compact" ? "px-ds-2 py-ds-2" : "px-ds-3 py-ds-3"), children: /* @__PURE__ */ jsx(SkeletonLine, { width: "16px" }) }),
|
|
6937
|
+
expandable && /* @__PURE__ */ jsx("td", { "aria-hidden": true, className: cn("w-8", density === "compact" ? "px-ds-1 py-ds-2" : "px-ds-2 py-ds-3") }),
|
|
6938
|
+
columns.map((col, c) => /* @__PURE__ */ jsx("td", { className: density === "compact" ? "px-ds-3 py-ds-2" : "px-ds-4 py-ds-3", children: /* @__PURE__ */ jsx("div", { "aria-hidden": true, children: /* @__PURE__ */ jsx(SkeletonLine, { width: SKELETON_WIDTHS[(r + c) % SKELETON_WIDTHS.length], end: (col.align ?? (kindOf2(col) === "number" ? "right" : "left")) === "right" }) }) }, col.key))
|
|
6939
|
+
] }, `skeleton-${r}`))
|
|
6940
|
+
) : data.length === 0 && emptyState ? /* @__PURE__ */ jsx("tr", { children: /* @__PURE__ */ jsx(
|
|
6941
|
+
"td",
|
|
6258
6942
|
{
|
|
6259
|
-
|
|
6260
|
-
|
|
6261
|
-
|
|
6262
|
-
"aria-labelledby": `${headingId}-select-all`
|
|
6943
|
+
colSpan: cellCount,
|
|
6944
|
+
className: "px-ds-4 py-ds-10 text-center text-sm text-[var(--ds-text-muted)]",
|
|
6945
|
+
children: emptyState
|
|
6263
6946
|
}
|
|
6264
|
-
) }),
|
|
6265
|
-
|
|
6266
|
-
|
|
6267
|
-
const
|
|
6268
|
-
const
|
|
6269
|
-
const
|
|
6270
|
-
const
|
|
6271
|
-
const
|
|
6272
|
-
const
|
|
6273
|
-
|
|
6274
|
-
"
|
|
6275
|
-
|
|
6276
|
-
|
|
6277
|
-
|
|
6278
|
-
|
|
6279
|
-
|
|
6280
|
-
|
|
6281
|
-
|
|
6282
|
-
|
|
6283
|
-
|
|
6284
|
-
|
|
6285
|
-
children: isSortable ? (
|
|
6286
|
-
// A47: a button with the column's name, reached with Tab and pressed with Enter or Space
|
|
6287
|
-
/* @__PURE__ */ jsxs(
|
|
6288
|
-
"button",
|
|
6289
|
-
{
|
|
6290
|
-
type: "button",
|
|
6291
|
-
onClick: () => handleSort(col.key),
|
|
6292
|
-
className: cn(
|
|
6293
|
-
"inline-flex items-center gap-ds-1 uppercase tracking-wider cursor-pointer select-none",
|
|
6294
|
-
"[font:inherit] text-inherit hover:text-[var(--ds-text-primary)]",
|
|
6295
|
-
"rounded-[var(--ds-radius-sm)]",
|
|
6296
|
-
// in a right-aligned column the indicator goes before the label, so the label ends where the
|
|
6297
|
-
// column's values end; the sorted column's label in full colour (the look check, 14 October).
|
|
6298
|
-
// Set at the line's top, not its baseline: reversed, the button takes its baseline from the
|
|
6299
|
-
// indicator, which has no text, and stood 2 px above the other headers' labels
|
|
6300
|
-
headerAlign === "right" && "flex-row-reverse",
|
|
6301
|
-
"align-top",
|
|
6302
|
-
isActiveSort && "text-[var(--ds-text-primary)]",
|
|
6303
|
-
FOCUS_RING
|
|
6304
|
-
),
|
|
6305
|
-
children: [
|
|
6306
|
-
col.header,
|
|
6307
|
-
/* @__PURE__ */ jsx(SortIndicator, { sorted: isActiveSort ? sortDir : false })
|
|
6308
|
-
]
|
|
6309
|
-
}
|
|
6310
|
-
)
|
|
6311
|
-
) : /* @__PURE__ */ jsx("span", { className: "inline-flex items-center gap-ds-1", children: col.header })
|
|
6312
|
-
},
|
|
6313
|
-
col.key
|
|
6314
|
-
);
|
|
6315
|
-
})
|
|
6316
|
-
] }) }),
|
|
6317
|
-
/* @__PURE__ */ jsx("tbody", { children: /* @__PURE__ */ jsx(RowsCtx, { value: true, children: loading && data.length === 0 ? (
|
|
6318
|
-
// the rows' shape on a first load (item 16), each cell's bar where its text will be; the rows are hidden
|
|
6319
|
-
// from a screen reader, which hears the status beside the table
|
|
6320
|
-
Array.from({ length: SKELETON_ROWS }, (_, r) => /* @__PURE__ */ jsxs("tr", { "data-table-skeleton": "", className: "border-b-[length:var(--ds-divider-width)] border-[var(--ds-border-subtle)] last:border-b-0", children: [
|
|
6321
|
-
selectable && /* @__PURE__ */ jsx("td", { "aria-hidden": true, className: cn("w-10", density === "compact" ? "px-ds-2 py-ds-2" : "px-ds-3 py-ds-3"), children: /* @__PURE__ */ jsx(SkeletonLine, { width: "16px" }) }),
|
|
6322
|
-
expandable && /* @__PURE__ */ jsx("td", { "aria-hidden": true, className: cn("w-8", density === "compact" ? "px-ds-1 py-ds-2" : "px-ds-2 py-ds-3") }),
|
|
6323
|
-
columns.map((col, c) => /* @__PURE__ */ jsx("td", { className: density === "compact" ? "px-ds-3 py-ds-2" : "px-ds-4 py-ds-3", children: /* @__PURE__ */ jsx("div", { "aria-hidden": true, children: /* @__PURE__ */ jsx(SkeletonLine, { width: SKELETON_WIDTHS[(r + c) % SKELETON_WIDTHS.length], end: (col.align ?? (kindOf2(col) === "number" ? "right" : "left")) === "right" }) }) }, col.key))
|
|
6324
|
-
] }, `skeleton-${r}`))
|
|
6325
|
-
) : data.length === 0 && emptyState ? /* @__PURE__ */ jsx("tr", { children: /* @__PURE__ */ jsx(
|
|
6326
|
-
"td",
|
|
6327
|
-
{
|
|
6328
|
-
colSpan: cellCount,
|
|
6329
|
-
className: "px-ds-4 py-ds-10 text-center text-sm text-[var(--ds-text-muted)]",
|
|
6330
|
-
children: emptyState
|
|
6331
|
-
}
|
|
6332
|
-
) }) : drawn.map(({ row, originalIdx }, i) => {
|
|
6333
|
-
const isSelected = selectedSet.has(originalIdx);
|
|
6334
|
-
const id = idOf(row, originalIdx);
|
|
6335
|
-
const isExpanded = expandedSet.has(String(id));
|
|
6336
|
-
const clickable = !!onRowClick || canOpenByClick;
|
|
6337
|
-
return /* @__PURE__ */ jsxs(Fragment$1, { children: [
|
|
6338
|
-
/* @__PURE__ */ jsxs(
|
|
6339
|
-
"tr",
|
|
6340
|
-
{
|
|
6341
|
-
...marksOf(row, originalIdx),
|
|
6342
|
-
className: cn(
|
|
6343
|
-
// an opened row's divider is under its panel (A6)
|
|
6344
|
-
!(expandable && isExpanded && renderExpanded) && "border-b-[length:var(--ds-divider-width)] border-[var(--ds-border-subtle)] last:border-b-0",
|
|
6345
|
-
// the row's background and its tint change together, so its pinned cells and the rest fade as one
|
|
6346
|
-
// (roots.css registers --gs-row-tint as a colour so it can)
|
|
6347
|
-
"transition-[background-color,--gs-row-tint]",
|
|
6348
|
-
// the row's tint, as a variable too, so its pinned cells draw it over their solid ground (A35)
|
|
6349
|
-
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)]",
|
|
6350
|
-
clickable && "cursor-pointer",
|
|
6351
|
-
// an outline inside the row, clear of the frame's rounded corners (D8): it shows over the pinned
|
|
6352
|
-
// cells, whose solid ground hid the inset shadow the row drew before (the review of 30 September)
|
|
6353
|
-
onRowClick && FOCUS_INSET
|
|
6354
|
-
),
|
|
6355
|
-
onClick: clickable ? (e) => {
|
|
6356
|
-
if (!clickIsRows(e)) return;
|
|
6357
|
-
if (onRowClick) onRowClick(row, originalIdx);
|
|
6358
|
-
else toggleExpand(id);
|
|
6359
|
-
} : void 0,
|
|
6360
|
-
tabIndex: onRowClick ? 0 : void 0,
|
|
6361
|
-
onKeyDown: onRowClick ? (e) => {
|
|
6362
|
-
if (e.target !== e.currentTarget) return;
|
|
6363
|
-
if (e.key === "Enter" || e.key === " ") {
|
|
6364
|
-
e.preventDefault();
|
|
6365
|
-
onRowClick(row, originalIdx);
|
|
6366
|
-
}
|
|
6367
|
-
} : void 0,
|
|
6368
|
-
children: [
|
|
6369
|
-
selectable && /* @__PURE__ */ jsx("td", { className: cn("w-10", density === "compact" ? "px-ds-2 py-ds-2" : "px-ds-3 py-ds-3", pinFocus(0, cellCount)), style: pinStyle(0, cellCount), children: /* @__PURE__ */ jsx(Checkbox, { checked: isSelected, onChange: (_, { shiftKey: shiftKey2 }) => toggleRow(originalIdx, shiftKey2), "aria-labelledby": nameIndex >= 0 ? `${headingId}-select ${headingId}-name-${idPart(id)}` : `${headingId}-select` }) }),
|
|
6370
|
-
expandable && /* @__PURE__ */ jsx("td", { className: cn("w-8", density === "compact" ? "px-ds-1 py-ds-2" : "px-ds-2 py-ds-3", pinFocus(selectable ? 1 : 0, cellCount)), style: pinStyle(selectable ? 1 : 0, cellCount), children: /* @__PURE__ */ jsx(AutoTooltip, { content: "Details", children: /* @__PURE__ */ jsx(
|
|
6371
|
-
"button",
|
|
6372
|
-
{
|
|
6373
|
-
type: "button",
|
|
6374
|
-
onClick: () => toggleExpand(id),
|
|
6375
|
-
className: cn("text-[var(--ds-text-muted)] hover:text-[var(--ds-text-primary)] cursor-pointer", FOCUS_RING),
|
|
6376
|
-
"aria-expanded": isExpanded,
|
|
6377
|
-
...nameIndex >= 0 ? { "aria-labelledby": `${headingId}-details ${headingId}-name-${idPart(id)}` } : { "aria-label": "Details" },
|
|
6378
|
-
children: /* @__PURE__ */ jsx(
|
|
6379
|
-
Icon,
|
|
6380
|
-
{
|
|
6381
|
-
name: "chevron-right",
|
|
6382
|
-
size: 14,
|
|
6383
|
-
className: cn("transition-transform", isExpanded && "rotate-90")
|
|
6384
|
-
}
|
|
6385
|
-
)
|
|
6386
|
-
}
|
|
6387
|
-
) }) }),
|
|
6388
|
-
columns.map((col, c) => {
|
|
6389
|
-
const truncLines = col.truncate === true ? 1 : col.truncate ? col.truncate.lines : 0;
|
|
6390
|
-
const kind = kindOf2(col);
|
|
6391
|
-
const alignClass = col.align ? col.align === "right" ? "text-right" : col.align === "center" ? "text-center" : "text-left" : kind === "number" ? "text-right" : "text-left";
|
|
6392
|
-
const cellContent = row[col.key];
|
|
6393
|
-
const shrink = (kind === "number" || kind === "date") && !col.maxWidth;
|
|
6394
|
-
const whole2 = !kind && renderedKinds.has(col.key);
|
|
6395
|
-
let inner;
|
|
6396
|
-
if (truncLines > 0) {
|
|
6397
|
-
inner = /* @__PURE__ */ jsx(CutCell, { lines: truncLines, children: cellContent });
|
|
6398
|
-
} else if (kind === "email") {
|
|
6399
|
-
inner = /* @__PURE__ */ jsx(CutEmail, { children: cellContent });
|
|
6400
|
-
} else {
|
|
6401
|
-
inner = cellContent;
|
|
6402
|
-
}
|
|
6403
|
-
const align = col.align ?? (kind === "number" ? "right" : "left");
|
|
6404
|
-
if (align !== "left" && cellContent !== null && cellContent !== void 0 && typeof cellContent !== "string" && typeof cellContent !== "number") {
|
|
6405
|
-
inner = /* @__PURE__ */ jsx("div", { className: cn("flex items-center", align === "center" ? "justify-center" : "justify-end"), children: inner });
|
|
6406
|
-
}
|
|
6407
|
-
return /* @__PURE__ */ jsx(
|
|
6408
|
-
"td",
|
|
6409
|
-
{
|
|
6410
|
-
id: lead > 0 && lead + c === nameIndex ? `${headingId}-name-${idPart(id)}` : void 0,
|
|
6411
|
-
"data-col": col.key,
|
|
6412
|
-
className: cn(
|
|
6413
|
-
density === "compact" ? "px-ds-3 py-ds-2" : "px-ds-4 py-ds-3",
|
|
6414
|
-
"text-[var(--ds-text-primary)]",
|
|
6415
|
-
alignClass,
|
|
6416
|
-
shrink && "w-px whitespace-nowrap",
|
|
6417
|
-
whole2 && "whitespace-nowrap",
|
|
6418
|
-
kind === "identifier" && "[overflow-wrap:anywhere]",
|
|
6419
|
-
pinFocus(lead + c, cellCount)
|
|
6420
|
-
),
|
|
6421
|
-
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,
|
|
6422
|
-
children: inner
|
|
6423
|
-
},
|
|
6424
|
-
col.key
|
|
6425
|
-
);
|
|
6426
|
-
})
|
|
6427
|
-
]
|
|
6428
|
-
}
|
|
6429
|
-
),
|
|
6430
|
-
expandable && isExpanded && renderExpanded && /* @__PURE__ */ jsx("tr", { className: "border-b-[length:var(--ds-divider-width)] border-[var(--ds-border-subtle)] last:border-b-0", children: /* @__PURE__ */ jsx(
|
|
6431
|
-
"td",
|
|
6947
|
+
) }) : bodyRows.map(({ row, originalIdx, tree: place }, i) => {
|
|
6948
|
+
const node = place?.node;
|
|
6949
|
+
const id = node ? node.id : idOf(row, originalIdx);
|
|
6950
|
+
const box = boxOf(originalIdx, id);
|
|
6951
|
+
const isSelected = !!box?.checked;
|
|
6952
|
+
const isExpanded = expandedSet.has(String(id));
|
|
6953
|
+
const clickable = !!onRowClick || canOpenByClick;
|
|
6954
|
+
const isParent = !!node?.children.length;
|
|
6955
|
+
const isOpen = isParent && openSet.has(String(id));
|
|
6956
|
+
const treeRow = place ? {
|
|
6957
|
+
"aria-level": place.node.level,
|
|
6958
|
+
"aria-setsize": place.size,
|
|
6959
|
+
"aria-posinset": place.pos,
|
|
6960
|
+
"aria-expanded": isParent ? isOpen : void 0,
|
|
6961
|
+
"data-grid-key": gridKey(String(id)),
|
|
6962
|
+
onFocus: onRowFocus
|
|
6963
|
+
} : {};
|
|
6964
|
+
const nameRef = node ? `${headingId}-tree-name-${idPart(id)}` : `${headingId}-name-${idPart(id)}`;
|
|
6965
|
+
const detailsAt = trail ? cellCount - 1 : selectable ? 1 : 0;
|
|
6966
|
+
const details = expandable && /* @__PURE__ */ jsx("td", { className: cn("w-8", density === "compact" ? "px-ds-1 py-ds-2" : "px-ds-2 py-ds-3", pinFocus(detailsAt, cellCount)), style: pinStyle(detailsAt, cellCount), children: /* @__PURE__ */ jsx(AutoTooltip, { content: "Details", children: /* @__PURE__ */ jsx(
|
|
6967
|
+
"button",
|
|
6432
6968
|
{
|
|
6433
|
-
|
|
6434
|
-
|
|
6435
|
-
|
|
6969
|
+
type: "button",
|
|
6970
|
+
onClick: () => toggleExpand(id),
|
|
6971
|
+
className: cn("text-[var(--ds-text-muted)] hover:text-[var(--ds-text-primary)] cursor-pointer", FOCUS_RING),
|
|
6972
|
+
"aria-expanded": isExpanded,
|
|
6973
|
+
...nameIndex >= 0 ? { "aria-labelledby": `${headingId}-details ${nameRef}` } : { "aria-label": "Details" },
|
|
6436
6974
|
children: /* @__PURE__ */ jsx(
|
|
6437
|
-
|
|
6975
|
+
Icon,
|
|
6438
6976
|
{
|
|
6439
|
-
|
|
6440
|
-
|
|
6441
|
-
|
|
6442
|
-
children: /* @__PURE__ */ jsx(PanelContent, { children: renderExpanded(row, originalIdx) })
|
|
6977
|
+
name: "chevron-right",
|
|
6978
|
+
size: 14,
|
|
6979
|
+
className: cn("transition-transform", isExpanded && "rotate-90")
|
|
6443
6980
|
}
|
|
6444
6981
|
)
|
|
6445
6982
|
}
|
|
6446
|
-
) })
|
|
6447
|
-
|
|
6448
|
-
|
|
6449
|
-
|
|
6983
|
+
) }) });
|
|
6984
|
+
return /* @__PURE__ */ jsxs(Fragment$1, { children: [
|
|
6985
|
+
/* @__PURE__ */ jsxs(
|
|
6986
|
+
"tr",
|
|
6987
|
+
{
|
|
6988
|
+
...marksOf(row, originalIdx, id),
|
|
6989
|
+
...treeRow,
|
|
6990
|
+
className: cn(
|
|
6991
|
+
// an opened row's divider is under its panel (A6)
|
|
6992
|
+
!(expandable && isExpanded && renderExpanded) && "border-b-[length:var(--ds-divider-width)] border-[var(--ds-border-subtle)] last:border-b-0",
|
|
6993
|
+
// the row's background and its tint change together, so its pinned cells and the rest fade as one
|
|
6994
|
+
// (roots.css registers --gs-row-tint as a colour so it can)
|
|
6995
|
+
"transition-[background-color,--gs-row-tint]",
|
|
6996
|
+
// the row's tint, as a variable too, so its pinned cells draw it over their solid ground (A35)
|
|
6997
|
+
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)]",
|
|
6998
|
+
clickable && "cursor-pointer",
|
|
6999
|
+
// an outline inside the row, clear of the frame's rounded corners (D8): it shows over the pinned
|
|
7000
|
+
// cells, whose solid ground hid the inset shadow the row drew before (the review of 30 September)
|
|
7001
|
+
(onRowClick || place) && FOCUS_INSET
|
|
7002
|
+
),
|
|
7003
|
+
onClick: clickable ? (e) => {
|
|
7004
|
+
if (!clickIsRows(e)) return;
|
|
7005
|
+
if (onRowClick) onRowClick(row, originalIdx);
|
|
7006
|
+
else toggleExpand(id);
|
|
7007
|
+
} : void 0,
|
|
7008
|
+
tabIndex: place ? heldOuter ? -1 : grid.tabIndexOf(String(id)) : onRowClick ? 0 : void 0,
|
|
7009
|
+
onKeyDown: onRowClick && !place ? (e) => {
|
|
7010
|
+
if (e.target !== e.currentTarget) return;
|
|
7011
|
+
if (e.key === "Enter" || e.key === " ") {
|
|
7012
|
+
e.preventDefault();
|
|
7013
|
+
onRowClick(row, originalIdx);
|
|
7014
|
+
}
|
|
7015
|
+
} : void 0,
|
|
7016
|
+
children: [
|
|
7017
|
+
selectable && /* @__PURE__ */ jsx("td", { className: cn("w-10", density === "compact" ? "px-ds-2 py-ds-2" : "px-ds-3 py-ds-3", pinFocus(0, cellCount)), style: pinStyle(0, cellCount), children: box && /* @__PURE__ */ jsx(Checkbox, { checked: isSelected, indeterminate: box.mixed, onChange: (_, { shiftKey: shiftKey2 }) => toggleBox(originalIdx, id, shiftKey2), "aria-labelledby": nameIndex >= 0 ? `${headingId}-select ${nameRef}` : `${headingId}-select` }) }),
|
|
7018
|
+
!trail && details,
|
|
7019
|
+
columns.map((col, c) => {
|
|
7020
|
+
const truncLines = col.truncate === true ? 1 : col.truncate ? col.truncate.lines : 0;
|
|
7021
|
+
const kind = kindOf2(col);
|
|
7022
|
+
const alignClass = col.align ? col.align === "right" ? "text-right" : col.align === "center" ? "text-center" : "text-left" : kind === "number" ? "text-right" : "text-left";
|
|
7023
|
+
const cellContent = row[col.key];
|
|
7024
|
+
const shrink = (kind === "number" || kind === "date") && !col.maxWidth;
|
|
7025
|
+
const whole2 = !kind && renderedKinds.has(col.key);
|
|
7026
|
+
let inner;
|
|
7027
|
+
if (truncLines > 0) {
|
|
7028
|
+
inner = /* @__PURE__ */ jsx(CutCell, { lines: truncLines, children: cellContent });
|
|
7029
|
+
} else if (kind === "email") {
|
|
7030
|
+
inner = /* @__PURE__ */ jsx(CutEmail, { children: cellContent });
|
|
7031
|
+
} else {
|
|
7032
|
+
inner = cellContent;
|
|
7033
|
+
}
|
|
7034
|
+
const align = col.align ?? (kind === "number" ? "right" : "left");
|
|
7035
|
+
if (align !== "left" && cellContent !== null && cellContent !== void 0 && typeof cellContent !== "string" && typeof cellContent !== "number") {
|
|
7036
|
+
inner = /* @__PURE__ */ jsx("div", { className: cn("flex items-center", align === "center" ? "justify-center" : "justify-end"), children: inner });
|
|
7037
|
+
}
|
|
7038
|
+
if (node && c === 0) {
|
|
7039
|
+
const nameId = nameRef;
|
|
7040
|
+
const under = node.children.length;
|
|
7041
|
+
inner = /* @__PURE__ */ jsxs("div", { "data-tree-indent": "", className: cn("flex items-center gap-ds-2", align === "center" ? "justify-center" : align === "right" && "justify-end"), style: node.level > 1 ? { paddingLeft: `calc(var(--ds-space-3) * ${node.level - 1})` } : void 0, children: [
|
|
7042
|
+
isParent ? (
|
|
7043
|
+
// named by its own words and then the row's name, which it points to: the cell's text stays the name
|
|
7044
|
+
/* @__PURE__ */ jsx("button", { type: "button", tabIndex: -1, "data-tree-toggle": "", id: `${nameId}-toggle`, "aria-label": `${isOpen ? "Hide" : "Show"} ${under} ${under === 1 ? "row" : "rows"} under`, "aria-labelledby": `${nameId}-toggle ${nameId}`, className: TREE_TOGGLE, onClick: (e) => {
|
|
7045
|
+
toggleOpen(id);
|
|
7046
|
+
e.currentTarget.closest("tr")?.focus();
|
|
7047
|
+
}, children: /* @__PURE__ */ jsx(Icon, { name: "chevron-right", size: 14, className: cn("transition-transform", isOpen && "rotate-90") }) })
|
|
7048
|
+
) : /* @__PURE__ */ jsx("span", { "aria-hidden": "true", className: "shrink-0 w-4 h-4" }),
|
|
7049
|
+
/* @__PURE__ */ jsx("div", { id: nameId, className: "min-w-0", children: inner })
|
|
7050
|
+
] });
|
|
7051
|
+
}
|
|
7052
|
+
return /* @__PURE__ */ jsx(
|
|
7053
|
+
"td",
|
|
7054
|
+
{
|
|
7055
|
+
id: !node && lead > 0 && lead + c === nameIndex ? `${headingId}-name-${idPart(id)}` : void 0,
|
|
7056
|
+
"data-col": col.key,
|
|
7057
|
+
className: cn(
|
|
7058
|
+
density === "compact" ? "px-ds-3 py-ds-2" : "px-ds-4 py-ds-3",
|
|
7059
|
+
"text-[var(--ds-text-primary)]",
|
|
7060
|
+
alignClass,
|
|
7061
|
+
shrink && "w-px whitespace-nowrap",
|
|
7062
|
+
whole2 && "whitespace-nowrap",
|
|
7063
|
+
kind === "identifier" && "[overflow-wrap:anywhere]",
|
|
7064
|
+
pinFocus(lead + c, cellCount)
|
|
7065
|
+
),
|
|
7066
|
+
style: col.maxWidth || col.width || col.minWidth || c + lead < pinnedStart || c >= columns.length - endColumns ? { maxWidth: col.maxWidth, width: col.width, minWidth: col.minWidth, ...pinStyle(lead + c, cellCount) } : void 0,
|
|
7067
|
+
children: inner
|
|
7068
|
+
},
|
|
7069
|
+
col.key
|
|
7070
|
+
);
|
|
7071
|
+
}),
|
|
7072
|
+
trail > 0 && details
|
|
7073
|
+
]
|
|
7074
|
+
}
|
|
7075
|
+
),
|
|
7076
|
+
expandable && isExpanded && renderExpanded && // in a tree table the panel's controls join its row's in the Tab order, focus in it makes its row the
|
|
7077
|
+
// stop, and the panel is at its row's level, so a screen reader never places it a level apart (item 14)
|
|
7078
|
+
/* @__PURE__ */ jsx("tr", { "data-panel-of": place ? String(id) : void 0, "aria-level": place ? place.node.level : void 0, onFocus: place ? onRowFocus : void 0, className: "border-b-[length:var(--ds-divider-width)] border-[var(--ds-border-subtle)] last:border-b-0", children: /* @__PURE__ */ jsx(
|
|
7079
|
+
"td",
|
|
7080
|
+
{
|
|
7081
|
+
colSpan: cellCount,
|
|
7082
|
+
className: cn("py-ds-4 text-sm text-[var(--ds-text-primary)]", !pins.panel && (density === "compact" ? "px-ds-3" : "px-ds-4")),
|
|
7083
|
+
style: pins.panel ? { paddingLeft: pins.panel[0], paddingRight: pins.panel[1] } : void 0,
|
|
7084
|
+
children: /* @__PURE__ */ jsx(
|
|
7085
|
+
"div",
|
|
7086
|
+
{
|
|
7087
|
+
"data-row-panel": "",
|
|
7088
|
+
className: "sticky",
|
|
7089
|
+
style: pins.panel ? { left: pins.panel[0], maxWidth: pins.frame ? pins.frame - pins.panel[0] - pins.panel[1] : void 0 } : { left: 0 },
|
|
7090
|
+
children: place ? /* @__PURE__ */ jsx(TreeHeldCtx, { value: String(id) !== stopKey, children: /* @__PURE__ */ jsx(PanelContent, { children: renderExpanded(row, originalIdx) }) }) : /* @__PURE__ */ jsx(PanelContent, { children: renderExpanded(row, originalIdx) })
|
|
7091
|
+
}
|
|
7092
|
+
)
|
|
7093
|
+
}
|
|
7094
|
+
) })
|
|
7095
|
+
] }, String(id));
|
|
7096
|
+
}) }) })
|
|
7097
|
+
] })
|
|
7098
|
+
);
|
|
6450
7099
|
const region = scrollable || regionFocused ? { tabIndex: 0, role: "region", ...title ? { "aria-labelledby": titleId } : { "aria-label": ariaLabel ?? "Table" } } : {};
|
|
6451
7100
|
return withControl(
|
|
6452
7101
|
/* @__PURE__ */ jsxs(
|
|
@@ -6462,7 +7111,7 @@ function Table({
|
|
|
6462
7111
|
loading && data.length > 0 && /* @__PURE__ */ jsx(RefreshLine, { className: "inset-x-0 rounded-t-[inherit]" }),
|
|
6463
7112
|
loading && data.length === 0 && /* @__PURE__ */ jsx("span", { role: "status", className: "sr-only", children: LOADING_LABEL }),
|
|
6464
7113
|
title && /* @__PURE__ */ jsx(TableHeading, { title, description, actions, titleId, descriptionId, inset: true }),
|
|
6465
|
-
selectable && /* @__PURE__ */ jsx("span", { hidden: true, id: `${headingId}-select-all`, children: "Select all rows shown" }),
|
|
7114
|
+
selectable && /* @__PURE__ */ jsx("span", { hidden: true, id: `${headingId}-select-all`, children: nested ? pager ? "Select all rows on this page" : "Select all rows" : "Select all rows shown" }),
|
|
6466
7115
|
selectable && /* @__PURE__ */ jsx("span", { hidden: true, id: `${headingId}-select`, children: "Select" }),
|
|
6467
7116
|
expandable && /* @__PURE__ */ jsx("span", { hidden: true, id: `${headingId}-details`, children: "Details" }),
|
|
6468
7117
|
/* @__PURE__ */ jsx(
|
|
@@ -6488,266 +7137,32 @@ function Table({
|
|
|
6488
7137
|
)
|
|
6489
7138
|
);
|
|
6490
7139
|
}
|
|
6491
|
-
function optionsKeyForFit(options) {
|
|
6492
|
-
return options.map((o) => `${o.value}:${o.label}`).join("|");
|
|
6493
|
-
}
|
|
6494
|
-
var sizes2 = {
|
|
6495
|
-
xs: "text-xs px-ds-2",
|
|
6496
|
-
sm: "text-xs px-ds-3",
|
|
6497
|
-
md: "text-sm px-ds-3",
|
|
6498
|
-
lg: "text-base px-ds-3"
|
|
6499
|
-
};
|
|
6500
|
-
var containerPadding = {
|
|
6501
|
-
xs: "p-[2px] gap-[2px]",
|
|
6502
|
-
sm: "p-ds-1 gap-ds-0.5",
|
|
6503
|
-
md: "p-ds-1 gap-ds-0.5",
|
|
6504
|
-
lg: "p-ds-1 gap-ds-0.5"
|
|
6505
|
-
};
|
|
6506
|
-
var indicatorInset = {
|
|
6507
|
-
xs: "2px",
|
|
6508
|
-
sm: "4px",
|
|
6509
|
-
md: "4px",
|
|
6510
|
-
lg: "4px"
|
|
6511
|
-
};
|
|
6512
|
-
function segmentRadius(inset, bordered) {
|
|
6513
|
-
return `max(var(--ds-radius-sm), calc(var(--ds-radius-md) - ${inset}${bordered ? " - var(--ds-border-width)" : ""}))`;
|
|
6514
|
-
}
|
|
6515
|
-
function SegmentedControl({
|
|
6516
|
-
value,
|
|
6517
|
-
onChange: onChangeProp,
|
|
6518
|
-
options,
|
|
6519
|
-
size: sizeProp,
|
|
6520
|
-
variant = "default",
|
|
6521
|
-
fullWidth = false,
|
|
6522
|
-
onHoverChange,
|
|
6523
|
-
className,
|
|
6524
|
-
"aria-label": ariaLabel,
|
|
6525
|
-
maxOptions = 6,
|
|
6526
|
-
...wiring
|
|
6527
|
-
}) {
|
|
6528
|
-
const onChange = useReportedChange(onChangeProp, value);
|
|
6529
|
-
const contextSize = useContext(ControlSizeContext);
|
|
6530
|
-
const control = useFieldControl(wiring);
|
|
6531
|
-
const named = !ariaLabel && control.labelId ? { "aria-labelledby": control.labelId } : {};
|
|
6532
|
-
const size = sizeProp ?? contextSize ?? "md";
|
|
6533
|
-
const containerRef = useRef(null);
|
|
6534
|
-
const [indicator, setIndicator] = useState({ left: 0, width: 0 });
|
|
6535
|
-
const parentRef = useRef(null);
|
|
6536
|
-
const neededRef = useRef(0);
|
|
6537
|
-
const [overflows, setOverflows] = useState(false);
|
|
6538
|
-
const measureFit = useCallback(() => {
|
|
6539
|
-
const row = containerRef.current;
|
|
6540
|
-
if (row) {
|
|
6541
|
-
parentRef.current = row.parentElement;
|
|
6542
|
-
if (row.scrollWidth > 0) neededRef.current = row.scrollWidth;
|
|
6543
|
-
}
|
|
6544
|
-
const parent = parentRef.current;
|
|
6545
|
-
const needed = neededRef.current;
|
|
6546
|
-
if (!parent || !needed) return;
|
|
6547
|
-
const style = getComputedStyle(parent);
|
|
6548
|
-
const available = parent.clientWidth - (parseFloat(style.paddingLeft) || 0) - (parseFloat(style.paddingRight) || 0);
|
|
6549
|
-
if (available <= 0) return;
|
|
6550
|
-
setOverflows((prev) => prev ? needed > available - 8 : needed > available);
|
|
6551
|
-
}, []);
|
|
6552
|
-
useLayoutEffect(() => {
|
|
6553
|
-
measureFit();
|
|
6554
|
-
const parent = parentRef.current;
|
|
6555
|
-
if (!parent || typeof ResizeObserver === "undefined") return;
|
|
6556
|
-
const observer = new ResizeObserver(measureFit);
|
|
6557
|
-
observer.observe(parent);
|
|
6558
|
-
return () => observer.disconnect();
|
|
6559
|
-
}, [measureFit, optionsKeyForFit(options)]);
|
|
6560
|
-
const collapsed = options.length > maxOptions || overflows;
|
|
6561
|
-
const updateIndicator = useCallback(() => {
|
|
6562
|
-
if (!containerRef.current) return;
|
|
6563
|
-
const active = containerRef.current.querySelector("[data-active='true']");
|
|
6564
|
-
if (active) {
|
|
6565
|
-
setIndicator({
|
|
6566
|
-
left: active.offsetLeft,
|
|
6567
|
-
width: active.offsetWidth
|
|
6568
|
-
});
|
|
6569
|
-
}
|
|
6570
|
-
}, []);
|
|
6571
|
-
const optionsKey = options.map((o) => `${o.value}:${o.label}`).join("|");
|
|
6572
|
-
useLayoutEffect(() => {
|
|
6573
|
-
updateIndicator();
|
|
6574
|
-
}, [value, optionsKey, updateIndicator]);
|
|
6575
|
-
useEffect(() => {
|
|
6576
|
-
const fonts = document.fonts;
|
|
6577
|
-
if (!fonts?.ready) return;
|
|
6578
|
-
let live = true;
|
|
6579
|
-
fonts.ready.then(() => {
|
|
6580
|
-
if (live) updateIndicator();
|
|
6581
|
-
});
|
|
6582
|
-
return () => {
|
|
6583
|
-
live = false;
|
|
6584
|
-
};
|
|
6585
|
-
}, [updateIndicator]);
|
|
6586
|
-
const [animate, setAnimate] = useState(false);
|
|
6587
|
-
const select = useCallback((v) => {
|
|
6588
|
-
setAnimate(true);
|
|
6589
|
-
onChange(v);
|
|
6590
|
-
}, [onChange]);
|
|
6591
|
-
useLayoutEffect(() => {
|
|
6592
|
-
if (collapsed || !containerRef.current || typeof ResizeObserver === "undefined") return;
|
|
6593
|
-
const observer = new ResizeObserver(updateIndicator);
|
|
6594
|
-
observer.observe(containerRef.current);
|
|
6595
|
-
containerRef.current.querySelectorAll("button").forEach((b) => observer.observe(b));
|
|
6596
|
-
return () => observer.disconnect();
|
|
6597
|
-
}, [updateIndicator, optionsKey, collapsed]);
|
|
6598
|
-
const containerHeight = {
|
|
6599
|
-
xs: "h-ds-6",
|
|
6600
|
-
sm: "h-[var(--ds-control-height-sm)]",
|
|
6601
|
-
md: "h-[var(--ds-control-height-md)]",
|
|
6602
|
-
lg: "h-[var(--ds-control-height-lg)]"
|
|
6603
|
-
};
|
|
6604
|
-
const tabStop = rovingTabStop(options, (o) => o.value === value, (o) => !!o.disabled);
|
|
6605
|
-
const handleKeyDown = (e) => {
|
|
6606
|
-
const enabled = options.filter((o) => !o.disabled);
|
|
6607
|
-
if (enabled.length === 0) return;
|
|
6608
|
-
const idx = Math.max(0, enabled.findIndex((o) => o.value === value));
|
|
6609
|
-
let next = null;
|
|
6610
|
-
if (e.key === "ArrowRight" || e.key === "ArrowDown") next = (idx + 1) % enabled.length;
|
|
6611
|
-
else if (e.key === "ArrowLeft" || e.key === "ArrowUp") next = (idx - 1 + enabled.length) % enabled.length;
|
|
6612
|
-
else if (e.key === "Home") next = 0;
|
|
6613
|
-
else if (e.key === "End") next = enabled.length - 1;
|
|
6614
|
-
if (next === null) return;
|
|
6615
|
-
e.preventDefault();
|
|
6616
|
-
select(enabled[next].value);
|
|
6617
|
-
const buttons = containerRef.current?.querySelectorAll('[role="radio"]');
|
|
6618
|
-
buttons?.forEach((b) => {
|
|
6619
|
-
if (b.dataset.value === enabled[next].value) b.focus();
|
|
6620
|
-
});
|
|
6621
|
-
};
|
|
6622
|
-
if (collapsed) {
|
|
6623
|
-
return /* @__PURE__ */ jsx(
|
|
6624
|
-
Dropdown,
|
|
6625
|
-
{
|
|
6626
|
-
"aria-label": ariaLabel,
|
|
6627
|
-
...wiring,
|
|
6628
|
-
size: size === "md" || size === "lg" ? "md" : "sm",
|
|
6629
|
-
options: options.filter((o) => !o.disabled).map((o) => ({ id: o.value, label: o.label })),
|
|
6630
|
-
value,
|
|
6631
|
-
onChange: (v) => onChange(v),
|
|
6632
|
-
className: cn("inline-block", fullWidth ? "w-full" : "w-auto", className)
|
|
6633
|
-
}
|
|
6634
|
-
);
|
|
6635
|
-
}
|
|
6636
|
-
return /* @__PURE__ */ jsxs(
|
|
6637
|
-
"div",
|
|
6638
|
-
{
|
|
6639
|
-
ref: containerRef,
|
|
6640
|
-
role: "radiogroup",
|
|
6641
|
-
id: control.id,
|
|
6642
|
-
"aria-label": ariaLabel,
|
|
6643
|
-
...named,
|
|
6644
|
-
"aria-describedby": control.describedBy,
|
|
6645
|
-
"aria-invalid": control.invalid || void 0,
|
|
6646
|
-
"aria-required": control.required || void 0,
|
|
6647
|
-
onKeyDown: handleKeyDown,
|
|
6648
|
-
className: cn(
|
|
6649
|
-
"relative items-center",
|
|
6650
|
-
// Sprint 25.14 A21: in a Field's column a track that isn't full width keeps its own width; w-fit, not self-start,
|
|
6651
|
-
// so a row or a centred column still aligns it (the review of 30 September)
|
|
6652
|
-
fullWidth ? "flex w-full" : "inline-flex w-fit",
|
|
6653
|
-
containerPadding[size],
|
|
6654
|
-
containerHeight[size],
|
|
6655
|
-
"bg-[var(--ds-bg-muted)]",
|
|
6656
|
-
// The owner's review of 1 October 2026: the frame's corner is a field's, so the two change together with the
|
|
6657
|
-
// theme's radius; the segments inside sit concentric with it (SEGMENT_RADIUS)
|
|
6658
|
-
"rounded-[var(--ds-radius-md)]",
|
|
6659
|
-
// The frame's edge is a button's: each segment is a labelled button, so the frame isn't what identifies the
|
|
6660
|
-
// control, and WCAG 1.4.11 asks no 3:1 of it
|
|
6661
|
-
variant === "default" && "border-[length:var(--ds-border-width)] border-[var(--ds-border-default)]",
|
|
6662
|
-
control.invalid && "border-[length:var(--ds-border-width)] border-[var(--ds-status-error)]",
|
|
6663
|
-
className
|
|
6664
|
-
),
|
|
6665
|
-
style: { "--ds-segment-radius": segmentRadius(indicatorInset[size], variant === "default" || !!control.invalid) },
|
|
6666
|
-
children: [
|
|
6667
|
-
/* @__PURE__ */ jsx(
|
|
6668
|
-
"div",
|
|
6669
|
-
{
|
|
6670
|
-
className: cn(
|
|
6671
|
-
"absolute rounded-[var(--ds-segment-radius)]",
|
|
6672
|
-
"bg-[var(--ds-bg-surface)]",
|
|
6673
|
-
// The selected segment is a kind of button, so it takes a secondary button's surface and edge, as the frame
|
|
6674
|
-
// takes a button's edge (the owner, 3 October 2026: the 3:1 strong edge it kept from Sprint 25.14 drew the
|
|
6675
|
-
// darker outline 25.19 took off the fields). It shows its state as the raised surface on the muted track, with
|
|
6676
|
-
// the default variant's shadow and its label's stronger colour. While its segment has keyboard focus the shadow
|
|
6677
|
-
// steps aside, as a button's does, so the segment's outline sits clear (Sprint 30, D7)
|
|
6678
|
-
"border-[length:var(--ds-border-width)] border-[var(--ds-border-default)]",
|
|
6679
|
-
variant === "default" && "shadow-[var(--ds-shadow-sm)]",
|
|
6680
|
-
"[[role=radiogroup]:has([aria-checked=true]:focus-visible)_&]:shadow-none",
|
|
6681
|
-
"transition-all motion-reduce:transition-none"
|
|
6682
|
-
),
|
|
6683
|
-
"data-animate": animate ? "true" : "false",
|
|
6684
|
-
style: {
|
|
6685
|
-
left: indicator.left,
|
|
6686
|
-
width: indicator.width,
|
|
6687
|
-
top: indicatorInset[size],
|
|
6688
|
-
bottom: indicatorInset[size],
|
|
6689
|
-
transitionDuration: animate ? "var(--ds-transition-speed)" : "0ms",
|
|
6690
|
-
transitionTimingFunction: "var(--ds-transition-ease)"
|
|
6691
|
-
}
|
|
6692
|
-
}
|
|
6693
|
-
),
|
|
6694
|
-
options.map((opt, i) => /* @__PURE__ */ jsx(
|
|
6695
|
-
"button",
|
|
6696
|
-
{
|
|
6697
|
-
type: "button",
|
|
6698
|
-
role: "radio",
|
|
6699
|
-
"aria-checked": opt.value === value,
|
|
6700
|
-
"data-active": opt.value === value,
|
|
6701
|
-
"data-value": opt.value,
|
|
6702
|
-
tabIndex: i === tabStop ? 0 : -1,
|
|
6703
|
-
disabled: opt.disabled,
|
|
6704
|
-
onClick: () => !opt.disabled && select(opt.value),
|
|
6705
|
-
onMouseEnter: onHoverChange && !opt.disabled ? () => onHoverChange(opt.value) : void 0,
|
|
6706
|
-
onMouseLeave: onHoverChange ? () => onHoverChange(null) : void 0,
|
|
6707
|
-
className: cn(
|
|
6708
|
-
"relative z-10 inline-flex items-center justify-center self-stretch font-medium whitespace-nowrap",
|
|
6709
|
-
fullWidth && "flex-1",
|
|
6710
|
-
"rounded-[var(--ds-segment-radius)]",
|
|
6711
|
-
"transition-colors cursor-pointer",
|
|
6712
|
-
FOCUS_RING,
|
|
6713
|
-
sizes2[size],
|
|
6714
|
-
opt.value === value ? "text-[var(--ds-text-primary)]" : "text-[var(--ds-text-muted)] hover:text-[var(--ds-text-secondary)]",
|
|
6715
|
-
opt.disabled && "opacity-disabled cursor-not-allowed"
|
|
6716
|
-
),
|
|
6717
|
-
children: opt.label
|
|
6718
|
-
},
|
|
6719
|
-
opt.value
|
|
6720
|
-
))
|
|
6721
|
-
]
|
|
6722
|
-
}
|
|
6723
|
-
);
|
|
6724
|
-
}
|
|
6725
7140
|
|
|
6726
7141
|
// ../../showcase/src/components/Calendar/event-colours.ts
|
|
6727
7142
|
function eventColours(category) {
|
|
6728
7143
|
const colour = category?.color;
|
|
6729
7144
|
if (colour === void 0 || colour === "accent" || colour === "var(--ds-accent-primary)") return ACCENT;
|
|
6730
|
-
if (colour === "neutral") return
|
|
6731
|
-
if (typeof colour === "number") return Number.isInteger(colour) && colour >= 1 ? supporting(colour) :
|
|
7145
|
+
if (colour === "neutral") return NEUTRAL2;
|
|
7146
|
+
if (typeof colour === "number") return Number.isInteger(colour) && colour >= 1 ? supporting(colour) : NEUTRAL2;
|
|
6732
7147
|
const named = SUPPORTING_TOKEN.exec(colour.trim());
|
|
6733
7148
|
if (named) return supporting(Number(named[1]));
|
|
6734
7149
|
const chart = CHART_TOKEN.exec(colour.trim());
|
|
6735
7150
|
if (chart) return Number(chart[1]) === 1 ? ACCENT : supporting(Number(chart[1]) - 1);
|
|
6736
|
-
return { ...
|
|
7151
|
+
return { ...NEUTRAL2, edge: colour };
|
|
6737
7152
|
}
|
|
6738
7153
|
var SUPPORTING_TOKEN = /^var\(\s*--ds-palette-(\d+)-[a-z-]+\s*\)$/;
|
|
6739
7154
|
var CHART_TOKEN = /^var\(\s*--ds-chart-(\d+)\s*\)$/;
|
|
6740
7155
|
var supporting = (n) => ({
|
|
6741
|
-
fill: `var(--ds-palette-${n}-bg, ${
|
|
6742
|
-
text: `var(--ds-palette-${n}-text, ${
|
|
6743
|
-
edge: `var(--ds-palette-${n}-chart, ${
|
|
7156
|
+
fill: `var(--ds-palette-${n}-bg, ${NEUTRAL2.fill})`,
|
|
7157
|
+
text: `var(--ds-palette-${n}-text, ${NEUTRAL2.text})`,
|
|
7158
|
+
edge: `var(--ds-palette-${n}-chart, ${NEUTRAL2.edge})`
|
|
6744
7159
|
});
|
|
6745
7160
|
var ACCENT = {
|
|
6746
7161
|
fill: "var(--ds-accent-bg, var(--ds-accent-subtle))",
|
|
6747
7162
|
text: "var(--ds-accent-text, var(--ds-text-primary))",
|
|
6748
7163
|
edge: "var(--ds-chart-1)"
|
|
6749
7164
|
};
|
|
6750
|
-
var
|
|
7165
|
+
var NEUTRAL2 = {
|
|
6751
7166
|
fill: "var(--ds-bg-muted)",
|
|
6752
7167
|
text: "var(--ds-text-primary)",
|
|
6753
7168
|
edge: "var(--ds-control-edge-strong)"
|
|
@@ -8303,7 +8718,11 @@ function Calendar({
|
|
|
8303
8718
|
}
|
|
8304
8719
|
check = setTimeout(settle, SETTLE_MS);
|
|
8305
8720
|
};
|
|
8306
|
-
const onOut = () => {
|
|
8721
|
+
const onOut = (e) => {
|
|
8722
|
+
if (!e.target?.closest?.('[role="dialog"], [role="alertdialog"]')) {
|
|
8723
|
+
stop();
|
|
8724
|
+
return;
|
|
8725
|
+
}
|
|
8307
8726
|
clearTimeout(check);
|
|
8308
8727
|
check = setTimeout(settle, SETTLE_MS);
|
|
8309
8728
|
};
|
|
@@ -8846,9 +9265,9 @@ function ExpandableDescription({ children, className }) {
|
|
|
8846
9265
|
}
|
|
8847
9266
|
);
|
|
8848
9267
|
}
|
|
8849
|
-
function HorizontalLayout({ items, minItemWidth, className }) {
|
|
9268
|
+
function HorizontalLayout({ items, minItemWidth, label, className }) {
|
|
8850
9269
|
const [row, setRow] = useState(null);
|
|
8851
|
-
useKeyboardScroll(row,
|
|
9270
|
+
useKeyboardScroll(row, label, true, false, "x");
|
|
8852
9271
|
return /* @__PURE__ */ jsx("div", { ref: setRow, "data-timeline-row": "", className: cn("relative flex items-start overflow-x-auto snap-x", FOCUS_INSET, className), children: items.map((item, i) => {
|
|
8853
9272
|
const isFirst = i === 0;
|
|
8854
9273
|
const isLast = i === items.length - 1;
|
|
@@ -8927,7 +9346,7 @@ function VerticalLayout({ items, className }) {
|
|
|
8927
9346
|
] })
|
|
8928
9347
|
] }, i)) });
|
|
8929
9348
|
}
|
|
8930
|
-
function Timeline({ items: allItems, orientation = "vertical", minItemWidth = 200, className, ref, pager }) {
|
|
9349
|
+
function Timeline({ items: allItems, orientation = "vertical", minItemWidth = 200, className, ref, pager, "aria-label": ariaLabel = "Timeline" }) {
|
|
8931
9350
|
useScrollsInside();
|
|
8932
9351
|
useWholeListCheck("Timeline", allItems.length, pager);
|
|
8933
9352
|
const items = pagerPart(allItems, pager);
|
|
@@ -8940,7 +9359,7 @@ function Timeline({ items: allItems, orientation = "vertical", minItemWidth = 20
|
|
|
8940
9359
|
}, [ref]);
|
|
8941
9360
|
const fits = width === 0 || width >= items.length * minItemWidth;
|
|
8942
9361
|
const horizontal = orientation === "horizontal" || orientation === "responsive" && fits;
|
|
8943
|
-
const list2 = /* @__PURE__ */ jsx("div", { ref: setRefs, "data-ds-list": "", "data-timeline-orientation": horizontal ? "horizontal" : "vertical", className: pager ? void 0 : className, children: /* @__PURE__ */ jsx(RowsCtx, { value: true, children: horizontal ? /* @__PURE__ */ jsx(HorizontalLayout, { items, minItemWidth }) : /* @__PURE__ */ jsx(VerticalLayout, { items }) }) });
|
|
9362
|
+
const list2 = /* @__PURE__ */ jsx("div", { ref: setRefs, "data-ds-list": "", "data-timeline-orientation": horizontal ? "horizontal" : "vertical", className: pager ? void 0 : className, children: /* @__PURE__ */ jsx(RowsCtx, { value: true, children: horizontal ? /* @__PURE__ */ jsx(HorizontalLayout, { items, minItemWidth, label: ariaLabel }) : /* @__PURE__ */ jsx(VerticalLayout, { items }) }) });
|
|
8944
9363
|
if (!pager) return list2;
|
|
8945
9364
|
return /* @__PURE__ */ jsxs("div", { "data-gs-paged": "", className: cn("flex flex-col min-w-0", className), children: [
|
|
8946
9365
|
list2,
|
|
@@ -8963,20 +9382,54 @@ function CollapsibleRoot({
|
|
|
8963
9382
|
const [internalOpen, setInternalOpen] = useState(defaultOpen);
|
|
8964
9383
|
const isControlled = controlledOpen !== void 0;
|
|
8965
9384
|
const isOpen = isControlled ? controlledOpen : internalOpen;
|
|
9385
|
+
const triggerRef = useRef(null);
|
|
9386
|
+
const setTrigger = useCallback((el) => {
|
|
9387
|
+
triggerRef.current = el;
|
|
9388
|
+
}, []);
|
|
9389
|
+
const trigger = useCallback(() => triggerRef.current, []);
|
|
9390
|
+
const open = () => {
|
|
9391
|
+
if (isOpen) return;
|
|
9392
|
+
if (!isControlled) setInternalOpen(true);
|
|
9393
|
+
onOpenChange?.(true);
|
|
9394
|
+
};
|
|
8966
9395
|
const toggle = () => {
|
|
8967
9396
|
const next = !isOpen;
|
|
8968
9397
|
if (!isControlled) setInternalOpen(next);
|
|
8969
9398
|
onOpenChange?.(next);
|
|
8970
9399
|
};
|
|
8971
|
-
return /* @__PURE__ */ jsx(CollapsibleContext, { value: { isOpen, toggle }, children: /* @__PURE__ */ jsx("div", { className, "data-state": isOpen ? "open" : "closed", children: typeof children === "function" ? children({ isOpen, toggle }) : children }) });
|
|
9400
|
+
return /* @__PURE__ */ jsx(CollapsibleContext, { value: { isOpen, toggle, setTrigger, trigger, open }, children: /* @__PURE__ */ jsx("div", { className, "data-state": isOpen ? "open" : "closed", children: typeof children === "function" ? children({ isOpen, toggle }) : children }) });
|
|
9401
|
+
}
|
|
9402
|
+
var merged = /* @__PURE__ */ new WeakMap();
|
|
9403
|
+
function withTrigger(own, setTrigger) {
|
|
9404
|
+
if (!own) return setTrigger;
|
|
9405
|
+
let bySetter = merged.get(own);
|
|
9406
|
+
if (!bySetter) merged.set(own, bySetter = /* @__PURE__ */ new WeakMap());
|
|
9407
|
+
let attach = bySetter.get(setTrigger);
|
|
9408
|
+
if (!attach) {
|
|
9409
|
+
attach = (el) => {
|
|
9410
|
+
setTrigger(el);
|
|
9411
|
+
let cleanup;
|
|
9412
|
+
if (typeof own === "function") cleanup = own(el);
|
|
9413
|
+
else own.current = el;
|
|
9414
|
+
return () => {
|
|
9415
|
+
setTrigger(null);
|
|
9416
|
+
if (typeof cleanup === "function") cleanup();
|
|
9417
|
+
else if (typeof own === "function") own(null);
|
|
9418
|
+
else own.current = null;
|
|
9419
|
+
};
|
|
9420
|
+
};
|
|
9421
|
+
bySetter.set(setTrigger, attach);
|
|
9422
|
+
}
|
|
9423
|
+
return attach;
|
|
8972
9424
|
}
|
|
8973
9425
|
function CollapsibleTrigger({ children, className }) {
|
|
8974
|
-
const { isOpen, toggle } = useCollapsible();
|
|
9426
|
+
const { isOpen, toggle, setTrigger } = useCollapsible();
|
|
8975
9427
|
if (isValidElement(children)) {
|
|
8976
9428
|
const child = children;
|
|
8977
9429
|
return cloneElement(child, {
|
|
8978
9430
|
// a Button trigger in a form toggles; it never submits the form (0.21.0)
|
|
8979
9431
|
...triggerType(child),
|
|
9432
|
+
ref: withTrigger(child.props.ref, setTrigger),
|
|
8980
9433
|
"aria-expanded": isOpen,
|
|
8981
9434
|
className: cn(child.props.className, className),
|
|
8982
9435
|
onClick: (e) => {
|
|
@@ -8985,29 +9438,92 @@ function CollapsibleTrigger({ children, className }) {
|
|
|
8985
9438
|
}
|
|
8986
9439
|
});
|
|
8987
9440
|
}
|
|
8988
|
-
return /* @__PURE__ */ jsx("button", { type: "button", className: cn("text-left cursor-pointer", FOCUS_RING, className), onClick: toggle, "aria-expanded": isOpen, children });
|
|
9441
|
+
return /* @__PURE__ */ jsx("button", { ref: withTrigger(void 0, setTrigger), type: "button", className: cn("text-left cursor-pointer", FOCUS_RING, className), onClick: toggle, "aria-expanded": isOpen, children });
|
|
8989
9442
|
}
|
|
8990
9443
|
function CollapsibleContent({ children, className }) {
|
|
8991
|
-
const { isOpen } = useCollapsible();
|
|
9444
|
+
const { isOpen, trigger, open } = useCollapsible();
|
|
8992
9445
|
const ref = useRef(null);
|
|
8993
|
-
const
|
|
8994
|
-
const
|
|
8995
|
-
|
|
8996
|
-
|
|
8997
|
-
|
|
9446
|
+
const asked = useRef(null);
|
|
9447
|
+
const isOpenNow = useLatest(isOpen);
|
|
9448
|
+
const openNow = useLatest(open);
|
|
9449
|
+
useLayoutEffect(() => {
|
|
9450
|
+
const el = ref.current;
|
|
9451
|
+
if (!el) return;
|
|
9452
|
+
const onAsk = (e) => {
|
|
9453
|
+
if (isOpenNow.current) return;
|
|
9454
|
+
asked.current = e.detail;
|
|
9455
|
+
openNow.current();
|
|
9456
|
+
};
|
|
9457
|
+
el.addEventListener(OPEN_TO_FOCUS, onAsk);
|
|
9458
|
+
return () => el.removeEventListener(OPEN_TO_FOCUS, onAsk);
|
|
9459
|
+
}, [isOpenNow, openNow]);
|
|
9460
|
+
useLayoutEffect(() => {
|
|
9461
|
+
if (asked.current && !isOpen) asked.current = null;
|
|
9462
|
+
});
|
|
9463
|
+
const [height, setHeight] = useState(isOpen ? "auto" : 0);
|
|
9464
|
+
const [inertNow, setInertNow] = useState(!isOpen);
|
|
9465
|
+
const was = useRef(isOpen);
|
|
9466
|
+
useLayoutEffect(() => {
|
|
9467
|
+
const el = ref.current;
|
|
9468
|
+
if (was.current === isOpen) return;
|
|
9469
|
+
was.current = isOpen;
|
|
9470
|
+
if (!el) return;
|
|
9471
|
+
if (!isOpen && el.contains(document.activeElement)) {
|
|
9472
|
+
trigger()?.focus();
|
|
9473
|
+
if (el.contains(document.activeElement)) focusOutOf(el);
|
|
9474
|
+
}
|
|
9475
|
+
const ask = asked.current;
|
|
9476
|
+
asked.current = null;
|
|
9477
|
+
if (isOpen && ask && !ask.done && performance.now() - ask.at < 1e3 && !ask.target.closest("[inert]")) {
|
|
9478
|
+
ask.done = true;
|
|
9479
|
+
ask.step();
|
|
9480
|
+
}
|
|
9481
|
+
setInertNow(!isOpen);
|
|
9482
|
+
const seconds = parseFloat(getComputedStyle(el).transitionDuration) || 0;
|
|
9483
|
+
if (seconds <= 0) {
|
|
9484
|
+
setHeight(isOpen ? "auto" : 0);
|
|
9485
|
+
return;
|
|
8998
9486
|
}
|
|
8999
|
-
|
|
9487
|
+
let frame = 0;
|
|
9488
|
+
if (isOpen) setHeight(el.scrollHeight);
|
|
9489
|
+
else {
|
|
9490
|
+
setHeight(el.scrollHeight);
|
|
9491
|
+
frame = requestAnimationFrame(() => {
|
|
9492
|
+
void el.offsetHeight;
|
|
9493
|
+
setHeight(0);
|
|
9494
|
+
});
|
|
9495
|
+
}
|
|
9496
|
+
let done = false;
|
|
9497
|
+
const settle = () => {
|
|
9498
|
+
if (done) return;
|
|
9499
|
+
done = true;
|
|
9500
|
+
if (isOpen) setHeight("auto");
|
|
9501
|
+
};
|
|
9502
|
+
const onEnd = (e) => {
|
|
9503
|
+
if (e.target === el && e.propertyName === "height") settle();
|
|
9504
|
+
};
|
|
9505
|
+
el.addEventListener("transitionend", onEnd);
|
|
9506
|
+
const timer = setTimeout(settle, seconds * 1e3 + 100);
|
|
9507
|
+
return () => {
|
|
9508
|
+
cancelAnimationFrame(frame);
|
|
9509
|
+
el.removeEventListener("transitionend", onEnd);
|
|
9510
|
+
clearTimeout(timer);
|
|
9511
|
+
};
|
|
9512
|
+
}, [isOpen, trigger]);
|
|
9513
|
+
const moving = typeof height === "number" && height > 0;
|
|
9000
9514
|
return /* @__PURE__ */ jsx(
|
|
9001
9515
|
"div",
|
|
9002
9516
|
{
|
|
9003
9517
|
ref,
|
|
9004
|
-
|
|
9518
|
+
"data-state": isOpen ? "open" : "closed",
|
|
9519
|
+
inert: inertNow && !isOpen,
|
|
9520
|
+
className: cn((!isOpen || moving) && "overflow-hidden", "transition-[height]", className),
|
|
9005
9521
|
style: {
|
|
9006
|
-
height: height
|
|
9522
|
+
height: height === "auto" ? void 0 : height,
|
|
9007
9523
|
transitionDuration: "var(--ds-transition-speed)",
|
|
9008
9524
|
transitionTimingFunction: "var(--ds-transition-ease)"
|
|
9009
9525
|
},
|
|
9010
|
-
children: /* @__PURE__ */ jsx("div", {
|
|
9526
|
+
children: /* @__PURE__ */ jsx("div", { children })
|
|
9011
9527
|
}
|
|
9012
9528
|
);
|
|
9013
9529
|
}
|
|
@@ -15421,6 +15937,7 @@ function SnappingHeader({
|
|
|
15421
15937
|
([entry]) => {
|
|
15422
15938
|
if (!entry.isIntersecting && !collapsedRef.current) {
|
|
15423
15939
|
collapsedRef.current = true;
|
|
15940
|
+
setSpacer(expandedHeightRef.current);
|
|
15424
15941
|
setCollapsed(true);
|
|
15425
15942
|
}
|
|
15426
15943
|
},
|
|
@@ -17895,6 +18412,6 @@ function DangerZone({ title = "Danger zone", description, children, className })
|
|
|
17895
18412
|
] });
|
|
17896
18413
|
}
|
|
17897
18414
|
|
|
17898
|
-
export { Accordion, ActionPanel, ActionPanelGroup, AddAnother, Alert, AsidePanel, AvatarGroup, BottomNav, BulkActionBar, Calendar, Card, CardContent, CardDescription, CardFooter, CardGrid, CardHeader, CardTitle, Carousel, ChatMessageList, ChatPanel, Collapsible, CollapsibleContent, CollapsibleTrigger, ColorPicker, Combobox, CommandPalette, ContextMenu, CornerPanel, DEFAULT_DATE_RANGE_PRESETS, DangerZone, DataList, DateRangePicker, DescriptionList, Dialog, Dock, EmptyState, EntityCell, FileUpload, FlowSaved, FormWrapper, Gantt, Kbd, Launcher, LocaleProvider, MentionInput, MobileHeaderMenu, NavItem, NavMenu, Navbar, NotificationCenter, PageActions, PageContainer, PageHeader, PinInput, Progress, RadioGroup, Rating, RecurrencePicker, RecurrenceScopeDialog, RelativeTime, ScrollArea, SectionHeading,
|
|
18415
|
+
export { Accordion, ActionPanel, ActionPanelGroup, AddAnother, Alert, AsidePanel, AvatarGroup, BottomNav, BulkActionBar, Calendar, Card, CardContent, CardDescription, CardFooter, CardGrid, CardHeader, CardTitle, Carousel, ChatMessageList, ChatPanel, Collapsible, CollapsibleContent, CollapsibleTrigger, ColorPicker, Combobox, CommandPalette, ContextMenu, CornerPanel, DEFAULT_DATE_RANGE_PRESETS, DangerZone, DataList, DateRangePicker, DescriptionList, Dialog, Dock, EmptyState, EntityCell, FileUpload, FlowSaved, FormWrapper, Gantt, Kbd, Launcher, LocaleProvider, MentionInput, MobileHeaderMenu, NavItem, NavMenu, Navbar, NotificationCenter, PageActions, PageContainer, PageHeader, PinInput, Progress, RadioGroup, Rating, RecurrencePicker, RecurrenceScopeDialog, RelativeTime, ScrollArea, SectionHeading, SettingsLayout, Sheet, Sidebar, SidebarNav, SliderRange, StackedList, StatsCard, StatusDot, Stepper, TIME_ZOOMS, Table, TableToolbar, Tabs, TabsContent, TabsList, TabsTrigger, Tag, TagInput, TimeBar, TimePicker, TimeRow, TimeScaleHeader, TimeViewport, Timeline, TimezoneSelect, Toast, ToastProvider, Tour, TransferList, TreeView, browserTimeZone, canonicalTimeZone, countEdited, dateOfDay, dayOf, deleteOccurrence, describeRecurrence, endDayOf, fitLabel, fitLabels, formatDateRange, nthOf, occurrenceOn, occurrences, parseRRule, readFlowProgress, readRecurrence, recurrencePresets, sameRecurrence, saveOccurrence, timeExtent, timeZoneOffset, toRRule, useBrowserTimeZone, useContentWidth, useDestructiveAction, useFittedLabels, useFlowSteps, useRelativeTimeFormat, useSidebar, useTextMeasure, useTimeScale, useTimeViewport, useTimeViewportLayout, useToast, useToastOptional };
|
|
17899
18416
|
//# sourceMappingURL=index.js.map
|
|
17900
18417
|
//# sourceMappingURL=index.js.map
|