@grampro/kit 2.7.1 → 2.7.3
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/.gbs/skills/gbs-components/SKILL.md +233 -207
- package/.gbs/skills/gbs-components/references/data-grid.md +9 -0
- package/.gbs/skills/gbs-components/references/forms.md +12 -0
- package/.gbs/skills/gbs-components/references/install.md +42 -5
- package/CHANGELOG.md +963 -798
- package/README.md +13 -4
- package/index.cjs +250 -138
- package/package.json +1 -1
- package/source/components/accordion/passport.json +1 -1
- package/source/components/alert/passport.json +1 -1
- package/source/components/avatar/passport.json +1 -1
- package/source/components/badge/passport.json +1 -1
- package/source/components/breadcrumb/passport.json +1 -1
- package/source/components/button/passport.json +1 -1
- package/source/components/card/passport.json +1 -1
- package/source/components/checkbox/passport.json +2 -2
- package/source/components/checkbox/passport.manual.json +1 -1
- package/source/components/checkbox/react/Checkbox.tsx +14 -0
- package/source/components/combobox/passport.json +3 -2
- package/source/components/combobox/passport.manual.json +1 -1
- package/source/components/combobox/react/MultiSelect.tsx +13 -0
- package/source/components/combobox/react/Select.tsx +13 -0
- package/source/components/combobox/react/surface.ts +70 -0
- package/source/components/data-grid/passport.json +6 -6
- package/source/components/data-grid/react/DataGrid.tsx +353 -351
- package/source/components/date-picker/passport.json +3 -2
- package/source/components/date-picker/passport.manual.json +1 -1
- package/source/components/date-picker/react/DatePicker.tsx +16 -2
- package/source/components/date-picker/react/DateRangePicker.tsx +16 -2
- package/source/components/date-picker/react/surface.ts +68 -0
- package/source/components/dialog/passport.json +1 -1
- package/source/components/file-uploader/passport.json +1 -1
- package/source/components/input/passport.json +2 -2
- package/source/components/input/passport.manual.json +1 -1
- package/source/components/input/react/Input.tsx +21 -0
- package/source/components/menu/passport.json +1 -1
- package/source/components/modal/passport.json +1 -1
- package/source/components/number-input/passport.json +2 -2
- package/source/components/number-input/passport.manual.json +1 -1
- package/source/components/number-input/react/NumberInput.tsx +30 -0
- package/source/components/popover/passport.json +1 -1
- package/source/components/progress/passport.json +1 -1
- package/source/components/radio-group/passport.json +2 -2
- package/source/components/radio-group/passport.manual.json +1 -1
- package/source/components/radio-group/react/RadioGroup.tsx +33 -0
- package/source/components/shared/core/agent/field-executors.ts +173 -137
- package/source/components/shared/core/agent/index.ts +21 -0
- package/source/components/shared/core/agent/surface.ts +437 -0
- package/source/components/shared/core/agent/webmcp.ts +332 -328
- package/source/components/shared/core/agent/write.ts +62 -58
- package/source/components/shared/index.ts +7 -0
- package/source/components/shared/react/AgentSurface.tsx +145 -0
- package/source/components/shared/react/agentSurfaceContext.ts +92 -0
- package/source/components/shared/react/useFieldAgent.ts +62 -88
- package/source/components/shared/version.json +4 -4
- package/source/components/shared/version.ts +6 -6
- package/source/components/skeleton/passport.json +1 -1
- package/source/components/spinner/passport.json +1 -1
- package/source/components/switch/passport.json +2 -2
- package/source/components/switch/passport.manual.json +1 -1
- package/source/components/switch/react/Switch.tsx +16 -0
- package/source/components/tabs/passport.json +1 -1
- package/source/components/textarea/passport.json +2 -2
- package/source/components/textarea/passport.manual.json +1 -1
- package/source/components/textarea/react/Textarea.tsx +16 -0
- package/source/components/toaster/passport.json +1 -1
- package/source/components/tooltip/passport.json +1 -1
- package/tools/doctor/baseline.cjs +228 -0
- package/tools/doctor/contract.cjs +252 -0
- package/tools/doctor/format.cjs +160 -0
- package/tools/doctor/index.cjs +246 -0
- package/tools/doctor/usage.cjs +95 -0
- package/tools/jsx-tags.cjs +120 -0
- package/tools/mcp/server.cjs +60 -41
- package/tools/passport/extract.cjs +22 -40
- package/tools/passport/hash.cjs +56 -0
- package/tools/passport/index.cjs +4 -2
- package/tools/passport/typescript.cjs +220 -0
- package/tools/prompt.cjs +205 -0
- package/tools/ui.cjs +67 -0
|
@@ -1,351 +1,353 @@
|
|
|
1
|
-
"use client";
|
|
2
|
-
|
|
3
|
-
import {
|
|
4
|
-
useDeferredValue,
|
|
5
|
-
useImperativeHandle,
|
|
6
|
-
useLayoutEffect,
|
|
7
|
-
useMemo,
|
|
8
|
-
useState,
|
|
9
|
-
type CSSProperties,
|
|
10
|
-
type ReactNode,
|
|
11
|
-
type Ref,
|
|
12
|
-
} from "react";
|
|
13
|
-
import { computeLayout, createSelectionColumn, resolveColumns } from "../core/columns";
|
|
14
|
-
import { filterRows } from "../core/filtering";
|
|
15
|
-
import { createGridEngine, type GridApi, type GridSnapshot } from "../core/grid";
|
|
16
|
-
import { buildRows, createRowIdGetter, paginate } from "../core/rows";
|
|
17
|
-
import { sortRows } from "../core/sorting";
|
|
18
|
-
import { shallowEqual } from "../core/store";
|
|
19
|
-
import type { Density, GridOptions } from "../core/types";
|
|
20
|
-
import { createFormatters } from "../core/values";
|
|
21
|
-
import { ColumnMenu } from "./ColumnMenu";
|
|
22
|
-
import { GridContext, cx, type GridContextValue, type GridSlot } from "./context";
|
|
23
|
-
import { usePopoverState, useStoreSelector } from "./hooks";
|
|
24
|
-
import { defaultLocaleText, type LocaleText } from "./locale";
|
|
25
|
-
import { Pagination } from "./Pagination";
|
|
26
|
-
import { Popover } from "./Popover";
|
|
27
|
-
import { Toolbar, type ToolbarOptions } from "./Toolbar";
|
|
28
|
-
import { AskGrid } from "./AskGrid";
|
|
29
|
-
import { createGridAgent, type GridAgent } from "../agent/engine";
|
|
30
|
-
import
|
|
31
|
-
import {
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
*
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
*
|
|
51
|
-
*
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
*
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
locale
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
*
|
|
73
|
-
*
|
|
74
|
-
*
|
|
75
|
-
*
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
const
|
|
86
|
-
const
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
*
|
|
141
|
-
*
|
|
142
|
-
*
|
|
143
|
-
*
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
const
|
|
162
|
-
const
|
|
163
|
-
const
|
|
164
|
-
const
|
|
165
|
-
const
|
|
166
|
-
const
|
|
167
|
-
const
|
|
168
|
-
const
|
|
169
|
-
|
|
170
|
-
const
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
const
|
|
181
|
-
const
|
|
182
|
-
|
|
183
|
-
const
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
const
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
const
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
const
|
|
223
|
-
|
|
224
|
-
|
|
225
|
-
|
|
226
|
-
|
|
227
|
-
|
|
228
|
-
|
|
229
|
-
|
|
230
|
-
|
|
231
|
-
|
|
232
|
-
|
|
233
|
-
|
|
234
|
-
|
|
235
|
-
|
|
236
|
-
|
|
237
|
-
|
|
238
|
-
|
|
239
|
-
|
|
240
|
-
|
|
241
|
-
|
|
242
|
-
|
|
243
|
-
|
|
244
|
-
|
|
245
|
-
|
|
246
|
-
|
|
247
|
-
|
|
248
|
-
|
|
249
|
-
|
|
250
|
-
|
|
251
|
-
|
|
252
|
-
|
|
253
|
-
|
|
254
|
-
|
|
255
|
-
|
|
256
|
-
|
|
257
|
-
|
|
258
|
-
|
|
259
|
-
|
|
260
|
-
|
|
261
|
-
|
|
262
|
-
|
|
263
|
-
|
|
264
|
-
|
|
265
|
-
|
|
266
|
-
|
|
267
|
-
|
|
268
|
-
|
|
269
|
-
|
|
270
|
-
|
|
271
|
-
|
|
272
|
-
|
|
273
|
-
|
|
274
|
-
|
|
275
|
-
|
|
276
|
-
|
|
277
|
-
|
|
278
|
-
|
|
279
|
-
|
|
280
|
-
|
|
281
|
-
|
|
282
|
-
|
|
283
|
-
const
|
|
284
|
-
|
|
285
|
-
|
|
286
|
-
|
|
287
|
-
|
|
288
|
-
|
|
289
|
-
|
|
290
|
-
|
|
291
|
-
|
|
292
|
-
|
|
293
|
-
|
|
294
|
-
|
|
295
|
-
|
|
296
|
-
|
|
297
|
-
|
|
298
|
-
|
|
299
|
-
|
|
300
|
-
|
|
301
|
-
{
|
|
302
|
-
|
|
303
|
-
|
|
304
|
-
|
|
305
|
-
|
|
306
|
-
|
|
307
|
-
|
|
308
|
-
|
|
309
|
-
|
|
310
|
-
|
|
311
|
-
|
|
312
|
-
|
|
313
|
-
|
|
314
|
-
|
|
315
|
-
|
|
316
|
-
|
|
317
|
-
|
|
318
|
-
|
|
319
|
-
|
|
320
|
-
|
|
321
|
-
|
|
322
|
-
|
|
323
|
-
|
|
324
|
-
|
|
325
|
-
|
|
326
|
-
|
|
327
|
-
|
|
328
|
-
|
|
329
|
-
|
|
330
|
-
|
|
331
|
-
|
|
332
|
-
|
|
333
|
-
|
|
334
|
-
|
|
335
|
-
|
|
336
|
-
|
|
337
|
-
|
|
338
|
-
|
|
339
|
-
|
|
340
|
-
|
|
341
|
-
|
|
342
|
-
|
|
343
|
-
|
|
344
|
-
|
|
345
|
-
|
|
346
|
-
|
|
347
|
-
|
|
348
|
-
|
|
349
|
-
|
|
350
|
-
|
|
351
|
-
|
|
1
|
+
"use client";
|
|
2
|
+
|
|
3
|
+
import {
|
|
4
|
+
useDeferredValue,
|
|
5
|
+
useImperativeHandle,
|
|
6
|
+
useLayoutEffect,
|
|
7
|
+
useMemo,
|
|
8
|
+
useState,
|
|
9
|
+
type CSSProperties,
|
|
10
|
+
type ReactNode,
|
|
11
|
+
type Ref,
|
|
12
|
+
} from "react";
|
|
13
|
+
import { computeLayout, createSelectionColumn, resolveColumns } from "../core/columns";
|
|
14
|
+
import { filterRows } from "../core/filtering";
|
|
15
|
+
import { createGridEngine, type GridApi, type GridSnapshot } from "../core/grid";
|
|
16
|
+
import { buildRows, createRowIdGetter, paginate } from "../core/rows";
|
|
17
|
+
import { sortRows } from "../core/sorting";
|
|
18
|
+
import { shallowEqual } from "../core/store";
|
|
19
|
+
import type { Density, GridOptions } from "../core/types";
|
|
20
|
+
import { createFormatters } from "../core/values";
|
|
21
|
+
import { ColumnMenu } from "./ColumnMenu";
|
|
22
|
+
import { GridContext, cx, type GridContextValue, type GridSlot } from "./context";
|
|
23
|
+
import { usePopoverState, useStoreSelector } from "./hooks";
|
|
24
|
+
import { defaultLocaleText, type LocaleText } from "./locale";
|
|
25
|
+
import { Pagination } from "./Pagination";
|
|
26
|
+
import { Popover } from "./Popover";
|
|
27
|
+
import { Toolbar, type ToolbarOptions } from "./Toolbar";
|
|
28
|
+
import { AskGrid } from "./AskGrid";
|
|
29
|
+
import { createGridAgent, type GridAgent } from "../agent/engine";
|
|
30
|
+
import { useAgentSurfaceGrid, useInAgentSurface } from "../../shared/react/agentSurfaceContext";
|
|
31
|
+
import type { GridAgentPolicy, GridColumnSemantics } from "../agent/contract";
|
|
32
|
+
import { GridViewport } from "./Viewport";
|
|
33
|
+
|
|
34
|
+
export interface DataGridProps<T> extends GridOptions<T> {
|
|
35
|
+
ref?: Ref<GridApi<T>>;
|
|
36
|
+
/** Height of the scrolling area. Ignored with `autoHeight`. Default 520. */
|
|
37
|
+
height?: number | string;
|
|
38
|
+
/** Grow to fit all rows instead of scrolling (use with pagination or small data). */
|
|
39
|
+
autoHeight?: boolean;
|
|
40
|
+
/** Fixed row height in px. Defaults to the density's height. */
|
|
41
|
+
rowHeight?: number;
|
|
42
|
+
/** Fixed header height in px. Defaults to the density's row height. */
|
|
43
|
+
headerHeight?: number;
|
|
44
|
+
/**
|
|
45
|
+
* Show the loading treatment over the grid. The existing rows stay in place
|
|
46
|
+
* underneath, so a refresh does not empty the screen.
|
|
47
|
+
*/
|
|
48
|
+
loading?: boolean;
|
|
49
|
+
/**
|
|
50
|
+
* The toolbar above the grid. `true` for all of it, `false` for none, or an
|
|
51
|
+
* object to choose parts — `{ search: true, export: false }` — and to put
|
|
52
|
+
* your own controls at its `start` or `end`.
|
|
53
|
+
*/
|
|
54
|
+
toolbar?: boolean | ToolbarOptions;
|
|
55
|
+
/** Page sizes offered in the pager. Default `[25, 50, 100, 250]`. */
|
|
56
|
+
pageSizeOptions?: number[];
|
|
57
|
+
/**
|
|
58
|
+
* Shown in place of rows when there are none. Worth distinguishing "nothing
|
|
59
|
+
* here yet" from "nothing matched your filters", which the default does not.
|
|
60
|
+
*/
|
|
61
|
+
emptyState?: ReactNode;
|
|
62
|
+
/** A class per row, for status colouring. Return undefined for no class. */
|
|
63
|
+
getRowClassName?(row: T, rowIndex: number): string | undefined;
|
|
64
|
+
classNames?: Partial<Record<GridSlot, string>>;
|
|
65
|
+
className?: string;
|
|
66
|
+
style?: CSSProperties;
|
|
67
|
+
/** BCP 47 locale for number and date formatting. */
|
|
68
|
+
locale?: string;
|
|
69
|
+
localeText?: Partial<LocaleText>;
|
|
70
|
+
"aria-label"?: string;
|
|
71
|
+
/**
|
|
72
|
+
* Render a natural-language box above the grid.
|
|
73
|
+
*
|
|
74
|
+
* Needs a `<GramproAIProvider>` above it supplying an adapter; without one
|
|
75
|
+
* this renders nothing and the grid is unchanged. No model is bundled or
|
|
76
|
+
* downloaded — the application brings its own.
|
|
77
|
+
*/
|
|
78
|
+
ai?: boolean;
|
|
79
|
+
/** What a machine cannot read off a column definition: units, synonyms, PII. */
|
|
80
|
+
semantics?: Readonly<Record<string, GridColumnSemantics>>;
|
|
81
|
+
/** Columns and operations withheld from whatever is driving the grid. */
|
|
82
|
+
agentPolicy?: GridAgentPolicy;
|
|
83
|
+
}
|
|
84
|
+
|
|
85
|
+
const ROW_HEIGHTS: Record<Density, number> = { compact: 32, standard: 40, comfortable: 52 };
|
|
86
|
+
const DEFAULT_PAGE_SIZES = [25, 50, 100, 250];
|
|
87
|
+
const EMPTY_CLASSNAMES: Partial<Record<GridSlot, string>> = {};
|
|
88
|
+
|
|
89
|
+
const selectModelState = ({ state }: GridSnapshot) => ({
|
|
90
|
+
sorting: state.sorting,
|
|
91
|
+
filters: state.filters,
|
|
92
|
+
globalFilter: state.globalFilter,
|
|
93
|
+
pagination: state.pagination,
|
|
94
|
+
columnOrder: state.columnOrder,
|
|
95
|
+
columnVisibility: state.columnVisibility,
|
|
96
|
+
columnSizing: state.columnSizing,
|
|
97
|
+
columnPinning: state.columnPinning,
|
|
98
|
+
density: state.density,
|
|
99
|
+
});
|
|
100
|
+
|
|
101
|
+
export function DataGrid<T>(props: DataGridProps<T>) {
|
|
102
|
+
const {
|
|
103
|
+
ref,
|
|
104
|
+
data,
|
|
105
|
+
columns: columnDefs,
|
|
106
|
+
getRowId,
|
|
107
|
+
mode = "client",
|
|
108
|
+
rowCount,
|
|
109
|
+
state: controlled,
|
|
110
|
+
enablePagination = true,
|
|
111
|
+
enableSorting = true,
|
|
112
|
+
enableFiltering = true,
|
|
113
|
+
enableColumnResizing = true,
|
|
114
|
+
enableColumnReordering = true,
|
|
115
|
+
enableColumnPinning = true,
|
|
116
|
+
enableColumnHiding = true,
|
|
117
|
+
enableRowSelection = false,
|
|
118
|
+
selectionMode = "multiple",
|
|
119
|
+
height = 520,
|
|
120
|
+
autoHeight = false,
|
|
121
|
+
loading = false,
|
|
122
|
+
toolbar = true,
|
|
123
|
+
pageSizeOptions = DEFAULT_PAGE_SIZES,
|
|
124
|
+
emptyState,
|
|
125
|
+
getRowClassName,
|
|
126
|
+
classNames = EMPTY_CLASSNAMES,
|
|
127
|
+
className,
|
|
128
|
+
style,
|
|
129
|
+
locale,
|
|
130
|
+
localeText: localeOverrides,
|
|
131
|
+
ai = false,
|
|
132
|
+
semantics,
|
|
133
|
+
agentPolicy,
|
|
134
|
+
} = props;
|
|
135
|
+
|
|
136
|
+
const [engine] = useState(() => createGridEngine<T>(props));
|
|
137
|
+
useImperativeHandle(ref, () => engine.api, [engine]);
|
|
138
|
+
|
|
139
|
+
/*
|
|
140
|
+
* The agent is built once, from the same engine the grid renders, so the
|
|
141
|
+
* contract it advertises is this instance's real state rather than a copy.
|
|
142
|
+
* Only when something will use it — `ai`, or an <AgentSurface> around the
|
|
143
|
+
* grid: an agent walks the data to derive column stats and enum values, which
|
|
144
|
+
* a grid nobody is going to ask questions of should not pay for.
|
|
145
|
+
*
|
|
146
|
+
* Imported statically. A dynamic import would not split it out anyway — the
|
|
147
|
+
* data-grid index re-exports the runtime for `createGridAgent` — and every
|
|
148
|
+
* host build would print a warning saying so.
|
|
149
|
+
*/
|
|
150
|
+
const inSurface = useInAgentSurface();
|
|
151
|
+
const wantsAgent = ai || inSurface;
|
|
152
|
+
const build = () =>
|
|
153
|
+
createGridAgent<T>({ api: engine.api, options: props, semantics, policy: agentPolicy, locale });
|
|
154
|
+
const [agent, setAgent] = useState<GridAgent<T> | null>(() => (wantsAgent ? build() : null));
|
|
155
|
+
// A grid that comes to need one later — moved into a surface — gets it then.
|
|
156
|
+
if (wantsAgent && !agent) setAgent(build());
|
|
157
|
+
useAgentSurfaceGrid(agent, props["aria-label"]);
|
|
158
|
+
|
|
159
|
+
// Selection and UI state are deliberately not selected here: changing them
|
|
160
|
+
// re-renders only the rows and cells that subscribe to them.
|
|
161
|
+
const internal = useStoreSelector(engine.store, selectModelState, shallowEqual);
|
|
162
|
+
const sorting = controlled?.sorting ?? internal.sorting;
|
|
163
|
+
const filters = controlled?.filters ?? internal.filters;
|
|
164
|
+
const globalFilter = controlled?.globalFilter ?? internal.globalFilter;
|
|
165
|
+
const pagination = controlled?.pagination ?? internal.pagination;
|
|
166
|
+
const columnOrder = controlled?.columnOrder ?? internal.columnOrder;
|
|
167
|
+
const columnVisibility = controlled?.columnVisibility ?? internal.columnVisibility;
|
|
168
|
+
const columnSizing = controlled?.columnSizing ?? internal.columnSizing;
|
|
169
|
+
const columnPinning = controlled?.columnPinning ?? internal.columnPinning;
|
|
170
|
+
const density = controlled?.density ?? internal.density;
|
|
171
|
+
|
|
172
|
+
const localeText = useMemo(() => ({ ...defaultLocaleText, ...localeOverrides }), [localeOverrides]);
|
|
173
|
+
const formatters = useMemo(
|
|
174
|
+
() => createFormatters(locale, { yes: localeText.yes, no: localeText.no }),
|
|
175
|
+
[locale, localeText.yes, localeText.no],
|
|
176
|
+
);
|
|
177
|
+
const numberFormat = useMemo(() => new Intl.NumberFormat(locale), [locale]);
|
|
178
|
+
|
|
179
|
+
// Row pipeline: each stage recomputes only when its own inputs change.
|
|
180
|
+
const server = mode === "server";
|
|
181
|
+
const rowIdGetter = useMemo(() => createRowIdGetter(getRowId), [getRowId]);
|
|
182
|
+
const columns = useMemo(() => resolveColumns(columnDefs), [columnDefs]);
|
|
183
|
+
const coreRows = useMemo(() => buildRows(data, rowIdGetter), [data, rowIdGetter]);
|
|
184
|
+
|
|
185
|
+
const liveQuery = useMemo(
|
|
186
|
+
() => ({ sorting, filters, globalFilter, pagination }),
|
|
187
|
+
[sorting, filters, globalFilter, pagination],
|
|
188
|
+
);
|
|
189
|
+
// Filtering and sorting large data render at low priority, so typing stays responsive.
|
|
190
|
+
const query = useDeferredValue(liveQuery);
|
|
191
|
+
const stale = query !== liveQuery;
|
|
192
|
+
|
|
193
|
+
const filteredRows = useMemo(
|
|
194
|
+
() => (server ? coreRows : filterRows(coreRows, columns, query.filters, query.globalFilter, formatters)),
|
|
195
|
+
[server, coreRows, columns, query.filters, query.globalFilter, formatters],
|
|
196
|
+
);
|
|
197
|
+
const sortedRows = useMemo(
|
|
198
|
+
() => (server ? filteredRows : sortRows(filteredRows, columns, query.sorting, locale)),
|
|
199
|
+
[server, filteredRows, columns, query.sorting, locale],
|
|
200
|
+
);
|
|
201
|
+
const page = useMemo(
|
|
202
|
+
() => paginate(sortedRows, query.pagination, { enabled: enablePagination, server, rowCount }),
|
|
203
|
+
[sortedRows, query.pagination, enablePagination, server, rowCount],
|
|
204
|
+
);
|
|
205
|
+
|
|
206
|
+
const hasSelection = enableRowSelection !== false;
|
|
207
|
+
const leadingColumns = useMemo(() => (hasSelection ? [createSelectionColumn<T>()] : []), [hasSelection]);
|
|
208
|
+
const layout = useMemo(
|
|
209
|
+
() => computeLayout(columns, { columnOrder, columnVisibility, columnSizing, columnPinning }, leadingColumns),
|
|
210
|
+
[columns, columnOrder, columnVisibility, columnSizing, columnPinning, leadingColumns],
|
|
211
|
+
);
|
|
212
|
+
|
|
213
|
+
const rowHeight = props.rowHeight ?? ROW_HEIGHTS[density];
|
|
214
|
+
const headerHeight = props.headerHeight ?? Math.max(40, rowHeight);
|
|
215
|
+
|
|
216
|
+
// Hand the committed props and model to the engine for event handlers.
|
|
217
|
+
useLayoutEffect(() => {
|
|
218
|
+
engine.sync(props, { columns, coreRows, sortedRows, page, layout, rowHeight, headerHeight, formatters });
|
|
219
|
+
});
|
|
220
|
+
|
|
221
|
+
const menu = usePopoverState<string>();
|
|
222
|
+
const openMenu = menu.open;
|
|
223
|
+
|
|
224
|
+
const isRowSelectable = useMemo(
|
|
225
|
+
() =>
|
|
226
|
+
typeof enableRowSelection === "function" ? enableRowSelection : () => enableRowSelection === true,
|
|
227
|
+
[enableRowSelection],
|
|
228
|
+
);
|
|
229
|
+
|
|
230
|
+
const context = useMemo<GridContextValue<T>>(
|
|
231
|
+
() => ({
|
|
232
|
+
engine,
|
|
233
|
+
locale: localeText,
|
|
234
|
+
classNames,
|
|
235
|
+
formatters,
|
|
236
|
+
numberFormat,
|
|
237
|
+
controlledSelection: controlled?.rowSelection,
|
|
238
|
+
isRowSelectable,
|
|
239
|
+
openColumnMenu: (columnId, anchor) => openMenu(anchor, columnId),
|
|
240
|
+
features: {
|
|
241
|
+
sorting: enableSorting,
|
|
242
|
+
filtering: enableFiltering,
|
|
243
|
+
resizing: enableColumnResizing,
|
|
244
|
+
reordering: enableColumnReordering,
|
|
245
|
+
pinning: enableColumnPinning,
|
|
246
|
+
hiding: enableColumnHiding,
|
|
247
|
+
selection: hasSelection,
|
|
248
|
+
selectionMode,
|
|
249
|
+
},
|
|
250
|
+
}),
|
|
251
|
+
[
|
|
252
|
+
engine,
|
|
253
|
+
localeText,
|
|
254
|
+
classNames,
|
|
255
|
+
formatters,
|
|
256
|
+
numberFormat,
|
|
257
|
+
controlled?.rowSelection,
|
|
258
|
+
isRowSelectable,
|
|
259
|
+
openMenu,
|
|
260
|
+
enableSorting,
|
|
261
|
+
enableFiltering,
|
|
262
|
+
enableColumnResizing,
|
|
263
|
+
enableColumnReordering,
|
|
264
|
+
enableColumnPinning,
|
|
265
|
+
enableColumnHiding,
|
|
266
|
+
hasSelection,
|
|
267
|
+
selectionMode,
|
|
268
|
+
],
|
|
269
|
+
);
|
|
270
|
+
|
|
271
|
+
const toolbarOptions: ToolbarOptions | null =
|
|
272
|
+
toolbar === false
|
|
273
|
+
? null
|
|
274
|
+
: {
|
|
275
|
+
search: true,
|
|
276
|
+
filterChips: true,
|
|
277
|
+
columns: true,
|
|
278
|
+
density: true,
|
|
279
|
+
export: true,
|
|
280
|
+
...(toolbar === true ? {} : toolbar),
|
|
281
|
+
};
|
|
282
|
+
|
|
283
|
+
const menuAnchor = menu.state?.anchor ?? null;
|
|
284
|
+
const menuItem = menu.state ? layout.columns.find((i) => i.column.id === menu.state?.payload) : undefined;
|
|
285
|
+
const closeMenu = () => menu.close(menuAnchor);
|
|
286
|
+
|
|
287
|
+
return (
|
|
288
|
+
<GridContext value={context as unknown as GridContextValue<unknown>}>
|
|
289
|
+
<div
|
|
290
|
+
className={cx("dg-root", classNames.root, className)}
|
|
291
|
+
style={
|
|
292
|
+
{
|
|
293
|
+
...style,
|
|
294
|
+
"--dg-row-height": `${rowHeight}px`,
|
|
295
|
+
"--dg-header-height": `${headerHeight}px`,
|
|
296
|
+
} as CSSProperties
|
|
297
|
+
}
|
|
298
|
+
data-density={density}
|
|
299
|
+
data-stale={stale || undefined}
|
|
300
|
+
>
|
|
301
|
+
{ai && <AskGrid agent={agent} aria-label={props['aria-label']} />}
|
|
302
|
+
|
|
303
|
+
{toolbarOptions && (
|
|
304
|
+
<Toolbar
|
|
305
|
+
options={toolbarOptions}
|
|
306
|
+
globalFilter={globalFilter}
|
|
307
|
+
filters={filters}
|
|
308
|
+
density={density}
|
|
309
|
+
columns={columns}
|
|
310
|
+
columnVisibility={columnVisibility}
|
|
311
|
+
/>
|
|
312
|
+
)}
|
|
313
|
+
|
|
314
|
+
<GridViewport
|
|
315
|
+
layout={layout}
|
|
316
|
+
page={page}
|
|
317
|
+
sortedRows={sortedRows}
|
|
318
|
+
sorting={sorting}
|
|
319
|
+
filters={filters}
|
|
320
|
+
hasQuery={filters.length > 0 || globalFilter !== ""}
|
|
321
|
+
rowHeight={rowHeight}
|
|
322
|
+
headerHeight={headerHeight}
|
|
323
|
+
height={autoHeight ? undefined : height}
|
|
324
|
+
loading={loading}
|
|
325
|
+
emptyState={emptyState}
|
|
326
|
+
ariaLabel={props["aria-label"] ?? localeText.gridLabel}
|
|
327
|
+
getRowClassName={getRowClassName}
|
|
328
|
+
/>
|
|
329
|
+
|
|
330
|
+
{enablePagination && (
|
|
331
|
+
<Pagination page={page} pageSize={pagination.pageSize} pageSizeOptions={pageSizeOptions} />
|
|
332
|
+
)}
|
|
333
|
+
|
|
334
|
+
{menuAnchor && menuItem && (
|
|
335
|
+
<Popover
|
|
336
|
+
anchor={menuAnchor}
|
|
337
|
+
onClose={closeMenu}
|
|
338
|
+
label={localeText.columnMenu(menuItem.column.header)}
|
|
339
|
+
className="dg-column-menu-popover"
|
|
340
|
+
>
|
|
341
|
+
<ColumnMenu
|
|
342
|
+
item={menuItem}
|
|
343
|
+
layout={layout}
|
|
344
|
+
sort={sorting.find((s) => s.columnId === menuItem.column.id)}
|
|
345
|
+
filter={filters.find((f) => f.columnId === menuItem.column.id)}
|
|
346
|
+
onClose={closeMenu}
|
|
347
|
+
/>
|
|
348
|
+
</Popover>
|
|
349
|
+
)}
|
|
350
|
+
</div>
|
|
351
|
+
</GridContext>
|
|
352
|
+
);
|
|
353
|
+
}
|