@bmsuisse/datagrid 0.29.0 → 0.31.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 +404 -3
- package/dist/index.js +1418 -364
- package/dist/index.js.map +1 -1
- package/package.json +1 -1
package/dist/index.d.ts
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { ReactNode, ReactElement, ComponentType, RefObject } from 'react';
|
|
1
|
+
import { ReactNode, ReactElement, MouseEvent, ComponentType, RefObject } from 'react';
|
|
2
2
|
import { ColumnSizingState, RowData } from '@tanstack/react-table';
|
|
3
3
|
export { ColumnSizingState } from '@tanstack/react-table';
|
|
4
4
|
|
|
@@ -209,9 +209,21 @@ interface BaseColumn<TRow> {
|
|
|
209
209
|
* this cell, including the default editors' own `onChange`.
|
|
210
210
|
*/
|
|
211
211
|
validateEdit?: (value: unknown, row: TRow) => string | undefined;
|
|
212
|
+
/**
|
|
213
|
+
* Overrides the plain-text form of this column's value used when copying a
|
|
214
|
+
* `cellEditing`-mode selection to the clipboard. Defaults to the same
|
|
215
|
+
* `defaultFormat` display text every other rendering path already uses —
|
|
216
|
+
* only needed for a column with a custom `cell` whose displayed content
|
|
217
|
+
* isn't a faithful plain-text rendering of the underlying value (e.g. a
|
|
218
|
+
* badge/icon), the same situation `renderFilter`/`renderEditCell` exist to
|
|
219
|
+
* override for their own concerns.
|
|
220
|
+
*/
|
|
221
|
+
formatForClipboard?: (value: unknown, row: TRow) => string;
|
|
212
222
|
}
|
|
213
223
|
type StringColumn<TRow> = BaseColumn<TRow> & {
|
|
214
224
|
type: "string";
|
|
225
|
+
/** Opt-in: defaults to false. Selects `MultilineStringEditor` (an auto-growing `<textarea>`) instead of `StringEditor`'s single-line `<Input>` for this column's default edit widget — same variant-flag idiom as `NumberColumn.currency`, not a separate `type`. Has no effect on static (non-editing) display, which stays whatever `column.cell`/`defaultFormat` already renders. */
|
|
226
|
+
multiline?: boolean;
|
|
215
227
|
};
|
|
216
228
|
type NumberColumn<TRow> = BaseColumn<TRow> & {
|
|
217
229
|
type: "number" | "currency";
|
|
@@ -658,6 +670,16 @@ declare function DateEditor<TRow>({ column, rowId, value, onChange, error, autoF
|
|
|
658
670
|
/** Default inline editor for `type: "enum"` columns: a single-value select over `column.options`. */
|
|
659
671
|
declare function EnumEditor<TRow>({ column, rowId, value, onChange, error, autoFocus, }: EditWidgetProps<EnumColumn<TRow>>): ReactElement;
|
|
660
672
|
|
|
673
|
+
/**
|
|
674
|
+
* Default inline editor for a `type: "string"` column with `multiline: true`:
|
|
675
|
+
* an auto-growing `<textarea>` in place of `StringEditor`'s single-line
|
|
676
|
+
* `<Input>`. Dispatched by `registry.tsx`'s existing `case "string":` branch
|
|
677
|
+
* — a rendering choice, not a new column `type` — so it works identically
|
|
678
|
+
* under both `DataGridProps.editing` (row-batch) and `.cellEditing`
|
|
679
|
+
* (immediate-apply) modes with zero extra wiring in either.
|
|
680
|
+
*/
|
|
681
|
+
declare function MultilineStringEditor<TRow>({ column, rowId, value, onChange, error, autoFocus, }: EditWidgetProps<StringColumn<TRow>>): ReactElement;
|
|
682
|
+
|
|
661
683
|
/**
|
|
662
684
|
* Default inline editor for `type: "number"` / `type: "currency"` columns: a
|
|
663
685
|
* native number input. Emits `null` for an emptied field (not `NaN` or `""`)
|
|
@@ -784,6 +806,375 @@ interface EditingBarProps<TRow> {
|
|
|
784
806
|
*/
|
|
785
807
|
declare function EditingBar<TRow>({ editing, pendingRowCount, editErrors, onSave, onDiscard, testIdPrefix, }: EditingBarProps<TRow>): ReactElement;
|
|
786
808
|
|
|
809
|
+
/**
|
|
810
|
+
* Identifies one cell by stable row id + column id — never by DOM node or
|
|
811
|
+
* virtualization index, so a selection/edit survives a virtualized row
|
|
812
|
+
* mounting, unmounting, and remounting as the grid scrolls.
|
|
813
|
+
*/
|
|
814
|
+
interface CellAddress {
|
|
815
|
+
rowId: string;
|
|
816
|
+
columnId: string;
|
|
817
|
+
}
|
|
818
|
+
/**
|
|
819
|
+
* A rectangular block of cells, expressed as its two corners: `anchor` is
|
|
820
|
+
* the cell where the selection/drag started, `focus` is the other corner —
|
|
821
|
+
* the one that moves as you shift+arrow or drag the mouse. Either corner can
|
|
822
|
+
* be the top-left or bottom-right one; use `normalizeRange` (in
|
|
823
|
+
* `rangeUtils.ts`) to resolve that.
|
|
824
|
+
*/
|
|
825
|
+
interface CellRange {
|
|
826
|
+
anchor: CellAddress;
|
|
827
|
+
focus: CellAddress;
|
|
828
|
+
}
|
|
829
|
+
/**
|
|
830
|
+
* One committed cell edit — from a typed commit, a paste, or a fill-drag.
|
|
831
|
+
* `previousValue` isn't read by anything in this pass; it's carried now so a
|
|
832
|
+
* future undo/redo can be built on top of the same `CellChange` log without
|
|
833
|
+
* a breaking API change later.
|
|
834
|
+
*/
|
|
835
|
+
interface CellChange<TRow> {
|
|
836
|
+
rowId: string;
|
|
837
|
+
row: TRow;
|
|
838
|
+
columnId: string;
|
|
839
|
+
previousValue: unknown;
|
|
840
|
+
value: unknown;
|
|
841
|
+
}
|
|
842
|
+
/**
|
|
843
|
+
* Enables the "true spreadsheet" cell-editing mode on `<DataGrid>`: click or
|
|
844
|
+
* type directly into any cell, range-select, paste, fill-handle — every
|
|
845
|
+
* change applies immediately, with no row-level Save/Discard gate. This is a
|
|
846
|
+
* different state machine from `DataGridProps.editing`'s accumulate-then-save
|
|
847
|
+
* workflow, not a superset of it — set at most one of `editing`/`cellEditing`
|
|
848
|
+
* on a given `<DataGrid>`; `editing` is ignored once `cellEditing` is set.
|
|
849
|
+
*/
|
|
850
|
+
interface CellEditingOptions<TRow> {
|
|
851
|
+
/**
|
|
852
|
+
* Called once per gesture — one typed-cell commit, one paste, one
|
|
853
|
+
* fill-drag — with every cell that gesture changed. There's no debouncing:
|
|
854
|
+
* each gesture's full change set is computed synchronously before this
|
|
855
|
+
* fires, so a single keystroke commit is one `[change]`, and pasting a
|
|
856
|
+
* 50-cell block is one call with 50 entries.
|
|
857
|
+
*
|
|
858
|
+
* Fire-and-forget: a rejection does not roll back the grid's own local
|
|
859
|
+
* display of the new values — there's no "pending" state to roll back to
|
|
860
|
+
* in an immediate-apply model, unlike `EditingOptions.onSave`. Show your
|
|
861
|
+
* own error UI (e.g. a toast) if a change needs to be surfaced as failed.
|
|
862
|
+
*/
|
|
863
|
+
onCellsChange: (changes: CellChange<TRow>[]) => void | Promise<void>;
|
|
864
|
+
/** Disables all cell-editing interaction — e.g. while a previous gesture's `onCellsChange` is still in flight. Defaults to false. */
|
|
865
|
+
disabled?: boolean;
|
|
866
|
+
/**
|
|
867
|
+
* Renders every editable cell's editor directly, all the time — no click,
|
|
868
|
+
* double-click, F2, or typed character needed to open one first. Selection
|
|
869
|
+
* (drag/shift+click/shift+arrow), copy, paste, and the fill-handle all
|
|
870
|
+
* still work exactly as they do without this flag; only the single-cell
|
|
871
|
+
* "one cell editing at a time" gate is gone, since with this on every
|
|
872
|
+
* editable cell already IS its own editor. A buffered (string/number/
|
|
873
|
+
* currency) editor still only commits on blur/Enter/Tab, same as always —
|
|
874
|
+
* this flag just means it's already open, not that it types straight
|
|
875
|
+
* through to `onCellsChange` on every keystroke. Defaults to false.
|
|
876
|
+
*/
|
|
877
|
+
alwaysEdit?: boolean;
|
|
878
|
+
}
|
|
879
|
+
|
|
880
|
+
/** Maps each id to its position in `ids` — built once per (rowIds|columnIds) identity change, then reused for every lookup during a drag, rather than an O(n) `indexOf` per cell per mousemove. */
|
|
881
|
+
declare function buildIndexMap(ids: string[]): Map<string, number>;
|
|
882
|
+
/** A `CellRange`'s two corners resolved to ordinal row/column indices, with `start <= end` on both axes regardless of which corner `anchor`/`focus` was. */
|
|
883
|
+
interface NormalizedRange {
|
|
884
|
+
rowStart: number;
|
|
885
|
+
rowEnd: number;
|
|
886
|
+
colStart: number;
|
|
887
|
+
colEnd: number;
|
|
888
|
+
}
|
|
889
|
+
/**
|
|
890
|
+
* Resolves a `CellRange` to ordinal indices via `rowIndex`/`columnIndex`
|
|
891
|
+
* (from `buildIndexMap`), or `undefined` if either endpoint's row or column
|
|
892
|
+
* id no longer exists — e.g. the row was removed from `data` since the
|
|
893
|
+
* selection was made.
|
|
894
|
+
*/
|
|
895
|
+
declare function normalizeRange(range: CellRange, rowIndex: Map<string, number>, columnIndex: Map<string, number>): NormalizedRange | undefined;
|
|
896
|
+
/** True if `cell` falls inside `range` (inclusive on all sides). */
|
|
897
|
+
declare function isCellInRange(cell: CellAddress, range: CellRange, rowIndex: Map<string, number>, columnIndex: Map<string, number>): boolean;
|
|
898
|
+
/** Every cell address inside `range`, in row-major order (top-to-bottom, left-to-right), skipping the row-major walk entirely once `normalizeRange` can't resolve either endpoint. */
|
|
899
|
+
declare function cellsInRange(range: CellRange, rowIds: string[], columnIds: string[], rowIndex: Map<string, number>, columnIndex: Map<string, number>): CellAddress[];
|
|
900
|
+
/**
|
|
901
|
+
* Extends a fill-handle drag's `base` range (the source selection, already
|
|
902
|
+
* normalized) toward `target`, locked to whichever single axis — row or
|
|
903
|
+
* column — has the larger overshoot past `base`'s own edge on that axis.
|
|
904
|
+
* Matches Excel/Sheets' own autofill behavior: dragging the fill handle
|
|
905
|
+
* never extends diagonally, only straight down/up/left/right from the
|
|
906
|
+
* source range. Returns `base` unchanged if `target` is inside or on its
|
|
907
|
+
* border (no overshoot on either axis).
|
|
908
|
+
*/
|
|
909
|
+
declare function extendRangeForFill(base: NormalizedRange, target: {
|
|
910
|
+
row: number;
|
|
911
|
+
col: number;
|
|
912
|
+
}): NormalizedRange;
|
|
913
|
+
|
|
914
|
+
type NavigationDirection = "up" | "down" | "left" | "right";
|
|
915
|
+
interface CellSelectionOptions {
|
|
916
|
+
/** Every row id, in on-screen order — the FULL logical row list, not just currently-mounted virtual items, so navigation and range math work correctly regardless of virtualization. */
|
|
917
|
+
rowIds: string[];
|
|
918
|
+
/** Every editable-surface column id, in on-screen order. */
|
|
919
|
+
columnIds: string[];
|
|
920
|
+
/** Called when navigation lands on a row id that (per the caller) may not currently be mounted — e.g. to `virtualizer.scrollToIndex` it into view. Not called for a move that stays on the same row (left/right). */
|
|
921
|
+
onNavigateToRow?: (rowId: string) => void;
|
|
922
|
+
}
|
|
923
|
+
interface CellSelectionController {
|
|
924
|
+
/** The committed selection (mouseup already happened, or a keyboard move), or `undefined` before any cell has ever been selected. */
|
|
925
|
+
selection: CellRange | undefined;
|
|
926
|
+
/** True while a mouse-drag range-select is in progress (between `startSelection` and `endDrag`). */
|
|
927
|
+
isDragging: boolean;
|
|
928
|
+
/** `selection` extended live to the drag's current cell while `isDragging`; otherwise identical to `selection`. This is the range a renderer should actually paint. */
|
|
929
|
+
effectiveRange: CellRange | undefined;
|
|
930
|
+
/** Mousedown on `cell`: starts a fresh single-cell selection, or (`extend: true`, e.g. shift+mousedown) extends the existing selection's focus corner to `cell` while keeping its anchor. Either way, also opens a drag (see `endDrag`) — a plain click-no-move sequence still round-trips through `startSelection`/`endDrag` and ends up exactly the same as if `updateDrag` were never called. */
|
|
931
|
+
startSelection: (cell: CellAddress, options?: {
|
|
932
|
+
extend?: boolean;
|
|
933
|
+
}) => void;
|
|
934
|
+
/** Mousemove while dragging: updates the live drag-focus cell. Callers should coalesce rapid calls themselves (e.g. one `requestAnimationFrame`-scheduled flush per animation frame) — this hook applies whatever it's given without its own throttling. No-op if not currently dragging. */
|
|
935
|
+
updateDrag: (cell: CellAddress) => void;
|
|
936
|
+
/** Mouseup: commits the in-progress drag's live focus cell as the real selection. No-op if not currently dragging. */
|
|
937
|
+
endDrag: () => void;
|
|
938
|
+
/** Keyboard navigation: moves the focus corner by one row/column in `direction`, clamped to grid bounds. Collapses the selection to the new single cell unless `extend` (shift+arrow), which instead moves only the focus corner, keeping the existing anchor. */
|
|
939
|
+
moveSelection: (direction: NavigationDirection, options?: {
|
|
940
|
+
extend?: boolean;
|
|
941
|
+
}) => void;
|
|
942
|
+
/** Directly replaces the selection, e.g. to leave a specific cell selected after a paste/fill commits. */
|
|
943
|
+
setSelection: (range: CellRange) => void;
|
|
944
|
+
clearSelection: () => void;
|
|
945
|
+
/** True while a fill-handle drag is in progress (between `startFillDrag` and `endFillDrag`). Mutually exclusive with `isDragging` — starting one doesn't check for the other, but a caller should never let both begin at once (the fill handle and the rest of a cell are different mousedown targets). */
|
|
946
|
+
isFillDragging: boolean;
|
|
947
|
+
/** The selection extended toward the fill-drag's current target cell, axis-locked (see `extendRangeForFill`'s own doc) — the range a renderer should paint as the live fill preview. `undefined` when not fill-dragging, or before the first `updateFillDrag` call of a given drag. */
|
|
948
|
+
fillPreviewRange: CellRange | undefined;
|
|
949
|
+
/** Starts a fill-drag from the current `selection` (mousedown on the fill handle). No-op if there's no selection yet. */
|
|
950
|
+
startFillDrag: () => void;
|
|
951
|
+
/** Updates the fill-drag's live target cell (mousemove while fill-dragging). Callers should coalesce rapid calls themselves, same as `updateDrag`. No-op if not currently fill-dragging. */
|
|
952
|
+
updateFillDrag: (cell: CellAddress) => void;
|
|
953
|
+
/**
|
|
954
|
+
* Commits the fill-drag (mouseup): sets the extended range as the new
|
|
955
|
+
* `selection` and returns both the original source range and the final
|
|
956
|
+
* extended one, so the caller can compute the actual fill values (which
|
|
957
|
+
* source cell each newly-covered cell copies from) — that data-dependent
|
|
958
|
+
* computation doesn't belong in this hook, which only knows row/column
|
|
959
|
+
* ids, not row data. Returns `undefined` if not fill-dragging, there was
|
|
960
|
+
* no base selection, or no target cell was ever reported (a drag that
|
|
961
|
+
* never moved) — in the last case, nothing to commit, current selection
|
|
962
|
+
* unchanged.
|
|
963
|
+
*/
|
|
964
|
+
endFillDrag: () => {
|
|
965
|
+
sourceRange: CellRange;
|
|
966
|
+
finalRange: CellRange;
|
|
967
|
+
} | undefined;
|
|
968
|
+
}
|
|
969
|
+
/**
|
|
970
|
+
* Owns the rectangular range-selection cursor for `cellEditing` mode: the
|
|
971
|
+
* committed selection, an in-progress mouse-drag's live extent, and
|
|
972
|
+
* keyboard navigation — all keyed by row-id/column-id (via `rowIds`/
|
|
973
|
+
* `columnIds`'s ordinal position), never by DOM node or virtualized index,
|
|
974
|
+
* so a selection is meaningful even for a row that isn't currently mounted.
|
|
975
|
+
*/
|
|
976
|
+
declare function useCellSelection({ rowIds, columnIds, onNavigateToRow }: CellSelectionOptions): CellSelectionController;
|
|
977
|
+
|
|
978
|
+
/**
|
|
979
|
+
* Everything `renderCellModeCell` needs to render one cell under
|
|
980
|
+
* `cellEditing` mode. Bundled into one object handed through a `useRef` for
|
|
981
|
+
* the identical reason `EditingCellContext` is (see that type's own doc):
|
|
982
|
+
* `<DataGrid>`'s `tanstackColumns` memo must not depend on anything that
|
|
983
|
+
* changes per-keystroke, or typing into one cell would remount the whole
|
|
984
|
+
* table body.
|
|
985
|
+
*/
|
|
986
|
+
interface CellEditingCellContext<TRow> {
|
|
987
|
+
/** Mirrors `CellEditingOptions.alwaysEdit` — every editable cell renders `AlwaysEditCell` instead of going through `editingCell`/`onBeginEdit` at all when this is set. */
|
|
988
|
+
alwaysEdit: boolean;
|
|
989
|
+
/** Mirrors `CellEditingOptions.disabled`. Click-to-edit mode blocks interaction by simply never opening an editor while this is set (see `onBeginEdit`'s own gate) — `AlwaysEditCell`'s editors are always open regardless, so it reads this directly to disable its rendered form control instead. */
|
|
990
|
+
disabled: boolean;
|
|
991
|
+
/** The one cell currently showing its editor, or `undefined` — at most one at a time, the same convention `EditingCellContext.activeRowId` uses at row granularity. Meaningless (always `undefined`) under `alwaysEdit`, where every editable cell already has its own editor. */
|
|
992
|
+
editingCell: CellAddress | undefined;
|
|
993
|
+
/** Replaces (doesn't append to) the editor's starting value when editing began by typing a printable character directly (Excel's "just start typing" gesture) rather than double-click/Enter/F2, which start from the cell's current value. `undefined` means "start from the current value." */
|
|
994
|
+
initialText: string | undefined;
|
|
995
|
+
/** Whether at least one `onChangeDraft` has fired this edit session — distinguishes "no keystrokes yet, show the starting value" from "the user explicitly typed something," including an empty string. */
|
|
996
|
+
hasDraft: boolean;
|
|
997
|
+
/** The in-progress typed value for `editingCell`, meaningful only when `hasDraft` is true. */
|
|
998
|
+
draftValue: unknown;
|
|
999
|
+
getRowId: (row: TRow) => string;
|
|
1000
|
+
getError: (rowId: string, columnId: string) => string | undefined;
|
|
1001
|
+
/**
|
|
1002
|
+
* The value to actually display for one cell: `rawValue` (the row's real
|
|
1003
|
+
* data) unless a still-"fresh" local override exists. An override is
|
|
1004
|
+
* fresh only while `rawValue` still equals what it was at the moment of
|
|
1005
|
+
* the edit (`previousValue`) — the instant the row's real data changes to
|
|
1006
|
+
* ANYTHING else (the consumer's `onCellsChange` handler updated its own
|
|
1007
|
+
* `data` to reflect the accepted edit, or a refetch landed with something
|
|
1008
|
+
* different entirely, e.g. server-side normalization), real data is
|
|
1009
|
+
* trusted again instead of the stale local echo. This is what lets a
|
|
1010
|
+
* fire-and-forget, no-rollback model (see `CellEditingOptions.onCellsChange`'s
|
|
1011
|
+
* own doc) still self-correct if the consumer's eventual real data
|
|
1012
|
+
* diverges from what was optimistically shown.
|
|
1013
|
+
*/
|
|
1014
|
+
resolveValue: (rowId: string, columnId: string, rawValue: unknown) => unknown;
|
|
1015
|
+
/** Starts editing `cell`. */
|
|
1016
|
+
onBeginEdit: (cell: CellAddress, initialText?: string) => void;
|
|
1017
|
+
/** Reverts without committing — Escape, or a blur while the current draft is invalid. */
|
|
1018
|
+
onCancelEdit: () => void;
|
|
1019
|
+
/** Records a keystroke/selection's new value for the cell currently being edited — for an "atomic" editor (enum/boolean/date, where a single selection IS the complete gesture) the caller follows this immediately with `onCommitEdit`; for a free-text editor (string/number) this only buffers, and the caller commits separately on blur/Enter/Tab. */
|
|
1020
|
+
onChangeDraft: (value: unknown) => void;
|
|
1021
|
+
/** Commits the current draft (or, if `hasDraft` is false, effectively a no-op close) for the cell currently being edited, as one `CellChange`, and closes its editor. `previousValue` is the row's real value before this edit, for the resulting `CellChange.previousValue`. */
|
|
1022
|
+
onCommitEdit: (row: TRow, previousValue: unknown) => void;
|
|
1023
|
+
/**
|
|
1024
|
+
* Commits an explicit `value` directly, bypassing the draft state
|
|
1025
|
+
* entirely — for an "atomic" editor (enum/boolean/date) whose `onChange`
|
|
1026
|
+
* fires once with the complete new value and wants to commit in that same
|
|
1027
|
+
* call. `onCommitEdit` above can't be reused for this: it reads `hasDraft`/
|
|
1028
|
+
* `draftValue` from React state, which a same-tick `onChangeDraft` call
|
|
1029
|
+
* immediately before it would NOT yet reflect (state updates don't apply
|
|
1030
|
+
* until the next render, even within the same event handler).
|
|
1031
|
+
*/
|
|
1032
|
+
onCommitValue: (row: TRow, previousValue: unknown, value: unknown) => void;
|
|
1033
|
+
onSetError: (rowId: string, columnId: string, message: string | undefined) => void;
|
|
1034
|
+
/** Commits one independently-managed cell's change directly — for `AlwaysEditCell`, which owns its own draft state locally rather than through `editingCell`/`onChangeDraft`/`onCommitEdit`'s single shared slot (every editable cell needs its own simultaneous editor under `alwaysEdit`, not just one at a time). */
|
|
1035
|
+
applyChange: (change: CellChange<TRow>) => void;
|
|
1036
|
+
/**
|
|
1037
|
+
* Reads (and clears) whether `onCommitEdit`/`onCommitValue` committed
|
|
1038
|
+
* synchronously during the current call stack. `<DataGrid>`'s own keydown
|
|
1039
|
+
* handler needs this: `renderCellModeCell`'s Enter/Tab commit deliberately
|
|
1040
|
+
* doesn't stop the event from bubbling, so that handler can advance the
|
|
1041
|
+
* selection afterward — but `editingCell` itself is React state, which
|
|
1042
|
+
* doesn't reflect `closeEditor()`'s update until the next render, so
|
|
1043
|
+
* reading it directly during that same bubbled dispatch always still
|
|
1044
|
+
* shows the row that JUST closed. This ref-backed flag is the one piece of
|
|
1045
|
+
* "did a commit just happen in this exact gesture" state that's readable
|
|
1046
|
+
* synchronously, in the same event, immediately after the commit.
|
|
1047
|
+
*/
|
|
1048
|
+
consumeJustCommitted: () => boolean;
|
|
1049
|
+
}
|
|
1050
|
+
interface CellEditingState<TRow> {
|
|
1051
|
+
/** The live context, read directly by a render path with no remount-avoidance concerns of its own. */
|
|
1052
|
+
ctx: CellEditingCellContext<TRow> | undefined;
|
|
1053
|
+
/** Same context, mirrored into a ref every render — see `CellEditingCellContext`'s own doc for why `<DataGrid>`'s per-cell closures must read through this instead of closing over `ctx` directly. */
|
|
1054
|
+
ctxRef: {
|
|
1055
|
+
current: CellEditingCellContext<TRow> | undefined;
|
|
1056
|
+
};
|
|
1057
|
+
/** Commits a whole gesture's changes at once (paste, fill-drag) — no `editingCell` involved, unlike `onCommitEdit` above. */
|
|
1058
|
+
applyChanges: (changes: CellChange<TRow>[]) => void;
|
|
1059
|
+
}
|
|
1060
|
+
/**
|
|
1061
|
+
* Owns the "true spreadsheet" per-cell edit state: which single cell (if
|
|
1062
|
+
* any) is showing its editor, that cell's in-progress typed draft, per-cell
|
|
1063
|
+
* validation errors, and the local-override echo every committed change
|
|
1064
|
+
* leaves behind until the consumer's own real data catches up. Every
|
|
1065
|
+
* mutation — a typed commit, a future paste, a future fill-drag — funnels
|
|
1066
|
+
* through `applyChanges`, so a later undo/redo can be built on top of that
|
|
1067
|
+
* one function without a rearchitecture.
|
|
1068
|
+
*/
|
|
1069
|
+
declare function useCellEditingState<TRow>(cellEditing: CellEditingOptions<TRow> | undefined, getRowId: (row: TRow) => string): CellEditingState<TRow>;
|
|
1070
|
+
|
|
1071
|
+
/**
|
|
1072
|
+
* Renders one cell under `cellEditing` mode — the immediate-apply
|
|
1073
|
+
* counterpart to `edit/renderEditableCell.tsx`'s accumulate-then-save one.
|
|
1074
|
+
* Reuses the exact same per-type editor widgets via `registry.tsx`'s
|
|
1075
|
+
* `renderDefaultEditWidget` (and the same `column.renderEditCell`/
|
|
1076
|
+
* `column.validateEdit` escape hatches) — only the commit semantics differ.
|
|
1077
|
+
*
|
|
1078
|
+
* Not responsible for range-selection visuals — that's `SelectionOverlay`,
|
|
1079
|
+
* one overlay for the whole grid — this only decides whether THIS cell is
|
|
1080
|
+
* the one currently showing its editor.
|
|
1081
|
+
*/
|
|
1082
|
+
declare function renderCellModeCell<TRow>(column: ColumnDef<TRow>, row: TRow, rawValue: unknown, ctx: CellEditingCellContext<TRow> | undefined): ReactNode;
|
|
1083
|
+
|
|
1084
|
+
/**
|
|
1085
|
+
* Renders the current range selection (and, while a fill-handle drag is in
|
|
1086
|
+
* progress, a dashed preview of the range it would extend to) as absolutely-
|
|
1087
|
+
* positioned overlay divs, geometry read live from the DOM rects of the
|
|
1088
|
+
* relevant cells' `data-cell-row`/`data-cell-col` nodes — deliberately not
|
|
1089
|
+
* derived from `columnSizing`/row-height state, since reading the live DOM
|
|
1090
|
+
* always matches exactly what's rendered (including natural, non-resizing
|
|
1091
|
+
* column widths `columnSizing`'s own math doesn't account for).
|
|
1092
|
+
*
|
|
1093
|
+
* Must render as a CHILD of the scrollable container (not a sibling outside
|
|
1094
|
+
* it), with that container given `position: relative` — position/left/top
|
|
1095
|
+
* are computed in the container's own unscrolled content-space (rect minus
|
|
1096
|
+
* the container's rect, plus the container's current scroll offset), so once
|
|
1097
|
+
* set, the overlay scrolls together with the table content via ordinary
|
|
1098
|
+
* browser scrolling with no scroll listener of its own. A virtualized grid's
|
|
1099
|
+
* scroll-driven re-renders (the virtualizer's own React state) naturally
|
|
1100
|
+
* recompute this on every such render; a non-virtualized grid never needs to
|
|
1101
|
+
* (native scroll changes nothing in content-space).
|
|
1102
|
+
*
|
|
1103
|
+
* Deliberately isolated from `visibleColumns`/`tanstackColumns` — it reads
|
|
1104
|
+
* nothing from either, only `range`/`fillPreviewRange` and the DOM — so
|
|
1105
|
+
* painting/updating a selection or a fill-drag (including during a fast
|
|
1106
|
+
* mouse-drag) never touches the column-definition memo that would otherwise
|
|
1107
|
+
* remount the whole table body.
|
|
1108
|
+
*/
|
|
1109
|
+
declare function SelectionOverlay({ containerRef, range, fillPreviewRange, onFillHandleMouseDown, }: {
|
|
1110
|
+
containerRef: {
|
|
1111
|
+
current: HTMLDivElement | null;
|
|
1112
|
+
};
|
|
1113
|
+
range: CellRange | undefined;
|
|
1114
|
+
/** The live preview range during a fill-handle drag, or `undefined` when not fill-dragging. */
|
|
1115
|
+
fillPreviewRange?: CellRange | undefined;
|
|
1116
|
+
/** Mousedown on the fill handle — starts a fill-drag. Omit to render no handle at all (e.g. a read-only or non-editable selection). */
|
|
1117
|
+
onFillHandleMouseDown?: (event: MouseEvent<HTMLDivElement>) => void;
|
|
1118
|
+
}): ReactElement | null;
|
|
1119
|
+
|
|
1120
|
+
/**
|
|
1121
|
+
* Coerces one pasted/filled raw TSV cell string into the typed value a
|
|
1122
|
+
* column's editor/validator expects — the paste/fill equivalent of
|
|
1123
|
+
* `edit/registry.tsx`'s per-type dispatch, reusing the exact same `toDate`/
|
|
1124
|
+
* `toNumber` parsing `column/format.ts` uses for display so paste coercion
|
|
1125
|
+
* can't drift from what the grid already shows.
|
|
1126
|
+
*
|
|
1127
|
+
* Returns `undefined` for a value that can't be coerced at all (e.g. "abc"
|
|
1128
|
+
* into a number column) — the caller's job to skip that cell rather than
|
|
1129
|
+
* hand `onCellsChange` a `NaN`/`Invalid Date`. An empty string coerces to
|
|
1130
|
+
* `null` for `number`/`currency` (pasting a blank cell over a numeric one
|
|
1131
|
+
* clears it, matching `NumberEditor`'s own null-for-cleared convention) —
|
|
1132
|
+
* `string` columns instead treat an empty string as itself a valid value.
|
|
1133
|
+
* An Excel/Sheets error string (`#N/A`, `#DIV/0!`, etc.) pasted into any
|
|
1134
|
+
* column but `string` is likewise skipped rather than coerced.
|
|
1135
|
+
*/
|
|
1136
|
+
declare function coerceValueForColumn<TRow>(column: ColumnDef<TRow>, raw: string): {
|
|
1137
|
+
value: unknown;
|
|
1138
|
+
} | undefined;
|
|
1139
|
+
|
|
1140
|
+
/**
|
|
1141
|
+
* Serializes the cells inside `range` to Excel-compatible TSV text: tab-
|
|
1142
|
+
* separated columns, newline-separated rows, walking `rowIds`/`columnIds` in
|
|
1143
|
+
* their on-screen order (not `range`'s own anchor/focus order). Each cell's
|
|
1144
|
+
* text comes from `column.formatForClipboard` if the column supplies one,
|
|
1145
|
+
* else the same `defaultFormat` display text the grid itself renders —
|
|
1146
|
+
* deliberately not a second "raw value to string" path.
|
|
1147
|
+
*/
|
|
1148
|
+
declare function rangeToTsv<TRow>(range: CellRange, rows: TRow[], rowIds: string[], columns: ColumnDef<TRow>[], columnIds: string[], getRowId: (row: TRow) => string): string;
|
|
1149
|
+
/**
|
|
1150
|
+
* Parses Excel-compatible TSV/tab-delimited clipboard text into a 2D array
|
|
1151
|
+
* of raw string cells. A small character-by-character state machine (not a
|
|
1152
|
+
* naive split-by-newline-then-split-by-tab) so a quoted field's own embedded
|
|
1153
|
+
* newline — a genuine multi-line cell copied from Excel/Sheets — isn't
|
|
1154
|
+
* mistaken for a row boundary, and a doubled `""` inside a quoted field
|
|
1155
|
+
* unescapes to one literal `"`.
|
|
1156
|
+
*/
|
|
1157
|
+
declare function parseTsv(text: string): string[][];
|
|
1158
|
+
|
|
1159
|
+
/**
|
|
1160
|
+
* Computes the `CellChange`s a fill-handle drag produces: every cell newly
|
|
1161
|
+
* covered by `finalRange` but not already inside `sourceRange` copies its
|
|
1162
|
+
* value from the corresponding source cell, TILING the source pattern across
|
|
1163
|
+
* the fill direction when the extension is longer than the source itself —
|
|
1164
|
+
* the same repeat-the-pattern behavior Excel's own fill-handle uses for a
|
|
1165
|
+
* multi-cell source (a single-cell source is just the degenerate case: every
|
|
1166
|
+
* new cell copies that one cell). Value-copy only, no numeric/date
|
|
1167
|
+
* auto-increment — MVP scope, matching the akeneo hand-rolled
|
|
1168
|
+
* implementation this feature replaces, which also only ever copies a
|
|
1169
|
+
* single value uniformly.
|
|
1170
|
+
*
|
|
1171
|
+
* Cells already inside `sourceRange` are left out of the result entirely —
|
|
1172
|
+
* they're untouched by a fill, only the newly-covered ones change.
|
|
1173
|
+
* A target cell that's missing, not editable, or whose source cell is
|
|
1174
|
+
* missing is silently skipped.
|
|
1175
|
+
*/
|
|
1176
|
+
declare function computeFillChanges<TRow>(sourceRange: CellRange, finalRange: CellRange, rowIds: string[], columnIds: string[], columns: ColumnDef<TRow>[], getRow: (rowId: string) => TRow | undefined): CellChange<TRow>[];
|
|
1177
|
+
|
|
787
1178
|
/**
|
|
788
1179
|
* Column visibility keyed by `ColumnDef.id`. A missing key means visible —
|
|
789
1180
|
* this matches TanStack Table's own `VisibilityState` convention, so a
|
|
@@ -1151,6 +1542,16 @@ interface DataGridProps<TRow> {
|
|
|
1151
1542
|
* contract — shared with `<TreeDataGrid>`'s own `editing` prop.
|
|
1152
1543
|
*/
|
|
1153
1544
|
editing?: EditingOptions<TRow>;
|
|
1545
|
+
/**
|
|
1546
|
+
* Enables the "true spreadsheet" cell-editing mode: click/type directly
|
|
1547
|
+
* into any cell, drag or shift+arrow to range-select, paste, drag a
|
|
1548
|
+
* fill-handle — every change applies immediately, with no row-level
|
|
1549
|
+
* Save/Discard gate. This is a different, mutually exclusive state machine
|
|
1550
|
+
* from `editing` above, not a superset of it — set at most one of the two
|
|
1551
|
+
* on a given `<DataGrid>`; `editing` is ignored once `cellEditing` is set.
|
|
1552
|
+
* See `CellEditingOptions` for the full contract.
|
|
1553
|
+
*/
|
|
1554
|
+
cellEditing?: CellEditingOptions<TRow>;
|
|
1154
1555
|
}
|
|
1155
1556
|
|
|
1156
1557
|
/**
|
|
@@ -1161,7 +1562,7 @@ interface DataGridProps<TRow> {
|
|
|
1161
1562
|
* (`"server"`). Column filter UI defaults to the type-appropriate widget
|
|
1162
1563
|
* from `src/filter` unless a column supplies its own `cell` renderer.
|
|
1163
1564
|
*/
|
|
1164
|
-
declare function DataGrid<TRow extends RowData>({ columns, dataSource, getRowId, rowActions, headerActions, enableMultiSort, initialState, columnVisibility, renderDetail, enableColumnResizing, columnResizeMode, columnSizing: controlledColumnSizing, onColumnSizingChange, virtualize, showPagination, getRowProps, getRowTestId, gridState, selectedIds: controlledSelectedIds, onSelectedIdsChange, testId, loading: loadingProp, groupBy, renderGroupHeader, defaultGroupsExpanded, expandedGroups: controlledExpandedGroups, onExpandedGroupsChange, zebra, editing, }: DataGridProps<TRow>): ReactElement;
|
|
1565
|
+
declare function DataGrid<TRow extends RowData>({ columns, dataSource, getRowId, rowActions, headerActions, enableMultiSort, initialState, columnVisibility, renderDetail, enableColumnResizing, columnResizeMode, columnSizing: controlledColumnSizing, onColumnSizingChange, virtualize, showPagination, getRowProps, getRowTestId, gridState, selectedIds: controlledSelectedIds, onSelectedIdsChange, testId, loading: loadingProp, groupBy, renderGroupHeader, defaultGroupsExpanded, expandedGroups: controlledExpandedGroups, onExpandedGroupsChange, zebra, editing, cellEditing, }: DataGridProps<TRow>): ReactElement;
|
|
1165
1566
|
|
|
1166
1567
|
interface GridStateController {
|
|
1167
1568
|
state: GridState;
|
|
@@ -1581,4 +1982,4 @@ interface UseTreeStateOptions<TRow> extends TreeAccessors<TRow> {
|
|
|
1581
1982
|
*/
|
|
1582
1983
|
declare function useTreeState<TRow>({ data, getRowId, getChildren, hasChildren, onLoadChildren, expanded: controlledExpanded, onExpandedChange, childrenMap: controlledChildrenMap, onChildrenMapChange, }: UseTreeStateOptions<TRow>): TreeStateController<TRow>;
|
|
1583
1984
|
|
|
1584
|
-
export { ActionsMenu, type BaseColumn, type BooleanColumn, BooleanEditor, BooleanFilter, type ClientProcessingResult, type ColumnAlign, type ColumnDef, type ColumnGroup, ColumnSelector, type ColumnSelectorProps, type ColumnVisibility, type CompositeFilterDescriptor, DataGrid, type DataGridProps, type DataSource, type DateColumn, DateEditor, DateRangeFilter, type DebouncedCallback, EditFieldError, type EditWidgetProps, type EditedRow, EditingBar, type EditingBarProps, type EditingCellContext, type EditingOptions, type EditingState, type EnumColumn, EnumEditor, EnumFilter, type EnumOption, type FilterDescriptor, type FilterOperator, type FilterWidgetProps, type FlatTreeRow, type GridState, type GridStateController, type GroupExpansionController, type MenuItem, type MenuItemContext, type NumberColumn, NumberComparisonFilter, NumberEditor, NumberHistogramFilter, type NumberHistogramFilterProps, NumberRangeFilter, type PendingRowEdit, type ResolvedMenuItem, type SortDescriptor, type StickyGroupHeaderTop, type StringColumn, StringEditor, StringFilter, type TreeAccessors, TreeDataGrid, type TreeDataGridProps, type TreeStateController, UNARY_OPERATORS, type UseTreeStateOptions, alignClassName, canHideColumn, canHideGroup, countVisible, defaultAlign, defaultFormat, editErrorId, evaluateFilter, facetedNumberValues, fieldKey, flattenTree, getColumnValue, groupColumns, isColumnVisible, isCompositeFilterDescriptor, isEditable, isFilterDescriptor, isFilterable, isSortable, processClientData, renderDefaultEditWidget, renderDefaultFilterWidget, renderEditableCell, resolveMenuItems, storageKeyFor, toDate, useDebouncedCallback, useEditingState, useGridState, useGroupExpansion, useStickyGroupHeaderTop, useTreeState, useVisibleColumns };
|
|
1985
|
+
export { ActionsMenu, type BaseColumn, type BooleanColumn, BooleanEditor, BooleanFilter, type CellAddress, type CellChange, type CellEditingCellContext, type CellEditingOptions, type CellEditingState, type CellRange, type CellSelectionController, type CellSelectionOptions, type ClientProcessingResult, type ColumnAlign, type ColumnDef, type ColumnGroup, ColumnSelector, type ColumnSelectorProps, type ColumnVisibility, type CompositeFilterDescriptor, DataGrid, type DataGridProps, type DataSource, type DateColumn, DateEditor, DateRangeFilter, type DebouncedCallback, EditFieldError, type EditWidgetProps, type EditedRow, EditingBar, type EditingBarProps, type EditingCellContext, type EditingOptions, type EditingState, type EnumColumn, EnumEditor, EnumFilter, type EnumOption, type FilterDescriptor, type FilterOperator, type FilterWidgetProps, type FlatTreeRow, type GridState, type GridStateController, type GroupExpansionController, type MenuItem, type MenuItemContext, MultilineStringEditor, type NavigationDirection, type NormalizedRange, type NumberColumn, NumberComparisonFilter, NumberEditor, NumberHistogramFilter, type NumberHistogramFilterProps, NumberRangeFilter, type PendingRowEdit, type ResolvedMenuItem, SelectionOverlay, type SortDescriptor, type StickyGroupHeaderTop, type StringColumn, StringEditor, StringFilter, type TreeAccessors, TreeDataGrid, type TreeDataGridProps, type TreeStateController, UNARY_OPERATORS, type UseTreeStateOptions, alignClassName, buildIndexMap, canHideColumn, canHideGroup, cellsInRange, coerceValueForColumn, computeFillChanges, countVisible, defaultAlign, defaultFormat, editErrorId, evaluateFilter, extendRangeForFill, facetedNumberValues, fieldKey, flattenTree, getColumnValue, groupColumns, isCellInRange, isColumnVisible, isCompositeFilterDescriptor, isEditable, isFilterDescriptor, isFilterable, isSortable, normalizeRange, parseTsv, processClientData, rangeToTsv, renderCellModeCell, renderDefaultEditWidget, renderDefaultFilterWidget, renderEditableCell, resolveMenuItems, storageKeyFor, toDate, useCellEditingState, useCellSelection, useDebouncedCallback, useEditingState, useGridState, useGroupExpansion, useStickyGroupHeaderTop, useTreeState, useVisibleColumns };
|