@kanunilabs/datagrid 1.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE +55 -0
- package/README.md +243 -0
- package/dist/datagrid.umd.js +13 -0
- package/dist/index.cjs +2 -0
- package/dist/index.d.cts +501 -0
- package/dist/index.d.ts +501 -0
- package/dist/index.js +2 -0
- package/dist/styles.css +3526 -0
- package/package.json +77 -0
package/dist/index.d.ts
ADDED
|
@@ -0,0 +1,501 @@
|
|
|
1
|
+
import { GridRowData, DataGridController, GridDictionary, RowNode, GridColumnDef, DataGridCoreConfig, GridTheme, GridPalette, GridDensity, DescribeFilterOptions, RowKey, StateStoringConfig } from '@kanunilabs/datagrid-core';
|
|
2
|
+
export { DENSITY_ROW_HEIGHT, DataGridController, GridColumnDef, GridDensity, GridRowData, GridTheme, RowKey, RowNode, SortDescriptor, THEME_ROW_HEIGHT, presetRowHeight } from '@kanunilabs/datagrid-core';
|
|
3
|
+
|
|
4
|
+
/** What a header menu is opened against — the React shape, verbatim. */
|
|
5
|
+
interface HeaderMenuContext {
|
|
6
|
+
columnId: string;
|
|
7
|
+
/** Header text as rendered, for labels and announcements. */
|
|
8
|
+
headerName: string;
|
|
9
|
+
}
|
|
10
|
+
interface HeaderMenuDeps<TRow = GridRowData> {
|
|
11
|
+
controller: DataGridController<TRow>;
|
|
12
|
+
t: GridDictionary;
|
|
13
|
+
/** Current UI switches the menu toggles operate on. */
|
|
14
|
+
groupPanelVisible: boolean;
|
|
15
|
+
footerVisible: boolean;
|
|
16
|
+
onToggleGroupPanel: () => void;
|
|
17
|
+
onToggleFooter: () => void;
|
|
18
|
+
onOpenFieldChooser: () => void;
|
|
19
|
+
onBestFit: (columnId: string) => void;
|
|
20
|
+
onBestFitAll: () => void;
|
|
21
|
+
/** Grouping levels allowed — 1 in Community, the React rule. */
|
|
22
|
+
maxGroupLevels: number;
|
|
23
|
+
}
|
|
24
|
+
declare function buildHeaderMenu<TRow = GridRowData>(context: HeaderMenuContext, deps: HeaderMenuDeps<TRow>): GridMenuItem<HeaderMenuContext>[];
|
|
25
|
+
|
|
26
|
+
/** Same value as the React renderer's lead column. */
|
|
27
|
+
declare const ROW_NUMBER_COLUMN_WIDTH = 60;
|
|
28
|
+
/** Same value as the React renderer's CHECKBOX_COLUMN_WIDTH. */
|
|
29
|
+
declare const CHECKBOX_COLUMN_WIDTH = 36;
|
|
30
|
+
/** Same value as the React renderer's master-detail expander column. */
|
|
31
|
+
declare const DETAIL_COLUMN_WIDTH = 28;
|
|
32
|
+
/** MIME type carrying a dragged row. The SAME string the React renderer uses,
|
|
33
|
+
* so a row can cross between a React grid and a vanilla grid on one page. */
|
|
34
|
+
declare const ROW_DRAG_MIME = "application/x-kanuni-row";
|
|
35
|
+
/** What travels in `dataTransfer` when a row leaves its grid. */
|
|
36
|
+
interface RowDragPayload {
|
|
37
|
+
/** Grid the row started in — a same-grid drop is a REORDER, not a move. */
|
|
38
|
+
gridId: string;
|
|
39
|
+
/** Only grids sharing a group exchange rows. */
|
|
40
|
+
group: string | null;
|
|
41
|
+
rowKey: RowKey;
|
|
42
|
+
/** The row itself, so the receiving grid can insert it without a round trip. */
|
|
43
|
+
row: unknown;
|
|
44
|
+
}
|
|
45
|
+
interface RowReorderEvent<TRow = GridRowData> {
|
|
46
|
+
dragKey: RowKey;
|
|
47
|
+
/** Row it was dropped onto, or null for the empty space past the last row. */
|
|
48
|
+
targetKey: RowKey | null;
|
|
49
|
+
position: 'before' | 'after';
|
|
50
|
+
row: TRow | undefined;
|
|
51
|
+
}
|
|
52
|
+
interface RowDropEvent<TRow = GridRowData> {
|
|
53
|
+
/** Row that crossed over, as the source grid had it. */
|
|
54
|
+
row: TRow;
|
|
55
|
+
rowKey: RowKey;
|
|
56
|
+
/** Grid it came from / went to. */
|
|
57
|
+
otherGridId: string;
|
|
58
|
+
targetKey: RowKey | null;
|
|
59
|
+
position: 'before' | 'after';
|
|
60
|
+
}
|
|
61
|
+
/** The React `rowDrag` prop's shape, DOM-flavoured. */
|
|
62
|
+
interface RowDragConfig<TRow = GridRowData> {
|
|
63
|
+
enabled?: boolean;
|
|
64
|
+
/** Grids sharing a group can exchange rows. */
|
|
65
|
+
group?: string;
|
|
66
|
+
/** Reordering within this grid. Default true. */
|
|
67
|
+
allowReordering?: boolean;
|
|
68
|
+
/** Accept rows from another grid in the group. Default true when `group` is set. */
|
|
69
|
+
allowDropInsert?: boolean;
|
|
70
|
+
/** A row was moved within this grid. Without a handler the grid reorders its
|
|
71
|
+
* own source array; with one, YOU own the order. */
|
|
72
|
+
onReorder?: (event: RowReorderEvent<TRow>) => void;
|
|
73
|
+
/** A row arrived from another grid. */
|
|
74
|
+
onAdd?: (event: RowDropEvent<TRow>) => void;
|
|
75
|
+
}
|
|
76
|
+
/** Default row cap. Report-sized results print; result sets do not. */
|
|
77
|
+
declare const PRINT_MAX_ROWS = 5000;
|
|
78
|
+
interface PrintLayoutOptions {
|
|
79
|
+
/** Stay in print layout permanently — for a grid rendered INTO a report page. */
|
|
80
|
+
always?: boolean;
|
|
81
|
+
/** Above this many rows the grid does NOT switch (default 5.000): print
|
|
82
|
+
* layout puts every row in the DOM, and past report sizes that is a frozen
|
|
83
|
+
* tab behind a dialog the user cannot cancel. Use exportPdf() there. */
|
|
84
|
+
maxRows?: number;
|
|
85
|
+
}
|
|
86
|
+
/** What a row template is handed — the React `RowTemplateContext`. */
|
|
87
|
+
interface RowTemplateContext<TRow> {
|
|
88
|
+
row: TRow;
|
|
89
|
+
node: RowNode<TRow>;
|
|
90
|
+
/** Position in the current view, not in the source array. */
|
|
91
|
+
rowIndex: number;
|
|
92
|
+
selected: boolean;
|
|
93
|
+
/** True when this is the focused row (`focusedRow` is on). */
|
|
94
|
+
focused: boolean;
|
|
95
|
+
}
|
|
96
|
+
/** The React `GridMenuItem`, DOM-flavoured: `icon` is a string or a Node. */
|
|
97
|
+
interface GridMenuItem<TContext = unknown> {
|
|
98
|
+
/** Stable key; falls back to the index when omitted. */
|
|
99
|
+
id?: string;
|
|
100
|
+
label?: string;
|
|
101
|
+
icon?: string | Node;
|
|
102
|
+
/** Right-aligned hint, e.g. "Ctrl+C". Purely visual — no binding is created. */
|
|
103
|
+
shortcut?: string;
|
|
104
|
+
disabled?: boolean;
|
|
105
|
+
/** Renders a divider instead of an item. */
|
|
106
|
+
separator?: boolean;
|
|
107
|
+
/** One level of nesting. */
|
|
108
|
+
items?: GridMenuItem<TContext>[];
|
|
109
|
+
onSelect?: (context: TContext) => void;
|
|
110
|
+
}
|
|
111
|
+
/** What a row menu is opened against — the React shape, verbatim. */
|
|
112
|
+
interface RowMenuContext<TRow = GridRowData> {
|
|
113
|
+
row: TRow;
|
|
114
|
+
node: RowNode<TRow>;
|
|
115
|
+
/** Index in the current view. */
|
|
116
|
+
rowIndex: number;
|
|
117
|
+
/** Column under the pointer, when the menu was opened from a cell. */
|
|
118
|
+
columnId: string | null;
|
|
119
|
+
/** Selected row keys at the moment the menu opened. */
|
|
120
|
+
selectedKeys: RowKey[];
|
|
121
|
+
}
|
|
122
|
+
/**
|
|
123
|
+
* What the Enterprise cell slots are handed — the React `CellSlotContext`,
|
|
124
|
+
* verbatim. `rowIndex`/`columnIndex` are VIEW coordinates (a range is a
|
|
125
|
+
* rectangle over what the user sees).
|
|
126
|
+
*/
|
|
127
|
+
interface CellSlotContext<TRow = GridRowData> {
|
|
128
|
+
node: RowNode<TRow>;
|
|
129
|
+
columnId: string;
|
|
130
|
+
rowIndex: number;
|
|
131
|
+
columnIndex: number;
|
|
132
|
+
value: unknown;
|
|
133
|
+
}
|
|
134
|
+
/** Which cell a note belongs to — the React `NoteCellContext`, verbatim. */
|
|
135
|
+
interface NoteCellContext<TRow = GridRowData> {
|
|
136
|
+
rowKey: RowKey;
|
|
137
|
+
columnId: string;
|
|
138
|
+
row: TRow;
|
|
139
|
+
}
|
|
140
|
+
/**
|
|
141
|
+
* Cell notes (P3.3) — the React `GridNotesConfig`, verbatim. The grid SHOWS
|
|
142
|
+
* notes (marker + tooltip) and, with `onChange`, collects edits; it does not
|
|
143
|
+
* decide where they live, because a note that survives a reload has to go
|
|
144
|
+
* somewhere only the app knows about.
|
|
145
|
+
*/
|
|
146
|
+
interface GridNotesConfig<TRow = GridRowData> {
|
|
147
|
+
/** This cell's note, or null. Called for every RENDERED cell — make it a lookup. */
|
|
148
|
+
get: (ctx: NoteCellContext<TRow>) => string | null | undefined;
|
|
149
|
+
/** The user changed a note; `text` is null when they cleared it. Its PRESENCE makes notes editable. */
|
|
150
|
+
onChange?: (ctx: NoteCellContext<TRow> & {
|
|
151
|
+
text: string | null;
|
|
152
|
+
}) => void;
|
|
153
|
+
/** Append add/edit/delete items to the row context menu. Default true when `onChange` is given. */
|
|
154
|
+
menu?: boolean;
|
|
155
|
+
}
|
|
156
|
+
/** What a custom cell renderer is handed — the React `CellRenderContext`, DOM-flavoured. */
|
|
157
|
+
interface CellRenderContext<TRow = GridRowData> {
|
|
158
|
+
value: unknown;
|
|
159
|
+
row: TRow;
|
|
160
|
+
node: RowNode<TRow>;
|
|
161
|
+
column: GridColumnDef<TRow>;
|
|
162
|
+
}
|
|
163
|
+
/**
|
|
164
|
+
* Column definition, plus the vanilla escape hatch.
|
|
165
|
+
*
|
|
166
|
+
* `renderCell` returns a string (set as textContent — safe by construction, no
|
|
167
|
+
* HTML parsing) or a Node (adopted as the cell's content). This is the honest
|
|
168
|
+
* translation of React's ReactNode contract: there is no vanilla equivalent of
|
|
169
|
+
* an element tree, and pretending otherwise would mean shipping an HTML-string
|
|
170
|
+
* API and its injection surface.
|
|
171
|
+
*/
|
|
172
|
+
type VanillaColumnDef<TRow = GridRowData> = GridColumnDef<TRow> & {
|
|
173
|
+
renderCell?: (ctx: CellRenderContext<TRow>) => string | Node;
|
|
174
|
+
/** Replace the header cell's LABEL — the React `renderHeader`, DOM-typed.
|
|
175
|
+
* Sorting, funnel, reorder and resize chrome behave as the def's own flags
|
|
176
|
+
* say; a chrome column (the command column) turns them all off itself. */
|
|
177
|
+
renderHeader?: (ctx: {
|
|
178
|
+
column: VanillaColumnDef<TRow>;
|
|
179
|
+
}) => string | Node;
|
|
180
|
+
/**
|
|
181
|
+
* Tooltip for this column's cells — the React column extension, DOM-typed.
|
|
182
|
+
* A string is static; a function runs only for the cell under the pointer,
|
|
183
|
+
* so it may be as expensive as it needs to be. Return null to suppress the
|
|
184
|
+
* tooltip INCLUDING the truncation fallback.
|
|
185
|
+
*/
|
|
186
|
+
tooltip?: string | ((ctx: CellRenderContext<TRow>) => string | null | undefined);
|
|
187
|
+
/** Read the tooltip from another field of the row. `tooltip` wins. */
|
|
188
|
+
tooltipField?: string;
|
|
189
|
+
/**
|
|
190
|
+
* Let this column's text WRAP, and let the row grow to fit it. Only
|
|
191
|
+
* RENDERED rows can be measured, so the scrollbar firms up as the user
|
|
192
|
+
* travels — every virtualized grid that measures has this property.
|
|
193
|
+
*/
|
|
194
|
+
autoHeight?: boolean;
|
|
195
|
+
};
|
|
196
|
+
interface CreateGridConfig<TRow = GridRowData> extends Omit<DataGridCoreConfig<TRow>, 'columns'> {
|
|
197
|
+
columns: VanillaColumnDef<TRow>[];
|
|
198
|
+
theme?: GridTheme;
|
|
199
|
+
palette?: GridPalette;
|
|
200
|
+
density?: GridDensity;
|
|
201
|
+
dark?: boolean;
|
|
202
|
+
/** Zebra rows. Default TRUE — the React renderer's default. */
|
|
203
|
+
striped?: boolean;
|
|
204
|
+
/** Leading 1-based row-number column. Adapter chrome; core never sees it. */
|
|
205
|
+
rowNumbers?: boolean;
|
|
206
|
+
/** Text of the empty-state overlay. Defaults to the locale dictionary. */
|
|
207
|
+
emptyText?: string;
|
|
208
|
+
/** Label of the busy overlay. Defaults to the locale dictionary. */
|
|
209
|
+
loadingText?: string;
|
|
210
|
+
/**
|
|
211
|
+
* The busy overlay. `true` (default) shows it after 300 ms of continuous
|
|
212
|
+
* FOREGROUND work; a number sets that delay; `false` turns it off entirely.
|
|
213
|
+
*
|
|
214
|
+
* The delay is not decoration. Every filter keystroke re-runs the pipeline,
|
|
215
|
+
* and a pass that finishes in 20 ms would raise and drop the overlay faster
|
|
216
|
+
* than anyone can read it — a strobe. Background passes (a streamed
|
|
217
|
+
* transaction batch, a block fetch caused by scrolling) never raise it at
|
|
218
|
+
* all: the user did not ask for them and is not waiting on them.
|
|
219
|
+
*
|
|
220
|
+
* `controller.showLoadingOverlay()` is an explicit decision rather than a
|
|
221
|
+
* flicker to absorb, so it appears at once, delay skipped.
|
|
222
|
+
*/
|
|
223
|
+
loadingOverlay?: boolean | number;
|
|
224
|
+
/** Dictionary locale (core's twelve). Default 'en'. */
|
|
225
|
+
locale?: string;
|
|
226
|
+
/** Totals row pinned to the bottom edge. Values come from `summaries`. */
|
|
227
|
+
footer?: boolean;
|
|
228
|
+
/**
|
|
229
|
+
* Wording for the filter panel's sentence — operator captions, the list
|
|
230
|
+
* separator, and `maxListValues` (how long an `in` list gets before it
|
|
231
|
+
* collapses to "N values").
|
|
232
|
+
*
|
|
233
|
+
* Defaults come from the grid's LOCALE; what you pass overrides key by key,
|
|
234
|
+
* so an app can rename one operator without restating the other thirteen.
|
|
235
|
+
*/
|
|
236
|
+
filterPanelLabels?: DescribeFilterOptions;
|
|
237
|
+
/**
|
|
238
|
+
* Replace each DATA row's content. Group headers and detail panels keep
|
|
239
|
+
* their own rendering — a template that had to handle those too would be a
|
|
240
|
+
* template of the whole grid.
|
|
241
|
+
*
|
|
242
|
+
* The row ELEMENT stays: it carries the height, the aria indices, the zebra
|
|
243
|
+
* and selection classes and the handlers the virtualizer depends on. What
|
|
244
|
+
* the template replaces are the CELLS — including the lead ones, so the row
|
|
245
|
+
* number, the detail expander and the selection checkbox are not drawn while
|
|
246
|
+
* it is on, and in-cell editing and range selection have nothing to attach
|
|
247
|
+
* to. (The drag grip survives: it is not a cell.) React draws exactly the
|
|
248
|
+
* same line.
|
|
249
|
+
*
|
|
250
|
+
* For per-cell customization that keeps the column layout, use a column's
|
|
251
|
+
* `renderCell`.
|
|
252
|
+
*
|
|
253
|
+
* Returning the SAME node you returned last time is how a template says
|
|
254
|
+
* "nothing changed" — the DOM is then left alone, so a focused input inside
|
|
255
|
+
* it keeps its caret.
|
|
256
|
+
*/
|
|
257
|
+
renderRow?: (context: RowTemplateContext<TRow>) => string | Node | null | undefined;
|
|
258
|
+
/**
|
|
259
|
+
* A polite live region reporting row count, sort and selection to screen
|
|
260
|
+
* readers. Default true.
|
|
261
|
+
*
|
|
262
|
+
* Sorting and filtering are otherwise visual-only events: the rows change
|
|
263
|
+
* under a screen-reader user with nothing said. The text is built from the
|
|
264
|
+
* resolved dictionary, so it is announced in the grid's language.
|
|
265
|
+
*/
|
|
266
|
+
announcements?: boolean;
|
|
267
|
+
/**
|
|
268
|
+
* Clicking a footer cell opens the aggregation picker — No total / Count /
|
|
269
|
+
* Sum / Average / Min / Max, filtered to what the column's data type
|
|
270
|
+
* supports, so a text column is never offered a Sum (`Number()` over names
|
|
271
|
+
* totals 0, and a 0 in a footer is indistinguishable from a real zero).
|
|
272
|
+
* Default true; `false` makes the footer read-only.
|
|
273
|
+
*
|
|
274
|
+
* With it on, a cell holding no total shows a faint dot — otherwise the
|
|
275
|
+
* only affordance is an empty rectangle nobody thinks to click.
|
|
276
|
+
*/
|
|
277
|
+
footerMenu?: boolean;
|
|
278
|
+
/** Rows fixed above the scrolling body. Adapter chrome, like React's. */
|
|
279
|
+
pinnedTopRows?: readonly TRow[];
|
|
280
|
+
/** Rows fixed below the scrolling body. */
|
|
281
|
+
pinnedBottomRows?: readonly TRow[];
|
|
282
|
+
/** Drag the trailing edge of a header to resize. Default true. */
|
|
283
|
+
resizable?: boolean;
|
|
284
|
+
/** Drag a header onto another to reorder. Default true. */
|
|
285
|
+
reorderable?: boolean;
|
|
286
|
+
/** Per-column text inputs under the header. */
|
|
287
|
+
filterRow?: boolean;
|
|
288
|
+
/** ms before typed filter text reaches the engine. Same default as React:
|
|
289
|
+
* 0 for local data (the pipeline is the debounce), 200 for remote. */
|
|
290
|
+
filterDebounce?: number;
|
|
291
|
+
/** Funnel buttons opening the distinct-value checkbox popup. */
|
|
292
|
+
headerFilter?: boolean;
|
|
293
|
+
/**
|
|
294
|
+
* When the header's funnel icon is visible: `'hover'` (default) reveals it
|
|
295
|
+
* on hover or keyboard focus, `'always'` pins it. An ACTIVE filter stays
|
|
296
|
+
* visible in both modes — it is the only sign that rows are being withheld.
|
|
297
|
+
*/
|
|
298
|
+
filterIconMode?: 'hover' | 'always';
|
|
299
|
+
/** The active filter, in words, with one-click clear. */
|
|
300
|
+
/**
|
|
301
|
+
* The strip under the grid that says, in words, what is being filtered —
|
|
302
|
+
* with an × to drop it and a checkbox to suspend it without losing it.
|
|
303
|
+
*
|
|
304
|
+
* `'always'` keeps the strip on screen with no filter applied, so the
|
|
305
|
+
* control does not appear and disappear under the pointer.
|
|
306
|
+
*/
|
|
307
|
+
filterPanel?: boolean | 'always';
|
|
308
|
+
/**
|
|
309
|
+
* Opens the app's filter builder from the panel's chevron. Without it the
|
|
310
|
+
* chevron is not drawn, because a control that opens nothing is worse than
|
|
311
|
+
* no control — React's rule, and the Enterprise wrapper wires it to its own
|
|
312
|
+
* builder.
|
|
313
|
+
*/
|
|
314
|
+
onOpenFilterBuilder?: () => void;
|
|
315
|
+
/** Highlight the row that holds focus. Default false — the React default. */
|
|
316
|
+
focusedRow?: boolean;
|
|
317
|
+
/**
|
|
318
|
+
* Focus this row when the grid is built — the React `focusedRowKey` prop.
|
|
319
|
+
*
|
|
320
|
+
* React re-applies it whenever the prop changes; a vanilla config is read
|
|
321
|
+
* once, so this is the STARTING focus and later moves go through
|
|
322
|
+
* `grid.controller.focusRow(key)`. Said plainly because a silently
|
|
323
|
+
* one-shot prop is exactly the kind of thing that costs an afternoon.
|
|
324
|
+
*/
|
|
325
|
+
focusedRowKey?: RowKey | null;
|
|
326
|
+
/** Fired when the focused ROW changes — not on every cell move within it. */
|
|
327
|
+
onFocusedRowChanged?: (event: {
|
|
328
|
+
rowKey: RowKey | null;
|
|
329
|
+
row?: TRow;
|
|
330
|
+
}) => void;
|
|
331
|
+
/** Fired on a click anywhere in a row, before the grid's own row event. */
|
|
332
|
+
onRowClick?: (node: RowNode<TRow>) => void;
|
|
333
|
+
/** Fired on Enter / double-click over the focused row. */
|
|
334
|
+
onRowActivate?: (node: RowNode<TRow>) => void;
|
|
335
|
+
/**
|
|
336
|
+
* Where the totals row sits: `'bottom'` (default) or `'top'`, directly
|
|
337
|
+
* under the header — the React `footerPosition` prop. Enterprise, like the
|
|
338
|
+
* totals themselves.
|
|
339
|
+
*/
|
|
340
|
+
footerPosition?: 'top' | 'bottom';
|
|
341
|
+
/**
|
|
342
|
+
* Cell notes (P3.3): a marker on noted cells, the note as the hover
|
|
343
|
+
* tooltip, and — with `onChange` — add/edit/delete on the row menu with an
|
|
344
|
+
* anchored textarea. Enterprise: ignored (reported under `debugMode`)
|
|
345
|
+
* without `enterpriseEdition`, the React rule.
|
|
346
|
+
*/
|
|
347
|
+
notes?: GridNotesConfig<TRow>;
|
|
348
|
+
/**
|
|
349
|
+
* Wrap search matches in `<mark>` inside the cell. Default true — the React
|
|
350
|
+
* `highlightSearch` prop. Applied to the FINISHED text (after the lookup,
|
|
351
|
+
* the formatter and the date format), because that is what the reader
|
|
352
|
+
* searched.
|
|
353
|
+
*/
|
|
354
|
+
highlightSearch?: boolean;
|
|
355
|
+
/**
|
|
356
|
+
* Sorting for the whole grid. Default true; `false` turns every header into
|
|
357
|
+
* a plain label. A column can still opt out on its own with
|
|
358
|
+
* `sortable: false` on its definition — the React prop of the same name.
|
|
359
|
+
*/
|
|
360
|
+
sortable?: boolean;
|
|
361
|
+
/**
|
|
362
|
+
* Column widths on startup. `'none'` (default) keeps the declared widths.
|
|
363
|
+
*
|
|
364
|
+
* `'fitGrid'` divides the grid's width among the columns and RE-RUNS on every
|
|
365
|
+
* grid resize, taking the current widths as its proportions — so a column the
|
|
366
|
+
* user dragged wider stays proportionally wider.
|
|
367
|
+
*
|
|
368
|
+
* `'fitCells'` measures what the first rows actually rendered and runs ONCE:
|
|
369
|
+
* before the first paint there is nothing to measure. It can overflow the
|
|
370
|
+
* grid; that is the point of asking for content-width columns.
|
|
371
|
+
*/
|
|
372
|
+
autoSizeStrategy?: 'none' | 'fitGrid' | 'fitCells';
|
|
373
|
+
/**
|
|
374
|
+
* @deprecated Retired 2026-08-15 and inert in BOTH renderers; accepted so
|
|
375
|
+
* existing call sites keep working.
|
|
376
|
+
*
|
|
377
|
+
* It rendered a strip under the grid whose only content was the row count.
|
|
378
|
+
* The per-column totals it once carried moved into the footer ROW, where
|
|
379
|
+
* each number sits under its own column — leaving a whole bar to say one
|
|
380
|
+
* number, printed a second time whenever the Enterprise status bar was on.
|
|
381
|
+
*
|
|
382
|
+
* The count lives in the **status bar** (Enterprise: total, filtered,
|
|
383
|
+
* selected) or in the **pager**, which shows the total when pagination is on.
|
|
384
|
+
*
|
|
385
|
+
* Unlike React, this renderer says so once in the console when you set it —
|
|
386
|
+
* a vanilla caller has no editor surfacing the `@deprecated` tag.
|
|
387
|
+
*/
|
|
388
|
+
showRowCount?: boolean;
|
|
389
|
+
/** Quick-search + CSV export bar above the grid. */
|
|
390
|
+
toolbar?: boolean;
|
|
391
|
+
/** "Columns" button in the toolbar opening the visibility chooser. */
|
|
392
|
+
toolbarColumnChooser?: boolean;
|
|
393
|
+
/**
|
|
394
|
+
* Extra toolbar buttons, appended after the grid's own — the React
|
|
395
|
+
* `toolbarItemsAfter` prop, DOM-flavoured. Ignored without `toolbar`.
|
|
396
|
+
*/
|
|
397
|
+
toolbarItemsAfter?: HTMLElement[];
|
|
398
|
+
/** Extra toolbar buttons, BEFORE the grid's own — React's `toolbarItemsBefore`. */
|
|
399
|
+
toolbarItemsBefore?: HTMLElement[];
|
|
400
|
+
/**
|
|
401
|
+
* Excel entries (all rows / selected rows) on the toolbar's export menu.
|
|
402
|
+
* Enterprise: shown only under `enterpriseEdition`, hidden rather than
|
|
403
|
+
* shown-and-failing — the controller would throw, and a menu entry whose
|
|
404
|
+
* only outcome is an error is worse than no entry (the React rule).
|
|
405
|
+
*/
|
|
406
|
+
toolbarExcel?: boolean;
|
|
407
|
+
/** PDF entry on the export menu — Enterprise, same gate as `toolbarExcel`. */
|
|
408
|
+
toolbarPdf?: boolean;
|
|
409
|
+
/** Right-click menu with Copy / Copy with headers. Default true. */
|
|
410
|
+
cellMenu?: boolean;
|
|
411
|
+
/**
|
|
412
|
+
* App-defined right-click menu for data rows — the React `rowMenu` prop,
|
|
413
|
+
* DOM-flavoured. A function receives the row that was clicked so the items
|
|
414
|
+
* can depend on it. The grid's own entries (Copy…) append BELOW after a
|
|
415
|
+
* separator, so an app's menu keeps the order it wrote.
|
|
416
|
+
*/
|
|
417
|
+
rowMenu?: GridMenuItem<RowMenuContext<TRow>>[] | ((context: RowMenuContext<TRow>) => GridMenuItem<RowMenuContext<TRow>>[]);
|
|
418
|
+
/**
|
|
419
|
+
* Right-click menu on column headers — the React `headerMenu` prop,
|
|
420
|
+
* DOM-flavoured. `true`/omitted shows the default items (sort, group,
|
|
421
|
+
* pin, hide, best fit…); `false` turns it off; a function receives the
|
|
422
|
+
* context and the defaults and returns the finished list, so an app can
|
|
423
|
+
* reorder, drop or append without rebuilding what the grid provides.
|
|
424
|
+
*/
|
|
425
|
+
headerMenu?: boolean | ((context: HeaderMenuContext, defaults: GridMenuItem<HeaderMenuContext>[]) => GridMenuItem<HeaderMenuContext>[]);
|
|
426
|
+
/**
|
|
427
|
+
* Drag rows to reorder them, and — with a shared `group` — between two
|
|
428
|
+
* grids. A grip appears at the start of each row on hover. Reordering the
|
|
429
|
+
* grid's own array only works on an UNSORTED view (the React caveat).
|
|
430
|
+
*/
|
|
431
|
+
rowDrag?: RowDragConfig<TRow>;
|
|
432
|
+
/**
|
|
433
|
+
* Grids naming the same group keep their column layout and horizontal
|
|
434
|
+
* scroll in step — a scrolling body with a totals strip below it. Sort,
|
|
435
|
+
* filter, selection and vertical scroll deliberately do NOT travel.
|
|
436
|
+
* (Aligns with other VANILLA grids; the React registry is separate.)
|
|
437
|
+
*/
|
|
438
|
+
alignedGrids?: string;
|
|
439
|
+
/**
|
|
440
|
+
* Render EVERY row while the browser prints, so the print engine paginates
|
|
441
|
+
* real content instead of one clipped screenful. `true` = only while the
|
|
442
|
+
* print dialog is open; an options object can pin it `always` (report
|
|
443
|
+
* pages) or move the `maxRows` refusal point.
|
|
444
|
+
*/
|
|
445
|
+
printLayout?: boolean | PrintLayoutOptions;
|
|
446
|
+
/** Persist and restore the view (sort, filters, widths…). Core's service. */
|
|
447
|
+
stateStoring?: StateStoringConfig;
|
|
448
|
+
/** Hover tooltips. `false` disables, a number overrides the 400ms delay. */
|
|
449
|
+
tooltip?: boolean | {
|
|
450
|
+
delay?: number;
|
|
451
|
+
};
|
|
452
|
+
/** Drop strip above the grid: drag a header here to group by it. Reads
|
|
453
|
+
* `grouping.panel` exactly like the React prop shape. */
|
|
454
|
+
/** Search box debounce, ms. React's default. */
|
|
455
|
+
searchDebounce?: number;
|
|
456
|
+
/** Replace a body cell's content. `undefined` = the default painter runs. */
|
|
457
|
+
renderCellContent?: (ctx: CellSlotContext<TRow>) => Node | string | undefined;
|
|
458
|
+
/**
|
|
459
|
+
* Panel body for a master-detail row. With the engine's `masterDetail`
|
|
460
|
+
* config present, supplying this turns the leading expander column on —
|
|
461
|
+
* the React `renderDetail` prop, DOM-typed.
|
|
462
|
+
*/
|
|
463
|
+
renderDetail?: (row: TRow) => Node | string;
|
|
464
|
+
/**
|
|
465
|
+
* Body for an in-grid edit form row (`mode: 'form'`). `row` is undefined
|
|
466
|
+
* for a record that does not exist yet — the form still opens, because the
|
|
467
|
+
* alternative is pressing "New row" and seeing nothing happen.
|
|
468
|
+
*/
|
|
469
|
+
renderEditForm?: (rowKey: RowKey, row: TRow | undefined) => Node | string;
|
|
470
|
+
/**
|
|
471
|
+
* The edition flag, set by the Enterprise wrapper — the React prop of the
|
|
472
|
+
* same name. It gates what the CONTROLLER agrees to do (styled exports,
|
|
473
|
+
* master-detail…); without it the `masterDetail` config is stripped, the
|
|
474
|
+
* way the React Community renderer strips it.
|
|
475
|
+
*/
|
|
476
|
+
enterpriseEdition?: boolean;
|
|
477
|
+
/** Extra classes for a body cell (pending edit, range, fill preview…). */
|
|
478
|
+
getCellClassName?: (ctx: CellSlotContext<TRow>) => string | undefined;
|
|
479
|
+
onCellPointerDown?: (ctx: CellSlotContext<TRow>, event: MouseEvent) => void;
|
|
480
|
+
onCellPointerEnter?: (ctx: CellSlotContext<TRow>, event: MouseEvent) => void;
|
|
481
|
+
onCellDoubleClick?: (ctx: CellSlotContext<TRow>) => void;
|
|
482
|
+
}
|
|
483
|
+
interface GridApi<TRow = GridRowData> {
|
|
484
|
+
/** The engine, whole. The same object React hands to `onReady`. */
|
|
485
|
+
controller: DataGridController<TRow>;
|
|
486
|
+
/** The `.kanuni-datagrid-root` element this grid built. */
|
|
487
|
+
element: HTMLElement;
|
|
488
|
+
setData(rows: TRow[]): void;
|
|
489
|
+
setColumns(columns: VanillaColumnDef<TRow>[]): void;
|
|
490
|
+
destroy(): void;
|
|
491
|
+
}
|
|
492
|
+
declare function createGrid<TRow = GridRowData>(container: HTMLElement, config: CreateGridConfig<TRow>): GridApi<TRow>;
|
|
493
|
+
|
|
494
|
+
/**
|
|
495
|
+
* Width that fits the header and every rendered cell of `columnId`.
|
|
496
|
+
* Returns null when nothing could be measured (no such column on screen, or no
|
|
497
|
+
* canvas — jsdom, SSR), so the caller can leave the width alone.
|
|
498
|
+
*/
|
|
499
|
+
declare function measureBestFitWidth(root: HTMLElement, columnId: string): number | null;
|
|
500
|
+
|
|
501
|
+
export { CHECKBOX_COLUMN_WIDTH, type CellRenderContext, type CellSlotContext, type CreateGridConfig, DETAIL_COLUMN_WIDTH, type GridApi, type GridMenuItem, type GridNotesConfig, type HeaderMenuContext, type HeaderMenuDeps, type NoteCellContext, PRINT_MAX_ROWS, type PrintLayoutOptions, ROW_DRAG_MIME, ROW_NUMBER_COLUMN_WIDTH, type RowDragConfig, type RowDragPayload, type RowDropEvent, type RowMenuContext, type RowReorderEvent, type VanillaColumnDef, buildHeaderMenu, createGrid, measureBestFitWidth };
|