@kanunilabs/datagrid-react 1.8.8 → 1.8.10

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/dist/index.d.cts CHANGED
@@ -1,7 +1,7 @@
1
1
  import * as react from 'react';
2
- import { ReactNode, RefObject } from 'react';
3
- import { GridRowData, DataGridController, GridDataType, RowKey, LookupItem, GridDictionary, StateStoringConfig, RowNode, GridColumnDef, DataGridCoreConfig, FilterRenderContextBase, FilterNode, InferColumnsOptions, GridThemeName, GridPaletteName, DescribeFilterOptions, GridDensity, ToolbarOptions, PortalContainer, CardViewOptions, EditMode, RowChange, RowStatusSource, ColumnRuntime, ColumnLayout, SortDescriptor, ColumnModel, RowSaveStatus, DataRowNode, ColSpanPlan, SummaryDef, RemoteDistinctList, PortalKind, ToolbarSearchOptions, ToolbarIconName, ColumnState, BusyPhase, VirtualWindow, ChartBoxSpec, ChartBoxModel, ChartSpec, ChartModel, ChartXYSpec, ChartXYModel, CellRange, RangeSelectionEngine, ColumnSelectMode, EditingEngine, ValidationRule, CrudHandlers, EditingPermissions, NewRowPosition, RowEditSession, LookupMatchMode } from '@kanunilabs/datagrid-core';
4
- export { BusyChangedEvent, BusyPhase, ClientRowModel, ColumnLayout, ColumnLookup, ColumnModel, ColumnPin, ColumnRuntime, ColumnState, ColumnStateChangedEvent, ContentReadyEvent, CustomFilterOperator, CustomFilterOperatorId, DEFAULT_ROW_HEIGHT, DENSITY_ROW_HEIGHT, DataGridController, DataGridCoreConfig, DataRowNode, DataSource, FilterChangedEvent, FilterCondition, FilterGroupNode, FilterNode, FilterOperator, FocusedRowChangedEvent, GRID_COLOR_SCHEMES, GRID_PALETTES, GRID_THEMES, GridColorScheme, GridColumnDef, GridDataType, GridDensity, GridEventMap, GridPalette, GridPaletteName, GridRowData, GridStateStore, GridTheme, GridThemeName, GridViewState, GroupRowNode, GroupingConfig, HeaderBandCell, InferColumnsOptions, LoadOptions, LoadResult, LookupItem, NewRowPosition, PortalContainer, RowDropPosition, RowKey, RowNode, SUMMARY_TYPE_LABEL, ScrollingConfig, SelectionDescriptor, SortChangedEvent, SortDescriptor, SortDirection, StateStoringConfig, SummaryDef, SummaryType, THEME_ROW_HEIGHT, ToolbarOptions, ToolbarSearchOptions, ViewportChangedEvent, VirtualWindow, VirtualWindowEngine, allowedSummaryTypes, andFilters, attachStateStoring, bandDepth, bandPath, computeColumnLayout, computeHeaderBands, createRestDataSource, describeFilter, downloadBlob, fillText, filterInputFromNode, formatSummaryValue, humanizeField, importCsv, inferColumns, isDataRow, isDataSource, isFilterGroup, isGroupRow, isPackagedTheme, lookupLabel, moveRowInArray, parseCsv, parseFilterInput, sniffDelimiter, summaryKey, summaryLabel, summaryTypeLabels, themeClassName } from '@kanunilabs/datagrid-core';
2
+ import { RefObject, ReactNode, FocusEvent, MouseEvent } from 'react';
3
+ import { GridRowData, DataGridController, GridDataType, RowKey, LookupItem, GridDictionary, StateStoringConfig, RowNode, DataRowNode, CardField, RowSaveStatus, GridColumnDef, DataGridCoreConfig, FilterRenderContextBase, FilterNode, InferColumnsOptions, GridThemeName, GridPaletteName, DescribeFilterOptions, GridDensity, ToolbarOptions, PortalContainer, CardViewOptions, EditMode, RowChange, RowStatusSource, ColumnRuntime, ColumnLayout, SortDescriptor, ColumnLookup, ColumnModel, ColSpanPlan, SummaryDef, RemoteDistinctList, PortalKind, ToolbarSearchOptions, ToolbarIconName, ColumnState, BusyPhase, VirtualWindow, ChartBoxSpec, ChartBoxModel, ChartSpec, ChartModel, ChartXYSpec, ChartXYModel, CellRange, RangeSelectionEngine, ColumnSelectMode, EditingEngine, EditingApi, NewRowPosition, ValidationRule, CrudHandlers, EditingPermissions, CommitOn, RowEditSession, ColumnNumberFormat, LookupMatchMode, LookupMatchFold } from '@kanunilabs/datagrid-core';
4
+ export { BusyChangedEvent, BusyPhase, ChangesChangedEvent, ClientRowModel, ColumnLayout, ColumnLookup, ColumnModel, ColumnPin, ColumnRuntime, ColumnState, ColumnStateChangedEvent, CommitOn, ContentReadyEvent, CustomFilterOperator, CustomFilterOperatorId, DEFAULT_ROW_HEIGHT, DENSITY_ROW_HEIGHT, DataGridController, DataGridCoreConfig, DataRowNode, DataSource, EditingApi, FilterChangedEvent, FilterCondition, FilterGroupNode, FilterNode, FilterOperator, FocusedRowChangedEvent, GRID_COLOR_SCHEMES, GRID_PALETTES, GRID_THEMES, GridColorScheme, GridColumnDef, GridDataType, GridDensity, GridEventMap, GridPalette, GridPaletteName, GridRowData, GridStateStore, GridTheme, GridThemeName, GridViewState, GroupRowNode, GroupingConfig, HeaderBandCell, InferColumnsOptions, LoadOptions, LoadResult, LookupItem, NewRowPosition, PortalContainer, RowDropPosition, RowKey, RowNode, SUMMARY_TYPE_LABEL, SaveRejected, SaveRowError, ScrollingConfig, SelectionDescriptor, SortChangedEvent, SortDescriptor, SortDirection, StateStoringConfig, SummaryDef, SummaryType, THEME_ROW_HEIGHT, ToolbarOptions, ToolbarSearchOptions, ViewportChangedEvent, VirtualWindow, VirtualWindowEngine, allowedSummaryTypes, andFilters, attachStateStoring, bandDepth, bandPath, computeColumnLayout, computeHeaderBands, createRestDataSource, describeFilter, downloadBlob, fillText, filterInputFromNode, formatSummaryValue, humanizeField, importCsv, inferColumns, isDataRow, isDataSource, isFilterGroup, isGroupRow, isPackagedTheme, isSaveRejected, lookupLabel, moveRowInArray, parseCsv, parseFilterInput, sniffDelimiter, summaryKey, summaryLabel, summaryTypeLabels, themeClassName } from '@kanunilabs/datagrid-core';
5
5
 
6
6
  /** Formats an export menu can offer. */
7
7
  type ExportKind = 'csv' | 'excel' | 'excel-selected' | 'pdf';
@@ -82,6 +82,11 @@ interface GridEditFormProps<TRow = GridRowData> {
82
82
  onNaturalHeight?: (px: number) => void;
83
83
  labels?: Partial<EditFormLabels>;
84
84
  onChange: (columnId: string, value: unknown) => void;
85
+ /**
86
+ * Several fields of the open row in one step — a custom editor's
87
+ * `ctx.api.setRowValues` (P-4.3). Absent: it answers false.
88
+ */
89
+ setRowValues?: (values: Readonly<Record<string, unknown>>) => boolean;
85
90
  onSave: () => void;
86
91
  onCancel: () => void;
87
92
  }
@@ -98,7 +103,141 @@ interface EditFormLabels {
98
103
  declare function editFormLabels(t: GridDictionary): EditFormLabels;
99
104
  /** English, kept as the constant this package already exported. */
100
105
  declare const DEFAULT_EDIT_FORM_LABELS: EditFormLabels;
101
- declare function GridEditForm<TRow = GridRowData>({ rowKey, fields, getValue, errors, lookups, customEditors, row, saving, saveError, isNew, dark, popup, inline, onNaturalHeight, labels: labelOverrides, onChange, onSave, onCancel, }: GridEditFormProps<TRow>): react.JSX.Element;
106
+ declare function GridEditForm<TRow = GridRowData>({ rowKey, fields, getValue, errors, lookups, customEditors, row, saving, saveError, isNew, dark, popup, inline, onNaturalHeight, labels: labelOverrides, onChange, setRowValues, onSave, onCancel, }: GridEditFormProps<TRow>): react.JSX.Element;
107
+
108
+ /**
109
+ * Which gestures open a cell's editor (P-7.1). Every field defaults to
110
+ * today's behaviour: `f2: true, enter: false, typing: true, doubleClick: true`.
111
+ */
112
+ interface EditKeys {
113
+ /**
114
+ * F2 opens the focused cell's editor. Default true. `false`: the grid does
115
+ * not handle F2 at all and does not `preventDefault()` it — the key reaches
116
+ * the page (an app whose F2 means Save).
117
+ */
118
+ f2?: boolean;
119
+ /**
120
+ * Enter opens the focused cell's editor, and Enter (or Shift+Enter) in an
121
+ * open editor commits and STAYS on the cell instead of moving down. Enter
122
+ * never adds a row. On a cell that cannot be edited Enter stays
123
+ * `onRowActivate`. Default false: Enter is `onRowActivate`, and in an open
124
+ * editor commits and moves down.
125
+ */
126
+ enter?: boolean;
127
+ /**
128
+ * Typing a printable character on a focused cell opens its editor with that
129
+ * character. Default true. Same as `editOnKeyPress`; this one wins when both
130
+ * are given.
131
+ */
132
+ typing?: boolean;
133
+ /**
134
+ * Space on a focused lookup cell opens its editor (and, with
135
+ * `lookup.openOnEdit`, its list) instead of doing nothing; the space is not
136
+ * typed into the box. While an editor is open Space types a space as usual.
137
+ * Default false (P-11).
138
+ */
139
+ space?: boolean;
140
+ /**
141
+ * A double-click (a double-tap on a touch screen) opens the cell's editor.
142
+ * Default true.
143
+ */
144
+ doubleClick?: boolean;
145
+ }
146
+ /** The cell the key is about: the open editor's, else the focused one. */
147
+ interface GridKeyCell {
148
+ rowKey: RowKey;
149
+ columnId: string;
150
+ }
151
+ /**
152
+ * What the app's `onKeyDown` hook is told about the grid (P-7.2).
153
+ */
154
+ interface GridKeyContext {
155
+ /** A cell editor (or, in a row mode, a row) is open. */
156
+ editing: boolean;
157
+ /** The open editor's cell, else the focused cell; null when neither. */
158
+ cell: GridKeyCell | null;
159
+ /** `cell`'s row was added and is not saved yet. */
160
+ isNewRow: boolean;
161
+ /**
162
+ * Commit the open cell editor — the value being typed becomes the cell's
163
+ * (pending) value. True when nothing was open or the value was taken; false
164
+ * when a rule refused it (the editor stays open) or a whole row is open in a
165
+ * row mode (save that with `api.saveChanges()`).
166
+ */
167
+ commit(): boolean;
168
+ /** Close the open editor without keeping its value. */
169
+ cancel(): void;
170
+ }
171
+ /**
172
+ * `onKeyDown` on the grid: called for EVERY key pressed inside the grid, in the
173
+ * capture phase at the grid's root — before the grid's own handling and before
174
+ * an open editor sees the key. Return `'handled'` and the grid does nothing with
175
+ * that key (the browser's own default is not prevented; call
176
+ * `event.preventDefault()` for that).
177
+ */
178
+ type GridKeyHook = (event: KeyboardEvent, ctx: GridKeyContext) => 'handled' | void;
179
+ type AnyKeyEvent = KeyboardEvent | {
180
+ nativeEvent: KeyboardEvent;
181
+ };
182
+ /** Remember that the app's hook took this key; every grid handler then skips it. */
183
+ declare function markKeyHandledByApp(event: AnyKeyEvent): void;
184
+ /**
185
+ * A character typed with AltGr (Alt+Ctrl on Windows). It is typing, not an Alt
186
+ * shortcut: it opens the editor like any other character.
187
+ */
188
+ declare function isAltGraphChar(event: AnyKeyEvent): boolean;
189
+ /**
190
+ * True when the grid must leave this key alone: the page already claimed it
191
+ * (`defaultPrevented`, read from the NATIVE event — React's copy is fixed when
192
+ * the event is created, and a capture listener on `window` runs first), the
193
+ * app's `onKeyDown` answered 'handled', or it is an Alt combination other than
194
+ * AltGr typing.
195
+ */
196
+ declare function gridIgnoresKey(event: AnyKeyEvent): boolean;
197
+ /**
198
+ * The page or the app's hook already took this key: an editor leaves it
199
+ * alone (no commit, no move, no `stopPropagation`).
200
+ */
201
+ declare function keyClaimed(event: AnyKeyEvent): boolean;
202
+ /**
203
+ * True when an open editor uses this key, so it must not reach the grid's (or
204
+ * the page's) shortcuts. F1-F12 and Ctrl/Cmd/Alt combinations a text box has no
205
+ * use for are NOT the editor's: they go on to the page (P-7.2), which is how an
206
+ * app's F2 "Save" or Ctrl+P still works while a cell is being typed in. Keys the
207
+ * page or the app's hook already took are not the editor's either.
208
+ */
209
+ declare function editorOwnsKey(event: AnyKeyEvent): boolean;
210
+ /**
211
+ * Elements that are part of an open editor (P-4). The grid puts it on the box
212
+ * it draws a column's `renderEditor` in; an app may put it on an editor's own
213
+ * popup or dialog. Focus moving into one is not "leaving the cell" (the P-10
214
+ * row send, `ctx.commitOnBlur`). Inside the grid, keys whose target is in one
215
+ * are the EDITOR's: the grid's own key handling (navigation, F2, Escape,
216
+ * typing-to-edit) leaves them alone; the app's `onKeyDown` hook still sees
217
+ * them. A key whose target is OUTSIDE the grid's DOM — an app dialog portaled
218
+ * to `<body>`, marked or not — is never the grid's (`eventFromOwnDom`).
219
+ */
220
+ declare const EDITOR_OWNED_SELECTOR = "[data-kanuni-editor]";
221
+ /** The grid's own popups (lookup list, calendar, menus, dialogs). */
222
+ declare const GRID_PORTAL_SELECTOR = ".kanuni-datagrid-portal, [data-kanuni-portal]";
223
+ /**
224
+ * Did this event start inside `currentTarget`'s DOM? React routes events from a
225
+ * portal through the COMPONENT tree: a dialog an app's custom editor opens
226
+ * (portaled to `<body>`) still bubbles through the cell, the row, the
227
+ * scroller and the grid root (P-4.7). Every grid handler asks this first and
228
+ * ignores events from outside its own subtree. `ownPortals`: also count the
229
+ * grid's own popups (they are portaled too, and are the grid's).
230
+ */
231
+ declare function eventFromOwnDom(event: {
232
+ currentTarget: EventTarget | null;
233
+ target: EventTarget | null;
234
+ }, ownPortals?: boolean): boolean;
235
+ /**
236
+ * Where focus may go and still be "in" the grid: the grid itself, one of its
237
+ * detached popups (date calendar, lookup list, dialogs) or an element the app
238
+ * marks as belonging to the open editor.
239
+ */
240
+ declare function focusStaysWithGrid(gridSelector: string, next: Element | null): boolean;
102
241
 
103
242
  declare function useStateStoring<TRow = GridRowData>(controller: DataGridController<TRow>, config: StateStoringConfig | undefined): void;
104
243
 
@@ -129,6 +268,13 @@ interface PrintLayoutOptions {
129
268
  rows: number;
130
269
  maxRows: number;
131
270
  }) => void;
271
+ /**
272
+ * Print the column headers (band rows, header, filter row) at the top of
273
+ * EVERY page, not only the first (default true; Tekax P-15). A row is never
274
+ * split across two pages, whichever way this is set. The summary row prints
275
+ * once, after the last row.
276
+ */
277
+ repeatHeader?: boolean;
132
278
  }
133
279
  /** Default row cap. Report-sized results print; result sets do not. */
134
280
  declare const PRINT_MAX_ROWS = 5000;
@@ -148,7 +294,9 @@ interface PrintLayoutState {
148
294
  * — an ordinary `setState` would land after that and print the old, clipped
149
295
  * view. This is the case the API exists for.
150
296
  */
151
- declare function usePrintLayout<TRow = GridRowData>(controller: DataGridController<TRow>, options: boolean | PrintLayoutOptions | undefined): PrintLayoutState;
297
+ declare function usePrintLayout<TRow = GridRowData>(controller: DataGridController<TRow>, options: boolean | PrintLayoutOptions | undefined,
298
+ /** The grid's root element, for the repeating header's printable copy. */
299
+ rootRef?: RefObject<HTMLElement | null>): PrintLayoutState;
152
300
 
153
301
  /** MIME type carrying the payload. Custom so nothing else claims it. */
154
302
  declare const ROW_DRAG_MIME = "application/x-kanuni-row";
@@ -237,10 +385,70 @@ interface CellRenderContext<TRow = GridRowData> {
237
385
  interface HeaderRenderContext<TRow = GridRowData> {
238
386
  column: GridColumnDef<TRow>;
239
387
  }
388
+ /**
389
+ * Where focus goes after a custom editor commits (P-4.2):
390
+ * `'down'` — the cell below (what Enter does in the built-in editor);
391
+ * `'next'` / `'previous'` — the next / previous editable cell (Tab /
392
+ * Shift+Tab, wrapping to the next row like the built-in editor);
393
+ * `'none'` — stay on the cell (today's `commit()`).
394
+ * An explicit `move` wins over `editing.editKeys.enter`.
395
+ */
396
+ type EditorCommitMove = 'down' | 'next' | 'previous' | 'none';
397
+ interface EditorCommitOptions {
398
+ /** Default `'none'`. */
399
+ move?: EditorCommitMove;
400
+ }
401
+ /** Writes a custom editor may make to ITS row (P-4.3). */
402
+ interface EditorRowApi {
403
+ /**
404
+ * Write several fields of the editor's row in ONE step — a picker writing
405
+ * code, name and id together: one undo step, one validation pass, one save
406
+ * in `cell` mode, pending in `batch`. All or nothing: `editable: false`
407
+ * columns ARE written (that flag only stops the user typing), a row lock
408
+ * (`allowUpdating` refusing the row/column) or a failing rule writes none
409
+ * and answers false. The editor stays open; if its own column is among the
410
+ * fields it shows the new value. Same as `EditingApi.setRowValues(rowKey, …)`.
411
+ */
412
+ setRowValues(values: Readonly<Record<string, unknown>>): boolean;
413
+ }
240
414
  /**
241
415
  * What a custom editor is handed. `commit`/`cancel` are the SAME handles the
242
416
  * built-in editor uses, so a replacement participates in Tab-walking, batch
243
417
  * changes and undo rather than living beside them.
418
+ *
419
+ * **The custom editor contract (P-4)** — what the grid does around a
420
+ * `renderEditor`:
421
+ *
422
+ * - The editor is drawn inside a box the grid owns, marked
423
+ * `data-kanuni-editor` (`display: contents`, so it does not change the
424
+ * layout). Keys whose target is inside it are the editor's: the grid does
425
+ * not navigate, open, or type-to-edit on them. Two exceptions, both only
426
+ * when the editor's own handler did not call `event.preventDefault()`:
427
+ * **Escape** cancels the editor (`cancel()`), and **Tab / Shift+Tab** walk
428
+ * the focusable elements INSIDE the box (text box → "…" button) and only
429
+ * past the last (first) one commit and move to the next (previous) cell —
430
+ * `commit({ move: 'next' })`. Enter is left to the editor: call
431
+ * `commit({ move: 'down' })` from it for the built-in behaviour. The
432
+ * editor's own shortcuts (F4, Alt+ArrowDown for its "…" button) are never
433
+ * taken by the grid.
434
+ * - Events from OUTSIDE the grid's DOM — a dialog the editor opens in a
435
+ * portal (Radix `Dialog`, a `<dialog>` under `<body>`) — never reach the
436
+ * grid's handlers, although React routes them through the editor's
437
+ * component tree: Enter, arrows, PageUp/PageDown, Space, Escape, Tab, F2,
438
+ * Insert, Ctrl+Delete, Ctrl+Z, clicks and double-clicks in that dialog
439
+ * change nothing in the grid or the editor session — also when the dialog
440
+ * holds another KanuniLabs grid. Escape in the dialog closes the dialog (its
441
+ * own business); a second Escape, back in the editor, cancels the editor.
442
+ * - Blur: the grid does not commit a custom editor on blur by itself. Put
443
+ * `onBlur={ctx.commitOnBlur}` on the editor's root element to commit when
444
+ * focus leaves it the way the built-in editors do. While a dialog of the
445
+ * editor is open call `suspendBlurCommit(true)` (before it takes focus) and
446
+ * `suspendBlurCommit(false)` when it closes: in between, neither
447
+ * `commitOnBlur` nor `commitOn: 'row'`'s "focus left the grid" send runs.
448
+ * - Focus: after `commit()` / `cancel()` focus goes to the grid's scroller
449
+ * (the keyboard keeps working); after `suspendBlurCommit(false)` focus that
450
+ * fell to `<body>` (the dialog's opener is gone) goes back to the editor, or
451
+ * to the scroller when the editor has closed.
244
452
  */
245
453
  interface EditorRenderContext<TRow = GridRowData> {
246
454
  /** Current (uncommitted) editor value. */
@@ -248,11 +456,45 @@ interface EditorRenderContext<TRow = GridRowData> {
248
456
  /** The row with pending edits applied — what a cascading list should read. */
249
457
  row: TRow;
250
458
  columnId: string;
459
+ /** Key of the edited row. */
460
+ rowKey: RowKey;
251
461
  /** Validation message for `value`, or null. */
252
462
  error: string | null;
463
+ /** True while `error` is set — for `aria-invalid`. */
464
+ invalid: boolean;
465
+ /**
466
+ * Id of an element holding `error` while there is one (screen-reader text
467
+ * the grid draws next to the editor) — for `aria-errormessage` /
468
+ * `aria-describedby`. Draw the message visibly yourself. Undefined when
469
+ * there is no error.
470
+ */
471
+ errorId: string | undefined;
472
+ /** The column's header text — for the editor's `aria-label`. */
473
+ ariaLabel: string;
253
474
  setValue: (value: unknown) => void;
254
- commit: () => void;
475
+ /**
476
+ * Commit the value. False when a rule refused it (the editor stays open).
477
+ * Without options it stays on the cell, as always.
478
+ */
479
+ commit: (options?: EditorCommitOptions) => boolean;
255
480
  cancel: () => void;
481
+ /**
482
+ * While on, losing focus is not leaving the editor: `commitOnBlur` and the
483
+ * `commitOn: 'row'` send on "focus left the grid" wait. Turn it on before a
484
+ * dialog of the editor takes focus, off when the dialog closes. Ends by
485
+ * itself when the editor closes. No-op in the row form.
486
+ */
487
+ suspendBlurCommit: (on: boolean) => void;
488
+ /**
489
+ * A `focusout` handler for the editor's root element: commits (staying on
490
+ * the cell, focus left where the user put it) once focus has gone somewhere
491
+ * that is not part of the editor — not inside its box, not one of the
492
+ * grid's popups, not an element marked `data-kanuni-editor` — unless
493
+ * `suspendBlurCommit(true)` is on. Optional to use.
494
+ */
495
+ commitOnBlur: (event: FocusEvent) => void;
496
+ /** Writes to this row (`setRowValues`). */
497
+ api: EditorRowApi;
256
498
  }
257
499
  /**
258
500
  * What a column's own filter UI is handed (`renderFilter`). `value` is the
@@ -479,6 +721,61 @@ interface RowTemplateContext<TRow = GridRowData> {
479
721
  /** True when this is the focused row (`focusedRow` is on). */
480
722
  focused: boolean;
481
723
  }
724
+ /** What `cardView.renderCard` draws one card from (P-9). */
725
+ interface CardRenderContext<TRow = GridRowData> {
726
+ /** The row as the user sees it — pending (unsaved) values included. */
727
+ row: TRow;
728
+ node: DataRowNode<TRow>;
729
+ /**
730
+ * The default card's fields, in order (the first is the title): each
731
+ * column's header and the TEXT its closed cell shows — formatter, number
732
+ * format and lookup label included (a function list's label too; empty
733
+ * while that list is still loading).
734
+ */
735
+ fields: CardField[];
736
+ selected: boolean;
737
+ /** The row's save status (`rowStatus`), or null. The grid draws its marker either way. */
738
+ status: RowSaveStatus | null;
739
+ }
740
+ /**
741
+ * `cardView` options of the React grids (P-9): the shared ones
742
+ * ({@link CardViewOptions}: `breakpoint`, `columns`) plus the card as a tap
743
+ * target.
744
+ */
745
+ interface DataGridCardViewOptions<TRow = GridRowData> extends CardViewOptions {
746
+ /**
747
+ * A card was pressed — tapped, or clicked with a mouse. A touch that moves
748
+ * more than 10 px (a scroll, a swipe) is not a press. Called after the grid
749
+ * has made the row the focused one (so `onFocusedRowChanged` has already
750
+ * fired for it) and before `edit: 'popup'` opens it. `event.preventDefault()`
751
+ * keeps the popup closed.
752
+ */
753
+ onCardPress?: (rowKey: RowKey, node: DataRowNode<TRow>, event: MouseEvent<HTMLElement>) => void;
754
+ /**
755
+ * Draw a card's content yourself. The grid keeps the card's box — its
756
+ * height, the press, selection, the `rowStatus` marker and `rowClassName`
757
+ * on the row element — and puts what this returns inside it. Cards are
758
+ * virtualised like rows, so every card is `height` pixels tall: give
759
+ * `height` when your card is not the default card's height.
760
+ */
761
+ renderCard?: (ctx: CardRenderContext<TRow>) => ReactNode;
762
+ /**
763
+ * Height of every card in pixels. Default: the default card's height for
764
+ * its field count (title 22 px, 20 px a line, 21 px of padding; at least 44
765
+ * — a touch target).
766
+ */
767
+ height?: number;
768
+ /**
769
+ * `'popup'`: pressing a card on an editing grid opens its row in the edit
770
+ * dialog (the `editing.mode: 'popup'` form), whatever `editing.mode` is.
771
+ * Save follows the mode: `batch` keeps the values pending for the batch
772
+ * Save, `cell` writes them into the row and sends the row once (also under
773
+ * `commitOn: 'row'` — closing the form is leaving the row), a row mode saves
774
+ * the row. Cancel puts the row back as it was when the dialog opened.
775
+ * The dialog stays open when the grid widens back into a table.
776
+ */
777
+ edit?: 'popup';
778
+ }
482
779
  /** What a header menu is opened against. */
483
780
  interface HeaderMenuContext {
484
781
  columnId: string;
@@ -535,11 +832,28 @@ interface DataGridEditingOptions<TRow = GridRowData> {
535
832
  formHeight?: number;
536
833
  /** Typing a printable character on a focused cell opens its editor. Default true. */
537
834
  editOnKeyPress?: boolean;
835
+ /**
836
+ * Which gestures open an editor (P-7.1): `{ f2, enter, typing, doubleClick }`.
837
+ * Each one left out keeps today's behaviour (`f2: true, enter: false,
838
+ * typing: true, doubleClick: true`). See `EditKeys`.
839
+ */
840
+ editKeys?: EditKeys;
538
841
  /** Tab moves between cells inside the grid instead of leaving it. Default true. */
539
842
  focusCellOnTab?: boolean;
540
843
  /** Tab past the last editable cell of a row wraps to the next row. Default true. */
541
844
  focusCellOnCycle?: boolean;
542
845
  }
846
+ /** What `rowClassName` is told about a row (P-8). */
847
+ interface RowClassNameContext<TRow = GridRowData> {
848
+ /** The row as it shows: with an editing grid's pending (unsaved) values. */
849
+ row: TRow;
850
+ node: DataRowNode<TRow>;
851
+ rowKey: RowKey;
852
+ /** Its save state (`new`, `changed`, `removed`, `saving`, `saved`, `error`), or null. */
853
+ status: RowSaveStatus | null;
854
+ /** 0-based position in the displayed rows (pinned rows: in their own block). */
855
+ index: number;
856
+ }
543
857
  interface DataGridProps<TRow = GridRowData> extends Omit<DataGridCoreConfig<TRow>, 'columns'> {
544
858
  /**
545
859
  * Optional: with an ARRAY data source and no columns, one column per field
@@ -681,6 +995,21 @@ interface DataGridProps<TRow = GridRowData> extends Omit<DataGridCoreConfig<TRow
681
995
  loadingOverlay?: boolean | number;
682
996
  /** Fired on Enter / double-click over the focused row. */
683
997
  onRowActivate?: (node: RowNode<TRow>) => void;
998
+ /**
999
+ * Called for EVERY key pressed inside the grid (P-7.2), in the capture phase
1000
+ * at the grid's root: before the grid's own handling and before an open
1001
+ * cell editor sees the key — so it also gets F2 while a cell is being typed
1002
+ * in. `ctx` says whether an editor is open, which cell the key is about,
1003
+ * whether that row is new, and can `commit()` the value being typed or
1004
+ * `cancel()` it. Return `'handled'` and the grid does nothing with the key
1005
+ * (the browser's own default is not prevented; call `event.preventDefault()`
1006
+ * for that).
1007
+ *
1008
+ * The grid also leaves alone any key whose `defaultPrevented` is already
1009
+ * true when it arrives (a page listener on `window` took it) and every Alt
1010
+ * combination except AltGr typing. Default: not called.
1011
+ */
1012
+ onKeyDown?: GridKeyHook;
684
1013
  /** Announcements for screen readers (sort/filter/selection). Defaults on. */
685
1014
  announcements?: boolean;
686
1015
  /** Drop area above the grid for grouping by a column. */
@@ -826,8 +1155,12 @@ interface DataGridProps<TRow = GridRowData> extends Omit<DataGridCoreConfig<TRow
826
1155
  *
827
1156
  * `columns` picks the fields and their order (the first is the title);
828
1157
  * default: the visible columns.
1158
+ *
1159
+ * A card is a tap target (P-9): `onCardPress` hears it, `renderCard` draws
1160
+ * the card's content yourself, and on an editing grid `edit: 'popup'` opens
1161
+ * the row in the edit dialog. See {@link DataGridCardViewOptions}.
829
1162
  */
830
- cardView?: boolean | CardViewOptions;
1163
+ cardView?: boolean | DataGridCardViewOptions<TRow>;
831
1164
  /**
832
1165
  * The grid switched between cards and the table (`cardView`), as its width
833
1166
  * crossed the breakpoint. `true` while cards are shown.
@@ -978,6 +1311,19 @@ interface DataGridProps<TRow = GridRowData> extends Omit<DataGridCoreConfig<TRow
978
1311
  * range selection, fill and paste are `EnterpriseDataGrid`.
979
1312
  */
980
1313
  editing?: DataGridEditingOptions<TRow>;
1314
+ /**
1315
+ * A class name for a whole data row (P-8), from the row itself: one rule
1316
+ * for every column instead of a `cellClassName` per column ("a return line
1317
+ * reads red"). Added to the row element beside the grid's own classes
1318
+ * (`rowStatus`, selection, odd/even); return `undefined` or `''` for none.
1319
+ *
1320
+ * Asked for every rendered row on every render, so it follows edits (with
1321
+ * pending values — `row` is what the row shows), `refreshCells()` and
1322
+ * scrolling without being told. Keep it cheap. Data rows only: group,
1323
+ * detail and message rows are not asked. Card view: the class lands on the
1324
+ * card's row element too.
1325
+ */
1326
+ rowClassName?: (ctx: RowClassNameContext<TRow>) => string | undefined;
981
1327
  /** Replace a cell's content (e.g. with an editor). Return undefined for default. */
982
1328
  renderCellContent?: (ctx: CellSlotContext<TRow>) => ReactNode | undefined;
983
1329
  /** Extra class names per cell (dirty marker, range highlight, invalid). */
@@ -1039,6 +1385,12 @@ interface DataGridProps<TRow = GridRowData> extends Omit<DataGridCoreConfig<TRow
1039
1385
  * position and height come from `controller.setEditFormRow`.
1040
1386
  */
1041
1387
  renderEditForm?: (rowKey: RowKey, row: TRow | undefined) => ReactNode;
1388
+ /**
1389
+ * Open a row in the edit dialog from a card (`cardView.edit: 'popup'`, P-9).
1390
+ * Set by `EnterpriseDataGrid`, which owns its editing layer; the free grid
1391
+ * uses its own `editing` when this is left empty. False when nothing opened.
1392
+ */
1393
+ openCardEditor?: (rowKey: RowKey) => boolean;
1042
1394
  }
1043
1395
  interface CellSlotContext<TRow = GridRowData> {
1044
1396
  node: RowNode<TRow>;
@@ -1168,6 +1520,41 @@ interface GridHeaderBandsProps<TRow = GridRowData> {
1168
1520
  declare function GridHeaderBandsImpl<TRow = GridRowData>({ layout, centerColumns, leadingSpacer, trailingSpacer, depth, checkboxColumn, detailColumn, statusColumn, rowNumberColumn, rowHeight, bandFold, }: GridHeaderBandsProps<TRow>): react.JSX.Element | null;
1169
1521
  declare const GridHeaderBands: typeof GridHeaderBandsImpl;
1170
1522
 
1523
+ /** What `label()` answers while the list is still being fetched. */
1524
+ declare const LOOKUP_PENDING: unique symbol;
1525
+ declare class LookupLabels<TRow = GridRowData> {
1526
+ private readonly controller;
1527
+ /** Lists per lookup definition, by row + `dependsOn` values. */
1528
+ private readonly lists;
1529
+ /** The label each cell last showed, by row + column: the no-flicker fallback. */
1530
+ private readonly shown;
1531
+ private repaintQueued;
1532
+ /**
1533
+ * The row WITH pending edits (batch mode keeps them out of the data), so a
1534
+ * child list follows a parent the user changed but has not saved. Set by
1535
+ * the grid on every render.
1536
+ */
1537
+ effectiveRow: ((rowKey: RowKey) => unknown) | null;
1538
+ constructor(controller: DataGridController<TRow>);
1539
+ private key;
1540
+ private repaint;
1541
+ /**
1542
+ * The list for this row: an array when known, the promise while it is not.
1543
+ * Called through the cache — the same row and `dependsOn` values never call
1544
+ * `items` twice — except with `fresh` (a list without `dependsOn`, opened in
1545
+ * the editor: it may read anything, so it is asked again, as before).
1546
+ */
1547
+ items(lookup: ColumnLookup<TRow>, row: TRow, rowKey: RowKey, fresh?: boolean): readonly LookupItem[] | Promise<readonly LookupItem[]>;
1548
+ /**
1549
+ * A FUNCTION lookup's label for a cell: the label, `LOOKUP_PENDING` while
1550
+ * the list is in flight, or null when the column is not a function lookup
1551
+ * or the value is not in the list (the caller falls through to the value).
1552
+ */
1553
+ label(def: GridColumnDef<TRow> | undefined, columnId: string, value: unknown, storedRow: TRow, rowKey: RowKey): string | null | typeof LOOKUP_PENDING;
1554
+ }
1555
+ /** The one label cache of this grid. */
1556
+ declare function lookupLabelsFor<TRow>(controller: DataGridController<TRow>): LookupLabels<TRow>;
1557
+
1171
1558
  interface GridRowProps<TRow = GridRowData> {
1172
1559
  /** Used to build stable cell ids for aria-activedescendant. */
1173
1560
  gridId: string;
@@ -1254,6 +1641,10 @@ interface GridRowProps<TRow = GridRowData> {
1254
1641
  rowStatusText?: string;
1255
1642
  /** `rowStatus.tint`: wash the whole row, not only the marker. */
1256
1643
  rowStatusTint?: boolean;
1644
+ /** `rowStatus.strike`: strike through a `'removed'` row's text (P-2). */
1645
+ rowStatusStrike?: boolean;
1646
+ /** The app's `rowClassName` for this row (P-8), already resolved: a primitive, so memo holds. */
1647
+ rowClass?: string;
1257
1648
  /** Renders the leading checkbox cell. */
1258
1649
  checkboxColumn: boolean;
1259
1650
  /** Renders the leading row-number cell (gap analysis P3.5). */
@@ -1348,6 +1739,12 @@ interface GridRowProps<TRow = GridRowData> {
1348
1739
  * when it does not, they do not.
1349
1740
  */
1350
1741
  searchNeedle?: string;
1742
+ /**
1743
+ * The grid's cache of FUNCTION lookup lists (P-5.1): a closed cell shows the
1744
+ * label, not the raw code. One stable object per grid; when a list arrives
1745
+ * it calls `refreshCells()`, which moves `revision`.
1746
+ */
1747
+ lookupLabels?: LookupLabels<TRow>;
1351
1748
  /** Aggregate definitions rendered inside group headers (Enterprise). */
1352
1749
  summaryDefs?: readonly SummaryDef<TRow>[];
1353
1750
  /** Render a leading expander cell for master-detail (Enterprise). */
@@ -1381,7 +1778,7 @@ interface GridRowProps<TRow = GridRowData> {
1381
1778
  onCellPointerEnter?: (ctx: CellSlotContext<TRow>, event: React.MouseEvent) => void;
1382
1779
  onCellDoubleClick?: (ctx: CellSlotContext<TRow>) => void;
1383
1780
  }
1384
- declare function GridRowImpl<TRow = GridRowData>({ gridId, node, index, layout, columnModel, centerColumns, centerIndices, stickyInsets, leadingSpacer, trailingSpacer, striped, selected, ariaSelectable, selectable, groupSelection, onToggleGroupSelect, groupDisplay, focusedColumnId, rowFocused, renderRow, checkboxColumn, statusColumn, rowNumberColumn, rowNumber, getNote, getSpan, resolveColSpans, findKind, headerRowCount, onRowClick, onRowMouseDown, onRowDoubleClick, onToggleSelect, onCellMouseDown, onRowContextMenu, searchNeedle, onToggleGroup, summaryDefs, detailColumn, detailExpanded, onToggleDetail, onToggleTreeRow, renderDetail, renderEditForm, renderRowMessage, renderCellContent, getCellClassName, onCellPointerDown, onCellPointerEnter, onCellDoubleClick, rowDrag, dropSide, rowStatus, rowStatusText, rowStatusTint, height, }: GridRowProps<TRow>): react.JSX.Element | null;
1781
+ declare function GridRowImpl<TRow = GridRowData>({ gridId, node, index, layout, columnModel, centerColumns, centerIndices, stickyInsets, leadingSpacer, trailingSpacer, striped, selected, ariaSelectable, selectable, groupSelection, onToggleGroupSelect, groupDisplay, focusedColumnId, rowFocused, renderRow, checkboxColumn, statusColumn, rowNumberColumn, rowNumber, getNote, getSpan, resolveColSpans, findKind, headerRowCount, onRowClick, onRowMouseDown, onRowDoubleClick, onToggleSelect, onCellMouseDown, onRowContextMenu, searchNeedle, lookupLabels, onToggleGroup, summaryDefs, detailColumn, detailExpanded, onToggleDetail, onToggleTreeRow, renderDetail, renderEditForm, renderRowMessage, renderCellContent, getCellClassName, onCellPointerDown, onCellPointerEnter, onCellDoubleClick, rowDrag, dropSide, rowStatus, rowStatusText, rowStatusTint, rowStatusStrike, rowClass, height, }: GridRowProps<TRow>): react.JSX.Element | null;
1385
1782
  declare const GridRow: typeof GridRowImpl;
1386
1783
 
1387
1784
  interface GridFilterRowProps<TRow = GridRowData> {
@@ -2010,8 +2407,10 @@ interface GridPinnedRowsProps<TRow = GridRowData> {
2010
2407
  * rows have to move down to make room. `DataGrid` does both from one count.
2011
2408
  */
2012
2409
  ariaRowBase: number;
2410
+ /** The app's `rowClassName` (P-8), resolved by `DataGrid`; `userKey` is the data row's key for a user-pinned row. */
2411
+ rowClassFor?: (node: DataRowNode<TRow>, index: number, userKey: RowKey | null) => string | undefined;
2013
2412
  }
2014
- declare function GridPinnedRowsImpl<TRow = GridRowData>({ gridId, side, rows, rowKeys, onUserRowContextMenu, layout, columnModel, centerColumns, centerIndices, stickyInsets, leadingSpacer, trailingSpacer, checkboxColumn, detailColumn, statusColumn, rowNumberColumn, rowHeight, bandOffset, headerRowsBetween, ariaRowBase, }: GridPinnedRowsProps<TRow>): react.JSX.Element | null;
2413
+ declare function GridPinnedRowsImpl<TRow = GridRowData>({ gridId, side, rows, rowKeys, onUserRowContextMenu, layout, columnModel, centerColumns, centerIndices, stickyInsets, leadingSpacer, trailingSpacer, checkboxColumn, detailColumn, statusColumn, rowNumberColumn, rowHeight, bandOffset, headerRowsBetween, ariaRowBase, rowClassFor, }: GridPinnedRowsProps<TRow>): react.JSX.Element | null;
2015
2414
  declare const GridPinnedRows: typeof GridPinnedRowsImpl;
2016
2415
 
2017
2416
  type UseDataGridOptions<TRow = GridRowData> = DataGridCoreConfig<TRow>;
@@ -2111,6 +2510,14 @@ declare function GridTextProvider({ locale, messages, children }: GridTextProvid
2111
2510
  /** The resolved dictionary. Stable between language changes. */
2112
2511
  declare function useGridText(): GridDictionary;
2113
2512
 
2513
+ /**
2514
+ * Text an editor opens with when the typed character is not a value yet
2515
+ * (P-3.6): `-` or `,` on a number cell, a digit on a date cell. Keyed by the
2516
+ * engine's edit SESSION object, so it belongs to that one opening; the session
2517
+ * itself keeps the cell's value until the editor reports a complete one, which
2518
+ * is what makes "-" followed by Enter change nothing.
2519
+ */
2520
+ declare const editorSeedText: WeakMap<object, string>;
2114
2521
  interface UseGridEditingOptions<TRow = GridRowData> {
2115
2522
  controller: DataGridController<TRow> | null;
2116
2523
  mode?: EditMode;
@@ -2128,13 +2535,42 @@ interface UseGridEditingOptions<TRow = GridRowData> {
2128
2535
  /** Typing a printable key on a focused cell starts editing. Default true. */
2129
2536
  editOnKeyPress?: boolean;
2130
2537
  /**
2131
- * `Insert` opens a blank row ABOVE the focused one. Default false.
2538
+ * `Insert` opens a blank row next to the focused one: `true` or `'above'`
2539
+ * above it, `'below'` under it. Default false (off).
2132
2540
  *
2133
2541
  * Off by default because Insert is not a neutral key: some users have it
2134
2542
  * bound elsewhere, and a grid that starts creating records on a keypress
2135
- * nobody asked for is a surprise.
2543
+ * nobody asked for is a surprise. When on, the key is the grid's whenever a
2544
+ * cell has focus: it is `preventDefault()`ed even when no row can be added,
2545
+ * so a page-level Insert shortcut does not fire for it (P-7.5).
2546
+ */
2547
+ insertKey?: boolean | 'above' | 'below';
2548
+ /**
2549
+ * Which gestures open an editor (P-7.1): `f2`, `enter`, `typing`,
2550
+ * `doubleClick`. Each left out keeps today's behaviour.
2551
+ */
2552
+ editKeys?: EditKeys;
2553
+ /**
2554
+ * Tab on the last editable cell of the last row adds a blank row and moves
2555
+ * to its first editable cell (P-7.8). Shift+Tab never adds one and stays on
2556
+ * the first cell. Needs `allowAdding`. Default false.
2557
+ */
2558
+ appendOnTab?: boolean;
2559
+ /**
2560
+ * Ctrl+Delete (Cmd+Delete) deletes the focused row (P-7.5): `allowDeleting`,
2561
+ * then the `confirmDelete` FUNCTION is asked; without a function nothing is
2562
+ * deleted. On a row already marked removed (`batch`) it restores it. Not
2563
+ * while an editor is open (the key is the text box's). Default false.
2564
+ */
2565
+ deleteKey?: boolean;
2566
+ /** Ctrl+D / Ctrl+R fill down / right over the selection. Default true. */
2567
+ fillKeys?: boolean;
2568
+ /**
2569
+ * Ctrl+V over several selected cells spreads a copied table over them.
2570
+ * Default true. `false`: the paste goes to the focused cell only and the
2571
+ * clipboard text is ONE value (tabs and line breaks do not split it).
2136
2572
  */
2137
- insertKey?: boolean;
2573
+ rangePaste?: boolean;
2138
2574
  /**
2139
2575
  * Arrow-down on the LAST row appends a blank one. Default false.
2140
2576
  *
@@ -2186,6 +2622,26 @@ interface UseGridEditingOptions<TRow = GridRowData> {
2186
2622
  * columns read-only — those editors are Enterprise.
2187
2623
  */
2188
2624
  canEditColumn?: (columnId: string) => boolean;
2625
+ /**
2626
+ * Called ONCE when the grid's editing is ready, with the `EditingApi` (P-1)
2627
+ * — the same object `controller.editing` returns while the grid is mounted.
2628
+ * Not called again for a React StrictMode remount or a re-render; the object
2629
+ * stays valid across both and turns into a harmless no-op after unmount.
2630
+ */
2631
+ onReady?: (api: EditingApi<TRow>) => void;
2632
+ /**
2633
+ * `cell` mode: save each committed cell at once (`'cell'`, default) or the
2634
+ * whole row once the user leaves it (`'row'`, P-10) — to another row by any
2635
+ * key or click, or out of the grid. A new row left empty is dropped, never
2636
+ * sent. Ignored by the other modes.
2637
+ */
2638
+ commitOn?: CommitOn;
2639
+ /**
2640
+ * The grid shows a refused save's reason under the row (`rowStatus.messages`).
2641
+ * With `commitOn: 'row'` a row refused on leave is then reported there only,
2642
+ * not also in the "cannot save" dialog. Default false.
2643
+ */
2644
+ rowMessages?: boolean;
2189
2645
  }
2190
2646
  /**
2191
2647
  * What the footer strip shows for the current range.
@@ -2240,13 +2696,21 @@ interface UseGridEditingResult<TRow = GridRowData> {
2240
2696
  range: RangeApi;
2241
2697
  /** Bumped on every engine change; consumers read through it. */
2242
2698
  version: number;
2699
+ /**
2700
+ * The app-facing editing API (P-1): one object for the life of this hook,
2701
+ * forwarding to the current engine — see `EditingApi`.
2702
+ */
2703
+ api: EditingApi<TRow>;
2243
2704
  beginEdit: (rowKey: RowKey, columnId: string) => void;
2244
2705
  /**
2245
2706
  * Open a whole ROW (row / form / popup modes). False when the mode does not
2246
2707
  * support it, or another row is already open — the caller decides what to
2247
2708
  * do with the first one rather than having it saved or discarded silently.
2709
+ * `standalone`: in any mode — a card's popup (P-9; see the engine).
2248
2710
  */
2249
- beginRowEdit: (rowKey: RowKey) => boolean;
2711
+ beginRowEdit: (rowKey: RowKey, options?: {
2712
+ standalone?: boolean;
2713
+ }) => boolean;
2250
2714
  /** Validate and persist the open row. Resolves false and stays open on failure. */
2251
2715
  saveRowEdit: () => Promise<boolean>;
2252
2716
  /** Discard the open row's edits. Other rows keep theirs. */
@@ -2259,7 +2723,44 @@ interface UseGridEditingResult<TRow = GridRowData> {
2259
2723
  * `beforeKey` puts it directly above that row instead of at the end — what
2260
2724
  * the Insert key needs.
2261
2725
  */
2262
- addRow: (values?: Record<string, unknown>, beforeKey?: RowKey) => RowKey | null;
2726
+ addRow: (values?: Record<string, unknown>, beforeKey?: RowKey, options?: {
2727
+ open?: boolean;
2728
+ position?: NewRowPosition;
2729
+ }) => RowKey | null;
2730
+ /**
2731
+ * The built-in cell editor's commit (Enter, blur, a picked item), shared by
2732
+ * both renderers. `'down'` moves to the cell below afterwards — unless
2733
+ * `editKeys.enter` is on, where Enter stays on the cell (P-7.1). `'blur'`:
2734
+ * focus has already gone where the user put it, so it is not pulled back to
2735
+ * the grid (P-10: a click on a field outside the grid must keep that field).
2736
+ */
2737
+ commitCellEditor: (move: 'down' | 'none' | 'blur') => void;
2738
+ /**
2739
+ * A custom editor's commit (`renderEditor`'s `ctx.commit`, P-4.2): `'none'`
2740
+ * stays on the cell, `'down'` moves down (whatever `editKeys.enter` says —
2741
+ * the editor asked), `'next'` / `'previous'` walk to the adjacent editable
2742
+ * cell like Tab, `'blur'` leaves focus where it is. False when a rule
2743
+ * refused the value.
2744
+ */
2745
+ commitCustomEditor: (move: 'down' | 'next' | 'previous' | 'none' | 'blur') => boolean;
2746
+ /**
2747
+ * `ctx.suspendBlurCommit` (P-4.1): while on, blur is not leaving the editor
2748
+ * (`ctx.commitOnBlur`, the `commitOn: 'row'` send). Turning it off puts focus
2749
+ * that fell to `<body>` back on the editor (`restoreTo`), else the scroller.
2750
+ */
2751
+ suspendBlurCommit: (on: boolean, restoreTo?: () => HTMLElement | null) => void;
2752
+ /** True while a custom editor's dialog holds `suspendBlurCommit(true)`. */
2753
+ blurCommitSuspended: () => boolean;
2754
+ /** What the app's `onKeyDown` hook is told (P-7.2). */
2755
+ keyContext: () => GridKeyContext;
2756
+ /** `editKeys.doubleClick` — a double-click / double-tap opens an editor. */
2757
+ doubleClickEdits: boolean;
2758
+ /**
2759
+ * Close the open cell editor without keeping its value and give focus back
2760
+ * to the grid (the editors' Escape). Under `commitOn: 'row'` a new row left
2761
+ * empty by it is dropped, never sent (P-10).
2762
+ */
2763
+ cancelCellEdit: () => void;
2263
2764
  /**
2264
2765
  * Commit and move to the next (1) or previous (-1) editable cell. By default
2265
2766
  * the destination is only FOCUSED; pass `open: true` to carry the editor
@@ -2355,6 +2856,12 @@ interface UseEditModesOptions<TRow = GridRowData> {
2355
2856
  * default batch mode saves from the command column) and passes that here.
2356
2857
  */
2357
2858
  batchBar?: boolean;
2859
+ /**
2860
+ * Cards are shown with `cardView.edit: 'popup'` (P-9): an open row session
2861
+ * of a row mode — opened in the table before the grid narrowed — is drawn
2862
+ * as the popup, the one editor a card view has.
2863
+ */
2864
+ cardPopup?: boolean;
2358
2865
  }
2359
2866
  interface EditModes<TRow = GridRowData> {
2360
2867
  /** A row mode (row / form / popup) is in force and drawn. */
@@ -2381,6 +2888,11 @@ interface EditModes<TRow = GridRowData> {
2381
2888
  editRowMenuItem: <TContext>(rowKey: RowKey) => GridMenuItem<TContext> | null;
2382
2889
  /** Open a row (double-click in a row mode). False when not a row mode. */
2383
2890
  openRow: (rowKey: RowKey) => boolean;
2891
+ /**
2892
+ * Open a row in the popup from a card (`cardView.edit: 'popup'`, P-9), in
2893
+ * any mode. False when it cannot be opened (locked, removed, another row open).
2894
+ */
2895
+ openCardEditor: (rowKey: RowKey) => boolean;
2384
2896
  }
2385
2897
  /**
2386
2898
  * The columns a record's form offers, in the grid's own order.
@@ -2394,7 +2906,7 @@ interface EditModes<TRow = GridRowData> {
2394
2906
  * them out).
2395
2907
  */
2396
2908
  declare function editFormColumnIds<TRow>(controller: DataGridController<TRow> | null, isFormColumn?: (columnId: string) => boolean): string[];
2397
- declare function useEditModes<TRow = GridRowData>({ controller, editing, mode, active, rootRef, rowHeight, formLabels, formHeight: formHeightOption, dark, rowLookups, customEditors, isFormColumn, batchBar, }: UseEditModesOptions<TRow>): EditModes<TRow>;
2909
+ declare function useEditModes<TRow = GridRowData>({ controller, editing, mode, active, rootRef, rowHeight, formLabels, formHeight: formHeightOption, dark, rowLookups, customEditors, isFormColumn, batchBar, cardPopup, }: UseEditModesOptions<TRow>): EditModes<TRow>;
2398
2910
 
2399
2911
  interface GridRowEditorProps<TRow = GridRowData> {
2400
2912
  controller: DataGridController<TRow>;
@@ -2414,6 +2926,122 @@ interface GridRowEditorProps<TRow = GridRowData> {
2414
2926
  }
2415
2927
  declare function GridRowEditor<TRow = GridRowData>({ controller, engine, columnId, message, saving, lookupOptions, onSave, onCancel, }: GridRowEditorProps<TRow>): react.JSX.Element;
2416
2928
 
2929
+ type ResolvedNumberFormat = ColumnNumberFormat & {
2930
+ locale: string;
2931
+ };
2932
+ /**
2933
+ * The column's `numberFormat` when its editor is the number TEXT box — not
2934
+ * for a lookup, a custom editor or a formula column, which own their value.
2935
+ */
2936
+ declare function numberTextFormat(def: {
2937
+ numberFormat?: ColumnNumberFormat;
2938
+ lookup?: unknown;
2939
+ renderEditor?: unknown;
2940
+ allowFormulas?: boolean;
2941
+ } | undefined): ResolvedNumberFormat | undefined;
2942
+
2943
+ interface GridLookupEditorProps {
2944
+ options: readonly LookupItem[];
2945
+ value: unknown;
2946
+ /** Prefix (default) or substring — for the label (the name of a `linked` list). */
2947
+ matchMode?: LookupMatchMode;
2948
+ /** How typed text matches a `linked` list's code (`value`). Default `'startsWith'`. */
2949
+ codeMatchMode?: LookupMatchMode;
2950
+ /**
2951
+ * A code + name list (`lookup.linkedColumns`, P-5.2): each item shows its
2952
+ * code (`value`) and name (`label`), typing matches either, and the box
2953
+ * shows the code.
2954
+ */
2955
+ linked?: boolean;
2956
+ /**
2957
+ * How typed text and item text are folded before they are compared
2958
+ * (`lookup.matchFold`, P-13). Default `'case'` — the editor's old behaviour.
2959
+ */
2960
+ matchFold?: LookupMatchFold;
2961
+ /** Let text that matches nothing become the value. Default false. */
2962
+ allowCustom?: boolean;
2963
+ /**
2964
+ * Open the list as soon as the editor mounts (`lookup.openOnEdit`, P-11).
2965
+ * Only for an editor that takes focus (`autoFocus`) — in a row or form every
2966
+ * field would open its list at once.
2967
+ */
2968
+ openOnEdit?: boolean;
2969
+ /**
2970
+ * The editor was opened by TYPING and `value` is that one character: the
2971
+ * box starts with it as the typed text (list filtered by it, caret after
2972
+ * it). Acts only together with `openOnEdit`.
2973
+ */
2974
+ seeded?: boolean;
2975
+ /**
2976
+ * Refuse typing that matches no item (`lookup.restrictInput`, P-12).
2977
+ * Deleting is always free; ignored with `allowCustom`.
2978
+ */
2979
+ restrictInput?: boolean;
2980
+ /**
2981
+ * Complete typed text to the one item left / an exact label on leaving.
2982
+ * Default true. False: the "pick from the list" rule (K-3, see the top).
2983
+ */
2984
+ autoCompleteSingle?: boolean;
2985
+ /**
2986
+ * Typed text that picks nothing (closed list): Enter keeps the editor open
2987
+ * and announces it either way; Tab stays (`'keep-open'`, default) or drops
2988
+ * the text and moves on (`'revert'`).
2989
+ */
2990
+ onNoMatch?: 'revert' | 'keep-open';
2991
+ /**
2992
+ * Picking an item writes it: answer true when written. Left out, a pick is
2993
+ * `onChange(item.value)`. A code + name pick writes several columns in one
2994
+ * step through this (P-5.2); false (a locked row) keeps the editor open.
2995
+ */
2996
+ onPick?: (item: LookupItem) => boolean;
2997
+ invalid?: boolean;
2998
+ /**
2999
+ * Take focus on mount. True for a cell editor — it opened BECAUSE the user
3000
+ * asked to edit that one cell. False in `row` mode, where every editable cell
3001
+ * mounts an editor at once and each would grab focus in turn, landing the
3002
+ * caret on whichever lookup happened to render last.
3003
+ */
3004
+ autoFocus?: boolean;
3005
+ testId?: string;
3006
+ /** Stamped as `data-column-id`, so callers can find one field of a row. */
3007
+ columnId?: string;
3008
+ ariaLabel?: string;
3009
+ onChange: (value: unknown) => void;
3010
+ /** Commit (Enter / picking an item), handed back to the engine. */
3011
+ onCommit: () => void;
3012
+ /**
3013
+ * Whether picking an item counts as committing. True for a cell editor —
3014
+ * the pick IS the edit. False in `row`/`form` mode, where picking fills one
3015
+ * field of a record the user is still filling in and only Save ends it.
3016
+ */
3017
+ commitOnPick?: boolean;
3018
+ onCancel: () => void;
3019
+ /** Tab moves to the adjacent cell; the engine owns that. */
3020
+ onTab?: (shiftKey: boolean) => void;
3021
+ /**
3022
+ * Focus left the box for somewhere that is not its list: commit (the cell
3023
+ * editor's click-away, P-10). Left out (row mode, the form), a blur only
3024
+ * settles the typed text, as before.
3025
+ */
3026
+ onBlurCommit?: () => void;
3027
+ }
3028
+ /**
3029
+ * The same match, as items. Kept for callers and tests that want the simple
3030
+ * shape; the component itself works in indices to avoid the copy.
3031
+ */
3032
+ declare function matchOptions(options: readonly LookupItem[], query: string, mode: LookupMatchMode): readonly LookupItem[];
3033
+ /** The editor's settings that come straight from a column's `lookup`. */
3034
+ type LookupEditorSettings = Pick<GridLookupEditorProps, 'matchMode' | 'codeMatchMode' | 'linked' | 'allowCustom' | 'autoCompleteSingle' | 'onNoMatch' | 'matchFold' | 'openOnEdit' | 'restrictInput'>;
3035
+ /** `lookup` → the editor's props, one reading for the cell, row and form editors. */
3036
+ declare function lookupEditorSettings(lookup: ColumnLookup<never> | undefined): LookupEditorSettings;
3037
+ /**
3038
+ * What one pick writes to the row (P-5.2 / P-5.3): the column's own value,
3039
+ * `linkedColumns`' code / name / id, then `map`. Null when the column has
3040
+ * neither — a plain pick, one cell, as before.
3041
+ */
3042
+ declare function lookupPickValues(lookup: ColumnLookup<never> | undefined, columnId: string, item: LookupItem): Record<string, unknown> | null;
3043
+ declare function GridLookupEditor({ options, value, matchMode, codeMatchMode, matchFold, linked, allowCustom, openOnEdit, seeded, restrictInput, autoCompleteSingle, onNoMatch, onPick, invalid, autoFocus, testId, columnId, ariaLabel, onChange, onCommit, commitOnPick, onCancel, onTab, onBlurCommit, }: GridLookupEditorProps): react.JSX.Element;
3044
+
2417
3045
  interface GridCellEditorProps {
2418
3046
  value: unknown;
2419
3047
  dataType: GridDataType | undefined;
@@ -2427,6 +3055,13 @@ interface GridCellEditorProps {
2427
3055
  allowCustom?: boolean;
2428
3056
  /** How typed text narrows the lookup list. Default `'startsWith'`. */
2429
3057
  matchMode?: LookupMatchMode;
3058
+ /**
3059
+ * The rest of the column's `lookup` as the combo box reads it (P-5 / P-6):
3060
+ * code + name, K-3, `onNoMatch`. Wins over `allowCustom` / `matchMode`.
3061
+ */
3062
+ lookupSettings?: LookupEditorSettings;
3063
+ /** A pick that writes more than this cell (code + name, `map`): true when written. */
3064
+ onPick?: (item: LookupItem) => boolean;
2430
3065
  /** Accessible name for the editor, used by the lookup combo box. */
2431
3066
  ariaLabel?: string;
2432
3067
  /** Format for a `date` column — governs both the mask and the display. */
@@ -2439,13 +3074,31 @@ interface GridCellEditorProps {
2439
3074
  * make the second keystroke erase the first.
2440
3075
  */
2441
3076
  seeded?: boolean;
3077
+ /**
3078
+ * The editor was opened by typing a character that is not a value yet
3079
+ * (P-3.6): `-` or `,` on a number cell, a digit on a date cell. The box
3080
+ * starts with it, caret after it; `value` stays the cell's own until a
3081
+ * complete value is typed.
3082
+ */
3083
+ seedText?: string;
3084
+ /**
3085
+ * The column's `numberFormat` (locale resolved): the editor is then a text
3086
+ * box in that locale (P-3) whose value is the TEXT; the engine reads it.
3087
+ */
3088
+ numberFormat?: ResolvedNumberFormat;
3089
+ /**
3090
+ * The grid's number locale (`'tr-TR'`), for reading a number box opened by
3091
+ * typing `-` or `,` on a column without `numberFormat`. Default `'en-US'`.
3092
+ */
3093
+ numberLocale?: string;
2442
3094
  onChange: (value: unknown) => void;
2443
- onCommit: (move: 'down' | 'none') => void;
3095
+ /** `'blur'`: focus left the editor — commit, but do not take focus back. */
3096
+ onCommit: (move: 'down' | 'none' | 'blur') => void;
2444
3097
  /** Tab / Shift+Tab: commit here and keep editing in the adjacent cell. */
2445
3098
  onTab: (direction: 1 | -1) => void;
2446
3099
  onCancel: () => void;
2447
3100
  }
2448
- declare function GridCellEditor({ value, dataType, error, seeded, options, allowCustom, matchMode, ariaLabel, dateFormat, onChange, onCommit, onTab, onCancel, }: GridCellEditorProps): react.JSX.Element;
3101
+ declare function GridCellEditor({ value, dataType, error, seeded, seedText, options, allowCustom, matchMode, lookupSettings, onPick, ariaLabel, dateFormat, numberFormat, numberLocale, onChange, onCommit, onTab, onCancel, }: GridCellEditorProps): react.JSX.Element;
2449
3102
 
2450
3103
  interface GridDateEditorProps {
2451
3104
  value: unknown;
@@ -2470,47 +3123,19 @@ interface GridDateEditorProps {
2470
3123
  onCommit: () => void;
2471
3124
  onCancel: () => void;
2472
3125
  onTab?: (shiftKey: boolean) => void;
2473
- }
2474
- declare function GridDateEditor({ value, format, invalid, disabled, autoFocus, testId, columnId, ariaLabel, onChange, onCommit, onCancel, onTab, }: GridDateEditorProps): react.JSX.Element;
2475
-
2476
- interface GridLookupEditorProps {
2477
- options: readonly LookupItem[];
2478
- value: unknown;
2479
- /** Prefix (default) or substring. */
2480
- matchMode?: LookupMatchMode;
2481
- /** Let text that matches nothing become the value. Default false. */
2482
- allowCustom?: boolean;
2483
- invalid?: boolean;
2484
3126
  /**
2485
- * Take focus on mount. True for a cell editor — it opened BECAUSE the user
2486
- * asked to edit that one cell. False in `row` mode, where every editable cell
2487
- * mounts an editor at once and each would grab focus in turn, landing the
2488
- * caret on whichever lookup happened to render last.
3127
+ * Focus left the box for somewhere that is not its calendar: commit (the
3128
+ * cell editor's click-away, P-10). Left out (row mode, the form), a blur
3129
+ * only settles the typed text, as before.
2489
3130
  */
2490
- autoFocus?: boolean;
2491
- testId?: string;
2492
- /** Stamped as `data-column-id`, so callers can find one field of a row. */
2493
- columnId?: string;
2494
- ariaLabel?: string;
2495
- onChange: (value: unknown) => void;
2496
- /** Commit (Enter / picking an item), handed back to the engine. */
2497
- onCommit: () => void;
3131
+ onBlurCommit?: () => void;
2498
3132
  /**
2499
- * Whether picking an item counts as committing. True for a cell editor —
2500
- * the pick IS the edit. False in `row`/`form` mode, where picking fills one
2501
- * field of a record the user is still filling in and only Save ends it.
3133
+ * Digits the box starts with — the editor was opened by typing one on the
3134
+ * cell (P-3.6). The caret goes after them instead of selecting.
2502
3135
  */
2503
- commitOnPick?: boolean;
2504
- onCancel: () => void;
2505
- /** Tab moves to the adjacent cell; the engine owns that. */
2506
- onTab?: (shiftKey: boolean) => void;
3136
+ seedDigits?: string;
2507
3137
  }
2508
- /**
2509
- * The same match, as items. Kept for callers and tests that want the simple
2510
- * shape; the component itself works in indices to avoid the copy.
2511
- */
2512
- declare function matchOptions(options: readonly LookupItem[], query: string, mode: LookupMatchMode): readonly LookupItem[];
2513
- declare function GridLookupEditor({ options, value, matchMode, allowCustom, invalid, autoFocus, testId, columnId, ariaLabel, onChange, onCommit, commitOnPick, onCancel, onTab, }: GridLookupEditorProps): react.JSX.Element;
3138
+ declare function GridDateEditor({ value, format, invalid, disabled, autoFocus, testId, columnId, ariaLabel, onChange, onCommit, onCancel, onTab, onBlurCommit, seedDigits, }: GridDateEditorProps): react.JSX.Element;
2514
3139
 
2515
3140
  interface GridDialogProps {
2516
3141
  open: boolean;
@@ -2527,4 +3152,4 @@ interface GridDialogProps {
2527
3152
  }
2528
3153
  declare function GridDialog({ open, title, message, cancelLabel, confirmLabel, danger, dark, onConfirm, onCancel, }: GridDialogProps): react.ReactPortal | null;
2529
3154
 
2530
- export { type AlignedGridsApi, BAND_ROW_HEIGHT, type BatchSaveError, type CellMenuOptions, type CellRenderContext, type CellSlotContext, type CellTooltipOptions, DEFAULT_EDIT_FORM_LABELS, DEFAULT_HEADER_MENU_LABELS, DataGrid, type DataGridProps, type DistinctEntry, type EditFormField, type EditFormLabels, type EditModes, type EditorRenderContext, type ExportOutcome, type FilterRenderContext, GridCellEditor, type GridCellEditorProps, GridColumnChooser, type GridColumnChooserProps, GridContextMenu, type GridContextMenuProps, GridDateEditor, type GridDateEditorProps, GridDialog, type GridDialogProps, GridEditForm, type GridEditFormProps, GridFilterPanel, type GridFilterPanelProps, GridFilterRow, type GridFilterRowProps, GridFooterRow, type GridFooterRowProps, GridGroupPanel, type GridGroupPanelProps, GridHeader, GridHeaderBands, type GridHeaderBandsProps, GridHeaderFilterPopup, type GridHeaderFilterPopupProps, type GridHeaderProps, GridLoadingOverlay, type GridLoadingOverlayProps, GridLookupEditor, type GridLookupEditorProps, type GridMenuItem, GridNoteEditor, type GridNotesConfig, GridPager, type GridPagerProps, GridPinnedRows, type GridPinnedRowsProps, GridPopupPanel, type GridPopupPanelProps, GridPortal, type GridPortalProps, GridRow, GridRowEditor, type GridRowEditorProps, type GridRowProps, GridSummaryBar, type GridSummaryBarProps, GridSurfaceProvider, type GridSurfaceProviderProps, GridTextProvider, type GridTextProviderProps, GridToolbar, GridToolbarButton, type GridToolbarButtonProps, type GridToolbarProps, GridTooltip, type GridTooltipConfig, type GridTooltipProps, type HeaderMenuContext, type HeaderMenuDeps, type HeaderMenuLabels, type HeaderRenderContext, type NoteCellContext, PRINT_MAX_ROWS, type PendingDelete, type PrintLayoutOptions, type PrintLayoutState, ROW_DRAG_MIME, type RangeApi, type ReactColumnRuntime, type ReactGridColumnDef, type RowDragConfig, type RowDragHandlers, type RowDragPayload, type RowDropEvent, type RowLookupMap, type RowMenuContext, type RowReorderEvent, type RowTemplateContext, SHORTCUT_COPY, SHORTCUT_CUT, SHORTCUT_PASTE, type SelectionStats, ToolbarIcon, type TooltipState, type UseDataGridOptions, type UseDataGridResult, type UseEditModesOptions, type UseGridEditingOptions, type UseGridEditingResult, buildCellMenuItems, buildHeaderMenu, copyToClipboard, editFormColumnIds, editFormLabels, headerMenuLabels, matchOptions, measureBestFitWidth, reconcileFilterInputs, runGridExport, useAlignedGrids, useAnchoredPopup, useCellTooltip, useDataGrid, useEditModes, useGridChartBoxData, useGridChartData, useGridChartXYData, useGridEditing, useGridPortalTarget, useGridSurfaceClass, useGridText, usePrintLayout, useRowDrag, useStateStoring, writeClipboardText };
3155
+ export { type AlignedGridsApi, BAND_ROW_HEIGHT, type BatchSaveError, type CardRenderContext, type CellMenuOptions, type CellRenderContext, type CellSlotContext, type CellTooltipOptions, DEFAULT_EDIT_FORM_LABELS, DEFAULT_HEADER_MENU_LABELS, DataGrid, type DataGridCardViewOptions, type DataGridProps, type DistinctEntry, EDITOR_OWNED_SELECTOR, type EditFormField, type EditFormLabels, type EditKeys, type EditModes, type EditorCommitMove, type EditorCommitOptions, type EditorRenderContext, type EditorRowApi, type ExportOutcome, type FilterRenderContext, GRID_PORTAL_SELECTOR, GridCellEditor, type GridCellEditorProps, GridColumnChooser, type GridColumnChooserProps, GridContextMenu, type GridContextMenuProps, GridDateEditor, type GridDateEditorProps, GridDialog, type GridDialogProps, GridEditForm, type GridEditFormProps, GridFilterPanel, type GridFilterPanelProps, GridFilterRow, type GridFilterRowProps, GridFooterRow, type GridFooterRowProps, GridGroupPanel, type GridGroupPanelProps, GridHeader, GridHeaderBands, type GridHeaderBandsProps, GridHeaderFilterPopup, type GridHeaderFilterPopupProps, type GridHeaderProps, type GridKeyCell, type GridKeyContext, type GridKeyHook, GridLoadingOverlay, type GridLoadingOverlayProps, GridLookupEditor, type GridLookupEditorProps, type GridMenuItem, GridNoteEditor, type GridNotesConfig, GridPager, type GridPagerProps, GridPinnedRows, type GridPinnedRowsProps, GridPopupPanel, type GridPopupPanelProps, GridPortal, type GridPortalProps, GridRow, GridRowEditor, type GridRowEditorProps, type GridRowProps, GridSummaryBar, type GridSummaryBarProps, GridSurfaceProvider, type GridSurfaceProviderProps, GridTextProvider, type GridTextProviderProps, GridToolbar, GridToolbarButton, type GridToolbarButtonProps, type GridToolbarProps, GridTooltip, type GridTooltipConfig, type GridTooltipProps, type HeaderMenuContext, type HeaderMenuDeps, type HeaderMenuLabels, type HeaderRenderContext, LOOKUP_PENDING, type LookupEditorSettings, LookupLabels, type NoteCellContext, PRINT_MAX_ROWS, type PendingDelete, type PrintLayoutOptions, type PrintLayoutState, ROW_DRAG_MIME, type RangeApi, type ReactColumnRuntime, type ReactGridColumnDef, type ResolvedNumberFormat, type RowClassNameContext, type RowDragConfig, type RowDragHandlers, type RowDragPayload, type RowDropEvent, type RowLookupMap, type RowMenuContext, type RowReorderEvent, type RowTemplateContext, SHORTCUT_COPY, SHORTCUT_CUT, SHORTCUT_PASTE, type SelectionStats, ToolbarIcon, type TooltipState, type UseDataGridOptions, type UseDataGridResult, type UseEditModesOptions, type UseGridEditingOptions, type UseGridEditingResult, buildCellMenuItems, buildHeaderMenu, copyToClipboard, editFormColumnIds, editFormLabels, editorOwnsKey, editorSeedText, eventFromOwnDom, focusStaysWithGrid, gridIgnoresKey, headerMenuLabels, isAltGraphChar, keyClaimed, lookupEditorSettings, lookupLabelsFor, lookupPickValues, markKeyHandledByApp, matchOptions, measureBestFitWidth, numberTextFormat, reconcileFilterInputs, runGridExport, useAlignedGrids, useAnchoredPopup, useCellTooltip, useDataGrid, useEditModes, useGridChartBoxData, useGridChartData, useGridChartXYData, useGridEditing, useGridPortalTarget, useGridSurfaceClass, useGridText, usePrintLayout, useRowDrag, useStateStoring, writeClipboardText };