@oprt/react 0.0.0-stage → 0.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/LICENSE +21 -0
- package/README.md +105 -2
- package/dist/ActionStatus/ActionStatus.js +104 -0
- package/dist/ActionStatus/ActionStatus.manifest.js +64 -0
- package/dist/ActionStatus/index.js +7 -0
- package/dist/Alert/Alert.js +86 -0
- package/dist/Alert/Alert.manifest.js +36 -0
- package/dist/Alert/index.js +7 -0
- package/dist/AppShell/AppShell.js +103 -0
- package/dist/AppShell/AppShell.manifest.js +66 -0
- package/dist/AppShell/index.js +9 -0
- package/dist/AttachmentPreview/AttachmentPreview.js +145 -0
- package/dist/AttachmentPreview/AttachmentPreview.manifest.js +42 -0
- package/dist/AttachmentPreview/index.js +9 -0
- package/dist/Avatar/Avatar.js +87 -0
- package/dist/Avatar/Avatar.manifest.js +25 -0
- package/dist/Avatar/index.js +7 -0
- package/dist/Badge/Badge.js +124 -0
- package/dist/Badge/Badge.manifest.js +41 -0
- package/dist/Badge/index.js +7 -0
- package/dist/Breadcrumb/Breadcrumb.js +64 -0
- package/dist/Breadcrumb/Breadcrumb.manifest.js +28 -0
- package/dist/Breadcrumb/index.js +7 -0
- package/dist/BulkActionBar/BulkActionBar.js +145 -0
- package/dist/BulkActionBar/BulkActionBar.manifest.js +46 -0
- package/dist/BulkActionBar/index.js +9 -0
- package/dist/BulkActionBar/selection.js +44 -0
- package/dist/BulkResults/BulkResults.js +269 -0
- package/dist/BulkResults/BulkResults.manifest.js +45 -0
- package/dist/BulkResults/index.js +7 -0
- package/dist/Button/Button.js +170 -0
- package/dist/Button/Button.manifest.js +36 -0
- package/dist/Button/index.js +7 -0
- package/dist/ButtonGroup/ButtonGroup.js +60 -0
- package/dist/ButtonGroup/ButtonGroup.manifest.js +22 -0
- package/dist/ButtonGroup/index.js +7 -0
- package/dist/Calendar/Calendar.js +106 -0
- package/dist/Calendar/Calendar.manifest.js +32 -0
- package/dist/Calendar/index.js +7 -0
- package/dist/Card/Card.js +70 -0
- package/dist/Card/Card.manifest.js +57 -0
- package/dist/Card/index.js +16 -0
- package/dist/Chart/Chart.js +1200 -0
- package/dist/Chart/Chart.manifest.js +110 -0
- package/dist/Chart/ChartControls.js +190 -0
- package/dist/Chart/geometry.js +217 -0
- package/dist/Chart/index.js +9 -0
- package/dist/Checkbox/Checkbox.js +166 -0
- package/dist/Checkbox/Checkbox.manifest.js +38 -0
- package/dist/Checkbox/index.js +7 -0
- package/dist/Collapsible/Collapsible.js +177 -0
- package/dist/Collapsible/Collapsible.manifest.js +54 -0
- package/dist/Collapsible/index.js +12 -0
- package/dist/CollectionState/CollectionState.js +68 -0
- package/dist/CollectionState/CollectionState.manifest.js +44 -0
- package/dist/CollectionState/index.js +7 -0
- package/dist/ComboBox/ComboBox.js +221 -0
- package/dist/ComboBox/ComboBox.manifest.js +87 -0
- package/dist/ComboBox/index.js +7 -0
- package/dist/CommandPalette/CommandPalette.js +276 -0
- package/dist/CommandPalette/CommandPalette.manifest.js +24 -0
- package/dist/CommandPalette/index.js +7 -0
- package/dist/ConfirmDialog/ConfirmDialog.js +84 -0
- package/dist/ConfirmDialog/ConfirmDialog.manifest.js +32 -0
- package/dist/ConfirmDialog/index.js +7 -0
- package/dist/ContextMenu/ContextMenu.js +192 -0
- package/dist/ContextMenu/ContextMenu.manifest.js +41 -0
- package/dist/ContextMenu/index.js +7 -0
- package/dist/CoordinateInput/CoordinateInput.js +141 -0
- package/dist/CoordinateInput/CoordinateInput.manifest.js +36 -0
- package/dist/CoordinateInput/index.js +9 -0
- package/dist/CopyButton/CopyButton.js +129 -0
- package/dist/CopyButton/CopyButton.manifest.js +35 -0
- package/dist/CopyButton/index.js +7 -0
- package/dist/DataGrid/DataGrid.js +459 -0
- package/dist/DataGrid/DataGrid.manifest.js +135 -0
- package/dist/DataGrid/PageControls.js +41 -0
- package/dist/DataGrid/index.js +9 -0
- package/dist/DataTable/DataTable.js +375 -0
- package/dist/DataTable/DataTable.manifest.js +86 -0
- package/dist/DataTable/index.js +9 -0
- package/dist/DataTable/sort.js +45 -0
- package/dist/DataTable/useScrollsSideways.js +61 -0
- package/dist/DataTable/useTableWindow.js +185 -0
- package/dist/DatePicker/DatePicker.js +187 -0
- package/dist/DatePicker/DatePicker.manifest.js +40 -0
- package/dist/DatePicker/index.js +7 -0
- package/dist/DateRangePicker/DateRangePicker.js +156 -0
- package/dist/DateRangePicker/DateRangePicker.manifest.js +41 -0
- package/dist/DateRangePicker/index.js +7 -0
- package/dist/DateTimePicker/DateTimePicker.js +213 -0
- package/dist/DateTimePicker/DateTimePicker.manifest.js +44 -0
- package/dist/DateTimePicker/index.js +7 -0
- package/dist/DescriptionList/DescriptionList.js +93 -0
- package/dist/DescriptionList/DescriptionList.manifest.js +40 -0
- package/dist/DescriptionList/index.js +9 -0
- package/dist/Dialog/Dialog.js +214 -0
- package/dist/Dialog/Dialog.manifest.js +31 -0
- package/dist/Dialog/index.js +7 -0
- package/dist/Divider/Divider.js +64 -0
- package/dist/Divider/Divider.manifest.js +21 -0
- package/dist/Divider/index.js +7 -0
- package/dist/DropdownMenu/DropdownMenu.js +170 -0
- package/dist/DropdownMenu/DropdownMenu.manifest.js +82 -0
- package/dist/DropdownMenu/index.js +16 -0
- package/dist/EntityPreview/EntityPreview.js +82 -0
- package/dist/EntityPreview/EntityPreview.manifest.js +43 -0
- package/dist/EntityPreview/index.js +7 -0
- package/dist/EventTimeline/EventTimeline.js +249 -0
- package/dist/EventTimeline/EventTimeline.manifest.js +57 -0
- package/dist/EventTimeline/index.js +7 -0
- package/dist/Field/Field.js +81 -0
- package/dist/Field/Field.manifest.js +32 -0
- package/dist/Field/index.js +9 -0
- package/dist/FileUpload/FileUpload.js +215 -0
- package/dist/FileUpload/FileUpload.manifest.js +48 -0
- package/dist/FileUpload/index.js +7 -0
- package/dist/FilterBar/FilterBar.js +173 -0
- package/dist/FilterBar/FilterBar.manifest.js +49 -0
- package/dist/FilterBar/index.js +7 -0
- package/dist/FormErrorSummary/FormErrorSummary.js +70 -0
- package/dist/FormErrorSummary/FormErrorSummary.manifest.js +29 -0
- package/dist/FormErrorSummary/index.js +9 -0
- package/dist/FormSection/FormSection.js +51 -0
- package/dist/FormSection/FormSection.manifest.js +30 -0
- package/dist/FormSection/index.js +7 -0
- package/dist/InlineEdit/InlineEdit.js +261 -0
- package/dist/InlineEdit/InlineEdit.manifest.js +40 -0
- package/dist/InlineEdit/index.js +7 -0
- package/dist/Input/Input.js +126 -0
- package/dist/Input/Input.manifest.js +49 -0
- package/dist/Input/index.js +7 -0
- package/dist/Inspector/Inspector.js +63 -0
- package/dist/Inspector/Inspector.manifest.js +35 -0
- package/dist/Inspector/index.js +7 -0
- package/dist/JobStatus/JobStatus.js +118 -0
- package/dist/JobStatus/JobStatus.manifest.js +53 -0
- package/dist/JobStatus/index.js +7 -0
- package/dist/LayerControl/LayerControl.js +199 -0
- package/dist/LayerControl/LayerControl.manifest.js +34 -0
- package/dist/LayerControl/index.js +7 -0
- package/dist/Link/Link.js +83 -0
- package/dist/Link/Link.manifest.js +37 -0
- package/dist/Link/index.js +7 -0
- package/dist/MapControls/MapControls.js +122 -0
- package/dist/MapControls/MapControls.manifest.js +31 -0
- package/dist/MapControls/index.js +7 -0
- package/dist/MapLegend/MapLegend.js +89 -0
- package/dist/MapLegend/MapLegend.manifest.js +29 -0
- package/dist/MapLegend/index.js +7 -0
- package/dist/MapScale/MapScale.js +96 -0
- package/dist/MapScale/MapScale.manifest.js +31 -0
- package/dist/MapScale/index.js +7 -0
- package/dist/MediaFrame/MediaFrame.js +113 -0
- package/dist/MediaFrame/MediaFrame.manifest.js +57 -0
- package/dist/MediaFrame/index.js +7 -0
- package/dist/MultiSelect/MultiSelect.js +113 -0
- package/dist/MultiSelect/MultiSelect.manifest.js +51 -0
- package/dist/MultiSelect/index.js +7 -0
- package/dist/NumberInput/NumberInput.js +210 -0
- package/dist/NumberInput/NumberInput.manifest.js +56 -0
- package/dist/NumberInput/index.js +7 -0
- package/dist/OperationalStatus/OperationalStatus.js +89 -0
- package/dist/OperationalStatus/OperationalStatus.manifest.js +39 -0
- package/dist/OperationalStatus/index.js +9 -0
- package/dist/PlaybackControls/PlaybackControls.js +289 -0
- package/dist/PlaybackControls/PlaybackControls.manifest.js +85 -0
- package/dist/PlaybackControls/index.js +7 -0
- package/dist/Popover/Popover.js +302 -0
- package/dist/Popover/Popover.manifest.js +50 -0
- package/dist/Popover/index.js +7 -0
- package/dist/Progress/Progress.js +132 -0
- package/dist/Progress/Progress.manifest.js +30 -0
- package/dist/Progress/index.js +7 -0
- package/dist/PropertyFilter/PropertyFilter.js +306 -0
- package/dist/PropertyFilter/PropertyFilter.manifest.js +32 -0
- package/dist/PropertyFilter/index.js +11 -0
- package/dist/PropertyFilter/tokenError.js +17 -0
- package/dist/RadioGroup/RadioGroup.js +143 -0
- package/dist/RadioGroup/RadioGroup.manifest.js +44 -0
- package/dist/RadioGroup/index.js +9 -0
- package/dist/Select/Select.js +219 -0
- package/dist/Select/Select.manifest.js +77 -0
- package/dist/Select/index.js +9 -0
- package/dist/Sidebar/Sidebar.js +146 -0
- package/dist/Sidebar/Sidebar.manifest.js +72 -0
- package/dist/Sidebar/index.js +18 -0
- package/dist/Skeleton/Skeleton.js +76 -0
- package/dist/Skeleton/Skeleton.manifest.js +30 -0
- package/dist/Skeleton/index.js +7 -0
- package/dist/Slider/Slider.js +246 -0
- package/dist/Slider/Slider.manifest.js +56 -0
- package/dist/Slider/index.js +7 -0
- package/dist/Sparkline/Sparkline.js +135 -0
- package/dist/Sparkline/Sparkline.manifest.js +37 -0
- package/dist/Sparkline/index.js +7 -0
- package/dist/SplitPane/SplitPane.js +316 -0
- package/dist/SplitPane/SplitPane.manifest.js +79 -0
- package/dist/SplitPane/index.js +7 -0
- package/dist/StatCard/StatCard.js +163 -0
- package/dist/StatCard/StatCard.manifest.js +45 -0
- package/dist/StatCard/index.js +7 -0
- package/dist/Tabs/Tabs.js +181 -0
- package/dist/Tabs/Tabs.manifest.js +72 -0
- package/dist/Tabs/index.js +16 -0
- package/dist/Tabs/useTabsIndicator.js +71 -0
- package/dist/Tabs/useTabsScroll.js +123 -0
- package/dist/TagGroup/TagGroup.js +142 -0
- package/dist/TagGroup/TagGroup.manifest.js +35 -0
- package/dist/TagGroup/index.js +7 -0
- package/dist/Textarea/Textarea.js +68 -0
- package/dist/Textarea/Textarea.manifest.js +25 -0
- package/dist/Textarea/index.js +7 -0
- package/dist/TimeField/TimeField.js +118 -0
- package/dist/TimeField/TimeField.manifest.js +42 -0
- package/dist/TimeField/index.js +7 -0
- package/dist/TimeRange/TimeRange.js +184 -0
- package/dist/TimeRange/TimeRange.manifest.js +48 -0
- package/dist/TimeRange/index.js +9 -0
- package/dist/Toast/Toast.js +188 -0
- package/dist/Toast/Toast.manifest.js +77 -0
- package/dist/Toast/index.js +9 -0
- package/dist/Toggle/Toggle.js +154 -0
- package/dist/Toggle/Toggle.manifest.js +54 -0
- package/dist/Toggle/index.js +7 -0
- package/dist/Toolbar/Toolbar.js +86 -0
- package/dist/Toolbar/Toolbar.manifest.js +70 -0
- package/dist/Toolbar/index.js +12 -0
- package/dist/Tooltip/Tooltip.js +123 -0
- package/dist/Tooltip/Tooltip.manifest.js +27 -0
- package/dist/Tooltip/index.js +7 -0
- package/dist/TreeView/TreeView.js +129 -0
- package/dist/TreeView/TreeView.manifest.js +56 -0
- package/dist/TreeView/index.js +7 -0
- package/dist/UploadQueue/UploadQueue.js +296 -0
- package/dist/UploadQueue/UploadQueue.manifest.js +34 -0
- package/dist/UploadQueue/index.js +7 -0
- package/dist/_internal/MotionPopover.js +113 -0
- package/dist/_internal/aria.js +40 -0
- package/dist/_internal/bytes.js +18 -0
- package/dist/_internal/controlStyles.js +26 -0
- package/dist/_internal/date.js +179 -0
- package/dist/_internal/devValidate.js +51 -0
- package/dist/_internal/fieldIds.js +50 -0
- package/dist/_internal/hydration.js +74 -0
- package/dist/_internal/manifest-entry.js +0 -0
- package/dist/_internal/mergeRefs.js +68 -0
- package/dist/_internal/motion.js +138 -0
- package/dist/_internal/navigationLandmark.js +13 -0
- package/dist/_internal/numberText.js +176 -0
- package/dist/_internal/overlay.js +53 -0
- package/dist/_internal/segmentField.js +125 -0
- package/dist/_internal/suggestions.js +20 -0
- package/dist/_internal/timestamp.js +25 -0
- package/dist/_internal/unavailable.js +13 -0
- package/dist/_internal/useActionFocus.js +27 -0
- package/dist/_internal/useElementWidth.js +37 -0
- package/dist/_internal/useIsMounted.js +18 -0
- package/dist/_internal/useIsomorphicLayoutEffect.js +8 -0
- package/dist/_internal/useRestoreFocusOnRemoval.js +57 -0
- package/dist/index.cjs +17831 -0
- package/dist/index.d.cts +2330 -0
- package/dist/index.d.ts +2330 -0
- package/dist/index.js +407 -0
- package/dist/version.js +8 -0
- package/package.json +80 -3
|
@@ -0,0 +1,459 @@
|
|
|
1
|
+
"use client";
|
|
2
|
+
|
|
3
|
+
// src/DataGrid/DataGrid.tsx
|
|
4
|
+
import {
|
|
5
|
+
forwardRef,
|
|
6
|
+
useEffect,
|
|
7
|
+
useId,
|
|
8
|
+
useMemo,
|
|
9
|
+
useRef,
|
|
10
|
+
useState
|
|
11
|
+
} from "react";
|
|
12
|
+
import clsx from "clsx";
|
|
13
|
+
import { Button } from "../Button/Button.js";
|
|
14
|
+
import { Checkbox } from "../Checkbox/Checkbox.js";
|
|
15
|
+
import {
|
|
16
|
+
DataTable
|
|
17
|
+
} from "../DataTable/DataTable.js";
|
|
18
|
+
import { Select, SelectOption } from "../Select/Select.js";
|
|
19
|
+
import { sortedOrder } from "../DataTable/sort.js";
|
|
20
|
+
import { devValidate } from "../_internal/devValidate.js";
|
|
21
|
+
import { DataGridManifest } from "./DataGrid.manifest.js";
|
|
22
|
+
import { PageControls } from "./PageControls.js";
|
|
23
|
+
import { jsx, jsxs } from "react/jsx-runtime";
|
|
24
|
+
function ColumnWidthInput({
|
|
25
|
+
value,
|
|
26
|
+
min,
|
|
27
|
+
max,
|
|
28
|
+
disabled,
|
|
29
|
+
label,
|
|
30
|
+
onCommit
|
|
31
|
+
}) {
|
|
32
|
+
const [draft, setDraft] = useState(null);
|
|
33
|
+
useEffect(() => setDraft(null), [value]);
|
|
34
|
+
const text = draft?.base === value ? draft.text : String(value);
|
|
35
|
+
const commit = (requested) => {
|
|
36
|
+
setDraft(null);
|
|
37
|
+
if (!disabled && Number.isFinite(requested)) onCommit(Math.min(max, Math.max(min, requested)));
|
|
38
|
+
};
|
|
39
|
+
return /* @__PURE__ */ jsx(
|
|
40
|
+
"input",
|
|
41
|
+
{
|
|
42
|
+
type: "number",
|
|
43
|
+
"aria-label": label,
|
|
44
|
+
min,
|
|
45
|
+
max,
|
|
46
|
+
step: 1,
|
|
47
|
+
value: text,
|
|
48
|
+
disabled,
|
|
49
|
+
className: "h-oprt-md w-12u border border-oprt-border-control bg-oprt-surface-2 px-1u font-mono text-oprt-base font-medium focus-visible:outline-hidden focus-visible:border-oprt-border-focus focus-visible:shadow-oprt-focus disabled:cursor-not-allowed disabled:text-oprt-text-dim",
|
|
50
|
+
onChange: (event) => setDraft({ text: event.target.value, base: value }),
|
|
51
|
+
onBlur: () => {
|
|
52
|
+
if (draft?.base === value) commit(text.trim() === "" ? Number.NaN : Number(text));
|
|
53
|
+
},
|
|
54
|
+
onKeyDown: (event) => {
|
|
55
|
+
if (event.key === "Escape") {
|
|
56
|
+
event.preventDefault();
|
|
57
|
+
setDraft(null);
|
|
58
|
+
return;
|
|
59
|
+
}
|
|
60
|
+
const base = text.trim() !== "" && Number.isFinite(Number(text)) ? Number(text) : value;
|
|
61
|
+
const next = event.key === "Enter" ? text.trim() === "" ? Number.NaN : Number(text) : event.key === "Home" ? min : event.key === "End" ? max : event.key === "ArrowUp" || event.key === "ArrowRight" ? base + 8 : event.key === "ArrowDown" || event.key === "ArrowLeft" ? base - 8 : void 0;
|
|
62
|
+
if (next !== void 0) {
|
|
63
|
+
event.preventDefault();
|
|
64
|
+
commit(next);
|
|
65
|
+
}
|
|
66
|
+
}
|
|
67
|
+
}
|
|
68
|
+
);
|
|
69
|
+
}
|
|
70
|
+
function withoutPage(selection, pageIds) {
|
|
71
|
+
const onPage = new Set(pageIds);
|
|
72
|
+
return selection.filter((id) => !onPage.has(id));
|
|
73
|
+
}
|
|
74
|
+
var DataGrid = forwardRef((allProps, ref) => {
|
|
75
|
+
const {
|
|
76
|
+
columns,
|
|
77
|
+
data,
|
|
78
|
+
getRowId,
|
|
79
|
+
caption = "Data grid",
|
|
80
|
+
selectedRowIds,
|
|
81
|
+
onSelectionChange,
|
|
82
|
+
sort,
|
|
83
|
+
onSortChange,
|
|
84
|
+
page,
|
|
85
|
+
onPageChange,
|
|
86
|
+
pageSize = 10,
|
|
87
|
+
mode = "client",
|
|
88
|
+
rowCount,
|
|
89
|
+
visibleColumnKeys,
|
|
90
|
+
onVisibleColumnsChange,
|
|
91
|
+
columnWidths,
|
|
92
|
+
onColumnWidthsChange,
|
|
93
|
+
pinnedColumnKeys,
|
|
94
|
+
onPinnedColumnsChange,
|
|
95
|
+
virtualization,
|
|
96
|
+
viewMode,
|
|
97
|
+
onViewModeChange,
|
|
98
|
+
loading = false,
|
|
99
|
+
disabled = false,
|
|
100
|
+
dense = false,
|
|
101
|
+
emptyMessage = "No results.",
|
|
102
|
+
onRowClick,
|
|
103
|
+
className,
|
|
104
|
+
...props
|
|
105
|
+
} = allProps;
|
|
106
|
+
if (process.env.NODE_ENV !== "production") {
|
|
107
|
+
devValidate("DataGrid", DataGridManifest.DataGrid.props, allProps);
|
|
108
|
+
}
|
|
109
|
+
const [localSelection, setLocalSelection] = useState([]);
|
|
110
|
+
const [localSort, setLocalSort] = useState(null);
|
|
111
|
+
const [localPage, setLocalPage] = useState(1);
|
|
112
|
+
const [hiddenColumns, setHiddenColumns] = useState([]);
|
|
113
|
+
const [columnsOpen, setColumnsOpen] = useState(false);
|
|
114
|
+
const [localWidths, setLocalWidths] = useState({});
|
|
115
|
+
const [localPinned, setLocalPinned] = useState([]);
|
|
116
|
+
const [localView, setLocalView] = useState("virtualized");
|
|
117
|
+
const columnsId = useId();
|
|
118
|
+
const blocked = disabled || loading;
|
|
119
|
+
const selection = selectedRowIds ?? localSelection;
|
|
120
|
+
const selectionSet = useMemo(() => new Set(selection), [selection]);
|
|
121
|
+
const selectionEnabled = selectedRowIds !== void 0 || Boolean(onSelectionChange);
|
|
122
|
+
const effectiveSort = sort === void 0 ? localSort : sort;
|
|
123
|
+
const visibleKeys = visibleColumnKeys ?? columns.filter((column) => !hiddenColumns.includes(column.key)).map((column) => column.key);
|
|
124
|
+
const widths = columnWidths ?? localWidths;
|
|
125
|
+
const pinned = [...new Set(pinnedColumnKeys ?? localPinned)].filter(
|
|
126
|
+
(key) => columns.some((column) => column.key === key)
|
|
127
|
+
);
|
|
128
|
+
const visibleColumns = [
|
|
129
|
+
...pinned.flatMap(
|
|
130
|
+
(key) => columns.filter((column) => column.key === key && visibleKeys.includes(key))
|
|
131
|
+
),
|
|
132
|
+
...columns.filter((column) => visibleKeys.includes(column.key) && !pinned.includes(column.key))
|
|
133
|
+
];
|
|
134
|
+
const virtual = Boolean(virtualization) && (viewMode ?? localView) === "virtualized";
|
|
135
|
+
const widthBounds = (column) => {
|
|
136
|
+
const min = Number.isFinite(column.minWidth) ? Math.max(48, column.minWidth) : 96;
|
|
137
|
+
const max = Number.isFinite(column.maxWidth) ? Math.max(min, column.maxWidth) : Math.max(min, 640);
|
|
138
|
+
return { min, max };
|
|
139
|
+
};
|
|
140
|
+
const widthFor = (column) => {
|
|
141
|
+
const { min, max } = widthBounds(column);
|
|
142
|
+
const requested = widths[column.key] ?? (column.width?.endsWith("px") ? Number.parseFloat(column.width) : 160);
|
|
143
|
+
return Math.min(max, Math.max(min, Number.isFinite(requested) ? requested : 160));
|
|
144
|
+
};
|
|
145
|
+
const resizeColumn = (column, requested) => {
|
|
146
|
+
if (blocked || !Number.isFinite(requested)) return;
|
|
147
|
+
const { min, max } = widthBounds(column);
|
|
148
|
+
const next = { ...widths, [column.key]: Math.min(max, Math.max(min, requested)) };
|
|
149
|
+
if (columnWidths === void 0) setLocalWidths(next);
|
|
150
|
+
onColumnWidthsChange?.(next);
|
|
151
|
+
};
|
|
152
|
+
const safePageSize = Number.isFinite(pageSize) && pageSize >= 1 ? Math.floor(pageSize) : 10;
|
|
153
|
+
const count = mode === "server" && rowCount !== void 0 && Number.isFinite(rowCount) ? Math.max(0, Math.floor(rowCount)) : data.length;
|
|
154
|
+
const pageCount = Math.max(1, Math.ceil(count / safePageSize));
|
|
155
|
+
const requestedPage = page ?? localPage;
|
|
156
|
+
const currentPage = Math.min(
|
|
157
|
+
pageCount,
|
|
158
|
+
Math.max(1, Number.isFinite(requestedPage) ? Math.floor(requestedPage) : 1)
|
|
159
|
+
);
|
|
160
|
+
const correction = useRef(null);
|
|
161
|
+
useEffect(() => {
|
|
162
|
+
if (requestedPage === currentPage) {
|
|
163
|
+
correction.current = null;
|
|
164
|
+
return;
|
|
165
|
+
}
|
|
166
|
+
const key = `${requestedPage}:${currentPage}`;
|
|
167
|
+
if (correction.current === key) return;
|
|
168
|
+
correction.current = key;
|
|
169
|
+
if (page === void 0) setLocalPage(currentPage);
|
|
170
|
+
onPageChange?.(currentPage);
|
|
171
|
+
}, [requestedPage, currentPage, page, onPageChange]);
|
|
172
|
+
const changePage = (next) => {
|
|
173
|
+
if (blocked) return;
|
|
174
|
+
if (page === void 0) setLocalPage(next);
|
|
175
|
+
onPageChange?.(next);
|
|
176
|
+
};
|
|
177
|
+
const changeSort = (next) => {
|
|
178
|
+
if (blocked) return;
|
|
179
|
+
if (sort === void 0) setLocalSort(next);
|
|
180
|
+
onSortChange?.(next);
|
|
181
|
+
};
|
|
182
|
+
const changeSelection = (next) => {
|
|
183
|
+
if (blocked) return;
|
|
184
|
+
if (selectedRowIds === void 0) setLocalSelection(next);
|
|
185
|
+
onSelectionChange?.(next);
|
|
186
|
+
};
|
|
187
|
+
const sortColumn = columns.find(
|
|
188
|
+
(column) => column.key === effectiveSort?.key && column.sortable !== false
|
|
189
|
+
);
|
|
190
|
+
const sortKey = sortColumn?.key;
|
|
191
|
+
const sortCompare = sortColumn?.compare;
|
|
192
|
+
const direction = effectiveSort?.direction;
|
|
193
|
+
const sorted = useMemo(() => {
|
|
194
|
+
if (mode !== "client" || sortKey === void 0 || direction === void 0) return data;
|
|
195
|
+
return sortedOrder(
|
|
196
|
+
data.map((row) => row[sortKey]),
|
|
197
|
+
direction === "asc" ? 1 : -1,
|
|
198
|
+
sortCompare
|
|
199
|
+
).map((position) => data[position]);
|
|
200
|
+
}, [data, mode, sortKey, direction, sortCompare]);
|
|
201
|
+
const pageStart = (currentPage - 1) * safePageSize;
|
|
202
|
+
const paged = mode === "client" && !virtual;
|
|
203
|
+
const pageRows = useMemo(
|
|
204
|
+
() => paged ? sorted.slice(pageStart, pageStart + safePageSize) : sorted,
|
|
205
|
+
[sorted, paged, pageStart, safePageSize]
|
|
206
|
+
);
|
|
207
|
+
const latestGetRowId = useRef(getRowId);
|
|
208
|
+
latestGetRowId.current = getRowId;
|
|
209
|
+
const pageIdsOf = useMemo(() => {
|
|
210
|
+
let ids = null;
|
|
211
|
+
return () => ids ??= pageRows.map((row) => latestGetRowId.current(row));
|
|
212
|
+
}, [pageRows]);
|
|
213
|
+
const { allSelected, someSelected } = useMemo(() => {
|
|
214
|
+
if (selectionSet.size === 0) return { allSelected: false, someSelected: false };
|
|
215
|
+
const pageIds = pageIdsOf();
|
|
216
|
+
let selected = 0;
|
|
217
|
+
for (const id of pageIds) if (selectionSet.has(id)) selected++;
|
|
218
|
+
return {
|
|
219
|
+
allSelected: pageIds.length > 0 && selected === pageIds.length,
|
|
220
|
+
someSelected: selected > 0
|
|
221
|
+
};
|
|
222
|
+
}, [pageIdsOf, selectionSet]);
|
|
223
|
+
let selectionKey = "__oprt_selection";
|
|
224
|
+
while (columns.some((column) => column.key === selectionKey)) selectionKey += "_";
|
|
225
|
+
const tableColumns = visibleColumns.map(
|
|
226
|
+
({ compare: _compare, minWidth: _min, maxWidth: _max, ...column }) => column
|
|
227
|
+
);
|
|
228
|
+
if (selectionEnabled)
|
|
229
|
+
tableColumns.push({
|
|
230
|
+
key: selectionKey,
|
|
231
|
+
label: "SELECT",
|
|
232
|
+
render: (_value, row) => {
|
|
233
|
+
const id = getRowId(row);
|
|
234
|
+
return /* @__PURE__ */ jsx(
|
|
235
|
+
Checkbox,
|
|
236
|
+
{
|
|
237
|
+
"aria-label": `Select row ${id}`,
|
|
238
|
+
checked: selectionSet.has(id),
|
|
239
|
+
disabled: blocked,
|
|
240
|
+
onCheckedChange: (checked) => changeSelection(
|
|
241
|
+
checked ? [.../* @__PURE__ */ new Set([...selection, id])] : selection.filter((key) => key !== id)
|
|
242
|
+
)
|
|
243
|
+
}
|
|
244
|
+
);
|
|
245
|
+
}
|
|
246
|
+
});
|
|
247
|
+
const sized = virtual || pinned.length > 0 || Object.keys(widths).length > 0;
|
|
248
|
+
const tableWidths = Object.fromEntries(
|
|
249
|
+
visibleColumns.map((column) => [column.key, widthFor(column)])
|
|
250
|
+
);
|
|
251
|
+
if (selectionEnabled) tableWidths[selectionKey] = 96;
|
|
252
|
+
const sortableColumns = columns.filter((column) => column.sortable !== false);
|
|
253
|
+
let unsortedKey = "__oprt_unsorted";
|
|
254
|
+
while (columns.some((column) => column.key === unsortedKey)) unsortedKey += "_";
|
|
255
|
+
return /* @__PURE__ */ jsxs(
|
|
256
|
+
"div",
|
|
257
|
+
{
|
|
258
|
+
ref,
|
|
259
|
+
className: clsx(
|
|
260
|
+
"flex min-w-0 flex-col gap-2u font-sans text-oprt-base normal-case text-oprt-text",
|
|
261
|
+
className
|
|
262
|
+
),
|
|
263
|
+
...props,
|
|
264
|
+
children: [
|
|
265
|
+
/* @__PURE__ */ jsxs(
|
|
266
|
+
"div",
|
|
267
|
+
{
|
|
268
|
+
className: "flex flex-wrap items-center gap-x-2u gap-y-1u",
|
|
269
|
+
"aria-label": `${caption} controls`,
|
|
270
|
+
role: "group",
|
|
271
|
+
children: [
|
|
272
|
+
sortableColumns.length > 0 && /* @__PURE__ */ jsxs("div", { className: "flex flex-wrap items-center gap-1u", role: "group", "aria-label": "Sort order", children: [
|
|
273
|
+
/* @__PURE__ */ jsxs(
|
|
274
|
+
Select,
|
|
275
|
+
{
|
|
276
|
+
"aria-label": "SORT BY",
|
|
277
|
+
size: "sm",
|
|
278
|
+
value: sortColumn ? sortColumn.key : unsortedKey,
|
|
279
|
+
disabled: blocked,
|
|
280
|
+
onValueChange: (key) => changeSort(
|
|
281
|
+
key === unsortedKey ? null : { key, direction: effectiveSort?.direction ?? "asc" }
|
|
282
|
+
),
|
|
283
|
+
children: [
|
|
284
|
+
/* @__PURE__ */ jsx(SelectOption, { value: unsortedKey, children: "SOURCE ORDER" }),
|
|
285
|
+
sortableColumns.map((column) => /* @__PURE__ */ jsx(SelectOption, { value: column.key, children: column.label }, column.key))
|
|
286
|
+
]
|
|
287
|
+
}
|
|
288
|
+
),
|
|
289
|
+
/* @__PURE__ */ jsx(
|
|
290
|
+
Button,
|
|
291
|
+
{
|
|
292
|
+
variant: "tertiary",
|
|
293
|
+
size: "sm",
|
|
294
|
+
disabled: blocked || !sortColumn,
|
|
295
|
+
onClick: () => effectiveSort && changeSort({
|
|
296
|
+
...effectiveSort,
|
|
297
|
+
direction: effectiveSort.direction === "asc" ? "desc" : "asc"
|
|
298
|
+
}),
|
|
299
|
+
children: effectiveSort?.direction === "desc" ? "DESCENDING" : "ASCENDING"
|
|
300
|
+
}
|
|
301
|
+
)
|
|
302
|
+
] }),
|
|
303
|
+
/* @__PURE__ */ jsx(
|
|
304
|
+
Button,
|
|
305
|
+
{
|
|
306
|
+
variant: "tertiary",
|
|
307
|
+
size: "sm",
|
|
308
|
+
disabled: blocked,
|
|
309
|
+
"aria-expanded": columnsOpen,
|
|
310
|
+
"aria-controls": columnsOpen ? columnsId : void 0,
|
|
311
|
+
onClick: () => setColumnsOpen(!columnsOpen),
|
|
312
|
+
children: "COLUMNS"
|
|
313
|
+
}
|
|
314
|
+
),
|
|
315
|
+
virtualization && /* @__PURE__ */ jsx(
|
|
316
|
+
Button,
|
|
317
|
+
{
|
|
318
|
+
variant: "tertiary",
|
|
319
|
+
size: "sm",
|
|
320
|
+
disabled: blocked,
|
|
321
|
+
onClick: () => {
|
|
322
|
+
const next = virtual ? "paginated" : "virtualized";
|
|
323
|
+
if (viewMode === void 0) setLocalView(next);
|
|
324
|
+
onViewModeChange?.(next);
|
|
325
|
+
},
|
|
326
|
+
children: virtual ? "Use paginated view" : "Use virtualized view"
|
|
327
|
+
}
|
|
328
|
+
),
|
|
329
|
+
selectionEnabled && /* @__PURE__ */ jsxs("div", { className: "inline-flex items-center gap-1u font-medium tracking-oprt-caps", children: [
|
|
330
|
+
/* @__PURE__ */ jsx(
|
|
331
|
+
Checkbox,
|
|
332
|
+
{
|
|
333
|
+
"aria-label": virtual && mode === "client" ? "Select results" : "Select page",
|
|
334
|
+
checked: allSelected ? true : someSelected ? "indeterminate" : false,
|
|
335
|
+
disabled: blocked || pageRows.length === 0,
|
|
336
|
+
onCheckedChange: (checked) => changeSelection(
|
|
337
|
+
checked ? [.../* @__PURE__ */ new Set([...selection, ...pageIdsOf()])] : withoutPage(selection, pageIdsOf())
|
|
338
|
+
)
|
|
339
|
+
}
|
|
340
|
+
),
|
|
341
|
+
virtual && mode === "client" ? "SELECT RESULTS" : "SELECT PAGE"
|
|
342
|
+
] })
|
|
343
|
+
]
|
|
344
|
+
}
|
|
345
|
+
),
|
|
346
|
+
columnsOpen && /* @__PURE__ */ jsxs(
|
|
347
|
+
"fieldset",
|
|
348
|
+
{
|
|
349
|
+
id: columnsId,
|
|
350
|
+
className: "m-0 flex flex-wrap gap-2u border border-oprt-border p-2u",
|
|
351
|
+
children: [
|
|
352
|
+
/* @__PURE__ */ jsx("legend", { className: "px-1u font-medium tracking-oprt-caps", children: "COLUMN SETTINGS" }),
|
|
353
|
+
columns.map((column) => /* @__PURE__ */ jsxs("div", { className: "flex flex-col gap-1u font-medium", children: [
|
|
354
|
+
/* @__PURE__ */ jsxs("div", { className: "inline-flex items-center gap-1u", children: [
|
|
355
|
+
/* @__PURE__ */ jsx(
|
|
356
|
+
Checkbox,
|
|
357
|
+
{
|
|
358
|
+
"aria-label": column.label,
|
|
359
|
+
checked: visibleKeys.includes(column.key),
|
|
360
|
+
disabled: blocked,
|
|
361
|
+
onCheckedChange: (checked) => {
|
|
362
|
+
const next = checked ? [.../* @__PURE__ */ new Set([...visibleKeys, column.key])] : visibleKeys.filter((key) => key !== column.key);
|
|
363
|
+
if (visibleColumnKeys === void 0)
|
|
364
|
+
setHiddenColumns(
|
|
365
|
+
columns.filter((item) => !next.includes(item.key)).map((item) => item.key)
|
|
366
|
+
);
|
|
367
|
+
onVisibleColumnsChange?.(next);
|
|
368
|
+
}
|
|
369
|
+
}
|
|
370
|
+
),
|
|
371
|
+
column.label
|
|
372
|
+
] }),
|
|
373
|
+
/* @__PURE__ */ jsxs("div", { className: "inline-flex items-center gap-1u", children: [
|
|
374
|
+
/* @__PURE__ */ jsx(
|
|
375
|
+
Checkbox,
|
|
376
|
+
{
|
|
377
|
+
"aria-label": `Pin to start: ${column.label}`,
|
|
378
|
+
checked: pinned.includes(column.key),
|
|
379
|
+
disabled: blocked,
|
|
380
|
+
onCheckedChange: (checked) => {
|
|
381
|
+
const next = checked ? [...pinned, column.key] : pinned.filter((key) => key !== column.key);
|
|
382
|
+
if (pinnedColumnKeys === void 0) setLocalPinned(next);
|
|
383
|
+
onPinnedColumnsChange?.(next);
|
|
384
|
+
}
|
|
385
|
+
}
|
|
386
|
+
),
|
|
387
|
+
"Pin to start"
|
|
388
|
+
] }),
|
|
389
|
+
/* @__PURE__ */ jsxs("label", { className: "m-0 flex flex-col gap-1u font-medium", children: [
|
|
390
|
+
column.label,
|
|
391
|
+
" width",
|
|
392
|
+
/* @__PURE__ */ jsxs("span", { className: "inline-flex items-center gap-1u", children: [
|
|
393
|
+
/* @__PURE__ */ jsx(
|
|
394
|
+
ColumnWidthInput,
|
|
395
|
+
{
|
|
396
|
+
label: `${column.label} width`,
|
|
397
|
+
min: widthBounds(column).min,
|
|
398
|
+
max: widthBounds(column).max,
|
|
399
|
+
value: widthFor(column),
|
|
400
|
+
disabled: blocked,
|
|
401
|
+
onCommit: (next) => resizeColumn(column, next)
|
|
402
|
+
}
|
|
403
|
+
),
|
|
404
|
+
/* @__PURE__ */ jsx("span", { className: "font-mono text-oprt-text-dim", children: "px" })
|
|
405
|
+
] })
|
|
406
|
+
] })
|
|
407
|
+
] }, column.key))
|
|
408
|
+
]
|
|
409
|
+
}
|
|
410
|
+
),
|
|
411
|
+
visibleColumns.length === 0 ? /* @__PURE__ */ jsx("p", { className: "m-0 border border-oprt-border p-3u text-oprt-text-dim", children: "Choose a column to display results." }) : /* @__PURE__ */ jsx(
|
|
412
|
+
DataTable,
|
|
413
|
+
{
|
|
414
|
+
columns: tableColumns,
|
|
415
|
+
data: pageRows,
|
|
416
|
+
sortDescriptor: sortColumn ? effectiveSort : null,
|
|
417
|
+
caption,
|
|
418
|
+
dense,
|
|
419
|
+
emptyMessage,
|
|
420
|
+
"aria-busy": loading,
|
|
421
|
+
getRowId,
|
|
422
|
+
totalRowCount: count,
|
|
423
|
+
rowIndexOffset: mode === "client" && virtual ? 0 : (currentPage - 1) * safePageSize,
|
|
424
|
+
pinnedColumnKeys: pinned,
|
|
425
|
+
...sized ? { columnWidths: tableWidths } : {},
|
|
426
|
+
...virtual && virtualization ? { virtualization } : {},
|
|
427
|
+
...onRowClick && !blocked ? {
|
|
428
|
+
onRowClick: (row) => {
|
|
429
|
+
onRowClick(row, data.indexOf(row));
|
|
430
|
+
}
|
|
431
|
+
} : {}
|
|
432
|
+
}
|
|
433
|
+
),
|
|
434
|
+
/* @__PURE__ */ jsx("p", { role: "status", className: loading ? "m-0 text-oprt-text-dim" : "sr-only", children: loading ? "Loading results." : "" }),
|
|
435
|
+
/* @__PURE__ */ jsxs("div", { className: "flex flex-wrap items-center justify-between gap-2u", children: [
|
|
436
|
+
/* @__PURE__ */ jsxs("p", { className: "m-0 font-mono tabular-nums text-oprt-text-dim", children: [
|
|
437
|
+
count,
|
|
438
|
+
" ",
|
|
439
|
+
count === 1 ? "ROW" : "ROWS",
|
|
440
|
+
selectionEnabled ? ` \xB7 ${selection.length} SELECTED` : ""
|
|
441
|
+
] }),
|
|
442
|
+
(!virtual || mode === "server") && /* @__PURE__ */ jsx(
|
|
443
|
+
PageControls,
|
|
444
|
+
{
|
|
445
|
+
page: currentPage,
|
|
446
|
+
pageCount,
|
|
447
|
+
disabled: blocked,
|
|
448
|
+
onPageChange: changePage
|
|
449
|
+
}
|
|
450
|
+
)
|
|
451
|
+
] })
|
|
452
|
+
]
|
|
453
|
+
}
|
|
454
|
+
);
|
|
455
|
+
});
|
|
456
|
+
DataGrid.displayName = "DataGrid";
|
|
457
|
+
export {
|
|
458
|
+
DataGrid
|
|
459
|
+
};
|
|
@@ -0,0 +1,135 @@
|
|
|
1
|
+
// src/DataGrid/DataGrid.manifest.ts
|
|
2
|
+
var DataGridManifest = {
|
|
3
|
+
DataGrid: {
|
|
4
|
+
description: "Native table with stable-ID selection, sorting, controlled column widths and pinning, saved-view state, pagination, and optional virtualization.",
|
|
5
|
+
props: {
|
|
6
|
+
columns: {
|
|
7
|
+
type: "array",
|
|
8
|
+
required: true,
|
|
9
|
+
description: "DataTableColumn descriptors plus render(value, originalRow) for display and compare(a, b) for raw-value sorting. compare must be pure; a new compare function sorts again, so define columns outside render or memoize them. Columns sort unless sortable is false. Keys must be unique.",
|
|
10
|
+
items: {
|
|
11
|
+
key: "string (required, unique)",
|
|
12
|
+
label: "string (required)",
|
|
13
|
+
as: "text | number | code | timestamp | badge",
|
|
14
|
+
highlight: "boolean (default: false)",
|
|
15
|
+
width: "string (CSS width; a px value seeds the column width)",
|
|
16
|
+
align: "left | right",
|
|
17
|
+
sortable: "boolean",
|
|
18
|
+
render: "(value, row) => ReactNode",
|
|
19
|
+
compare: "(a, b) => number",
|
|
20
|
+
minWidth: "number (CSS pixels; default 96; minimum 48)",
|
|
21
|
+
maxWidth: "number (CSS pixels; default 640)"
|
|
22
|
+
}
|
|
23
|
+
},
|
|
24
|
+
data: {
|
|
25
|
+
type: "array",
|
|
26
|
+
required: true,
|
|
27
|
+
description: "Client mode: complete filtered row set. Server mode: current page only; order and row count are preserved."
|
|
28
|
+
},
|
|
29
|
+
getRowId: {
|
|
30
|
+
type: "function",
|
|
31
|
+
required: true,
|
|
32
|
+
description: "(originalRow) => string. Return a unique, stable ID across filtering, sorting, and pagination; do not use an array index. Keep it pure: IDs are read again only when data changes, not when only the function does."
|
|
33
|
+
},
|
|
34
|
+
caption: {
|
|
35
|
+
type: "string",
|
|
36
|
+
default: "Data grid",
|
|
37
|
+
description: "Accessible native table caption and controls group name."
|
|
38
|
+
},
|
|
39
|
+
selectedRowIds: {
|
|
40
|
+
type: "array",
|
|
41
|
+
description: "Controlled IDs. Supplying this or onSelectionChange enables selection. IDs outside the displayed data are preserved."
|
|
42
|
+
},
|
|
43
|
+
onSelectionChange: {
|
|
44
|
+
type: "function",
|
|
45
|
+
description: "(ids: string[]) => void. Select page changes only current-page IDs. Without selectedRowIds, selection is stored internally."
|
|
46
|
+
},
|
|
47
|
+
sort: {
|
|
48
|
+
type: "node",
|
|
49
|
+
description: "Controlled { key: string, direction: 'asc' | 'desc' } or null for source order. Omit for internal sorting state. Uses raw values before custom rendering and announces the active direction with aria-sort on the corresponding table header."
|
|
50
|
+
},
|
|
51
|
+
onSortChange: {
|
|
52
|
+
type: "function",
|
|
53
|
+
description: "(sort: DataGridSort | null) => void. Server mode only reports the requested sort; the caller supplies sorted rows."
|
|
54
|
+
},
|
|
55
|
+
page: {
|
|
56
|
+
type: "number",
|
|
57
|
+
default: 1,
|
|
58
|
+
description: "One-based controlled page. Omit for internal pagination state. Out-of-range values are clamped and reported once through onPageChange."
|
|
59
|
+
},
|
|
60
|
+
onPageChange: {
|
|
61
|
+
type: "function",
|
|
62
|
+
description: "(page: number) => void. A supplied page remains controlled until its owner updates it."
|
|
63
|
+
},
|
|
64
|
+
pageSize: {
|
|
65
|
+
type: "number",
|
|
66
|
+
default: 10,
|
|
67
|
+
description: "Rows per client page and denominator for server page counts. Invalid or less-than-one values use 10; fractional values round down."
|
|
68
|
+
},
|
|
69
|
+
mode: { type: "enum", values: ["client", "server"], default: "client" },
|
|
70
|
+
rowCount: {
|
|
71
|
+
type: "number",
|
|
72
|
+
description: "Total filtered row count in server mode. Defaults to data.length; provide the total to enable navigation beyond the supplied page."
|
|
73
|
+
},
|
|
74
|
+
visibleColumnKeys: {
|
|
75
|
+
type: "array",
|
|
76
|
+
description: "Controlled displayed column keys. Omit for internal visibility state; all columns are visible initially. An empty list shows a recovery message."
|
|
77
|
+
},
|
|
78
|
+
onVisibleColumnsChange: {
|
|
79
|
+
type: "function",
|
|
80
|
+
description: "(keys: string[]) => void. Receives visibility changes from the COLUMNS controls."
|
|
81
|
+
},
|
|
82
|
+
columnWidths: {
|
|
83
|
+
type: "node",
|
|
84
|
+
description: "Controlled Record<columnKey, CSS pixel width>. Omit for internal widths. Values are clamped to each column's minWidth/maxWidth; default width is 160 or a pixel width from the descriptor. Stored keys outside the current columns are preserved in resize callbacks."
|
|
85
|
+
},
|
|
86
|
+
onColumnWidthsChange: {
|
|
87
|
+
type: "function",
|
|
88
|
+
description: "(widths: DataGridColumnWidths) => void. Columns controls support direct numeric entry, Arrow keys (8 pixels), and Home/End (bounds)."
|
|
89
|
+
},
|
|
90
|
+
pinnedColumnKeys: {
|
|
91
|
+
type: "array",
|
|
92
|
+
description: "Controlled leading-edge pinned keys in display order. Omit for internal state. Hidden pinned columns retain their preference; unknown keys are ignored for display."
|
|
93
|
+
},
|
|
94
|
+
onPinnedColumnsChange: {
|
|
95
|
+
type: "function",
|
|
96
|
+
description: "(keys: string[]) => void. Called by keyboard-accessible Pin checkboxes in Columns."
|
|
97
|
+
},
|
|
98
|
+
virtualization: {
|
|
99
|
+
type: "node",
|
|
100
|
+
description: "Opt-in { height: number, rowHeight?: number, estimateRowHeight?: number, overscan?: number }, CSS pixels. Fixed rowHeight clips overlong cell contents; omit rowHeight to measure wrapped rows with ResizeObserver, starting at estimateRowHeight (default 40). Minimum row height 24; default overscan 3, minimum 1. Client mode windows all filtered rows; server mode windows only the supplied page."
|
|
101
|
+
},
|
|
102
|
+
viewMode: {
|
|
103
|
+
type: "enum",
|
|
104
|
+
values: ["paginated", "virtualized"],
|
|
105
|
+
description: "Controlled display mode. Virtualization must be supplied for virtualized mode. Defaults to virtualized with configuration, paginated without it. The built-in toggle always offers a paginated native-table alternative."
|
|
106
|
+
},
|
|
107
|
+
onViewModeChange: {
|
|
108
|
+
type: "function",
|
|
109
|
+
description: "(mode: DataGridViewMode) => void. Controlled owners must apply the requested mode for the fallback toggle to update the table."
|
|
110
|
+
},
|
|
111
|
+
loading: {
|
|
112
|
+
type: "boolean",
|
|
113
|
+
default: false,
|
|
114
|
+
description: "Marks the table busy, announces loading, and disables grid-owned controls and row activation while retaining supplied data."
|
|
115
|
+
},
|
|
116
|
+
disabled: {
|
|
117
|
+
type: "boolean",
|
|
118
|
+
default: false,
|
|
119
|
+
description: "Disables grid-owned actions and row activation. Custom interactive cell content remains the caller's responsibility."
|
|
120
|
+
},
|
|
121
|
+
dense: { type: "boolean", default: false },
|
|
122
|
+
emptyMessage: { type: "string", default: "No results." },
|
|
123
|
+
onRowClick: {
|
|
124
|
+
type: "function",
|
|
125
|
+
description: "(originalRow, indexInSuppliedData) => void. Uses the existing DataTable's native first-cell button; independent cell controls do not activate the row."
|
|
126
|
+
}
|
|
127
|
+
},
|
|
128
|
+
composable_with: ["Card", "ComboBox"],
|
|
129
|
+
never_inside: ["DataTable", "DataGrid"],
|
|
130
|
+
example: '<DataGrid\n caption="Station telemetry"\n columns={[{ key: "name", label: "STATION" }, { key: "latency", label: "LATENCY / MS", as: "number" }]}\n data={rows}\n getRowId={(row) => String(row.id)}\n selectedRowIds={selected}\n onSelectionChange={setSelected}\n pageSize={10}\n/>'
|
|
131
|
+
}
|
|
132
|
+
};
|
|
133
|
+
export {
|
|
134
|
+
DataGridManifest
|
|
135
|
+
};
|
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
// src/DataGrid/PageControls.tsx
|
|
2
|
+
import { Button } from "../Button/Button.js";
|
|
3
|
+
import { jsx, jsxs } from "react/jsx-runtime";
|
|
4
|
+
function PageControls({
|
|
5
|
+
page,
|
|
6
|
+
pageCount,
|
|
7
|
+
disabled,
|
|
8
|
+
onPageChange
|
|
9
|
+
}) {
|
|
10
|
+
return /* @__PURE__ */ jsxs("div", { className: "flex flex-wrap items-center gap-1u", children: [
|
|
11
|
+
/* @__PURE__ */ jsx(
|
|
12
|
+
Button,
|
|
13
|
+
{
|
|
14
|
+
variant: "tertiary",
|
|
15
|
+
size: "sm",
|
|
16
|
+
disabled: disabled || page <= 1,
|
|
17
|
+
onClick: () => onPageChange(page - 1),
|
|
18
|
+
children: "PREVIOUS PAGE"
|
|
19
|
+
}
|
|
20
|
+
),
|
|
21
|
+
/* @__PURE__ */ jsxs("span", { className: "font-mono tabular-nums", "aria-live": "polite", children: [
|
|
22
|
+
"PAGE ",
|
|
23
|
+
page,
|
|
24
|
+
" OF ",
|
|
25
|
+
pageCount
|
|
26
|
+
] }),
|
|
27
|
+
/* @__PURE__ */ jsx(
|
|
28
|
+
Button,
|
|
29
|
+
{
|
|
30
|
+
variant: "tertiary",
|
|
31
|
+
size: "sm",
|
|
32
|
+
disabled: disabled || page >= pageCount,
|
|
33
|
+
onClick: () => onPageChange(page + 1),
|
|
34
|
+
children: "NEXT PAGE"
|
|
35
|
+
}
|
|
36
|
+
)
|
|
37
|
+
] });
|
|
38
|
+
}
|
|
39
|
+
export {
|
|
40
|
+
PageControls
|
|
41
|
+
};
|