@gridkitjs/core 0.0.0-dev-20261106222533
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 +36 -0
- package/dist/index.d.ts +4229 -0
- package/dist/index.js +4757 -0
- package/dist/index.js.map +1 -0
- package/package.json +49 -0
package/dist/index.d.ts
ADDED
|
@@ -0,0 +1,4229 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* A row or column selection change by id — see
|
|
3
|
+
* `GridControllerOptions.onSelectionDiff`.
|
|
4
|
+
*/
|
|
5
|
+
interface SelectionDiffEvent extends SelectionDiff {
|
|
6
|
+
/** Which selection changed. */
|
|
7
|
+
readonly target: "rows" | "columns";
|
|
8
|
+
/** The whole selection after the change. */
|
|
9
|
+
readonly selection: SelectionState;
|
|
10
|
+
}
|
|
11
|
+
/**
|
|
12
|
+
* What `createGridController` is given: the grid's options and selection
|
|
13
|
+
* callbacks, plus what a renderer supplies that is not a setting — the column
|
|
14
|
+
* definitions, whose templates name the renderer's own node type, the width
|
|
15
|
+
* the viewport measured, and a hook for its own selection feedback.
|
|
16
|
+
*/
|
|
17
|
+
interface GridControllerOptions<Row, Node = string> extends GridOptions<Row>, SelectionCallbacks<Row, Node> {
|
|
18
|
+
/**
|
|
19
|
+
* The columns to show. Omitted or empty, one column is inferred per field
|
|
20
|
+
* of `dataSource` — see `defineColumnsFromRows`.
|
|
21
|
+
*/
|
|
22
|
+
columns?: readonly ColumnDefinition<Row, Node>[] | undefined;
|
|
23
|
+
/**
|
|
24
|
+
* The width, in px, `resizeMode: "fit"` fills. `null` or absent before it
|
|
25
|
+
* has been measured, or where there is no viewport at all (an export in
|
|
26
|
+
* Node), and then columns keep their resolved widths.
|
|
27
|
+
*/
|
|
28
|
+
viewportWidth?: number | null | undefined;
|
|
29
|
+
/**
|
|
30
|
+
* Called once per row or column selection change, after the selection
|
|
31
|
+
* callbacks, with the change by id — every id it added or removed,
|
|
32
|
+
* including those with no row on screen (on another page, in a collapsed
|
|
33
|
+
* group, filtered out), which the callbacks' resolved rows leave out. For a
|
|
34
|
+
* renderer's own feedback, such as a live region announcing how many rows
|
|
35
|
+
* are selected; an application reads the selection callbacks instead.
|
|
36
|
+
*/
|
|
37
|
+
onSelectionDiff?: ((event: SelectionDiffEvent) => void) | undefined;
|
|
38
|
+
}
|
|
39
|
+
/**
|
|
40
|
+
* A grid without a renderer: its state, the view derived from it, and every
|
|
41
|
+
* action that changes it. A renderer creates one per grid, hands it the
|
|
42
|
+
* current options on each update, draws `getView()` and calls the actions
|
|
43
|
+
* from its event handlers, so no renderer decides anything the user can see.
|
|
44
|
+
*
|
|
45
|
+
* Each slice of `GridState` is controlled or not on its own, the way a form
|
|
46
|
+
* input is: given as an option (`columnSort`), the grid shows that value and
|
|
47
|
+
* an action only asks for a change through the slice's callback
|
|
48
|
+
* (`onColumnSortChange`); left out, the controller keeps the slice itself,
|
|
49
|
+
* starting from its default (`defaultColumnSort`).
|
|
50
|
+
*
|
|
51
|
+
* Every action follows the same steps: work out the next value; stop if it
|
|
52
|
+
* is the very object the slice already holds; keep it, unless the slice is
|
|
53
|
+
* controlled; report it through the slice's callback; then call every
|
|
54
|
+
* subscriber, synchronously. The setters (`setColumnSort` and the like) also
|
|
55
|
+
* stop for a value equal to the current one, so restoring what is already
|
|
56
|
+
* there reports nothing.
|
|
57
|
+
*
|
|
58
|
+
* Every member is a plain function bound to its grid, safe to hand around on
|
|
59
|
+
* its own — `onClick={controller.nextPage}`.
|
|
60
|
+
*/
|
|
61
|
+
interface GridController<Row, Node = string> {
|
|
62
|
+
readonly getOptions: () => GridControllerOptions<Row, Node>;
|
|
63
|
+
/**
|
|
64
|
+
* Replaces the options, as a renderer does with its current props on every
|
|
65
|
+
* update; calling it again with equal options changes nothing. A controlled
|
|
66
|
+
* slice takes its new value from here.
|
|
67
|
+
*
|
|
68
|
+
* Does not call subscribers: a renderer calls this while it updates, and
|
|
69
|
+
* draws the result itself — a subscriber called mid-update would update
|
|
70
|
+
* mid-update too. A renderer that also tells other listeners about it does
|
|
71
|
+
* so once its update is done.
|
|
72
|
+
*/
|
|
73
|
+
readonly setOptions: (options: GridControllerOptions<Row, Node>) => void;
|
|
74
|
+
/** Every slice as the grid now applies it. The same object until a slice changes. */
|
|
75
|
+
readonly getState: () => GridState<Row>;
|
|
76
|
+
/** What the user is looking at — see `resolveGridView`. The same object until something in it changes. */
|
|
77
|
+
readonly getView: () => GridView<Row, Node>;
|
|
78
|
+
/**
|
|
79
|
+
* Calls `listener` after each action that got as far as reporting a
|
|
80
|
+
* change. Returns the function that unsubscribes it.
|
|
81
|
+
*/
|
|
82
|
+
readonly subscribe: (listener: () => void) => () => void;
|
|
83
|
+
/**
|
|
84
|
+
* Puts back state saved earlier — from `getState()`, or from
|
|
85
|
+
* `serializeGridState` and back through JSON. Every slice given is set as
|
|
86
|
+
* its own `set*` action would set it, so each that changes fires its
|
|
87
|
+
* callback and a controlled one only asks; slices left out keep their value.
|
|
88
|
+
* Subscribers are called once, after every slice is in place, and a
|
|
89
|
+
* restored pagination is kept even when the same call changed the sort,
|
|
90
|
+
* filter or grouping that would otherwise send it back to the first page.
|
|
91
|
+
*/
|
|
92
|
+
readonly restoreState: (saved: Partial<GridState<Row>> | Partial<SerializedGridState<Row>>) => void;
|
|
93
|
+
/**
|
|
94
|
+
* Replaces the column widths. Reported through `onColumnResize` as the
|
|
95
|
+
* `"end"` of a resize of the first column whose width changed, at its new
|
|
96
|
+
* width — or, when its entry was removed, the width its definition gives
|
|
97
|
+
* it. Equal widths report nothing.
|
|
98
|
+
*/
|
|
99
|
+
readonly setColumnSizing: (sizing: ColumnSizingState) => void;
|
|
100
|
+
/**
|
|
101
|
+
* Sets one column's width, as a resize gesture does: `"move"` while the
|
|
102
|
+
* gesture lasts, `"end"` once it is over. Never skipped for an unchanged
|
|
103
|
+
* width, so a drag held against a column's minimum still reports every
|
|
104
|
+
* move.
|
|
105
|
+
*/
|
|
106
|
+
readonly resizeColumn: (columnId: string, width: number, phase: "move" | "end") => void;
|
|
107
|
+
/**
|
|
108
|
+
* Ends a resize gesture by putting its column back as it was when the
|
|
109
|
+
* gesture began — `startSizing` is the sizing state then, `startWidth` the
|
|
110
|
+
* width the column was drawn at — keeping any other column's change made in
|
|
111
|
+
* the meantime. Reported as the gesture's `"end"`, at `startWidth`.
|
|
112
|
+
*/
|
|
113
|
+
readonly cancelColumnResize: (columnId: string, startSizing: ColumnSizingState, startWidth: number) => void;
|
|
114
|
+
/**
|
|
115
|
+
* Replaces the column order. Reported through `onColumnOrderChange` naming
|
|
116
|
+
* the first column whose position changed; an equal order reports nothing.
|
|
117
|
+
*/
|
|
118
|
+
readonly setColumnOrder: (order: ColumnOrderState) => void;
|
|
119
|
+
/**
|
|
120
|
+
* Moves a column in front of `beforeId`, or to the end when that is
|
|
121
|
+
* `null`, among every column — hidden ones keep their place. A move that
|
|
122
|
+
* changes nothing reports nothing.
|
|
123
|
+
*/
|
|
124
|
+
readonly moveColumn: (columnId: string, beforeId: string | null) => void;
|
|
125
|
+
/**
|
|
126
|
+
* Replaces the column visibility state. Reported through
|
|
127
|
+
* `onColumnVisibilityChange` with every column whose entry changed; an
|
|
128
|
+
* equal state reports nothing.
|
|
129
|
+
*/
|
|
130
|
+
readonly setColumnVisibility: (visibility: ColumnVisibilityState) => void;
|
|
131
|
+
/** Shows the given columns, each in the place it held when hidden. One report for the whole call. */
|
|
132
|
+
readonly showColumns: (columnIds: readonly string[]) => void;
|
|
133
|
+
/** Hides the given columns. A hidden column still sorts, filters and groups. */
|
|
134
|
+
readonly hideColumns: (columnIds: readonly string[]) => void;
|
|
135
|
+
/**
|
|
136
|
+
* Replaces the filter. Reported through `onFilterChange`; a filter equal to
|
|
137
|
+
* the current one — the same entries in the same order, a `Date` value
|
|
138
|
+
* compared by time and a predicate by identity — reports nothing.
|
|
139
|
+
*/
|
|
140
|
+
readonly setFilter: (filter: FilterState<Row>) => void;
|
|
141
|
+
/**
|
|
142
|
+
* Replaces the selected row ids as given, whatever `selectable` allows —
|
|
143
|
+
* the way a controlled or default value is applied. The same ids in the
|
|
144
|
+
* same order report nothing.
|
|
145
|
+
*/
|
|
146
|
+
readonly setRowSelection: (selection: SelectionState) => void;
|
|
147
|
+
/**
|
|
148
|
+
* Selects rows as a user could, within what `selectable.rows` allows:
|
|
149
|
+
* `"replace"` (the default) selects exactly these — only the last of them
|
|
150
|
+
* under `"single"` — and `"toggle"` flips each one. An id need not name a
|
|
151
|
+
* row on screen. A call that leaves the selection as it was reports
|
|
152
|
+
* nothing.
|
|
153
|
+
*/
|
|
154
|
+
readonly selectRows: (rowIds: readonly string[], intent?: "replace" | "toggle") => void;
|
|
155
|
+
/**
|
|
156
|
+
* Applies one click or key press to a row: `"replace"`, `"toggle"` or
|
|
157
|
+
* `"range"` from the last row selected by anything but a range, across
|
|
158
|
+
* the data rows on the current page.
|
|
159
|
+
*/
|
|
160
|
+
readonly selectRow: (rowId: string, intent: SelectIntent) => void;
|
|
161
|
+
/** Selects every data row on the current page, when `selectable.rows` is `"multiple"`. */
|
|
162
|
+
readonly selectAllRows: () => void;
|
|
163
|
+
/** Lets go of every row, column and cell selection at once, as Escape does. */
|
|
164
|
+
readonly clearSelection: () => void;
|
|
165
|
+
/** Replaces the selected column ids as given — see `setRowSelection`. */
|
|
166
|
+
readonly setColumnSelection: (selection: SelectionState) => void;
|
|
167
|
+
/** `selectRow`, for a column among the columns as rendered. */
|
|
168
|
+
readonly selectColumn: (columnId: string, intent: SelectIntent) => void;
|
|
169
|
+
/** Replaces the selected cell as given, `null` for none. */
|
|
170
|
+
readonly setCellSelection: (selection: CellSelectionState) => void;
|
|
171
|
+
/**
|
|
172
|
+
* Applies one click or key press to a cell: `"toggle"` lets go of it when
|
|
173
|
+
* it is the one selected; anything else selects it. A cell holds one value,
|
|
174
|
+
* so a range over cells reads as a plain click.
|
|
175
|
+
*/
|
|
176
|
+
readonly selectCell: (cell: SelectedCellRef, intent: SelectIntent) => void;
|
|
177
|
+
/**
|
|
178
|
+
* Replaces the sort. Reported through `onColumnSortChange` naming the
|
|
179
|
+
* first column whose place or direction changed; a sort equal to the
|
|
180
|
+
* current one changes nothing and reports nothing.
|
|
181
|
+
*/
|
|
182
|
+
readonly setColumnSort: (sort: ColumnSortState) => void;
|
|
183
|
+
/**
|
|
184
|
+
* Cycles a column's sort, as its header toggle does: ascending, descending,
|
|
185
|
+
* off. `stack` adds it to the sort rather than replacing the sort with it.
|
|
186
|
+
*/
|
|
187
|
+
readonly toggleColumnSort: (columnId: string, options?: {
|
|
188
|
+
readonly stack?: boolean | undefined;
|
|
189
|
+
}) => void;
|
|
190
|
+
/**
|
|
191
|
+
* Takes one column out of the sort, keeping the rest in their order, and
|
|
192
|
+
* reports naming that column — which `setColumnSort` without it would not
|
|
193
|
+
* when it was the first key, naming instead the key that moved up. A
|
|
194
|
+
* column the sort leaves out already reports nothing.
|
|
195
|
+
*/
|
|
196
|
+
readonly clearColumnSort: (columnId: string) => void;
|
|
197
|
+
/**
|
|
198
|
+
* Replaces the group-by stack. Reported through `onGroupByChange` naming
|
|
199
|
+
* the first level that changed; an equal stack reports nothing.
|
|
200
|
+
*/
|
|
201
|
+
readonly setGroupBy: (groupBy: GroupByState) => void;
|
|
202
|
+
/** Adds a column to the end of the group-by stack, or removes it if it is already there. */
|
|
203
|
+
readonly toggleGroupBy: (columnId: string) => void;
|
|
204
|
+
/**
|
|
205
|
+
* Puts a column into the group-by stack in front of `beforeColumnId`, or at
|
|
206
|
+
* the end when that is `null` — adding it, or moving it if it is already
|
|
207
|
+
* there.
|
|
208
|
+
*/
|
|
209
|
+
readonly moveGroupBy: (columnId: string, beforeColumnId: string | null) => void;
|
|
210
|
+
/**
|
|
211
|
+
* Replaces the collapsed groups. Reported with `groupId: null`, as a change
|
|
212
|
+
* to every group at once; the same ids in the same order report nothing.
|
|
213
|
+
*/
|
|
214
|
+
readonly setGroupExpansion: (expansion: GroupExpansionState) => void;
|
|
215
|
+
readonly toggleGroupExpansion: (groupId: string) => void;
|
|
216
|
+
readonly expandAllGroups: () => void;
|
|
217
|
+
/** Collapses every group currently shown — see `collapseAllGroups`. */
|
|
218
|
+
readonly collapseAllGroups: () => void;
|
|
219
|
+
/**
|
|
220
|
+
* Replaces the page and page size as given; the view clamps a page past
|
|
221
|
+
* the last one. An equal pagination reports nothing.
|
|
222
|
+
*/
|
|
223
|
+
readonly setPagination: (pagination: PaginationState) => void;
|
|
224
|
+
/**
|
|
225
|
+
* Moves to the given page, clamped into range. A page that clamps to the
|
|
226
|
+
* current one reports nothing.
|
|
227
|
+
*/
|
|
228
|
+
readonly goToPage: (pageIndex: number) => void;
|
|
229
|
+
/** Moves one page on; on the last page it does nothing and reports nothing. */
|
|
230
|
+
readonly nextPage: () => void;
|
|
231
|
+
/** Moves one page back; on the first page it does nothing and reports nothing. */
|
|
232
|
+
readonly previousPage: () => void;
|
|
233
|
+
/**
|
|
234
|
+
* Changes the page size and goes back to the first page. The current size,
|
|
235
|
+
* already on the first page, reports nothing.
|
|
236
|
+
*/
|
|
237
|
+
readonly setPageSize: (pageSize: number) => void;
|
|
238
|
+
}
|
|
239
|
+
|
|
240
|
+
/** How a column's values compare, which decides what an operand must be. */
|
|
241
|
+
type ValueKind = "number" | "boolean" | "date" | "text";
|
|
242
|
+
|
|
243
|
+
/**
|
|
244
|
+
* The kind of value a column filters as — what decides which conditions a
|
|
245
|
+
* filter menu offers on it, how their operators read, and what a typed
|
|
246
|
+
* operand must be.
|
|
247
|
+
*/
|
|
248
|
+
type FilterOperatorFamily = ValueKind;
|
|
249
|
+
/**
|
|
250
|
+
* The family a column of `type` falls in: `"number"` for the numeric
|
|
251
|
+
* types, `"date"` for date, date-time and time, `"boolean"`, and `"text"`
|
|
252
|
+
* for everything else. It is the filter engine's own reading of `type`, so
|
|
253
|
+
* a menu never offers a condition the column would compare differently.
|
|
254
|
+
*/
|
|
255
|
+
declare function filterOperatorFamily(type: ColumnType | undefined): FilterOperatorFamily;
|
|
256
|
+
/**
|
|
257
|
+
* The conditions a filter menu offers on a column of `type`, in the order it
|
|
258
|
+
* lists them, unless the column names its own. Never `in`: a list of values
|
|
259
|
+
* is the checklist's to pick, not a condition's to type.
|
|
260
|
+
*/
|
|
261
|
+
declare function defaultFilterOperators(type: ColumnType | undefined): readonly FilterOperator[];
|
|
262
|
+
/**
|
|
263
|
+
* How many operands `operator` takes — how many inputs a condition row
|
|
264
|
+
* shows: none for the blanks, `between`'s two ends, one for the rest. `in`
|
|
265
|
+
* takes one list, which only a checklist writes.
|
|
266
|
+
*/
|
|
267
|
+
declare function filterOperandArity(operator: FilterOperator): 0 | 1 | 2;
|
|
268
|
+
/**
|
|
269
|
+
* The operand a condition input's `text` stands for on a column of `type`,
|
|
270
|
+
* read as the column filters — or `undefined` when the text is empty or
|
|
271
|
+
* doesn't read as one, which an editor shows as a value still to fix.
|
|
272
|
+
*
|
|
273
|
+
* - Text is kept as typed, spaces and all.
|
|
274
|
+
* - A number reads with a point for decimals, as a number input gives it:
|
|
275
|
+
* `"12abc"` and `"1,5"` read as nothing rather than as a guess.
|
|
276
|
+
* - A date reads as a date input gives it, `yyyy-mm-dd`, at that day's
|
|
277
|
+
* local midnight; or as a date-time input does, `yyyy-mm-ddThh:mm`, at
|
|
278
|
+
* that local time.
|
|
279
|
+
* - A boolean reads `"true"` or `"false"`.
|
|
280
|
+
*/
|
|
281
|
+
declare function parseFilterOperand(text: string, type: ColumnType | undefined): Exclude<FilterScalar, null> | undefined;
|
|
282
|
+
/**
|
|
283
|
+
* The text a condition input shows for `value` — `parseFilterOperand`'s
|
|
284
|
+
* inverse, for opening a condition already applied. A date reads back in
|
|
285
|
+
* the form its column's input takes: the day alone on a `"date"` column,
|
|
286
|
+
* the day and time on a `"dateTime"` or `"time"` one. A blank operand is
|
|
287
|
+
* empty, and one that isn't a date on a date column — a string set in code
|
|
288
|
+
* that names none — shows as it is, for the user to fix.
|
|
289
|
+
*/
|
|
290
|
+
declare function formatFilterOperand(value: FilterScalar | undefined, type: ColumnType | undefined): string;
|
|
291
|
+
|
|
292
|
+
/** The locale(s) values are formatted for — `undefined` is the runtime's own. */
|
|
293
|
+
type FormatLocale = string | readonly string[] | undefined;
|
|
294
|
+
/**
|
|
295
|
+
* The text a value reads as in `column` — what a cell shows when the column
|
|
296
|
+
* has no `cellTemplate`, and what an export or a print writes, so the two
|
|
297
|
+
* cannot disagree.
|
|
298
|
+
*
|
|
299
|
+
* A `valueFormatter` decides outright. `null`/`undefined` read `""`, a
|
|
300
|
+
* boolean `"true"`/`"false"` — or `messages.booleanTrue`/`booleanFalse`
|
|
301
|
+
* when given, for a grid speaking another language — a string as it is, a
|
|
302
|
+
* plain object or array as JSON.
|
|
303
|
+
*
|
|
304
|
+
* Dates and numbers are formatted through `Intl` only once asked to — the
|
|
305
|
+
* column has a `format`, or a `locale` is given. Until then they print as a
|
|
306
|
+
* grid always printed them, so adopting this changes nothing on screen: a
|
|
307
|
+
* `Date` through `toLocaleString()`, a number as-is (`1234.5`, never
|
|
308
|
+
* `1,234.5`). Once asked:
|
|
309
|
+
*
|
|
310
|
+
* - A `Date` → `Intl.DateTimeFormat`: the date alone under `"date"`, the time
|
|
311
|
+
* alone under `"time"`, both otherwise.
|
|
312
|
+
* - A number under a numeric `type` → `Intl.NumberFormat`: `"currency"` with
|
|
313
|
+
* a currency symbol once `format.currency` names one (two fraction digits
|
|
314
|
+
* until then), `"percent"` reading `0.25` as 25 %. Under any other type it
|
|
315
|
+
* is still printed as-is, the way a number id should be.
|
|
316
|
+
*
|
|
317
|
+
* `format` and `locale` go to the `Intl` constructor unchanged, so any
|
|
318
|
+
* option it accepts is honoured.
|
|
319
|
+
*/
|
|
320
|
+
declare function formatCellValue<Row>(value: unknown, column: ColumnDefinition<Row, unknown>, locale?: FormatLocale, row?: Row, messages?: Pick<GridMessages, "booleanTrue" | "booleanFalse">): string;
|
|
321
|
+
/**
|
|
322
|
+
* The text an aggregate result reads as — a footer cell, a group's subtotal
|
|
323
|
+
* — through `formatCellValue`, so once a `format` or `locale` asks for it a
|
|
324
|
+
* `sum` of a currency column reads as currency and a `max` of a date column
|
|
325
|
+
* as a date. `column` is `undefined` for a spec naming a column the grid
|
|
326
|
+
* does not have, which then formats by its value alone.
|
|
327
|
+
*
|
|
328
|
+
* Until then a numeric result reads through `toLocaleString()`, with digit
|
|
329
|
+
* grouping, where a cell prints its number as-is: that is how a grid has
|
|
330
|
+
* always shown its totals, and a sum easily runs into the thousands.
|
|
331
|
+
*/
|
|
332
|
+
declare function formatAggregateValue<Row>(value: unknown, spec: AggregateSpec<Row>, column: ColumnDefinition<Row, unknown> | undefined, locale?: FormatLocale): string;
|
|
333
|
+
/**
|
|
334
|
+
* The text a group's own value reads as — a group header's name, and the
|
|
335
|
+
* label an export writes for it: as the grouped column's cells read it,
|
|
336
|
+
* except that a missing value reads `messages.blankGroupValue` ("(blank)"),
|
|
337
|
+
* since an empty label would leave the group looking unnamed rather than
|
|
338
|
+
* named "nothing".
|
|
339
|
+
*/
|
|
340
|
+
declare function formatGroupValue<Row>(value: unknown, column: ColumnDefinition<Row, unknown>, locale: FormatLocale, messages: Pick<GridMessages, "booleanTrue" | "booleanFalse" | "blankGroupValue">): string;
|
|
341
|
+
|
|
342
|
+
/**
|
|
343
|
+
* Every string a grid shows or announces of its own — the pager, the group-by
|
|
344
|
+
* bar, the loading row, the text of a boolean or missing value, the labels of
|
|
345
|
+
* its built-in commands, the names of its menus, toolbar and column chooser,
|
|
346
|
+
* and the live-region
|
|
347
|
+
* announcements — so a grid can
|
|
348
|
+
* speak a language other than English. A message that names something takes
|
|
349
|
+
* a function, so a translation can put the name where its own grammar wants
|
|
350
|
+
* it.
|
|
351
|
+
*
|
|
352
|
+
* Text the data supplies (cells, headers, labels) is not here: it is already
|
|
353
|
+
* the app's to choose. Nor is formatting — dates and numbers follow
|
|
354
|
+
* `locale`, and so do the counts the defaults print: "1,204 of 10,000 rows"
|
|
355
|
+
* under `"en"`, "1.204 of 10.000 rows" under `"de-DE"`.
|
|
356
|
+
*/
|
|
357
|
+
interface GridMessages {
|
|
358
|
+
/** The pager's accessible name. */
|
|
359
|
+
pagerLabel: string;
|
|
360
|
+
/** The pager button to the first page; drawn as an icon, so this is its accessible name. */
|
|
361
|
+
firstPage: string;
|
|
362
|
+
/** The pager button to the previous page; its accessible name. */
|
|
363
|
+
previousPage: string;
|
|
364
|
+
/** The pager button to the next page; its accessible name. */
|
|
365
|
+
nextPage: string;
|
|
366
|
+
/** The pager button to the last page; its accessible name. */
|
|
367
|
+
lastPage: string;
|
|
368
|
+
/** The page-size control's label. */
|
|
369
|
+
pageSizeLabel: string;
|
|
370
|
+
/** A numbered pager button's accessible name. */
|
|
371
|
+
pageButtonLabel: (page: number) => string;
|
|
372
|
+
/**
|
|
373
|
+
* The compact pager's status, and what a page change announces. `page`
|
|
374
|
+
* counts from one, and is `0` while there are no pages.
|
|
375
|
+
*/
|
|
376
|
+
pageStatus: (page: number, pageCount: number) => string;
|
|
377
|
+
/** The row shown while `infiniteScroll` loads more. */
|
|
378
|
+
loadingMore: string;
|
|
379
|
+
/** A boolean cell's text. */
|
|
380
|
+
booleanTrue: string;
|
|
381
|
+
booleanFalse: string;
|
|
382
|
+
/** What a group header names a group of missing values. */
|
|
383
|
+
blankGroupValue: string;
|
|
384
|
+
/** The group-by bar's accessible name. */
|
|
385
|
+
groupByBarLabel: string;
|
|
386
|
+
/** Shown in an empty group-by bar a header can be dragged into. */
|
|
387
|
+
groupByBarPlaceholder: string;
|
|
388
|
+
/** A group-by chip's accessible name. `level` counts from one. */
|
|
389
|
+
groupByChipLabel: (columnName: string, level: number, levelCount: number) => string;
|
|
390
|
+
/** A group-by chip's remove button's accessible name. */
|
|
391
|
+
removeGroupBy: (columnName: string) => string;
|
|
392
|
+
/** Announced when a resize ends, `width` in whole pixels. */
|
|
393
|
+
columnResized: (columnName: string, width: number) => string;
|
|
394
|
+
/** Announced when a column is moved. `position` counts from one. */
|
|
395
|
+
columnMoved: (columnName: string, position: number, columnCount: number) => string;
|
|
396
|
+
/** Announced when a column is sorted. `key` is its place in the sort, from one. */
|
|
397
|
+
columnSorted: (columnName: string, direction: SortDirection, key: number, keyCount: number) => string;
|
|
398
|
+
/** Announced when a column leaves the sort. */
|
|
399
|
+
sortCleared: (columnName: string) => string;
|
|
400
|
+
/** Announced when a column is grouped by. `level` counts from one. */
|
|
401
|
+
groupedBy: (columnName: string, level: number, levelCount: number) => string;
|
|
402
|
+
/** Announced when a column leaves the grouping. */
|
|
403
|
+
groupingRemoved: (columnName: string) => string;
|
|
404
|
+
groupExpanded: string;
|
|
405
|
+
groupCollapsed: string;
|
|
406
|
+
allGroupsExpanded: string;
|
|
407
|
+
allGroupsCollapsed: string;
|
|
408
|
+
/** Announced when one change selects or deselects more than one row or column. */
|
|
409
|
+
selectedCount: (count: number, target: "rows" | "columns") => string;
|
|
410
|
+
/** Announced when a cell is selected. `rowNumber` counts from one. */
|
|
411
|
+
cellSelected: (columnName: string, rowNumber: number) => string;
|
|
412
|
+
/** Announced when one column is hidden. */
|
|
413
|
+
columnHidden: (columnName: string) => string;
|
|
414
|
+
/** Announced when one column is shown. */
|
|
415
|
+
columnShown: (columnName: string) => string;
|
|
416
|
+
/** Announced when one change hides more than one column. */
|
|
417
|
+
columnsHidden: (count: number) => string;
|
|
418
|
+
/** Announced when one change shows more than one column. */
|
|
419
|
+
columnsShown: (count: number) => string;
|
|
420
|
+
/**
|
|
421
|
+
* Announced when one action autofits more than one column, as
|
|
422
|
+
* `column.autoFitAll` does, in place of each column's `columnResized`.
|
|
423
|
+
*/
|
|
424
|
+
columnsAutoFitted: (count: number) => string;
|
|
425
|
+
/** A column header's context menu's accessible name. */
|
|
426
|
+
headerMenuLabel: (columnName: string) => string;
|
|
427
|
+
/** A data cell's context menu's accessible name — a menu for its row. */
|
|
428
|
+
cellMenuLabel: string;
|
|
429
|
+
/** A group header row's context menu's accessible name. */
|
|
430
|
+
groupMenuLabel: string;
|
|
431
|
+
/** The accessible name of the menu in the body's empty space. */
|
|
432
|
+
bodyMenuLabel: string;
|
|
433
|
+
/** The built-in `sort.ascending` command's label. */
|
|
434
|
+
sortAscending: string;
|
|
435
|
+
sortDescending: string;
|
|
436
|
+
/** `sort.clear`: takes one column out of the sort. */
|
|
437
|
+
clearSort: string;
|
|
438
|
+
/** `sort.clearAll` */
|
|
439
|
+
clearAllSorting: string;
|
|
440
|
+
/** `group.add`, naming the column it groups by. */
|
|
441
|
+
groupByColumn: (columnName: string) => string;
|
|
442
|
+
/** `group.clearAll`. `group.remove` reads `removeGroupBy`, as the group-by chip's button does. */
|
|
443
|
+
ungroupAll: string;
|
|
444
|
+
expandAllGroups: string;
|
|
445
|
+
collapseAllGroups: string;
|
|
446
|
+
/** `column.hide` */
|
|
447
|
+
hideColumn: string;
|
|
448
|
+
/** `column.autoFit`: sizes the column to its content. */
|
|
449
|
+
autoFitColumn: string;
|
|
450
|
+
autoFitAllColumns: string;
|
|
451
|
+
/** `selection.selectAllRows` */
|
|
452
|
+
selectAllRows: string;
|
|
453
|
+
/** `selection.clear` */
|
|
454
|
+
clearSelection: string;
|
|
455
|
+
/** `filter.clearAll`, which clears the search too. */
|
|
456
|
+
clearFilters: string;
|
|
457
|
+
/** `column.choose`, which opens the column chooser. */
|
|
458
|
+
chooseColumns: string;
|
|
459
|
+
/** The toolbar's accessible name, unless its `label` gives one. */
|
|
460
|
+
toolbarLabel: string;
|
|
461
|
+
/** The toolbar's search box's accessible name. */
|
|
462
|
+
searchLabel: string;
|
|
463
|
+
/** Shown in the toolbar's empty search box. */
|
|
464
|
+
searchPlaceholder: string;
|
|
465
|
+
/** The toolbar's "More" button, holding the items that do not fit. */
|
|
466
|
+
moreToolbarItems: string;
|
|
467
|
+
/** Announced when a search settles: how many rows it found. */
|
|
468
|
+
searchResults: (count: number) => string;
|
|
469
|
+
/** The column chooser's accessible name. */
|
|
470
|
+
columnChooserLabel: string;
|
|
471
|
+
/** The column chooser's search box's accessible name. */
|
|
472
|
+
columnChooserSearchLabel: string;
|
|
473
|
+
/** The column chooser's checkbox showing or hiding every column its search lists. */
|
|
474
|
+
showAllColumns: string;
|
|
475
|
+
/** Shown in the column chooser when its search matches no column. */
|
|
476
|
+
noMatchingColumns: string;
|
|
477
|
+
/**
|
|
478
|
+
* A condition's operator, as a filter menu lists it. `family` is the
|
|
479
|
+
* column's (`filterOperatorFamily`), so a date can read `lt` as "Before"
|
|
480
|
+
* where a number reads "Less than".
|
|
481
|
+
*/
|
|
482
|
+
filterOperatorLabel: (operator: FilterOperator, family: FilterOperatorFamily) => string;
|
|
483
|
+
/** A filter checklist's item for the column's blank cells. */
|
|
484
|
+
filterBlanks: string;
|
|
485
|
+
/**
|
|
486
|
+
* Shown in place of a filter checklist whose column holds more values
|
|
487
|
+
* than `filterMenu.valueLimit`, until something is searched.
|
|
488
|
+
*/
|
|
489
|
+
filterSearchFirst: (total: number) => string;
|
|
490
|
+
/** Shown under a searched filter checklist `filterMenu.valueLimit` cut short: how many matches it left out. */
|
|
491
|
+
filterMoreValues: (count: number) => string;
|
|
492
|
+
/** `filter.open`, which opens a column's filter menu. */
|
|
493
|
+
openFilter: string;
|
|
494
|
+
/** `filter.clear`, and the filter menu's button doing the same: clears one column's filter. */
|
|
495
|
+
clearColumnFilter: string;
|
|
496
|
+
/** A column's filter menu's accessible name. */
|
|
497
|
+
filterMenuLabel: (columnName: string) => string;
|
|
498
|
+
/** What a column header is described as while its column is filtered. */
|
|
499
|
+
columnFiltered: string;
|
|
500
|
+
/** The filter menu's button applying what it holds. */
|
|
501
|
+
applyFilter: string;
|
|
502
|
+
/** The filter menu's button closing it without applying. */
|
|
503
|
+
cancelFilter: string;
|
|
504
|
+
/**
|
|
505
|
+
* Shown in a filter menu for a filter its editor cannot show — a
|
|
506
|
+
* predicate, a text query, a group across columns — which applying
|
|
507
|
+
* replaces.
|
|
508
|
+
*/
|
|
509
|
+
customFilter: string;
|
|
510
|
+
/** Announced when a filter menu applies: how many rows the filter keeps, of how many. */
|
|
511
|
+
filterResults: (shown: number, total: number) => string;
|
|
512
|
+
/** The accessible name of one of a filter menu's conditions. `position` counts from one. */
|
|
513
|
+
filterConditionLabel: (position: number) => string;
|
|
514
|
+
/** The accessible name of a condition's operator picker. */
|
|
515
|
+
filterOperatorFieldLabel: string;
|
|
516
|
+
/** The accessible name of a condition's value box. */
|
|
517
|
+
filterValueLabel: string;
|
|
518
|
+
/** The accessible name of a `between` condition's first value box, its lower end. */
|
|
519
|
+
filterFromLabel: string;
|
|
520
|
+
/** The accessible name of a `between` condition's second value box, its upper end. */
|
|
521
|
+
filterToLabel: string;
|
|
522
|
+
/** The accessible name of the choice joining a filter menu's two conditions. */
|
|
523
|
+
filterCombinatorLabel: string;
|
|
524
|
+
/** Joins two conditions: a row has to meet both. */
|
|
525
|
+
filterAnd: string;
|
|
526
|
+
/** Joins two conditions: a row has to meet either. */
|
|
527
|
+
filterOr: string;
|
|
528
|
+
/**
|
|
529
|
+
* Shown under a filter menu's conditions when one's value is missing or
|
|
530
|
+
* doesn't read as its column's `family` (`filterOperatorFamily`) — "Enter
|
|
531
|
+
* a number" on a number column.
|
|
532
|
+
*/
|
|
533
|
+
filterValueInvalid: (family: FilterOperatorFamily) => string;
|
|
534
|
+
/** The accessible name of a filter checklist's search box. */
|
|
535
|
+
filterSearchLabel: string;
|
|
536
|
+
/** The checkbox above a filter checklist checking every value its search shows. */
|
|
537
|
+
filterSelectAll: string;
|
|
538
|
+
/** The accessible name of a filter checklist's list of values. */
|
|
539
|
+
filterValuesLabel: string;
|
|
540
|
+
/**
|
|
541
|
+
* Shown above a filter checklist whose column is filtered by conditions,
|
|
542
|
+
* which checking values replaces.
|
|
543
|
+
*/
|
|
544
|
+
filterByCondition: string;
|
|
545
|
+
/**
|
|
546
|
+
* The excel editor's button opening the conditions its column offers, and
|
|
547
|
+
* that menu's accessible name — "Number filters" on a number column, by
|
|
548
|
+
* its `family` (`filterOperatorFamily`).
|
|
549
|
+
*/
|
|
550
|
+
filterOperatorMenu: (family: FilterOperatorFamily) => string;
|
|
551
|
+
/** The button taking the excel editor from a condition back to its checklist. */
|
|
552
|
+
filterBackToValues: string;
|
|
553
|
+
/** The toolbar's `"export"` dropdown, listing the export commands. */
|
|
554
|
+
exportMenu: string;
|
|
555
|
+
/** `export.csv` */
|
|
556
|
+
exportCsv: string;
|
|
557
|
+
/** `export.json` */
|
|
558
|
+
exportJson: string;
|
|
559
|
+
/** `export.xlsx`, shown once an xlsx writer is registered. */
|
|
560
|
+
exportXlsx: string;
|
|
561
|
+
/** `export.pdf`, shown once a PDF writer is registered. */
|
|
562
|
+
exportPdf: string;
|
|
563
|
+
/** `exportSelection.csv`: the selected rows only. */
|
|
564
|
+
exportSelectionCsv: string;
|
|
565
|
+
/** `exportSelection.json` */
|
|
566
|
+
exportSelectionJson: string;
|
|
567
|
+
/** `exportSelection.xlsx` */
|
|
568
|
+
exportSelectionXlsx: string;
|
|
569
|
+
/** Announced when an export's writer fails, so no file is saved. */
|
|
570
|
+
exportFailed: string;
|
|
571
|
+
/** `copy.cell` */
|
|
572
|
+
copyCell: string;
|
|
573
|
+
/** `copy.row` */
|
|
574
|
+
copyRow: string;
|
|
575
|
+
/** `copy.selection` */
|
|
576
|
+
copySelection: string;
|
|
577
|
+
/** Announced once a copy is on the clipboard. */
|
|
578
|
+
copied: (count: number, unit: "cells" | "rows" | "columns") => string;
|
|
579
|
+
/** Announced when the browser refuses the clipboard, so nothing was copied. */
|
|
580
|
+
copyFailed: string;
|
|
581
|
+
/** `print` */
|
|
582
|
+
print: string;
|
|
583
|
+
}
|
|
584
|
+
/**
|
|
585
|
+
* The grid's own English, its counts printed in `locale`'s digits —
|
|
586
|
+
* "1,204 of 10,000 rows" under `"en"`, "1.204 of 10.000 rows" under
|
|
587
|
+
* `"de-DE"`. Without a locale, the runtime's own; that one is
|
|
588
|
+
* `defaultMessages`.
|
|
589
|
+
*/
|
|
590
|
+
declare function createDefaultMessages(locale?: FormatLocale): GridMessages;
|
|
591
|
+
/** The grid's own English, which `messages` replaces key by key. */
|
|
592
|
+
declare const defaultMessages: GridMessages;
|
|
593
|
+
/**
|
|
594
|
+
* `messages` over the defaults for `locale` — every key the grid needs,
|
|
595
|
+
* whichever the caller gave, the defaults counting in `locale`'s digits. The
|
|
596
|
+
* defaults themselves, same object for the same locale, when it gave none, so
|
|
597
|
+
* a renderer memoising on the result does not see a change that is not one.
|
|
598
|
+
*/
|
|
599
|
+
declare function resolveMessages(messages: Partial<GridMessages> | undefined, locale?: FormatLocale): GridMessages;
|
|
600
|
+
|
|
601
|
+
/**
|
|
602
|
+
* A value an export stores as it is rather than as text — what a cell's
|
|
603
|
+
* `ExportCell.value` holds and a column's `exportValue` returns. Narrow on
|
|
604
|
+
* purpose: these are the kinds every format has a reading for (a spreadsheet
|
|
605
|
+
* number, date or boolean cell; a JSON scalar), so nothing a writer cannot
|
|
606
|
+
* represent reaches it.
|
|
607
|
+
*/
|
|
608
|
+
type ExportScalar = string | number | boolean | Date | null;
|
|
609
|
+
/**
|
|
610
|
+
* One cell of an export, in both of its readings. `text` is what the grid
|
|
611
|
+
* shows — CSV, the clipboard and print write it, so a file reads as the
|
|
612
|
+
* screen does. `value` is the typed value a spreadsheet stores, so a number
|
|
613
|
+
* stays a number a formula can sum rather than text that looks like one.
|
|
614
|
+
*/
|
|
615
|
+
interface ExportCell {
|
|
616
|
+
readonly value: ExportScalar;
|
|
617
|
+
readonly text: string;
|
|
618
|
+
}
|
|
619
|
+
/**
|
|
620
|
+
* A column of an export, settled once so that no writer reads a column
|
|
621
|
+
* definition for itself. `type` and `format` pass through for a writer that
|
|
622
|
+
* keeps typed values, which derives its own number or date format from them.
|
|
623
|
+
*/
|
|
624
|
+
interface ExportColumn {
|
|
625
|
+
readonly id: string;
|
|
626
|
+
/** The column's name as text — `resolveColumnHeaderText`, never markup. */
|
|
627
|
+
readonly header: string;
|
|
628
|
+
/** The column's `type`, `"string"` when it has none. */
|
|
629
|
+
readonly type: ColumnType;
|
|
630
|
+
readonly format?: Intl.NumberFormatOptions | Intl.DateTimeFormatOptions | undefined;
|
|
631
|
+
/** How the column's cells align, after falling back to its type. */
|
|
632
|
+
readonly alignment: ColumnAlignment;
|
|
633
|
+
/** Width in px: as rendered for a visible column, as it would start for a hidden one. */
|
|
634
|
+
readonly width: number;
|
|
635
|
+
}
|
|
636
|
+
/** One row of data: a cell per `ExportTable.columns` entry, in that order. */
|
|
637
|
+
interface ExportDataRow {
|
|
638
|
+
readonly kind: "data";
|
|
639
|
+
readonly rowId: string;
|
|
640
|
+
readonly cells: readonly ExportCell[];
|
|
641
|
+
}
|
|
642
|
+
/**
|
|
643
|
+
* A group header. `label` is the header's text, `"Region: West"`; `cells`
|
|
644
|
+
* holds the group's aggregates under their own columns when the grid shows
|
|
645
|
+
* them inline in the header, and is empty text elsewhere — a cell per
|
|
646
|
+
* column either way, so a writer can lay it out like any other row.
|
|
647
|
+
*/
|
|
648
|
+
interface ExportGroupRow {
|
|
649
|
+
readonly kind: "group";
|
|
650
|
+
/** Nesting depth, 0 for a top-level group. */
|
|
651
|
+
readonly level: number;
|
|
652
|
+
readonly groupId: string;
|
|
653
|
+
readonly label: string;
|
|
654
|
+
/** Data rows under this group, at every depth. */
|
|
655
|
+
readonly count: number;
|
|
656
|
+
readonly cells: readonly ExportCell[];
|
|
657
|
+
}
|
|
658
|
+
/**
|
|
659
|
+
* A group's aggregates as a row of their own, after everything in the group
|
|
660
|
+
* — present where the grid shows them that way (`groupAggregateDisplay:
|
|
661
|
+
* "row"`), and at the same `level` as its group.
|
|
662
|
+
*/
|
|
663
|
+
interface ExportGroupSummaryRow {
|
|
664
|
+
readonly kind: "groupSummary";
|
|
665
|
+
readonly level: number;
|
|
666
|
+
readonly cells: readonly ExportCell[];
|
|
667
|
+
}
|
|
668
|
+
/**
|
|
669
|
+
* A body row of an export, in the order the grid shows them. Discriminate on
|
|
670
|
+
* `kind`.
|
|
671
|
+
*/
|
|
672
|
+
type ExportRow = ExportDataRow | ExportGroupRow | ExportGroupSummaryRow;
|
|
673
|
+
/**
|
|
674
|
+
* The grand total — every aggregate over the exported rows. Its own kind
|
|
675
|
+
* rather than an `ExportRow`, since it only ever stands in
|
|
676
|
+
* `ExportTable.footer`, never among the body rows.
|
|
677
|
+
*/
|
|
678
|
+
interface ExportTotalRow {
|
|
679
|
+
readonly kind: "total";
|
|
680
|
+
readonly cells: readonly ExportCell[];
|
|
681
|
+
}
|
|
682
|
+
/**
|
|
683
|
+
* What an export writes, whatever the format: the grid's view as data,
|
|
684
|
+
* built by `buildExportTable` from the controller's view and state and
|
|
685
|
+
* never from the page. Every serialiser and writer reads this one shape, so
|
|
686
|
+
* a file, the clipboard and a print cannot disagree.
|
|
687
|
+
*/
|
|
688
|
+
interface ExportTable {
|
|
689
|
+
readonly columns: readonly ExportColumn[];
|
|
690
|
+
/** Whether a header row of column names leads the output. */
|
|
691
|
+
readonly header: boolean;
|
|
692
|
+
readonly rows: readonly ExportRow[];
|
|
693
|
+
/** The grand total, or `null` when there are no aggregates to total. */
|
|
694
|
+
readonly footer: ExportTotalRow | null;
|
|
695
|
+
}
|
|
696
|
+
/**
|
|
697
|
+
* Narrows what an export holds. Every field defaults to what the user sees,
|
|
698
|
+
* with nothing hidden by paging or a collapsed group.
|
|
699
|
+
*/
|
|
700
|
+
interface ExportOptions {
|
|
701
|
+
/**
|
|
702
|
+
* Which rows: `"all"` (the default) every row the filter, search and sort
|
|
703
|
+
* leave, across every page; `"page"` the data rows on the current page;
|
|
704
|
+
* `"selection"` the selected rows among those `"all"` holds.
|
|
705
|
+
*/
|
|
706
|
+
readonly scope?: "all" | "page" | "selection" | undefined;
|
|
707
|
+
/**
|
|
708
|
+
* Which columns: `"visible"` (the default) those shown, in their current
|
|
709
|
+
* order; `"all"` hidden ones too; or a list of column ids, in that order.
|
|
710
|
+
* A column with `exportable: false` is left out of every one.
|
|
711
|
+
*/
|
|
712
|
+
readonly columns?: "visible" | "all" | readonly string[] | undefined;
|
|
713
|
+
/**
|
|
714
|
+
* Whether a grouped grid exports its group header rows, every group
|
|
715
|
+
* expanded whatever its state on screen. Defaults to `true`; `false`
|
|
716
|
+
* keeps the rows in grouped order without the headers.
|
|
717
|
+
*/
|
|
718
|
+
readonly includeGroups?: boolean | undefined;
|
|
719
|
+
/** Whether group aggregates and the grand total are exported. Defaults to `true`. */
|
|
720
|
+
readonly includeAggregates?: boolean | undefined;
|
|
721
|
+
/** Whether a header row of column names leads the output. Defaults to `true`. */
|
|
722
|
+
readonly includeHeader?: boolean | undefined;
|
|
723
|
+
}
|
|
724
|
+
|
|
725
|
+
/**
|
|
726
|
+
* What an export is built from: the grid's view and state as a controller
|
|
727
|
+
* holds them, never the page — so rows virtualised, paged or scrolled out of
|
|
728
|
+
* sight still export. Typed as the few fields it reads, so a
|
|
729
|
+
* `GridCommandContext` is one as it stands.
|
|
730
|
+
*/
|
|
731
|
+
interface ExportSource<Row> {
|
|
732
|
+
readonly view: GridView<Row, unknown>;
|
|
733
|
+
readonly state: Pick<GridState<Row>, "groupBy" | "rowSelection" | "columnSizing">;
|
|
734
|
+
readonly options: {
|
|
735
|
+
readonly locale?: FormatLocale;
|
|
736
|
+
readonly aggregates?: AggregateState<Row> | undefined;
|
|
737
|
+
readonly groupAggregateDisplay?: GroupAggregateDisplay | undefined;
|
|
738
|
+
readonly columnSizeDefaults?: Partial<ColumnSizeDefaults> | undefined;
|
|
739
|
+
};
|
|
740
|
+
readonly messages: Pick<GridMessages, "booleanTrue" | "booleanFalse" | "blankGroupValue">;
|
|
741
|
+
}
|
|
742
|
+
/**
|
|
743
|
+
* The grid's view as an `ExportTable` — the one model every export format,
|
|
744
|
+
* the clipboard and print are written from, so none of them reads the page
|
|
745
|
+
* and none can disagree with another.
|
|
746
|
+
*
|
|
747
|
+
* By default it holds what the user sees, minus what only hides it: every
|
|
748
|
+
* row the filter, search and sort leave, across every page; the visible
|
|
749
|
+
* columns in their current order, less any with `exportable: false`; and,
|
|
750
|
+
* in a grouped grid, every group expanded whatever its state on screen,
|
|
751
|
+
* with its aggregates where the grid shows them. `options` narrows it.
|
|
752
|
+
*
|
|
753
|
+
* Each cell carries the text `formatCellValue` makes of it, so the export
|
|
754
|
+
* reads as the screen does, and a typed value — the column's `exportValue`,
|
|
755
|
+
* else the raw value when it is a string, number, boolean or `Date`.
|
|
756
|
+
*
|
|
757
|
+
* The groups are rebuilt from the exported rows rather than read off
|
|
758
|
+
* `displayRows`, which omits a collapsed group's rows; so group counts,
|
|
759
|
+
* subtotals and the grand total describe exactly the rows exported — the
|
|
760
|
+
* selection, under `scope: "selection"`, not the whole grid.
|
|
761
|
+
*/
|
|
762
|
+
declare function buildExportTable<Row>(source: ExportSource<Row>, options?: ExportOptions): ExportTable;
|
|
763
|
+
|
|
764
|
+
/**
|
|
765
|
+
* What a copy is built from: an export's source, with the column and cell
|
|
766
|
+
* selection a selection copy reads as well. A `GridCommandContext` is one
|
|
767
|
+
* as it stands.
|
|
768
|
+
*/
|
|
769
|
+
interface CopySource<Row> extends ExportSource<Row> {
|
|
770
|
+
readonly state: Pick<GridState<Row>, "groupBy" | "rowSelection" | "columnSizing" | "columnSelection" | "cellSelection">;
|
|
771
|
+
}
|
|
772
|
+
/**
|
|
773
|
+
* What to copy: one cell, one row, or whatever the grid has selected — the
|
|
774
|
+
* selected rows, else the selected columns, else the selected cell.
|
|
775
|
+
*/
|
|
776
|
+
type CopyRequest = {
|
|
777
|
+
readonly kind: "cell";
|
|
778
|
+
readonly rowId: string;
|
|
779
|
+
readonly columnId: string;
|
|
780
|
+
} | {
|
|
781
|
+
readonly kind: "row";
|
|
782
|
+
readonly rowId: string;
|
|
783
|
+
} | {
|
|
784
|
+
readonly kind: "selection";
|
|
785
|
+
};
|
|
786
|
+
/**
|
|
787
|
+
* A copy in the two forms the clipboard carries, with what it holds for the
|
|
788
|
+
* announcement: `count` cells, rows or columns.
|
|
789
|
+
*/
|
|
790
|
+
interface CopyContent {
|
|
791
|
+
/** Tab-separated text, as `toTsv` writes it — what a spreadsheet splits into cells. */
|
|
792
|
+
readonly text: string;
|
|
793
|
+
/** The same as an HTML table, as `toHtmlTable` writes it — what a word processor keeps the columns of. */
|
|
794
|
+
readonly html: string;
|
|
795
|
+
readonly count: number;
|
|
796
|
+
readonly unit: "cells" | "rows" | "columns";
|
|
797
|
+
}
|
|
798
|
+
/**
|
|
799
|
+
* What `request` copies, as tab-separated text and an HTML table, or `null`
|
|
800
|
+
* when there is nothing to copy — a row the filter hides, a column hidden
|
|
801
|
+
* or marked `exportable: false`, or an empty selection.
|
|
802
|
+
*
|
|
803
|
+
* Built from the export model, never the page, so a copy holds exactly what
|
|
804
|
+
* an export would and reads as the grid shows it: each cell's formatted
|
|
805
|
+
* text, the shown columns in their order less any with `exportable: false`.
|
|
806
|
+
* The text has no byte order mark and no formula neutralising — what is
|
|
807
|
+
* copied is what is seen, and pasting it is the user's own act.
|
|
808
|
+
*
|
|
809
|
+
* A cell copies its text alone, and a row its cells without a header. A
|
|
810
|
+
* selection copies the selected rows, in the order the grid shows them and
|
|
811
|
+
* under a header row once there are two or more; else the selected columns
|
|
812
|
+
* over every row the filter leaves, under their header; else the selected
|
|
813
|
+
* cell.
|
|
814
|
+
*/
|
|
815
|
+
declare function copyContent<Row>(source: CopySource<Row>, request: CopyRequest): CopyContent | null;
|
|
816
|
+
|
|
817
|
+
/** Which way the paper is turned. */
|
|
818
|
+
type PrintOrientation = "portrait" | "landscape";
|
|
819
|
+
/**
|
|
820
|
+
* How a grid prints: which rows and columns (every `ExportOptions` field),
|
|
821
|
+
* the text around the table, and the page it is laid out on. The grid's
|
|
822
|
+
* `print` option.
|
|
823
|
+
*/
|
|
824
|
+
interface PrintOptions extends ExportOptions {
|
|
825
|
+
/** A heading above the table, and the printed document's title. */
|
|
826
|
+
readonly title?: string | undefined;
|
|
827
|
+
/** A line under the title. */
|
|
828
|
+
readonly subtitle?: string | undefined;
|
|
829
|
+
/** A line after the table. */
|
|
830
|
+
readonly footer?: string | undefined;
|
|
831
|
+
/**
|
|
832
|
+
* When the print was made, under the title: `true` for now, or a `Date`
|
|
833
|
+
* to print instead. Off by default.
|
|
834
|
+
*/
|
|
835
|
+
readonly timestamp?: boolean | Date | undefined;
|
|
836
|
+
/** The language the timestamp is written in. Defaults to the grid's. */
|
|
837
|
+
readonly locale?: FormatLocale;
|
|
838
|
+
/**
|
|
839
|
+
* Which way the paper is turned. Defaults to `"landscape"` for a table of
|
|
840
|
+
* more than six columns, which rarely fits a portrait page, else
|
|
841
|
+
* `"portrait"`.
|
|
842
|
+
*/
|
|
843
|
+
readonly orientation?: PrintOrientation | undefined;
|
|
844
|
+
/**
|
|
845
|
+
* A page size CSS names — `"A4"` (the default), `"Letter"`, `"A3"`,
|
|
846
|
+
* `"Legal"`.
|
|
847
|
+
*/
|
|
848
|
+
readonly paperSize?: "A4" | "Letter" | (string & {}) | undefined;
|
|
849
|
+
/** Whether each page is numbered, "3 / 12", where the browser can. Defaults to `true`. */
|
|
850
|
+
readonly pageNumbers?: boolean | undefined;
|
|
851
|
+
/**
|
|
852
|
+
* Whether a wide table is squeezed onto the page — a smaller font and
|
|
853
|
+
* fixed column widths that wrap their text — rather than run off its
|
|
854
|
+
* edge. Defaults to `false`.
|
|
855
|
+
*/
|
|
856
|
+
readonly fitToWidth?: boolean | undefined;
|
|
857
|
+
/** CSS added after the print stylesheet, to restyle the printed table. */
|
|
858
|
+
readonly styles?: string | undefined;
|
|
859
|
+
}
|
|
860
|
+
/**
|
|
861
|
+
* The page a print is laid out on, every choice settled — what
|
|
862
|
+
* `@gridkitjs/dom`'s `printStyles` turns into the page's CSS.
|
|
863
|
+
*/
|
|
864
|
+
interface PrintPage {
|
|
865
|
+
readonly paperSize: string;
|
|
866
|
+
readonly orientation: PrintOrientation;
|
|
867
|
+
readonly pageNumbers: boolean;
|
|
868
|
+
readonly fitToWidth: boolean;
|
|
869
|
+
}
|
|
870
|
+
/** A print ready for a renderer to put on paper: what `buildPrintDocument` returns. */
|
|
871
|
+
interface PrintDocument {
|
|
872
|
+
/**
|
|
873
|
+
* The document's title as text, `""` when untitled — what the browser
|
|
874
|
+
* puts in a page's header and names a PDF saved from the print dialog.
|
|
875
|
+
*/
|
|
876
|
+
readonly title: string;
|
|
877
|
+
/** The `<body>`'s markup: the heading, the table and the footer, every piece of text escaped. */
|
|
878
|
+
readonly bodyHtml: string;
|
|
879
|
+
readonly page: PrintPage;
|
|
880
|
+
}
|
|
881
|
+
/**
|
|
882
|
+
* The table as a printable document: its heading — the title, subtitle and
|
|
883
|
+
* timestamp `options` set — then the table as `toHtmlTable` writes it, then
|
|
884
|
+
* the footer line, with the page it is laid out on. Every piece of text is
|
|
885
|
+
* escaped. It holds no styles: putting it on paper, with a stylesheet for
|
|
886
|
+
* the page, is the renderer's — `@gridkitjs/dom`'s `printStyles` and
|
|
887
|
+
* `printDocument` in a browser.
|
|
888
|
+
*
|
|
889
|
+
* The heading and footer carry semantic class names for a stylesheet:
|
|
890
|
+
* `gridkit-print-header` around `print-title`, `print-subtitle` and
|
|
891
|
+
* `print-timestamp`, and `gridkit-print-footer`.
|
|
892
|
+
*/
|
|
893
|
+
declare function buildPrintDocument(table: ExportTable, options?: PrintOptions): PrintDocument;
|
|
894
|
+
/**
|
|
895
|
+
* What `exportPrintDocument` prints from: an `ExportSource` that may carry
|
|
896
|
+
* the grid's `label`. A `GridCommandContext` is one as it stands.
|
|
897
|
+
*/
|
|
898
|
+
interface PrintSource<Row> extends ExportSource<Row> {
|
|
899
|
+
readonly options: ExportSource<Row>["options"] & {
|
|
900
|
+
readonly label?: string | undefined;
|
|
901
|
+
};
|
|
902
|
+
}
|
|
903
|
+
/**
|
|
904
|
+
* The grid's view as a print document: the table `options` narrow, laid out
|
|
905
|
+
* as `buildPrintDocument` lays it out, with the timestamp in the grid's
|
|
906
|
+
* locale unless `options` name another. Given no `title`, it takes the
|
|
907
|
+
* grid's `label` — the name a screen reader already reads for it; `""`
|
|
908
|
+
* leaves it untitled.
|
|
909
|
+
*/
|
|
910
|
+
declare function exportPrintDocument<Row>(source: PrintSource<Row>, options?: PrintOptions): PrintDocument;
|
|
911
|
+
|
|
912
|
+
/** How `toCsv` writes a file. Every field is optional. */
|
|
913
|
+
interface CsvOptions {
|
|
914
|
+
/**
|
|
915
|
+
* The field separator: `","` by default, any string, or `"auto"` for the
|
|
916
|
+
* separator a spreadsheet expects in `locale` — `";"` where a decimal is
|
|
917
|
+
* written with a comma, as in most of Europe, since a comma there is part
|
|
918
|
+
* of a number; `","` elsewhere.
|
|
919
|
+
*/
|
|
920
|
+
readonly delimiter?: string | undefined;
|
|
921
|
+
/** The locale `delimiter: "auto"` reads; the runtime's own when absent. */
|
|
922
|
+
readonly locale?: FormatLocale;
|
|
923
|
+
/** What ends each record. Defaults to `"\r\n"`, as RFC 4180 writes it. */
|
|
924
|
+
readonly eol?: string | undefined;
|
|
925
|
+
/**
|
|
926
|
+
* Whether the file starts with a UTF-8 byte order mark. Defaults to
|
|
927
|
+
* `true`: without one, Excel reads the file in the system's legacy code
|
|
928
|
+
* page and garbles every character outside ASCII.
|
|
929
|
+
*/
|
|
930
|
+
readonly bom?: boolean | undefined;
|
|
931
|
+
/**
|
|
932
|
+
* Whether a field a spreadsheet would run as a formula is written as text
|
|
933
|
+
* instead. Defaults to `true`; see `toCsv`.
|
|
934
|
+
*/
|
|
935
|
+
readonly neutralizeFormulas?: boolean | undefined;
|
|
936
|
+
/**
|
|
937
|
+
* Which reading of each cell is written: `"text"` (the default), as the
|
|
938
|
+
* grid shows it; or `"raw"`, the typed value — numbers plain, dates in ISO
|
|
939
|
+
* 8601, booleans as `true` and `false` — for a file a program reads.
|
|
940
|
+
*/
|
|
941
|
+
readonly values?: "text" | "raw" | undefined;
|
|
942
|
+
}
|
|
943
|
+
/**
|
|
944
|
+
* The table as CSV, quoted per RFC 4180: a field is quoted when it holds the
|
|
945
|
+
* delimiter, a quote or a line break, and a quote inside one is doubled, so
|
|
946
|
+
* a line break inside a cell survives. A group row writes its label in the
|
|
947
|
+
* first column; summary rows and the footer write their aggregates under
|
|
948
|
+
* their columns.
|
|
949
|
+
*
|
|
950
|
+
* A CSV file opened in a spreadsheet runs any field that starts with `=`,
|
|
951
|
+
* `+`, `-` or `@` as a formula — and a tab or a carriage return can hide
|
|
952
|
+
* such a start — so a value a user typed into the data could make another
|
|
953
|
+
* user's spreadsheet fetch a URL or run a command. By default such a field
|
|
954
|
+
* gets a leading `'`, which the spreadsheet shows as text. A cell whose
|
|
955
|
+
* value is a number keeps its leading sign, since it is one.
|
|
956
|
+
*
|
|
957
|
+
* Returns a string, not a file: making a `Blob` of it, with the type
|
|
958
|
+
* `text/csv;charset=utf-8`, is the renderer's job.
|
|
959
|
+
*/
|
|
960
|
+
declare function toCsv(table: ExportTable, options?: CsvOptions): string;
|
|
961
|
+
|
|
962
|
+
/** How `toJson` writes its text. Every field is optional. */
|
|
963
|
+
interface JsonOptions {
|
|
964
|
+
/**
|
|
965
|
+
* What each record is keyed by: `"id"` (the default), the column's id,
|
|
966
|
+
* stable whatever the header says; or `"header"`, its header text, for a
|
|
967
|
+
* reader who sees the keys. A header repeated across columns is suffixed
|
|
968
|
+
* ` (2)`, ` (3)` and so on, so no column overwrites another.
|
|
969
|
+
*/
|
|
970
|
+
readonly keys?: "id" | "header" | undefined;
|
|
971
|
+
/** Indentation, as `JSON.stringify` takes it; none by default. */
|
|
972
|
+
readonly space?: number | string | undefined;
|
|
973
|
+
}
|
|
974
|
+
/**
|
|
975
|
+
* The table's data rows as a JSON array of objects, one property per
|
|
976
|
+
* column holding the cell's typed value — a number stays a number, a `Date`
|
|
977
|
+
* becomes its ISO 8601 string. Group headers, summary rows and the footer
|
|
978
|
+
* are left out: JSON is read by programs, which group and total for
|
|
979
|
+
* themselves, and a row that is not data would only have to be filtered
|
|
980
|
+
* out again.
|
|
981
|
+
*
|
|
982
|
+
* Returns a string; making a `Blob` of it, with the type
|
|
983
|
+
* `application/json`, is the renderer's job.
|
|
984
|
+
*/
|
|
985
|
+
declare function toJson(table: ExportTable, options?: JsonOptions): string;
|
|
986
|
+
|
|
987
|
+
/**
|
|
988
|
+
* How a grid exports unless a call says otherwise: which rows and columns
|
|
989
|
+
* (every `ExportOptions` field), what the file is called, and each built-in
|
|
990
|
+
* format's settings. The grid's `export` option.
|
|
991
|
+
*/
|
|
992
|
+
interface GridExportOptions extends ExportOptions {
|
|
993
|
+
/**
|
|
994
|
+
* The file's name, without its extension — the writer's is added unless
|
|
995
|
+
* the name already ends with it. A function is asked per export with the
|
|
996
|
+
* format, `"csv"` or `"xlsx"`. Defaults to `"export"`.
|
|
997
|
+
*/
|
|
998
|
+
readonly fileName?: string | ((format: string) => string) | undefined;
|
|
999
|
+
/**
|
|
1000
|
+
* How the CSV writer writes. Its `locale`, which `delimiter: "auto"`
|
|
1001
|
+
* reads, defaults to the grid's.
|
|
1002
|
+
*/
|
|
1003
|
+
readonly csv?: CsvOptions | undefined;
|
|
1004
|
+
/** How the JSON writer writes. */
|
|
1005
|
+
readonly json?: JsonOptions | undefined;
|
|
1006
|
+
}
|
|
1007
|
+
/** What a writer is given beside the table: the grid's language and the export's settings. */
|
|
1008
|
+
interface ExportWriteContext {
|
|
1009
|
+
/** The grid's `locale`. */
|
|
1010
|
+
readonly locale: FormatLocale;
|
|
1011
|
+
/** The grid's messages, over the defaults. */
|
|
1012
|
+
readonly messages: GridMessages;
|
|
1013
|
+
/**
|
|
1014
|
+
* The export's options, where a writer finds its own settings: the CSV
|
|
1015
|
+
* writer reads `csv`, the JSON writer `json`. A writer of the app's own
|
|
1016
|
+
* takes its settings when it is made instead, as a closure.
|
|
1017
|
+
*/
|
|
1018
|
+
readonly options: GridExportOptions;
|
|
1019
|
+
}
|
|
1020
|
+
/**
|
|
1021
|
+
* One export format: how to write an `ExportTable` as a file of it, and what
|
|
1022
|
+
* the file is. CSV and JSON ship with the grid; any other — xlsx from
|
|
1023
|
+
* `@gridkitjs/export-xlsx`, or one of the app's own — is registered through
|
|
1024
|
+
* the grid's `exportWriters`.
|
|
1025
|
+
*
|
|
1026
|
+
* `write` returns the file's contents, not a file: text, bytes, or a promise
|
|
1027
|
+
* of either for a writer that loads a library first. Making a `Blob` of it
|
|
1028
|
+
* is the renderer's job.
|
|
1029
|
+
*/
|
|
1030
|
+
interface ExportWriter {
|
|
1031
|
+
/** The id the grid knows it by — `"csv"`, `"xlsx"`; one per grid. */
|
|
1032
|
+
readonly format: string;
|
|
1033
|
+
/** Without the dot: `"csv"`. */
|
|
1034
|
+
readonly fileExtension: string;
|
|
1035
|
+
/** The file's media type, the `Blob`'s `type`. */
|
|
1036
|
+
readonly mimeType: string;
|
|
1037
|
+
readonly write: (table: ExportTable, context: ExportWriteContext) => string | Uint8Array | Promise<string | Uint8Array>;
|
|
1038
|
+
}
|
|
1039
|
+
/** An export ready to save: what `exportFile` hands a renderer to download. */
|
|
1040
|
+
interface ExportFile {
|
|
1041
|
+
/** With its extension: `"export.csv"`. */
|
|
1042
|
+
readonly fileName: string;
|
|
1043
|
+
readonly mimeType: string;
|
|
1044
|
+
readonly content: string | Uint8Array;
|
|
1045
|
+
}
|
|
1046
|
+
/** CSV through `toCsv`, its delimiter read for the grid's locale unless `csv.locale` says otherwise. */
|
|
1047
|
+
declare const csvWriter: ExportWriter;
|
|
1048
|
+
/** The data rows as JSON, through `toJson`. */
|
|
1049
|
+
declare const jsonWriter: ExportWriter;
|
|
1050
|
+
/**
|
|
1051
|
+
* Every writer a grid can export with, by format: CSV and JSON, then
|
|
1052
|
+
* `writers` — one with a built-in's format replacing it, as an app command
|
|
1053
|
+
* replaces a built-in of the same id.
|
|
1054
|
+
*/
|
|
1055
|
+
declare function resolveExportWriters(writers: readonly ExportWriter[] | undefined): ReadonlyMap<string, ExportWriter>;
|
|
1056
|
+
|
|
1057
|
+
/**
|
|
1058
|
+
* Where a command was asked for: the part of the grid a menu was opened on,
|
|
1059
|
+
* the toolbar item pressed, or nowhere in particular for a call through a
|
|
1060
|
+
* renderer's API. A built-in reads the column, row or group it acts on from
|
|
1061
|
+
* here, and is hidden on a target that has none.
|
|
1062
|
+
*/
|
|
1063
|
+
type GridCommandTarget = {
|
|
1064
|
+
readonly area: "header";
|
|
1065
|
+
readonly columnId: string;
|
|
1066
|
+
} | {
|
|
1067
|
+
readonly area: "cell";
|
|
1068
|
+
readonly rowId: string;
|
|
1069
|
+
readonly columnId: string;
|
|
1070
|
+
} | {
|
|
1071
|
+
readonly area: "group";
|
|
1072
|
+
readonly groupId: string;
|
|
1073
|
+
readonly columnId: string;
|
|
1074
|
+
}
|
|
1075
|
+
/** Empty body space, or a grid with no rows. */
|
|
1076
|
+
| {
|
|
1077
|
+
readonly area: "body";
|
|
1078
|
+
} | {
|
|
1079
|
+
readonly area: "toolbar";
|
|
1080
|
+
readonly itemId: string;
|
|
1081
|
+
}
|
|
1082
|
+
/** A renderer's API, with no particular place. */
|
|
1083
|
+
| {
|
|
1084
|
+
readonly area: "grid";
|
|
1085
|
+
};
|
|
1086
|
+
/**
|
|
1087
|
+
* Where a command was run from: a context menu, the toolbar, a renderer's
|
|
1088
|
+
* API, or a column's filter menu — its sort entries and its "Clear filter".
|
|
1089
|
+
*/
|
|
1090
|
+
type GridCommandSource = "contextMenu" | "toolbar" | "api" | "filterMenu";
|
|
1091
|
+
/** What `onCommand` is told of a command, or an inline menu item, that ran. */
|
|
1092
|
+
interface GridCommandEvent {
|
|
1093
|
+
/** The command's id, or the inline item's. */
|
|
1094
|
+
readonly commandId: string;
|
|
1095
|
+
/** Where it was asked for. */
|
|
1096
|
+
readonly target: GridCommandTarget;
|
|
1097
|
+
readonly source: GridCommandSource;
|
|
1098
|
+
}
|
|
1099
|
+
/**
|
|
1100
|
+
* The panels a command can ask a renderer to open: the column chooser, and
|
|
1101
|
+
* a column's filter menu, which opens on a header target only.
|
|
1102
|
+
*/
|
|
1103
|
+
type GridPanelKind = "columnChooser" | "filter";
|
|
1104
|
+
/**
|
|
1105
|
+
* What a command needs that only a renderer has: a DOM to measure, panels to
|
|
1106
|
+
* open, a live region to speak through. A caller with none of these — a test,
|
|
1107
|
+
* a script in Node — passes members that do nothing.
|
|
1108
|
+
*/
|
|
1109
|
+
interface GridCommandHost {
|
|
1110
|
+
/** Sizes each column to fit its content, as double-clicking its resize handle does. */
|
|
1111
|
+
readonly autoFitColumns: (columnIds: readonly string[]) => void;
|
|
1112
|
+
/** Opens one of the grid's panels, anchored to where the command was asked for. */
|
|
1113
|
+
readonly openPanel: (kind: GridPanelKind, target: GridCommandTarget) => void;
|
|
1114
|
+
/** Reads `text` out through the grid's live region. */
|
|
1115
|
+
readonly announce: (text: string) => void;
|
|
1116
|
+
/**
|
|
1117
|
+
* Saves an export as a file — in a browser, a download. A promise is the
|
|
1118
|
+
* file of a writer still writing; the host waits for it, and reports a
|
|
1119
|
+
* rejected one rather than saving.
|
|
1120
|
+
*/
|
|
1121
|
+
readonly saveFile: (file: ExportFile | Promise<ExportFile>) => void;
|
|
1122
|
+
/**
|
|
1123
|
+
* Puts a copy on the clipboard, as text and as HTML, and announces it —
|
|
1124
|
+
* `count` and `unit` say what to announce — or that the browser refused.
|
|
1125
|
+
*/
|
|
1126
|
+
readonly writeClipboard: (content: CopyContent) => void;
|
|
1127
|
+
/**
|
|
1128
|
+
* Puts a print document on paper — in a browser, through the print
|
|
1129
|
+
* dialog. `options` are those it was built under, for what the host adds
|
|
1130
|
+
* itself, such as `styles` over its print stylesheet.
|
|
1131
|
+
*/
|
|
1132
|
+
readonly print: (document: PrintDocument, options: PrintOptions) => void;
|
|
1133
|
+
}
|
|
1134
|
+
/**
|
|
1135
|
+
* Every action of the controller — the only way a command changes state, so
|
|
1136
|
+
* each change reports through its slice's callback exactly as the user's own
|
|
1137
|
+
* gesture would. Leaves out `setOptions`, which is the renderer's alone,
|
|
1138
|
+
* `subscribe`, and the getters whose results the context already carries.
|
|
1139
|
+
*
|
|
1140
|
+
* Nothing left names the renderer's node type, so a controller of any `Node`
|
|
1141
|
+
* is one.
|
|
1142
|
+
*/
|
|
1143
|
+
type GridCommandActions<Row> = Omit<GridController<Row, unknown>, "getOptions" | "setOptions" | "subscribe" | "getState" | "getView">;
|
|
1144
|
+
/**
|
|
1145
|
+
* Everything a command reads to decide whether it shows, whether it is
|
|
1146
|
+
* enabled and what it does — one snapshot of the grid, taken when a menu or
|
|
1147
|
+
* toolbar is resolved. Build one with `createCommandContext`.
|
|
1148
|
+
*/
|
|
1149
|
+
interface GridCommandContext<Row> {
|
|
1150
|
+
readonly target: GridCommandTarget;
|
|
1151
|
+
readonly state: GridState<Row>;
|
|
1152
|
+
readonly view: GridView<Row, unknown>;
|
|
1153
|
+
readonly options: GridOptions<Row>;
|
|
1154
|
+
readonly messages: GridMessages;
|
|
1155
|
+
readonly actions: GridCommandActions<Row>;
|
|
1156
|
+
readonly host: GridCommandHost;
|
|
1157
|
+
/** The row a cell target is on; `null` for any other target, or a row the filter hides. */
|
|
1158
|
+
readonly row: ResolvedRow<Row> | null;
|
|
1159
|
+
/** The column a header, cell or group target names, hidden or not; `null` otherwise. */
|
|
1160
|
+
readonly column: DataColumn<Row, unknown> | null;
|
|
1161
|
+
/**
|
|
1162
|
+
* The selected rows that pass the filter, in the order they are shown,
|
|
1163
|
+
* across every page and collapsed group. A function, computed on first
|
|
1164
|
+
* call and remembered: resolving it walks every filtered row, and a toolbar
|
|
1165
|
+
* builds a context on every change without most commands ever asking.
|
|
1166
|
+
*/
|
|
1167
|
+
readonly selectedRows: () => readonly ResolvedRow<Row>[];
|
|
1168
|
+
}
|
|
1169
|
+
/**
|
|
1170
|
+
* The one implementation behind a menu item, a toolbar button and a
|
|
1171
|
+
* renderer's `runCommand`. Whether it shows and whether it is enabled are
|
|
1172
|
+
* predicates over the context, asked each time a menu or toolbar is resolved,
|
|
1173
|
+
* so a command follows the grid's state without being told about it.
|
|
1174
|
+
*/
|
|
1175
|
+
interface GridCommand<Row> {
|
|
1176
|
+
/** `"sort.ascending"` for a built-in, or any id of the app's own. Never `"separator"`, which a menu reads as one. */
|
|
1177
|
+
readonly id: string;
|
|
1178
|
+
readonly label: string | ((context: GridCommandContext<Row>) => string);
|
|
1179
|
+
/** A key the renderer maps to an icon of its own; a key it does not know draws nothing. */
|
|
1180
|
+
readonly icon?: string | undefined;
|
|
1181
|
+
/** A key-combination hint in `aria-keyshortcuts` syntax, such as `"Alt+ArrowUp"`. Shown, not bound. */
|
|
1182
|
+
readonly shortcut?: string | undefined;
|
|
1183
|
+
/** Whether the command shows here at all. Defaults to always. */
|
|
1184
|
+
readonly isVisible?: ((context: GridCommandContext<Row>) => boolean) | undefined;
|
|
1185
|
+
/** Whether it can run. A disabled command still shows, so a user can see what is not possible. Defaults to always. */
|
|
1186
|
+
readonly isEnabled?: ((context: GridCommandContext<Row>) => boolean) | undefined;
|
|
1187
|
+
/** Present for a checkable command — drawn as a checkbox item or a toggle button — and says whether it is checked. */
|
|
1188
|
+
readonly isChecked?: ((context: GridCommandContext<Row>) => boolean) | undefined;
|
|
1189
|
+
readonly execute: (context: GridCommandContext<Row>) => void;
|
|
1190
|
+
}
|
|
1191
|
+
|
|
1192
|
+
/** The id of every command `builtInCommands` returns. */
|
|
1193
|
+
type BuiltInCommandId = "sort.ascending" | "sort.descending" | "sort.clear" | "sort.clearAll" | "group.add" | "group.remove" | "group.clearAll" | "group.expandAll" | "group.collapseAll" | "column.hide" | "column.autoFit" | "column.autoFitAll" | "column.choose" | "filter.open" | "filter.clear" | "selection.selectAllRows" | "selection.clear" | "filter.clearAll" | "export.csv" | "export.json" | "export.xlsx" | "export.pdf" | "exportSelection.csv" | "exportSelection.json" | "exportSelection.xlsx" | "copy.cell" | "copy.row" | "copy.selection" | "print";
|
|
1194
|
+
/**
|
|
1195
|
+
* The icon keys the built-ins carry, which a renderer draws as icons of its
|
|
1196
|
+
* own. An app command may use them too, to look like the built-ins.
|
|
1197
|
+
*/
|
|
1198
|
+
type BuiltInCommandIcon = "sortAscending" | "sortDescending" | "group" | "hide" | "autoFit" | "copy" | "print";
|
|
1199
|
+
/**
|
|
1200
|
+
* The grid's own commands, one per action its menus and toolbar offer —
|
|
1201
|
+
* sorting, grouping, hiding, fitting and choosing columns, selecting,
|
|
1202
|
+
* clearing, exporting, copying and printing.
|
|
1203
|
+
* Labels come from `messages`, so they follow the grid's language.
|
|
1204
|
+
*
|
|
1205
|
+
* A function rather than a constant so each comes typed for the caller's
|
|
1206
|
+
* `Row`; the commands hold no state, and two calls build equal ones.
|
|
1207
|
+
*/
|
|
1208
|
+
declare function builtInCommands<Row>(): readonly GridCommand<Row>[];
|
|
1209
|
+
|
|
1210
|
+
/** A value given outright, or worked out from the context each time the menu is resolved. */
|
|
1211
|
+
type FromContext<Row, Value> = Value | ((context: GridCommandContext<Row>) => Value);
|
|
1212
|
+
/**
|
|
1213
|
+
* An item written into the menu itself rather than registered as a command —
|
|
1214
|
+
* for an action only one menu offers.
|
|
1215
|
+
*/
|
|
1216
|
+
interface MenuItemEntry<Row> {
|
|
1217
|
+
readonly type: "item";
|
|
1218
|
+
readonly id: string;
|
|
1219
|
+
readonly label: FromContext<Row, string>;
|
|
1220
|
+
readonly icon?: string | undefined;
|
|
1221
|
+
readonly shortcut?: string | undefined;
|
|
1222
|
+
readonly hidden?: FromContext<Row, boolean> | undefined;
|
|
1223
|
+
readonly disabled?: FromContext<Row, boolean> | undefined;
|
|
1224
|
+
/** Present for a checkable item, and says whether it is checked. */
|
|
1225
|
+
readonly checked?: FromContext<Row, boolean> | undefined;
|
|
1226
|
+
readonly onSelect: (context: GridCommandContext<Row>) => void;
|
|
1227
|
+
}
|
|
1228
|
+
/** An item that opens a menu of its own. Left out when nothing in it shows. */
|
|
1229
|
+
interface MenuSubmenuEntry<Row> {
|
|
1230
|
+
readonly type: "submenu";
|
|
1231
|
+
readonly id: string;
|
|
1232
|
+
readonly label: FromContext<Row, string>;
|
|
1233
|
+
readonly icon?: string | undefined;
|
|
1234
|
+
readonly items: readonly MenuEntry<Row>[];
|
|
1235
|
+
}
|
|
1236
|
+
/**
|
|
1237
|
+
* One entry of a menu as an app writes it: a command id — a built-in's or
|
|
1238
|
+
* one of its own — `"separator"`, an inline item or a submenu. The same
|
|
1239
|
+
* vocabulary every menu and toolbar is listed in.
|
|
1240
|
+
*/
|
|
1241
|
+
type MenuEntry<Row> = BuiltInCommandId | "separator" | (string & {}) | MenuItemEntry<Row> | MenuSubmenuEntry<Row>;
|
|
1242
|
+
/**
|
|
1243
|
+
* A menu item ready to draw: every label a string, every flag a boolean, and
|
|
1244
|
+
* `run` bound to the context the menu was resolved in.
|
|
1245
|
+
*/
|
|
1246
|
+
interface ResolvedMenuItem {
|
|
1247
|
+
readonly type: "item";
|
|
1248
|
+
/** The command's id, or the inline item's. */
|
|
1249
|
+
readonly id: string;
|
|
1250
|
+
readonly label: string;
|
|
1251
|
+
readonly icon?: string | undefined;
|
|
1252
|
+
readonly shortcut?: string | undefined;
|
|
1253
|
+
/** Drawn, and focusable, but `run` does nothing. */
|
|
1254
|
+
readonly disabled: boolean;
|
|
1255
|
+
/** `undefined` for an item that is not checkable. */
|
|
1256
|
+
readonly checked: boolean | undefined;
|
|
1257
|
+
/**
|
|
1258
|
+
* Runs the item — a command only when it is still visible and enabled —
|
|
1259
|
+
* and says whether it ran, so a renderer reports only what did something.
|
|
1260
|
+
*/
|
|
1261
|
+
readonly run: () => boolean;
|
|
1262
|
+
}
|
|
1263
|
+
interface ResolvedMenuSubmenu {
|
|
1264
|
+
readonly type: "submenu";
|
|
1265
|
+
readonly id: string;
|
|
1266
|
+
readonly label: string;
|
|
1267
|
+
readonly icon?: string | undefined;
|
|
1268
|
+
/** Never empty: a submenu with nothing to show is left out. */
|
|
1269
|
+
readonly items: readonly ResolvedMenuEntry[];
|
|
1270
|
+
}
|
|
1271
|
+
interface ResolvedMenuSeparator {
|
|
1272
|
+
readonly type: "separator";
|
|
1273
|
+
/**
|
|
1274
|
+
* The separator's place among the entries it was resolved from, which
|
|
1275
|
+
* stays put however the items around it come and go — a key for a
|
|
1276
|
+
* renderer that needs one, unique among its menu's separators.
|
|
1277
|
+
*/
|
|
1278
|
+
readonly key: string;
|
|
1279
|
+
}
|
|
1280
|
+
/** One entry of a menu as `resolveMenu` hands it to a renderer to draw. */
|
|
1281
|
+
type ResolvedMenuEntry = ResolvedMenuItem | ResolvedMenuSubmenu | ResolvedMenuSeparator;
|
|
1282
|
+
|
|
1283
|
+
/** The parts of a grid that open a context menu of their own. */
|
|
1284
|
+
type GridContextMenuArea = "header" | "cell" | "group" | "body";
|
|
1285
|
+
/**
|
|
1286
|
+
* Where a context menu opens: a command target in one of the context menu
|
|
1287
|
+
* areas — a column header, a data cell, a group header row, or empty space
|
|
1288
|
+
* in the body — or in `Area` alone.
|
|
1289
|
+
*/
|
|
1290
|
+
type GridContextMenuTarget<Area extends GridContextMenuArea = GridContextMenuArea> = Extract<GridCommandTarget, {
|
|
1291
|
+
readonly area: Area;
|
|
1292
|
+
}>;
|
|
1293
|
+
/** What `onContextMenuOpenChange` is told as a context menu opens or closes. */
|
|
1294
|
+
interface ContextMenuOpenChangeEvent {
|
|
1295
|
+
readonly open: boolean;
|
|
1296
|
+
/** Where the menu opened, or where the one closing had. */
|
|
1297
|
+
readonly target: GridContextMenuTarget;
|
|
1298
|
+
}
|
|
1299
|
+
/** What a function given for an area is asked, each time its menu opens. */
|
|
1300
|
+
interface GridContextMenuRequest<Row, Area extends GridContextMenuArea = GridContextMenuArea> {
|
|
1301
|
+
/** Where the menu opens. */
|
|
1302
|
+
readonly target: GridContextMenuTarget<Area>;
|
|
1303
|
+
/** The area's default entries, to keep, trim, reorder or add to. */
|
|
1304
|
+
readonly defaults: readonly MenuEntry<Row>[];
|
|
1305
|
+
/** The grid as the menu sees it — the context its items run in. */
|
|
1306
|
+
readonly context: GridCommandContext<Row>;
|
|
1307
|
+
}
|
|
1308
|
+
/**
|
|
1309
|
+
* An area's menu: its entries, or a function that works them out each time
|
|
1310
|
+
* the menu opens — from where it opens, the area's defaults and the grid's
|
|
1311
|
+
* state. A function giving `null` or `[]` shows no grid menu there, so the
|
|
1312
|
+
* browser's own menu shows.
|
|
1313
|
+
*/
|
|
1314
|
+
type GridContextMenuEntries<Row, Area extends GridContextMenuArea = GridContextMenuArea> = readonly MenuEntry<Row>[] | ((request: GridContextMenuRequest<Row, Area>) => readonly MenuEntry<Row>[] | null);
|
|
1315
|
+
/**
|
|
1316
|
+
* A grid's context menus, by area, in the vocabulary every grid menu is
|
|
1317
|
+
* written in. An area left out shows its defaults; one given `[]` shows no
|
|
1318
|
+
* grid menu, so the browser's own menu shows there.
|
|
1319
|
+
*/
|
|
1320
|
+
interface GridContextMenuOptions<Row> {
|
|
1321
|
+
/** A column header's menu. */
|
|
1322
|
+
readonly header?: GridContextMenuEntries<Row, "header"> | undefined;
|
|
1323
|
+
/** A data cell's menu, acting on its row and cell. */
|
|
1324
|
+
readonly cell?: GridContextMenuEntries<Row, "cell"> | undefined;
|
|
1325
|
+
/** A group header row's menu. */
|
|
1326
|
+
readonly group?: GridContextMenuEntries<Row, "group"> | undefined;
|
|
1327
|
+
/** The menu of the body's empty space, below the last row or in a grid with none. */
|
|
1328
|
+
readonly body?: GridContextMenuEntries<Row, "body"> | undefined;
|
|
1329
|
+
}
|
|
1330
|
+
/**
|
|
1331
|
+
* The menu each area shows unless the grid says otherwise — built-in
|
|
1332
|
+
* commands only, each hidden where it has nothing to act on, so the menu a
|
|
1333
|
+
* column header shows holds only what that column can do. The body has
|
|
1334
|
+
* none: empty space keeps the browser's menu until a grid gives it one.
|
|
1335
|
+
*/
|
|
1336
|
+
declare const defaultContextMenu: {
|
|
1337
|
+
readonly [Area in GridContextMenuArea]: readonly (BuiltInCommandId | "separator")[];
|
|
1338
|
+
};
|
|
1339
|
+
/**
|
|
1340
|
+
* Whether the `contextMenu` option opens a grid menu on `area` at all: it is
|
|
1341
|
+
* on, and gives the area entries or a function rather than `[]`. A function
|
|
1342
|
+
* may still give no menu for one place or another; this answers for the
|
|
1343
|
+
* area, as a cell's `aria-keyshortcuts` needs to before anything is asked.
|
|
1344
|
+
*/
|
|
1345
|
+
declare function hasContextMenu<Row>(contextMenu: boolean | GridContextMenuOptions<Row> | undefined, area: GridContextMenuArea): boolean;
|
|
1346
|
+
/**
|
|
1347
|
+
* The entries a grid's `contextMenu` option gives the place `context.target`
|
|
1348
|
+
* names, to resolve with `resolveMenu` in that same context: none while the
|
|
1349
|
+
* option is off — left out or `false` — or for a target no context menu
|
|
1350
|
+
* opens on; the area's defaults under `true` or when the option leaves the
|
|
1351
|
+
* area out; the entries it lists; or what its function gives this request.
|
|
1352
|
+
* No entries means no grid menu there.
|
|
1353
|
+
*/
|
|
1354
|
+
declare function contextMenuEntries<Row>(contextMenu: boolean | GridContextMenuOptions<Row> | undefined, context: GridCommandContext<Row>): readonly MenuEntry<Row>[];
|
|
1355
|
+
|
|
1356
|
+
/** Where a toolbar item's command runs: the toolbar item it was asked from. */
|
|
1357
|
+
type GridToolbarTarget = Extract<GridCommandTarget, {
|
|
1358
|
+
readonly area: "toolbar";
|
|
1359
|
+
}>;
|
|
1360
|
+
/**
|
|
1361
|
+
* A place in the toolbar the renderer fills with content of the app's own —
|
|
1362
|
+
* React's `renderToolbarItem(id)` — for anything the entries cannot say.
|
|
1363
|
+
*/
|
|
1364
|
+
interface ToolbarCustomEntry {
|
|
1365
|
+
readonly type: "custom";
|
|
1366
|
+
readonly id: string;
|
|
1367
|
+
}
|
|
1368
|
+
/**
|
|
1369
|
+
* One entry of a toolbar as an app writes it: anything a menu lists — a
|
|
1370
|
+
* command id, `"separator"`, an inline item, or a submenu, which the toolbar
|
|
1371
|
+
* draws as a dropdown button — plus the entries only a toolbar has:
|
|
1372
|
+
* `"search"`, the box searching every column; `"spacer"`, which takes up the
|
|
1373
|
+
* free space and so pushes what follows it to the far end; `"export"`, a
|
|
1374
|
+
* dropdown of the export commands that show; and a custom entry.
|
|
1375
|
+
*/
|
|
1376
|
+
type ToolbarEntry<Row> = MenuEntry<Row> | "search" | "spacer" | "export" | ToolbarCustomEntry;
|
|
1377
|
+
/**
|
|
1378
|
+
* A toolbar button ready to draw — a command, or an inline item — with
|
|
1379
|
+
* every label a string, every flag a boolean, and `run` bound to the
|
|
1380
|
+
* context of its place in the toolbar.
|
|
1381
|
+
*/
|
|
1382
|
+
interface ResolvedToolbarButton {
|
|
1383
|
+
readonly type: "button";
|
|
1384
|
+
/** The command's id, or the inline item's. */
|
|
1385
|
+
readonly id: string;
|
|
1386
|
+
/** The same as `id`. */
|
|
1387
|
+
readonly key: string;
|
|
1388
|
+
readonly label: string;
|
|
1389
|
+
readonly icon?: string | undefined;
|
|
1390
|
+
readonly shortcut?: string | undefined;
|
|
1391
|
+
/** Drawn, and focusable, but `run` does nothing. */
|
|
1392
|
+
readonly disabled: boolean;
|
|
1393
|
+
/**
|
|
1394
|
+
* Whether a toggle button is pressed — `undefined` for a button that is
|
|
1395
|
+
* not one: a checkable command or item draws as a toggle.
|
|
1396
|
+
*/
|
|
1397
|
+
readonly pressed: boolean | undefined;
|
|
1398
|
+
/** Runs the button, and says whether it ran — see `ResolvedMenuItem.run`. */
|
|
1399
|
+
readonly run: () => boolean;
|
|
1400
|
+
}
|
|
1401
|
+
/** A dropdown button, opening the menu its submenu entry lists. */
|
|
1402
|
+
interface ResolvedToolbarMenu {
|
|
1403
|
+
readonly type: "menu";
|
|
1404
|
+
readonly id: string;
|
|
1405
|
+
/** The same as `id`. */
|
|
1406
|
+
readonly key: string;
|
|
1407
|
+
readonly label: string;
|
|
1408
|
+
readonly icon?: string | undefined;
|
|
1409
|
+
/** Never empty: a dropdown with nothing to show is left out. */
|
|
1410
|
+
readonly items: readonly ResolvedMenuEntry[];
|
|
1411
|
+
}
|
|
1412
|
+
/** The search box, over the grid's global text filter. */
|
|
1413
|
+
interface ResolvedToolbarSearch {
|
|
1414
|
+
readonly type: "search";
|
|
1415
|
+
/** Always `"search"`. */
|
|
1416
|
+
readonly key: string;
|
|
1417
|
+
}
|
|
1418
|
+
/** The free space between the entries either side of it. */
|
|
1419
|
+
interface ResolvedToolbarSpacer {
|
|
1420
|
+
readonly type: "spacer";
|
|
1421
|
+
/** `spacer-<index>`, from its place among the entries it was resolved from. */
|
|
1422
|
+
readonly key: string;
|
|
1423
|
+
}
|
|
1424
|
+
/** A custom entry's place, for the renderer to fill. */
|
|
1425
|
+
interface ResolvedToolbarCustom {
|
|
1426
|
+
readonly type: "custom";
|
|
1427
|
+
readonly id: string;
|
|
1428
|
+
/** The same as `id`. */
|
|
1429
|
+
readonly key: string;
|
|
1430
|
+
}
|
|
1431
|
+
/**
|
|
1432
|
+
* One entry of a toolbar as `resolveToolbar` hands it to a renderer to draw.
|
|
1433
|
+
* Each has a `key` — an item's id, `"search"`, or a separator's or spacer's
|
|
1434
|
+
* place among the entries — unique among the toolbar's entries, which the
|
|
1435
|
+
* renderer writes into the entry's `data-gridkit-toolbar-item`.
|
|
1436
|
+
*/
|
|
1437
|
+
type ResolvedToolbarItem = ResolvedToolbarButton | ResolvedToolbarMenu | ResolvedToolbarSearch | ResolvedToolbarSpacer | ResolvedMenuSeparator | ResolvedToolbarCustom;
|
|
1438
|
+
|
|
1439
|
+
/** A grid's toolbar: what it lists, and what a screen reader calls it. */
|
|
1440
|
+
interface GridToolbarOptions<Row> {
|
|
1441
|
+
/** The toolbar's entries, in order. Left out, the defaults. */
|
|
1442
|
+
readonly items?: readonly ToolbarEntry<Row>[] | undefined;
|
|
1443
|
+
/** The toolbar's accessible name. Left out, `messages.toolbarLabel`. */
|
|
1444
|
+
readonly label?: string | undefined;
|
|
1445
|
+
}
|
|
1446
|
+
/**
|
|
1447
|
+
* What a toolbar lists unless the grid says otherwise: the search box, then
|
|
1448
|
+
* the free space, then "Clear filters" and "Choose columns" at the far end.
|
|
1449
|
+
*/
|
|
1450
|
+
declare const defaultToolbar: readonly (BuiltInCommandId | "search" | "spacer")[];
|
|
1451
|
+
/**
|
|
1452
|
+
* The entries a grid's `toolbar` option lists, to resolve with
|
|
1453
|
+
* `resolveToolbar`: none while it is off — left out or `false` — the
|
|
1454
|
+
* defaults under `true` or an object without `items`, else its `items`.
|
|
1455
|
+
* No entries means no toolbar.
|
|
1456
|
+
*/
|
|
1457
|
+
declare function toolbarEntries<Row>(toolbar: boolean | GridToolbarOptions<Row> | undefined): readonly ToolbarEntry<Row>[];
|
|
1458
|
+
|
|
1459
|
+
/** Which cell borders a grid draws. */
|
|
1460
|
+
type Borders = "horizontal" | "vertical" | "all" | "none";
|
|
1461
|
+
/** Which hover highlighting a grid shows. Every member defaults to on. */
|
|
1462
|
+
interface HoverableConfig {
|
|
1463
|
+
rows?: boolean;
|
|
1464
|
+
columns?: boolean;
|
|
1465
|
+
cells?: boolean;
|
|
1466
|
+
}
|
|
1467
|
+
/**
|
|
1468
|
+
* How the group-by bar's visibility follows the active grouping. `"always"`
|
|
1469
|
+
* renders it even with an empty `groupBy` — a fixed drop target and a
|
|
1470
|
+
* constant reminder grouping exists. `"never"` never renders it, for a grid
|
|
1471
|
+
* driving `groupBy` entirely by its own UI (a header toggle, `Alt+ArrowDown`)
|
|
1472
|
+
* or programmatically. `"auto"` renders it once `groupBy` is non-empty, or
|
|
1473
|
+
* while a header drag eligible to drop into it is in progress — so there is
|
|
1474
|
+
* always somewhere to drop the very first column, even from a fully empty
|
|
1475
|
+
* grouping.
|
|
1476
|
+
*/
|
|
1477
|
+
type GroupByBarVisibility = "always" | "auto" | "never";
|
|
1478
|
+
/**
|
|
1479
|
+
* What `getRowProps` adds to a data row: a class for the theme or the
|
|
1480
|
+
* app's own stylesheet to target, and `data-*` attributes for a test or a
|
|
1481
|
+
* script to find the row by. No inline style — styling belongs to the
|
|
1482
|
+
* stylesheet, which a class already reaches.
|
|
1483
|
+
*/
|
|
1484
|
+
interface RowProps {
|
|
1485
|
+
className?: string | undefined;
|
|
1486
|
+
/**
|
|
1487
|
+
* Set on the row alongside the grid's own `data-gridkit-*` attributes,
|
|
1488
|
+
* which win over one of the same name — the grid finds its rows by them.
|
|
1489
|
+
*/
|
|
1490
|
+
attributes?: Readonly<Record<`data-${string}`, string>> | undefined;
|
|
1491
|
+
}
|
|
1492
|
+
/**
|
|
1493
|
+
* Every setting of a grid that names no renderer's types: the data, what the
|
|
1494
|
+
* user may do with it, the state it starts in and the callbacks that report
|
|
1495
|
+
* changes. A renderer's own props are this plus what only it can express —
|
|
1496
|
+
* React's `columns` (whose templates return `ReactNode`), its pager and
|
|
1497
|
+
* infinite-scroll templates, its `ref` — so two renderers cannot drift apart
|
|
1498
|
+
* on what a setting is called or what it means.
|
|
1499
|
+
*/
|
|
1500
|
+
interface GridOptions<Row> {
|
|
1501
|
+
dataSource?: readonly Row[] | undefined;
|
|
1502
|
+
/**
|
|
1503
|
+
* A row's stable identity, for state keyed by it. Defaults to the row's
|
|
1504
|
+
* position, which is enough for a static grid but ties that state to where a
|
|
1505
|
+
* row sits rather than to the row — so anything sorting, filtering or paging
|
|
1506
|
+
* its data should give one.
|
|
1507
|
+
*
|
|
1508
|
+
* Called for every row on every change to `dataSource`, so it should be
|
|
1509
|
+
* cheap and stable; an inline arrow is fine, one that re-reads the data is
|
|
1510
|
+
* not.
|
|
1511
|
+
*/
|
|
1512
|
+
getRowId?: ((row: Row, index: number) => string) | undefined;
|
|
1513
|
+
/**
|
|
1514
|
+
* A class and `data-*` attributes for each data row, worked out from the
|
|
1515
|
+
* row — an `is-overdue` class, a `data-status` to style or find it by.
|
|
1516
|
+
* Group headers and summary rows are not passed to it.
|
|
1517
|
+
*
|
|
1518
|
+
* Called for each data row as it renders, so it should be cheap. A row
|
|
1519
|
+
* whose result reads the same as last time is not redrawn for it, so an
|
|
1520
|
+
* inline arrow returning a fresh object each time is fine.
|
|
1521
|
+
*/
|
|
1522
|
+
getRowProps?: ((row: ResolvedRow<Row>) => RowProps) | undefined;
|
|
1523
|
+
/**
|
|
1524
|
+
* Called when a data row is clicked, after the click has changed the
|
|
1525
|
+
* selection — so a handler reading the selection sees the new one. Not
|
|
1526
|
+
* called for a group header, whose click expands or collapses it.
|
|
1527
|
+
*/
|
|
1528
|
+
onRowClick?: ((event: RowPointerEvent<Row>) => void) | undefined;
|
|
1529
|
+
/**
|
|
1530
|
+
* Called once when a data row is double-clicked — the usual "open this
|
|
1531
|
+
* record" gesture. The two clicks before it still report through
|
|
1532
|
+
* `onRowClick` and select as clicks do.
|
|
1533
|
+
*/
|
|
1534
|
+
onRowDoubleClick?: ((event: RowPointerEvent<Row>) => void) | undefined;
|
|
1535
|
+
borders?: Borders | undefined;
|
|
1536
|
+
hoverable?: HoverableConfig | undefined;
|
|
1537
|
+
/**
|
|
1538
|
+
* Which parts of the grid the user may select, and how many of each —
|
|
1539
|
+
* `{ rows: "multiple", cells: "single" }`. A cell addresses one value, so it
|
|
1540
|
+
* has no `"multiple"`.
|
|
1541
|
+
*
|
|
1542
|
+
* Off by default, unlike `hoverable`: selection claims the click, which a
|
|
1543
|
+
* grid that only displays data should not do. Give `getRowId` alongside it
|
|
1544
|
+
* for data that sorts, filters or pages, or a selection follows the position
|
|
1545
|
+
* rather than the row.
|
|
1546
|
+
*/
|
|
1547
|
+
selectable?: SelectableConfig | undefined;
|
|
1548
|
+
/** Row ids selected to start with, keyed as `getRowId` resolves them. Uncontrolled. */
|
|
1549
|
+
defaultRowSelection?: SelectionState | undefined;
|
|
1550
|
+
/**
|
|
1551
|
+
* The selected row ids, controlled — applied as given, changed only through
|
|
1552
|
+
* the row selection callbacks (`onRowSelectionChange` carries the whole
|
|
1553
|
+
* next state). Leave it `undefined` for the grid to keep it itself,
|
|
1554
|
+
* starting from `defaultRowSelection`.
|
|
1555
|
+
*/
|
|
1556
|
+
rowSelection?: SelectionState | undefined;
|
|
1557
|
+
/** Column ids selected to start with. Uncontrolled. */
|
|
1558
|
+
defaultColumnSelection?: SelectionState | undefined;
|
|
1559
|
+
/**
|
|
1560
|
+
* The selected column ids, controlled — changed only through the column
|
|
1561
|
+
* selection callbacks. Leave it `undefined` for the grid to keep it.
|
|
1562
|
+
*/
|
|
1563
|
+
columnSelection?: SelectionState | undefined;
|
|
1564
|
+
/** The cell selected to start with. Uncontrolled. */
|
|
1565
|
+
defaultCellSelection?: CellSelectionState | undefined;
|
|
1566
|
+
/**
|
|
1567
|
+
* The selected cell, controlled — `null` for none, changed only through
|
|
1568
|
+
* the cell selection callbacks. Leave it `undefined` for the grid to keep
|
|
1569
|
+
* it.
|
|
1570
|
+
*/
|
|
1571
|
+
cellSelection?: CellSelectionState | undefined;
|
|
1572
|
+
/** Whether columns can be dragged wider, unless a column says otherwise. */
|
|
1573
|
+
resizableColumns?: boolean | undefined;
|
|
1574
|
+
/**
|
|
1575
|
+
* Whether columns can be dragged into a new position, unless a column says
|
|
1576
|
+
* otherwise. Turning it off leaves an order the user already made in place.
|
|
1577
|
+
*/
|
|
1578
|
+
reorderableColumns?: boolean | undefined;
|
|
1579
|
+
/**
|
|
1580
|
+
* Whether columns fill the grid's width or sit at their own. Defaults to
|
|
1581
|
+
* `"fit"`, under which columns the user has sized keep their width and the
|
|
1582
|
+
* rest share what is left.
|
|
1583
|
+
*/
|
|
1584
|
+
resizeMode?: ResizeMode | undefined;
|
|
1585
|
+
/** Column widths to start from, keyed by column id. Uncontrolled. */
|
|
1586
|
+
defaultColumnSizing?: ColumnSizingState | undefined;
|
|
1587
|
+
/**
|
|
1588
|
+
* Column widths, controlled — applied as given, changed only through
|
|
1589
|
+
* `onColumnResize`, whose `sizing` is the next state. Leave it
|
|
1590
|
+
* `undefined` for the grid to keep the widths itself, starting from
|
|
1591
|
+
* `defaultColumnSizing`.
|
|
1592
|
+
*/
|
|
1593
|
+
columnSizing?: ColumnSizingState | undefined;
|
|
1594
|
+
/**
|
|
1595
|
+
* Column ids in the order to start in. Uncontrolled, and partial: ids it
|
|
1596
|
+
* omits keep their position among `columns` and follow those it lists.
|
|
1597
|
+
*/
|
|
1598
|
+
defaultColumnOrder?: ColumnOrderState | undefined;
|
|
1599
|
+
/**
|
|
1600
|
+
* The column order, controlled — applied as given, changed only through
|
|
1601
|
+
* `onColumnOrderChange`. Leave it `undefined` for the grid to keep the
|
|
1602
|
+
* order itself, starting from `defaultColumnOrder`.
|
|
1603
|
+
*/
|
|
1604
|
+
columnOrder?: ColumnOrderState | undefined;
|
|
1605
|
+
/**
|
|
1606
|
+
* Columns shown (`true`) or hidden (`false`) to start with, keyed by
|
|
1607
|
+
* column id, over each definition's own `hidden`. Uncontrolled.
|
|
1608
|
+
*/
|
|
1609
|
+
defaultColumnVisibility?: ColumnVisibilityState | undefined;
|
|
1610
|
+
/**
|
|
1611
|
+
* Which columns are shown, controlled — applied as given, changed only
|
|
1612
|
+
* through `onColumnVisibilityChange`. Leave it `undefined` for the grid to
|
|
1613
|
+
* keep it itself, starting from `defaultColumnVisibility`.
|
|
1614
|
+
*/
|
|
1615
|
+
columnVisibility?: ColumnVisibilityState | undefined;
|
|
1616
|
+
/**
|
|
1617
|
+
* Called once when columns are shown or hidden, with every column that one
|
|
1618
|
+
* change touched. A call that changes nothing does not call it.
|
|
1619
|
+
*/
|
|
1620
|
+
onColumnVisibilityChange?: ((event: ColumnVisibilityEvent) => void) | undefined;
|
|
1621
|
+
/**
|
|
1622
|
+
* Sizes applied to columns that do not set their own — the width they start
|
|
1623
|
+
* at and the bounds they may be resized between. Distinct from
|
|
1624
|
+
* `defaultColumnSizing`, which sets specific columns' starting widths.
|
|
1625
|
+
*/
|
|
1626
|
+
columnSizeDefaults?: Partial<ColumnSizeDefaults> | undefined;
|
|
1627
|
+
/**
|
|
1628
|
+
* Called as the user resizes a column. Fires continuously with
|
|
1629
|
+
* `phase: "move"` and once on release with `phase: "end"` — the latter being
|
|
1630
|
+
* the one to persist. Auto-fitting a column calls it once, with "end".
|
|
1631
|
+
*/
|
|
1632
|
+
onColumnResize?: ((event: ColumnResizeEvent) => void) | undefined;
|
|
1633
|
+
/**
|
|
1634
|
+
* Called once when the user drops a column somewhere new. A drop that leaves
|
|
1635
|
+
* the order as it was does not call it.
|
|
1636
|
+
*/
|
|
1637
|
+
onColumnOrderChange?: ((event: ColumnOrderEvent) => void) | undefined;
|
|
1638
|
+
/**
|
|
1639
|
+
* Whether columns can be sorted by clicking their header toggle, unless a
|
|
1640
|
+
* column says otherwise. Shift-click stacks a column into the sort instead
|
|
1641
|
+
* of replacing it.
|
|
1642
|
+
*/
|
|
1643
|
+
sortableColumns?: boolean | undefined;
|
|
1644
|
+
/** The sort to start with, in priority order. Uncontrolled. */
|
|
1645
|
+
defaultColumnSort?: ColumnSortState | undefined;
|
|
1646
|
+
/**
|
|
1647
|
+
* The sort, controlled: the grid shows exactly this, and a header click
|
|
1648
|
+
* only asks for a change through `onColumnSortChange`, which takes effect
|
|
1649
|
+
* once this prop follows it. Leave it `undefined` for the grid to keep the
|
|
1650
|
+
* sort itself, starting from `defaultColumnSort`.
|
|
1651
|
+
*/
|
|
1652
|
+
columnSort?: ColumnSortState | undefined;
|
|
1653
|
+
/**
|
|
1654
|
+
* Called once when the user changes the sort — a toggle, a stack, or a
|
|
1655
|
+
* clear back to "none".
|
|
1656
|
+
*/
|
|
1657
|
+
onColumnSortChange?: ((event: ColumnSortEvent) => void) | undefined;
|
|
1658
|
+
/**
|
|
1659
|
+
* Whether columns can be grouped by — a header's click/`Alt+ArrowDown`
|
|
1660
|
+
* toggle — unless a column says otherwise. The grouping itself still
|
|
1661
|
+
* applies when this is off, via `defaultGroupBy` or the imperative API;
|
|
1662
|
+
* this only gates that one interaction, the same way `sortableColumns`
|
|
1663
|
+
* gates the sort toggle without disabling `defaultColumnSort`. Independent
|
|
1664
|
+
* of `groupByBarVisibility` and `groupByDraggableColumns`, which gate the
|
|
1665
|
+
* bar and the drag-in gesture respectively.
|
|
1666
|
+
*/
|
|
1667
|
+
groupableColumns?: boolean | undefined;
|
|
1668
|
+
/**
|
|
1669
|
+
* Whether a groupable header shows its group-toggle icon, unless a column
|
|
1670
|
+
* says otherwise. Purely a rendering choice: `Alt+ArrowDown` keeps working
|
|
1671
|
+
* on a groupable header with the icon hidden.
|
|
1672
|
+
*/
|
|
1673
|
+
groupToggleIconColumns?: boolean | undefined;
|
|
1674
|
+
/**
|
|
1675
|
+
* Whether a column's header may be dragged into the group-by bar to add
|
|
1676
|
+
* it to the grouping, unless a column says otherwise. Independent of
|
|
1677
|
+
* `groupableColumns`: a column can be groupable via its header's
|
|
1678
|
+
* click/keyboard toggle, via this drag, both, or neither.
|
|
1679
|
+
*/
|
|
1680
|
+
groupByDraggableColumns?: boolean | undefined;
|
|
1681
|
+
/** How the group-by bar's visibility follows the active grouping. */
|
|
1682
|
+
groupByBarVisibility?: GroupByBarVisibility | undefined;
|
|
1683
|
+
/** The group-by stack to start with, outer to inner. Uncontrolled. */
|
|
1684
|
+
defaultGroupBy?: GroupByState | undefined;
|
|
1685
|
+
/**
|
|
1686
|
+
* The group-by stack, controlled — applied as given, changed only through
|
|
1687
|
+
* `onGroupByChange`. Leave it `undefined` for the grid to keep it itself,
|
|
1688
|
+
* starting from `defaultGroupBy`.
|
|
1689
|
+
*/
|
|
1690
|
+
groupBy?: GroupByState | undefined;
|
|
1691
|
+
/**
|
|
1692
|
+
* Called once when the user changes the group-by stack — adding, removing,
|
|
1693
|
+
* or reordering a level.
|
|
1694
|
+
*/
|
|
1695
|
+
onGroupByChange?: ((event: GroupByEvent) => void) | undefined;
|
|
1696
|
+
/** Group keys collapsed to start with — every other group starts expanded. Uncontrolled. */
|
|
1697
|
+
defaultGroupExpansion?: GroupExpansionState | undefined;
|
|
1698
|
+
/**
|
|
1699
|
+
* The collapsed groups, controlled — applied as given, changed only
|
|
1700
|
+
* through `onGroupExpansionChange`. Leave it `undefined` for the grid to
|
|
1701
|
+
* keep it itself, starting from `defaultGroupExpansion`.
|
|
1702
|
+
*/
|
|
1703
|
+
groupExpansion?: GroupExpansionState | undefined;
|
|
1704
|
+
/** Called once when the user expands or collapses a group, or every group at once. */
|
|
1705
|
+
onGroupExpansionChange?: ((event: GroupExpansionEvent) => void) | undefined;
|
|
1706
|
+
/** The filter to start with — every applied entry, ANDed together. Uncontrolled. */
|
|
1707
|
+
defaultFilter?: FilterState<Row> | undefined;
|
|
1708
|
+
/**
|
|
1709
|
+
* The filter, controlled — applied as given, changed only through
|
|
1710
|
+
* `onFilterChange`. Leave it `undefined` for the grid to keep it itself,
|
|
1711
|
+
* starting from `defaultFilter`.
|
|
1712
|
+
*/
|
|
1713
|
+
filter?: FilterState<Row> | undefined;
|
|
1714
|
+
/**
|
|
1715
|
+
* Called once when the filter changes — from the toolbar's search box, the
|
|
1716
|
+
* `filter.clearAll` command, `setFilter` or a restored state.
|
|
1717
|
+
*/
|
|
1718
|
+
onFilterChange?: ((event: FilterChangeEvent<Row>) => void) | undefined;
|
|
1719
|
+
/**
|
|
1720
|
+
* Whether columns get a filter menu, opened from their header, unless a
|
|
1721
|
+
* column says otherwise. Off by default, like `sortableColumns`; the
|
|
1722
|
+
* filter itself applies either way, from `defaultFilter`, `setFilter` or a
|
|
1723
|
+
* search box. A renderer draws the menu from what
|
|
1724
|
+
* `resolveColumnFilterMenu` settles.
|
|
1725
|
+
*/
|
|
1726
|
+
filterableColumns?: boolean | undefined;
|
|
1727
|
+
/**
|
|
1728
|
+
* How the filter menus look: which editor they open — `"simple"`
|
|
1729
|
+
* conditions or an `"excel"` checklist — and the checklist's counts and
|
|
1730
|
+
* value limit. A column's own `filterMenu` wins over it. Switching `ui`
|
|
1731
|
+
* keeps every filter, since both editors edit the one `filter`.
|
|
1732
|
+
*/
|
|
1733
|
+
filterMenu?: GridFilterMenuOptions | undefined;
|
|
1734
|
+
/**
|
|
1735
|
+
* Whether the grid's rows are split into pages. A page's unit is a
|
|
1736
|
+
* top-level group or a bare data row, never a leaf row — a group is never
|
|
1737
|
+
* split across a page boundary. Off by default, matching `sortableColumns`.
|
|
1738
|
+
*/
|
|
1739
|
+
paginated?: boolean | undefined;
|
|
1740
|
+
/**
|
|
1741
|
+
* The page and page size to start on. Uncontrolled. Defaults to
|
|
1742
|
+
* `{ pageIndex: 0, pageSize: 25 }` when `paginated` is on and this is
|
|
1743
|
+
* omitted.
|
|
1744
|
+
*/
|
|
1745
|
+
defaultPagination?: PaginationState | undefined;
|
|
1746
|
+
/**
|
|
1747
|
+
* The page and page size, controlled — applied as given, changed only
|
|
1748
|
+
* through `onPaginationChange`. Leave it `undefined` for the grid to keep
|
|
1749
|
+
* them itself, starting from `defaultPagination`.
|
|
1750
|
+
*
|
|
1751
|
+
* The grid sends an uncontrolled pagination back to the first page when
|
|
1752
|
+
* the filter, sort or grouping changes; a controlled one is the parent's
|
|
1753
|
+
* to reset alongside that change. Until it does, the grid shows the last
|
|
1754
|
+
* page that exists rather than an empty one.
|
|
1755
|
+
*/
|
|
1756
|
+
pagination?: PaginationState | undefined;
|
|
1757
|
+
/** Called once when the user changes the page or the page size. */
|
|
1758
|
+
onPaginationChange?: ((event: PaginationChangeEvent) => void) | undefined;
|
|
1759
|
+
/**
|
|
1760
|
+
* Aggregates to compute — a subtotal per group (rendered in that group's
|
|
1761
|
+
* header) plus a grand total over the whole filtered/grouped dataset
|
|
1762
|
+
* (rendered in a footer). Always computed over every row, never scoped to
|
|
1763
|
+
* the current page. A plain controlled prop, unlike `sort`/`filter`/
|
|
1764
|
+
* `groupBy`/`pagination`: there is no built-in UI for a user to add or
|
|
1765
|
+
* remove an aggregate interactively, so there is no `defaultAggregates`/
|
|
1766
|
+
* `onAggregatesChange` pair to go with it.
|
|
1767
|
+
*/
|
|
1768
|
+
aggregates?: AggregateState<Row> | undefined;
|
|
1769
|
+
/**
|
|
1770
|
+
* Where a group's own aggregate results render. `"inline"` (the default)
|
|
1771
|
+
* keeps them as text in the group header, next to its leaf-row count.
|
|
1772
|
+
* `"row"` instead renders a dedicated row after that group's last visible
|
|
1773
|
+
* entry, with each aggregate's value in the `<td>` for its own column —
|
|
1774
|
+
* the same alignment the grand-total footer's own cells have. Has no
|
|
1775
|
+
* effect when `aggregates` is empty or omitted.
|
|
1776
|
+
*/
|
|
1777
|
+
groupAggregateDisplay?: GroupAggregateDisplay | undefined;
|
|
1778
|
+
/**
|
|
1779
|
+
* Bounds the row area's height, independently scrollable — the grid's own
|
|
1780
|
+
* chrome (group-by bar, header, footer, pager) stays outside it and
|
|
1781
|
+
* always visible. A number is pixels; a string is passed through as a CSS
|
|
1782
|
+
* length (e.g. "60vh"). Omitted, the body's height stays content-driven,
|
|
1783
|
+
* same as today.
|
|
1784
|
+
*/
|
|
1785
|
+
height?: number | string | undefined;
|
|
1786
|
+
/**
|
|
1787
|
+
* Renders only the rows near the current scroll position rather than every
|
|
1788
|
+
* row at once — for a dataset too large to mount in full. Requires
|
|
1789
|
+
* `height` to be set; a grid without a bounded body has no viewport to
|
|
1790
|
+
* window rows against (a dev-time console warning fires when it's
|
|
1791
|
+
* missing). Off by default, matching every other opt-in behavior here.
|
|
1792
|
+
*/
|
|
1793
|
+
virtualized?: boolean | undefined;
|
|
1794
|
+
/**
|
|
1795
|
+
* Rows rendered outside the visible range on each side, to reduce
|
|
1796
|
+
* blank-frame flashes on fast scrolling. Only meaningful with `virtualized`
|
|
1797
|
+
* on.
|
|
1798
|
+
*/
|
|
1799
|
+
overscan?: number | undefined;
|
|
1800
|
+
/**
|
|
1801
|
+
* Assumed height for a row never yet measured — only matters for the very
|
|
1802
|
+
* first paint and for `scrollToRow`'s initial jump before it corrects
|
|
1803
|
+
* itself against that row's real, measured height. Only meaningful with
|
|
1804
|
+
* `virtualized` on.
|
|
1805
|
+
*/
|
|
1806
|
+
estimatedRowHeight?: number | undefined;
|
|
1807
|
+
/**
|
|
1808
|
+
* The grid's accessible name, announced when it takes focus. A grid without
|
|
1809
|
+
* one is read only as "grid", which says nothing about which grid.
|
|
1810
|
+
*/
|
|
1811
|
+
label?: string | undefined;
|
|
1812
|
+
/**
|
|
1813
|
+
* The id of an element naming the grid, for a heading already on the page.
|
|
1814
|
+
* Takes precedence over `label`, as `aria-labelledby` does.
|
|
1815
|
+
*/
|
|
1816
|
+
labelledBy?: string | undefined;
|
|
1817
|
+
/**
|
|
1818
|
+
* The locale values are formatted for — a BCP 47 tag such as `"de-DE"`, or
|
|
1819
|
+
* a list to fall back through. Setting it turns on `Intl` formatting of
|
|
1820
|
+
* dates and numbers in every cell and aggregate shown without a template;
|
|
1821
|
+
* without it, only a column with its own `format` is formatted, in the
|
|
1822
|
+
* runtime's locale, and the rest print as they always have.
|
|
1823
|
+
*/
|
|
1824
|
+
locale?: FormatLocale;
|
|
1825
|
+
/**
|
|
1826
|
+
* The grid's own strings, replacing its English key by key — the pager's
|
|
1827
|
+
* buttons, the group-by bar, the loading row, boolean and blank values,
|
|
1828
|
+
* the built-in commands' labels, the menus' names, and every live-region
|
|
1829
|
+
* announcement. Keys
|
|
1830
|
+
* left out keep their default.
|
|
1831
|
+
* Formatting is `locale`'s, not this.
|
|
1832
|
+
*/
|
|
1833
|
+
messages?: Partial<GridMessages> | undefined;
|
|
1834
|
+
/**
|
|
1835
|
+
* The grid's own context menu, opened on a column header, a data cell, a
|
|
1836
|
+
* group row or the body's empty space by a right-click, Shift+F10 or the
|
|
1837
|
+
* ContextMenu key. Off by default, like every other feature, leaving the
|
|
1838
|
+
* browser's menu. `true` shows each area's defaults — see
|
|
1839
|
+
* `defaultContextMenu`; an object lists an area's entries, an area left
|
|
1840
|
+
* out keeping its defaults and one given `[]` showing the browser's menu
|
|
1841
|
+
* there.
|
|
1842
|
+
*/
|
|
1843
|
+
contextMenu?: boolean | GridContextMenuOptions<Row> | undefined;
|
|
1844
|
+
/**
|
|
1845
|
+
* Called when the grid's context menu opens or closes, with where. A menu
|
|
1846
|
+
* opened in place of another reports that one closing first. The open
|
|
1847
|
+
* state is the renderer's to keep, so no option holds it.
|
|
1848
|
+
*/
|
|
1849
|
+
onContextMenuOpenChange?: ((event: ContextMenuOpenChangeEvent) => void) | undefined;
|
|
1850
|
+
/**
|
|
1851
|
+
* The app's own commands, for its menus to list by id. One with a
|
|
1852
|
+
* built-in's id replaces it wherever that id is listed — a translated,
|
|
1853
|
+
* privilege-gated or differently behaving "Hide column" — see
|
|
1854
|
+
* `resolveCommands`.
|
|
1855
|
+
*/
|
|
1856
|
+
commands?: readonly GridCommand<Row>[] | undefined;
|
|
1857
|
+
/**
|
|
1858
|
+
* Called after a command or an inline menu item runs — chosen from a menu,
|
|
1859
|
+
* or run through a renderer's API — saying which, where it was asked for
|
|
1860
|
+
* and from where. One that did not run, being hidden or disabled, is not
|
|
1861
|
+
* reported.
|
|
1862
|
+
*/
|
|
1863
|
+
onCommand?: ((event: GridCommandEvent) => void) | undefined;
|
|
1864
|
+
/**
|
|
1865
|
+
* A toolbar above the grid: its own commands, a search box over the
|
|
1866
|
+
* filter's global text entry, dropdowns and the app's own content, in the
|
|
1867
|
+
* menu vocabulary. Off by default. `true` lists `defaultToolbar`; an object
|
|
1868
|
+
* lists its `items` and may name it with `label` — see `ToolbarEntry`.
|
|
1869
|
+
*/
|
|
1870
|
+
toolbar?: boolean | GridToolbarOptions<Row> | undefined;
|
|
1871
|
+
/**
|
|
1872
|
+
* How the grid exports unless a call says otherwise: which rows and
|
|
1873
|
+
* columns, the file's name, and the CSV and JSON settings. Left out, an
|
|
1874
|
+
* export holds what the user sees, across every page, in a file named
|
|
1875
|
+
* `export` with the format's extension.
|
|
1876
|
+
*/
|
|
1877
|
+
export?: GridExportOptions | undefined;
|
|
1878
|
+
/**
|
|
1879
|
+
* Export formats beyond CSV and JSON — an xlsx writer, or one of the
|
|
1880
|
+
* app's own — each registered by its `format`, replacing a built-in
|
|
1881
|
+
* writer of the same format. `export.xlsx` and `export.pdf` show only
|
|
1882
|
+
* once a writer for their format is here — see `resolveExportWriters`.
|
|
1883
|
+
*/
|
|
1884
|
+
exportWriters?: readonly ExportWriter[] | undefined;
|
|
1885
|
+
/**
|
|
1886
|
+
* How the grid prints unless a call says otherwise: the rows and columns,
|
|
1887
|
+
* the title and text around the table, and the page. Left out, a print
|
|
1888
|
+
* holds what an export does, titled with `label`, on an A4 page.
|
|
1889
|
+
*/
|
|
1890
|
+
print?: PrintOptions | undefined;
|
|
1891
|
+
}
|
|
1892
|
+
/**
|
|
1893
|
+
* Reported as the user selects. Every one of these is fanned out from a single
|
|
1894
|
+
* diff of the transition it describes, so no two can disagree about what one
|
|
1895
|
+
* interaction did.
|
|
1896
|
+
*
|
|
1897
|
+
* Kept apart from `GridOptions` because the column payloads carry resolved
|
|
1898
|
+
* columns, whose labels are whatever a renderer's `headerTemplate` returns —
|
|
1899
|
+
* `Node` is that renderer's node type.
|
|
1900
|
+
*/
|
|
1901
|
+
interface SelectionCallbacks<Row, Node = string> {
|
|
1902
|
+
/** Called once per row newly selected. The last call names the last row. */
|
|
1903
|
+
onRowSelect?: ((event: RowSelectEvent<Row>) => void) | undefined;
|
|
1904
|
+
/** Called once with every row one interaction selected. */
|
|
1905
|
+
onRowsSelect?: ((event: RowsSelectEvent<Row>) => void) | undefined;
|
|
1906
|
+
onRowDeselect?: ((event: RowSelectEvent<Row>) => void) | undefined;
|
|
1907
|
+
onRowsDeselect?: ((event: RowsSelectEvent<Row>) => void) | undefined;
|
|
1908
|
+
/**
|
|
1909
|
+
* Called once per change with what it added, what it removed and everything
|
|
1910
|
+
* selected after it — the one to persist from.
|
|
1911
|
+
*/
|
|
1912
|
+
onRowSelectionChange?: ((event: RowSelectionChangeEvent<Row>) => void) | undefined;
|
|
1913
|
+
onColumnSelect?: ((event: ColumnSelectEvent<Row, Node>) => void) | undefined;
|
|
1914
|
+
onColumnsSelect?: ((event: ColumnsSelectEvent<Row, Node>) => void) | undefined;
|
|
1915
|
+
onColumnDeselect?: ((event: ColumnSelectEvent<Row, Node>) => void) | undefined;
|
|
1916
|
+
onColumnsDeselect?: ((event: ColumnsSelectEvent<Row, Node>) => void) | undefined;
|
|
1917
|
+
onColumnSelectionChange?: ((event: ColumnSelectionChangeEvent<Row, Node>) => void) | undefined;
|
|
1918
|
+
onCellSelect?: ((event: CellSelectEvent<Row, Node>) => void) | undefined;
|
|
1919
|
+
onCellDeselect?: ((event: CellSelectEvent<Row, Node>) => void) | undefined;
|
|
1920
|
+
onCellSelectionChange?: ((event: CellSelectionChangeEvent<Row, Node>) => void) | undefined;
|
|
1921
|
+
}
|
|
1922
|
+
|
|
1923
|
+
/**
|
|
1924
|
+
* Which editor a filter menu opens. Both edit the same `FilterState`, so
|
|
1925
|
+
* switching between them keeps every filter applied.
|
|
1926
|
+
*
|
|
1927
|
+
* - `"simple"`: one or two conditions — an operator and a value each —
|
|
1928
|
+
* joined by and/or.
|
|
1929
|
+
* - `"excel"`: a search box over a checklist of the column's values, with
|
|
1930
|
+
* the conditions a submenu away.
|
|
1931
|
+
*/
|
|
1932
|
+
type FilterMenuUi = "simple" | "excel";
|
|
1933
|
+
/** How a grid's filter menus look, unless a column says otherwise. */
|
|
1934
|
+
interface GridFilterMenuOptions {
|
|
1935
|
+
/** Which editor a filter menu opens. Defaults to `"simple"`. */
|
|
1936
|
+
readonly ui?: FilterMenuUi | undefined;
|
|
1937
|
+
/** Whether the excel editor's checklist shows how many rows hold each value. Off by default. */
|
|
1938
|
+
readonly showCounts?: boolean | undefined;
|
|
1939
|
+
/**
|
|
1940
|
+
* How many distinct values the excel editor's checklist lists before it
|
|
1941
|
+
* asks for a search first. Defaults to `DEFAULT_FILTER_VALUE_LIMIT`.
|
|
1942
|
+
*/
|
|
1943
|
+
readonly valueLimit?: number | undefined;
|
|
1944
|
+
}
|
|
1945
|
+
/** A column's own filter menu settings, over the grid's `filterMenu`. */
|
|
1946
|
+
interface ColumnFilterMenuOptions {
|
|
1947
|
+
/** Which editor this column's filter menu opens, over the grid's `filterMenu.ui`. */
|
|
1948
|
+
readonly ui?: FilterMenuUi | undefined;
|
|
1949
|
+
/**
|
|
1950
|
+
* The operators this column's conditions offer, in order, in place of its
|
|
1951
|
+
* type's `defaultFilterOperators`. `in` is dropped — the checklist is its
|
|
1952
|
+
* editor — and `[]` offers no condition, leaving the excel editor its
|
|
1953
|
+
* checklist alone.
|
|
1954
|
+
*/
|
|
1955
|
+
readonly operators?: readonly FilterOperator[] | undefined;
|
|
1956
|
+
}
|
|
1957
|
+
/** One column's filter menu with every setting settled — what a renderer draws. */
|
|
1958
|
+
interface ResolvedColumnFilterMenu {
|
|
1959
|
+
readonly ui: FilterMenuUi;
|
|
1960
|
+
/** The operators its conditions offer, in order. Never `in`. */
|
|
1961
|
+
readonly operators: readonly FilterOperator[];
|
|
1962
|
+
/** The family the column's `type` falls in, which its operators are labelled by. */
|
|
1963
|
+
readonly family: FilterOperatorFamily;
|
|
1964
|
+
readonly showCounts: boolean;
|
|
1965
|
+
readonly valueLimit: number;
|
|
1966
|
+
}
|
|
1967
|
+
/**
|
|
1968
|
+
* How many distinct values a checklist lists before asking for a search —
|
|
1969
|
+
* Excel's own cap. The list is virtualized, so what this bounds is counting
|
|
1970
|
+
* the values, not drawing them.
|
|
1971
|
+
*/
|
|
1972
|
+
declare const DEFAULT_FILTER_VALUE_LIMIT = 10000;
|
|
1973
|
+
/**
|
|
1974
|
+
* The filter menu `column` opens, or `null` when it has none: a column is
|
|
1975
|
+
* filterable when its own `filterable` says so, else when the grid's
|
|
1976
|
+
* `filterableColumns` does — off unless one of them turns it on, as
|
|
1977
|
+
* `sortable` is. The column's `filterMenu` settings win over the grid's
|
|
1978
|
+
* one by one; what neither sets takes its default.
|
|
1979
|
+
*/
|
|
1980
|
+
declare function resolveColumnFilterMenu(options: Pick<GridOptions<unknown>, "filterableColumns" | "filterMenu">, column: Pick<ColumnDefinition<unknown, unknown>, "type" | "filterable" | "filterMenu">): ResolvedColumnFilterMenu | null;
|
|
1981
|
+
|
|
1982
|
+
/**
|
|
1983
|
+
* Values a cell shows as-is instead of being drilled into. Arrays and `Date`s
|
|
1984
|
+
* are cell values rather than groups of columns, and `null` cannot be
|
|
1985
|
+
* introspected, so all three end a path.
|
|
1986
|
+
*/
|
|
1987
|
+
type LeafValue = bigint | boolean | number | string | symbol | null | undefined | Date | readonly unknown[] | ((...args: never[]) => unknown);
|
|
1988
|
+
/** Keys of `T` holding a leaf value — the only ones a path may end on. */
|
|
1989
|
+
type LeafKey<T> = {
|
|
1990
|
+
[K in keyof T & string]: NonNullable<T[K]> extends LeafValue ? K : never;
|
|
1991
|
+
}[keyof T & string];
|
|
1992
|
+
/**
|
|
1993
|
+
* Every addressable field of `Row`, one level deep: `"Id"` for a flat field,
|
|
1994
|
+
* `"Application.Id"` for a leaf inside a nested object. A nested object
|
|
1995
|
+
* contributes only its leaf children, never itself and never anything deeper.
|
|
1996
|
+
*/
|
|
1997
|
+
type FieldPath<Row> = {
|
|
1998
|
+
[K in keyof Row & string]: NonNullable<Row[K]> extends LeafValue ? K : `${K}.${LeafKey<NonNullable<Row[K]>>}`;
|
|
1999
|
+
}[keyof Row & string];
|
|
2000
|
+
/**
|
|
2001
|
+
* The value type of a column's cells. This package is framework-agnostic so it
|
|
2002
|
+
* defaults to `string`;
|
|
2003
|
+
*/
|
|
2004
|
+
type ColumnType = "dateTime" | "date" | "time" | "number" | "string" | "boolean" | "decimal" | "currency" | "percent";
|
|
2005
|
+
type ColumnAlignment = "left" | "center" | "right";
|
|
2006
|
+
/**
|
|
2007
|
+
* What `cellTemplate` receives. An object rather than positional arguments so
|
|
2008
|
+
* that a later addition — a sort state, whether the row is selected — is not a
|
|
2009
|
+
* breaking change to every template already written.
|
|
2010
|
+
*/
|
|
2011
|
+
interface CellTemplateContext<Row> {
|
|
2012
|
+
/**
|
|
2013
|
+
* This cell's value, read off the column's field path. `unknown` because a
|
|
2014
|
+
* dotted path's type cannot be recovered here; a template narrows it.
|
|
2015
|
+
*/
|
|
2016
|
+
value: unknown;
|
|
2017
|
+
/** The whole row, for a template that needs a sibling field. */
|
|
2018
|
+
row: Row;
|
|
2019
|
+
/** Position among the rows as rendered — the index within the current page once paging is on. */
|
|
2020
|
+
rowIndex: number;
|
|
2021
|
+
/** This row's absolute position in the whole filtered/sorted/grouped dataset, unaffected by which page is showing. */
|
|
2022
|
+
datasetIndex: number;
|
|
2023
|
+
/** This row's id, as `resolveRowId` settled it. */
|
|
2024
|
+
rowId: string;
|
|
2025
|
+
/** Whether this row is selected, so a template can style itself to match. */
|
|
2026
|
+
selected: boolean;
|
|
2027
|
+
}
|
|
2028
|
+
/**
|
|
2029
|
+
* What a column's `footerTemplate` receives. Mirrors `CellTemplateContext`'s
|
|
2030
|
+
* shape where it applies — `value`, `rows` — minus everything scoped to one
|
|
2031
|
+
* rendered row (`rowIndex`, `rowId`, `selected`), since a footer addresses
|
|
2032
|
+
* every row an aggregate was computed over at once, not a single one.
|
|
2033
|
+
*/
|
|
2034
|
+
interface FooterTemplateContext<Row> {
|
|
2035
|
+
/** This column's aggregate result, as `computeAggregates` produced it. */
|
|
2036
|
+
value: unknown;
|
|
2037
|
+
/** Every row the aggregate was computed over — the grand total's full dataset, or one group's full leaf descendants. */
|
|
2038
|
+
rows: readonly Row[];
|
|
2039
|
+
}
|
|
2040
|
+
/**
|
|
2041
|
+
* @typeParam Node - What a header or cell renders to. This package is
|
|
2042
|
+
* framework-agnostic so it defaults to `string`; `@gridkitjs/react` binds it to
|
|
2043
|
+
* `ReactNode` so a template can return JSX.
|
|
2044
|
+
*/
|
|
2045
|
+
interface ColumnDefinition<Row, Node = string> {
|
|
2046
|
+
/**
|
|
2047
|
+
* Path to this cell's value: a key of `Row`, or `"Parent.Child"` for a leaf
|
|
2048
|
+
* one level inside a nested object. Any string still compiles — the union
|
|
2049
|
+
* exists to drive autocomplete, not to lock the grid down.
|
|
2050
|
+
*/
|
|
2051
|
+
field: FieldPath<Row> | (string & {});
|
|
2052
|
+
/**
|
|
2053
|
+
* Stable identity for state keyed by this column. Defaults to `field`, which
|
|
2054
|
+
* is unique in the common case but need not be — two columns may render the
|
|
2055
|
+
* same field differently.
|
|
2056
|
+
*/
|
|
2057
|
+
id?: string;
|
|
2058
|
+
/**
|
|
2059
|
+
* The column's name as plain text. The header shows it when there is no
|
|
2060
|
+
* `headerTemplate`, and anything that needs the name as text rather than
|
|
2061
|
+
* markup — a screen-reader announcement, an export — reads it even when
|
|
2062
|
+
* there is one, since a template's output need not be text at all.
|
|
2063
|
+
*/
|
|
2064
|
+
header?: string | undefined;
|
|
2065
|
+
/** Header content, or a function returning it at render time. */
|
|
2066
|
+
headerTemplate?: Node | (() => Node) | undefined;
|
|
2067
|
+
/**
|
|
2068
|
+
* Renders this column's cells in place of the text `formatCellValue` makes
|
|
2069
|
+
* of the value at `field`. The raw value is still resolved and handed over,
|
|
2070
|
+
* so a template never repeats the field path.
|
|
2071
|
+
*/
|
|
2072
|
+
cellTemplate?: ((context: CellTemplateContext<Row>) => Node) | undefined;
|
|
2073
|
+
/**
|
|
2074
|
+
* Renders this column's own aggregate result in a group footer or the
|
|
2075
|
+
* grand-total footer, in place of the raw computed value. Absent for a
|
|
2076
|
+
* column with no aggregate: nothing is shown, the same way a column
|
|
2077
|
+
* missing from `AggregateState` contributes no cell to either footer.
|
|
2078
|
+
*/
|
|
2079
|
+
footerTemplate?: ((context: FooterTemplateContext<Row>) => Node) | undefined;
|
|
2080
|
+
/**
|
|
2081
|
+
* The value type of this column's cells. This package is framework-agnostic so it
|
|
2082
|
+
* defaults to `string`;
|
|
2083
|
+
*/
|
|
2084
|
+
type?: ColumnType;
|
|
2085
|
+
/**
|
|
2086
|
+
* `Intl` options for how this column's values read as text: number options
|
|
2087
|
+
* for a numeric `type`, date options for a date or time one. Passed to
|
|
2088
|
+
* `Intl.NumberFormat`/`Intl.DateTimeFormat` with the grid's `locale` — see
|
|
2089
|
+
* `formatCellValue` for the defaults each `type` starts from. Setting it,
|
|
2090
|
+
* or the grid's `locale`, is what turns that formatting on: without either,
|
|
2091
|
+
* numbers print as-is and dates through `toLocaleString()`.
|
|
2092
|
+
*/
|
|
2093
|
+
format?: Intl.NumberFormatOptions | Intl.DateTimeFormatOptions | undefined;
|
|
2094
|
+
/**
|
|
2095
|
+
* Turns a value into the text shown for it, in place of `format` and
|
|
2096
|
+
* `type`. Applies wherever this column's values are shown as text — its
|
|
2097
|
+
* cells and its aggregates. `row` is the cell's row, and `undefined` for a
|
|
2098
|
+
* value no single row owns: an aggregate result, or a group header's value.
|
|
2099
|
+
*/
|
|
2100
|
+
valueFormatter?: ((value: unknown, row: Row | undefined) => string) | undefined;
|
|
2101
|
+
/**
|
|
2102
|
+
* Alignment of this column's cells. This package is framework-agnostic so it
|
|
2103
|
+
* defaults to `left` (`right` for numbers);
|
|
2104
|
+
*/
|
|
2105
|
+
alignment?: ColumnAlignment;
|
|
2106
|
+
/**
|
|
2107
|
+
* Width in px this column starts at. A user resize overrides it for as long
|
|
2108
|
+
* as that resize lives in the sizing state.
|
|
2109
|
+
*/
|
|
2110
|
+
width?: number;
|
|
2111
|
+
/** Lower bound a resize may not drag below. */
|
|
2112
|
+
minWidth?: number;
|
|
2113
|
+
/** Upper bound a resize may not drag above. */
|
|
2114
|
+
maxWidth?: number;
|
|
2115
|
+
/** Whether this column can be resized, overriding the grid-level default. */
|
|
2116
|
+
resizable?: boolean;
|
|
2117
|
+
/**
|
|
2118
|
+
* Whether this column can be dragged to a new position, overriding the
|
|
2119
|
+
* grid-level default. A column that cannot move can still be moved past.
|
|
2120
|
+
*/
|
|
2121
|
+
reorderable?: boolean;
|
|
2122
|
+
/** Whether this column can be sorted, overriding the grid-level default. */
|
|
2123
|
+
sortable?: boolean;
|
|
2124
|
+
/**
|
|
2125
|
+
* Whether this column has a filter menu, overriding the grid-level
|
|
2126
|
+
* `filterableColumns`. Like `sortable`, it gates the user's way in and
|
|
2127
|
+
* nothing else: a filter on the column set in code still applies.
|
|
2128
|
+
*/
|
|
2129
|
+
filterable?: boolean | undefined;
|
|
2130
|
+
/**
|
|
2131
|
+
* This column's own filter menu settings — its editor and the operators
|
|
2132
|
+
* its conditions offer — over the grid's `filterMenu`.
|
|
2133
|
+
*/
|
|
2134
|
+
filterMenu?: ColumnFilterMenuOptions | undefined;
|
|
2135
|
+
/** Whether this column can be grouped by, overriding the grid-level default. */
|
|
2136
|
+
groupable?: boolean;
|
|
2137
|
+
/**
|
|
2138
|
+
* Whether this column's header shows its group-toggle icon, overriding
|
|
2139
|
+
* the grid-level default. Purely a rendering choice — it does not affect
|
|
2140
|
+
* whether the column can be grouped by (`groupable`) or the
|
|
2141
|
+
* `Alt+ArrowDown` shortcut, which keeps working with the icon hidden, the
|
|
2142
|
+
* same way the resize handle stays `aria-hidden` while `Alt+ArrowLeft`/
|
|
2143
|
+
* `ArrowRight` still resize.
|
|
2144
|
+
*/
|
|
2145
|
+
groupToggleIcon?: boolean;
|
|
2146
|
+
/**
|
|
2147
|
+
* Whether this column's header may be dragged into the group-by bar to
|
|
2148
|
+
* add it to the active grouping, overriding the grid-level default.
|
|
2149
|
+
* Distinct from `groupable`: a column can be groupable via its header's
|
|
2150
|
+
* click/`Alt+ArrowDown` toggle, via this drag, both, or neither.
|
|
2151
|
+
*/
|
|
2152
|
+
groupByDraggable?: boolean;
|
|
2153
|
+
/**
|
|
2154
|
+
* Lets this column's header and/or cell text wrap onto multiple lines
|
|
2155
|
+
* instead of the grid's default single line with an ellipsis. Off by
|
|
2156
|
+
* default: wrapping changes row height, so it stays a column's own choice
|
|
2157
|
+
* rather than something a minor release could turn on under an existing
|
|
2158
|
+
* grid.
|
|
2159
|
+
*/
|
|
2160
|
+
wrap?: ColumnWrapConfig;
|
|
2161
|
+
/**
|
|
2162
|
+
* Extra class names appended to this column's `th`. An escape hatch for a
|
|
2163
|
+
* consumer's own CSS — nothing in this package reads them — for anything
|
|
2164
|
+
* `wrap` and the rest of this type don't cover.
|
|
2165
|
+
*/
|
|
2166
|
+
headerClassName?: string;
|
|
2167
|
+
/**
|
|
2168
|
+
* Extra class names appended to this column's `td`, on every row. Static
|
|
2169
|
+
* per column: a per-row condition is already `cellTemplate`'s job (a
|
|
2170
|
+
* template returning its own markup with a conditional class), so this
|
|
2171
|
+
* stays a plain string rather than taking the row.
|
|
2172
|
+
*/
|
|
2173
|
+
cellClassName?: string;
|
|
2174
|
+
/**
|
|
2175
|
+
* Whether this column starts out hidden. A hidden column is not rendered
|
|
2176
|
+
* but is still a column of the grid: a sort, filter or grouping on it
|
|
2177
|
+
* still applies, and it keeps its place in the column order. The user
|
|
2178
|
+
* showing or hiding it lives in `ColumnVisibilityState`, which wins over
|
|
2179
|
+
* this for as long as it holds an entry for the column.
|
|
2180
|
+
*/
|
|
2181
|
+
hidden?: boolean | undefined;
|
|
2182
|
+
/**
|
|
2183
|
+
* Whether the user may hide this column — from its header's menu, or the
|
|
2184
|
+
* column chooser. Defaults to `true`. Like `sortable`, it gates the user's
|
|
2185
|
+
* ways to do it and nothing else: `hideColumns` still hides the column.
|
|
2186
|
+
*/
|
|
2187
|
+
hideable?: boolean | undefined;
|
|
2188
|
+
/**
|
|
2189
|
+
* Whether this column is written to an export, a clipboard copy or a
|
|
2190
|
+
* print. Defaults to `true`. `false` keeps it out of every one of them —
|
|
2191
|
+
* even when an export names it by id — for a column whose cells mean
|
|
2192
|
+
* nothing off screen, such as one of action buttons.
|
|
2193
|
+
*/
|
|
2194
|
+
exportable?: boolean | undefined;
|
|
2195
|
+
/**
|
|
2196
|
+
* The typed value an export stores for this column's cells, where the raw
|
|
2197
|
+
* value at `field` is not the one to keep — an id to resolve into a name,
|
|
2198
|
+
* a string date to turn into a `Date`. Only a format that keeps typed
|
|
2199
|
+
* values (a spreadsheet, JSON) reads it; the text every format writes
|
|
2200
|
+
* still comes from `formatCellValue`, so what is exported reads as what
|
|
2201
|
+
* is shown.
|
|
2202
|
+
*/
|
|
2203
|
+
exportValue?: ((value: unknown, row: Row) => ExportScalar) | undefined;
|
|
2204
|
+
}
|
|
2205
|
+
/** Which parts of a column opt out of the grid's default single-line text. */
|
|
2206
|
+
interface ColumnWrapConfig {
|
|
2207
|
+
header?: boolean;
|
|
2208
|
+
cells?: boolean;
|
|
2209
|
+
}
|
|
2210
|
+
/**
|
|
2211
|
+
* Widths the user has changed, keyed by column id. Holding only what changed —
|
|
2212
|
+
* rather than every width — means a `width` edited in the column definition
|
|
2213
|
+
* still takes effect, and resetting is discarding the state.
|
|
2214
|
+
*/
|
|
2215
|
+
type ColumnSizingState = Readonly<Record<string, number>>;
|
|
2216
|
+
/** The active page, and how many rows/units make one up. */
|
|
2217
|
+
interface PaginationState {
|
|
2218
|
+
readonly pageIndex: number;
|
|
2219
|
+
readonly pageSize: number;
|
|
2220
|
+
}
|
|
2221
|
+
/** Reports a user page/page-size change whole — the one to persist from, mirroring ColumnSortEvent. */
|
|
2222
|
+
interface PaginationChangeEvent {
|
|
2223
|
+
readonly pagination: PaginationState;
|
|
2224
|
+
readonly pageCount: number;
|
|
2225
|
+
}
|
|
2226
|
+
/** Sizes used for a column that does not specify its own. */
|
|
2227
|
+
interface ColumnSizeDefaults {
|
|
2228
|
+
width: number;
|
|
2229
|
+
minWidth: number;
|
|
2230
|
+
maxWidth: number;
|
|
2231
|
+
}
|
|
2232
|
+
/** The bounds a column's width is held between, resolved once from both. */
|
|
2233
|
+
interface ColumnConstraints {
|
|
2234
|
+
minWidth: number;
|
|
2235
|
+
maxWidth: number;
|
|
2236
|
+
}
|
|
2237
|
+
/**
|
|
2238
|
+
* Grid-level defaults a column falls back to when it does not set its own.
|
|
2239
|
+
* Sizes are grouped so the rest of the grid's defaults have somewhere to go.
|
|
2240
|
+
*/
|
|
2241
|
+
interface ColumnResolveOptions {
|
|
2242
|
+
sizes?: Partial<ColumnSizeDefaults> | undefined;
|
|
2243
|
+
/** Whether columns are resizable, unless a column says otherwise. */
|
|
2244
|
+
resizable?: boolean | undefined;
|
|
2245
|
+
/** Whether columns are reorderable, unless a column says otherwise. */
|
|
2246
|
+
reorderable?: boolean | undefined;
|
|
2247
|
+
/** Whether columns may be dragged into the group-by bar, unless a column says otherwise. */
|
|
2248
|
+
groupByDraggable?: boolean | undefined;
|
|
2249
|
+
}
|
|
2250
|
+
/**
|
|
2251
|
+
* How a column's width relates to the grid's.
|
|
2252
|
+
*
|
|
2253
|
+
* `"fit"` keeps the columns filling the grid: the space a column gives up is
|
|
2254
|
+
* handed to the others, and the space it takes comes out of them. `"fixed"`
|
|
2255
|
+
* lets every column keep its own width, so a resize moves one column and
|
|
2256
|
+
* nothing else, and the grid scrolls or leaves a gap accordingly.
|
|
2257
|
+
*/
|
|
2258
|
+
type ResizeMode = "fit" | "fixed";
|
|
2259
|
+
/**
|
|
2260
|
+
* A column as the data stages read it — filtering, sorting, grouping and
|
|
2261
|
+
* aggregating need its id and its definition's `field` and `type`, never its
|
|
2262
|
+
* width. Kept apart from `ResolvedColumn` so that a resize or a viewport
|
|
2263
|
+
* change, which re-resolves every width, leaves these stages' input — and so
|
|
2264
|
+
* their output — untouched. `ResolvedColumn` satisfies it structurally.
|
|
2265
|
+
*/
|
|
2266
|
+
interface DataColumn<Row, Node = string> {
|
|
2267
|
+
readonly id: string;
|
|
2268
|
+
readonly column: ColumnDefinition<Row, Node>;
|
|
2269
|
+
}
|
|
2270
|
+
/**
|
|
2271
|
+
* A column paired with everything it takes to render it. Each field is a
|
|
2272
|
+
* decision made once here rather than in each adapter, so a second framework
|
|
2273
|
+
* binding renders identically without repeating the logic.
|
|
2274
|
+
*/
|
|
2275
|
+
interface ResolvedColumn<Row, Node = string> {
|
|
2276
|
+
column: ColumnDefinition<Row, Node>;
|
|
2277
|
+
id: string;
|
|
2278
|
+
width: number;
|
|
2279
|
+
/**
|
|
2280
|
+
* Whether `width` came from the sizing state rather than the column
|
|
2281
|
+
* definition — that is, whether the user set it. Auto-fit leaves these
|
|
2282
|
+
* columns alone so that resizing one does not undo itself.
|
|
2283
|
+
*/
|
|
2284
|
+
sized: boolean;
|
|
2285
|
+
/**
|
|
2286
|
+
* What the header shows: the column's own `headerTemplate`, else its
|
|
2287
|
+
* `header`, else a label read off the field path. `string` is in the
|
|
2288
|
+
* union because both fallbacks are text whatever `Node` is bound to.
|
|
2289
|
+
*/
|
|
2290
|
+
label: Node | string;
|
|
2291
|
+
/** Whether this column can be resized, after the grid-level default. */
|
|
2292
|
+
resizable: boolean;
|
|
2293
|
+
/** Whether this column can be dragged, after the grid-level default. */
|
|
2294
|
+
reorderable: boolean;
|
|
2295
|
+
/** Whether this column's header may be dragged into the group-by bar, after the grid-level default. */
|
|
2296
|
+
groupByDraggable: boolean;
|
|
2297
|
+
/** How this column's cells align, after falling back to its type. */
|
|
2298
|
+
alignment: ColumnAlignment;
|
|
2299
|
+
}
|
|
2300
|
+
/**
|
|
2301
|
+
* A resize in progress. It captures its constraints up front so that applying
|
|
2302
|
+
* a pointer position is arithmetic on numbers alone — no column, no DOM.
|
|
2303
|
+
*/
|
|
2304
|
+
interface ColumnResizeSession {
|
|
2305
|
+
readonly columnId: string;
|
|
2306
|
+
readonly startWidth: number;
|
|
2307
|
+
readonly startPosition: number;
|
|
2308
|
+
readonly constraints: ColumnConstraints;
|
|
2309
|
+
}
|
|
2310
|
+
/**
|
|
2311
|
+
* Reports a user resize. `phase` separates the two audiences: `"move"` fires
|
|
2312
|
+
* continuously for live feedback, `"end"` once on release — the one to persist.
|
|
2313
|
+
*/
|
|
2314
|
+
interface ColumnResizeEvent {
|
|
2315
|
+
readonly columnId: string;
|
|
2316
|
+
readonly width: number;
|
|
2317
|
+
readonly sizing: ColumnSizingState;
|
|
2318
|
+
readonly phase: "move" | "end";
|
|
2319
|
+
}
|
|
2320
|
+
/**
|
|
2321
|
+
* Columns shown (`true`) or hidden (`false`) since the grid started, keyed by
|
|
2322
|
+
* column id. Holding only what changed, the way `ColumnSizingState` does: a
|
|
2323
|
+
* column absent from it follows its definition's `hidden`, so a definition
|
|
2324
|
+
* edited later still takes effect for every column the user never touched.
|
|
2325
|
+
*/
|
|
2326
|
+
type ColumnVisibilityState = Readonly<Record<string, boolean>>;
|
|
2327
|
+
/**
|
|
2328
|
+
* Reports columns shown or hidden. `columnIds` lists every column the one
|
|
2329
|
+
* change touched — showing three columns at once is one event, not three —
|
|
2330
|
+
* and `visibility` is the whole state to persist from.
|
|
2331
|
+
*/
|
|
2332
|
+
interface ColumnVisibilityEvent {
|
|
2333
|
+
readonly columnIds: readonly string[];
|
|
2334
|
+
readonly visibility: ColumnVisibilityState;
|
|
2335
|
+
}
|
|
2336
|
+
/**
|
|
2337
|
+
* Column ids in the order they render. It need not list every column: one
|
|
2338
|
+
* absent from it keeps its position among the definitions and follows those
|
|
2339
|
+
* that are listed.
|
|
2340
|
+
*/
|
|
2341
|
+
type ColumnOrderState = readonly string[];
|
|
2342
|
+
/**
|
|
2343
|
+
* Which side of a column a drop lands on, normalised away by
|
|
2344
|
+
* `resolveDropBefore` so it reaches no state.
|
|
2345
|
+
*/
|
|
2346
|
+
type DropSide = "before" | "after";
|
|
2347
|
+
/**
|
|
2348
|
+
* Reports a user reorder. Unlike a resize there is no `"move"` phase — the
|
|
2349
|
+
* order does not change until the drop.
|
|
2350
|
+
*/
|
|
2351
|
+
interface ColumnOrderEvent {
|
|
2352
|
+
readonly columnId: string;
|
|
2353
|
+
readonly order: ColumnOrderState;
|
|
2354
|
+
}
|
|
2355
|
+
/** Which way a column sorts. */
|
|
2356
|
+
type SortDirection = "asc" | "desc";
|
|
2357
|
+
/** One column's place in a stacked sort, and which way it sorts. */
|
|
2358
|
+
interface ColumnSortEntry {
|
|
2359
|
+
readonly columnId: string;
|
|
2360
|
+
readonly direction: SortDirection;
|
|
2361
|
+
}
|
|
2362
|
+
/**
|
|
2363
|
+
* The active sort, in priority order: index 0 sorts first, ties broken by
|
|
2364
|
+
* index 1, and so on down the stack. Empty for an unsorted grid, mirroring
|
|
2365
|
+
* `SelectionState`'s empty array for "nothing selected".
|
|
2366
|
+
*/
|
|
2367
|
+
type ColumnSortState = readonly ColumnSortEntry[];
|
|
2368
|
+
/**
|
|
2369
|
+
* Reports a user sort change whole — the stack to persist from. No `phase`:
|
|
2370
|
+
* unlike a resize, a sort has no in-progress state, only before and after.
|
|
2371
|
+
*/
|
|
2372
|
+
interface ColumnSortEvent {
|
|
2373
|
+
readonly columnId: string;
|
|
2374
|
+
readonly sort: ColumnSortState;
|
|
2375
|
+
}
|
|
2376
|
+
/** One level of a stacked group-by, outer to inner. Mirrors ColumnSortEntry. */
|
|
2377
|
+
interface GroupByEntry {
|
|
2378
|
+
readonly columnId: string;
|
|
2379
|
+
/** Order of this level's own group values (not row order within a group). Defaults to "asc". */
|
|
2380
|
+
readonly direction?: SortDirection;
|
|
2381
|
+
}
|
|
2382
|
+
/**
|
|
2383
|
+
* The active grouping, outer to inner: index 0 groups first, each
|
|
2384
|
+
* subsequent index nests inside it. Empty for an ungrouped grid, mirroring
|
|
2385
|
+
* ColumnSortState's empty array for "no sort".
|
|
2386
|
+
*/
|
|
2387
|
+
type GroupByState = readonly GroupByEntry[];
|
|
2388
|
+
/**
|
|
2389
|
+
* Reports a user group-by change whole — the stack to persist from. Mirrors
|
|
2390
|
+
* ColumnSortEvent's `{columnId, sort}` shape.
|
|
2391
|
+
*/
|
|
2392
|
+
interface GroupByEvent {
|
|
2393
|
+
readonly columnId: string;
|
|
2394
|
+
readonly groupBy: GroupByState;
|
|
2395
|
+
}
|
|
2396
|
+
/**
|
|
2397
|
+
* Group keys collapsed by the user — holding only the exceptions, the same
|
|
2398
|
+
* way ColumnSizingState holds only resized widths. A key absent from this
|
|
2399
|
+
* set is expanded; there is no separate "collapsed by default" concept.
|
|
2400
|
+
*/
|
|
2401
|
+
type GroupExpansionState = readonly string[];
|
|
2402
|
+
/**
|
|
2403
|
+
* Reports a user expansion change. `groupId` is the group toggled, or `null`
|
|
2404
|
+
* for expandAllGroups/collapseAllGroups, which touch every group in one call
|
|
2405
|
+
* rather than one at a time.
|
|
2406
|
+
*/
|
|
2407
|
+
interface GroupExpansionEvent {
|
|
2408
|
+
readonly groupId: string | null;
|
|
2409
|
+
readonly expansion: GroupExpansionState;
|
|
2410
|
+
}
|
|
2411
|
+
/**
|
|
2412
|
+
* One group header in a grouped result. `path` is every ancestor value
|
|
2413
|
+
* down to and including this group's own, outermost first — what a header
|
|
2414
|
+
* template needs to render "West / Enterprise", not just "Enterprise".
|
|
2415
|
+
*
|
|
2416
|
+
* Not parameterized by `Row`: nothing here holds a `Row`-typed value today —
|
|
2417
|
+
* `aggregates` holds computed `unknown` results, not rows themselves.
|
|
2418
|
+
*/
|
|
2419
|
+
interface ResolvedGroupRow {
|
|
2420
|
+
readonly kind: "group";
|
|
2421
|
+
/** Stable id for this node: this plan's join of `path`, used as the React key and the GroupExpansionState entry. Opaque — build it with `groupRowId`, never construct one by hand. */
|
|
2422
|
+
readonly groupId: string;
|
|
2423
|
+
/** Nesting depth, 0 for a top-level group. */
|
|
2424
|
+
readonly level: number;
|
|
2425
|
+
readonly columnId: string;
|
|
2426
|
+
/** This level's own value — the last entry of `path`. */
|
|
2427
|
+
readonly value: unknown;
|
|
2428
|
+
readonly path: readonly unknown[];
|
|
2429
|
+
readonly expanded: boolean;
|
|
2430
|
+
/** Leaf row count under this group, regardless of collapse state. */
|
|
2431
|
+
readonly count: number;
|
|
2432
|
+
/** Position among the display rows as rendered — same invariant ResolvedRow.rowIndex keeps. */
|
|
2433
|
+
readonly rowIndex: number;
|
|
2434
|
+
/** This header's absolute position in the whole filtered/sorted/grouped dataset, matching ResolvedRow.datasetIndex. */
|
|
2435
|
+
readonly datasetIndex: number;
|
|
2436
|
+
/**
|
|
2437
|
+
* This group's own aggregate results, computed over its full leaf-row
|
|
2438
|
+
* descendants regardless of collapse state — see `withGroupAggregates`.
|
|
2439
|
+
* Empty when no `AggregateState` is active.
|
|
2440
|
+
*/
|
|
2441
|
+
readonly aggregates: AggregateResults;
|
|
2442
|
+
}
|
|
2443
|
+
/**
|
|
2444
|
+
* A group's own aggregate results, rendered as a row of its own rather than
|
|
2445
|
+
* inline in its header — see `groupAggregateDisplay: "row"`. Emitted by
|
|
2446
|
+
* `withGroupAggregates` immediately after a group's last visible
|
|
2447
|
+
* descendant (its last nested group or data row, or immediately after its
|
|
2448
|
+
* own header when collapsed), at that same group's `level`, one per group
|
|
2449
|
+
* with `AggregateState` active — mirroring `ResolvedGroupRow` closely
|
|
2450
|
+
* enough that the two are meant to be read side by side.
|
|
2451
|
+
*/
|
|
2452
|
+
interface ResolvedGroupSummaryRow {
|
|
2453
|
+
readonly kind: "group-summary";
|
|
2454
|
+
/** The group this summary belongs to — shared with that group's own `ResolvedGroupRow.groupId`, not a new id of its own. */
|
|
2455
|
+
readonly groupId: string;
|
|
2456
|
+
/** Nesting depth, matching the group's own `level`. */
|
|
2457
|
+
readonly level: number;
|
|
2458
|
+
/** Position among the display rows as rendered — same invariant every other DisplayRow's `rowIndex` keeps. */
|
|
2459
|
+
readonly rowIndex: number;
|
|
2460
|
+
/** This row's absolute position in the whole filtered/sorted/grouped dataset, matching ResolvedRow.datasetIndex. */
|
|
2461
|
+
readonly datasetIndex: number;
|
|
2462
|
+
/** This group's own aggregate results — identical to its `ResolvedGroupRow.aggregates`, computed once and shared rather than recomputed. */
|
|
2463
|
+
readonly aggregates: AggregateResults;
|
|
2464
|
+
}
|
|
2465
|
+
/**
|
|
2466
|
+
* One entry of a grouped result: an ordinary data row (no `kind` field at
|
|
2467
|
+
* all — ResolvedRow is unchanged, so every existing consumer of plain
|
|
2468
|
+
* ResolvedRow[] keeps compiling), a group header, or — only when
|
|
2469
|
+
* `groupAggregateDisplay: "row"` is active — that group's own summary row.
|
|
2470
|
+
* Discriminate with `"kind" in entry`, then `entry.kind`.
|
|
2471
|
+
*/
|
|
2472
|
+
type DisplayRow<Row> = ResolvedRow<Row> | ResolvedGroupRow | ResolvedGroupSummaryRow;
|
|
2473
|
+
/** A reducer this package computes without a custom `AggregateFn`. */
|
|
2474
|
+
type BuiltInAggregate = "sum" | "avg" | "min" | "max" | "count" | "countDistinct";
|
|
2475
|
+
/**
|
|
2476
|
+
* Called with every raw row in scope — always the full leaf set, never a
|
|
2477
|
+
* partial reduction combined from child groups, so a non-associative
|
|
2478
|
+
* aggregate (median, distinct count) is never computed from
|
|
2479
|
+
* already-aggregated values. Mirrors `FilterPredicate`'s shape, minus the
|
|
2480
|
+
* per-row `value` since an aggregate reduces across rows rather than
|
|
2481
|
+
* testing one.
|
|
2482
|
+
*/
|
|
2483
|
+
type AggregateFn<Row> = (rows: readonly Row[]) => unknown;
|
|
2484
|
+
/** One aggregate to compute against a column — a built-in reducer, or custom logic via `fn`. */
|
|
2485
|
+
interface AggregateSpec<Row> {
|
|
2486
|
+
readonly columnId: string;
|
|
2487
|
+
readonly fn: BuiltInAggregate | AggregateFn<Row>;
|
|
2488
|
+
/** Distinguishes two aggregates on the same column (e.g. both sum and avg of Amount). Defaults to columnId, mirroring ColumnDefinition.id defaulting to field. */
|
|
2489
|
+
readonly id?: string;
|
|
2490
|
+
/**
|
|
2491
|
+
* Overrides this aggregate's own cell alignment, in the grand-total
|
|
2492
|
+
* footer and a group's own summary row (`groupAggregateDisplay: "row"`)
|
|
2493
|
+
* — inline rendering (`"inline"`) is text, not a cell, so this has no
|
|
2494
|
+
* effect there. Falls back to the column's own `alignment` when omitted.
|
|
2495
|
+
* When two specs share a column and disagree, the first one in
|
|
2496
|
+
* `AggregateState` wins for that shared cell, since one `<td>` can only
|
|
2497
|
+
* take one `text-align`.
|
|
2498
|
+
*/
|
|
2499
|
+
readonly alignment?: ColumnAlignment;
|
|
2500
|
+
}
|
|
2501
|
+
/**
|
|
2502
|
+
* The active aggregates to compute. Empty for a grid with none, mirroring
|
|
2503
|
+
* `FilterState`'s empty array for "no filter". A fully controlled prop —
|
|
2504
|
+
* unlike `sort`/`filter`/`groupBy`/`pagination`, there is no built-in UI
|
|
2505
|
+
* affordance for a user to add or remove an aggregate interactively.
|
|
2506
|
+
*/
|
|
2507
|
+
type AggregateState<Row> = readonly AggregateSpec<Row>[];
|
|
2508
|
+
/** One computed aggregate result, keyed by `spec.id ?? spec.columnId`. */
|
|
2509
|
+
type AggregateResults = ReadonlyMap<string, unknown>;
|
|
2510
|
+
/**
|
|
2511
|
+
* Where a group's own aggregate results render. `"inline"` (the default)
|
|
2512
|
+
* keeps them as text in the group header itself, next to its leaf-row
|
|
2513
|
+
* count. `"row"` instead emits a `ResolvedGroupSummaryRow` immediately
|
|
2514
|
+
* after that group's last visible descendant, with each aggregate's value
|
|
2515
|
+
* in the `<td>` for its own column — the same alignment a grand-total
|
|
2516
|
+
* footer cell has to its column, just scoped to one group instead of the
|
|
2517
|
+
* whole dataset.
|
|
2518
|
+
*/
|
|
2519
|
+
type GroupAggregateDisplay = "inline" | "row";
|
|
2520
|
+
interface FilterEntryBase<Row> {
|
|
2521
|
+
readonly columnId?: FieldPath<Row> | (string & {});
|
|
2522
|
+
}
|
|
2523
|
+
/** Matches a column's stringified value against an SQL LIKE-style query. */
|
|
2524
|
+
interface TextFilterEntry<Row> extends FilterEntryBase<Row> {
|
|
2525
|
+
/**
|
|
2526
|
+
* A bare query is an exact match; `%text%` is contains; `text%` is
|
|
2527
|
+
* starts-with; `%text` is ends-with. Always case-insensitive. Only the
|
|
2528
|
+
* first and last characters are read as anchors — a `%` anywhere else is
|
|
2529
|
+
* a literal character, not a wildcard.
|
|
2530
|
+
*/
|
|
2531
|
+
readonly query: string;
|
|
2532
|
+
}
|
|
2533
|
+
/**
|
|
2534
|
+
* Matches a column's actual (non-stringified) value by strict equality —
|
|
2535
|
+
* only when the column's resolved `type` agrees: `number`/`decimal`/
|
|
2536
|
+
* `currency`/`percent` for a `number` value, `boolean` for a `boolean`
|
|
2537
|
+
* value, `date`/`dateTime`/`time` for a `Date` value (compared via
|
|
2538
|
+
* `getTime()`). A `value` against a column of the wrong type never matches,
|
|
2539
|
+
* rather than silently stringifying and falling through to a text
|
|
2540
|
+
* comparison — the whole point of this variant existing separately from
|
|
2541
|
+
* `TextFilterEntry` is that it doesn't do that.
|
|
2542
|
+
*/
|
|
2543
|
+
interface ValueFilterEntry<Row> extends FilterEntryBase<Row> {
|
|
2544
|
+
readonly value: number | boolean | Date;
|
|
2545
|
+
}
|
|
2546
|
+
type FilterPredicate<Row> = (value: unknown, row: Row) => boolean;
|
|
2547
|
+
/**
|
|
2548
|
+
* Matches via caller-supplied logic — a numeric range, a cross-field
|
|
2549
|
+
* combination, anything `query`/`value` can't express. Called once per row,
|
|
2550
|
+
* not per column: when `columnId` is given, `value` is that column's value,
|
|
2551
|
+
* resolved for convenience; when it's omitted, `value` is `undefined` and
|
|
2552
|
+
* the predicate is expected to read whatever it needs off `row` itself.
|
|
2553
|
+
*/
|
|
2554
|
+
interface PredicateFilterEntry<Row> extends FilterEntryBase<Row> {
|
|
2555
|
+
readonly predicate: FilterPredicate<Row>;
|
|
2556
|
+
}
|
|
2557
|
+
/**
|
|
2558
|
+
* A nested group of entries, combined with `combinator` instead of the
|
|
2559
|
+
* implicit AND every top-level `FilterState` uses. `entries` is itself a
|
|
2560
|
+
* `FilterState<Row>`, so groups nest to any depth — the only entry variant
|
|
2561
|
+
* with no `columnId` of its own, since it isn't scoped to one column, only
|
|
2562
|
+
* to the entries it composes.
|
|
2563
|
+
*/
|
|
2564
|
+
interface GroupFilterEntry<Row> {
|
|
2565
|
+
readonly combinator: "and" | "or";
|
|
2566
|
+
readonly entries: FilterState<Row>;
|
|
2567
|
+
}
|
|
2568
|
+
/**
|
|
2569
|
+
* What an `OperatorFilterEntry` asks of a cell. `contains`, `notContains`,
|
|
2570
|
+
* `startsWith` and `endsWith` read the value as text; the rest compare it as
|
|
2571
|
+
* the column's `type` says.
|
|
2572
|
+
*/
|
|
2573
|
+
type FilterOperator = "eq" | "ne" | "contains" | "notContains" | "startsWith" | "endsWith" | "gt" | "gte" | "lt" | "lte" | "between" | "in" | "isEmpty" | "isNotEmpty";
|
|
2574
|
+
/** A value an `OperatorFilterEntry` compares a cell against. */
|
|
2575
|
+
type FilterScalar = string | number | boolean | Date | null;
|
|
2576
|
+
/**
|
|
2577
|
+
* Matches one column's value by a named operator — plain data, unlike a
|
|
2578
|
+
* predicate, so a filter built from these can be saved and restored.
|
|
2579
|
+
*
|
|
2580
|
+
* `value` is one `FilterScalar` for most operators, a list of them for
|
|
2581
|
+
* `in`, a `[low, high]` pair for `between` (both ends inclusive), and
|
|
2582
|
+
* absent for `isEmpty`/`isNotEmpty`.
|
|
2583
|
+
*
|
|
2584
|
+
* - An empty cell is `null`, `undefined` or `""`. `isEmpty` matches it,
|
|
2585
|
+
* `isNotEmpty` does not, and so does no other operator — except `ne` and
|
|
2586
|
+
* `notContains`, which match it: a "not" filter must not quietly drop the
|
|
2587
|
+
* blanks. Each of those two is the exact opposite of `eq`/`contains`.
|
|
2588
|
+
* - The text operators compare the stringified value, case-insensitively.
|
|
2589
|
+
* - `eq`, `ne`, `gt`, `gte`, `lt`, `lte` and `between` compare as
|
|
2590
|
+
* `compareValues` does under the column's `type`: numerically,
|
|
2591
|
+
* chronologically, or as text (case-insensitively, like a query). A cell
|
|
2592
|
+
* of another kind — a string in a number column — is never equal, greater
|
|
2593
|
+
* or less.
|
|
2594
|
+
* - `in` matches the values grouping would put in the same group.
|
|
2595
|
+
* - A date column reads a string `value` as `new Date(value)`.
|
|
2596
|
+
* - A `value` of the wrong kind for the column — a string against a number
|
|
2597
|
+
* column, a missing pair for `between` — matches no row at all, as a
|
|
2598
|
+
* `ValueFilterEntry` of the wrong type doesn't.
|
|
2599
|
+
*/
|
|
2600
|
+
interface OperatorFilterEntry<Row> {
|
|
2601
|
+
readonly columnId: FieldPath<Row> | (string & {});
|
|
2602
|
+
readonly operator: FilterOperator;
|
|
2603
|
+
readonly value?: FilterScalar | readonly FilterScalar[];
|
|
2604
|
+
}
|
|
2605
|
+
type FilterEntry<Row> = TextFilterEntry<Row> | ValueFilterEntry<Row> | PredicateFilterEntry<Row> | OperatorFilterEntry<Row> | GroupFilterEntry<Row>;
|
|
2606
|
+
/**
|
|
2607
|
+
* The active filter, every entry ANDed together at the top level — nest a
|
|
2608
|
+
* `GroupFilterEntry` for anything that needs OR. Empty for an unfiltered
|
|
2609
|
+
* grid, mirroring `ColumnSortState`'s empty array for "no sort".
|
|
2610
|
+
*/
|
|
2611
|
+
type FilterState<Row> = readonly FilterEntry<Row>[];
|
|
2612
|
+
/**
|
|
2613
|
+
* A `ValueFilterEntry` as JSON holds it: a `Date` value becomes its ISO
|
|
2614
|
+
* string, which restoring turns back into a `Date`.
|
|
2615
|
+
*/
|
|
2616
|
+
interface SerializedValueFilterEntry<Row> extends FilterEntryBase<Row> {
|
|
2617
|
+
readonly value: number | boolean | string;
|
|
2618
|
+
}
|
|
2619
|
+
/** A `FilterScalar` as JSON holds it: a `Date` becomes its ISO string. */
|
|
2620
|
+
type SerializedFilterScalar = string | number | boolean | null;
|
|
2621
|
+
/**
|
|
2622
|
+
* An `OperatorFilterEntry` as JSON holds it: each `Date` becomes its ISO
|
|
2623
|
+
* string, which restoring turns back into a `Date` when the column is a
|
|
2624
|
+
* date, date-time or time column.
|
|
2625
|
+
*/
|
|
2626
|
+
interface SerializedOperatorFilterEntry<Row> {
|
|
2627
|
+
readonly columnId: FieldPath<Row> | (string & {});
|
|
2628
|
+
readonly operator: FilterOperator;
|
|
2629
|
+
readonly value?: SerializedFilterScalar | readonly SerializedFilterScalar[];
|
|
2630
|
+
}
|
|
2631
|
+
/** A `GroupFilterEntry` whose entries are serialised too. */
|
|
2632
|
+
interface SerializedGroupFilterEntry<Row> {
|
|
2633
|
+
readonly combinator: "and" | "or";
|
|
2634
|
+
readonly entries: SerializedFilterState<Row>;
|
|
2635
|
+
}
|
|
2636
|
+
/**
|
|
2637
|
+
* A filter entry that survives `JSON.stringify`: every kind but a predicate,
|
|
2638
|
+
* which is a function and cannot be written down.
|
|
2639
|
+
*/
|
|
2640
|
+
type SerializedFilterEntry<Row> = TextFilterEntry<Row> | SerializedValueFilterEntry<Row> | SerializedOperatorFilterEntry<Row> | SerializedGroupFilterEntry<Row>;
|
|
2641
|
+
type SerializedFilterState<Row> = readonly SerializedFilterEntry<Row>[];
|
|
2642
|
+
/** Reports a filter change whole — the filter to persist from. */
|
|
2643
|
+
interface FilterChangeEvent<Row> {
|
|
2644
|
+
readonly filter: FilterState<Row>;
|
|
2645
|
+
}
|
|
2646
|
+
/**
|
|
2647
|
+
* Ids selected, in the order they were selected — so the most recent is last,
|
|
2648
|
+
* and a consumer wanting only that reads `at(-1)` rather than tracking it
|
|
2649
|
+
* alongside.
|
|
2650
|
+
*
|
|
2651
|
+
* Ordered rather than a keyed record for that reason alone; a render layer
|
|
2652
|
+
* that needs lookups builds a `Set` from it. Rows and columns share the type:
|
|
2653
|
+
* they are both a list of ids, and the state they live in already names which.
|
|
2654
|
+
*/
|
|
2655
|
+
type SelectionState = readonly string[];
|
|
2656
|
+
/**
|
|
2657
|
+
* How much of a member may be selected at once. `false` rather than an absent
|
|
2658
|
+
* key so that turning selection off for one member reads the same as never
|
|
2659
|
+
* having enabled it.
|
|
2660
|
+
*/
|
|
2661
|
+
type SelectionMode = false | "single" | "multiple";
|
|
2662
|
+
/**
|
|
2663
|
+
* The modes a cell may take. A cell addresses one value, so it has no
|
|
2664
|
+
* `"multiple"` — a range of cells is a different feature, with a rectangle
|
|
2665
|
+
* rather than a list behind it.
|
|
2666
|
+
*/
|
|
2667
|
+
type CellSelectionMode = false | "single";
|
|
2668
|
+
/**
|
|
2669
|
+
* Which parts of the grid the user may select, and how many of each.
|
|
2670
|
+
*
|
|
2671
|
+
* Off by default, unlike `HoverableConfig`: selection claims the click, which
|
|
2672
|
+
* a grid that only displays data should not do.
|
|
2673
|
+
*/
|
|
2674
|
+
interface SelectableConfig {
|
|
2675
|
+
rows?: SelectionMode | undefined;
|
|
2676
|
+
columns?: SelectionMode | undefined;
|
|
2677
|
+
cells?: CellSelectionMode | undefined;
|
|
2678
|
+
/**
|
|
2679
|
+
* Whether a plain click on a row toggles it rather than selecting it
|
|
2680
|
+
* alone — a checklist, where picking rows one after another should not
|
|
2681
|
+
* need Ctrl held down. Shift still selects a range and Ctrl/Cmd still
|
|
2682
|
+
* toggles. Rows only: a column or cell click is unchanged.
|
|
2683
|
+
*/
|
|
2684
|
+
toggleOnClick?: boolean | undefined;
|
|
2685
|
+
}
|
|
2686
|
+
/**
|
|
2687
|
+
* What an interaction means for the selection, read off its modifiers once at
|
|
2688
|
+
* the boundary so that nothing downstream handles a raw event.
|
|
2689
|
+
*/
|
|
2690
|
+
type SelectIntent = "replace" | "toggle" | "range";
|
|
2691
|
+
/** The address of one cell: which row, and which column within it. */
|
|
2692
|
+
interface SelectedCellRef {
|
|
2693
|
+
readonly rowId: string;
|
|
2694
|
+
readonly columnId: string;
|
|
2695
|
+
}
|
|
2696
|
+
/** The one selected cell, or `null` for none. */
|
|
2697
|
+
type CellSelectionState = SelectedCellRef | null;
|
|
2698
|
+
/**
|
|
2699
|
+
* What changed between two selections. Ids rather than resolved members, so
|
|
2700
|
+
* that the transform producing it stays free of the data it selects from.
|
|
2701
|
+
*/
|
|
2702
|
+
interface SelectionDiff {
|
|
2703
|
+
readonly added: readonly string[];
|
|
2704
|
+
readonly removed: readonly string[];
|
|
2705
|
+
}
|
|
2706
|
+
/**
|
|
2707
|
+
* A row paired with the identity and position it renders under — the row
|
|
2708
|
+
* counterpart to `ResolvedColumn`, and resolved once for the same reason: so
|
|
2709
|
+
* no part of the grid works out a row's id for itself.
|
|
2710
|
+
*
|
|
2711
|
+
* It is also what the selection callbacks report, so a handler reads the row
|
|
2712
|
+
* itself rather than an id it has to look up.
|
|
2713
|
+
*/
|
|
2714
|
+
interface ResolvedRow<Row> {
|
|
2715
|
+
readonly rowId: string;
|
|
2716
|
+
readonly row: Row;
|
|
2717
|
+
/** Position among the rows as rendered, matching `CellTemplateContext`. */
|
|
2718
|
+
readonly rowIndex: number;
|
|
2719
|
+
/** This row's absolute position in the whole filtered/sorted/grouped dataset, matching `CellTemplateContext`. */
|
|
2720
|
+
readonly datasetIndex: number;
|
|
2721
|
+
}
|
|
2722
|
+
/**
|
|
2723
|
+
* A selected column. Carries the resolved column rather than the bare
|
|
2724
|
+
* definition, so a handler reads the width and label the user actually
|
|
2725
|
+
* clicked rather than what the definition asked for.
|
|
2726
|
+
*/
|
|
2727
|
+
interface SelectedColumn<Row, Node = string> {
|
|
2728
|
+
readonly columnId: string;
|
|
2729
|
+
readonly column: ResolvedColumn<Row, Node>;
|
|
2730
|
+
/** Position among the columns as displayed, so after any reorder. */
|
|
2731
|
+
readonly columnIndex: number;
|
|
2732
|
+
}
|
|
2733
|
+
/** A selected cell, resolved down to the value it shows. */
|
|
2734
|
+
interface SelectedCell<Row, Node = string> {
|
|
2735
|
+
readonly rowId: string;
|
|
2736
|
+
readonly columnId: string;
|
|
2737
|
+
readonly row: Row;
|
|
2738
|
+
readonly column: ResolvedColumn<Row, Node>;
|
|
2739
|
+
readonly rowIndex: number;
|
|
2740
|
+
readonly columnIndex: number;
|
|
2741
|
+
/** Read off the column's field path — the value a `cellTemplate` receives. */
|
|
2742
|
+
readonly value: unknown;
|
|
2743
|
+
}
|
|
2744
|
+
/**
|
|
2745
|
+
* Reports a click or double-click on a data row. Carries the modifiers and
|
|
2746
|
+
* button rather than the browser's own event, so a handler reads the same
|
|
2747
|
+
* payload whichever renderer drew the row.
|
|
2748
|
+
*/
|
|
2749
|
+
interface RowPointerEvent<Row> {
|
|
2750
|
+
readonly row: ResolvedRow<Row>;
|
|
2751
|
+
/** The column of the cell the pointer was on, or `null` when it was on no cell. */
|
|
2752
|
+
readonly columnId: string | null;
|
|
2753
|
+
readonly native: {
|
|
2754
|
+
readonly ctrlKey: boolean;
|
|
2755
|
+
readonly metaKey: boolean;
|
|
2756
|
+
readonly shiftKey: boolean;
|
|
2757
|
+
readonly altKey: boolean;
|
|
2758
|
+
/** Which button was pressed, numbered as `MouseEvent.button` numbers them — `0` for the main one. */
|
|
2759
|
+
readonly button: number;
|
|
2760
|
+
};
|
|
2761
|
+
}
|
|
2762
|
+
/** Reports one row selected or deselected. */
|
|
2763
|
+
interface RowSelectEvent<Row> {
|
|
2764
|
+
readonly row: ResolvedRow<Row>;
|
|
2765
|
+
readonly selection: SelectionState;
|
|
2766
|
+
}
|
|
2767
|
+
/**
|
|
2768
|
+
* Reports every row one interaction selected or deselected. Fires once for a
|
|
2769
|
+
* range that `RowSelectEvent` reports one row at a time.
|
|
2770
|
+
*/
|
|
2771
|
+
interface RowsSelectEvent<Row> {
|
|
2772
|
+
readonly rows: readonly ResolvedRow<Row>[];
|
|
2773
|
+
readonly selection: SelectionState;
|
|
2774
|
+
}
|
|
2775
|
+
/**
|
|
2776
|
+
* Reports a row selection change whole: what it gained, what it lost, and
|
|
2777
|
+
* everything it now holds. The one to persist from.
|
|
2778
|
+
*/
|
|
2779
|
+
interface RowSelectionChangeEvent<Row> {
|
|
2780
|
+
readonly added: readonly ResolvedRow<Row>[];
|
|
2781
|
+
readonly removed: readonly ResolvedRow<Row>[];
|
|
2782
|
+
/** Every selected row, not only what this interaction changed. */
|
|
2783
|
+
readonly selected: readonly ResolvedRow<Row>[];
|
|
2784
|
+
readonly selection: SelectionState;
|
|
2785
|
+
}
|
|
2786
|
+
/** Reports one column selected or deselected. */
|
|
2787
|
+
interface ColumnSelectEvent<Row, Node = string> {
|
|
2788
|
+
readonly column: SelectedColumn<Row, Node>;
|
|
2789
|
+
readonly selection: SelectionState;
|
|
2790
|
+
}
|
|
2791
|
+
/** Reports every column one interaction selected or deselected. */
|
|
2792
|
+
interface ColumnsSelectEvent<Row, Node = string> {
|
|
2793
|
+
readonly columns: readonly SelectedColumn<Row, Node>[];
|
|
2794
|
+
readonly selection: SelectionState;
|
|
2795
|
+
}
|
|
2796
|
+
/** Reports a column selection change whole. The one to persist from. */
|
|
2797
|
+
interface ColumnSelectionChangeEvent<Row, Node = string> {
|
|
2798
|
+
readonly added: readonly SelectedColumn<Row, Node>[];
|
|
2799
|
+
readonly removed: readonly SelectedColumn<Row, Node>[];
|
|
2800
|
+
/** Every selected column, not only what this interaction changed. */
|
|
2801
|
+
readonly selected: readonly SelectedColumn<Row, Node>[];
|
|
2802
|
+
readonly selection: SelectionState;
|
|
2803
|
+
}
|
|
2804
|
+
/** Reports the cell selected or deselected. */
|
|
2805
|
+
interface CellSelectEvent<Row, Node = string> {
|
|
2806
|
+
readonly cell: SelectedCell<Row, Node>;
|
|
2807
|
+
readonly selection: CellSelectionState;
|
|
2808
|
+
}
|
|
2809
|
+
/**
|
|
2810
|
+
* Reports a cell selection change whole. Both fields are nullable and one
|
|
2811
|
+
* interaction can fill both — moving between cells deselects and selects at
|
|
2812
|
+
* once.
|
|
2813
|
+
*/
|
|
2814
|
+
interface CellSelectionChangeEvent<Row, Node = string> {
|
|
2815
|
+
readonly selected: SelectedCell<Row, Node> | null;
|
|
2816
|
+
readonly deselected: SelectedCell<Row, Node> | null;
|
|
2817
|
+
readonly selection: CellSelectionState;
|
|
2818
|
+
}
|
|
2819
|
+
/**
|
|
2820
|
+
* Everything about a grid the user can change, one slice per feature. Each
|
|
2821
|
+
* slice is the same `*State` type its own `default*` prop and change event
|
|
2822
|
+
* already use, so state read from here can be fed straight back as a default.
|
|
2823
|
+
*/
|
|
2824
|
+
interface GridState<Row> {
|
|
2825
|
+
readonly columnSizing: ColumnSizingState;
|
|
2826
|
+
readonly columnOrder: ColumnOrderState;
|
|
2827
|
+
readonly columnVisibility: ColumnVisibilityState;
|
|
2828
|
+
readonly columnSort: ColumnSortState;
|
|
2829
|
+
readonly filter: FilterState<Row>;
|
|
2830
|
+
readonly groupBy: GroupByState;
|
|
2831
|
+
readonly groupExpansion: GroupExpansionState;
|
|
2832
|
+
readonly pagination: PaginationState;
|
|
2833
|
+
readonly rowSelection: SelectionState;
|
|
2834
|
+
readonly columnSelection: SelectionState;
|
|
2835
|
+
readonly cellSelection: CellSelectionState;
|
|
2836
|
+
}
|
|
2837
|
+
/**
|
|
2838
|
+
* `GridState` as `serializeGridState` writes it: safe to pass through
|
|
2839
|
+
* `JSON.stringify` and back, and to hand straight to `restoreState`.
|
|
2840
|
+
*/
|
|
2841
|
+
interface SerializedGridState<Row> extends Omit<GridState<Row>, "filter"> {
|
|
2842
|
+
readonly filter: SerializedFilterState<Row>;
|
|
2843
|
+
}
|
|
2844
|
+
/**
|
|
2845
|
+
* The slices the view is derived from: every one but the selections, which
|
|
2846
|
+
* change what is highlighted and never what is shown. A whole `GridState`
|
|
2847
|
+
* is one.
|
|
2848
|
+
*/
|
|
2849
|
+
type GridViewState<Row> = Omit<GridState<Row>, "rowSelection" | "columnSelection" | "cellSelection">;
|
|
2850
|
+
/**
|
|
2851
|
+
* The settings that shape the view but are not user state: what the grid is
|
|
2852
|
+
* configured to do, plus the one measurement — `viewportWidth` — that fitting
|
|
2853
|
+
* columns needs from the page. Every field falls back to the same default
|
|
2854
|
+
* the React grid's matching prop does.
|
|
2855
|
+
*/
|
|
2856
|
+
interface GridViewOptions<Row> {
|
|
2857
|
+
/** Whether `pageRows` is one page of `displayRows` rather than all of it. Defaults to `false`. */
|
|
2858
|
+
readonly paginated?: boolean | undefined;
|
|
2859
|
+
readonly aggregates?: AggregateState<Row> | undefined;
|
|
2860
|
+
/** Defaults to `"inline"`. */
|
|
2861
|
+
readonly groupAggregateDisplay?: GroupAggregateDisplay | undefined;
|
|
2862
|
+
readonly columnSizeDefaults?: Partial<ColumnSizeDefaults> | undefined;
|
|
2863
|
+
readonly resizableColumns?: boolean | undefined;
|
|
2864
|
+
readonly reorderableColumns?: boolean | undefined;
|
|
2865
|
+
readonly groupByDraggableColumns?: boolean | undefined;
|
|
2866
|
+
/** Defaults to `"fit"`, which only takes effect once `viewportWidth` is known. */
|
|
2867
|
+
readonly resizeMode?: ResizeMode | undefined;
|
|
2868
|
+
/**
|
|
2869
|
+
* The width, in px, `"fit"` fills. `null` or absent before it has been
|
|
2870
|
+
* measured, or where there is no viewport at all (an export in Node), and
|
|
2871
|
+
* then columns keep their resolved widths.
|
|
2872
|
+
*/
|
|
2873
|
+
readonly viewportWidth?: number | null | undefined;
|
|
2874
|
+
}
|
|
2875
|
+
/** What `resolveGridView` derives the view from. */
|
|
2876
|
+
interface GridViewInput<Row, Node = string> {
|
|
2877
|
+
readonly rows: readonly Row[];
|
|
2878
|
+
readonly getRowId?: ((row: Row, index: number) => string) | undefined;
|
|
2879
|
+
readonly columns: readonly ColumnDefinition<Row, Node>[];
|
|
2880
|
+
readonly state: GridViewState<Row>;
|
|
2881
|
+
readonly options: GridViewOptions<Row>;
|
|
2882
|
+
}
|
|
2883
|
+
/**
|
|
2884
|
+
* What the user is looking at, derived once from `GridViewInput` — every
|
|
2885
|
+
* list a renderer draws, and the ones an export, a toolbar or a status line
|
|
2886
|
+
* reads, so none of them composes the pipeline for itself.
|
|
2887
|
+
*/
|
|
2888
|
+
interface GridView<Row, Node = string> {
|
|
2889
|
+
/** Every column, hidden ones included, ordered but not sized — what the data stages read. */
|
|
2890
|
+
readonly dataColumns: readonly DataColumn<Row, Node>[];
|
|
2891
|
+
/** The columns as rendered: visible, ordered and sized. */
|
|
2892
|
+
readonly columns: readonly ResolvedColumn<Row, Node>[];
|
|
2893
|
+
/** The rows, filtered then sorted. */
|
|
2894
|
+
readonly rows: readonly ResolvedRow<Row>[];
|
|
2895
|
+
/** `rows` grouped, with each group's aggregates attached — every page of it. */
|
|
2896
|
+
readonly displayRows: readonly DisplayRow<Row>[];
|
|
2897
|
+
/** The current page of `displayRows`; all of it when not paginated. */
|
|
2898
|
+
readonly pageRows: readonly DisplayRow<Row>[];
|
|
2899
|
+
/** `pageRows` narrowed to its data rows, in display order — what a range selection spans. */
|
|
2900
|
+
readonly displayDataRows: readonly ResolvedRow<Row>[];
|
|
2901
|
+
/** `1` when not paginated. */
|
|
2902
|
+
readonly pageCount: number;
|
|
2903
|
+
/** `state.pagination.pageIndex` clamped into range; `0` when not paginated. */
|
|
2904
|
+
readonly pageIndex: number;
|
|
2905
|
+
/** Every aggregate over all of `rows`, ungrouped and unpaginated. */
|
|
2906
|
+
readonly grandTotal: AggregateResults;
|
|
2907
|
+
}
|
|
2908
|
+
|
|
2909
|
+
/**
|
|
2910
|
+
* Creates the state container for one grid — see `GridController`. Hold one
|
|
2911
|
+
* per grid for its whole life: it keeps the uncontrolled slices, and its view
|
|
2912
|
+
* is memoised across calls the way `createGridViewResolver`'s is.
|
|
2913
|
+
*/
|
|
2914
|
+
declare function createGridController<Row, Node = string>(initial: GridControllerOptions<Row, Node>): GridController<Row, Node>;
|
|
2915
|
+
|
|
2916
|
+
/** What `createCommandContext` builds a context from. */
|
|
2917
|
+
interface GridCommandContextInput<Row, Node> {
|
|
2918
|
+
readonly controller: GridController<Row, Node>;
|
|
2919
|
+
readonly target: GridCommandTarget;
|
|
2920
|
+
/** The grid's messages, already laid over the defaults — see `resolveMessages`. */
|
|
2921
|
+
readonly messages: GridMessages;
|
|
2922
|
+
readonly host: GridCommandHost;
|
|
2923
|
+
}
|
|
2924
|
+
/**
|
|
2925
|
+
* A command context for `target`, over the controller's state, view and
|
|
2926
|
+
* options as they are now. The controller itself serves as `actions`, typed
|
|
2927
|
+
* down to them, so a command cannot reach `setOptions`.
|
|
2928
|
+
*
|
|
2929
|
+
* `row` and `column` are looked up once here, against every filtered row and
|
|
2930
|
+
* every column, hidden ones included, so a target the API names off screen
|
|
2931
|
+
* still resolves.
|
|
2932
|
+
*/
|
|
2933
|
+
declare function createCommandContext<Row, Node>({ controller, target, messages, host, }: GridCommandContextInput<Row, Node>): GridCommandContext<Row>;
|
|
2934
|
+
|
|
2935
|
+
/**
|
|
2936
|
+
* Every command a grid knows, by id: the built-ins, then `commands` — an app
|
|
2937
|
+
* command with a built-in's id replacing it, so every menu and toolbar
|
|
2938
|
+
* listing that id gets the app's version (translated, gated by a privilege,
|
|
2939
|
+
* or doing something else) without being changed itself.
|
|
2940
|
+
*
|
|
2941
|
+
* A fresh map per call; a renderer resolves it once per change to
|
|
2942
|
+
* `commands`, not per menu.
|
|
2943
|
+
*/
|
|
2944
|
+
declare function resolveCommands<Row>(commands: readonly GridCommand<Row>[] | undefined): ReadonlyMap<string, GridCommand<Row>>;
|
|
2945
|
+
/**
|
|
2946
|
+
* Runs `command` when it is visible and enabled on `context`'s target, and
|
|
2947
|
+
* says whether it did — so a renderer reports only a command that ran, and a
|
|
2948
|
+
* stale button or a call through the API cannot run one the grid's state no
|
|
2949
|
+
* longer allows.
|
|
2950
|
+
*/
|
|
2951
|
+
declare function runCommand<Row>(command: GridCommand<Row>, context: GridCommandContext<Row>): boolean;
|
|
2952
|
+
|
|
2953
|
+
/** What `resolveMenu` resolves a menu's entries against. */
|
|
2954
|
+
interface MenuResolveOptions<Row> {
|
|
2955
|
+
/** Every command the grid knows, by id — see `resolveCommands`. */
|
|
2956
|
+
readonly commands: ReadonlyMap<string, GridCommand<Row>>;
|
|
2957
|
+
readonly context: GridCommandContext<Row>;
|
|
2958
|
+
}
|
|
2959
|
+
/**
|
|
2960
|
+
* A menu's entries resolved against the grid as `context` sees it, ready to
|
|
2961
|
+
* draw:
|
|
2962
|
+
*
|
|
2963
|
+
* - A command id becomes its command's item, and a hidden command or item
|
|
2964
|
+
* is left out. An id naming no command is left out too, and reported once
|
|
2965
|
+
* per command map through `console.error`.
|
|
2966
|
+
* - Labels become strings and flags booleans; `checked` stays `undefined`
|
|
2967
|
+
* for an item that is not checkable.
|
|
2968
|
+
* - A submenu is resolved the same way, and left out when nothing in it
|
|
2969
|
+
* shows.
|
|
2970
|
+
* - Separators never lead, trail or double up, however the items around
|
|
2971
|
+
* them came and went.
|
|
2972
|
+
*
|
|
2973
|
+
* An empty result means there is nothing to show — no grid menu at all
|
|
2974
|
+
* here.
|
|
2975
|
+
*/
|
|
2976
|
+
declare function resolveMenu<Row>(entries: readonly MenuEntry<Row>[], options: MenuResolveOptions<Row>): readonly ResolvedMenuEntry[];
|
|
2977
|
+
|
|
2978
|
+
/** Where an arrow, Home or End key moves a menu's focus. */
|
|
2979
|
+
type MenuMove = "next" | "previous" | "first" | "last";
|
|
2980
|
+
/**
|
|
2981
|
+
* The index of the item focus moves to from `from` — `-1` when nothing is
|
|
2982
|
+
* focused yet, so `"next"` lands on the first item and `"previous"` on the
|
|
2983
|
+
* last. Separators are skipped and `"next"`/`"previous"` wrap round the
|
|
2984
|
+
* ends; disabled items count, since they stay focusable for a screen reader
|
|
2985
|
+
* to find. `-1` when there is no item at all.
|
|
2986
|
+
*
|
|
2987
|
+
* Takes anything with a `type`, so a behaviour that reads its items off the
|
|
2988
|
+
* page can pass `{ type: "item" }` for each.
|
|
2989
|
+
*/
|
|
2990
|
+
declare function nextMenuIndex(entries: readonly Pick<ResolvedMenuEntry, "type">[], from: number, move: MenuMove): number;
|
|
2991
|
+
/**
|
|
2992
|
+
* The index of the item `query` — what was typed, buffered for a moment —
|
|
2993
|
+
* picks, matched case-insensitively against the start of each label and
|
|
2994
|
+
* wrapping round the end; `-1` when none matches.
|
|
2995
|
+
*
|
|
2996
|
+
* `from` is the item focused now. A single letter, or the same letter
|
|
2997
|
+
* typed again and again, searches from the item after it, so repeating a
|
|
2998
|
+
* letter steps through every item it starts. A longer query searches from
|
|
2999
|
+
* `from` itself, so the item already found stays put while what is typed
|
|
3000
|
+
* still matches it.
|
|
3001
|
+
*/
|
|
3002
|
+
declare function typeaheadIndex(labels: readonly string[], from: number, query: string): number;
|
|
3003
|
+
|
|
3004
|
+
/** What `resolveToolbar` resolves a toolbar's entries against. */
|
|
3005
|
+
interface ToolbarResolveOptions<Row> {
|
|
3006
|
+
/** Every command the grid knows, by id — see `resolveCommands`. */
|
|
3007
|
+
readonly commands: ReadonlyMap<string, GridCommand<Row>>;
|
|
3008
|
+
/**
|
|
3009
|
+
* The context an item resolves and runs in, for its target — the item
|
|
3010
|
+
* itself, or the dropdown an item in one is listed under. A command that
|
|
3011
|
+
* opens a panel anchors it there.
|
|
3012
|
+
*/
|
|
3013
|
+
readonly contextFor: (target: GridToolbarTarget) => GridCommandContext<Row>;
|
|
3014
|
+
}
|
|
3015
|
+
/**
|
|
3016
|
+
* A toolbar's entries resolved against the grid, ready to draw, by the
|
|
3017
|
+
* rules `resolveMenu` follows:
|
|
3018
|
+
*
|
|
3019
|
+
* - A command id becomes its command's button, and an inline item a button
|
|
3020
|
+
* of its own; either is a toggle, with `pressed`, when it is checkable. A
|
|
3021
|
+
* hidden one is left out, and so is an id naming no command, reported
|
|
3022
|
+
* once per command map through `console.error`.
|
|
3023
|
+
* - A submenu becomes a dropdown, its items resolved as a menu's, and is
|
|
3024
|
+
* left out when nothing in it shows. `"export"` is one too, of the export
|
|
3025
|
+
* commands, keyed `"export"`.
|
|
3026
|
+
* - `"search"`, `"spacer"` and custom entries stay as they are.
|
|
3027
|
+
* - Separators never lead, trail, double up or sit next to a spacer, which
|
|
3028
|
+
* already parts what is on either side of it.
|
|
3029
|
+
*
|
|
3030
|
+
* Resolve again whenever the grid changes, so each button's label, flags
|
|
3031
|
+
* and `run` follow its state.
|
|
3032
|
+
*/
|
|
3033
|
+
declare function resolveToolbar<Row>(entries: readonly ToolbarEntry<Row>[], options: ToolbarResolveOptions<Row>): readonly ResolvedToolbarItem[];
|
|
3034
|
+
|
|
3035
|
+
/** What `fitToolbarItems` fits: a toolbar's entries, by width, into its space. */
|
|
3036
|
+
interface ToolbarFitInput {
|
|
3037
|
+
/** Each entry's width, in order — `0` for a spacer, whose width is only the space left over. */
|
|
3038
|
+
readonly widths: readonly number[];
|
|
3039
|
+
/** The width the entries share. */
|
|
3040
|
+
readonly available: number;
|
|
3041
|
+
/** The width of the "More" button the entries that do not fit go into. */
|
|
3042
|
+
readonly moreWidth: number;
|
|
3043
|
+
/** Whether each entry, in order, stays however little room there is. */
|
|
3044
|
+
readonly pinned: readonly boolean[];
|
|
3045
|
+
}
|
|
3046
|
+
/**
|
|
3047
|
+
* How many of a toolbar's entries fit, from the start: the first `count`
|
|
3048
|
+
* stay in the toolbar, with every pinned entry after them, and the rest go
|
|
3049
|
+
* into a "More" menu.
|
|
3050
|
+
*
|
|
3051
|
+
* Pinned entries take their room first, wherever they are. Room for "More"
|
|
3052
|
+
* is kept only when something does not fit — when everything does, the
|
|
3053
|
+
* result is every entry and no "More" is drawn. Entries are taken in order
|
|
3054
|
+
* and the first that does not fit ends the count, so the toolbar keeps its
|
|
3055
|
+
* order rather than filling gaps with later, narrower entries; one with no
|
|
3056
|
+
* width, a spacer, fits wherever the entries before it did.
|
|
3057
|
+
*/
|
|
3058
|
+
declare function fitToolbarItems({ widths, available, moreWidth, pinned, }: ToolbarFitInput): number;
|
|
3059
|
+
/**
|
|
3060
|
+
* Whether a toolbar entry stays in the toolbar however narrow it gets: the
|
|
3061
|
+
* search box and custom entries, which have no menu item to become.
|
|
3062
|
+
*/
|
|
3063
|
+
declare function isPinnedToolbarItem(item: Pick<ResolvedToolbarItem, "type">): boolean;
|
|
3064
|
+
/** A toolbar split at the count `fitToolbarItems` gave — see `splitToolbarItems`. */
|
|
3065
|
+
interface ToolbarSplit {
|
|
3066
|
+
/** What stays in the toolbar. */
|
|
3067
|
+
readonly shown: readonly ResolvedToolbarItem[];
|
|
3068
|
+
/** The "More" menu's entries, empty when everything fits. */
|
|
3069
|
+
readonly overflow: readonly ResolvedMenuEntry[];
|
|
3070
|
+
}
|
|
3071
|
+
/**
|
|
3072
|
+
* `items` split at the first `fit`: those before it, and every pinned item,
|
|
3073
|
+
* stay in the toolbar; the rest become the "More" menu's entries — a button
|
|
3074
|
+
* an item, checked where it was pressed, and a dropdown a submenu. Neither
|
|
3075
|
+
* side keeps a separator at its ends, doubled, or beside a spacer.
|
|
3076
|
+
*/
|
|
3077
|
+
declare function splitToolbarItems(items: readonly ResolvedToolbarItem[], fit: number): ToolbarSplit;
|
|
3078
|
+
|
|
3079
|
+
/**
|
|
3080
|
+
* What a search box shows for `filter`: the global text entry's query — the
|
|
3081
|
+
* one naming no column — without the `%` anchors that make it a "contains"
|
|
3082
|
+
* match, or `""` when there is none. A `%` the user typed inside the text
|
|
3083
|
+
* stays: only the first and last characters are anchors.
|
|
3084
|
+
*/
|
|
3085
|
+
declare function searchTextOf<Row>(filter: FilterState<Row>): string;
|
|
3086
|
+
/**
|
|
3087
|
+
* `filter` with its global text entry set to search for `text` anywhere in
|
|
3088
|
+
* any column — the query `%text%` — or removed for an empty `text`. Every
|
|
3089
|
+
* entry naming a column stays as it was. `filter` itself, unchanged, when
|
|
3090
|
+
* it already searches for `text`.
|
|
3091
|
+
*
|
|
3092
|
+
* `text` is written as typed, spaces and all: a search box reads its text
|
|
3093
|
+
* back from the filter, and trimming here would take a space away from
|
|
3094
|
+
* under the caret as the user types it.
|
|
3095
|
+
*/
|
|
3096
|
+
declare function setSearchText<Row>(filter: FilterState<Row>, text: string): FilterState<Row>;
|
|
3097
|
+
|
|
3098
|
+
/**
|
|
3099
|
+
* How a column of `type` aligns by default. Numeric types align right so that
|
|
3100
|
+
* their digits line up by place value; everything else reads from the left.
|
|
3101
|
+
*/
|
|
3102
|
+
declare function alignmentForType(type: ColumnType): ColumnAlignment;
|
|
3103
|
+
/**
|
|
3104
|
+
* Derives one column per field across `rows`, in the order each field is first
|
|
3105
|
+
* seen — so a key that only appears in a later row still gets a column,
|
|
3106
|
+
* appended at the end. Nested objects contribute their non-object properties
|
|
3107
|
+
* as `"Parent.Child"`; anything deeper is skipped, as is the nested object
|
|
3108
|
+
* itself.
|
|
3109
|
+
*
|
|
3110
|
+
* Order follows `Object.entries`, which lists integer-like keys first
|
|
3111
|
+
* regardless of the order they were written in.
|
|
3112
|
+
*
|
|
3113
|
+
* `Node` is whatever the caller's renderer draws: an inferred column sets no
|
|
3114
|
+
* template, so it suits any.
|
|
3115
|
+
*/
|
|
3116
|
+
declare function defineColumnsFromRows<Row, Node = string>(rows: readonly Row[]): readonly ColumnDefinition<Row, Node>[];
|
|
3117
|
+
/**
|
|
3118
|
+
* The key state about a column is stored under, and the key it renders with.
|
|
3119
|
+
* Every such lookup goes through here so the two can never disagree.
|
|
3120
|
+
*/
|
|
3121
|
+
declare function getColumnId<Row>(column: ColumnDefinition<Row, unknown>): string;
|
|
3122
|
+
/**
|
|
3123
|
+
* The key state about a row is stored under, and the key it renders with — the
|
|
3124
|
+
* row's counterpart to `getColumnId`, and for the same reason: every such
|
|
3125
|
+
* lookup goes through here so no two can disagree.
|
|
3126
|
+
*
|
|
3127
|
+
* Falls back to the position so a grid given no `getRowId` still works. That
|
|
3128
|
+
* fallback ties a selection to where a row sits rather than to the row, so
|
|
3129
|
+
* anything that sorts, filters or pages its data has to supply one — otherwise
|
|
3130
|
+
* a re-sort leaves the same positions selected under different rows.
|
|
3131
|
+
*/
|
|
3132
|
+
declare function resolveRowId<Row>(row: Row, index: number, getRowId?: (row: Row, index: number) => string): string;
|
|
3133
|
+
/**
|
|
3134
|
+
* What a column's header shows: its own `headerTemplate`, called first if it is
|
|
3135
|
+
* a function, or else its plain-text `header`, or else a label read off the
|
|
3136
|
+
* field path.
|
|
3137
|
+
*/
|
|
3138
|
+
declare function resolveColumnLabel<Row, Node>(column: ColumnDefinition<Row, Node>): Node | string;
|
|
3139
|
+
/**
|
|
3140
|
+
* A column's name as text, for wherever markup will not do — an
|
|
3141
|
+
* announcement, an export. Its `header` first, even beside a
|
|
3142
|
+
* `headerTemplate`, since a template's output need not be text; then the
|
|
3143
|
+
* label `resolveColumnLabel` gives, when that is a string; then the label
|
|
3144
|
+
* read off the field path.
|
|
3145
|
+
*/
|
|
3146
|
+
declare function resolveColumnHeaderText<Row>(column: ColumnDefinition<Row, unknown>): string;
|
|
3147
|
+
/** Which of a column header's keyboard interactions to announce. */
|
|
3148
|
+
interface KeyShortcutCapabilities {
|
|
3149
|
+
reorderable: boolean;
|
|
3150
|
+
resizable: boolean;
|
|
3151
|
+
sortable: boolean;
|
|
3152
|
+
groupable: boolean;
|
|
3153
|
+
/** Whether the column has a filter menu the header opens. Defaults to `false`. */
|
|
3154
|
+
filterable?: boolean | undefined;
|
|
3155
|
+
/** Whether the header opens the grid's context menu. Defaults to `false`. */
|
|
3156
|
+
contextMenu?: boolean | undefined;
|
|
3157
|
+
}
|
|
3158
|
+
/**
|
|
3159
|
+
* The `aria-keyshortcuts` string for a column header, naming only the keys
|
|
3160
|
+
* that column actually responds to — so the keys are discoverable, since
|
|
3161
|
+
* none of them is a convention a user would try unprompted.
|
|
3162
|
+
*/
|
|
3163
|
+
declare function buildKeyShortcuts(capabilities: KeyShortcutCapabilities): string;
|
|
3164
|
+
/**
|
|
3165
|
+
* Accesses a value at a dotted path, e.g. `foo.bar.baz`.
|
|
3166
|
+
*
|
|
3167
|
+
* @param obj The object to access
|
|
3168
|
+
* @param path Path to the value, e.g. `"foo.bar"`
|
|
3169
|
+
* @returns The value at `path`, or `undefined` if it doesn't exist
|
|
3170
|
+
*/
|
|
3171
|
+
declare function accessDotted(obj: unknown, path: string): unknown;
|
|
3172
|
+
|
|
3173
|
+
/**
|
|
3174
|
+
* The header's row index. One coordinate space covers the header and the body
|
|
3175
|
+
* so that arrowing up out of the first row reaches the header without a case
|
|
3176
|
+
* of its own, and every other move is plain arithmetic.
|
|
3177
|
+
*/
|
|
3178
|
+
declare const HEADER_ROW = -1;
|
|
3179
|
+
/** The cell the grid's single tab stop sits on. */
|
|
3180
|
+
interface GridFocus {
|
|
3181
|
+
readonly rowIndex: number;
|
|
3182
|
+
readonly columnIndex: number;
|
|
3183
|
+
}
|
|
3184
|
+
/** The modifier keys held with a navigation key press. */
|
|
3185
|
+
interface NavigationModifiers {
|
|
3186
|
+
readonly ctrlKey: boolean;
|
|
3187
|
+
readonly metaKey: boolean;
|
|
3188
|
+
readonly altKey: boolean;
|
|
3189
|
+
readonly shiftKey: boolean;
|
|
3190
|
+
}
|
|
3191
|
+
/**
|
|
3192
|
+
* Holds a coordinate inside the grid, so that a focus surviving a column
|
|
3193
|
+
* removal or a shorter page never leaves the grid with no tab stop at all —
|
|
3194
|
+
* which is a grid a keyboard cannot reach.
|
|
3195
|
+
*/
|
|
3196
|
+
declare function clampFocus(focus: GridFocus, rowCount: number, columnCount: number): GridFocus;
|
|
3197
|
+
/**
|
|
3198
|
+
* The focus a navigation key press moves to, or `null` when the key isn't
|
|
3199
|
+
* this grid's to handle — left for the browser or another handler.
|
|
3200
|
+
*
|
|
3201
|
+
* `pageSize` is a pre-measured row count rather than a callback: this
|
|
3202
|
+
* function takes plain data only, so a caller measures the viewport once and
|
|
3203
|
+
* hands over the number.
|
|
3204
|
+
*
|
|
3205
|
+
* `isSkippableRow` names rows the vertical moves (`ArrowUp`/`ArrowDown`/
|
|
3206
|
+
* `PageUp`/`PageDown`/`Ctrl+End`) never land a tab stop on — a group's own
|
|
3207
|
+
* summary row (`groupAggregateDisplay: "row"`), which still occupies a real
|
|
3208
|
+
* row slot for `rowCount`/`aria-rowindex` purposes but is presentational,
|
|
3209
|
+
* not a stop of its own. Left/right and plain `Home`/`End` stay row-scoped
|
|
3210
|
+
* and so never consult it. Defaults to skipping nothing, so every existing
|
|
3211
|
+
* caller (and every horizontal move) is unaffected.
|
|
3212
|
+
*/
|
|
3213
|
+
declare function nextFocusForKey(key: string, modifiers: NavigationModifiers, focus: GridFocus, rowCount: number, columnCount: number, pageSize: number, isSkippableRow?: (rowIndex: number) => boolean): GridFocus | null;
|
|
3214
|
+
|
|
3215
|
+
/**
|
|
3216
|
+
* Puts `columns` in the order `order` gives. Ids it lists come first, in that
|
|
3217
|
+
* order; columns it omits keep their position among the definitions and
|
|
3218
|
+
* follow. Ids naming no column are ignored.
|
|
3219
|
+
*
|
|
3220
|
+
* Tolerating both gaps is what lets a stored order outlive the column list it
|
|
3221
|
+
* was made against.
|
|
3222
|
+
*/
|
|
3223
|
+
declare function applyColumnOrder<Row, Node>(columns: readonly ColumnDefinition<Row, Node>[], order: ColumnOrderState): readonly ColumnDefinition<Row, Node>[];
|
|
3224
|
+
/**
|
|
3225
|
+
* `columns` in the order `order` gives, each paired with its id — the
|
|
3226
|
+
* width-free column list the data stages (filter, sort, group, aggregate)
|
|
3227
|
+
* read. Ordered here, ahead of sizing, so every later stage sees the one
|
|
3228
|
+
* already-ordered list and no part of the grid has to know a reorder
|
|
3229
|
+
* happened.
|
|
3230
|
+
*/
|
|
3231
|
+
declare function resolveDataColumns<Row, Node>(columns: readonly ColumnDefinition<Row, Node>[], order: ColumnOrderState): readonly DataColumn<Row, Node>[];
|
|
3232
|
+
/**
|
|
3233
|
+
* The order with `movedId` lifted out and put back in front of `beforeId`, or
|
|
3234
|
+
* at the end when that is `null`.
|
|
3235
|
+
*
|
|
3236
|
+
* Returns `orderedIds` itself when the move changes nothing, so callers can
|
|
3237
|
+
* treat an unchanged reference as "no move happened".
|
|
3238
|
+
*/
|
|
3239
|
+
declare function moveColumnBefore(orderedIds: ColumnOrderState, movedId: string, beforeId: string | null): ColumnOrderState;
|
|
3240
|
+
/**
|
|
3241
|
+
* Whether moving `movedId` in front of `beforeId` would rearrange anything, so
|
|
3242
|
+
* that a drop indicator promises exactly the moves that happen.
|
|
3243
|
+
*
|
|
3244
|
+
* Defined against `moveColumnBefore` rather than restating its conditions, so
|
|
3245
|
+
* the two cannot disagree about what a no-op is.
|
|
3246
|
+
*/
|
|
3247
|
+
declare function movesColumn(orderedIds: ColumnOrderState, movedId: string, beforeId: string | null): boolean;
|
|
3248
|
+
/**
|
|
3249
|
+
* The id a drop on `side` of `targetId` lands in front of, which is `null`
|
|
3250
|
+
* past the last column.
|
|
3251
|
+
*
|
|
3252
|
+
* "After C" and "before D" name the same gap, so collapsing both to one id
|
|
3253
|
+
* keeps a drop target a single nullable string.
|
|
3254
|
+
*/
|
|
3255
|
+
declare function resolveDropBefore(orderedIds: ColumnOrderState, targetId: string, side: DropSide): string | null;
|
|
3256
|
+
/**
|
|
3257
|
+
* The `beforeId` a keyboard nudge on `columnId` produces, for `onDrop` to
|
|
3258
|
+
* apply the same way a pointer drop does — or `undefined` when the nudge is a
|
|
3259
|
+
* no-op: `columnId` is not in `orderedIds`, or the nudge would move it left
|
|
3260
|
+
* of the start.
|
|
3261
|
+
*
|
|
3262
|
+
* `null` is a real answer here, not "no-op": it means append to the end, the
|
|
3263
|
+
* same convention `moveColumnBefore` uses.
|
|
3264
|
+
*/
|
|
3265
|
+
declare function resolveKeyboardDropTarget(orderedIds: ColumnOrderState, columnId: string, direction: -1 | 1): string | null | undefined;
|
|
3266
|
+
|
|
3267
|
+
/**
|
|
3268
|
+
* The selection with `id` added if absent and removed if present — a
|
|
3269
|
+
* Ctrl-click, or Space on the focused member.
|
|
3270
|
+
*
|
|
3271
|
+
* The mode is enforced here rather than by each caller, so `"single"` cannot
|
|
3272
|
+
* accumulate no matter which interaction reaches it. Returns `selection`
|
|
3273
|
+
* itself when `mode` is `false`, keeping the unchanged-reference contract
|
|
3274
|
+
* `moveColumnBefore` set: a caller treats an unchanged reference as "nothing
|
|
3275
|
+
* happened" and neither renders nor reports.
|
|
3276
|
+
*/
|
|
3277
|
+
declare function toggleSelection(selection: SelectionState, id: string, mode: SelectionMode): SelectionState;
|
|
3278
|
+
/**
|
|
3279
|
+
* The selection reduced to `id` alone — a plain click, which discards what
|
|
3280
|
+
* came before rather than adding to it.
|
|
3281
|
+
*
|
|
3282
|
+
* Never deselects, so clicking the one selected row leaves it selected.
|
|
3283
|
+
* Letting go of it is Ctrl-click's job, and `toggleSelection`'s.
|
|
3284
|
+
*/
|
|
3285
|
+
declare function selectOnly(selection: SelectionState, id: string, mode: SelectionMode): SelectionState;
|
|
3286
|
+
/**
|
|
3287
|
+
* The selection replaced by every id from `anchorId` to `focusId` inclusive — a
|
|
3288
|
+
* Shift-click. The two may be given in either order.
|
|
3289
|
+
*
|
|
3290
|
+
* Spans `orderedIds`, the order as displayed, rather than the selection's own:
|
|
3291
|
+
* the range a user drew across the screen is the range they mean, whatever
|
|
3292
|
+
* order they clicked its ends in. Degrades to `selectOnly` under `"single"`,
|
|
3293
|
+
* where a range has nowhere to go.
|
|
3294
|
+
*/
|
|
3295
|
+
declare function selectRange(selection: SelectionState, orderedIds: readonly string[], anchorId: string, focusId: string, mode: SelectionMode): SelectionState;
|
|
3296
|
+
/**
|
|
3297
|
+
* Every id in `orderedIds`, or `selection` untouched under any mode but
|
|
3298
|
+
* `"multiple"` — there is no selecting all of one thing.
|
|
3299
|
+
*/
|
|
3300
|
+
declare function selectAll(selection: SelectionState, orderedIds: readonly string[], mode: SelectionMode): SelectionState;
|
|
3301
|
+
declare function clearSelection(selection: SelectionState): SelectionState;
|
|
3302
|
+
/**
|
|
3303
|
+
* What one transition added and what it removed.
|
|
3304
|
+
*
|
|
3305
|
+
* Defined here rather than in an adapter so that every callback reporting a
|
|
3306
|
+
* selection change reads one answer, and a select and a deselect fired for the
|
|
3307
|
+
* same interaction cannot disagree about which it was.
|
|
3308
|
+
*/
|
|
3309
|
+
declare function diffSelection(previous: SelectionState, next: SelectionState): SelectionDiff;
|
|
3310
|
+
declare function isSameCell(a: CellSelectionState, b: CellSelectionState): boolean;
|
|
3311
|
+
/**
|
|
3312
|
+
* The cell selection moved to `cell` — a plain click. Idempotent: clicking the
|
|
3313
|
+
* selected cell again leaves it selected, matching `selectOnly`.
|
|
3314
|
+
*/
|
|
3315
|
+
declare function selectCell(selection: CellSelectionState, cell: SelectedCellRef, mode: CellSelectionMode): CellSelectionState;
|
|
3316
|
+
/**
|
|
3317
|
+
* The cell selection moved to `cell`, or cleared when it is already there — a
|
|
3318
|
+
* Ctrl-click, matching `toggleSelection`.
|
|
3319
|
+
*/
|
|
3320
|
+
declare function toggleCellSelection(selection: CellSelectionState, cell: SelectedCellRef, mode: CellSelectionMode): CellSelectionState;
|
|
3321
|
+
/**
|
|
3322
|
+
* The intent a click or key press carries, by the modifiers held with it.
|
|
3323
|
+
*
|
|
3324
|
+
* `toggleOnClick` makes the unmodified press a toggle — the
|
|
3325
|
+
* `selectable.toggleOnClick` checklist behaviour — leaving Shift and Ctrl
|
|
3326
|
+
* to mean what they always do.
|
|
3327
|
+
*/
|
|
3328
|
+
declare function intentOf(event: {
|
|
3329
|
+
ctrlKey: boolean;
|
|
3330
|
+
metaKey: boolean;
|
|
3331
|
+
shiftKey: boolean;
|
|
3332
|
+
}, options?: {
|
|
3333
|
+
toggleOnClick?: boolean | undefined;
|
|
3334
|
+
}): SelectIntent;
|
|
3335
|
+
/**
|
|
3336
|
+
* The transform an intent asks for. A function rather than a branch inside
|
|
3337
|
+
* each caller, so a row and a column cannot come to mean different things by
|
|
3338
|
+
* the same click.
|
|
3339
|
+
*/
|
|
3340
|
+
declare function applySelectionIntent(selection: SelectionState, orderedIds: readonly string[], anchorId: string | null, id: string, intent: SelectIntent, mode: SelectionMode): SelectionState;
|
|
3341
|
+
|
|
3342
|
+
/**
|
|
3343
|
+
* Applied to any column that does not size itself. The minimum is a width a
|
|
3344
|
+
* header stays legible at rather than a measured value — a column dragged
|
|
3345
|
+
* narrower than this reads as a rendering fault.
|
|
3346
|
+
*/
|
|
3347
|
+
declare const DEFAULT_COLUMN_SIZES: ColumnSizeDefaults;
|
|
3348
|
+
/** How far one arrow key press moves a column edge. */
|
|
3349
|
+
declare const KEYBOARD_STEP = 10;
|
|
3350
|
+
/**
|
|
3351
|
+
* The bounds `column` may be sized between. Resolved in one place so that a
|
|
3352
|
+
* drag, a clamp and an auto-fit cannot disagree about a column's limits.
|
|
3353
|
+
*/
|
|
3354
|
+
declare function resolveColumnConstraints<Row>(column: ColumnDefinition<Row, unknown>, defaults?: Partial<ColumnSizeDefaults>): ColumnConstraints;
|
|
3355
|
+
/** Holds `width` within `constraints`. */
|
|
3356
|
+
declare function clampColumnWidth(width: number, constraints: ColumnConstraints): number;
|
|
3357
|
+
/**
|
|
3358
|
+
* Pairs each column with everything needed to render it — the width it sits
|
|
3359
|
+
* at, the label its header shows, whether it may be resized and how its cells
|
|
3360
|
+
* align. Widths take the first of the sizing state, the column's own `width`,
|
|
3361
|
+
* and the default, then clamp.
|
|
3362
|
+
*
|
|
3363
|
+
* The sizing state winning means a user's drag outlives a re-render; a column
|
|
3364
|
+
* absent from it still tracks a `width` edited in the definition.
|
|
3365
|
+
*/
|
|
3366
|
+
declare function resolveColumnWidths<Row, Node>(columns: readonly ColumnDefinition<Row, Node>[], sizing: ColumnSizingState, options?: ColumnResolveOptions): readonly ResolvedColumn<Row, Node>[];
|
|
3367
|
+
declare function totalColumnWidth<Row, Node>(resolved: readonly ResolvedColumn<Row, Node>[]): number;
|
|
3368
|
+
/**
|
|
3369
|
+
* Opens a resize. The session captures its constraints and starting point up
|
|
3370
|
+
* front, so applying a pointer position later is arithmetic on numbers alone —
|
|
3371
|
+
* which is what keeps the drag testable without a DOM.
|
|
3372
|
+
*
|
|
3373
|
+
* @param startPosition Where the pointer went down, on the axis being dragged.
|
|
3374
|
+
*/
|
|
3375
|
+
declare function beginColumnResize<Row>(column: ColumnDefinition<Row, unknown>, startWidth: number, startPosition: number, defaults?: Partial<ColumnSizeDefaults>): ColumnResizeSession;
|
|
3376
|
+
/**
|
|
3377
|
+
* The width the dragged column takes with the pointer at `position`. The delta
|
|
3378
|
+
* is signed, so a right-to-left adapter negates it and nothing else changes.
|
|
3379
|
+
*/
|
|
3380
|
+
declare function applyColumnResize(session: ColumnResizeSession, position: number): number;
|
|
3381
|
+
/**
|
|
3382
|
+
* Fits columns to `availableWidth`: grows them to fill leftover space, or
|
|
3383
|
+
* shrinks them to relieve an overflow, in both cases proportionally to each
|
|
3384
|
+
* column's current width. Columns the user has sized are left alone in
|
|
3385
|
+
* either direction, so dragging one column neither rubber-bands it back nor
|
|
3386
|
+
* has it absorb a squeeze meant for the rest.
|
|
3387
|
+
*
|
|
3388
|
+
* Growing stops at each column's `maxWidth`; shrinking stops at its
|
|
3389
|
+
* `minWidth`. If shrinking every adjustable column to its floor still does
|
|
3390
|
+
* not reach `availableWidth`, the columns are returned untouched and the
|
|
3391
|
+
* container scrolls rather than crushing them further.
|
|
3392
|
+
*/
|
|
3393
|
+
declare function fitColumnsToWidth<Row, Node>(resolved: readonly ResolvedColumn<Row, Node>[], availableWidth: number, defaults?: Partial<ColumnSizeDefaults>): readonly ResolvedColumn<Row, Node>[];
|
|
3394
|
+
/**
|
|
3395
|
+
* The width a column needs to show `measuredWidth` of content.
|
|
3396
|
+
*
|
|
3397
|
+
* `padding` is an allowance on top of the measurement, since a column sized to
|
|
3398
|
+
* exactly its content can still round down into an ellipsis.
|
|
3399
|
+
*/
|
|
3400
|
+
declare function sizeColumnToContent(measuredWidth: number, constraints: ColumnConstraints, padding?: number): number;
|
|
3401
|
+
/**
|
|
3402
|
+
* `current` with `columnId` reverted to its width in `base` — or omitted
|
|
3403
|
+
* entirely if `base` had none — for Escape to restore a resize in progress.
|
|
3404
|
+
*
|
|
3405
|
+
* A column with no stored width in `base` is correctly omitted by deleting
|
|
3406
|
+
* the key rather than merging its `base` width back in, which would
|
|
3407
|
+
* otherwise leave it pinned and hidden from auto-fit.
|
|
3408
|
+
*/
|
|
3409
|
+
declare function revertColumnSize(current: ColumnSizingState, base: ColumnSizingState, columnId: string): ColumnSizingState;
|
|
3410
|
+
|
|
3411
|
+
/**
|
|
3412
|
+
* Compares two cell values the way `type` implies — numerically for the
|
|
3413
|
+
* numeric types, chronologically for the date/time types, lexically
|
|
3414
|
+
* otherwise. Defaults to string comparison when `type` is absent, mirroring
|
|
3415
|
+
* `ColumnDefinition.type`'s own default.
|
|
3416
|
+
*
|
|
3417
|
+
* `null`/`undefined` sort after every value on both sides. Used directly,
|
|
3418
|
+
* that ordering is fixed; `sortRows` applies it directionally without
|
|
3419
|
+
* disturbing it — see its own doc comment.
|
|
3420
|
+
*/
|
|
3421
|
+
declare function compareValues(a: unknown, b: unknown, type?: ColumnType): number;
|
|
3422
|
+
/** This column's direction in `sort`, or `null` outside it. */
|
|
3423
|
+
declare function sortDirectionFor(sort: ColumnSortState, columnId: string): SortDirection | null;
|
|
3424
|
+
/** This column's 1-based place in `sort`, or `null` outside it. */
|
|
3425
|
+
declare function sortPriorityFor(sort: ColumnSortState, columnId: string): number | null;
|
|
3426
|
+
/**
|
|
3427
|
+
* The sort with `columnId` cycled to its next direction — none → asc → desc →
|
|
3428
|
+
* none.
|
|
3429
|
+
*
|
|
3430
|
+
* `stack: false` (a plain click) means "sort by only this column": unless
|
|
3431
|
+
* `columnId` is already the sole entry, in which case its own cycle just
|
|
3432
|
+
* continues, it collapses `sort` down to `columnId` alone at `"asc"`,
|
|
3433
|
+
* regardless of any direction it held as part of a larger stack.
|
|
3434
|
+
*
|
|
3435
|
+
* `stack: true` (a Shift-click) cycles or appends `columnId` in place without
|
|
3436
|
+
* disturbing the rest of the stack; cycling it back to `"none"` removes it
|
|
3437
|
+
* and closes the gap, leaving the others in their existing order.
|
|
3438
|
+
*/
|
|
3439
|
+
declare function toggleColumnSort(sort: ColumnSortState, columnId: string, options: {
|
|
3440
|
+
readonly stack: boolean;
|
|
3441
|
+
}): ColumnSortState;
|
|
3442
|
+
/**
|
|
3443
|
+
* `rows` ordered by `sort` — each entry read against `columns` for its
|
|
3444
|
+
* `field` and `type` — with `rowIndex` and `datasetIndex` renumbered to
|
|
3445
|
+
* match the new positions, the invariant the rest of the grid relies on for
|
|
3446
|
+
* keyboard navigation and `aria-rowindex`.
|
|
3447
|
+
*
|
|
3448
|
+
* Stable (`Array.prototype.sort` has been stable since ES2019), so rows
|
|
3449
|
+
* equal under every active key keep their relative order. A `null`/
|
|
3450
|
+
* `undefined` value sorts last under either direction — resolved before
|
|
3451
|
+
* `compareValues` is asked, and left out of the direction flip below, so
|
|
3452
|
+
* that toggling a column reorders the values it holds rather than moving its
|
|
3453
|
+
* gaps to the front.
|
|
3454
|
+
*
|
|
3455
|
+
* Returns `rows` itself, untouched, when `sort` is empty or names only
|
|
3456
|
+
* columns absent from `columns` — a stored sort tolerates a column removed
|
|
3457
|
+
* from the definition the same way a stored `ColumnOrderState` does.
|
|
3458
|
+
*/
|
|
3459
|
+
declare function sortRows<Row>(rows: readonly ResolvedRow<Row>[], sort: ColumnSortState, columns: readonly DataColumn<Row, unknown>[]): readonly ResolvedRow<Row>[];
|
|
3460
|
+
|
|
3461
|
+
/**
|
|
3462
|
+
* Whether `value`, stringified, matches `query`'s SQL LIKE-style pattern —
|
|
3463
|
+
* case-insensitive always. A bare query is an exact match; `%text%` is
|
|
3464
|
+
* contains; `text%` is starts-with; `%text` is ends-with. `null`/`undefined`
|
|
3465
|
+
* stringify to `""`.
|
|
3466
|
+
*
|
|
3467
|
+
* A one-shot convenience: parses `query` fresh on every call. `filterRows`
|
|
3468
|
+
* does not call this per cell — it compiles each `TextFilterEntry` once,
|
|
3469
|
+
* outside its row loop.
|
|
3470
|
+
*/
|
|
3471
|
+
declare function matchesQuery(value: unknown, query: string): boolean;
|
|
3472
|
+
/**
|
|
3473
|
+
* This column's current text query, or the global entry's when `columnId`
|
|
3474
|
+
* is omitted; `null` if no `TextFilterEntry` names it — including when the
|
|
3475
|
+
* entry that exists for that key is a `ValueFilterEntry`/
|
|
3476
|
+
* `PredicateFilterEntry`/`OperatorFilterEntry`/`GroupFilterEntry` instead,
|
|
3477
|
+
* since none of those hold a query string to report.
|
|
3478
|
+
*/
|
|
3479
|
+
declare function filterQueryFor<Row>(filter: FilterState<Row>, columnId?: FieldPath<Row> | (string & {})): string | null;
|
|
3480
|
+
/**
|
|
3481
|
+
* The filter with the `TextFilterEntry` for `columnId` (or the global
|
|
3482
|
+
* entry, when `columnId` is omitted) set to `query` — replacing whatever
|
|
3483
|
+
* entry already holds that key, of any variant, if present; appending a new
|
|
3484
|
+
* `TextFilterEntry` if not. An empty `query` removes the entry instead of
|
|
3485
|
+
* storing a filter that can never usefully match.
|
|
3486
|
+
*
|
|
3487
|
+
* Returns `filter` itself, unchanged, when the result would be a no-op: an
|
|
3488
|
+
* empty `query` naming a key with no existing entry, or a `query` equal to
|
|
3489
|
+
* an existing `TextFilterEntry`'s.
|
|
3490
|
+
*/
|
|
3491
|
+
declare function setColumnFilter<Row>(filter: FilterState<Row>, columnId: (FieldPath<Row> | (string & {})) | undefined, query: string): FilterState<Row>;
|
|
3492
|
+
/** `filter` reduced to empty. Returns `filter` itself when already empty. */
|
|
3493
|
+
declare function clearAllFilters<Row>(filter: FilterState<Row>): FilterState<Row>;
|
|
3494
|
+
/**
|
|
3495
|
+
* `rows` reduced to those matching every entry in `filter` (AND at the top
|
|
3496
|
+
* level — nest a `GroupFilterEntry` for OR). `rowIndex` and `datasetIndex`
|
|
3497
|
+
* are renumbered to match the retained positions — the same invariant
|
|
3498
|
+
* `sortRows` keeps,
|
|
3499
|
+
* needed here independently since `filterRows` runs before `sortRows` in
|
|
3500
|
+
* the composed pipeline (see `resolveShownRows`).
|
|
3501
|
+
*
|
|
3502
|
+
* Order-preserving: surviving rows keep their relative order, which is what
|
|
3503
|
+
* makes running this before a sort produce the identical final order a
|
|
3504
|
+
* sort-then-filter would — only the cost differs.
|
|
3505
|
+
*
|
|
3506
|
+
* Every entry is compiled once, before the row loop.
|
|
3507
|
+
*
|
|
3508
|
+
* Returns `rows` itself, untouched, when `filter` is empty or names only
|
|
3509
|
+
* columns absent from `columns` — a stored filter tolerates a column
|
|
3510
|
+
* removed from the definition the same way a stored `ColumnSortState` does.
|
|
3511
|
+
*/
|
|
3512
|
+
declare function filterRows<Row>(rows: readonly ResolvedRow<Row>[], filter: FilterState<Row>, columns: readonly DataColumn<Row, unknown>[]): readonly ResolvedRow<Row>[];
|
|
3513
|
+
|
|
3514
|
+
/**
|
|
3515
|
+
* This group's id, from its path. Every group-id producer/consumer in this
|
|
3516
|
+
* package goes through this — never join `path` by hand elsewhere.
|
|
3517
|
+
*
|
|
3518
|
+
* `JSON.stringify` rather than a delimiter join: a delimiter would have to be
|
|
3519
|
+
* escaped in every segment to stay collision-free against a value that
|
|
3520
|
+
* legitimately contains it, and `JSON.stringify` already draws that
|
|
3521
|
+
* boundary between array entries for free.
|
|
3522
|
+
*/
|
|
3523
|
+
declare function groupRowId(path: readonly unknown[]): string;
|
|
3524
|
+
/**
|
|
3525
|
+
* `rows`, regrouped into `groupBy`'s stacked levels — a group header per
|
|
3526
|
+
* distinct value at each level, ordered by `compareValues` per that level's
|
|
3527
|
+
* own `direction`, followed depth-first by its nested groups and/or data
|
|
3528
|
+
* rows. A collapsed group (its `groupId` present in `expansion`) contributes
|
|
3529
|
+
* only its own header, nothing beneath it — but its `count` still reports
|
|
3530
|
+
* the group's full leaf-row count either way.
|
|
3531
|
+
*
|
|
3532
|
+
* Filter and sort are expected to have already run (see `resolveShownRows`):
|
|
3533
|
+
* this only reshapes their output, and never changes which rows appear or
|
|
3534
|
+
* their relative order within a group.
|
|
3535
|
+
*
|
|
3536
|
+
* `rowIndex` and `datasetIndex` are renumbered across the whole flattened
|
|
3537
|
+
* output, header rows included — the same invariant `sortRows`/`filterRows`
|
|
3538
|
+
* keep for a `ResolvedRow`, extended to `ResolvedGroupRow` since `GridBody`
|
|
3539
|
+
* addresses both kinds by the same flat position, and `aria-rowindex`
|
|
3540
|
+
* counts both.
|
|
3541
|
+
*
|
|
3542
|
+
* Returns `rows` itself, untouched, when `groupBy` is empty or names only
|
|
3543
|
+
* columns absent from `columns` — a stored grouping tolerates a column
|
|
3544
|
+
* removed from the definition the same way a stored `ColumnSortState` does.
|
|
3545
|
+
*/
|
|
3546
|
+
declare function groupRows<Row>(rows: readonly ResolvedRow<Row>[], groupBy: GroupByState, expansion: GroupExpansionState, columns: readonly DataColumn<Row, unknown>[]): readonly DisplayRow<Row>[];
|
|
3547
|
+
/**
|
|
3548
|
+
* The expansion with `groupId` collapsed if it was expanded, or expanded if
|
|
3549
|
+
* it was collapsed.
|
|
3550
|
+
*/
|
|
3551
|
+
declare function toggleGroupExpansion(expansion: GroupExpansionState, groupId: string): GroupExpansionState;
|
|
3552
|
+
/** `expansion` reduced to empty — every group expanded. Mirrors `clearAllFilters`. */
|
|
3553
|
+
declare function expandAllGroups(expansion: GroupExpansionState): GroupExpansionState;
|
|
3554
|
+
/**
|
|
3555
|
+
* Every group id present in `rows` — for collapsing every group currently
|
|
3556
|
+
* shown in one call. Operates on the already-grouped display, not the raw
|
|
3557
|
+
* grouping, so a group hidden beneath an already-collapsed ancestor (and so
|
|
3558
|
+
* absent from `rows`) keeps whatever expansion it already had rather than
|
|
3559
|
+
* being forced closed too; expanding that ancestor again reveals it exactly
|
|
3560
|
+
* as it was left.
|
|
3561
|
+
*
|
|
3562
|
+
* Group headers only: a summary row (`groupAggregateDisplay: "row"`) carries
|
|
3563
|
+
* its group's id too, and counting it would list that group twice.
|
|
3564
|
+
*/
|
|
3565
|
+
declare function collapseAllGroups<Row>(rows: readonly DisplayRow<Row>[]): GroupExpansionState;
|
|
3566
|
+
/**
|
|
3567
|
+
* `groupBy` with `columnId` positioned in front of `beforeColumnId` — or at
|
|
3568
|
+
* the end when that is `null` — inserting a fresh entry if `columnId` isn't
|
|
3569
|
+
* already part of the stack, or lifting its existing entry out and back in
|
|
3570
|
+
* if it is. The one function both a header dropped on the group-by bar and
|
|
3571
|
+
* a chip dragged within it need: the former's `columnId` is usually new to
|
|
3572
|
+
* the stack, the latter's never is, and this doesn't need to be told which.
|
|
3573
|
+
*
|
|
3574
|
+
* An existing entry keeps its own object (and so its own `direction`)
|
|
3575
|
+
* rather than being rebuilt, so a level merely repositioned stays
|
|
3576
|
+
* reference-equal at its new index — the same reason `moveColumnBefore`
|
|
3577
|
+
* moves ids rather than rebuilding them.
|
|
3578
|
+
*
|
|
3579
|
+
* Returns `groupBy` itself, untouched, when the move changes nothing: a
|
|
3580
|
+
* drop on the entry's own id, or back into the gap it already occupies, or
|
|
3581
|
+
* naming a `beforeColumnId` absent from the stack. Inserting a column not
|
|
3582
|
+
* yet in the stack is never a no-op.
|
|
3583
|
+
*/
|
|
3584
|
+
declare function moveGroupByBefore(groupBy: GroupByState, columnId: string, beforeColumnId: string | null): GroupByState;
|
|
3585
|
+
/**
|
|
3586
|
+
* Whether moving `columnId` in front of `beforeColumnId` would change
|
|
3587
|
+
* `groupBy` at all, so that a drop indicator promises exactly the move that
|
|
3588
|
+
* happens. Defined against `moveGroupByBefore` rather than restating its
|
|
3589
|
+
* conditions, the same relationship `movesColumn` keeps with
|
|
3590
|
+
* `moveColumnBefore`.
|
|
3591
|
+
*/
|
|
3592
|
+
declare function movesGroupBy(groupBy: GroupByState, columnId: string, beforeColumnId: string | null): boolean;
|
|
3593
|
+
|
|
3594
|
+
/**
|
|
3595
|
+
* `rows`, filtered then sorted — the one function `DataGrid.tsx` (and any
|
|
3596
|
+
* future framework binding) calls instead of composing `filterRows`/
|
|
3597
|
+
* `sortRows` itself.
|
|
3598
|
+
*
|
|
3599
|
+
* Filter always runs first: an O(n) pass that shrinks what the O(n log n)
|
|
3600
|
+
* sort has to touch whenever a filter is active, free when it isn't. This
|
|
3601
|
+
* is a performance choice, not a correctness one — filtering is an
|
|
3602
|
+
* order-preserving predicate and sort is a stable total order over whatever
|
|
3603
|
+
* it's handed, so the final order is identical either way.
|
|
3604
|
+
*/
|
|
3605
|
+
declare function resolveShownRows<Row>(rows: readonly ResolvedRow<Row>[], filter: FilterState<Row>, sort: ColumnSortState, columns: readonly DataColumn<Row, unknown>[]): readonly ResolvedRow<Row>[];
|
|
3606
|
+
/**
|
|
3607
|
+
* `ids` resolved back to the rows behind them, keyed by `rowsById`.
|
|
3608
|
+
*
|
|
3609
|
+
* An id with no row behind it is dropped rather than left `undefined`: a
|
|
3610
|
+
* selection outlives a change to the data, so that filtering a row out and
|
|
3611
|
+
* back leaves it selected, and only what still exists can be handed to a
|
|
3612
|
+
* callback.
|
|
3613
|
+
*/
|
|
3614
|
+
declare function resolveRows<Row>(rowsById: ReadonlyMap<string, ResolvedRow<Row>>, ids: readonly string[]): readonly ResolvedRow<Row>[];
|
|
3615
|
+
/**
|
|
3616
|
+
* `ids` resolved back to the columns behind them, paired with the position
|
|
3617
|
+
* each holds in `columns` — a stale id is dropped, matching `resolveRows`.
|
|
3618
|
+
*/
|
|
3619
|
+
declare function resolveColumns<Row, Node>(columns: readonly ResolvedColumn<Row, Node>[], ids: readonly string[]): readonly SelectedColumn<Row, Node>[];
|
|
3620
|
+
/**
|
|
3621
|
+
* `cell` resolved down to the row, column and value it addresses — `null`
|
|
3622
|
+
* when there is no cell, or when either half of it names a row or column
|
|
3623
|
+
* that no longer exists.
|
|
3624
|
+
*/
|
|
3625
|
+
declare function resolveCell<Row, Node>(rowsById: ReadonlyMap<string, ResolvedRow<Row>>, columns: readonly ResolvedColumn<Row, Node>[], cell: SelectedCellRef | null): SelectedCell<Row, Node> | null;
|
|
3626
|
+
|
|
3627
|
+
interface PaginatedRows<Row> {
|
|
3628
|
+
readonly rows: readonly DisplayRow<Row>[];
|
|
3629
|
+
readonly pageCount: number;
|
|
3630
|
+
/**
|
|
3631
|
+
* `pagination.pageIndex` clamped into `[0, pageCount - 1]` (or `0` when
|
|
3632
|
+
* `pageCount` is `0`) — read this back rather than trusting the input
|
|
3633
|
+
* verbatim, the same way `sortRows`/`filterRows` tolerate a stale stored
|
|
3634
|
+
* state.
|
|
3635
|
+
*/
|
|
3636
|
+
readonly pageIndex: number;
|
|
3637
|
+
}
|
|
3638
|
+
/**
|
|
3639
|
+
* `rows` sliced into pages of `pagination.pageSize` units — see `unitsOf`
|
|
3640
|
+
* for what a unit is. `pageIndex` is clamped into range, `pageSize <= 0` is
|
|
3641
|
+
* clamped to `1` (this codebase's general tolerance for stale/odd stored
|
|
3642
|
+
* state, matching `sortRows`/`filterRows`), and the returned page's
|
|
3643
|
+
* `rowIndex` is renumbered to be page-relative — 0-based from the top of the
|
|
3644
|
+
* page, header rows included, mirroring `groupRows`'s own renumbering
|
|
3645
|
+
* invariant. `datasetIndex` is left untouched: the stages ahead of this one
|
|
3646
|
+
* set it to each row's position in the whole displayed result, which stays
|
|
3647
|
+
* the same whichever page is showing.
|
|
3648
|
+
*/
|
|
3649
|
+
declare function paginateRows<Row>(rows: readonly DisplayRow<Row>[], pagination: PaginationState): PaginatedRows<Row>;
|
|
3650
|
+
|
|
3651
|
+
type PaginationWindowEntry = number | "ellipsis";
|
|
3652
|
+
/**
|
|
3653
|
+
* Which page numbers a numbered pager should show for `currentPage` of
|
|
3654
|
+
* `pageCount` — the boundary + sibling windowing MUI's `usePagination` uses.
|
|
3655
|
+
* Always includes the first/last `boundaryCount` pages and a run of
|
|
3656
|
+
* `2 * siblingCount + 1` pages around `currentPage`, slid inwards rather than
|
|
3657
|
+
* cut short near either end, with one slot between each boundary and that
|
|
3658
|
+
* run holding either the single page it skips or an `"ellipsis"`.
|
|
3659
|
+
*
|
|
3660
|
+
* So once `pageCount` exceeds `2 * boundaryCount + 2 * siblingCount + 3`,
|
|
3661
|
+
* every window is exactly that many entries long, wherever `currentPage`
|
|
3662
|
+
* sits: a pager drawing one fixed-width slot per entry keeps its trailing
|
|
3663
|
+
* controls in place as the user pages through. Below that, every page shows.
|
|
3664
|
+
*/
|
|
3665
|
+
declare function paginationWindow(currentPage: number, pageCount: number, options?: {
|
|
3666
|
+
boundaryCount?: number | undefined;
|
|
3667
|
+
siblingCount?: number | undefined;
|
|
3668
|
+
}): readonly PaginationWindowEntry[];
|
|
3669
|
+
|
|
3670
|
+
/**
|
|
3671
|
+
* `rows` reduced through every spec in `specs`, keyed by `spec.id ??
|
|
3672
|
+
* spec.columnId`. A custom `fn` (a plain function, not a `BuiltInAggregate`
|
|
3673
|
+
* name) is called once with the raw `rows` — no wrapping, no
|
|
3674
|
+
* pre-processing, so it sees exactly the same leaf set a built-in reducer
|
|
3675
|
+
* does.
|
|
3676
|
+
*
|
|
3677
|
+
* Two specs resolving to the same key: the later one wins, matching
|
|
3678
|
+
* `setColumnFilter`'s own silent-replace precedent for a key collision
|
|
3679
|
+
* rather than throwing.
|
|
3680
|
+
*
|
|
3681
|
+
* Returns a fresh empty `Map` for empty `rows` or empty `specs` — never a
|
|
3682
|
+
* shared singleton — matching this codebase's general avoidance of shared
|
|
3683
|
+
* mutable module state.
|
|
3684
|
+
*/
|
|
3685
|
+
declare function computeAggregates<Row>(rows: readonly Row[], specs: AggregateState<Row>, columns: readonly DataColumn<Row, unknown>[]): AggregateResults;
|
|
3686
|
+
declare function withGroupAggregates<Row>(displayRows: readonly DisplayRow<Row>[], flatRows: readonly ResolvedRow<Row>[], groupBy: GroupByState, specs: AggregateState<Row>, columns: readonly DataColumn<Row, unknown>[], display?: GroupAggregateDisplay): readonly DisplayRow<Row>[];
|
|
3687
|
+
|
|
3688
|
+
/**
|
|
3689
|
+
* Whether `column` is shown: what the user last chose for it, if anything,
|
|
3690
|
+
* else what its definition says. The one place that precedence is decided,
|
|
3691
|
+
* so the view and an imperative "is it showing?" cannot disagree.
|
|
3692
|
+
*/
|
|
3693
|
+
declare function isColumnVisible<Row>(column: ColumnDefinition<Row, unknown>, visibility: ColumnVisibilityState): boolean;
|
|
3694
|
+
/**
|
|
3695
|
+
* `columns` without the hidden ones, in the same order. `columns` itself when
|
|
3696
|
+
* every column is shown — the common case — so a stage memoised on this
|
|
3697
|
+
* output sees nothing change.
|
|
3698
|
+
*/
|
|
3699
|
+
declare function applyColumnVisibility<Row, Node>(columns: readonly DataColumn<Row, Node>[], visibility: ColumnVisibilityState): readonly DataColumn<Row, Node>[];
|
|
3700
|
+
/**
|
|
3701
|
+
* `visibility` with each of `columnIds` shown (`visible: true`) or hidden.
|
|
3702
|
+
* Only a column whose visibility actually changes gets an entry, and ids
|
|
3703
|
+
* naming no column are ignored, so asking to show what is already showing
|
|
3704
|
+
* hands back `visibility` itself — the same reference, for a caller deciding
|
|
3705
|
+
* whether anything happened.
|
|
3706
|
+
*/
|
|
3707
|
+
declare function setColumnVisibility<Row>(columns: readonly DataColumn<Row, unknown>[], visibility: ColumnVisibilityState, columnIds: readonly string[], visible: boolean): ColumnVisibilityState;
|
|
3708
|
+
|
|
3709
|
+
/**
|
|
3710
|
+
* What one column's filter looks like to an editor — which of its forms can
|
|
3711
|
+
* show it, or that none can.
|
|
3712
|
+
*
|
|
3713
|
+
* - `"none"`: no entry touches the column.
|
|
3714
|
+
* - `"values"`: a checklist — one `in` entry, optionally OR-grouped with an
|
|
3715
|
+
* `isEmpty` on the same column (`includeBlanks`).
|
|
3716
|
+
* - `"conditions"`: one or two operator entries on the column (any but
|
|
3717
|
+
* `in`), at the top level (ANDed) or alone in one group with its
|
|
3718
|
+
* combinator.
|
|
3719
|
+
* - `"custom"`: anything else that touches the column — a text query, a
|
|
3720
|
+
* predicate, a group spanning several columns. An editor shows it as
|
|
3721
|
+
* such, and applying an editor's draft replaces it.
|
|
3722
|
+
*/
|
|
3723
|
+
type ColumnFilterShape<Row> = {
|
|
3724
|
+
readonly kind: "none";
|
|
3725
|
+
} | {
|
|
3726
|
+
readonly kind: "values";
|
|
3727
|
+
readonly values: readonly FilterScalar[];
|
|
3728
|
+
readonly includeBlanks: boolean;
|
|
3729
|
+
} | {
|
|
3730
|
+
readonly kind: "conditions";
|
|
3731
|
+
readonly conditions: readonly OperatorFilterEntry<Row>[];
|
|
3732
|
+
readonly combinator: "and" | "or";
|
|
3733
|
+
} | {
|
|
3734
|
+
readonly kind: "custom";
|
|
3735
|
+
};
|
|
3736
|
+
/** One distinct value a column holds, as a checklist offers it. */
|
|
3737
|
+
interface ColumnValueOption {
|
|
3738
|
+
readonly value: Exclude<FilterScalar, null>;
|
|
3739
|
+
/** The value as the column prints it — what a search matches against. */
|
|
3740
|
+
readonly label: string;
|
|
3741
|
+
/** How many rows hold it, among the rows the other columns' filters keep. */
|
|
3742
|
+
readonly count: number;
|
|
3743
|
+
}
|
|
3744
|
+
/** What `columnValueOptions` narrows its list by. */
|
|
3745
|
+
interface ColumnValueQuery {
|
|
3746
|
+
/** Keeps the values whose label contains this, ignoring case. */
|
|
3747
|
+
readonly search?: string;
|
|
3748
|
+
/** Keeps at most this many values, first in sorted order. */
|
|
3749
|
+
readonly limit?: number;
|
|
3750
|
+
/** The locale labels are formatted for — the grid's own `locale`. */
|
|
3751
|
+
readonly locale?: FormatLocale;
|
|
3752
|
+
/**
|
|
3753
|
+
* The grid's own `messages`, over the defaults: a boolean is labelled
|
|
3754
|
+
* `booleanTrue`/`booleanFalse`, as its cells print it.
|
|
3755
|
+
*/
|
|
3756
|
+
readonly messages?: Partial<GridMessages>;
|
|
3757
|
+
}
|
|
3758
|
+
interface ColumnValueOptions {
|
|
3759
|
+
/** The distinct values, sorted as the column sorts, searched and cut to `limit`. */
|
|
3760
|
+
readonly options: readonly ColumnValueOption[];
|
|
3761
|
+
/** How many values matched the search, before `limit` cut them. */
|
|
3762
|
+
readonly total: number;
|
|
3763
|
+
/** Whether `limit` left values out. */
|
|
3764
|
+
readonly truncated: boolean;
|
|
3765
|
+
/** How many of the same rows hold a blank — `null`, `undefined` or `""`. */
|
|
3766
|
+
readonly blanks: number;
|
|
3767
|
+
/**
|
|
3768
|
+
* The column's `type`, which tells values apart the way an `in` filter
|
|
3769
|
+
* does — on a date column, a date string and the `Date` it names are one
|
|
3770
|
+
* value. `initialFilterEditorDraft` carries it into the draft.
|
|
3771
|
+
*/
|
|
3772
|
+
readonly columnType?: ColumnType | undefined;
|
|
3773
|
+
}
|
|
3774
|
+
/**
|
|
3775
|
+
* A checklist or condition editor's working copy of one column's filter,
|
|
3776
|
+
* changed by `filterEditorReducer` and turned into a filter by
|
|
3777
|
+
* `draftToFilter` only when the user applies it — so cancelling is just
|
|
3778
|
+
* dropping the draft.
|
|
3779
|
+
*/
|
|
3780
|
+
interface FilterEditorDraft<Row> {
|
|
3781
|
+
/** Which half of the draft `draftToFilter` applies: the last one changed. */
|
|
3782
|
+
readonly mode: "values" | "conditions";
|
|
3783
|
+
/** Every value the editor offers, from `columnValueOptions`. */
|
|
3784
|
+
readonly options: readonly ColumnValueOption[];
|
|
3785
|
+
/** How many rows hold a blank; the blanks entry only matters when some do. */
|
|
3786
|
+
readonly blanks: number;
|
|
3787
|
+
readonly search: string;
|
|
3788
|
+
/** The checked values, keyed as an `in` filter on the column keys them. */
|
|
3789
|
+
readonly checked: ReadonlyMap<string, FilterScalar>;
|
|
3790
|
+
readonly includeBlanks: boolean;
|
|
3791
|
+
readonly conditions: readonly OperatorFilterEntry<Row>[];
|
|
3792
|
+
readonly combinator: "and" | "or";
|
|
3793
|
+
/** The column's `type`, from `ColumnValueOptions` — what values are keyed by. */
|
|
3794
|
+
readonly columnType?: ColumnType | undefined;
|
|
3795
|
+
}
|
|
3796
|
+
type FilterEditorAction<Row> = {
|
|
3797
|
+
readonly type: "search";
|
|
3798
|
+
readonly search: string;
|
|
3799
|
+
} | {
|
|
3800
|
+
readonly type: "toggleValue";
|
|
3801
|
+
readonly value: FilterScalar;
|
|
3802
|
+
}
|
|
3803
|
+
/** Checks every value the search shows, or unchecks them once all are. */
|
|
3804
|
+
| {
|
|
3805
|
+
readonly type: "toggleAll";
|
|
3806
|
+
} | {
|
|
3807
|
+
readonly type: "setIncludeBlanks";
|
|
3808
|
+
readonly includeBlanks: boolean;
|
|
3809
|
+
} | {
|
|
3810
|
+
readonly type: "setConditions";
|
|
3811
|
+
readonly conditions: readonly OperatorFilterEntry<Row>[];
|
|
3812
|
+
/** Keeps the draft's own when omitted. */
|
|
3813
|
+
readonly combinator?: "and" | "or";
|
|
3814
|
+
}
|
|
3815
|
+
/** Back to "no filter": every value checked, no conditions, no search. */
|
|
3816
|
+
| {
|
|
3817
|
+
readonly type: "clear";
|
|
3818
|
+
};
|
|
3819
|
+
/** A select-all checkbox's state over the values the search shows. */
|
|
3820
|
+
type SelectAllState = "checked" | "unchecked" | "mixed";
|
|
3821
|
+
/**
|
|
3822
|
+
* How `filter` filters `columnId`, as one of the forms an editor can show —
|
|
3823
|
+
* see `ColumnFilterShape`. Entries about other columns don't count, nor do
|
|
3824
|
+
* entries across every column (a global search).
|
|
3825
|
+
*/
|
|
3826
|
+
declare function describeColumnFilter<Row>(filter: FilterState<Row>, columnId: string): ColumnFilterShape<Row>;
|
|
3827
|
+
/**
|
|
3828
|
+
* Whether `filter` filters `columnId` — whether `describeColumnFilter` reads
|
|
3829
|
+
* it as anything but `"none"` — for a header to show its column as
|
|
3830
|
+
* filtered. A global search filters every column alike, so it marks none.
|
|
3831
|
+
*/
|
|
3832
|
+
declare function isColumnFiltered<Row>(filter: FilterState<Row>, columnId: string): boolean;
|
|
3833
|
+
/**
|
|
3834
|
+
* The distinct values `columnId` holds, for a checklist editor: each with
|
|
3835
|
+
* its label and how many rows hold it.
|
|
3836
|
+
*
|
|
3837
|
+
* Counted over the rows every *other* column's filter keeps — every entry
|
|
3838
|
+
* except those `describeColumnFilter` would count for this column — so a
|
|
3839
|
+
* column's list cascades from the other filters without its own pick
|
|
3840
|
+
* hiding the values the user unchecked. Values are told apart as an `in`
|
|
3841
|
+
* filter tells them apart — as grouping does, except that a date column's
|
|
3842
|
+
* date strings are the dates they name — ordered as the column sorts, and
|
|
3843
|
+
* labelled as its cells print, a boolean in `query.messages`' words; blanks
|
|
3844
|
+
* are counted apart, in `blanks`.
|
|
3845
|
+
*
|
|
3846
|
+
* Costs one pass over `rows` (tens of milliseconds at 100k rows), so compute
|
|
3847
|
+
* it when an editor opens rather than on every render, and hand the whole
|
|
3848
|
+
* list to `initialFilterEditorDraft`, whose search needs no recount.
|
|
3849
|
+
*/
|
|
3850
|
+
declare function columnValueOptions<Row>(rows: readonly Row[], dataColumns: readonly DataColumn<Row, unknown>[], filter: FilterState<Row>, columnId: string, query?: ColumnValueQuery): ColumnValueOptions;
|
|
3851
|
+
/**
|
|
3852
|
+
* A draft showing `shape` over `values` — what an editor opens with. A
|
|
3853
|
+
* column with no filter, or one only a custom editor could show, opens with
|
|
3854
|
+
* every value checked; a checklist with its own values checked, kept even
|
|
3855
|
+
* when the other filters now hide them; conditions as they are.
|
|
3856
|
+
*/
|
|
3857
|
+
declare function initialFilterEditorDraft<Row>(shape: ColumnFilterShape<Row>, values: ColumnValueOptions): FilterEditorDraft<Row>;
|
|
3858
|
+
/** The options the draft's search shows — those a select-all acts on. */
|
|
3859
|
+
declare function visibleFilterOptions<Row>(draft: FilterEditorDraft<Row>): readonly ColumnValueOption[];
|
|
3860
|
+
/**
|
|
3861
|
+
* The select-all checkbox's state: whether every value the search shows is
|
|
3862
|
+
* checked, none is, or some are — blanks included while nothing is
|
|
3863
|
+
* searched.
|
|
3864
|
+
*/
|
|
3865
|
+
declare function selectAllState<Row>(draft: FilterEditorDraft<Row>): SelectAllState;
|
|
3866
|
+
/**
|
|
3867
|
+
* The next draft after `action` — a plain reducer, so a renderer can hold
|
|
3868
|
+
* the draft in whatever state it has (`useReducer`, a signal, a store).
|
|
3869
|
+
* Changing a value or the blanks switches the draft to its checklist;
|
|
3870
|
+
* setting conditions switches it to them.
|
|
3871
|
+
*/
|
|
3872
|
+
declare function filterEditorReducer<Row>(draft: FilterEditorDraft<Row>, action: FilterEditorAction<Row>): FilterEditorDraft<Row>;
|
|
3873
|
+
/**
|
|
3874
|
+
* `current` with `columnId`'s filter replaced by what `draft` holds — what
|
|
3875
|
+
* applying an editor sets. Every entry about the column goes (custom ones
|
|
3876
|
+
* included); the draft's entries take the place of the first, so the rest
|
|
3877
|
+
* keep their order.
|
|
3878
|
+
*
|
|
3879
|
+
* A checklist with everything checked is no filter at all, and a partial
|
|
3880
|
+
* pick is one `in` entry, OR-grouped with an `isEmpty` when blanks are
|
|
3881
|
+
* kept. One condition is stored as itself, two as a group with the
|
|
3882
|
+
* draft's combinator. Returns `current` itself when nothing changes.
|
|
3883
|
+
*/
|
|
3884
|
+
declare function draftToFilter<Row>(draft: FilterEditorDraft<Row>, columnId: string, current: FilterState<Row>): FilterState<Row>;
|
|
3885
|
+
|
|
3886
|
+
/** What a column chooser is drawn from: every column, the visibility, and the search typed. */
|
|
3887
|
+
interface ColumnChooserInput<Row> {
|
|
3888
|
+
/** Every column in its current order, hidden ones included — a view's `dataColumns`. */
|
|
3889
|
+
readonly columns: readonly DataColumn<Row, unknown>[];
|
|
3890
|
+
readonly visibility: ColumnVisibilityState;
|
|
3891
|
+
/** Narrows the list to the columns whose header text contains it, ignoring case. */
|
|
3892
|
+
readonly search?: string | undefined;
|
|
3893
|
+
}
|
|
3894
|
+
/** One column's checkbox in a column chooser. */
|
|
3895
|
+
interface ColumnChooserEntry {
|
|
3896
|
+
readonly columnId: string;
|
|
3897
|
+
/** The column's header text — what the search matches, and the checkbox's label. */
|
|
3898
|
+
readonly label: string;
|
|
3899
|
+
/** Whether the column is shown — whether its checkbox is checked. */
|
|
3900
|
+
readonly visible: boolean;
|
|
3901
|
+
/**
|
|
3902
|
+
* Whether the checkbox cannot be unchecked: the column is shown and is
|
|
3903
|
+
* either not `hideable` or the last column shown. A hidden column can
|
|
3904
|
+
* always be shown, `hideable` or not.
|
|
3905
|
+
*/
|
|
3906
|
+
readonly disabled: boolean;
|
|
3907
|
+
}
|
|
3908
|
+
/** What toggling a chooser's "Show all" checkbox does: shows these columns, or hides them. */
|
|
3909
|
+
interface ColumnChooserToggle {
|
|
3910
|
+
readonly visible: boolean;
|
|
3911
|
+
readonly columnIds: readonly string[];
|
|
3912
|
+
}
|
|
3913
|
+
interface ColumnChooserModel {
|
|
3914
|
+
/** The columns the search matches, in column order. */
|
|
3915
|
+
readonly entries: readonly ColumnChooserEntry[];
|
|
3916
|
+
/**
|
|
3917
|
+
* The "Show all" checkbox's state over the entries whose columns are
|
|
3918
|
+
* `hideable` — the ones it acts on. A column the user cannot hide is
|
|
3919
|
+
* always on, so counting it would leave "Show all" stuck at mixed.
|
|
3920
|
+
*/
|
|
3921
|
+
readonly selectAll: SelectAllState;
|
|
3922
|
+
/** What toggling "Show all" does, or `null` when it can do nothing — a disabled checkbox. */
|
|
3923
|
+
readonly toggleAll: ColumnChooserToggle | null;
|
|
3924
|
+
}
|
|
3925
|
+
/**
|
|
3926
|
+
* A column chooser's list for a search, and what its "Show all" checkbox
|
|
3927
|
+
* says and does — the same tri-state over what the search shows that a
|
|
3928
|
+
* filter editor's select-all is (`selectAllState`).
|
|
3929
|
+
*
|
|
3930
|
+
* "Show all" shows every hidden column the search shows once any is hidden,
|
|
3931
|
+
* and hides those it shows once none is. It never touches a column that is
|
|
3932
|
+
* not `hideable`, and never hides the last column shown: when that is all
|
|
3933
|
+
* that would be left, the first of them in column order stays, since a grid
|
|
3934
|
+
* with no column shown has no header to bring one back from.
|
|
3935
|
+
*/
|
|
3936
|
+
declare function resolveColumnChooser<Row>({ columns, visibility, search, }: ColumnChooserInput<Row>): ColumnChooserModel;
|
|
3937
|
+
|
|
3938
|
+
/**
|
|
3939
|
+
* `resolveGridView`, memoised per stage: each stage remembers its last
|
|
3940
|
+
* inputs and returns its last output when none of them changed identity, so
|
|
3941
|
+
* a call that changes one slice of state recomputes only what depends on
|
|
3942
|
+
* it. The data stages (filter → sort → group → aggregate → paginate) read
|
|
3943
|
+
* `dataColumns`, which carry no width, so a resize or a viewport change
|
|
3944
|
+
* leaves `rows`, `displayRows`, `pageRows`, `displayDataRows` and
|
|
3945
|
+
* `grandTotal` reference-equal to the previous call's — only `columns` is
|
|
3946
|
+
* new. The view object itself is reused when every field is unchanged, so a
|
|
3947
|
+
* snapshot-based renderer sees nothing to re-render.
|
|
3948
|
+
*
|
|
3949
|
+
* Hold one resolver per grid and call it with the current input every time
|
|
3950
|
+
* the view is needed; the memo only pays off across calls to the same one.
|
|
3951
|
+
*/
|
|
3952
|
+
declare function createGridViewResolver<Row, Node = string>(): (input: GridViewInput<Row, Node>) => GridView<Row, Node>;
|
|
3953
|
+
/**
|
|
3954
|
+
* What the user is looking at, derived from the rows, the columns, the
|
|
3955
|
+
* grid's state and its options in one call: rows filtered → sorted →
|
|
3956
|
+
* grouped → aggregated → paginated, and columns ordered → hidden → sized.
|
|
3957
|
+
* The one function a renderer, an export or a toolbar calls instead of
|
|
3958
|
+
* composing the stages itself, so none of them can disagree about what is
|
|
3959
|
+
* shown.
|
|
3960
|
+
*
|
|
3961
|
+
* Unmemoised — a one-off resolver. A renderer that derives the view on every
|
|
3962
|
+
* change holds a `createGridViewResolver()` instead.
|
|
3963
|
+
*/
|
|
3964
|
+
declare function resolveGridView<Row, Node = string>(input: GridViewInput<Row, Node>): GridView<Row, Node>;
|
|
3965
|
+
|
|
3966
|
+
/**
|
|
3967
|
+
* `state` in a form that survives `JSON.stringify` and back unchanged, for
|
|
3968
|
+
* saving a layout — to local storage, a URL, a user's profile — and handing
|
|
3969
|
+
* it to `restoreState` later. Every slice is plain data already except the
|
|
3970
|
+
* filter: a `Date` value or operand is written as its ISO string, and a
|
|
3971
|
+
* predicate entry, being a function, cannot be written at all and is left
|
|
3972
|
+
* out with a `console.error` naming its column.
|
|
3973
|
+
*/
|
|
3974
|
+
declare function serializeGridState<Row>(state: GridState<Row>): SerializedGridState<Row>;
|
|
3975
|
+
|
|
3976
|
+
/**
|
|
3977
|
+
* One condition row of a simple filter editor as the user types it: text,
|
|
3978
|
+
* not yet a value, so a half-typed number or date stays in its input until
|
|
3979
|
+
* the editor is applied and `conditionsFromRows` reads it.
|
|
3980
|
+
*/
|
|
3981
|
+
interface ConditionRowDraft {
|
|
3982
|
+
readonly operator: FilterOperator;
|
|
3983
|
+
/** The operand as typed — `between`'s lower end. */
|
|
3984
|
+
readonly text: string;
|
|
3985
|
+
/**
|
|
3986
|
+
* `between`'s upper end, as typed. Kept under any other operator, unread,
|
|
3987
|
+
* so switching back to `between` finds it still there.
|
|
3988
|
+
*/
|
|
3989
|
+
readonly textTo: string;
|
|
3990
|
+
}
|
|
3991
|
+
/** What `conditionsFromRows` reads off an editor's rows. */
|
|
3992
|
+
interface ParsedConditionRows<Row> {
|
|
3993
|
+
/** A condition for each row that reads as one, in row order. */
|
|
3994
|
+
readonly conditions: readonly OperatorFilterEntry<Row>[];
|
|
3995
|
+
/**
|
|
3996
|
+
* The indexes of the rows that don't, for the editor to mark. Apply the
|
|
3997
|
+
* conditions only once this is empty.
|
|
3998
|
+
*/
|
|
3999
|
+
readonly invalid: readonly number[];
|
|
4000
|
+
}
|
|
4001
|
+
/**
|
|
4002
|
+
* The rows a simple editor opens with over a column's filter `shape`, its
|
|
4003
|
+
* operands written as the column's `type` reads them: two, holding the
|
|
4004
|
+
* column's conditions when its filter is conditions, and each row they
|
|
4005
|
+
* don't fill starting at the first of `operators`, empty. With no operator
|
|
4006
|
+
* to start one at, only the rows the filter fills.
|
|
4007
|
+
*/
|
|
4008
|
+
declare function conditionRowsFrom<Row>(shape: ColumnFilterShape<Row>, operators: readonly FilterOperator[], type: ColumnType | undefined): readonly ConditionRowDraft[];
|
|
4009
|
+
/**
|
|
4010
|
+
* The conditions a simple editor's rows stand for on `columnId`, each
|
|
4011
|
+
* operand read as the column's `type` filters (`parseFilterOperand`) — for
|
|
4012
|
+
* `filterEditorReducer`'s `setConditions`, with the combinator the editor
|
|
4013
|
+
* shows.
|
|
4014
|
+
*
|
|
4015
|
+
* A row needs every operand its operator takes, or it is `invalid`; the
|
|
4016
|
+
* blanks operators take none. A row after the first left empty is dropped
|
|
4017
|
+
* rather than invalid, since the second condition is optional; an empty
|
|
4018
|
+
* first row is invalid — clearing the filter is the editor's clear action,
|
|
4019
|
+
* not an apply with nothing typed.
|
|
4020
|
+
*/
|
|
4021
|
+
declare function conditionsFromRows<Row>(rows: readonly ConditionRowDraft[], columnId: string, type: ColumnType | undefined): ParsedConditionRows<Row>;
|
|
4022
|
+
|
|
4023
|
+
/**
|
|
4024
|
+
* What a cached list is labelled by: `columnValueOptions`' query without
|
|
4025
|
+
* `search` and `limit`, which a draft applies over the whole list.
|
|
4026
|
+
*/
|
|
4027
|
+
type ColumnValueCacheQuery = Pick<ColumnValueQuery, "locale" | "messages">;
|
|
4028
|
+
/** `columnValueOptions`, remembered per column. */
|
|
4029
|
+
interface ColumnValueOptionsCache<Row> {
|
|
4030
|
+
/**
|
|
4031
|
+
* `columnId`'s whole value list — `columnValueOptions` with no `search`
|
|
4032
|
+
* or `limit` — or the very list it returned last time, when nothing the
|
|
4033
|
+
* list is counted from or labelled by has changed since.
|
|
4034
|
+
*/
|
|
4035
|
+
readonly get: (rows: readonly Row[], dataColumns: readonly DataColumn<Row, unknown>[], filter: FilterState<Row>, columnId: string, query?: ColumnValueCacheQuery) => ColumnValueOptions;
|
|
4036
|
+
}
|
|
4037
|
+
/**
|
|
4038
|
+
* A memo of each column's checklist values, for a renderer to hold one of
|
|
4039
|
+
* per grid: reopening a column's checklist hands back the list it was given
|
|
4040
|
+
* last time — the same object — rather than counting `rows` again, until
|
|
4041
|
+
* something the list depends on changes.
|
|
4042
|
+
*
|
|
4043
|
+
* That is the `rows` and `dataColumns`, the `locale` and `messages` it is
|
|
4044
|
+
* labelled in, and the filter's entries not about the column — all compared
|
|
4045
|
+
* by identity, the entries one by one. Identity holds across an apply:
|
|
4046
|
+
* `draftToFilter` keeps every entry it doesn't replace as it was, so
|
|
4047
|
+
* filtering one column leaves the lists of the others to recount and its
|
|
4048
|
+
* own cached, since a column's list never depends on its own entries.
|
|
4049
|
+
*
|
|
4050
|
+
* Each column keeps its latest list. New rows, columns, locale or messages
|
|
4051
|
+
* drop every list, so the cache never holds on to rows the grid has let go
|
|
4052
|
+
* of — pass the grid's own, which keep their identity between renders.
|
|
4053
|
+
*/
|
|
4054
|
+
declare function createColumnValueOptionsCache<Row>(): ColumnValueOptionsCache<Row>;
|
|
4055
|
+
|
|
4056
|
+
/** One row of a checklist: a value the column holds, or its blank cells. */
|
|
4057
|
+
type FilterChecklistItem = {
|
|
4058
|
+
/**
|
|
4059
|
+
* Tells the item apart from every other in the list: a value's key is the
|
|
4060
|
+
* one `draft.checked` holds it under, and the blanks have their own.
|
|
4061
|
+
*/
|
|
4062
|
+
readonly key: string;
|
|
4063
|
+
/** The value as its cells print it, or the blanks' label. */
|
|
4064
|
+
readonly label: string;
|
|
4065
|
+
/** How many rows hold it, among those the other columns' filters keep. */
|
|
4066
|
+
readonly count: number;
|
|
4067
|
+
readonly checked: boolean;
|
|
4068
|
+
} & ({
|
|
4069
|
+
/** Toggled with `filterEditorReducer`'s `toggleValue`. */
|
|
4070
|
+
readonly kind: "value";
|
|
4071
|
+
readonly value: Exclude<FilterScalar, null>;
|
|
4072
|
+
} | {
|
|
4073
|
+
/** Toggled with `filterEditorReducer`'s `setIncludeBlanks`. */
|
|
4074
|
+
readonly kind: "blanks";
|
|
4075
|
+
});
|
|
4076
|
+
interface FilterChecklistOptions {
|
|
4077
|
+
/** How many values the list shows at most: the column's resolved `valueLimit`. */
|
|
4078
|
+
readonly valueLimit: number;
|
|
4079
|
+
/** The blanks item's label: the grid's `filterBlanks` message. */
|
|
4080
|
+
readonly blanksLabel: string;
|
|
4081
|
+
}
|
|
4082
|
+
/** What a checklist editor draws below its search box and select-all. */
|
|
4083
|
+
interface FilterChecklist {
|
|
4084
|
+
/**
|
|
4085
|
+
* The rows to draw, in order: the values the search shows, cut to
|
|
4086
|
+
* `valueLimit`, then the blanks while nothing is searched and some cells
|
|
4087
|
+
* are blank. Empty while `needsSearch`.
|
|
4088
|
+
*/
|
|
4089
|
+
readonly items: readonly FilterChecklistItem[];
|
|
4090
|
+
/**
|
|
4091
|
+
* Whether the list waits for a search: the column holds more values than
|
|
4092
|
+
* `valueLimit` and nothing is searched yet — `filterSearchFirst(total)`.
|
|
4093
|
+
*/
|
|
4094
|
+
readonly needsSearch: boolean;
|
|
4095
|
+
/**
|
|
4096
|
+
* How many of the values the search matches `valueLimit` left out of
|
|
4097
|
+
* `items` — `filterMoreValues(hiddenCount)`. `0` while `needsSearch`, so
|
|
4098
|
+
* the two notes never show together.
|
|
4099
|
+
*/
|
|
4100
|
+
readonly hiddenCount: number;
|
|
4101
|
+
/** How many values the search matches — every value while nothing is searched. Blanks aside. */
|
|
4102
|
+
readonly total: number;
|
|
4103
|
+
}
|
|
4104
|
+
/**
|
|
4105
|
+
* The list a checklist editor draws for `draft`: the window of values its
|
|
4106
|
+
* search shows, as items carrying what each row says and whether it is
|
|
4107
|
+
* checked.
|
|
4108
|
+
*
|
|
4109
|
+
* A column can hold far more values than a list is worth scrolling, so the
|
|
4110
|
+
* list shows at most `valueLimit` of them. Past that, it shows nothing until
|
|
4111
|
+
* something is searched (`needsSearch`) — every value is still in the draft,
|
|
4112
|
+
* and select-all still covers them all — and a search matching more shows
|
|
4113
|
+
* the first `valueLimit` of its matches in sort order, with the rest counted
|
|
4114
|
+
* in `hiddenCount`.
|
|
4115
|
+
*
|
|
4116
|
+
* The blanks item comes last, as in Excel's, and only while nothing is
|
|
4117
|
+
* searched: exactly when select-all counts the blanks, so the checkbox acts
|
|
4118
|
+
* on what the list shows.
|
|
4119
|
+
*/
|
|
4120
|
+
declare function filterChecklist<Row>(draft: FilterEditorDraft<Row>, { valueLimit, blanksLabel }: FilterChecklistOptions): FilterChecklist;
|
|
4121
|
+
|
|
4122
|
+
/**
|
|
4123
|
+
* One entry per row: its measured height once known, `undefined` until then.
|
|
4124
|
+
* A row never yet rendered (or rendered but not yet observed) falls back to
|
|
4125
|
+
* `visibleRange`'s own `estimatedHeight` argument.
|
|
4126
|
+
*/
|
|
4127
|
+
type RowHeights = readonly (number | undefined)[];
|
|
4128
|
+
interface VisibleRange {
|
|
4129
|
+
readonly startIndex: number;
|
|
4130
|
+
readonly endIndex: number;
|
|
4131
|
+
/** Total height of every row before `startIndex` — the leading spacer's height. */
|
|
4132
|
+
readonly offsetBefore: number;
|
|
4133
|
+
/** Total height of every row after `endIndex` — the trailing spacer's height. */
|
|
4134
|
+
readonly offsetAfter: number;
|
|
4135
|
+
}
|
|
4136
|
+
/**
|
|
4137
|
+
* Which rows of a dynamic-height, virtualized list fall within
|
|
4138
|
+
* `[scrollTop, scrollTop + viewportHeight)`, padded by `overscan` rows on
|
|
4139
|
+
* each side and clamped to the array's own bounds.
|
|
4140
|
+
*
|
|
4141
|
+
* Walks a cumulative-offset prefix sum built from `heights` (measured height
|
|
4142
|
+
* where known, `estimatedHeight` otherwise) rather than assuming a uniform
|
|
4143
|
+
* row height — this codebase's rows are not uniform (`.is-wrapped` cells,
|
|
4144
|
+
* group header/summary rows), so a fixed-height virtualizer would either
|
|
4145
|
+
* break wrapping or force it out of scope.
|
|
4146
|
+
*
|
|
4147
|
+
* `O(n)` in `heights.length`. Deliberately not a Fenwick tree or a
|
|
4148
|
+
* binary-searchable prefix-sum structure — that optimization belongs in the
|
|
4149
|
+
* mutable height cache that already owns mutability (`createRowVirtualizer`
|
|
4150
|
+
* in `@gridkitjs/dom`), not in this pure function's contract, and is not
|
|
4151
|
+
* worth taking on until a profiled scenario actually shows it matters at
|
|
4152
|
+
* realistic row counts.
|
|
4153
|
+
*/
|
|
4154
|
+
declare function visibleRange(heights: RowHeights, estimatedHeight: number, scrollTop: number, viewportHeight: number, overscan: number): VisibleRange;
|
|
4155
|
+
|
|
4156
|
+
/** How `toTsv` writes its text. */
|
|
4157
|
+
interface TsvOptions {
|
|
4158
|
+
/**
|
|
4159
|
+
* Which reading of each cell is written: `"text"` (the default), as the
|
|
4160
|
+
* grid shows it; or `"raw"`, the typed value written plainly.
|
|
4161
|
+
*/
|
|
4162
|
+
readonly values?: "text" | "raw" | undefined;
|
|
4163
|
+
}
|
|
4164
|
+
/**
|
|
4165
|
+
* The table as tab-separated text, records ending `"\n"` — the plain-text
|
|
4166
|
+
* form a spreadsheet splits into cells when it is pasted, which is what the
|
|
4167
|
+
* clipboard carries. TSV has no quoting a paste target agrees on, so a tab
|
|
4168
|
+
* or line break inside a cell becomes a space instead. Unlike `toCsv` it
|
|
4169
|
+
* writes no byte order mark and leaves formulas alone: what is copied is
|
|
4170
|
+
* exactly what the grid shows, and pasting it is the user's own act.
|
|
4171
|
+
*/
|
|
4172
|
+
declare function toTsv(table: ExportTable, options?: TsvOptions): string;
|
|
4173
|
+
|
|
4174
|
+
/** How `toHtmlTable` writes its markup. */
|
|
4175
|
+
interface HtmlTableOptions {
|
|
4176
|
+
/** Text for a `<caption>` above the table; none by default. */
|
|
4177
|
+
readonly caption?: string | undefined;
|
|
4178
|
+
}
|
|
4179
|
+
/**
|
|
4180
|
+
* The table as an HTML `<table>` string: a `<thead>` of column names when
|
|
4181
|
+
* the table has a header, every row in `<tbody>`, and the grand total in
|
|
4182
|
+
* `<tfoot>`. Every piece of text is escaped. It carries the semantic class
|
|
4183
|
+
* names a stylesheet targets — `gridkit-export-table` on the table,
|
|
4184
|
+
* `export-group` with a `data-level` on group headers,
|
|
4185
|
+
* `export-group-summary` on summary rows — and nothing else of style but
|
|
4186
|
+
* each column's alignment, so it reads the same pasted into a document as
|
|
4187
|
+
* it does printed.
|
|
4188
|
+
*/
|
|
4189
|
+
declare function toHtmlTable(table: ExportTable, options?: HtmlTableOptions): string;
|
|
4190
|
+
|
|
4191
|
+
/**
|
|
4192
|
+
* What `exportFile` exports from: an `ExportSource` whose messages are the
|
|
4193
|
+
* grid's whole set, since a writer may print any of them. A
|
|
4194
|
+
* `GridCommandContext` is one as it stands.
|
|
4195
|
+
*/
|
|
4196
|
+
interface ExportFileSource<Row> extends ExportSource<Row> {
|
|
4197
|
+
readonly messages: GridMessages;
|
|
4198
|
+
}
|
|
4199
|
+
/**
|
|
4200
|
+
* The grid's view exported as a file of `format`: the table `options`
|
|
4201
|
+
* narrow, written by that format's writer among `writers` (see
|
|
4202
|
+
* `resolveExportWriters`) — or by `format` itself, when it is a writer —
|
|
4203
|
+
* and named. A writer that returns a promise gives a promise of the file.
|
|
4204
|
+
*
|
|
4205
|
+
* A format no writer is registered for is reported and gives `null`, so a
|
|
4206
|
+
* renderer saves nothing rather than failing.
|
|
4207
|
+
*/
|
|
4208
|
+
declare function exportFile<Row>(source: ExportFileSource<Row>, format: string | ExportWriter, options: GridExportOptions, writers: ReadonlyMap<string, ExportWriter>): ExportFile | Promise<ExportFile> | null;
|
|
4209
|
+
|
|
4210
|
+
/**
|
|
4211
|
+
* Turns on the per-column filter popup in its Excel-style form — a search
|
|
4212
|
+
* box, a checklist of the column's values with their counts, and an operator
|
|
4213
|
+
* submenu — in one spread: `<DataGrid {...excelFilter} />`.
|
|
4214
|
+
*
|
|
4215
|
+
* A preset is a plain value of `GridOptions`, not a component or a hook, so
|
|
4216
|
+
* any renderer can take it the way it takes its other options (a Vue spread,
|
|
4217
|
+
* an Angular binding) and a later option overrides it: spreading it before
|
|
4218
|
+
* `filterMenu={{ ui: "simple" }}` brings the simple editor back. `filterMenu`
|
|
4219
|
+
* is replaced whole, not merged, so repeat `showCounts` if it should stay.
|
|
4220
|
+
*/
|
|
4221
|
+
declare const excelFilter: {
|
|
4222
|
+
readonly filterableColumns: true;
|
|
4223
|
+
readonly filterMenu: {
|
|
4224
|
+
readonly ui: "excel";
|
|
4225
|
+
readonly showCounts: true;
|
|
4226
|
+
};
|
|
4227
|
+
};
|
|
4228
|
+
|
|
4229
|
+
export { type AggregateFn, type AggregateResults, type AggregateSpec, type AggregateState, type Borders, type BuiltInAggregate, type BuiltInCommandIcon, type BuiltInCommandId, type CellSelectEvent, type CellSelectionChangeEvent, type CellSelectionMode, type CellSelectionState, type CellTemplateContext, type ColumnAlignment, type ColumnChooserEntry, type ColumnChooserInput, type ColumnChooserModel, type ColumnChooserToggle, type ColumnConstraints, type ColumnDefinition, type ColumnFilterMenuOptions, type ColumnFilterShape, type ColumnOrderEvent, type ColumnOrderState, type ColumnResizeEvent, type ColumnResizeSession, type ColumnResolveOptions, type ColumnSelectEvent, type ColumnSelectionChangeEvent, type ColumnSizeDefaults, type ColumnSizingState, type ColumnSortEntry, type ColumnSortEvent, type ColumnSortState, type ColumnType, type ColumnValueCacheQuery, type ColumnValueOption, type ColumnValueOptions, type ColumnValueOptionsCache, type ColumnValueQuery, type ColumnVisibilityEvent, type ColumnVisibilityState, type ColumnWrapConfig, type ColumnsSelectEvent, type ConditionRowDraft, type ContextMenuOpenChangeEvent, type CopyContent, type CopyRequest, type CopySource, type CsvOptions, DEFAULT_COLUMN_SIZES, DEFAULT_FILTER_VALUE_LIMIT, type DataColumn, type DisplayRow, type DropSide, type ExportCell, type ExportColumn, type ExportDataRow, type ExportFile, type ExportFileSource, type ExportGroupRow, type ExportGroupSummaryRow, type ExportOptions, type ExportRow, type ExportScalar, type ExportSource, type ExportTable, type ExportTotalRow, type ExportWriteContext, type ExportWriter, type FieldPath, type FilterChangeEvent, type FilterChecklist, type FilterChecklistItem, type FilterChecklistOptions, type FilterEditorAction, type FilterEditorDraft, type FilterEntry, type FilterMenuUi, type FilterOperator, type FilterOperatorFamily, type FilterPredicate, type FilterScalar, type FilterState, type FooterTemplateContext, type FormatLocale, type GridCommand, type GridCommandActions, type GridCommandContext, type GridCommandContextInput, type GridCommandEvent, type GridCommandHost, type GridCommandSource, type GridCommandTarget, type GridContextMenuArea, type GridContextMenuEntries, type GridContextMenuOptions, type GridContextMenuRequest, type GridContextMenuTarget, type GridController, type GridControllerOptions, type GridExportOptions, type GridFilterMenuOptions, type GridFocus, type GridMessages, type GridOptions, type GridPanelKind, type GridState, type GridToolbarOptions, type GridToolbarTarget, type GridView, type GridViewInput, type GridViewOptions, type GridViewState, type GroupAggregateDisplay, type GroupByBarVisibility, type GroupByEntry, type GroupByEvent, type GroupByState, type GroupExpansionEvent, type GroupExpansionState, type GroupFilterEntry, HEADER_ROW, type HoverableConfig, type HtmlTableOptions, type JsonOptions, KEYBOARD_STEP, type KeyShortcutCapabilities, type MenuEntry, type MenuItemEntry, type MenuMove, type MenuResolveOptions, type MenuSubmenuEntry, type NavigationModifiers, type OperatorFilterEntry, type PaginatedRows, type PaginationChangeEvent, type PaginationState, type PaginationWindowEntry, type ParsedConditionRows, type PredicateFilterEntry, type PrintDocument, type PrintOptions, type PrintOrientation, type PrintPage, type PrintSource, type ResizeMode, type ResolvedColumn, type ResolvedColumnFilterMenu, type ResolvedGroupRow, type ResolvedGroupSummaryRow, type ResolvedMenuEntry, type ResolvedMenuItem, type ResolvedMenuSeparator, type ResolvedMenuSubmenu, type ResolvedRow, type ResolvedToolbarButton, type ResolvedToolbarCustom, type ResolvedToolbarItem, type ResolvedToolbarMenu, type ResolvedToolbarSearch, type ResolvedToolbarSpacer, type RowHeights, type RowPointerEvent, type RowProps, type RowSelectEvent, type RowSelectionChangeEvent, type RowsSelectEvent, type SelectAllState, type SelectIntent, type SelectableConfig, type SelectedCell, type SelectedCellRef, type SelectedColumn, type SelectionCallbacks, type SelectionDiff, type SelectionDiffEvent, type SelectionMode, type SelectionState, type SerializedFilterEntry, type SerializedFilterScalar, type SerializedFilterState, type SerializedGridState, type SerializedGroupFilterEntry, type SerializedOperatorFilterEntry, type SerializedValueFilterEntry, type SortDirection, type TextFilterEntry, type ToolbarCustomEntry, type ToolbarEntry, type ToolbarFitInput, type ToolbarResolveOptions, type ToolbarSplit, type TsvOptions, type ValueFilterEntry, type VisibleRange, accessDotted, alignmentForType, applyColumnOrder, applyColumnResize, applyColumnVisibility, applySelectionIntent, beginColumnResize, buildExportTable, buildKeyShortcuts, buildPrintDocument, builtInCommands, clampColumnWidth, clampFocus, clearAllFilters, clearSelection, collapseAllGroups, columnValueOptions, compareValues, computeAggregates, conditionRowsFrom, conditionsFromRows, contextMenuEntries, copyContent, createColumnValueOptionsCache, createCommandContext, createDefaultMessages, createGridController, createGridViewResolver, csvWriter, defaultContextMenu, defaultFilterOperators, defaultMessages, defaultToolbar, defineColumnsFromRows, describeColumnFilter, diffSelection, draftToFilter, excelFilter, expandAllGroups, exportFile, exportPrintDocument, filterChecklist, filterEditorReducer, filterOperandArity, filterOperatorFamily, filterQueryFor, filterRows, fitColumnsToWidth, fitToolbarItems, formatAggregateValue, formatCellValue, formatFilterOperand, formatGroupValue, getColumnId, groupRowId, groupRows, hasContextMenu, initialFilterEditorDraft, intentOf, isColumnFiltered, isColumnVisible, isPinnedToolbarItem, isSameCell, jsonWriter, matchesQuery, moveColumnBefore, moveGroupByBefore, movesColumn, movesGroupBy, nextFocusForKey, nextMenuIndex, paginateRows, paginationWindow, parseFilterOperand, resolveCell, resolveColumnChooser, resolveColumnConstraints, resolveColumnFilterMenu, resolveColumnHeaderText, resolveColumnLabel, resolveColumnWidths, resolveColumns, resolveCommands, resolveDataColumns, resolveDropBefore, resolveExportWriters, resolveGridView, resolveKeyboardDropTarget, resolveMenu, resolveMessages, resolveRowId, resolveRows, resolveShownRows, resolveToolbar, revertColumnSize, runCommand, searchTextOf, selectAll, selectAllState, selectCell, selectOnly, selectRange, serializeGridState, setColumnFilter, setColumnVisibility, setSearchText, sizeColumnToContent, sortDirectionFor, sortPriorityFor, sortRows, splitToolbarItems, toCsv, toHtmlTable, toJson, toTsv, toggleCellSelection, toggleColumnSort, toggleGroupExpansion, toggleSelection, toolbarEntries, totalColumnWidth, typeaheadIndex, visibleFilterOptions, visibleRange, withGroupAggregates };
|