@godxjp/ui 20.0.0 → 20.2.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +8 -2
- package/dist/app/app-provider.js +37 -21
- package/dist/app/index.d.ts +2 -0
- package/dist/app/index.js +2 -0
- package/dist/app/storage.d.ts +17 -0
- package/dist/app/storage.js +28 -0
- package/dist/app/theme-axes.d.ts +2 -0
- package/dist/app/theme-axes.js +45 -0
- package/dist/components/charts/chart-cartesian.d.ts +2 -1
- package/dist/components/charts/chart-cartesian.js +52 -3
- package/dist/components/charts/chart-category-axis.d.ts +55 -0
- package/dist/components/charts/chart-category-axis.js +93 -0
- package/dist/components/charts/chart-frame.d.ts +10 -1
- package/dist/components/charts/chart-frame.js +19 -3
- package/dist/components/charts/compact-bar-trend.d.ts +1 -1
- package/dist/components/charts/compact-bar-trend.js +2 -0
- package/dist/components/charts/pie-chart.d.ts +1 -1
- package/dist/components/charts/pie-chart.js +12 -1
- package/dist/components/charts/recharts-peer.d.ts +49 -0
- package/dist/components/charts/recharts-peer.js +45 -0
- package/dist/components/data-display/card.d.ts +12 -1
- package/dist/components/data-display/card.js +22 -4
- package/dist/components/data-display/code-block.js +6 -2
- package/dist/components/data-display/data-table.d.ts +39 -4
- package/dist/components/data-display/data-table.js +802 -270
- package/dist/components/data-display/descriptions.d.ts +27 -6
- package/dist/components/data-display/descriptions.js +58 -17
- package/dist/components/data-display/index.d.ts +2 -0
- package/dist/components/data-display/index.js +2 -0
- package/dist/components/data-display/list-row.d.ts +10 -1
- package/dist/components/data-display/list-row.js +7 -1
- package/dist/components/data-display/popover.d.ts +9 -3
- package/dist/components/data-display/popover.js +65 -11
- package/dist/components/data-display/range-timeline.d.ts +38 -0
- package/dist/components/data-display/range-timeline.js +161 -0
- package/dist/components/data-display/scroll-area.js +13 -2
- package/dist/components/data-display/service-launcher-card.js +14 -12
- package/dist/components/data-display/table.d.ts +71 -3
- package/dist/components/data-display/table.js +56 -18
- package/dist/components/data-display/tree-list.js +4 -9
- package/dist/components/data-entry/calendar.d.ts +2 -2
- package/dist/components/data-entry/calendar.js +23 -3
- package/dist/components/data-entry/cascader.d.ts +1 -1
- package/dist/components/data-entry/cascader.js +188 -24
- package/dist/components/data-entry/color-picker.d.ts +1 -1
- package/dist/components/data-entry/color-picker.js +17 -5
- package/dist/components/data-entry/control-appearance.d.ts +64 -0
- package/dist/components/data-entry/control-appearance.js +39 -0
- package/dist/components/data-entry/control-surface.d.ts +61 -0
- package/dist/components/data-entry/control-surface.js +39 -0
- package/dist/components/data-entry/date-picker.d.ts +1 -1
- package/dist/components/data-entry/date-picker.js +344 -113
- package/dist/components/data-entry/date-range-picker.d.ts +1 -1
- package/dist/components/data-entry/date-range-picker.js +278 -140
- package/dist/components/data-entry/form-field.d.ts +1 -1
- package/dist/components/data-entry/form-field.js +39 -4
- package/dist/components/data-entry/form.d.ts +4 -0
- package/dist/components/data-entry/form.js +4 -2
- package/dist/components/data-entry/index.d.ts +7 -3
- package/dist/components/data-entry/index.js +10 -1
- package/dist/components/data-entry/input-otp.d.ts +1 -1
- package/dist/components/data-entry/input.d.ts +12 -34
- package/dist/components/data-entry/input.js +92 -24
- package/dist/components/data-entry/month-picker.d.ts +1 -1
- package/dist/components/data-entry/month-picker.js +47 -10
- package/dist/components/data-entry/month-range-picker.d.ts +1 -1
- package/dist/components/data-entry/month-range-picker.js +51 -11
- package/dist/components/data-entry/number-input.d.ts +7 -0
- package/dist/components/data-entry/number-input.js +147 -98
- package/dist/components/data-entry/password-input.d.ts +1 -1
- package/dist/components/data-entry/radio.d.ts +1 -1
- package/dist/components/data-entry/radio.js +61 -13
- package/dist/components/data-entry/search-input.d.ts +1 -1
- package/dist/components/data-entry/search-input.js +16 -2
- package/dist/components/data-entry/search-select.d.ts +2 -2
- package/dist/components/data-entry/search-select.js +209 -78
- package/dist/components/data-entry/select.d.ts +22 -4
- package/dist/components/data-entry/select.js +215 -163
- package/dist/components/data-entry/slider.d.ts +9 -1
- package/dist/components/data-entry/slider.js +87 -9
- package/dist/components/data-entry/switch.d.ts +3 -0
- package/dist/components/data-entry/switch.js +29 -3
- package/dist/components/data-entry/textarea.d.ts +14 -56
- package/dist/components/data-entry/textarea.js +80 -33
- package/dist/components/data-entry/time-picker.d.ts +2 -2
- package/dist/components/data-entry/time-picker.js +333 -109
- package/dist/components/data-entry/time-range-picker.d.ts +5 -0
- package/dist/components/data-entry/time-range-picker.js +89 -0
- package/dist/components/data-entry/transfer.d.ts +1 -1
- package/dist/components/data-entry/transfer.js +86 -28
- package/dist/components/data-entry/tree-select.d.ts +1 -1
- package/dist/components/data-entry/tree-select.js +201 -113
- package/dist/components/data-entry/tree-utils.js +7 -14
- package/dist/components/data-entry/upload-files.d.ts +2 -0
- package/dist/components/data-entry/upload-files.js +31 -0
- package/dist/components/data-entry/upload-request.d.ts +4 -0
- package/dist/components/data-entry/upload-request.js +53 -0
- package/dist/components/data-entry/upload-types.d.ts +28 -0
- package/dist/components/data-entry/upload-types.js +2 -0
- package/dist/components/data-entry/upload.d.ts +2 -2
- package/dist/components/data-entry/upload.js +475 -115
- package/dist/components/feedback/dialog.js +19 -19
- package/dist/components/feedback/sheet.js +3 -0
- package/dist/components/feedback/tooltip.js +3 -0
- package/dist/components/general/button.d.ts +2 -1
- package/dist/components/general/button.js +7 -1
- package/dist/components/general/index.d.ts +1 -0
- package/dist/components/general/index.js +2 -0
- package/dist/components/general/typography.d.ts +3 -0
- package/dist/components/general/typography.js +15 -1
- package/dist/components/general/visually-hidden.d.ts +3 -0
- package/dist/components/general/visually-hidden.js +9 -0
- package/dist/components/layout/app-launcher.d.ts +34 -0
- package/dist/components/layout/app-launcher.js +261 -0
- package/dist/components/layout/app-shell.d.ts +3 -1
- package/dist/components/layout/app-shell.js +34 -14
- package/dist/components/layout/auth-shell.d.ts +1 -1
- package/dist/components/layout/auth-shell.js +2 -0
- package/dist/components/layout/breadcrumb.d.ts +14 -2
- package/dist/components/layout/breadcrumb.js +46 -4
- package/dist/components/layout/flex.d.ts +1 -1
- package/dist/components/layout/flex.js +23 -2
- package/dist/components/layout/index.d.ts +3 -0
- package/dist/components/layout/index.js +5 -1
- package/dist/components/layout/org-switcher.js +20 -1
- package/dist/components/layout/page-container.d.ts +1 -1
- package/dist/components/layout/page-container.js +5 -3
- package/dist/components/layout/responsive-grid.d.ts +16 -2
- package/dist/components/layout/responsive-grid.js +29 -2
- package/dist/components/layout/sidebar.js +2 -1
- package/dist/components/layout/topbar-item.d.ts +3 -0
- package/dist/components/layout/topbar-item.js +18 -3
- package/dist/components/layout/topbar.d.ts +1 -1
- package/dist/components/layout/topbar.js +27 -6
- package/dist/components/navigation/dropdown-menu.d.ts +30 -2
- package/dist/components/navigation/dropdown-menu.js +73 -11
- package/dist/components/navigation/pagination.d.ts +2 -2
- package/dist/components/navigation/pagination.js +155 -83
- package/dist/components/navigation/steps.d.ts +2 -2
- package/dist/components/navigation/steps.js +29 -4
- package/dist/components/navigation/tabs.d.ts +5 -33
- package/dist/components/navigation/tabs.js +232 -64
- package/dist/components/ui/hover-card.js +3 -0
- package/dist/components/ui/input-otp.d.ts +26 -28
- package/dist/components/ui/input-otp.js +50 -7
- package/dist/components/ui/password-input.d.ts +36 -2
- package/dist/components/ui/password-input.js +27 -7
- package/dist/components/ui/rating.d.ts +25 -0
- package/dist/components/ui/rating.js +67 -27
- package/dist/components/ui/segmented.d.ts +9 -0
- package/dist/components/ui/segmented.js +17 -2
- package/dist/components/ui/separator.d.ts +4 -0
- package/dist/components/ui/separator.js +13 -0
- package/dist/components/ui/tag-input.d.ts +45 -0
- package/dist/components/ui/tag-input.js +109 -27
- package/dist/form/form-context.d.ts +29 -0
- package/dist/form/form-context.js +44 -4
- package/dist/form/form-field-array.d.ts +22 -0
- package/dist/form/form-field-array.js +50 -0
- package/dist/form/form-field-control.d.ts +2 -1
- package/dist/form/form-field-control.js +116 -40
- package/dist/form/form-root.d.ts +2 -1
- package/dist/form/form-root.js +142 -23
- package/dist/form/index.d.ts +3 -1
- package/dist/form/index.js +12 -1
- package/dist/i18n/index.d.ts +1 -1
- package/dist/i18n/index.js +3 -1
- package/dist/i18n/messages/en.json +59 -6
- package/dist/i18n/messages/ja.json +59 -6
- package/dist/i18n/messages/vi.json +59 -6
- package/dist/i18n/translate.d.ts +19 -0
- package/dist/i18n/translate.js +24 -0
- package/dist/inertia/index.d.ts +20 -0
- package/dist/inertia/index.js +60 -1
- package/dist/lib/control-styles.d.ts +25 -3
- package/dist/lib/control-styles.js +9 -3
- package/dist/lib/datetime/picker-format.d.ts +8 -0
- package/dist/lib/datetime/picker-format.js +54 -0
- package/dist/lib/overlay-portal.d.ts +18 -0
- package/dist/lib/overlay-portal.js +17 -0
- package/dist/props/components/app.prop.d.ts +13 -2
- package/dist/props/components/charts.prop.d.ts +21 -0
- package/dist/props/components/data-display.prop.d.ts +55 -4
- package/dist/props/components/data-entry.prop.d.ts +687 -43
- package/dist/props/components/form.prop.d.ts +142 -4
- package/dist/props/components/general.prop.d.ts +30 -1
- package/dist/props/components/index.d.ts +2 -2
- package/dist/props/components/layout.prop.d.ts +255 -8
- package/dist/props/components/navigation.prop.d.ts +113 -3
- package/dist/props/registry.d.ts +376 -10
- package/dist/props/registry.js +493 -9
- package/dist/props/vocabulary/data.prop.d.ts +179 -1
- package/dist/props/vocabulary/index.d.ts +4 -4
- package/dist/props/vocabulary/interaction.prop.d.ts +51 -2
- package/dist/props/vocabulary/navigation.prop.d.ts +40 -0
- package/dist/props/vocabulary/shared.prop.d.ts +33 -0
- package/dist/styles/badge-layout.css +2 -1
- package/dist/styles/card-layout.css +36 -5
- package/dist/styles/chart-layout.css +17 -1
- package/dist/styles/control.css +520 -14
- package/dist/styles/data-display-layout.css +248 -7
- package/dist/styles/data-entry-layout.css +13 -0
- package/dist/styles/layout.css +221 -4
- package/dist/styles/navigation-layout.css +230 -1
- package/dist/styles/shell-layout.css +690 -21
- package/dist/styles/table-layout.css +95 -6
- package/dist/styles/text-layout.css +5 -0
- package/dist/tokens/base.css +1 -0
- package/dist/tokens/components/badge.css +1 -0
- package/dist/tokens/components/chart.css +6 -0
- package/dist/tokens/components/control.css +81 -3
- package/dist/tokens/components/data-display.css +9 -0
- package/dist/tokens/components/descriptions.css +11 -0
- package/dist/tokens/components/flex.css +8 -0
- package/dist/tokens/components/navigation.css +55 -0
- package/dist/tokens/components/shell.css +100 -5
- package/dist/tokens/components/table.css +14 -0
- package/dist/tokens/foundation.css +2 -0
- package/dist/tokens/semantic/layout.css +9 -0
- package/docs/CONSUMER-RULES.md +13 -0
- package/docs/DESIGN-AUTHORITY.md +43 -6
- package/docs/DEVELOPMENT.md +4 -3
- package/docs/FORMS.md +151 -6
- package/docs/FRAME-COVERAGE-REPORT.md +29 -16
- package/docs/README.md +1 -1
- package/docs/STANDARDS-vocabulary-tokens.md +1 -1
- package/docs/TESTING.md +15 -6
- package/docs/charts/cjk-category-axis.tsx +81 -0
- package/docs/data-display/card/index.tsx +22 -0
- package/docs/data-display/data-table/examples/antd-parity.tsx +257 -0
- package/docs/data-display/data-table/index.tsx +23 -0
- package/docs/data-display/descriptions.tsx +41 -0
- package/docs/data-display/list-row.tsx +6 -6
- package/docs/data-display/scroll-area.tsx +31 -25
- package/docs/data-display/table.tsx +104 -45
- package/docs/data-display/timeline.tsx +41 -0
- package/docs/data-entry/date-picker.tsx +85 -0
- package/docs/data-entry/date-range-picker.tsx +26 -0
- package/docs/data-entry/form-dynamic-fields.tsx +199 -0
- package/docs/data-entry/form.tsx +74 -4
- package/docs/data-entry/input-otp.tsx +24 -0
- package/docs/data-entry/input.tsx +46 -1
- package/docs/data-entry/month-range-picker.tsx +1 -1
- package/docs/data-entry/select.tsx +27 -0
- package/docs/data-entry/switch.tsx +41 -0
- package/docs/data-entry/textarea.tsx +38 -0
- package/docs/data-entry/time-picker.tsx +85 -1
- package/docs/data-entry/time-range-picker.tsx +55 -0
- package/docs/data-entry/transfer.tsx +17 -0
- package/docs/data-entry/upload.tsx +56 -12
- package/docs/feedback/tooltip.tsx +1 -1
- package/docs/general/activity.tsx +2 -2
- package/docs/general/button/index.tsx +14 -1
- package/docs/general/typography.tsx +14 -1
- package/docs/layout/app-launcher.tsx +195 -0
- package/docs/layout/app-shell-arrangements.tsx +5 -5
- package/docs/layout/app-shell.tsx +11 -0
- package/docs/layout/flex.tsx +50 -0
- package/docs/layout/responsive-grid.tsx +21 -1
- package/docs/layout/topbar.tsx +5 -9
- package/docs/navigation/app-setting-picker.tsx +11 -0
- package/docs/navigation/breadcrumb.tsx +48 -0
- package/docs/navigation/dropdown-menu.tsx +21 -0
- package/docs/navigation/pagination.tsx +52 -0
- package/docs/navigation/steps.tsx +37 -0
- package/docs/navigation/tabs.tsx +97 -1
- package/docs/query/button-refetch.tsx +1 -0
- package/docs/showcase/settings-security-mfa.tsx +3 -3
- package/package.json +24 -4
- package/scripts/_agent-setup.mjs +76 -9
- package/scripts/init-guinea-pig.mjs +26 -4
- package/scripts/ui-audit.mjs +243 -30
- package/scripts/visual-audit.mjs +45 -7
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
"use client";
|
|
2
|
-
import { jsx, jsxs } from "react/jsx-runtime";
|
|
2
|
+
import { Fragment, jsx, jsxs } from "react/jsx-runtime";
|
|
3
3
|
import * as React from "react";
|
|
4
4
|
import {
|
|
5
5
|
columnFilteringFeature,
|
|
@@ -20,11 +20,13 @@ import {
|
|
|
20
20
|
AlertCircle,
|
|
21
21
|
ArrowDown,
|
|
22
22
|
ArrowUp,
|
|
23
|
+
ChevronDown,
|
|
23
24
|
ChevronLeft,
|
|
24
25
|
ChevronRight,
|
|
25
26
|
ChevronsUpDown,
|
|
26
27
|
Layers,
|
|
27
28
|
Layers2,
|
|
29
|
+
ListFilter,
|
|
28
30
|
MoreHorizontal,
|
|
29
31
|
RefreshCw,
|
|
30
32
|
ShieldAlert,
|
|
@@ -47,10 +49,15 @@ import {
|
|
|
47
49
|
DropdownMenu,
|
|
48
50
|
DropdownMenuCheckboxItem,
|
|
49
51
|
DropdownMenuContent,
|
|
52
|
+
DropdownMenuItem,
|
|
50
53
|
DropdownMenuLabel,
|
|
54
|
+
DropdownMenuRadioGroup,
|
|
55
|
+
DropdownMenuRadioItem,
|
|
51
56
|
DropdownMenuSeparator,
|
|
52
57
|
DropdownMenuTrigger
|
|
53
58
|
} from "../navigation/dropdown-menu.js";
|
|
59
|
+
import { RadioGroupRoot, RadioItem } from "../data-entry/radio.js";
|
|
60
|
+
import { Tooltip, TooltipContent, TooltipTrigger } from "../feedback/tooltip.js";
|
|
54
61
|
import {
|
|
55
62
|
Table,
|
|
56
63
|
TableBody,
|
|
@@ -81,16 +88,81 @@ function dataTableFeatures() {
|
|
|
81
88
|
columnMeta: {}
|
|
82
89
|
});
|
|
83
90
|
}
|
|
91
|
+
const DEFAULT_SORT_DIRECTIONS = ["asc", "desc"];
|
|
92
|
+
function columnIsSortable(col) {
|
|
93
|
+
if (col.sortable) return true;
|
|
94
|
+
if (col.sorter === true || typeof col.sorter === "function") return true;
|
|
95
|
+
return typeof col.sorter === "object" && col.sorter !== null;
|
|
96
|
+
}
|
|
97
|
+
function columnCompare(col) {
|
|
98
|
+
if (typeof col.sorter === "function") return col.sorter;
|
|
99
|
+
if (col.sorter && typeof col.sorter === "object") return col.sorter.compare;
|
|
100
|
+
return void 0;
|
|
101
|
+
}
|
|
102
|
+
function columnSortPriority(col) {
|
|
103
|
+
return col.sorter && typeof col.sorter === "object" ? col.sorter.multiple : void 0;
|
|
104
|
+
}
|
|
105
|
+
function columnSortDirections(col, tableDirections) {
|
|
106
|
+
const declared = col.sortDirections ?? tableDirections ?? DEFAULT_SORT_DIRECTIONS;
|
|
107
|
+
return declared.length > 0 ? declared : DEFAULT_SORT_DIRECTIONS;
|
|
108
|
+
}
|
|
109
|
+
function nextSortDirection(current, directions) {
|
|
110
|
+
if (!current) return directions[0];
|
|
111
|
+
const at = directions.indexOf(current);
|
|
112
|
+
if (at === -1) return directions[0];
|
|
113
|
+
return directions[at + 1];
|
|
114
|
+
}
|
|
115
|
+
function applySortToState(state, key, direction, priority, priorities) {
|
|
116
|
+
if (priority === void 0) {
|
|
117
|
+
return direction ? [{ id: key, desc: direction === "desc" }] : [];
|
|
118
|
+
}
|
|
119
|
+
const kept = state.filter((entry) => entry.id !== key && priorities[entry.id] !== void 0);
|
|
120
|
+
const next = direction ? [...kept, { id: key, desc: direction === "desc" }] : kept;
|
|
121
|
+
return next.sort((a, b) => (priorities[b.id] ?? 0) - (priorities[a.id] ?? 0));
|
|
122
|
+
}
|
|
123
|
+
function directionOf(state, key) {
|
|
124
|
+
const entry = state.find((s) => s.id === key);
|
|
125
|
+
return entry ? entry.desc ? "desc" : "asc" : void 0;
|
|
126
|
+
}
|
|
127
|
+
function columnFilterPredicate(col, row, values) {
|
|
128
|
+
if (values.length === 0) return true;
|
|
129
|
+
const onFilter = col.onFilter;
|
|
130
|
+
if (onFilter) return values.some((value) => onFilter(value, row));
|
|
131
|
+
const raw = row[col.key];
|
|
132
|
+
return values.some((value) => value === raw || String(value) === String(raw));
|
|
133
|
+
}
|
|
134
|
+
function useStableValue(value) {
|
|
135
|
+
const key = JSON.stringify(value);
|
|
136
|
+
const ref = React.useRef({ key, value });
|
|
137
|
+
if (ref.current.key !== key) ref.current = { key, value };
|
|
138
|
+
return ref.current.value;
|
|
139
|
+
}
|
|
140
|
+
function cssLength(value) {
|
|
141
|
+
if (value === void 0) return void 0;
|
|
142
|
+
return typeof value === "number" ? `${value}px` : value;
|
|
143
|
+
}
|
|
84
144
|
function toTanstackColumns(columns) {
|
|
85
|
-
return columns.map((col) =>
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
145
|
+
return columns.map((col) => {
|
|
146
|
+
const compare = columnCompare(col);
|
|
147
|
+
return {
|
|
148
|
+
id: col.key,
|
|
149
|
+
accessorFn: (row) => row[col.key],
|
|
150
|
+
header: () => col.header,
|
|
151
|
+
enableSorting: columnIsSortable(col),
|
|
152
|
+
enableHiding: col.enableHiding ?? true,
|
|
153
|
+
enableGlobalFilter: true,
|
|
154
|
+
enableColumnFilter: !!col.filters,
|
|
155
|
+
...compare ? {
|
|
156
|
+
sortFn: (rowA, rowB) => compare(rowA.original, rowB.original)
|
|
157
|
+
} : {},
|
|
158
|
+
filterFn: (row, _id, filterValue) => columnFilterPredicate(
|
|
159
|
+
col,
|
|
160
|
+
row.original,
|
|
161
|
+
Array.isArray(filterValue) ? filterValue : []
|
|
162
|
+
),
|
|
163
|
+
meta: { lean: col }
|
|
164
|
+
};
|
|
165
|
+
});
|
|
94
166
|
}
|
|
95
167
|
const DataTableContext = React.createContext(null);
|
|
96
168
|
function useDataTableContext() {
|
|
@@ -128,7 +200,7 @@ function DataTable({
|
|
|
128
200
|
onSortChange,
|
|
129
201
|
globalFilter: controlledGlobalFilter,
|
|
130
202
|
onGlobalFilterChange,
|
|
131
|
-
pagination:
|
|
203
|
+
pagination: paginationProp,
|
|
132
204
|
onPaginationChange,
|
|
133
205
|
rowCount,
|
|
134
206
|
columnVisibility: controlledVisibility,
|
|
@@ -147,6 +219,16 @@ function DataTable({
|
|
|
147
219
|
preset = "default",
|
|
148
220
|
collapseBelow = "sm",
|
|
149
221
|
rowClassName,
|
|
222
|
+
rowSelection,
|
|
223
|
+
expandable,
|
|
224
|
+
summary,
|
|
225
|
+
scroll,
|
|
226
|
+
sticky,
|
|
227
|
+
onRow,
|
|
228
|
+
bordered = false,
|
|
229
|
+
showSorterTooltip = false,
|
|
230
|
+
sortDirections,
|
|
231
|
+
onFilterChange,
|
|
150
232
|
className,
|
|
151
233
|
children
|
|
152
234
|
}) {
|
|
@@ -156,23 +238,90 @@ function DataTable({
|
|
|
156
238
|
setInternalDensity(d);
|
|
157
239
|
onDensityChange?.(d);
|
|
158
240
|
};
|
|
159
|
-
const
|
|
160
|
-
const
|
|
241
|
+
const pagerHidden = paginationProp === false;
|
|
242
|
+
const paginationConfig = paginationProp && typeof paginationProp === "object" && !("pageIndex" in paginationProp) ? paginationProp : void 0;
|
|
243
|
+
const controlledPagination = paginationProp && typeof paginationProp === "object" && "pageIndex" in paginationProp ? paginationProp : void 0;
|
|
244
|
+
const [internalSorting, setInternalSorting] = React.useState(
|
|
245
|
+
() => columns.filter((col) => col.defaultSortOrder).map((col) => ({ id: col.key, desc: col.defaultSortOrder === "desc" }))
|
|
246
|
+
);
|
|
247
|
+
const [internalFilters, setInternalFilters] = React.useState(
|
|
248
|
+
() => columns.filter((col) => (col.defaultFilteredValue?.length ?? 0) > 0).map((col) => ({ id: col.key, value: col.defaultFilteredValue }))
|
|
249
|
+
);
|
|
161
250
|
const [internalGlobal, setInternalGlobal] = React.useState("");
|
|
162
251
|
const [internalPagination, setInternalPagination] = React.useState({
|
|
163
252
|
pageIndex: 0,
|
|
164
|
-
pageSize: 10
|
|
253
|
+
pageSize: paginationConfig?.pageSize ?? 10
|
|
165
254
|
});
|
|
166
|
-
const [internalSelection, setInternalSelection] = React.useState(
|
|
255
|
+
const [internalSelection, setInternalSelection] = React.useState(
|
|
256
|
+
() => Object.fromEntries(
|
|
257
|
+
(rowSelection?.defaultSelectedRowKeys ?? []).map((key) => [key, true])
|
|
258
|
+
)
|
|
259
|
+
);
|
|
167
260
|
const [internalVisibility, setInternalVisibility] = React.useState({});
|
|
261
|
+
const [internalExpanded, setInternalExpanded] = React.useState(
|
|
262
|
+
() => expandable?.defaultExpandAllRows ? data.map(getRowId) : []
|
|
263
|
+
);
|
|
264
|
+
const pageIndex = controlledPagination?.pageIndex ?? (paginationConfig?.current !== void 0 ? Math.max(0, paginationConfig.current - 1) : internalPagination.pageIndex);
|
|
265
|
+
const pageSize = controlledPagination?.pageSize ?? paginationConfig?.pageSize ?? internalPagination.pageSize;
|
|
266
|
+
const resolvedPagination = React.useMemo(
|
|
267
|
+
() => ({ pageIndex, pageSize }),
|
|
268
|
+
[pageIndex, pageSize]
|
|
269
|
+
);
|
|
270
|
+
const handlePaginationChange = (updater) => {
|
|
271
|
+
const next = typeof updater === "function" ? updater(resolvedPagination) : updater;
|
|
272
|
+
setInternalPagination(next);
|
|
273
|
+
onPaginationChange?.(next);
|
|
274
|
+
paginationConfig?.onChange?.(next.pageIndex + 1, next.pageSize);
|
|
275
|
+
};
|
|
168
276
|
const selectionFromSet = React.useCallback(
|
|
169
277
|
(set) => Object.fromEntries([...set].map((id) => [id, true])),
|
|
170
278
|
[]
|
|
171
279
|
);
|
|
172
|
-
const
|
|
173
|
-
|
|
280
|
+
const sortPriorities = React.useMemo(() => {
|
|
281
|
+
const map = {};
|
|
282
|
+
for (const col of columns) {
|
|
283
|
+
const priority = columnSortPriority(col);
|
|
284
|
+
if (priority !== void 0) map[col.key] = priority;
|
|
285
|
+
}
|
|
286
|
+
return map;
|
|
287
|
+
}, [columns]);
|
|
288
|
+
const columnSortOrders = columns.filter((col) => col.sortOrder !== void 0);
|
|
289
|
+
const sortingState = useStableValue(
|
|
290
|
+
columnSortOrders.length > 0 ? columnSortOrders.filter((col) => col.sortOrder).map((col) => ({ id: col.key, desc: col.sortOrder === "desc" })).sort((a, b) => (sortPriorities[b.id] ?? 0) - (sortPriorities[a.id] ?? 0)) : sort !== void 0 ? sortToSortingState(sort) : internalSorting
|
|
291
|
+
);
|
|
292
|
+
const controlledFilterKeys = new Set(
|
|
293
|
+
columns.filter((col) => col.filteredValue !== void 0).map((col) => col.key)
|
|
294
|
+
);
|
|
295
|
+
const columnFilters = useStableValue([
|
|
296
|
+
...internalFilters.filter((entry) => !controlledFilterKeys.has(entry.id)),
|
|
297
|
+
...columns.filter((col) => (col.filteredValue?.length ?? 0) > 0).map((col) => ({ id: col.key, value: col.filteredValue }))
|
|
298
|
+
]);
|
|
299
|
+
const filterValues = Object.fromEntries(
|
|
300
|
+
columnFilters.map((entry) => [entry.id, entry.value ?? []])
|
|
301
|
+
);
|
|
302
|
+
const setFilterValue = (key, next) => {
|
|
303
|
+
if (!controlledFilterKeys.has(key)) {
|
|
304
|
+
setInternalFilters((prev) => {
|
|
305
|
+
const rest = prev.filter((entry) => entry.id !== key);
|
|
306
|
+
return next.length > 0 ? [...rest, { id: key, value: next }] : rest;
|
|
307
|
+
});
|
|
308
|
+
}
|
|
309
|
+
const merged = { ...filterValues };
|
|
310
|
+
if (next.length > 0) {
|
|
311
|
+
merged[key] = next;
|
|
312
|
+
} else {
|
|
313
|
+
delete merged[key];
|
|
314
|
+
}
|
|
315
|
+
onFilterChange?.(merged);
|
|
316
|
+
};
|
|
317
|
+
const rowSelectionKeys = rowSelection?.selectedRowKeys;
|
|
318
|
+
const rowSelectionState = rowSelectionKeys !== void 0 ? Object.fromEntries(rowSelectionKeys.map((key) => [key, true])) : controlledSelected !== void 0 ? selectionFromSet(controlledSelected) : internalSelection;
|
|
174
319
|
const onSortingChange = (updater) => {
|
|
175
320
|
const next = typeof updater === "function" ? updater(sortingState) : updater;
|
|
321
|
+
if (columnSortOrders.length > 0) {
|
|
322
|
+
onSortChange?.(sortingStateToSort(next));
|
|
323
|
+
return;
|
|
324
|
+
}
|
|
176
325
|
if (sort !== void 0 || onSortChange) {
|
|
177
326
|
onSortChange?.(sortingStateToSort(next));
|
|
178
327
|
} else {
|
|
@@ -180,14 +329,38 @@ function DataTable({
|
|
|
180
329
|
}
|
|
181
330
|
};
|
|
182
331
|
const onRowSelectionChange = (updater) => {
|
|
183
|
-
|
|
184
|
-
if (
|
|
185
|
-
const
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
}
|
|
332
|
+
let next = typeof updater === "function" ? updater(rowSelectionState) : updater;
|
|
333
|
+
if (rowSelection?.type === "radio") {
|
|
334
|
+
const added = Object.keys(next).filter((key) => next[key] && !rowSelectionState[key]);
|
|
335
|
+
const only = added[added.length - 1];
|
|
336
|
+
next = only ? { [only]: true } : {};
|
|
337
|
+
}
|
|
338
|
+
if (rowSelection) {
|
|
339
|
+
const onPage = new Set(data.map(getRowId));
|
|
340
|
+
if (rowSelection.preserveSelectedRowKeys) {
|
|
341
|
+
const offPage = Object.keys(rowSelectionState).filter(
|
|
342
|
+
(key) => rowSelectionState[key] && !onPage.has(key)
|
|
343
|
+
);
|
|
344
|
+
next = {
|
|
345
|
+
...next,
|
|
346
|
+
...Object.fromEntries(offPage.map((key) => [key, true]))
|
|
347
|
+
};
|
|
348
|
+
} else {
|
|
349
|
+
next = Object.fromEntries(
|
|
350
|
+
Object.entries(next).filter(([key, on]) => on && onPage.has(key))
|
|
351
|
+
);
|
|
352
|
+
}
|
|
353
|
+
}
|
|
354
|
+
const keys = Object.keys(next).filter((key) => next[key]);
|
|
355
|
+
if (rowSelectionKeys === void 0 && controlledSelected === void 0) {
|
|
189
356
|
setInternalSelection(next);
|
|
190
357
|
}
|
|
358
|
+
onSelectChange?.(new Set(keys));
|
|
359
|
+
const byId = new Map(data.map((row) => [getRowId(row), row]));
|
|
360
|
+
rowSelection?.onChange?.(
|
|
361
|
+
keys,
|
|
362
|
+
keys.map((key) => byId.get(key)).filter((row) => row !== void 0)
|
|
363
|
+
);
|
|
191
364
|
};
|
|
192
365
|
const onGlobalFilterChangeFn = (updater) => {
|
|
193
366
|
const current = controlledGlobalFilter ?? internalGlobal;
|
|
@@ -203,8 +376,9 @@ function DataTable({
|
|
|
203
376
|
const hasNumberedPager = React.Children.toArray(children).some(
|
|
204
377
|
(c) => React.isValidElement(c) && c.type.displayName === "DataTable.Pagination" && typeof c.props.onChange !== "function"
|
|
205
378
|
);
|
|
206
|
-
const paginationEngaged = manualPagination || controlledPagination !== void 0 || onPaginationChange !== void 0 || hasNumberedPager;
|
|
379
|
+
const paginationEngaged = !pagerHidden && (manualPagination || controlledPagination !== void 0 || paginationConfig !== void 0 || onPaginationChange !== void 0 || hasNumberedPager);
|
|
207
380
|
const features = React.useMemo(() => dataTableFeatures(), []);
|
|
381
|
+
const selectionEnabled = selectable || rowSelection !== void 0;
|
|
208
382
|
const table = useTable({
|
|
209
383
|
features,
|
|
210
384
|
data,
|
|
@@ -215,27 +389,33 @@ function DataTable({
|
|
|
215
389
|
// "no pager on this table" is expressed the same way as "the server paginates" — leave the
|
|
216
390
|
// rows unsliced. Page count still derives from `rowCount`/the pre-paginated model either way.
|
|
217
391
|
manualPagination: manualPagination || !paginationEngaged,
|
|
218
|
-
rowCount,
|
|
219
|
-
enableRowSelection:
|
|
392
|
+
rowCount: paginationConfig?.total ?? rowCount,
|
|
393
|
+
enableRowSelection: selectionEnabled,
|
|
220
394
|
state: {
|
|
221
395
|
sorting: sortingState,
|
|
222
|
-
columnFilters
|
|
396
|
+
columnFilters,
|
|
223
397
|
globalFilter: controlledGlobalFilter ?? internalGlobal,
|
|
224
|
-
pagination:
|
|
225
|
-
rowSelection,
|
|
398
|
+
pagination: resolvedPagination,
|
|
399
|
+
rowSelection: rowSelectionState,
|
|
226
400
|
columnVisibility: controlledVisibility ?? internalVisibility
|
|
227
401
|
},
|
|
228
402
|
onSortingChange,
|
|
229
403
|
onGlobalFilterChange: onGlobalFilterChangeFn,
|
|
230
|
-
onPaginationChange:
|
|
404
|
+
onPaginationChange: handlePaginationChange,
|
|
231
405
|
onRowSelectionChange,
|
|
232
406
|
onColumnVisibilityChange: onColumnVisibilityChange ?? setInternalVisibility
|
|
233
407
|
});
|
|
408
|
+
const expandedKeys = expandable?.expandedRowKeys ?? internalExpanded;
|
|
409
|
+
const toggleExpanded = (key) => {
|
|
410
|
+
const next = expandedKeys.includes(key) ? expandedKeys.filter((k) => k !== key) : [...expandedKeys, key];
|
|
411
|
+
if (expandable?.expandedRowKeys === void 0) setInternalExpanded(next);
|
|
412
|
+
expandable?.onExpandedRowsChange?.(next);
|
|
413
|
+
};
|
|
234
414
|
const ctx = {
|
|
235
415
|
table,
|
|
236
416
|
density,
|
|
237
417
|
setDensity,
|
|
238
|
-
selectable,
|
|
418
|
+
selectable: selectionEnabled,
|
|
239
419
|
sort,
|
|
240
420
|
onSortChange,
|
|
241
421
|
onRowClick,
|
|
@@ -246,10 +426,28 @@ function DataTable({
|
|
|
246
426
|
onRetry,
|
|
247
427
|
striped,
|
|
248
428
|
hoverable,
|
|
249
|
-
stickyHeader
|
|
429
|
+
// antd `sticky` supersedes `stickyHeader` whenever it is given (either form of it).
|
|
430
|
+
stickyHeader: sticky === void 0 ? stickyHeader : sticky !== false,
|
|
250
431
|
preset,
|
|
251
432
|
collapseBelow,
|
|
252
|
-
rowClassName
|
|
433
|
+
rowClassName,
|
|
434
|
+
bordered,
|
|
435
|
+
scroll,
|
|
436
|
+
sticky,
|
|
437
|
+
onRow,
|
|
438
|
+
summary,
|
|
439
|
+
expandable,
|
|
440
|
+
expandedKeys,
|
|
441
|
+
toggleExpanded,
|
|
442
|
+
rowSelection,
|
|
443
|
+
getRowId,
|
|
444
|
+
showSorterTooltip,
|
|
445
|
+
sortDirections,
|
|
446
|
+
sortPriorities,
|
|
447
|
+
filterValues,
|
|
448
|
+
setFilterValue,
|
|
449
|
+
paginationConfig,
|
|
450
|
+
pagerHidden
|
|
253
451
|
};
|
|
254
452
|
const hasContent = React.Children.toArray(children).some(
|
|
255
453
|
(c) => React.isValidElement(c) && c.type.displayName === "DataTable.Content"
|
|
@@ -342,12 +540,15 @@ function columnLabel(column) {
|
|
|
342
540
|
return column.id;
|
|
343
541
|
}
|
|
344
542
|
DataTable.SelectAll = function DataTableSelectAll() {
|
|
345
|
-
const { table, selectable } = useDataTableContext();
|
|
543
|
+
const { table, selectable, rowSelection, getRowId } = useDataTableContext();
|
|
346
544
|
const { t } = useTranslation();
|
|
347
545
|
if (!selectable) return null;
|
|
546
|
+
if (rowSelection?.type === "radio" || rowSelection?.hideSelectAll) {
|
|
547
|
+
return /* @__PURE__ */ jsx(Fragment, { children: rowSelection.columnTitle ?? /* @__PURE__ */ jsx("span", { className: "sr-only", children: t("dataTable.selectColumn") }) });
|
|
548
|
+
}
|
|
348
549
|
const allSelected = table.getIsAllPageRowsSelected();
|
|
349
550
|
const someSelected = table.getIsSomePageRowsSelected();
|
|
350
|
-
|
|
551
|
+
const box = /* @__PURE__ */ jsx(
|
|
351
552
|
Checkbox,
|
|
352
553
|
{
|
|
353
554
|
checked: allSelected ? true : someSelected ? "indeterminate" : false,
|
|
@@ -355,6 +556,54 @@ DataTable.SelectAll = function DataTableSelectAll() {
|
|
|
355
556
|
"aria-label": t("dataTable.selectAll")
|
|
356
557
|
}
|
|
357
558
|
);
|
|
559
|
+
if (rowSelection?.columnTitle !== void 0) return /* @__PURE__ */ jsx(Fragment, { children: rowSelection.columnTitle });
|
|
560
|
+
if (!rowSelection?.selections) return box;
|
|
561
|
+
const pageKeys = table.getRowModel().rows.map((row) => getRowId(row.original));
|
|
562
|
+
const selectedKeys = table.getSelectedRowModel().rows.map((row) => getRowId(row.original));
|
|
563
|
+
const builtIn = [
|
|
564
|
+
{
|
|
565
|
+
key: "all",
|
|
566
|
+
text: t("dataTable.selectAll"),
|
|
567
|
+
onSelect: () => table.toggleAllPageRowsSelected(true)
|
|
568
|
+
},
|
|
569
|
+
{
|
|
570
|
+
key: "invert",
|
|
571
|
+
text: t("dataTable.selectInvert"),
|
|
572
|
+
onSelect: () => {
|
|
573
|
+
table.setRowSelection(
|
|
574
|
+
Object.fromEntries(
|
|
575
|
+
table.getRowModel().rows.filter((row) => !row.getIsSelected()).map((row) => [getRowId(row.original), true])
|
|
576
|
+
)
|
|
577
|
+
);
|
|
578
|
+
}
|
|
579
|
+
},
|
|
580
|
+
{
|
|
581
|
+
key: "none",
|
|
582
|
+
text: t("dataTable.selectNone"),
|
|
583
|
+
onSelect: () => table.toggleAllPageRowsSelected(false)
|
|
584
|
+
}
|
|
585
|
+
];
|
|
586
|
+
const entries = rowSelection.selections === true ? builtIn : rowSelection.selections.map((entry) => ({
|
|
587
|
+
key: entry.key,
|
|
588
|
+
text: entry.text,
|
|
589
|
+
onSelect: () => entry.onSelect(pageKeys.length > 0 ? pageKeys : selectedKeys)
|
|
590
|
+
}));
|
|
591
|
+
return /* @__PURE__ */ jsxs("span", { className: "ui-data-table-selection-menu", children: [
|
|
592
|
+
box,
|
|
593
|
+
/* @__PURE__ */ jsxs(DropdownMenu, { children: [
|
|
594
|
+
/* @__PURE__ */ jsx(DropdownMenuTrigger, { asChild: true, children: /* @__PURE__ */ jsx(
|
|
595
|
+
Button,
|
|
596
|
+
{
|
|
597
|
+
variant: "ghost",
|
|
598
|
+
size: "icon-xs",
|
|
599
|
+
"aria-label": t("dataTable.selectionMenu"),
|
|
600
|
+
className: "ui-data-table-selection-trigger",
|
|
601
|
+
children: /* @__PURE__ */ jsx(ChevronDown, { className: "ui-data-table-sort-icon", "aria-hidden": "true" })
|
|
602
|
+
}
|
|
603
|
+
) }),
|
|
604
|
+
/* @__PURE__ */ jsx(DropdownMenuContent, { align: "start", children: entries.map((entry) => /* @__PURE__ */ jsx(DropdownMenuItem, { onSelect: entry.onSelect, children: entry.text }, entry.key)) })
|
|
605
|
+
] })
|
|
606
|
+
] });
|
|
358
607
|
};
|
|
359
608
|
DataTable.SelectAll.displayName = "DataTable.SelectAll";
|
|
360
609
|
DataTable.BulkActions = function DataTableBulkActions({
|
|
@@ -418,12 +667,78 @@ DataTable.DensityToggle = function DataTableDensityToggle() {
|
|
|
418
667
|
);
|
|
419
668
|
};
|
|
420
669
|
DataTable.DensityToggle.displayName = "DataTable.DensityToggle";
|
|
670
|
+
function fixedEdge(col) {
|
|
671
|
+
return col.fixed ?? (col.pin === "end" ? "end" : void 0);
|
|
672
|
+
}
|
|
673
|
+
function sameOffsets(a, b) {
|
|
674
|
+
const keys = Object.keys(a);
|
|
675
|
+
if (keys.length !== Object.keys(b).length) return false;
|
|
676
|
+
return keys.every((key) => a[key] === b[key]);
|
|
677
|
+
}
|
|
678
|
+
function ColumnFilterMenu({ column }) {
|
|
679
|
+
const { filterValues, setFilterValue } = useDataTableContext();
|
|
680
|
+
const { t } = useTranslation();
|
|
681
|
+
const options = column.filters ?? [];
|
|
682
|
+
const active = filterValues[column.key] ?? [];
|
|
683
|
+
const multiple = column.filterMultiple ?? true;
|
|
684
|
+
const apply = (next) => {
|
|
685
|
+
setFilterValue(column.key, next);
|
|
686
|
+
};
|
|
687
|
+
return /* @__PURE__ */ jsxs(DropdownMenu, { children: [
|
|
688
|
+
/* @__PURE__ */ jsx(DropdownMenuTrigger, { asChild: true, children: /* @__PURE__ */ jsx(
|
|
689
|
+
Button,
|
|
690
|
+
{
|
|
691
|
+
variant: "ghost",
|
|
692
|
+
size: "icon-xs",
|
|
693
|
+
"aria-label": t("dataTable.filterColumn"),
|
|
694
|
+
"data-filtered": active.length > 0 ? "" : void 0,
|
|
695
|
+
className: "ui-data-table-filter-trigger",
|
|
696
|
+
children: /* @__PURE__ */ jsx(ListFilter, { className: "ui-data-table-sort-icon", "aria-hidden": "true" })
|
|
697
|
+
}
|
|
698
|
+
) }),
|
|
699
|
+
/* @__PURE__ */ jsxs(DropdownMenuContent, { align: "start", children: [
|
|
700
|
+
/* @__PURE__ */ jsx(DropdownMenuLabel, { children: t("dataTable.filterColumn") }),
|
|
701
|
+
/* @__PURE__ */ jsx(DropdownMenuSeparator, {}),
|
|
702
|
+
multiple ? options.map((option) => /* @__PURE__ */ jsx(
|
|
703
|
+
DropdownMenuCheckboxItem,
|
|
704
|
+
{
|
|
705
|
+
checked: active.includes(option.value),
|
|
706
|
+
onCheckedChange: (checked) => {
|
|
707
|
+
apply(
|
|
708
|
+
checked ? [...active, option.value] : active.filter((value) => value !== option.value)
|
|
709
|
+
);
|
|
710
|
+
},
|
|
711
|
+
children: option.text
|
|
712
|
+
},
|
|
713
|
+
String(option.value)
|
|
714
|
+
)) : /* @__PURE__ */ jsx(
|
|
715
|
+
DropdownMenuRadioGroup,
|
|
716
|
+
{
|
|
717
|
+
value: active.length > 0 ? String(active[0]) : "",
|
|
718
|
+
onValueChange: (value) => {
|
|
719
|
+
const picked = options.find((option) => String(option.value) === value);
|
|
720
|
+
apply(picked ? [picked.value] : []);
|
|
721
|
+
},
|
|
722
|
+
children: options.map((option) => /* @__PURE__ */ jsx(DropdownMenuRadioItem, { value: String(option.value), children: option.text }, String(option.value)))
|
|
723
|
+
}
|
|
724
|
+
),
|
|
725
|
+
/* @__PURE__ */ jsx(DropdownMenuSeparator, {}),
|
|
726
|
+
/* @__PURE__ */ jsx(
|
|
727
|
+
DropdownMenuItem,
|
|
728
|
+
{
|
|
729
|
+
onSelect: () => {
|
|
730
|
+
apply([]);
|
|
731
|
+
},
|
|
732
|
+
children: t("dataTable.filterReset")
|
|
733
|
+
}
|
|
734
|
+
)
|
|
735
|
+
] })
|
|
736
|
+
] });
|
|
737
|
+
}
|
|
421
738
|
DataTable.Content = function DataTableContent() {
|
|
422
739
|
const {
|
|
423
740
|
table,
|
|
424
741
|
selectable,
|
|
425
|
-
sort,
|
|
426
|
-
onSortChange,
|
|
427
742
|
onRowClick,
|
|
428
743
|
loading,
|
|
429
744
|
empty,
|
|
@@ -435,7 +750,20 @@ DataTable.Content = function DataTableContent() {
|
|
|
435
750
|
stickyHeader,
|
|
436
751
|
preset,
|
|
437
752
|
collapseBelow,
|
|
438
|
-
rowClassName
|
|
753
|
+
rowClassName,
|
|
754
|
+
bordered,
|
|
755
|
+
scroll,
|
|
756
|
+
sticky,
|
|
757
|
+
onRow,
|
|
758
|
+
summary,
|
|
759
|
+
expandable,
|
|
760
|
+
expandedKeys,
|
|
761
|
+
toggleExpanded,
|
|
762
|
+
rowSelection,
|
|
763
|
+
getRowId,
|
|
764
|
+
showSorterTooltip,
|
|
765
|
+
sortDirections,
|
|
766
|
+
sortPriorities
|
|
439
767
|
} = useDataTableContext();
|
|
440
768
|
const { t } = useTranslation();
|
|
441
769
|
const presetAttr = preset === "default" ? void 0 : preset;
|
|
@@ -444,8 +772,13 @@ DataTable.Content = function DataTableContent() {
|
|
|
444
772
|
const rowPadding = tableRowHeightClass;
|
|
445
773
|
const cellPadding = tableCellPaddingClass;
|
|
446
774
|
const visibleColumns = table.getVisibleLeafColumns().map((c) => c.columnDef.meta?.lean).filter((c) => !!c);
|
|
447
|
-
const
|
|
448
|
-
const
|
|
775
|
+
const expandColumnShown = !!expandable?.expandedRowRender;
|
|
776
|
+
const leadingColumnCount = (expandColumnShown ? 1 : 0) + (selectable ? 1 : 0);
|
|
777
|
+
const emptyColSpan = visibleColumns.length + leadingColumnCount;
|
|
778
|
+
const hasPinEnd = visibleColumns.some((col) => fixedEdge(col) === "end");
|
|
779
|
+
const hasFixedStart = visibleColumns.some((col) => fixedEdge(col) === "start");
|
|
780
|
+
const leadingFixed = hasFixedStart ? "start" : void 0;
|
|
781
|
+
const fixedTableLayout = scroll?.x !== void 0 || visibleColumns.some((col) => col.ellipsis || columnWidth(col.width).style !== void 0);
|
|
449
782
|
const missingHeaderNames = visibleColumns.filter((col) => isEmptyHeader(col.header) && !col.ariaLabel).map((col) => col.key).join("|");
|
|
450
783
|
React.useEffect(() => {
|
|
451
784
|
if (process.env.NODE_ENV === "production" || !missingHeaderNames) return;
|
|
@@ -475,24 +808,82 @@ DataTable.Content = function DataTableContent() {
|
|
|
475
808
|
observer.disconnect();
|
|
476
809
|
};
|
|
477
810
|
}, []);
|
|
478
|
-
const
|
|
479
|
-
const
|
|
480
|
-
|
|
481
|
-
|
|
482
|
-
|
|
483
|
-
|
|
484
|
-
|
|
485
|
-
|
|
486
|
-
|
|
487
|
-
|
|
488
|
-
|
|
811
|
+
const [fixedOffsets, setFixedOffsets] = React.useState({});
|
|
812
|
+
const fixedSignature = [
|
|
813
|
+
leadingFixed ?? "",
|
|
814
|
+
expandColumnShown ? "x" : "",
|
|
815
|
+
selectable ? "s" : "",
|
|
816
|
+
...visibleColumns.map((col) => `${col.key}:${fixedEdge(col) ?? ""}`)
|
|
817
|
+
].join("|");
|
|
818
|
+
React.useEffect(() => {
|
|
819
|
+
const el = scrollRef.current;
|
|
820
|
+
if (!el) return;
|
|
821
|
+
const measure = () => {
|
|
822
|
+
const headerRow2 = el.querySelector("thead tr");
|
|
823
|
+
if (!headerRow2) return;
|
|
824
|
+
const cells = Array.from(headerRow2.children);
|
|
825
|
+
const next = {};
|
|
826
|
+
let start = 0;
|
|
827
|
+
for (const cell of cells) {
|
|
828
|
+
if (cell.dataset.fixed !== "start") continue;
|
|
829
|
+
next[cell.dataset.columnKey ?? ""] = start;
|
|
830
|
+
start += cell.offsetWidth;
|
|
489
831
|
}
|
|
490
|
-
|
|
491
|
-
|
|
492
|
-
|
|
832
|
+
let end = 0;
|
|
833
|
+
for (const cell of [...cells].reverse()) {
|
|
834
|
+
if (cell.dataset.fixed !== "end") continue;
|
|
835
|
+
next[cell.dataset.columnKey ?? ""] = end;
|
|
836
|
+
end += cell.offsetWidth;
|
|
837
|
+
}
|
|
838
|
+
setFixedOffsets((prev) => sameOffsets(prev, next) ? prev : next);
|
|
839
|
+
};
|
|
840
|
+
measure();
|
|
841
|
+
const observer = new ResizeObserver(measure);
|
|
842
|
+
observer.observe(el);
|
|
843
|
+
const headerRow = el.querySelector("thead tr");
|
|
844
|
+
if (headerRow) observer.observe(headerRow);
|
|
845
|
+
return () => {
|
|
846
|
+
observer.disconnect();
|
|
847
|
+
};
|
|
848
|
+
}, [fixedSignature]);
|
|
849
|
+
const fixedCellProps = (key, edge) => edge ? { "data-column-key": key, "data-fixed": edge } : { "data-column-key": key };
|
|
850
|
+
const leadingFixedStyle = (key) => leadingFixed ? { "--table-fixed-offset": fixedOffsets[key] ?? 0 } : void 0;
|
|
851
|
+
const columnCellClass = (col) => {
|
|
852
|
+
const edge = fixedEdge(col);
|
|
853
|
+
return cn(
|
|
854
|
+
columnWidth(col.width).className,
|
|
855
|
+
col.align === "right" && "text-end",
|
|
856
|
+
col.align === "center" && "text-center",
|
|
857
|
+
col.hiddenOnMobile && "hidden md:table-cell",
|
|
858
|
+
col.ellipsis && "ui-data-table-ellipsis",
|
|
859
|
+
edge === "end" && "ui-data-table-pin-end",
|
|
860
|
+
edge === "start" && "ui-data-table-pin-start"
|
|
861
|
+
);
|
|
862
|
+
};
|
|
863
|
+
const columnCellStyle = (col) => {
|
|
864
|
+
const base = columnWidth(col.width).style;
|
|
865
|
+
const edge = fixedEdge(col);
|
|
866
|
+
if (!edge) return base;
|
|
867
|
+
return { ...base, "--table-fixed-offset": fixedOffsets[col.key] ?? 0 };
|
|
868
|
+
};
|
|
869
|
+
const sortingState = table.state.sorting;
|
|
870
|
+
const onHeaderClick = (col) => {
|
|
871
|
+
if (!columnIsSortable(col)) return;
|
|
872
|
+
const directions = columnSortDirections(col, sortDirections);
|
|
873
|
+
const next = nextSortDirection(directionOf(sortingState, col.key), directions);
|
|
874
|
+
table.setSorting(
|
|
875
|
+
applySortToState(sortingState, col.key, next, sortPriorities[col.key], sortPriorities)
|
|
876
|
+
);
|
|
493
877
|
};
|
|
494
878
|
const dataRows = table.getRowModel().rows;
|
|
495
879
|
const rowCount = dataRows.length;
|
|
880
|
+
const scrollStyle = {};
|
|
881
|
+
const scrollVars = scrollStyle;
|
|
882
|
+
if (scroll?.x !== void 0) scrollVars["--table-scroll-inline-size"] = cssLength(scroll.x);
|
|
883
|
+
if (scroll?.y !== void 0) scrollVars["--table-scroll-block-size"] = cssLength(scroll.y);
|
|
884
|
+
if (typeof sticky === "object" && sticky.offsetHeader !== void 0) {
|
|
885
|
+
scrollVars["--table-sticky-offset"] = cssLength(sticky.offsetHeader);
|
|
886
|
+
}
|
|
496
887
|
return /* @__PURE__ */ jsx(
|
|
497
888
|
"div",
|
|
498
889
|
{
|
|
@@ -502,6 +893,9 @@ DataTable.Content = function DataTableContent() {
|
|
|
502
893
|
hasPinEnd && "ui-data-table-has-pin-end",
|
|
503
894
|
hasOverflowEnd && "ui-data-table-has-overflow-end"
|
|
504
895
|
),
|
|
896
|
+
style: scrollStyle,
|
|
897
|
+
"data-scroll-x": scroll?.x !== void 0 ? "" : void 0,
|
|
898
|
+
"data-scroll-y": scroll?.y !== void 0 ? "" : void 0,
|
|
505
899
|
"aria-busy": loading,
|
|
506
900
|
tabIndex: presetAttr ? void 0 : 0,
|
|
507
901
|
children: /* @__PURE__ */ jsx(
|
|
@@ -509,52 +903,69 @@ DataTable.Content = function DataTableContent() {
|
|
|
509
903
|
{
|
|
510
904
|
className: "ui-data-table-surface",
|
|
511
905
|
"data-preset": presetAttr,
|
|
906
|
+
"data-table-layout": fixedTableLayout ? "fixed" : void 0,
|
|
512
907
|
"data-striped": striped ? "" : void 0,
|
|
513
908
|
"data-hoverable": hoverable ? "" : void 0,
|
|
514
|
-
children: /* @__PURE__ */ jsxs(
|
|
515
|
-
|
|
516
|
-
|
|
517
|
-
|
|
518
|
-
|
|
519
|
-
|
|
520
|
-
|
|
521
|
-
|
|
522
|
-
|
|
523
|
-
|
|
524
|
-
|
|
525
|
-
|
|
526
|
-
|
|
527
|
-
|
|
528
|
-
|
|
529
|
-
|
|
530
|
-
|
|
531
|
-
|
|
532
|
-
|
|
533
|
-
|
|
534
|
-
|
|
535
|
-
|
|
536
|
-
|
|
537
|
-
|
|
538
|
-
|
|
539
|
-
|
|
540
|
-
|
|
541
|
-
|
|
542
|
-
|
|
543
|
-
|
|
544
|
-
|
|
545
|
-
|
|
546
|
-
|
|
547
|
-
|
|
548
|
-
|
|
549
|
-
|
|
550
|
-
|
|
551
|
-
|
|
552
|
-
|
|
553
|
-
|
|
554
|
-
|
|
555
|
-
|
|
556
|
-
|
|
557
|
-
|
|
909
|
+
children: /* @__PURE__ */ jsxs(
|
|
910
|
+
Table,
|
|
911
|
+
{
|
|
912
|
+
scrollable: preset !== "default",
|
|
913
|
+
preset,
|
|
914
|
+
collapseBelow,
|
|
915
|
+
bordered,
|
|
916
|
+
children: [
|
|
917
|
+
/* @__PURE__ */ jsx(
|
|
918
|
+
TableHeader,
|
|
919
|
+
{
|
|
920
|
+
className: cn("bg-secondary", stickyHeader && "ui-data-table-sticky-header"),
|
|
921
|
+
children: /* @__PURE__ */ jsxs(TableRow, { children: [
|
|
922
|
+
expandColumnShown && /* @__PURE__ */ jsx(
|
|
923
|
+
TableHead,
|
|
924
|
+
{
|
|
925
|
+
className: cn(
|
|
926
|
+
"ui-data-table-expand-column",
|
|
927
|
+
leadingFixed === "start" && "ui-data-table-pin-start"
|
|
928
|
+
),
|
|
929
|
+
...fixedCellProps("__expand", leadingFixed),
|
|
930
|
+
style: leadingFixedStyle("__expand"),
|
|
931
|
+
children: /* @__PURE__ */ jsx("span", { className: "sr-only", children: expandable?.columnTitle ?? t("dataTable.expandColumn") })
|
|
932
|
+
}
|
|
933
|
+
),
|
|
934
|
+
selectable && /* @__PURE__ */ jsx(
|
|
935
|
+
TableHead,
|
|
936
|
+
{
|
|
937
|
+
className: cn(
|
|
938
|
+
"ui-data-table-select-column",
|
|
939
|
+
leadingFixed === "start" && "ui-data-table-pin-start"
|
|
940
|
+
),
|
|
941
|
+
...fixedCellProps("__select", leadingFixed),
|
|
942
|
+
style: leadingFixedStyle("__select"),
|
|
943
|
+
children: /* @__PURE__ */ jsx(DataTable.SelectAll, {})
|
|
944
|
+
}
|
|
945
|
+
),
|
|
946
|
+
visibleColumns.map((col) => {
|
|
947
|
+
const isSortable = columnIsSortable(col);
|
|
948
|
+
const activeDirection = directionOf(sortingState, col.key);
|
|
949
|
+
const sortIndicator = isSortable ? activeDirection ? activeDirection === "asc" ? /* @__PURE__ */ jsx(ArrowUp, { className: "ui-data-table-sort-icon", "aria-hidden": "true" }) : /* @__PURE__ */ jsx(ArrowDown, { className: "ui-data-table-sort-icon", "aria-hidden": "true" }) : /* @__PURE__ */ jsx(
|
|
950
|
+
ChevronsUpDown,
|
|
951
|
+
{
|
|
952
|
+
className: "ui-data-table-sort-icon text-muted-foreground",
|
|
953
|
+
"aria-hidden": "true"
|
|
954
|
+
}
|
|
955
|
+
) : null;
|
|
956
|
+
const headerEmpty = isEmptyHeader(col.header);
|
|
957
|
+
const headerContent = headerEmpty && col.ariaLabel ? /* @__PURE__ */ jsx("span", { className: "sr-only", children: col.ariaLabel }) : col.header;
|
|
958
|
+
const label = /* @__PURE__ */ jsxs("span", { className: "ui-data-table-sort-label", children: [
|
|
959
|
+
headerContent,
|
|
960
|
+
sortIndicator
|
|
961
|
+
] });
|
|
962
|
+
const tooltipOn = col.showSorterTooltip ?? showSorterTooltip;
|
|
963
|
+
const nextDirection = nextSortDirection(
|
|
964
|
+
activeDirection,
|
|
965
|
+
columnSortDirections(col, sortDirections)
|
|
966
|
+
);
|
|
967
|
+
const sortHint = nextDirection === "asc" ? t("dataTable.sortAscending") : nextDirection === "desc" ? t("dataTable.sortDescending") : t("dataTable.sortCancel");
|
|
968
|
+
const sortButton = /* @__PURE__ */ jsx(
|
|
558
969
|
"button",
|
|
559
970
|
{
|
|
560
971
|
type: "button",
|
|
@@ -564,179 +975,300 @@ DataTable.Content = function DataTableContent() {
|
|
|
564
975
|
},
|
|
565
976
|
children: label
|
|
566
977
|
}
|
|
567
|
-
)
|
|
568
|
-
|
|
569
|
-
|
|
570
|
-
|
|
571
|
-
|
|
572
|
-
|
|
573
|
-
|
|
574
|
-
|
|
575
|
-
|
|
576
|
-
|
|
577
|
-
|
|
578
|
-
|
|
579
|
-
|
|
580
|
-
|
|
581
|
-
|
|
582
|
-
|
|
583
|
-
|
|
584
|
-
|
|
585
|
-
|
|
586
|
-
|
|
587
|
-
|
|
588
|
-
|
|
589
|
-
|
|
590
|
-
|
|
591
|
-
|
|
592
|
-
|
|
593
|
-
|
|
594
|
-
|
|
595
|
-
|
|
596
|
-
|
|
597
|
-
|
|
978
|
+
);
|
|
979
|
+
return /* @__PURE__ */ jsxs(
|
|
980
|
+
TableHead,
|
|
981
|
+
{
|
|
982
|
+
priority: col.priority,
|
|
983
|
+
"data-empty": headerEmpty || void 0,
|
|
984
|
+
"data-align": col.headerAlign ?? col.align,
|
|
985
|
+
"aria-sort": isSortable ? activeDirection ? activeDirection === "asc" ? "ascending" : "descending" : "none" : void 0,
|
|
986
|
+
...fixedCellProps(col.key, fixedEdge(col)),
|
|
987
|
+
style: columnCellStyle(col),
|
|
988
|
+
className: cn(
|
|
989
|
+
columnCellClass(col),
|
|
990
|
+
// `headerAlign` when the heading differs from the rows,
|
|
991
|
+
// `align` otherwise. A table wanting centred headings
|
|
992
|
+
// over start-aligned text could not say so before, and
|
|
993
|
+
// consumers reached for `[&_th_button]:justify-center`.
|
|
994
|
+
(col.headerAlign ?? col.align) === "right" && "text-end",
|
|
995
|
+
(col.headerAlign ?? col.align) === "center" && "text-center",
|
|
996
|
+
isSortable && "select-none"
|
|
997
|
+
),
|
|
998
|
+
children: [
|
|
999
|
+
isSortable ? tooltipOn ? /* @__PURE__ */ jsxs(Tooltip, { children: [
|
|
1000
|
+
/* @__PURE__ */ jsx(TooltipTrigger, { asChild: true, children: sortButton }),
|
|
1001
|
+
/* @__PURE__ */ jsx(TooltipContent, { children: sortHint })
|
|
1002
|
+
] }) : sortButton : label,
|
|
1003
|
+
col.filters ? /* @__PURE__ */ jsx(ColumnFilterMenu, { column: col }) : null
|
|
1004
|
+
]
|
|
1005
|
+
},
|
|
1006
|
+
col.key
|
|
1007
|
+
);
|
|
1008
|
+
})
|
|
1009
|
+
] })
|
|
1010
|
+
}
|
|
1011
|
+
),
|
|
1012
|
+
/* @__PURE__ */ jsx(TableBody, { children: loading ? (
|
|
1013
|
+
// Shaped skeleton rows rendered INSIDE the real table grid so they
|
|
1014
|
+
// share its borders + column widths — no second framed container
|
|
1015
|
+
// (which double-borders when the table sits in a Card). Count is
|
|
1016
|
+
// bounded to the previous page so the height barely shifts.
|
|
1017
|
+
Array.from({ length: Math.min(Math.max(rowCount, 6), 10) }).map((_, i) => /* @__PURE__ */ jsxs(TableRow, { className: cn(rowPadding, "hover:bg-transparent"), children: [
|
|
1018
|
+
expandColumnShown && /* @__PURE__ */ jsx(TableCell, { className: cellPadding }),
|
|
1019
|
+
selectable && /* @__PURE__ */ jsx(TableCell, { className: cellPadding, children: /* @__PURE__ */ jsx("div", { className: "ui-skeleton-block ui-data-table-skeleton-check" }) }),
|
|
1020
|
+
visibleColumns.map((col, j) => /* @__PURE__ */ jsx(
|
|
1021
|
+
TableCell,
|
|
598
1022
|
{
|
|
599
|
-
|
|
600
|
-
|
|
601
|
-
|
|
602
|
-
|
|
603
|
-
|
|
1023
|
+
priority: col.priority,
|
|
1024
|
+
"data-align": col.align,
|
|
1025
|
+
style: columnCellStyle(col),
|
|
1026
|
+
className: cn(cellPadding, columnCellClass(col)),
|
|
1027
|
+
children: /* @__PURE__ */ jsx(
|
|
1028
|
+
"div",
|
|
1029
|
+
{
|
|
1030
|
+
className: cn(
|
|
1031
|
+
"ui-skeleton-block ui-data-table-skeleton-line",
|
|
1032
|
+
j === 0 ? "w-1/2" : "w-3/4",
|
|
1033
|
+
col.align === "right" && "ms-auto",
|
|
1034
|
+
col.align === "center" && "mx-auto"
|
|
1035
|
+
)
|
|
1036
|
+
}
|
|
604
1037
|
)
|
|
605
|
-
}
|
|
606
|
-
|
|
607
|
-
|
|
608
|
-
|
|
609
|
-
)
|
|
610
|
-
|
|
611
|
-
|
|
612
|
-
|
|
613
|
-
|
|
614
|
-
|
|
615
|
-
|
|
616
|
-
|
|
617
|
-
|
|
618
|
-
|
|
619
|
-
|
|
620
|
-
|
|
621
|
-
|
|
1038
|
+
},
|
|
1039
|
+
col.key
|
|
1040
|
+
))
|
|
1041
|
+
] }, `skeleton-${i}`))
|
|
1042
|
+
) : isDenied ? (
|
|
1043
|
+
// repeating a 403 cannot succeed. `warning` (not destructive) keeps it a policy
|
|
1044
|
+
// statement rather than a system fault. Announced politely: a permission boundary
|
|
1045
|
+
// is expected information, not an interruption.
|
|
1046
|
+
/* @__PURE__ */ jsx(TableRow, { className: "hover:bg-transparent", children: /* @__PURE__ */ jsx(
|
|
1047
|
+
TableCell,
|
|
1048
|
+
{
|
|
1049
|
+
colSpan: emptyColSpan,
|
|
1050
|
+
className: "ui-data-table-empty",
|
|
1051
|
+
"aria-live": "polite",
|
|
1052
|
+
children: denied === true ? /* @__PURE__ */ jsx(
|
|
1053
|
+
EmptyState,
|
|
1054
|
+
{
|
|
1055
|
+
icon: ShieldAlert,
|
|
1056
|
+
tone: "warning",
|
|
1057
|
+
title: t("dataTable.denied"),
|
|
1058
|
+
description: t("dataTable.deniedDescription"),
|
|
1059
|
+
titleAs: "p"
|
|
1060
|
+
}
|
|
1061
|
+
) : denied
|
|
1062
|
+
}
|
|
1063
|
+
) })
|
|
1064
|
+
) : isError ? (
|
|
1065
|
+
// Announced assertively (`role="alert"`) because the
|
|
1066
|
+
// user's request did not complete — unlike empty/denied, which are states of the data
|
|
1067
|
+
// itself. The role sits on an inner wrapper, never on the <td>: overriding a cell's
|
|
1068
|
+
// role would strip it out of the table's grid semantics for AT.
|
|
1069
|
+
/* @__PURE__ */ jsx(TableRow, { className: "hover:bg-transparent", children: /* @__PURE__ */ jsx(TableCell, { colSpan: emptyColSpan, className: "ui-data-table-empty", children: /* @__PURE__ */ jsx("div", { role: "alert", children: error === true ? /* @__PURE__ */ jsx(
|
|
622
1070
|
EmptyState,
|
|
623
1071
|
{
|
|
624
|
-
icon:
|
|
625
|
-
tone: "
|
|
626
|
-
title: t("dataTable.
|
|
627
|
-
description: t("dataTable.
|
|
628
|
-
titleAs: "p"
|
|
1072
|
+
icon: AlertCircle,
|
|
1073
|
+
tone: "destructive",
|
|
1074
|
+
title: t("dataTable.error"),
|
|
1075
|
+
description: t("dataTable.errorDescription"),
|
|
1076
|
+
titleAs: "p",
|
|
1077
|
+
action: onRetry ? /* @__PURE__ */ jsxs(Button, { variant: "outline", size: "sm", onClick: onRetry, children: [
|
|
1078
|
+
/* @__PURE__ */ jsx(RefreshCw, { "aria-hidden": "true" }),
|
|
1079
|
+
t("common.retry")
|
|
1080
|
+
] }) : void 0
|
|
629
1081
|
}
|
|
630
|
-
) :
|
|
631
|
-
|
|
632
|
-
|
|
633
|
-
|
|
634
|
-
|
|
635
|
-
|
|
636
|
-
|
|
637
|
-
|
|
638
|
-
|
|
639
|
-
|
|
640
|
-
|
|
641
|
-
|
|
642
|
-
|
|
643
|
-
|
|
644
|
-
|
|
645
|
-
|
|
646
|
-
|
|
647
|
-
|
|
648
|
-
|
|
649
|
-
|
|
650
|
-
|
|
651
|
-
|
|
652
|
-
|
|
653
|
-
|
|
654
|
-
{
|
|
655
|
-
colSpan: emptyColSpan,
|
|
656
|
-
className: "ui-data-table-empty",
|
|
657
|
-
"aria-live": "polite",
|
|
658
|
-
children: empty ?? /* @__PURE__ */ jsx(EmptyState, { title: t("dataTable.empty"), titleAs: "p" })
|
|
659
|
-
}
|
|
660
|
-
) }) : dataRows.map((row) => {
|
|
661
|
-
const original = row.original;
|
|
662
|
-
const isSelected = row.getIsSelected();
|
|
663
|
-
const isInteractiveTarget = (target) => !!target.closest(
|
|
664
|
-
"button, a, input, select, textarea, [role=menuitem], [role=checkbox]"
|
|
665
|
-
);
|
|
666
|
-
return /* @__PURE__ */ jsxs(
|
|
667
|
-
TableRow,
|
|
668
|
-
{
|
|
669
|
-
"data-state": isSelected ? "selected" : void 0,
|
|
670
|
-
tabIndex: onRowClick ? 0 : void 0,
|
|
671
|
-
onClick: (e) => {
|
|
672
|
-
const target = e.target;
|
|
673
|
-
if (isInteractiveTarget(target)) return;
|
|
674
|
-
onRowClick?.(original);
|
|
675
|
-
},
|
|
676
|
-
onKeyDown: onRowClick ? (e) => {
|
|
677
|
-
if (e.key !== "Enter" && e.key !== " ") return;
|
|
678
|
-
if (e.target !== e.currentTarget) return;
|
|
679
|
-
e.preventDefault();
|
|
680
|
-
onRowClick?.(original);
|
|
681
|
-
} : void 0,
|
|
682
|
-
className: cn(
|
|
683
|
-
rowPadding,
|
|
684
|
-
// Hover highlight when rows are clickable OR explicitly hoverable…
|
|
685
|
-
(onRowClick || hoverable) && "hover:bg-muted/50",
|
|
686
|
-
// …but the affordance (cursor + focus mark) only when clickable.
|
|
687
|
-
//
|
|
688
|
-
// `ui-focus-ring` = the single focus source (styles/focus-ring.css). It
|
|
689
|
-
// replaces `focus-visible:ring-ring focus-visible:ring-2
|
|
690
|
-
// focus-visible:ring-inset`, which was a hand-rolled second ring: it read no
|
|
691
|
-
// `--focus-ring-*` knob, so a service could not retune it, and — being a
|
|
692
|
-
// utility — it painted regardless of the `--focus-outline` switch, which is
|
|
693
|
-
// exactly the hole the switch exists to close.
|
|
694
|
-
onRowClick && "ui-focus-ring cursor-pointer",
|
|
695
|
-
isSelected && "bg-muted/30",
|
|
696
|
-
rowClassName?.(original)
|
|
697
|
-
),
|
|
698
|
-
children: [
|
|
699
|
-
selectable && /* @__PURE__ */ jsx(TableCell, { className: cellPadding, children: /* @__PURE__ */ jsx(
|
|
700
|
-
Checkbox,
|
|
1082
|
+
) : error }) }) })
|
|
1083
|
+
) : rowCount === 0 ? /* @__PURE__ */ jsx(TableRow, { className: "hover:bg-transparent", children: /* @__PURE__ */ jsx(
|
|
1084
|
+
TableCell,
|
|
1085
|
+
{
|
|
1086
|
+
colSpan: emptyColSpan,
|
|
1087
|
+
className: "ui-data-table-empty",
|
|
1088
|
+
"aria-live": "polite",
|
|
1089
|
+
children: empty ?? /* @__PURE__ */ jsx(EmptyState, { title: t("dataTable.empty"), titleAs: "p" })
|
|
1090
|
+
}
|
|
1091
|
+
) }) : dataRows.map((row, rowIndex) => {
|
|
1092
|
+
const original = row.original;
|
|
1093
|
+
const rowKey = getRowId(original);
|
|
1094
|
+
const isSelected = row.getIsSelected();
|
|
1095
|
+
const checkboxProps = rowSelection?.getCheckboxProps?.(original) ?? {};
|
|
1096
|
+
const canExpand = expandColumnShown && (expandable?.rowExpandable?.(original) ?? true);
|
|
1097
|
+
const isExpanded = canExpand && expandedKeys.includes(rowKey);
|
|
1098
|
+
const rowProps = onRow?.(original, rowIndex) ?? {};
|
|
1099
|
+
const isInteractiveTarget = (target) => !!target.closest(
|
|
1100
|
+
"button, a, input, select, textarea, [role=menuitem], [role=checkbox], [role=radio]"
|
|
1101
|
+
);
|
|
1102
|
+
const expandByClick = canExpand && expandable?.expandRowByClick;
|
|
1103
|
+
return /* @__PURE__ */ jsxs(React.Fragment, { children: [
|
|
1104
|
+
/* @__PURE__ */ jsxs(
|
|
1105
|
+
TableRow,
|
|
701
1106
|
{
|
|
702
|
-
|
|
703
|
-
|
|
704
|
-
|
|
705
|
-
},
|
|
706
|
-
"aria-label": t("dataTable.selectRow", { id: row.id }),
|
|
1107
|
+
...rowProps,
|
|
1108
|
+
"data-state": isSelected ? "selected" : void 0,
|
|
1109
|
+
tabIndex: onRowClick ? 0 : rowProps.tabIndex,
|
|
707
1110
|
onClick: (e) => {
|
|
708
|
-
|
|
709
|
-
|
|
710
|
-
|
|
711
|
-
|
|
712
|
-
|
|
713
|
-
|
|
714
|
-
|
|
715
|
-
|
|
716
|
-
|
|
717
|
-
|
|
1111
|
+
rowProps.onClick?.(e);
|
|
1112
|
+
const target = e.target;
|
|
1113
|
+
if (isInteractiveTarget(target)) return;
|
|
1114
|
+
if (expandByClick) toggleExpanded(rowKey);
|
|
1115
|
+
onRowClick?.(original);
|
|
1116
|
+
},
|
|
1117
|
+
onKeyDown: onRowClick ? (e) => {
|
|
1118
|
+
rowProps.onKeyDown?.(e);
|
|
1119
|
+
if (e.key !== "Enter" && e.key !== " ") return;
|
|
1120
|
+
if (e.target !== e.currentTarget) return;
|
|
1121
|
+
e.preventDefault();
|
|
1122
|
+
onRowClick?.(original);
|
|
1123
|
+
} : rowProps.onKeyDown,
|
|
718
1124
|
className: cn(
|
|
719
|
-
|
|
720
|
-
|
|
721
|
-
|
|
722
|
-
|
|
723
|
-
|
|
724
|
-
|
|
1125
|
+
rowPadding,
|
|
1126
|
+
// Hover highlight when rows are clickable OR explicitly hoverable…
|
|
1127
|
+
(onRowClick || hoverable) && "hover:bg-muted/50",
|
|
1128
|
+
// …but the affordance (cursor + focus mark) only when clickable.
|
|
1129
|
+
//
|
|
1130
|
+
// `ui-focus-ring` = the single focus source (styles/focus-ring.css). It
|
|
1131
|
+
// replaces `focus-visible:ring-ring focus-visible:ring-2
|
|
1132
|
+
// focus-visible:ring-inset`, which was a hand-rolled second ring: it read no
|
|
1133
|
+
// `--focus-ring-*` knob, so a service could not retune it, and — being a
|
|
1134
|
+
// utility — it painted regardless of the `--focus-outline` switch, which is
|
|
1135
|
+
// exactly the hole the switch exists to close.
|
|
1136
|
+
onRowClick && "ui-focus-ring cursor-pointer",
|
|
1137
|
+
isSelected && "bg-muted/30",
|
|
1138
|
+
rowProps.className,
|
|
1139
|
+
rowClassName?.(original)
|
|
725
1140
|
),
|
|
726
|
-
children:
|
|
727
|
-
|
|
728
|
-
|
|
729
|
-
|
|
730
|
-
|
|
731
|
-
|
|
732
|
-
|
|
733
|
-
|
|
734
|
-
|
|
735
|
-
|
|
736
|
-
|
|
737
|
-
|
|
738
|
-
|
|
739
|
-
|
|
1141
|
+
children: [
|
|
1142
|
+
expandColumnShown && /* @__PURE__ */ jsx(
|
|
1143
|
+
TableCell,
|
|
1144
|
+
{
|
|
1145
|
+
className: cn(
|
|
1146
|
+
cellPadding,
|
|
1147
|
+
leadingFixed === "start" && "ui-data-table-pin-start"
|
|
1148
|
+
),
|
|
1149
|
+
...fixedCellProps("__expand", leadingFixed),
|
|
1150
|
+
style: leadingFixedStyle("__expand"),
|
|
1151
|
+
children: canExpand ? /* @__PURE__ */ jsx(
|
|
1152
|
+
Button,
|
|
1153
|
+
{
|
|
1154
|
+
variant: "ghost",
|
|
1155
|
+
size: "icon-xs",
|
|
1156
|
+
"aria-expanded": isExpanded,
|
|
1157
|
+
"aria-label": isExpanded ? t("dataTable.collapseRow") : t("dataTable.expandRow"),
|
|
1158
|
+
className: "ui-data-table-expand-trigger",
|
|
1159
|
+
onClick: (e) => {
|
|
1160
|
+
e.stopPropagation();
|
|
1161
|
+
toggleExpanded(rowKey);
|
|
1162
|
+
},
|
|
1163
|
+
children: isExpanded ? /* @__PURE__ */ jsx(
|
|
1164
|
+
ChevronDown,
|
|
1165
|
+
{
|
|
1166
|
+
className: "ui-data-table-sort-icon",
|
|
1167
|
+
"aria-hidden": "true"
|
|
1168
|
+
}
|
|
1169
|
+
) : /* @__PURE__ */ jsx(
|
|
1170
|
+
ChevronRight,
|
|
1171
|
+
{
|
|
1172
|
+
className: "ui-data-table-sort-icon",
|
|
1173
|
+
"aria-hidden": "true"
|
|
1174
|
+
}
|
|
1175
|
+
)
|
|
1176
|
+
}
|
|
1177
|
+
) : null
|
|
1178
|
+
}
|
|
1179
|
+
),
|
|
1180
|
+
selectable && /* @__PURE__ */ jsx(
|
|
1181
|
+
TableCell,
|
|
1182
|
+
{
|
|
1183
|
+
className: cn(
|
|
1184
|
+
cellPadding,
|
|
1185
|
+
leadingFixed === "start" && "ui-data-table-pin-start"
|
|
1186
|
+
),
|
|
1187
|
+
...fixedCellProps("__select", leadingFixed),
|
|
1188
|
+
style: leadingFixedStyle("__select"),
|
|
1189
|
+
children: rowSelection?.type === "radio" ? (
|
|
1190
|
+
// One choice per table, so each cell is its own single-item group:
|
|
1191
|
+
// Radix requires a Root for an Item, and a Root cannot legally span
|
|
1192
|
+
// <tr> boundaries without rewriting the table's own semantics.
|
|
1193
|
+
/* @__PURE__ */ jsx(
|
|
1194
|
+
RadioGroupRoot,
|
|
1195
|
+
{
|
|
1196
|
+
value: isSelected ? rowKey : "",
|
|
1197
|
+
disabled: checkboxProps.disabled,
|
|
1198
|
+
onValueChange: () => {
|
|
1199
|
+
row.toggleSelected(true);
|
|
1200
|
+
},
|
|
1201
|
+
children: /* @__PURE__ */ jsx(
|
|
1202
|
+
RadioItem,
|
|
1203
|
+
{
|
|
1204
|
+
value: rowKey,
|
|
1205
|
+
"aria-label": checkboxProps["aria-label"] ?? t("dataTable.selectRow", { id: row.id }),
|
|
1206
|
+
onClick: (e) => {
|
|
1207
|
+
e.stopPropagation();
|
|
1208
|
+
}
|
|
1209
|
+
}
|
|
1210
|
+
)
|
|
1211
|
+
}
|
|
1212
|
+
)
|
|
1213
|
+
) : /* @__PURE__ */ jsx(
|
|
1214
|
+
Checkbox,
|
|
1215
|
+
{
|
|
1216
|
+
checked: isSelected,
|
|
1217
|
+
disabled: checkboxProps.disabled,
|
|
1218
|
+
onCheckedChange: (v) => {
|
|
1219
|
+
row.toggleSelected(!!v);
|
|
1220
|
+
},
|
|
1221
|
+
"aria-label": checkboxProps["aria-label"] ?? t("dataTable.selectRow", { id: row.id }),
|
|
1222
|
+
onClick: (e) => {
|
|
1223
|
+
e.stopPropagation();
|
|
1224
|
+
}
|
|
1225
|
+
}
|
|
1226
|
+
)
|
|
1227
|
+
}
|
|
1228
|
+
),
|
|
1229
|
+
visibleColumns.map((col) => {
|
|
1230
|
+
const rendered = col.render ? col.render(original) : (() => {
|
|
1231
|
+
const v = original[col.key];
|
|
1232
|
+
const text = v == null || !(typeof v === "string" || typeof v === "number") ? "\u2014" : String(v);
|
|
1233
|
+
return /* @__PURE__ */ jsx("span", { "data-slot": "table-cell-text", children: text });
|
|
1234
|
+
})();
|
|
1235
|
+
const rawValue = original[col.key];
|
|
1236
|
+
const title = col.ellipsis && !col.render && (typeof rawValue === "string" || typeof rawValue === "number") ? String(rawValue) : void 0;
|
|
1237
|
+
return /* @__PURE__ */ jsx(
|
|
1238
|
+
TableCell,
|
|
1239
|
+
{
|
|
1240
|
+
priority: col.priority,
|
|
1241
|
+
"data-align": col.align,
|
|
1242
|
+
title,
|
|
1243
|
+
...fixedCellProps(col.key, fixedEdge(col)),
|
|
1244
|
+
style: columnCellStyle(col),
|
|
1245
|
+
className: cn(cellPadding, columnCellClass(col)),
|
|
1246
|
+
children: rendered
|
|
1247
|
+
},
|
|
1248
|
+
col.key
|
|
1249
|
+
);
|
|
1250
|
+
})
|
|
1251
|
+
]
|
|
1252
|
+
}
|
|
1253
|
+
),
|
|
1254
|
+
isExpanded && expandable?.expandedRowRender ? /* @__PURE__ */ jsx(
|
|
1255
|
+
TableRow,
|
|
1256
|
+
{
|
|
1257
|
+
className: "ui-data-table-expanded-row hover:bg-transparent",
|
|
1258
|
+
"data-expanded-row": "",
|
|
1259
|
+
children: /* @__PURE__ */ jsx(TableCell, { colSpan: emptyColSpan, flush: true, children: expandable.expandedRowRender(original, rowIndex, true) })
|
|
1260
|
+
}
|
|
1261
|
+
) : null
|
|
1262
|
+
] }, row.id);
|
|
1263
|
+
}) }),
|
|
1264
|
+
summary ? (
|
|
1265
|
+
// A real <tfoot>: the totals row belongs to the table's own grid, so it keeps the
|
|
1266
|
+
// column widths, the header association and the screen-reader row navigation.
|
|
1267
|
+
/* @__PURE__ */ jsx("tfoot", { "data-slot": "table-footer", className: "ui-data-table-summary", children: summary(dataRows.map((row) => row.original)) })
|
|
1268
|
+
) : null
|
|
1269
|
+
]
|
|
1270
|
+
}
|
|
1271
|
+
)
|
|
740
1272
|
}
|
|
741
1273
|
)
|
|
742
1274
|
}
|
|
@@ -779,14 +1311,14 @@ function CursorPagination({ cursor, hasMore, onChange, className }) {
|
|
|
779
1311
|
)
|
|
780
1312
|
] });
|
|
781
1313
|
}
|
|
782
|
-
function NumberedPagination({
|
|
783
|
-
|
|
784
|
-
className
|
|
785
|
-
}) {
|
|
786
|
-
const { table } = useDataTableContext();
|
|
1314
|
+
function NumberedPagination({ pageSizeOptions, className }) {
|
|
1315
|
+
const { table, paginationConfig, pagerHidden } = useDataTableContext();
|
|
787
1316
|
const { t } = useTranslation();
|
|
788
1317
|
const { pageIndex, pageSize } = table.state.pagination;
|
|
789
1318
|
const pageCount = table.getPageCount();
|
|
1319
|
+
if (pagerHidden) return null;
|
|
1320
|
+
const options = pageSizeOptions ?? paginationConfig?.pageSizeOptions ?? [10, 20, 50, 100];
|
|
1321
|
+
const showSizeChanger = paginationConfig?.showSizeChanger ?? true;
|
|
790
1322
|
return /* @__PURE__ */ jsxs(
|
|
791
1323
|
Flex,
|
|
792
1324
|
{
|
|
@@ -797,7 +1329,7 @@ function NumberedPagination({
|
|
|
797
1329
|
wrap: true,
|
|
798
1330
|
className: cn("ui-data-table-pagination ui-data-table-pagination--numbered", className),
|
|
799
1331
|
children: [
|
|
800
|
-
/* @__PURE__ */ jsxs(Flex, { direction: "row", align: "center", gap: "sm", className: "ui-data-table-page-size", children: [
|
|
1332
|
+
showSizeChanger ? /* @__PURE__ */ jsxs(Flex, { direction: "row", align: "center", gap: "sm", className: "ui-data-table-page-size", children: [
|
|
801
1333
|
/* @__PURE__ */ jsx("span", { className: "ui-data-table-page-size-label ui-data-table-pagination-text", children: t("dataGrid.rowsPerPage") }),
|
|
802
1334
|
/* @__PURE__ */ jsxs(
|
|
803
1335
|
Select,
|
|
@@ -814,11 +1346,11 @@ function NumberedPagination({
|
|
|
814
1346
|
children: /* @__PURE__ */ jsx(SelectValue, {})
|
|
815
1347
|
}
|
|
816
1348
|
),
|
|
817
|
-
/* @__PURE__ */ jsx(SelectContent, { children:
|
|
1349
|
+
/* @__PURE__ */ jsx(SelectContent, { children: options.map((n) => /* @__PURE__ */ jsx(SelectItem, { value: String(n), className: "tabular-nums", children: n }, n)) })
|
|
818
1350
|
]
|
|
819
1351
|
}
|
|
820
1352
|
)
|
|
821
|
-
] }),
|
|
1353
|
+
] }) : /* @__PURE__ */ jsx("span", {}),
|
|
822
1354
|
/* @__PURE__ */ jsxs(Flex, { direction: "row", align: "center", gap: "sm", className: "ui-data-table-page-nav", children: [
|
|
823
1355
|
/* @__PURE__ */ jsx("span", { className: "ui-data-table-pagination-text tabular-nums", children: t("dataGrid.pageOf", { page: pageIndex + 1, total: Math.max(1, pageCount) }) }),
|
|
824
1356
|
/* @__PURE__ */ jsx(
|