@kanunilabs/datagrid-react 1.8.7 → 1.8.9

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 { ReactNode, FocusEvent, MouseEvent, RefObject } 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 } 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,134 @@ 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
+ * A double-click (a double-tap on a touch screen) opens the cell's editor.
135
+ * Default true.
136
+ */
137
+ doubleClick?: boolean;
138
+ }
139
+ /** The cell the key is about: the open editor's, else the focused one. */
140
+ interface GridKeyCell {
141
+ rowKey: RowKey;
142
+ columnId: string;
143
+ }
144
+ /**
145
+ * What the app's `onKeyDown` hook is told about the grid (P-7.2).
146
+ */
147
+ interface GridKeyContext {
148
+ /** A cell editor (or, in a row mode, a row) is open. */
149
+ editing: boolean;
150
+ /** The open editor's cell, else the focused cell; null when neither. */
151
+ cell: GridKeyCell | null;
152
+ /** `cell`'s row was added and is not saved yet. */
153
+ isNewRow: boolean;
154
+ /**
155
+ * Commit the open cell editor — the value being typed becomes the cell's
156
+ * (pending) value. True when nothing was open or the value was taken; false
157
+ * when a rule refused it (the editor stays open) or a whole row is open in a
158
+ * row mode (save that with `api.saveChanges()`).
159
+ */
160
+ commit(): boolean;
161
+ /** Close the open editor without keeping its value. */
162
+ cancel(): void;
163
+ }
164
+ /**
165
+ * `onKeyDown` on the grid: called for EVERY key pressed inside the grid, in the
166
+ * capture phase at the grid's root — before the grid's own handling and before
167
+ * an open editor sees the key. Return `'handled'` and the grid does nothing with
168
+ * that key (the browser's own default is not prevented; call
169
+ * `event.preventDefault()` for that).
170
+ */
171
+ type GridKeyHook = (event: KeyboardEvent, ctx: GridKeyContext) => 'handled' | void;
172
+ type AnyKeyEvent = KeyboardEvent | {
173
+ nativeEvent: KeyboardEvent;
174
+ };
175
+ /** Remember that the app's hook took this key; every grid handler then skips it. */
176
+ declare function markKeyHandledByApp(event: AnyKeyEvent): void;
177
+ /**
178
+ * A character typed with AltGr (Alt+Ctrl on Windows). It is typing, not an Alt
179
+ * shortcut: it opens the editor like any other character.
180
+ */
181
+ declare function isAltGraphChar(event: AnyKeyEvent): boolean;
182
+ /**
183
+ * True when the grid must leave this key alone: the page already claimed it
184
+ * (`defaultPrevented`, read from the NATIVE event — React's copy is fixed when
185
+ * the event is created, and a capture listener on `window` runs first), the
186
+ * app's `onKeyDown` answered 'handled', or it is an Alt combination other than
187
+ * AltGr typing.
188
+ */
189
+ declare function gridIgnoresKey(event: AnyKeyEvent): boolean;
190
+ /**
191
+ * The page or the app's hook already took this key: an editor leaves it
192
+ * alone (no commit, no move, no `stopPropagation`).
193
+ */
194
+ declare function keyClaimed(event: AnyKeyEvent): boolean;
195
+ /**
196
+ * True when an open editor uses this key, so it must not reach the grid's (or
197
+ * the page's) shortcuts. F1-F12 and Ctrl/Cmd/Alt combinations a text box has no
198
+ * use for are NOT the editor's: they go on to the page (P-7.2), which is how an
199
+ * app's F2 "Save" or Ctrl+P still works while a cell is being typed in. Keys the
200
+ * page or the app's hook already took are not the editor's either.
201
+ */
202
+ declare function editorOwnsKey(event: AnyKeyEvent): boolean;
203
+ /**
204
+ * Elements that are part of an open editor (P-4). The grid puts it on the box
205
+ * it draws a column's `renderEditor` in; an app may put it on an editor's own
206
+ * popup or dialog. Focus moving into one is not "leaving the cell" (the P-10
207
+ * row send, `ctx.commitOnBlur`). Inside the grid, keys whose target is in one
208
+ * are the EDITOR's: the grid's own key handling (navigation, F2, Escape,
209
+ * typing-to-edit) leaves them alone; the app's `onKeyDown` hook still sees
210
+ * them. A key whose target is OUTSIDE the grid's DOM — an app dialog portaled
211
+ * to `<body>`, marked or not — is never the grid's (`eventFromOwnDom`).
212
+ */
213
+ declare const EDITOR_OWNED_SELECTOR = "[data-kanuni-editor]";
214
+ /** The grid's own popups (lookup list, calendar, menus, dialogs). */
215
+ declare const GRID_PORTAL_SELECTOR = ".kanuni-datagrid-portal, [data-kanuni-portal]";
216
+ /**
217
+ * Did this event start inside `currentTarget`'s DOM? React routes events from a
218
+ * portal through the COMPONENT tree: a dialog an app's custom editor opens
219
+ * (portaled to `<body>`) still bubbles through the cell, the row, the
220
+ * scroller and the grid root (P-4.7). Every grid handler asks this first and
221
+ * ignores events from outside its own subtree. `ownPortals`: also count the
222
+ * grid's own popups (they are portaled too, and are the grid's).
223
+ */
224
+ declare function eventFromOwnDom(event: {
225
+ currentTarget: EventTarget | null;
226
+ target: EventTarget | null;
227
+ }, ownPortals?: boolean): boolean;
228
+ /**
229
+ * Where focus may go and still be "in" the grid: the grid itself, one of its
230
+ * detached popups (date calendar, lookup list, dialogs) or an element the app
231
+ * marks as belonging to the open editor.
232
+ */
233
+ declare function focusStaysWithGrid(gridSelector: string, next: Element | null): boolean;
102
234
 
103
235
  declare function useStateStoring<TRow = GridRowData>(controller: DataGridController<TRow>, config: StateStoringConfig | undefined): void;
104
236
 
@@ -237,10 +369,70 @@ interface CellRenderContext<TRow = GridRowData> {
237
369
  interface HeaderRenderContext<TRow = GridRowData> {
238
370
  column: GridColumnDef<TRow>;
239
371
  }
372
+ /**
373
+ * Where focus goes after a custom editor commits (P-4.2):
374
+ * `'down'` — the cell below (what Enter does in the built-in editor);
375
+ * `'next'` / `'previous'` — the next / previous editable cell (Tab /
376
+ * Shift+Tab, wrapping to the next row like the built-in editor);
377
+ * `'none'` — stay on the cell (today's `commit()`).
378
+ * An explicit `move` wins over `editing.editKeys.enter`.
379
+ */
380
+ type EditorCommitMove = 'down' | 'next' | 'previous' | 'none';
381
+ interface EditorCommitOptions {
382
+ /** Default `'none'`. */
383
+ move?: EditorCommitMove;
384
+ }
385
+ /** Writes a custom editor may make to ITS row (P-4.3). */
386
+ interface EditorRowApi {
387
+ /**
388
+ * Write several fields of the editor's row in ONE step — a picker writing
389
+ * code, name and id together: one undo step, one validation pass, one save
390
+ * in `cell` mode, pending in `batch`. All or nothing: `editable: false`
391
+ * columns ARE written (that flag only stops the user typing), a row lock
392
+ * (`allowUpdating` refusing the row/column) or a failing rule writes none
393
+ * and answers false. The editor stays open; if its own column is among the
394
+ * fields it shows the new value. Same as `EditingApi.setRowValues(rowKey, …)`.
395
+ */
396
+ setRowValues(values: Readonly<Record<string, unknown>>): boolean;
397
+ }
240
398
  /**
241
399
  * What a custom editor is handed. `commit`/`cancel` are the SAME handles the
242
400
  * built-in editor uses, so a replacement participates in Tab-walking, batch
243
401
  * changes and undo rather than living beside them.
402
+ *
403
+ * **The custom editor contract (P-4)** — what the grid does around a
404
+ * `renderEditor`:
405
+ *
406
+ * - The editor is drawn inside a box the grid owns, marked
407
+ * `data-kanuni-editor` (`display: contents`, so it does not change the
408
+ * layout). Keys whose target is inside it are the editor's: the grid does
409
+ * not navigate, open, or type-to-edit on them. Two exceptions, both only
410
+ * when the editor's own handler did not call `event.preventDefault()`:
411
+ * **Escape** cancels the editor (`cancel()`), and **Tab / Shift+Tab** walk
412
+ * the focusable elements INSIDE the box (text box → "…" button) and only
413
+ * past the last (first) one commit and move to the next (previous) cell —
414
+ * `commit({ move: 'next' })`. Enter is left to the editor: call
415
+ * `commit({ move: 'down' })` from it for the built-in behaviour. The
416
+ * editor's own shortcuts (F4, Alt+ArrowDown for its "…" button) are never
417
+ * taken by the grid.
418
+ * - Events from OUTSIDE the grid's DOM — a dialog the editor opens in a
419
+ * portal (Radix `Dialog`, a `<dialog>` under `<body>`) — never reach the
420
+ * grid's handlers, although React routes them through the editor's
421
+ * component tree: Enter, arrows, PageUp/PageDown, Space, Escape, Tab, F2,
422
+ * Insert, Ctrl+Delete, Ctrl+Z, clicks and double-clicks in that dialog
423
+ * change nothing in the grid or the editor session — also when the dialog
424
+ * holds another KanuniLabs grid. Escape in the dialog closes the dialog (its
425
+ * own business); a second Escape, back in the editor, cancels the editor.
426
+ * - Blur: the grid does not commit a custom editor on blur by itself. Put
427
+ * `onBlur={ctx.commitOnBlur}` on the editor's root element to commit when
428
+ * focus leaves it the way the built-in editors do. While a dialog of the
429
+ * editor is open call `suspendBlurCommit(true)` (before it takes focus) and
430
+ * `suspendBlurCommit(false)` when it closes: in between, neither
431
+ * `commitOnBlur` nor `commitOn: 'row'`'s "focus left the grid" send runs.
432
+ * - Focus: after `commit()` / `cancel()` focus goes to the grid's scroller
433
+ * (the keyboard keeps working); after `suspendBlurCommit(false)` focus that
434
+ * fell to `<body>` (the dialog's opener is gone) goes back to the editor, or
435
+ * to the scroller when the editor has closed.
244
436
  */
245
437
  interface EditorRenderContext<TRow = GridRowData> {
246
438
  /** Current (uncommitted) editor value. */
@@ -248,11 +440,45 @@ interface EditorRenderContext<TRow = GridRowData> {
248
440
  /** The row with pending edits applied — what a cascading list should read. */
249
441
  row: TRow;
250
442
  columnId: string;
443
+ /** Key of the edited row. */
444
+ rowKey: RowKey;
251
445
  /** Validation message for `value`, or null. */
252
446
  error: string | null;
447
+ /** True while `error` is set — for `aria-invalid`. */
448
+ invalid: boolean;
449
+ /**
450
+ * Id of an element holding `error` while there is one (screen-reader text
451
+ * the grid draws next to the editor) — for `aria-errormessage` /
452
+ * `aria-describedby`. Draw the message visibly yourself. Undefined when
453
+ * there is no error.
454
+ */
455
+ errorId: string | undefined;
456
+ /** The column's header text — for the editor's `aria-label`. */
457
+ ariaLabel: string;
253
458
  setValue: (value: unknown) => void;
254
- commit: () => void;
459
+ /**
460
+ * Commit the value. False when a rule refused it (the editor stays open).
461
+ * Without options it stays on the cell, as always.
462
+ */
463
+ commit: (options?: EditorCommitOptions) => boolean;
255
464
  cancel: () => void;
465
+ /**
466
+ * While on, losing focus is not leaving the editor: `commitOnBlur` and the
467
+ * `commitOn: 'row'` send on "focus left the grid" wait. Turn it on before a
468
+ * dialog of the editor takes focus, off when the dialog closes. Ends by
469
+ * itself when the editor closes. No-op in the row form.
470
+ */
471
+ suspendBlurCommit: (on: boolean) => void;
472
+ /**
473
+ * A `focusout` handler for the editor's root element: commits (staying on
474
+ * the cell, focus left where the user put it) once focus has gone somewhere
475
+ * that is not part of the editor — not inside its box, not one of the
476
+ * grid's popups, not an element marked `data-kanuni-editor` — unless
477
+ * `suspendBlurCommit(true)` is on. Optional to use.
478
+ */
479
+ commitOnBlur: (event: FocusEvent) => void;
480
+ /** Writes to this row (`setRowValues`). */
481
+ api: EditorRowApi;
256
482
  }
257
483
  /**
258
484
  * What a column's own filter UI is handed (`renderFilter`). `value` is the
@@ -479,6 +705,61 @@ interface RowTemplateContext<TRow = GridRowData> {
479
705
  /** True when this is the focused row (`focusedRow` is on). */
480
706
  focused: boolean;
481
707
  }
708
+ /** What `cardView.renderCard` draws one card from (P-9). */
709
+ interface CardRenderContext<TRow = GridRowData> {
710
+ /** The row as the user sees it — pending (unsaved) values included. */
711
+ row: TRow;
712
+ node: DataRowNode<TRow>;
713
+ /**
714
+ * The default card's fields, in order (the first is the title): each
715
+ * column's header and the TEXT its closed cell shows — formatter, number
716
+ * format and lookup label included (a function list's label too; empty
717
+ * while that list is still loading).
718
+ */
719
+ fields: CardField[];
720
+ selected: boolean;
721
+ /** The row's save status (`rowStatus`), or null. The grid draws its marker either way. */
722
+ status: RowSaveStatus | null;
723
+ }
724
+ /**
725
+ * `cardView` options of the React grids (P-9): the shared ones
726
+ * ({@link CardViewOptions}: `breakpoint`, `columns`) plus the card as a tap
727
+ * target.
728
+ */
729
+ interface DataGridCardViewOptions<TRow = GridRowData> extends CardViewOptions {
730
+ /**
731
+ * A card was pressed — tapped, or clicked with a mouse. A touch that moves
732
+ * more than 10 px (a scroll, a swipe) is not a press. Called after the grid
733
+ * has made the row the focused one (so `onFocusedRowChanged` has already
734
+ * fired for it) and before `edit: 'popup'` opens it. `event.preventDefault()`
735
+ * keeps the popup closed.
736
+ */
737
+ onCardPress?: (rowKey: RowKey, node: DataRowNode<TRow>, event: MouseEvent<HTMLElement>) => void;
738
+ /**
739
+ * Draw a card's content yourself. The grid keeps the card's box — its
740
+ * height, the press, selection, the `rowStatus` marker and `rowClassName`
741
+ * on the row element — and puts what this returns inside it. Cards are
742
+ * virtualised like rows, so every card is `height` pixels tall: give
743
+ * `height` when your card is not the default card's height.
744
+ */
745
+ renderCard?: (ctx: CardRenderContext<TRow>) => ReactNode;
746
+ /**
747
+ * Height of every card in pixels. Default: the default card's height for
748
+ * its field count (title 22 px, 20 px a line, 21 px of padding; at least 44
749
+ * — a touch target).
750
+ */
751
+ height?: number;
752
+ /**
753
+ * `'popup'`: pressing a card on an editing grid opens its row in the edit
754
+ * dialog (the `editing.mode: 'popup'` form), whatever `editing.mode` is.
755
+ * Save follows the mode: `batch` keeps the values pending for the batch
756
+ * Save, `cell` writes them into the row and sends the row once (also under
757
+ * `commitOn: 'row'` — closing the form is leaving the row), a row mode saves
758
+ * the row. Cancel puts the row back as it was when the dialog opened.
759
+ * The dialog stays open when the grid widens back into a table.
760
+ */
761
+ edit?: 'popup';
762
+ }
482
763
  /** What a header menu is opened against. */
483
764
  interface HeaderMenuContext {
484
765
  columnId: string;
@@ -535,11 +816,28 @@ interface DataGridEditingOptions<TRow = GridRowData> {
535
816
  formHeight?: number;
536
817
  /** Typing a printable character on a focused cell opens its editor. Default true. */
537
818
  editOnKeyPress?: boolean;
819
+ /**
820
+ * Which gestures open an editor (P-7.1): `{ f2, enter, typing, doubleClick }`.
821
+ * Each one left out keeps today's behaviour (`f2: true, enter: false,
822
+ * typing: true, doubleClick: true`). See `EditKeys`.
823
+ */
824
+ editKeys?: EditKeys;
538
825
  /** Tab moves between cells inside the grid instead of leaving it. Default true. */
539
826
  focusCellOnTab?: boolean;
540
827
  /** Tab past the last editable cell of a row wraps to the next row. Default true. */
541
828
  focusCellOnCycle?: boolean;
542
829
  }
830
+ /** What `rowClassName` is told about a row (P-8). */
831
+ interface RowClassNameContext<TRow = GridRowData> {
832
+ /** The row as it shows: with an editing grid's pending (unsaved) values. */
833
+ row: TRow;
834
+ node: DataRowNode<TRow>;
835
+ rowKey: RowKey;
836
+ /** Its save state (`new`, `changed`, `removed`, `saving`, `saved`, `error`), or null. */
837
+ status: RowSaveStatus | null;
838
+ /** 0-based position in the displayed rows (pinned rows: in their own block). */
839
+ index: number;
840
+ }
543
841
  interface DataGridProps<TRow = GridRowData> extends Omit<DataGridCoreConfig<TRow>, 'columns'> {
544
842
  /**
545
843
  * Optional: with an ARRAY data source and no columns, one column per field
@@ -681,6 +979,21 @@ interface DataGridProps<TRow = GridRowData> extends Omit<DataGridCoreConfig<TRow
681
979
  loadingOverlay?: boolean | number;
682
980
  /** Fired on Enter / double-click over the focused row. */
683
981
  onRowActivate?: (node: RowNode<TRow>) => void;
982
+ /**
983
+ * Called for EVERY key pressed inside the grid (P-7.2), in the capture phase
984
+ * at the grid's root: before the grid's own handling and before an open
985
+ * cell editor sees the key — so it also gets F2 while a cell is being typed
986
+ * in. `ctx` says whether an editor is open, which cell the key is about,
987
+ * whether that row is new, and can `commit()` the value being typed or
988
+ * `cancel()` it. Return `'handled'` and the grid does nothing with the key
989
+ * (the browser's own default is not prevented; call `event.preventDefault()`
990
+ * for that).
991
+ *
992
+ * The grid also leaves alone any key whose `defaultPrevented` is already
993
+ * true when it arrives (a page listener on `window` took it) and every Alt
994
+ * combination except AltGr typing. Default: not called.
995
+ */
996
+ onKeyDown?: GridKeyHook;
684
997
  /** Announcements for screen readers (sort/filter/selection). Defaults on. */
685
998
  announcements?: boolean;
686
999
  /** Drop area above the grid for grouping by a column. */
@@ -826,8 +1139,12 @@ interface DataGridProps<TRow = GridRowData> extends Omit<DataGridCoreConfig<TRow
826
1139
  *
827
1140
  * `columns` picks the fields and their order (the first is the title);
828
1141
  * default: the visible columns.
1142
+ *
1143
+ * A card is a tap target (P-9): `onCardPress` hears it, `renderCard` draws
1144
+ * the card's content yourself, and on an editing grid `edit: 'popup'` opens
1145
+ * the row in the edit dialog. See {@link DataGridCardViewOptions}.
829
1146
  */
830
- cardView?: boolean | CardViewOptions;
1147
+ cardView?: boolean | DataGridCardViewOptions<TRow>;
831
1148
  /**
832
1149
  * The grid switched between cards and the table (`cardView`), as its width
833
1150
  * crossed the breakpoint. `true` while cards are shown.
@@ -978,6 +1295,19 @@ interface DataGridProps<TRow = GridRowData> extends Omit<DataGridCoreConfig<TRow
978
1295
  * range selection, fill and paste are `EnterpriseDataGrid`.
979
1296
  */
980
1297
  editing?: DataGridEditingOptions<TRow>;
1298
+ /**
1299
+ * A class name for a whole data row (P-8), from the row itself: one rule
1300
+ * for every column instead of a `cellClassName` per column ("a return line
1301
+ * reads red"). Added to the row element beside the grid's own classes
1302
+ * (`rowStatus`, selection, odd/even); return `undefined` or `''` for none.
1303
+ *
1304
+ * Asked for every rendered row on every render, so it follows edits (with
1305
+ * pending values — `row` is what the row shows), `refreshCells()` and
1306
+ * scrolling without being told. Keep it cheap. Data rows only: group,
1307
+ * detail and message rows are not asked. Card view: the class lands on the
1308
+ * card's row element too.
1309
+ */
1310
+ rowClassName?: (ctx: RowClassNameContext<TRow>) => string | undefined;
981
1311
  /** Replace a cell's content (e.g. with an editor). Return undefined for default. */
982
1312
  renderCellContent?: (ctx: CellSlotContext<TRow>) => ReactNode | undefined;
983
1313
  /** Extra class names per cell (dirty marker, range highlight, invalid). */
@@ -1039,6 +1369,12 @@ interface DataGridProps<TRow = GridRowData> extends Omit<DataGridCoreConfig<TRow
1039
1369
  * position and height come from `controller.setEditFormRow`.
1040
1370
  */
1041
1371
  renderEditForm?: (rowKey: RowKey, row: TRow | undefined) => ReactNode;
1372
+ /**
1373
+ * Open a row in the edit dialog from a card (`cardView.edit: 'popup'`, P-9).
1374
+ * Set by `EnterpriseDataGrid`, which owns its editing layer; the free grid
1375
+ * uses its own `editing` when this is left empty. False when nothing opened.
1376
+ */
1377
+ openCardEditor?: (rowKey: RowKey) => boolean;
1042
1378
  }
1043
1379
  interface CellSlotContext<TRow = GridRowData> {
1044
1380
  node: RowNode<TRow>;
@@ -1168,6 +1504,41 @@ interface GridHeaderBandsProps<TRow = GridRowData> {
1168
1504
  declare function GridHeaderBandsImpl<TRow = GridRowData>({ layout, centerColumns, leadingSpacer, trailingSpacer, depth, checkboxColumn, detailColumn, statusColumn, rowNumberColumn, rowHeight, bandFold, }: GridHeaderBandsProps<TRow>): react.JSX.Element | null;
1169
1505
  declare const GridHeaderBands: typeof GridHeaderBandsImpl;
1170
1506
 
1507
+ /** What `label()` answers while the list is still being fetched. */
1508
+ declare const LOOKUP_PENDING: unique symbol;
1509
+ declare class LookupLabels<TRow = GridRowData> {
1510
+ private readonly controller;
1511
+ /** Lists per lookup definition, by row + `dependsOn` values. */
1512
+ private readonly lists;
1513
+ /** The label each cell last showed, by row + column: the no-flicker fallback. */
1514
+ private readonly shown;
1515
+ private repaintQueued;
1516
+ /**
1517
+ * The row WITH pending edits (batch mode keeps them out of the data), so a
1518
+ * child list follows a parent the user changed but has not saved. Set by
1519
+ * the grid on every render.
1520
+ */
1521
+ effectiveRow: ((rowKey: RowKey) => unknown) | null;
1522
+ constructor(controller: DataGridController<TRow>);
1523
+ private key;
1524
+ private repaint;
1525
+ /**
1526
+ * The list for this row: an array when known, the promise while it is not.
1527
+ * Called through the cache — the same row and `dependsOn` values never call
1528
+ * `items` twice — except with `fresh` (a list without `dependsOn`, opened in
1529
+ * the editor: it may read anything, so it is asked again, as before).
1530
+ */
1531
+ items(lookup: ColumnLookup<TRow>, row: TRow, rowKey: RowKey, fresh?: boolean): readonly LookupItem[] | Promise<readonly LookupItem[]>;
1532
+ /**
1533
+ * A FUNCTION lookup's label for a cell: the label, `LOOKUP_PENDING` while
1534
+ * the list is in flight, or null when the column is not a function lookup
1535
+ * or the value is not in the list (the caller falls through to the value).
1536
+ */
1537
+ label(def: GridColumnDef<TRow> | undefined, columnId: string, value: unknown, storedRow: TRow, rowKey: RowKey): string | null | typeof LOOKUP_PENDING;
1538
+ }
1539
+ /** The one label cache of this grid. */
1540
+ declare function lookupLabelsFor<TRow>(controller: DataGridController<TRow>): LookupLabels<TRow>;
1541
+
1171
1542
  interface GridRowProps<TRow = GridRowData> {
1172
1543
  /** Used to build stable cell ids for aria-activedescendant. */
1173
1544
  gridId: string;
@@ -1254,6 +1625,10 @@ interface GridRowProps<TRow = GridRowData> {
1254
1625
  rowStatusText?: string;
1255
1626
  /** `rowStatus.tint`: wash the whole row, not only the marker. */
1256
1627
  rowStatusTint?: boolean;
1628
+ /** `rowStatus.strike`: strike through a `'removed'` row's text (P-2). */
1629
+ rowStatusStrike?: boolean;
1630
+ /** The app's `rowClassName` for this row (P-8), already resolved: a primitive, so memo holds. */
1631
+ rowClass?: string;
1257
1632
  /** Renders the leading checkbox cell. */
1258
1633
  checkboxColumn: boolean;
1259
1634
  /** Renders the leading row-number cell (gap analysis P3.5). */
@@ -1348,6 +1723,12 @@ interface GridRowProps<TRow = GridRowData> {
1348
1723
  * when it does not, they do not.
1349
1724
  */
1350
1725
  searchNeedle?: string;
1726
+ /**
1727
+ * The grid's cache of FUNCTION lookup lists (P-5.1): a closed cell shows the
1728
+ * label, not the raw code. One stable object per grid; when a list arrives
1729
+ * it calls `refreshCells()`, which moves `revision`.
1730
+ */
1731
+ lookupLabels?: LookupLabels<TRow>;
1351
1732
  /** Aggregate definitions rendered inside group headers (Enterprise). */
1352
1733
  summaryDefs?: readonly SummaryDef<TRow>[];
1353
1734
  /** Render a leading expander cell for master-detail (Enterprise). */
@@ -1381,7 +1762,7 @@ interface GridRowProps<TRow = GridRowData> {
1381
1762
  onCellPointerEnter?: (ctx: CellSlotContext<TRow>, event: React.MouseEvent) => void;
1382
1763
  onCellDoubleClick?: (ctx: CellSlotContext<TRow>) => void;
1383
1764
  }
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;
1765
+ 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
1766
  declare const GridRow: typeof GridRowImpl;
1386
1767
 
1387
1768
  interface GridFilterRowProps<TRow = GridRowData> {
@@ -2010,8 +2391,10 @@ interface GridPinnedRowsProps<TRow = GridRowData> {
2010
2391
  * rows have to move down to make room. `DataGrid` does both from one count.
2011
2392
  */
2012
2393
  ariaRowBase: number;
2394
+ /** The app's `rowClassName` (P-8), resolved by `DataGrid`; `userKey` is the data row's key for a user-pinned row. */
2395
+ rowClassFor?: (node: DataRowNode<TRow>, index: number, userKey: RowKey | null) => string | undefined;
2013
2396
  }
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;
2397
+ 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
2398
  declare const GridPinnedRows: typeof GridPinnedRowsImpl;
2016
2399
 
2017
2400
  type UseDataGridOptions<TRow = GridRowData> = DataGridCoreConfig<TRow>;
@@ -2111,6 +2494,14 @@ declare function GridTextProvider({ locale, messages, children }: GridTextProvid
2111
2494
  /** The resolved dictionary. Stable between language changes. */
2112
2495
  declare function useGridText(): GridDictionary;
2113
2496
 
2497
+ /**
2498
+ * Text an editor opens with when the typed character is not a value yet
2499
+ * (P-3.6): `-` or `,` on a number cell, a digit on a date cell. Keyed by the
2500
+ * engine's edit SESSION object, so it belongs to that one opening; the session
2501
+ * itself keeps the cell's value until the editor reports a complete one, which
2502
+ * is what makes "-" followed by Enter change nothing.
2503
+ */
2504
+ declare const editorSeedText: WeakMap<object, string>;
2114
2505
  interface UseGridEditingOptions<TRow = GridRowData> {
2115
2506
  controller: DataGridController<TRow> | null;
2116
2507
  mode?: EditMode;
@@ -2128,13 +2519,42 @@ interface UseGridEditingOptions<TRow = GridRowData> {
2128
2519
  /** Typing a printable key on a focused cell starts editing. Default true. */
2129
2520
  editOnKeyPress?: boolean;
2130
2521
  /**
2131
- * `Insert` opens a blank row ABOVE the focused one. Default false.
2522
+ * `Insert` opens a blank row next to the focused one: `true` or `'above'`
2523
+ * above it, `'below'` under it. Default false (off).
2132
2524
  *
2133
2525
  * Off by default because Insert is not a neutral key: some users have it
2134
2526
  * bound elsewhere, and a grid that starts creating records on a keypress
2135
- * nobody asked for is a surprise.
2527
+ * nobody asked for is a surprise. When on, the key is the grid's whenever a
2528
+ * cell has focus: it is `preventDefault()`ed even when no row can be added,
2529
+ * so a page-level Insert shortcut does not fire for it (P-7.5).
2530
+ */
2531
+ insertKey?: boolean | 'above' | 'below';
2532
+ /**
2533
+ * Which gestures open an editor (P-7.1): `f2`, `enter`, `typing`,
2534
+ * `doubleClick`. Each left out keeps today's behaviour.
2535
+ */
2536
+ editKeys?: EditKeys;
2537
+ /**
2538
+ * Tab on the last editable cell of the last row adds a blank row and moves
2539
+ * to its first editable cell (P-7.8). Shift+Tab never adds one and stays on
2540
+ * the first cell. Needs `allowAdding`. Default false.
2136
2541
  */
2137
- insertKey?: boolean;
2542
+ appendOnTab?: boolean;
2543
+ /**
2544
+ * Ctrl+Delete (Cmd+Delete) deletes the focused row (P-7.5): `allowDeleting`,
2545
+ * then the `confirmDelete` FUNCTION is asked; without a function nothing is
2546
+ * deleted. On a row already marked removed (`batch`) it restores it. Not
2547
+ * while an editor is open (the key is the text box's). Default false.
2548
+ */
2549
+ deleteKey?: boolean;
2550
+ /** Ctrl+D / Ctrl+R fill down / right over the selection. Default true. */
2551
+ fillKeys?: boolean;
2552
+ /**
2553
+ * Ctrl+V over several selected cells spreads a copied table over them.
2554
+ * Default true. `false`: the paste goes to the focused cell only and the
2555
+ * clipboard text is ONE value (tabs and line breaks do not split it).
2556
+ */
2557
+ rangePaste?: boolean;
2138
2558
  /**
2139
2559
  * Arrow-down on the LAST row appends a blank one. Default false.
2140
2560
  *
@@ -2186,6 +2606,26 @@ interface UseGridEditingOptions<TRow = GridRowData> {
2186
2606
  * columns read-only — those editors are Enterprise.
2187
2607
  */
2188
2608
  canEditColumn?: (columnId: string) => boolean;
2609
+ /**
2610
+ * Called ONCE when the grid's editing is ready, with the `EditingApi` (P-1)
2611
+ * — the same object `controller.editing` returns while the grid is mounted.
2612
+ * Not called again for a React StrictMode remount or a re-render; the object
2613
+ * stays valid across both and turns into a harmless no-op after unmount.
2614
+ */
2615
+ onReady?: (api: EditingApi<TRow>) => void;
2616
+ /**
2617
+ * `cell` mode: save each committed cell at once (`'cell'`, default) or the
2618
+ * whole row once the user leaves it (`'row'`, P-10) — to another row by any
2619
+ * key or click, or out of the grid. A new row left empty is dropped, never
2620
+ * sent. Ignored by the other modes.
2621
+ */
2622
+ commitOn?: CommitOn;
2623
+ /**
2624
+ * The grid shows a refused save's reason under the row (`rowStatus.messages`).
2625
+ * With `commitOn: 'row'` a row refused on leave is then reported there only,
2626
+ * not also in the "cannot save" dialog. Default false.
2627
+ */
2628
+ rowMessages?: boolean;
2189
2629
  }
2190
2630
  /**
2191
2631
  * What the footer strip shows for the current range.
@@ -2240,13 +2680,21 @@ interface UseGridEditingResult<TRow = GridRowData> {
2240
2680
  range: RangeApi;
2241
2681
  /** Bumped on every engine change; consumers read through it. */
2242
2682
  version: number;
2683
+ /**
2684
+ * The app-facing editing API (P-1): one object for the life of this hook,
2685
+ * forwarding to the current engine — see `EditingApi`.
2686
+ */
2687
+ api: EditingApi<TRow>;
2243
2688
  beginEdit: (rowKey: RowKey, columnId: string) => void;
2244
2689
  /**
2245
2690
  * Open a whole ROW (row / form / popup modes). False when the mode does not
2246
2691
  * support it, or another row is already open — the caller decides what to
2247
2692
  * do with the first one rather than having it saved or discarded silently.
2693
+ * `standalone`: in any mode — a card's popup (P-9; see the engine).
2248
2694
  */
2249
- beginRowEdit: (rowKey: RowKey) => boolean;
2695
+ beginRowEdit: (rowKey: RowKey, options?: {
2696
+ standalone?: boolean;
2697
+ }) => boolean;
2250
2698
  /** Validate and persist the open row. Resolves false and stays open on failure. */
2251
2699
  saveRowEdit: () => Promise<boolean>;
2252
2700
  /** Discard the open row's edits. Other rows keep theirs. */
@@ -2259,7 +2707,44 @@ interface UseGridEditingResult<TRow = GridRowData> {
2259
2707
  * `beforeKey` puts it directly above that row instead of at the end — what
2260
2708
  * the Insert key needs.
2261
2709
  */
2262
- addRow: (values?: Record<string, unknown>, beforeKey?: RowKey) => RowKey | null;
2710
+ addRow: (values?: Record<string, unknown>, beforeKey?: RowKey, options?: {
2711
+ open?: boolean;
2712
+ position?: NewRowPosition;
2713
+ }) => RowKey | null;
2714
+ /**
2715
+ * The built-in cell editor's commit (Enter, blur, a picked item), shared by
2716
+ * both renderers. `'down'` moves to the cell below afterwards — unless
2717
+ * `editKeys.enter` is on, where Enter stays on the cell (P-7.1). `'blur'`:
2718
+ * focus has already gone where the user put it, so it is not pulled back to
2719
+ * the grid (P-10: a click on a field outside the grid must keep that field).
2720
+ */
2721
+ commitCellEditor: (move: 'down' | 'none' | 'blur') => void;
2722
+ /**
2723
+ * A custom editor's commit (`renderEditor`'s `ctx.commit`, P-4.2): `'none'`
2724
+ * stays on the cell, `'down'` moves down (whatever `editKeys.enter` says —
2725
+ * the editor asked), `'next'` / `'previous'` walk to the adjacent editable
2726
+ * cell like Tab, `'blur'` leaves focus where it is. False when a rule
2727
+ * refused the value.
2728
+ */
2729
+ commitCustomEditor: (move: 'down' | 'next' | 'previous' | 'none' | 'blur') => boolean;
2730
+ /**
2731
+ * `ctx.suspendBlurCommit` (P-4.1): while on, blur is not leaving the editor
2732
+ * (`ctx.commitOnBlur`, the `commitOn: 'row'` send). Turning it off puts focus
2733
+ * that fell to `<body>` back on the editor (`restoreTo`), else the scroller.
2734
+ */
2735
+ suspendBlurCommit: (on: boolean, restoreTo?: () => HTMLElement | null) => void;
2736
+ /** True while a custom editor's dialog holds `suspendBlurCommit(true)`. */
2737
+ blurCommitSuspended: () => boolean;
2738
+ /** What the app's `onKeyDown` hook is told (P-7.2). */
2739
+ keyContext: () => GridKeyContext;
2740
+ /** `editKeys.doubleClick` — a double-click / double-tap opens an editor. */
2741
+ doubleClickEdits: boolean;
2742
+ /**
2743
+ * Close the open cell editor without keeping its value and give focus back
2744
+ * to the grid (the editors' Escape). Under `commitOn: 'row'` a new row left
2745
+ * empty by it is dropped, never sent (P-10).
2746
+ */
2747
+ cancelCellEdit: () => void;
2263
2748
  /**
2264
2749
  * Commit and move to the next (1) or previous (-1) editable cell. By default
2265
2750
  * the destination is only FOCUSED; pass `open: true` to carry the editor
@@ -2355,6 +2840,12 @@ interface UseEditModesOptions<TRow = GridRowData> {
2355
2840
  * default batch mode saves from the command column) and passes that here.
2356
2841
  */
2357
2842
  batchBar?: boolean;
2843
+ /**
2844
+ * Cards are shown with `cardView.edit: 'popup'` (P-9): an open row session
2845
+ * of a row mode — opened in the table before the grid narrowed — is drawn
2846
+ * as the popup, the one editor a card view has.
2847
+ */
2848
+ cardPopup?: boolean;
2358
2849
  }
2359
2850
  interface EditModes<TRow = GridRowData> {
2360
2851
  /** A row mode (row / form / popup) is in force and drawn. */
@@ -2381,6 +2872,11 @@ interface EditModes<TRow = GridRowData> {
2381
2872
  editRowMenuItem: <TContext>(rowKey: RowKey) => GridMenuItem<TContext> | null;
2382
2873
  /** Open a row (double-click in a row mode). False when not a row mode. */
2383
2874
  openRow: (rowKey: RowKey) => boolean;
2875
+ /**
2876
+ * Open a row in the popup from a card (`cardView.edit: 'popup'`, P-9), in
2877
+ * any mode. False when it cannot be opened (locked, removed, another row open).
2878
+ */
2879
+ openCardEditor: (rowKey: RowKey) => boolean;
2384
2880
  }
2385
2881
  /**
2386
2882
  * The columns a record's form offers, in the grid's own order.
@@ -2394,7 +2890,7 @@ interface EditModes<TRow = GridRowData> {
2394
2890
  * them out).
2395
2891
  */
2396
2892
  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>;
2893
+ 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
2894
 
2399
2895
  interface GridRowEditorProps<TRow = GridRowData> {
2400
2896
  controller: DataGridController<TRow>;
@@ -2414,6 +2910,100 @@ interface GridRowEditorProps<TRow = GridRowData> {
2414
2910
  }
2415
2911
  declare function GridRowEditor<TRow = GridRowData>({ controller, engine, columnId, message, saving, lookupOptions, onSave, onCancel, }: GridRowEditorProps<TRow>): react.JSX.Element;
2416
2912
 
2913
+ type ResolvedNumberFormat = ColumnNumberFormat & {
2914
+ locale: string;
2915
+ };
2916
+ /**
2917
+ * The column's `numberFormat` when its editor is the number TEXT box — not
2918
+ * for a lookup, a custom editor or a formula column, which own their value.
2919
+ */
2920
+ declare function numberTextFormat(def: {
2921
+ numberFormat?: ColumnNumberFormat;
2922
+ lookup?: unknown;
2923
+ renderEditor?: unknown;
2924
+ allowFormulas?: boolean;
2925
+ } | undefined): ResolvedNumberFormat | undefined;
2926
+
2927
+ interface GridLookupEditorProps {
2928
+ options: readonly LookupItem[];
2929
+ value: unknown;
2930
+ /** Prefix (default) or substring — for the label (the name of a `linked` list). */
2931
+ matchMode?: LookupMatchMode;
2932
+ /** How typed text matches a `linked` list's code (`value`). Default `'startsWith'`. */
2933
+ codeMatchMode?: LookupMatchMode;
2934
+ /**
2935
+ * A code + name list (`lookup.linkedColumns`, P-5.2): each item shows its
2936
+ * code (`value`) and name (`label`), typing matches either, and the box
2937
+ * shows the code.
2938
+ */
2939
+ linked?: boolean;
2940
+ /** Let text that matches nothing become the value. Default false. */
2941
+ allowCustom?: boolean;
2942
+ /**
2943
+ * Complete typed text to the one item left / an exact label on leaving.
2944
+ * Default true. False: the "pick from the list" rule (K-3, see the top).
2945
+ */
2946
+ autoCompleteSingle?: boolean;
2947
+ /**
2948
+ * Typed text that picks nothing (closed list): Enter keeps the editor open
2949
+ * and announces it either way; Tab stays (`'keep-open'`, default) or drops
2950
+ * the text and moves on (`'revert'`).
2951
+ */
2952
+ onNoMatch?: 'revert' | 'keep-open';
2953
+ /**
2954
+ * Picking an item writes it: answer true when written. Left out, a pick is
2955
+ * `onChange(item.value)`. A code + name pick writes several columns in one
2956
+ * step through this (P-5.2); false (a locked row) keeps the editor open.
2957
+ */
2958
+ onPick?: (item: LookupItem) => boolean;
2959
+ invalid?: boolean;
2960
+ /**
2961
+ * Take focus on mount. True for a cell editor — it opened BECAUSE the user
2962
+ * asked to edit that one cell. False in `row` mode, where every editable cell
2963
+ * mounts an editor at once and each would grab focus in turn, landing the
2964
+ * caret on whichever lookup happened to render last.
2965
+ */
2966
+ autoFocus?: boolean;
2967
+ testId?: string;
2968
+ /** Stamped as `data-column-id`, so callers can find one field of a row. */
2969
+ columnId?: string;
2970
+ ariaLabel?: string;
2971
+ onChange: (value: unknown) => void;
2972
+ /** Commit (Enter / picking an item), handed back to the engine. */
2973
+ onCommit: () => void;
2974
+ /**
2975
+ * Whether picking an item counts as committing. True for a cell editor —
2976
+ * the pick IS the edit. False in `row`/`form` mode, where picking fills one
2977
+ * field of a record the user is still filling in and only Save ends it.
2978
+ */
2979
+ commitOnPick?: boolean;
2980
+ onCancel: () => void;
2981
+ /** Tab moves to the adjacent cell; the engine owns that. */
2982
+ onTab?: (shiftKey: boolean) => void;
2983
+ /**
2984
+ * Focus left the box for somewhere that is not its list: commit (the cell
2985
+ * editor's click-away, P-10). Left out (row mode, the form), a blur only
2986
+ * settles the typed text, as before.
2987
+ */
2988
+ onBlurCommit?: () => void;
2989
+ }
2990
+ /**
2991
+ * The same match, as items. Kept for callers and tests that want the simple
2992
+ * shape; the component itself works in indices to avoid the copy.
2993
+ */
2994
+ declare function matchOptions(options: readonly LookupItem[], query: string, mode: LookupMatchMode): readonly LookupItem[];
2995
+ /** The editor's settings that come straight from a column's `lookup`. */
2996
+ type LookupEditorSettings = Pick<GridLookupEditorProps, 'matchMode' | 'codeMatchMode' | 'linked' | 'allowCustom' | 'autoCompleteSingle' | 'onNoMatch'>;
2997
+ /** `lookup` → the editor's props, one reading for the cell, row and form editors. */
2998
+ declare function lookupEditorSettings(lookup: ColumnLookup<never> | undefined): LookupEditorSettings;
2999
+ /**
3000
+ * What one pick writes to the row (P-5.2 / P-5.3): the column's own value,
3001
+ * `linkedColumns`' code / name / id, then `map`. Null when the column has
3002
+ * neither — a plain pick, one cell, as before.
3003
+ */
3004
+ declare function lookupPickValues(lookup: ColumnLookup<never> | undefined, columnId: string, item: LookupItem): Record<string, unknown> | null;
3005
+ declare function GridLookupEditor({ options, value, matchMode, codeMatchMode, linked, allowCustom, autoCompleteSingle, onNoMatch, onPick, invalid, autoFocus, testId, columnId, ariaLabel, onChange, onCommit, commitOnPick, onCancel, onTab, onBlurCommit, }: GridLookupEditorProps): react.JSX.Element;
3006
+
2417
3007
  interface GridCellEditorProps {
2418
3008
  value: unknown;
2419
3009
  dataType: GridDataType | undefined;
@@ -2427,6 +3017,13 @@ interface GridCellEditorProps {
2427
3017
  allowCustom?: boolean;
2428
3018
  /** How typed text narrows the lookup list. Default `'startsWith'`. */
2429
3019
  matchMode?: LookupMatchMode;
3020
+ /**
3021
+ * The rest of the column's `lookup` as the combo box reads it (P-5 / P-6):
3022
+ * code + name, K-3, `onNoMatch`. Wins over `allowCustom` / `matchMode`.
3023
+ */
3024
+ lookupSettings?: LookupEditorSettings;
3025
+ /** A pick that writes more than this cell (code + name, `map`): true when written. */
3026
+ onPick?: (item: LookupItem) => boolean;
2430
3027
  /** Accessible name for the editor, used by the lookup combo box. */
2431
3028
  ariaLabel?: string;
2432
3029
  /** Format for a `date` column — governs both the mask and the display. */
@@ -2439,13 +3036,31 @@ interface GridCellEditorProps {
2439
3036
  * make the second keystroke erase the first.
2440
3037
  */
2441
3038
  seeded?: boolean;
3039
+ /**
3040
+ * The editor was opened by typing a character that is not a value yet
3041
+ * (P-3.6): `-` or `,` on a number cell, a digit on a date cell. The box
3042
+ * starts with it, caret after it; `value` stays the cell's own until a
3043
+ * complete value is typed.
3044
+ */
3045
+ seedText?: string;
3046
+ /**
3047
+ * The column's `numberFormat` (locale resolved): the editor is then a text
3048
+ * box in that locale (P-3) whose value is the TEXT; the engine reads it.
3049
+ */
3050
+ numberFormat?: ResolvedNumberFormat;
3051
+ /**
3052
+ * The grid's number locale (`'tr-TR'`), for reading a number box opened by
3053
+ * typing `-` or `,` on a column without `numberFormat`. Default `'en-US'`.
3054
+ */
3055
+ numberLocale?: string;
2442
3056
  onChange: (value: unknown) => void;
2443
- onCommit: (move: 'down' | 'none') => void;
3057
+ /** `'blur'`: focus left the editor — commit, but do not take focus back. */
3058
+ onCommit: (move: 'down' | 'none' | 'blur') => void;
2444
3059
  /** Tab / Shift+Tab: commit here and keep editing in the adjacent cell. */
2445
3060
  onTab: (direction: 1 | -1) => void;
2446
3061
  onCancel: () => void;
2447
3062
  }
2448
- declare function GridCellEditor({ value, dataType, error, seeded, options, allowCustom, matchMode, ariaLabel, dateFormat, onChange, onCommit, onTab, onCancel, }: GridCellEditorProps): react.JSX.Element;
3063
+ 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
3064
 
2450
3065
  interface GridDateEditorProps {
2451
3066
  value: unknown;
@@ -2470,47 +3085,19 @@ interface GridDateEditorProps {
2470
3085
  onCommit: () => void;
2471
3086
  onCancel: () => void;
2472
3087
  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
3088
  /**
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.
3089
+ * Focus left the box for somewhere that is not its calendar: commit (the
3090
+ * cell editor's click-away, P-10). Left out (row mode, the form), a blur
3091
+ * only settles the typed text, as before.
2489
3092
  */
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;
3093
+ onBlurCommit?: () => void;
2498
3094
  /**
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.
3095
+ * Digits the box starts with — the editor was opened by typing one on the
3096
+ * cell (P-3.6). The caret goes after them instead of selecting.
2502
3097
  */
2503
- commitOnPick?: boolean;
2504
- onCancel: () => void;
2505
- /** Tab moves to the adjacent cell; the engine owns that. */
2506
- onTab?: (shiftKey: boolean) => void;
3098
+ seedDigits?: string;
2507
3099
  }
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;
3100
+ declare function GridDateEditor({ value, format, invalid, disabled, autoFocus, testId, columnId, ariaLabel, onChange, onCommit, onCancel, onTab, onBlurCommit, seedDigits, }: GridDateEditorProps): react.JSX.Element;
2514
3101
 
2515
3102
  interface GridDialogProps {
2516
3103
  open: boolean;
@@ -2527,4 +3114,4 @@ interface GridDialogProps {
2527
3114
  }
2528
3115
  declare function GridDialog({ open, title, message, cancelLabel, confirmLabel, danger, dark, onConfirm, onCancel, }: GridDialogProps): react.ReactPortal | null;
2529
3116
 
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 };
3117
+ 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 };