@kanunilabs/datagrid-react 1.6.0 → 1.8.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.d.ts CHANGED
@@ -1,7 +1,7 @@
1
1
  import * as react from 'react';
2
2
  import { ReactNode, RefObject } from 'react';
3
- import { GridRowData, DataGridController, StateStoringConfig, RowKey, RowNode, GridColumnDef, DataGridCoreConfig, InferColumnsOptions, GridThemeName, GridPaletteName, DescribeFilterOptions, GridDensity, ColumnRuntime, ColumnLayout, SortDescriptor, ColumnModel, DataRowNode, ColSpanPlan, SummaryDef, FilterNode, ColumnState, BusyPhase, GridDictionary, VirtualWindow, ChartBoxSpec, ChartBoxModel, ChartSpec, ChartModel, ChartXYSpec, ChartXYModel } from '@kanunilabs/datagrid-core';
4
- export { BusyChangedEvent, BusyPhase, ClientRowModel, ColumnLayout, ColumnLookup, ColumnModel, ColumnPin, ColumnRuntime, ColumnState, ColumnStateChangedEvent, ContentReadyEvent, 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, RowDropPosition, RowKey, RowNode, SUMMARY_TYPE_LABEL, ScrollingConfig, SelectionDescriptor, SortChangedEvent, SortDescriptor, SortDirection, StateStoringConfig, SummaryDef, SummaryType, THEME_ROW_HEIGHT, 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';
3
+ import { GridRowData, DataGridController, StateStoringConfig, RowKey, RowNode, GridColumnDef, DataGridCoreConfig, FilterRenderContextBase, FilterNode, InferColumnsOptions, GridThemeName, GridPaletteName, DescribeFilterOptions, GridDensity, CardViewOptions, RowChange, ColumnRuntime, ColumnLayout, SortDescriptor, ColumnModel, DataRowNode, ColSpanPlan, SummaryDef, ToolbarIconName, ColumnState, BusyPhase, GridDictionary, VirtualWindow, ChartBoxSpec, ChartBoxModel, ChartSpec, ChartModel, ChartXYSpec, ChartXYModel, CellRange, RangeSelectionEngine, ColumnSelectMode, EditMode, ValidationRule, CrudHandlers, EditingPermissions, NewRowPosition, EditingEngine, GridDataType, LookupItem, 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, RowDropPosition, RowKey, RowNode, SUMMARY_TYPE_LABEL, ScrollingConfig, SelectionDescriptor, SortChangedEvent, SortDescriptor, SortDirection, StateStoringConfig, SummaryDef, SummaryType, THEME_ROW_HEIGHT, 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';
5
5
 
6
6
  /** Formats an export menu can offer. */
7
7
  type ExportKind = 'csv' | 'excel' | 'excel-selected' | 'pdf';
@@ -165,6 +165,14 @@ interface EditorRenderContext<TRow = GridRowData> {
165
165
  commit: () => void;
166
166
  cancel: () => void;
167
167
  }
168
+ /**
169
+ * What a column's own filter UI is handed (`renderFilter`). `value` is the
170
+ * filter that surface holds now — re-read on every filter change, so the UI
171
+ * follows a cleared filter or a restored saved view.
172
+ */
173
+ interface FilterRenderContext<TRow = GridRowData> extends FilterRenderContextBase<TRow> {
174
+ value: FilterNode | null;
175
+ }
168
176
  interface ReactGridColumnDef<TRow = GridRowData> extends GridColumnDef<TRow> {
169
177
  /** Expensive escape hatch — renders arbitrary React per cell. */
170
178
  renderCell?: (ctx: CellRenderContext<TRow>) => ReactNode;
@@ -175,6 +183,19 @@ interface ReactGridColumnDef<TRow = GridRowData> extends GridColumnDef<TRow> {
175
183
  * against your own API.
176
184
  */
177
185
  renderEditor?: (ctx: EditorRenderContext<TRow>) => ReactNode;
186
+ /**
187
+ * Replace this column's filter UI with your own — a range slider, a date
188
+ * picker, a tag list. Drawn in the filter row's cell (`surface: 'row'`)
189
+ * when `filterRow` is on, and as the header popup's content
190
+ * (`surface: 'popup'`) when `headerFilter` is on; branch on `surface` to
191
+ * draw each differently.
192
+ *
193
+ * Call `setValue` with any filter for this column — a built-in condition,
194
+ * a group, or one using a custom operator from `filterOperators` — or
195
+ * null to clear. It goes through the same `setColumnFilter` the built-in
196
+ * surfaces use, so the funnel, the filter panel and saved views see it.
197
+ */
198
+ renderFilter?: (ctx: FilterRenderContext<TRow>) => ReactNode;
178
199
  /**
179
200
  * Extra class(es) on every cell of this column — a monospace SKU column, a
180
201
  * status tint. A function form allows per-VALUE classes without paying for a
@@ -386,6 +407,27 @@ interface RowMenuContext<TRow = GridRowData> {
386
407
  /** Selected row keys at the moment the menu opened. */
387
408
  selectedKeys: RowKey[];
388
409
  }
410
+ /** Single-cell editing in the Community grid — see `DataGridProps.editing`. */
411
+ interface DataGridEditingOptions<TRow = GridRowData> {
412
+ /** Default true once `editing` is given. */
413
+ enabled?: boolean;
414
+ /**
415
+ * Always `'cell'` here — accepted so the same object works in both editions
416
+ * (`EnterpriseDataGrid` defaults to `'batch'` and adds the other modes).
417
+ */
418
+ mode?: 'cell';
419
+ /**
420
+ * Persist one committed cell. Called after the value is written to the row;
421
+ * a rejected promise is reported in the grid and the edit stays visible.
422
+ */
423
+ onSave?: (changes: RowChange<TRow>[]) => Promise<void> | void;
424
+ /** Typing a printable character on a focused cell opens its editor. Default true. */
425
+ editOnKeyPress?: boolean;
426
+ /** Tab moves between cells inside the grid instead of leaving it. Default true. */
427
+ focusCellOnTab?: boolean;
428
+ /** Tab past the last editable cell of a row wraps to the next row. Default true. */
429
+ focusCellOnCycle?: boolean;
430
+ }
389
431
  interface DataGridProps<TRow = GridRowData> extends Omit<DataGridCoreConfig<TRow>, 'columns'> {
390
432
  /**
391
433
  * Optional: with an ARRAY data source and no columns, one column per field
@@ -456,6 +498,19 @@ interface DataGridProps<TRow = GridRowData> extends Omit<DataGridCoreConfig<TRow
456
498
  emptyText?: string;
457
499
  /** Header click sorting (multi-sort follows `sorting.multi` + Shift). */
458
500
  sortable?: boolean;
501
+ /**
502
+ * Let the header row grow to fit its tallest caption — the partner of a
503
+ * column's `wrapHeaderText`. Default false: the header keeps the theme's
504
+ * fixed height and a long caption ends in an ellipsis (or, wrapped, is
505
+ * clipped).
506
+ *
507
+ * Off by default because the height is MEASURED after layout: everything
508
+ * stuck under the header (the filter row, pinned rows, the totals row at
509
+ * the top, sticky group headers) has to move with it, and a grid that never
510
+ * wraps a caption should not pay for that. Only the columns on screen are measured,
511
+ * so scrolling sideways onto a longer caption can grow the header then.
512
+ */
513
+ autoHeaderHeight?: boolean;
459
514
  /** Text-input row under the header, one box per column. */
460
515
  filterRow?: boolean;
461
516
  /**
@@ -621,6 +676,28 @@ interface DataGridProps<TRow = GridRowData> extends Omit<DataGridCoreConfig<TRow
621
676
  * customization that keeps the column layout, use a column's `renderCell`.
622
677
  */
623
678
  renderRow?: (ctx: RowTemplateContext<TRow>) => ReactNode;
679
+ /**
680
+ * Rows as cards on a narrow grid — a phone, a side panel. Below
681
+ * `breakpoint` pixels (default 600) each data row is drawn as a card: the
682
+ * first field as its title, the rest as "Header value" lines, as wide as
683
+ * the grid. The column headers give way to a sort control.
684
+ *
685
+ * Sort, filter, search, selection, grouping, virtual scrolling and remote
686
+ * data keep working. What needs a cell does not apply while cards are shown:
687
+ * in-cell editing, range selection, the fill handle and column resizing.
688
+ * A card shows each field's TEXT (formatters and lookups included); a
689
+ * column's `renderCell` is not used on a card. While cards are shown they
690
+ * replace `renderRow`.
691
+ *
692
+ * `columns` picks the fields and their order (the first is the title);
693
+ * default: the visible columns.
694
+ */
695
+ cardView?: boolean | CardViewOptions;
696
+ /**
697
+ * The grid switched between cards and the table (`cardView`), as its width
698
+ * crossed the breakpoint. `true` while cards are shown.
699
+ */
700
+ onCardViewChange?: (active: boolean) => void;
624
701
  /**
625
702
  * Remember the user's columns, sort, filters and grouping between visits.
626
703
  * Off by default: persisting a layout the app never asked to persist is a
@@ -745,6 +822,22 @@ interface DataGridProps<TRow = GridRowData> extends Omit<DataGridCoreConfig<TRow
745
822
  * (useCallback) or it will fire on every render.
746
823
  */
747
824
  onReady?: (controller: DataGridController<TRow>) => void;
825
+ /**
826
+ * Edit a cell in place — free in Community since 2026-10-12.
827
+ *
828
+ * Off unless this object is given (`editing={{ onSave }}`); `enabled: false`
829
+ * turns it off again. Double-click, F2 or typing opens the editor on
830
+ * an editable column; Enter commits and moves down, Tab moves to the next
831
+ * editable cell, Esc cancels. Each committed cell is written to its row and
832
+ * passed to `onSave` — one call per edit — and `cellValueChanged` fires.
833
+ * A column with `editable: false`, a `lookup` or a `renderEditor` stays
834
+ * read-only here.
835
+ *
836
+ * Batch, row, form and popup modes, validation rules, add/delete,
837
+ * per-row permissions, lookup and custom editors, undo/redo, range
838
+ * selection, fill and paste are `EnterpriseDataGrid`.
839
+ */
840
+ editing?: DataGridEditingOptions<TRow>;
748
841
  /** Replace a cell's content (e.g. with an editor). Return undefined for default. */
749
842
  renderCellContent?: (ctx: CellSlotContext<TRow>) => ReactNode | undefined;
750
843
  /** Extra class names per cell (dirty marker, range highlight, invalid). */
@@ -1166,6 +1259,18 @@ interface GridFilterRowProps<TRow = GridRowData> {
1166
1259
  */
1167
1260
  periodSuggestions?: readonly string[];
1168
1261
  periodListId?: string;
1262
+ /**
1263
+ * The operator picked in a column's operator menu, by column id — `''` (or
1264
+ * absent) for the default entry, which keeps the box's typed rules. Only
1265
+ * columns with `filterOperators` show the menu.
1266
+ */
1267
+ operators?: Record<string, string>;
1268
+ onOperatorChange?: (columnId: string, operatorId: string) => void;
1269
+ /**
1270
+ * The app's own filter UI for a column with `renderFilter`, drawn in place of
1271
+ * the box. Returns undefined for a column without one.
1272
+ */
1273
+ renderCustom?: (columnId: string) => React.ReactNode | undefined;
1169
1274
  }
1170
1275
 
1171
1276
  /** What the reconciler needs to know about one column. Kept tiny so it is testable. */
@@ -1203,7 +1308,7 @@ interface FilterInputSyncProbe {
1203
1308
  * re-render entirely.
1204
1309
  */
1205
1310
  declare function reconcileFilterInputs(prev: Record<string, string>, probe: FilterInputSyncProbe, columnIds?: readonly string[]): Record<string, string>;
1206
- declare function GridFilterRowImpl<TRow = GridRowData>({ bandOffset, stickyInsets, layout, centerColumns, leadingSpacer, trailingSpacer, values, checkboxColumn, detailColumn, rowNumberColumn, placeholder, onChange, onCommit, periodSuggestions, periodListId, }: GridFilterRowProps<TRow>): react.JSX.Element;
1311
+ declare function GridFilterRowImpl<TRow = GridRowData>({ bandOffset, stickyInsets, layout, centerColumns, leadingSpacer, trailingSpacer, values, checkboxColumn, detailColumn, rowNumberColumn, placeholder, onChange, onCommit, periodSuggestions, periodListId, operators, onOperatorChange, renderCustom, }: GridFilterRowProps<TRow>): react.JSX.Element;
1207
1312
  declare const GridFilterRow: typeof GridFilterRowImpl;
1208
1313
 
1209
1314
  interface DistinctEntry {
@@ -1394,6 +1499,12 @@ interface GridToolbarProps<TRow = GridRowData> {
1394
1499
  declare function GridToolbarImpl<TRow = GridRowData>({ controller, search, exportCsv, exportExcel, exportPdf, columnChooser, dark, onOpenColumnChooser, itemsBefore, itemsAfter, searchDebounce, labels, }: GridToolbarProps<TRow>): react.JSX.Element;
1395
1500
  declare const GridToolbar: typeof GridToolbarImpl;
1396
1501
 
1502
+ /** A command button's icon — the shared paths of `toolbarIcons.ts` (see there for why). */
1503
+ declare function ToolbarIcon({ name, size }: {
1504
+ name: ToolbarIconName;
1505
+ size?: number;
1506
+ }): react.JSX.Element;
1507
+
1397
1508
  interface GridColumnChooserProps<TRow = GridRowData> {
1398
1509
  controller: DataGridController<TRow>;
1399
1510
  /** Passed in so the panel re-renders when visibility changes. */
@@ -1404,7 +1515,7 @@ interface GridColumnChooserProps<TRow = GridRowData> {
1404
1515
  };
1405
1516
  onClose: () => void;
1406
1517
  dark?: boolean;
1407
- labels?: Partial<Record<'title' | 'empty' | 'showAll' | 'ok', string>>;
1518
+ labels?: Partial<Record<'title' | 'empty' | 'search' | 'showAll' | 'ok', string>>;
1408
1519
  }
1409
1520
  declare function GridColumnChooser<TRow = GridRowData>({ controller, columns, anchor, onClose, dark, labels, }: GridColumnChooserProps<TRow>): react.JSX.Element;
1410
1521
 
@@ -1781,4 +1892,326 @@ declare function GridTextProvider({ locale, messages, children }: GridTextProvid
1781
1892
  /** The resolved dictionary. Stable between language changes. */
1782
1893
  declare function useGridText(): GridDictionary;
1783
1894
 
1784
- export { type AlignedGridsApi, BAND_ROW_HEIGHT, type CellMenuOptions, type CellRenderContext, type CellSlotContext, type CellTooltipOptions, DEFAULT_HEADER_MENU_LABELS, DataGrid, type DataGridProps, type DistinctEntry, type EditorRenderContext, type ExportOutcome, GridColumnChooser, type GridColumnChooserProps, GridContextMenu, type GridContextMenuProps, GridFilterPanel, type GridFilterPanelProps, GridFilterRow, type GridFilterRowProps, GridFooterRow, type GridFooterRowProps, GridGroupPanel, type GridGroupPanelProps, GridHeader, GridHeaderBands, type GridHeaderBandsProps, GridHeaderFilterPopup, type GridHeaderFilterPopupProps, type GridHeaderProps, GridLoadingOverlay, type GridLoadingOverlayProps, type GridMenuItem, GridNoteEditor, type GridNotesConfig, GridPager, type GridPagerProps, GridPinnedRows, type GridPinnedRowsProps, GridPopupPanel, type GridPopupPanelProps, GridPortal, type GridPortalProps, GridRow, type GridRowProps, GridSummaryBar, type GridSummaryBarProps, GridSurfaceProvider, type GridSurfaceProviderProps, GridTextProvider, type GridTextProviderProps, GridToolbar, type GridToolbarProps, GridTooltip, type GridTooltipConfig, type GridTooltipProps, type HeaderMenuContext, type HeaderMenuDeps, type HeaderMenuLabels, type HeaderRenderContext, type NoteCellContext, PRINT_MAX_ROWS, type PrintLayoutOptions, type PrintLayoutState, ROW_DRAG_MIME, type ReactColumnRuntime, type ReactGridColumnDef, type RowDragConfig, type RowDragHandlers, type RowDragPayload, type RowDropEvent, type RowMenuContext, type RowReorderEvent, type RowTemplateContext, SHORTCUT_COPY, SHORTCUT_CUT, SHORTCUT_PASTE, type TooltipState, type UseDataGridOptions, type UseDataGridResult, buildCellMenuItems, buildHeaderMenu, copyToClipboard, headerMenuLabels, measureBestFitWidth, reconcileFilterInputs, runGridExport, useAlignedGrids, useAnchoredPopup, useCellTooltip, useDataGrid, useGridChartBoxData, useGridChartData, useGridChartXYData, useGridSurfaceClass, useGridText, usePrintLayout, useRowDrag, useStateStoring, writeClipboardText };
1895
+ interface UseGridEditingOptions<TRow = GridRowData> {
1896
+ controller: DataGridController<TRow> | null;
1897
+ mode?: EditMode;
1898
+ rules?: Record<string, ValidationRule<TRow>[]>;
1899
+ onSave?: (changes: unknown[]) => Promise<void> | void;
1900
+ /** Per-row persistence — the app's own insert/update/delete calls. */
1901
+ crud?: CrudHandlers<TRow>;
1902
+ allowAdding?: boolean;
1903
+ allowUpdating?: EditingPermissions<TRow>['allowUpdating'];
1904
+ allowDeleting?: EditingPermissions<TRow>['allowDeleting'];
1905
+ onInitNewRow?: (values: Record<string, unknown>) => void;
1906
+ onRowInserted?: (key: RowKey, row: TRow | undefined) => void;
1907
+ onRowUpdated?: (key: RowKey, row: TRow | undefined, values: Record<string, unknown>) => void;
1908
+ onRowRemoved?: (key: RowKey, row: TRow | undefined) => void;
1909
+ /** Typing a printable key on a focused cell starts editing. Default true. */
1910
+ editOnKeyPress?: boolean;
1911
+ /**
1912
+ * `Insert` opens a blank row ABOVE the focused one. Default false.
1913
+ *
1914
+ * Off by default because Insert is not a neutral key: some users have it
1915
+ * bound elsewhere, and a grid that starts creating records on a keypress
1916
+ * nobody asked for is a surprise.
1917
+ */
1918
+ insertKey?: boolean;
1919
+ /**
1920
+ * Arrow-down on the LAST row appends a blank one. Default false.
1921
+ *
1922
+ * The other half of the same data-entry habit: fill a row, press down, keep
1923
+ * typing. Also off by default — with it on, a user who holds arrow-down to
1924
+ * reach the bottom creates a row when they arrive.
1925
+ */
1926
+ appendOnArrowDown?: boolean;
1927
+ /** Where `addRow()` puts the new record. Default 'last'. */
1928
+ newRowPosition?: NewRowPosition;
1929
+ /** Tab moves between cells inside the grid instead of leaving it. Default true. */
1930
+ focusCellOnTab?: boolean;
1931
+ /** Tab past the end of a row wraps to the next one. Default true. */
1932
+ focusCellOnCycle?: boolean;
1933
+ /** Keep the editor open when Tab moves. Default false. */
1934
+ keepEditingOnTab?: boolean;
1935
+ /**
1936
+ * Ask before deleting. Default: a browser confirm.
1937
+ *
1938
+ * `false` deletes straight away. A FUNCTION replaces the prompt with the
1939
+ * app's own dialog — return false (or a promise of false) to abandon it.
1940
+ */
1941
+ confirmDelete?: boolean | ((rowKey: RowKey, row: TRow | undefined) => boolean | Promise<boolean>);
1942
+ /** Wording for the built-in prompt. Ignored when `confirmDelete` is a function. */
1943
+ confirmDeleteMessage?: string;
1944
+ /** Disables editing entirely (`editing={{ enabled: false }}`). */
1945
+ enabled?: boolean;
1946
+ /**
1947
+ * `editing.range` — the rectangle, the fill handle and the clipboard
1948
+ * gestures (cut / paste). Default true. Off means Ctrl+X and Ctrl+V are left
1949
+ * alone too, the same as the vanilla renderer: one switch, all three.
1950
+ */
1951
+ range?: boolean;
1952
+ /**
1953
+ * Undo / redo: Ctrl+Z and Ctrl+Y (Cmd on a Mac) and `controller.undo()`.
1954
+ * Default true. The free grid passes false — single-cell editing is
1955
+ * Community, history is Enterprise (owner decision, 2026-10-12).
1956
+ */
1957
+ history?: boolean;
1958
+ /**
1959
+ * An extra say on which columns open an editor, on top of the column's own
1960
+ * `editable: false`. The free grid uses it to keep lookup and custom-editor
1961
+ * columns read-only — those editors are Enterprise.
1962
+ */
1963
+ canEditColumn?: (columnId: string) => boolean;
1964
+ }
1965
+ /**
1966
+ * What the footer strip shows for the current range.
1967
+ *
1968
+ * `numeric` is null when the range holds no numbers at all (a text column), and
1969
+ * `truncated` is true when the range was too large to total — see the limit
1970
+ * below. Both cases are reported rather than shown as zeros.
1971
+ */
1972
+ interface SelectionStats {
1973
+ cells: number;
1974
+ truncated: boolean;
1975
+ numeric: {
1976
+ sum: number;
1977
+ count: number;
1978
+ avg: number;
1979
+ min: number;
1980
+ max: number;
1981
+ } | null;
1982
+ }
1983
+ /** A delete the user has asked for and not yet confirmed. */
1984
+ interface PendingDelete {
1985
+ rowKey: RowKey;
1986
+ message: string;
1987
+ }
1988
+ /** A save the engine refused, with the cell to blame when validation refused it. */
1989
+ interface BatchSaveError {
1990
+ message: string;
1991
+ rowKey?: RowKey;
1992
+ columnId?: string;
1993
+ }
1994
+ /** Range API that keeps React in sync (see the wrapper in the hook). */
1995
+ interface RangeApi {
1996
+ start(row: number, column: number): void;
1997
+ /** Begin another range and keep the selected ones (Ctrl/Cmd+click or drag, G-SEL-01). */
1998
+ add(row: number, column: number): void;
1999
+ extend(row: number, column: number): void;
2000
+ finish(): void;
2001
+ clear(): void;
2002
+ contains(row: number, column: number): boolean;
2003
+ isAnchor(row: number, column: number): boolean;
2004
+ getRange(): CellRange | null;
2005
+ getBounds(): ReturnType<RangeSelectionEngine['getBounds']>;
2006
+ /** TSV for the selected rectangle; `textAt` supplies each cell's text. */
2007
+ toTsv(textAt: (row: number, column: number) => string): string;
2008
+ /** Select a whole column (G-SEL-02); false when there are no rows. */
2009
+ selectColumn(column: number, rowCount: number, mode: ColumnSelectMode): boolean;
2010
+ /** The column indexes some range covers from the first row to the last. */
2011
+ fullColumns(rowCount: number): Set<number>;
2012
+ }
2013
+ interface UseGridEditingResult<TRow = GridRowData> {
2014
+ engine: EditingEngine<TRow> | null;
2015
+ range: RangeApi;
2016
+ /** Bumped on every engine change; consumers read through it. */
2017
+ version: number;
2018
+ beginEdit: (rowKey: RowKey, columnId: string) => void;
2019
+ /**
2020
+ * Open a whole ROW (row / form / popup modes). False when the mode does not
2021
+ * support it, or another row is already open — the caller decides what to
2022
+ * do with the first one rather than having it saved or discarded silently.
2023
+ */
2024
+ beginRowEdit: (rowKey: RowKey) => boolean;
2025
+ /** Validate and persist the open row. Resolves false and stays open on failure. */
2026
+ saveRowEdit: () => Promise<boolean>;
2027
+ /** Discard the open row's edits. Other rows keep theirs. */
2028
+ cancelRowEdit: () => void;
2029
+ /** Message from the last rejected row save; null once anything changes. */
2030
+ rowSaveError: string | null;
2031
+ /**
2032
+ * Adds a pending row and opens its first editable cell. Null when not allowed.
2033
+ *
2034
+ * `beforeKey` puts it directly above that row instead of at the end — what
2035
+ * the Insert key needs.
2036
+ */
2037
+ addRow: (values?: Record<string, unknown>, beforeKey?: RowKey) => RowKey | null;
2038
+ /**
2039
+ * Commit and move to the next (1) or previous (-1) editable cell. By default
2040
+ * the destination is only FOCUSED; pass `open: true` to carry the editor
2041
+ * along, `cycle: false` to stop at the end of a row instead of wrapping.
2042
+ */
2043
+ editAdjacentCell: (direction: 1 | -1, options?: {
2044
+ open?: boolean;
2045
+ cycle?: boolean;
2046
+ }) => boolean;
2047
+ /** Open the editor on the focused cell, seeded with a typed character. */
2048
+ editFocusedCellWith: (char: string) => boolean;
2049
+ /**
2050
+ * Return DOM focus to the grid's scroller. Closing an editor destroys the
2051
+ * element that held focus, so every path that ends a session has to call
2052
+ * this or the keyboard goes dead until the user clicks the grid again.
2053
+ */
2054
+ focusScroller: () => void;
2055
+ deleteRow: (rowKey: RowKey) => boolean;
2056
+ saveChanges: () => Promise<void>;
2057
+ /** Why the last save was refused, or null. */
2058
+ saveError: BatchSaveError | null;
2059
+ /** Dismiss the save error once the user has read it. */
2060
+ clearSaveError: () => void;
2061
+ /** A delete waiting on confirmation, or null. */
2062
+ pendingDelete: PendingDelete | null;
2063
+ /** Answer the confirmation: true deletes, false abandons. */
2064
+ resolveDelete: (confirmed: boolean) => void;
2065
+ cancelChanges: () => void;
2066
+ handleKeyDown: (event: React.KeyboardEvent) => boolean;
2067
+ /**
2068
+ * Copy the selected RANGE, then clear the cells the user may clear. One undo
2069
+ * step. False when there was nothing to cut.
2070
+ *
2071
+ * Cells the permissions refuse are copied but left in place: the user asked
2072
+ * for the part they own, and refusing the whole rectangle over one read-only
2073
+ * column would be the less useful answer.
2074
+ */
2075
+ cut: (target?: {
2076
+ rowKey: RowKey;
2077
+ columnId: string;
2078
+ } | null) => boolean;
2079
+ /**
2080
+ * Copy the selected RANGE. False when no range is selected, which lets the
2081
+ * Community row copy take the gesture instead.
2082
+ */
2083
+ copySelection: () => boolean;
2084
+ /**
2085
+ * Paste the clipboard over the range, anchored at its top-left cell. With no
2086
+ * range, at `target` (the cell a context menu was opened over), else at the
2087
+ * focused cell. Cells the permissions refuse are skipped, as cut skips them.
2088
+ */
2089
+ paste: (target?: {
2090
+ rowKey: RowKey;
2091
+ columnId: string;
2092
+ } | null) => Promise<void>;
2093
+ /** Fill preview rectangle while the handle is dragged, else null. */
2094
+ /** Totals for the current range, or null when nothing is selected. */
2095
+ selectionStats: SelectionStats | null;
2096
+ fillPreview: CellRange | null;
2097
+ startFillDrag: (row: number, column: number) => void;
2098
+ moveFillDrag: (row: number, column: number) => void;
2099
+ endFillDrag: () => void;
2100
+ isDraggingFill: boolean;
2101
+ }
2102
+ declare function useGridEditing<TRow = GridRowData>(options: UseGridEditingOptions<TRow>): UseGridEditingResult<TRow>;
2103
+
2104
+ interface GridCellEditorProps {
2105
+ value: unknown;
2106
+ dataType: GridDataType | undefined;
2107
+ /**
2108
+ * Choices for a lookup/select editor. `null` means the list is still being
2109
+ * fetched — the control renders disabled rather than empty, so the user
2110
+ * cannot commit a blank over a value while the options are in flight.
2111
+ */
2112
+ options?: readonly LookupItem[] | null;
2113
+ /** Let the user type a value outside `options`. */
2114
+ allowCustom?: boolean;
2115
+ /** How typed text narrows the lookup list. Default `'startsWith'`. */
2116
+ matchMode?: LookupMatchMode;
2117
+ /** Accessible name for the editor, used by the lookup combo box. */
2118
+ ariaLabel?: string;
2119
+ /** Format for a `date` column — governs both the mask and the display. */
2120
+ dateFormat?: string;
2121
+ /** Validation message for the current value; null when valid. */
2122
+ error: string | null;
2123
+ /**
2124
+ * The editor was opened by TYPING, so `value` is the character the user just
2125
+ * pressed. The caret goes after it instead of selecting it — selecting would
2126
+ * make the second keystroke erase the first.
2127
+ */
2128
+ seeded?: boolean;
2129
+ onChange: (value: unknown) => void;
2130
+ onCommit: (move: 'down' | 'none') => void;
2131
+ /** Tab / Shift+Tab: commit here and keep editing in the adjacent cell. */
2132
+ onTab: (direction: 1 | -1) => void;
2133
+ onCancel: () => void;
2134
+ }
2135
+ declare function GridCellEditor({ value, dataType, error, seeded, options, allowCustom, matchMode, ariaLabel, dateFormat, onChange, onCommit, onTab, onCancel, }: GridCellEditorProps): react.JSX.Element;
2136
+
2137
+ interface GridDateEditorProps {
2138
+ value: unknown;
2139
+ /** Column format. Defaults to `yyyy-MM-dd`. */
2140
+ format?: string;
2141
+ invalid?: boolean;
2142
+ disabled?: boolean;
2143
+ /**
2144
+ * Take focus on mount. True for a cell editor, false in `row` mode where
2145
+ * every editable cell mounts one at once.
2146
+ */
2147
+ autoFocus?: boolean;
2148
+ testId?: string;
2149
+ columnId?: string;
2150
+ ariaLabel?: string;
2151
+ /**
2152
+ * Commit shape follows the value the editor was GIVEN: a column holding
2153
+ * `Date` objects gets a `Date` back, one holding ISO strings gets a string.
2154
+ * Changing an app's storage shape on save is not the editor's business.
2155
+ */
2156
+ onChange: (value: unknown) => void;
2157
+ onCommit: () => void;
2158
+ onCancel: () => void;
2159
+ onTab?: (shiftKey: boolean) => void;
2160
+ }
2161
+ declare function GridDateEditor({ value, format, invalid, disabled, autoFocus, testId, columnId, ariaLabel, onChange, onCommit, onCancel, onTab, }: GridDateEditorProps): react.JSX.Element;
2162
+
2163
+ interface GridLookupEditorProps {
2164
+ options: readonly LookupItem[];
2165
+ value: unknown;
2166
+ /** Prefix (default) or substring. */
2167
+ matchMode?: LookupMatchMode;
2168
+ /** Let text that matches nothing become the value. Default false. */
2169
+ allowCustom?: boolean;
2170
+ invalid?: boolean;
2171
+ /**
2172
+ * Take focus on mount. True for a cell editor — it opened BECAUSE the user
2173
+ * asked to edit that one cell. False in `row` mode, where every editable cell
2174
+ * mounts an editor at once and each would grab focus in turn, landing the
2175
+ * caret on whichever lookup happened to render last.
2176
+ */
2177
+ autoFocus?: boolean;
2178
+ testId?: string;
2179
+ /** Stamped as `data-column-id`, so callers can find one field of a row. */
2180
+ columnId?: string;
2181
+ ariaLabel?: string;
2182
+ onChange: (value: unknown) => void;
2183
+ /** Commit (Enter / picking an item), handed back to the engine. */
2184
+ onCommit: () => void;
2185
+ /**
2186
+ * Whether picking an item counts as committing. True for a cell editor —
2187
+ * the pick IS the edit. False in `row`/`form` mode, where picking fills one
2188
+ * field of a record the user is still filling in and only Save ends it.
2189
+ */
2190
+ commitOnPick?: boolean;
2191
+ onCancel: () => void;
2192
+ /** Tab moves to the adjacent cell; the engine owns that. */
2193
+ onTab?: (shiftKey: boolean) => void;
2194
+ }
2195
+ /**
2196
+ * The same match, as items. Kept for callers and tests that want the simple
2197
+ * shape; the component itself works in indices to avoid the copy.
2198
+ */
2199
+ declare function matchOptions(options: readonly LookupItem[], query: string, mode: LookupMatchMode): readonly LookupItem[];
2200
+ declare function GridLookupEditor({ options, value, matchMode, allowCustom, invalid, autoFocus, testId, columnId, ariaLabel, onChange, onCommit, commitOnPick, onCancel, onTab, }: GridLookupEditorProps): react.JSX.Element;
2201
+
2202
+ interface GridDialogProps {
2203
+ open: boolean;
2204
+ title: string;
2205
+ message: string;
2206
+ /** Omitted for an acknowledgement dialog, which gets only the confirm button. */
2207
+ cancelLabel?: string;
2208
+ confirmLabel: string;
2209
+ /** Styles the confirm button as destructive. */
2210
+ danger?: boolean;
2211
+ dark?: boolean;
2212
+ onConfirm: () => void;
2213
+ onCancel: () => void;
2214
+ }
2215
+ declare function GridDialog({ open, title, message, cancelLabel, confirmLabel, danger, dark, onConfirm, onCancel, }: GridDialogProps): react.ReactPortal | null;
2216
+
2217
+ export { type AlignedGridsApi, BAND_ROW_HEIGHT, type BatchSaveError, type CellMenuOptions, type CellRenderContext, type CellSlotContext, type CellTooltipOptions, DEFAULT_HEADER_MENU_LABELS, DataGrid, type DataGridProps, type DistinctEntry, type EditorRenderContext, type ExportOutcome, type FilterRenderContext, GridCellEditor, type GridCellEditorProps, GridColumnChooser, type GridColumnChooserProps, GridContextMenu, type GridContextMenuProps, GridDateEditor, type GridDateEditorProps, GridDialog, type GridDialogProps, 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, type GridRowProps, GridSummaryBar, type GridSummaryBarProps, GridSurfaceProvider, type GridSurfaceProviderProps, GridTextProvider, type GridTextProviderProps, GridToolbar, 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 RowMenuContext, type RowReorderEvent, type RowTemplateContext, SHORTCUT_COPY, SHORTCUT_CUT, SHORTCUT_PASTE, type SelectionStats, ToolbarIcon, type TooltipState, type UseDataGridOptions, type UseDataGridResult, type UseGridEditingOptions, type UseGridEditingResult, buildCellMenuItems, buildHeaderMenu, copyToClipboard, headerMenuLabels, matchOptions, measureBestFitWidth, reconcileFilterInputs, runGridExport, useAlignedGrids, useAnchoredPopup, useCellTooltip, useDataGrid, useGridChartBoxData, useGridChartData, useGridChartXYData, useGridEditing, useGridSurfaceClass, useGridText, usePrintLayout, useRowDrag, useStateStoring, writeClipboardText };