@bmsuisse/datagrid 0.25.2 → 0.26.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 +221 -2
- package/dist/index.js +573 -132
- package/dist/index.js.map +1 -1
- package/package.json +1 -1
package/dist/index.d.ts
CHANGED
|
@@ -161,6 +161,43 @@ interface BaseColumn<TRow> {
|
|
|
161
161
|
* any, since `<DataGrid>` has no way to tell your content lacks one.
|
|
162
162
|
*/
|
|
163
163
|
renderHeader?: (column: BaseColumn<TRow>) => ReactNode;
|
|
164
|
+
/**
|
|
165
|
+
* Opt-in: defaults to false — must be explicitly set (or return true) for
|
|
166
|
+
* `<DataGrid>` to render this column's cells as inline editors. A function
|
|
167
|
+
* makes it conditional per row (e.g. a "locked" row that can't be
|
|
168
|
+
* edited). See `DataGridProps.editing` for the accumulate-then-save
|
|
169
|
+
* workflow this feeds into — editable cells with no `editing` prop
|
|
170
|
+
* supplied just render as static text, same as if `editable` were unset.
|
|
171
|
+
*
|
|
172
|
+
* A cell doesn't become an editor just because this is true, though:
|
|
173
|
+
* clicking (or Enter/Space-ing) any editable cell in a row is what
|
|
174
|
+
* activates editors for every editable column in THAT row at once — the
|
|
175
|
+
* rest of the grid's rows stay static until clicked into themselves. A
|
|
176
|
+
* row stays active until its edits are saved or discarded, and
|
|
177
|
+
* activating one row never deactivates another.
|
|
178
|
+
*/
|
|
179
|
+
editable?: boolean | ((row: TRow) => boolean);
|
|
180
|
+
/**
|
|
181
|
+
* Overrides the default type-based editor (see `renderDefaultEditWidget`)
|
|
182
|
+
* for this column's cells. Receives the cell's current value (the row's
|
|
183
|
+
* original value, or a still-pending edit if the user already changed it
|
|
184
|
+
* this session), the row itself, an `onChange` to record a new pending
|
|
185
|
+
* value, this cell's current validation error message (from
|
|
186
|
+
* `validateEdit` below) if any, and whether this specific cell is the one
|
|
187
|
+
* whose click just activated the row (see `editable`'s own doc) — forward
|
|
188
|
+
* it to your control's native `autoFocus` so the row-activating click also
|
|
189
|
+
* focuses the field the user actually clicked, not just some other cell
|
|
190
|
+
* in the same row.
|
|
191
|
+
*/
|
|
192
|
+
renderEditCell?: (value: unknown, row: TRow, onChange: (next: unknown) => void, error: string | undefined, autoFocus: boolean) => ReactNode;
|
|
193
|
+
/**
|
|
194
|
+
* Validates a pending edit before it's allowed into `editing.onSave`'s
|
|
195
|
+
* payload. Returning a message string blocks the Save button (and shows
|
|
196
|
+
* the message under the cell) until the value is fixed or reverted to its
|
|
197
|
+
* original; returning `undefined` means valid. Runs on every change to
|
|
198
|
+
* this cell, including the default editors' own `onChange`.
|
|
199
|
+
*/
|
|
200
|
+
validateEdit?: (value: unknown, row: TRow) => string | undefined;
|
|
164
201
|
}
|
|
165
202
|
type StringColumn<TRow> = BaseColumn<TRow> & {
|
|
166
203
|
type: "string";
|
|
@@ -191,6 +228,8 @@ declare function getColumnValue<TRow>(column: ColumnDef<TRow>, row: TRow): unkno
|
|
|
191
228
|
declare function isSortable<TRow>(column: ColumnDef<TRow>): boolean;
|
|
192
229
|
/** True only if a column explicitly opts in (`filterable: true`) — the default is false. */
|
|
193
230
|
declare function isFilterable<TRow>(column: ColumnDef<TRow>): boolean;
|
|
231
|
+
/** True only if a column explicitly opts in to `editable` — for this specific row, when `editable` is a predicate. Default is false. */
|
|
232
|
+
declare function isEditable<TRow>(column: ColumnDef<TRow>, row: TRow): boolean;
|
|
194
233
|
|
|
195
234
|
/**
|
|
196
235
|
* Default filter widget for `type: "boolean"` columns: a 3-way All/Yes/No
|
|
@@ -450,6 +489,14 @@ declare function renderDefaultFilterWidget<TRow>(column: ColumnDef<TRow>, value:
|
|
|
450
489
|
declare function defaultAlign<TRow>(column: ColumnDef<TRow>): ColumnAlign;
|
|
451
490
|
/** The literal Tailwind class for a column's default alignment; see `defaultAlign`. */
|
|
452
491
|
declare function alignClassName<TRow>(column: ColumnDef<TRow>): string;
|
|
492
|
+
/**
|
|
493
|
+
* Parses an arbitrary raw cell value into a `Date`, or `null` if it isn't
|
|
494
|
+
* one. Exported (unlike `toNumber` below, which stays internal) because
|
|
495
|
+
* `edit/DateEditor.tsx` needs the exact same date-only-vs-datetime parsing
|
|
496
|
+
* this module already uses for display — a second copy would risk drifting
|
|
497
|
+
* from the UTC-midnight fix documented below.
|
|
498
|
+
*/
|
|
499
|
+
declare function toDate(value: unknown): Date | null;
|
|
453
500
|
/**
|
|
454
501
|
* Renders a raw cell value as a display string, using the type-appropriate
|
|
455
502
|
* default formatter for `column.type`. Columns with a custom `cell` render
|
|
@@ -457,6 +504,118 @@ declare function alignClassName<TRow>(column: ColumnDef<TRow>): string;
|
|
|
457
504
|
*/
|
|
458
505
|
declare function defaultFormat<TRow>(column: ColumnDef<TRow>, value: unknown): string;
|
|
459
506
|
|
|
507
|
+
/**
|
|
508
|
+
* One row carrying at least one pending edit, as handed to
|
|
509
|
+
* `DataGridEditingOptions.onSave`. `values` is keyed by column id and holds
|
|
510
|
+
* only the columns that actually changed — not a full patched `TRow` — so
|
|
511
|
+
* this works uniformly for `accessorKey` columns (which have one obvious
|
|
512
|
+
* field to write back into) and `accessorFn` columns (which may not: a
|
|
513
|
+
* derived/computed column has no single field of `TRow` an edit could patch
|
|
514
|
+
* back onto).
|
|
515
|
+
*/
|
|
516
|
+
interface EditedRow<TRow> {
|
|
517
|
+
rowId: string;
|
|
518
|
+
/** The row as it looked when its first still-pending edit was made — not necessarily the row's current on-screen data if it was refetched since. */
|
|
519
|
+
row: TRow;
|
|
520
|
+
values: Record<string, unknown>;
|
|
521
|
+
}
|
|
522
|
+
|
|
523
|
+
/**
|
|
524
|
+
* Contract every built-in edit widget implements — the `renderEditCell`
|
|
525
|
+
* equivalent of `filter/widget-types.ts`'s `FilterWidgetProps`. `TColumn` is
|
|
526
|
+
* narrowed to the specific column shape the widget knows how to render (e.g.
|
|
527
|
+
* `EnumColumn` for `EnumEditor`) — `renderDefaultEditWidget` picks the right
|
|
528
|
+
* widget by `column.type` before handing it a column, so the widget itself
|
|
529
|
+
* never has to branch on `type`.
|
|
530
|
+
*
|
|
531
|
+
* `value` is the cell's current value: the row's original value, or a
|
|
532
|
+
* still-pending edit if the user already changed it this session.
|
|
533
|
+
* `onChange` records a new pending value — it does not itself validate or
|
|
534
|
+
* persist anything. `error`, when set, is this cell's current
|
|
535
|
+
* `column.validateEdit` message; every built-in widget shows it as small
|
|
536
|
+
* text under its control and marks the control `aria-invalid`.
|
|
537
|
+
*
|
|
538
|
+
* `rowId` exists purely so each built-in widget's own `data-testid` (`edit-
|
|
539
|
+
* ${rowId}-${column.id}`) stays unique per cell — unlike a filter widget,
|
|
540
|
+
* which renders exactly once per column (in the header), an edit widget
|
|
541
|
+
* renders once per (row, column) pair, so a column-id-only testid would
|
|
542
|
+
* collide across every row the moment a grid has more than one.
|
|
543
|
+
*
|
|
544
|
+
* `autoFocus` is true for exactly one cell per row-activation: the specific
|
|
545
|
+
* column whose static cell the user clicked (or Enter/Space'd) to turn the
|
|
546
|
+
* whole row into editors — every other cell in that same row gets `false`.
|
|
547
|
+
* Every built-in widget forwards it straight to its underlying control's own
|
|
548
|
+
* native `autoFocus` prop, so the browser focuses that one control the
|
|
549
|
+
* moment it mounts, without an extra click to actually start typing.
|
|
550
|
+
*/
|
|
551
|
+
interface EditWidgetProps<TColumn> {
|
|
552
|
+
column: TColumn;
|
|
553
|
+
rowId: string;
|
|
554
|
+
value: unknown;
|
|
555
|
+
onChange: (next: unknown) => void;
|
|
556
|
+
error?: string;
|
|
557
|
+
autoFocus?: boolean;
|
|
558
|
+
}
|
|
559
|
+
/**
|
|
560
|
+
* The `id` every built-in widget gives its own error `<span>`, so its
|
|
561
|
+
* control's `aria-describedby` can point at it — a screen reader announces
|
|
562
|
+
* `aria-invalid` alone with no indication of *why*, so the association
|
|
563
|
+
* matters, not just the flag. Exported for a custom `renderEditCell` that
|
|
564
|
+
* wants the same convention instead of inventing its own id scheme.
|
|
565
|
+
*/
|
|
566
|
+
declare function editErrorId(rowId: string, columnId: string): string;
|
|
567
|
+
|
|
568
|
+
/**
|
|
569
|
+
* The error text every built-in editor shows under its control, associated
|
|
570
|
+
* with it via `id` + the control's own `aria-describedby={editErrorId(...)}`
|
|
571
|
+
* — pulled out to one place so the a11y wiring/styling convention can't
|
|
572
|
+
* drift between the 5 editors the way five independent copies of the same
|
|
573
|
+
* `<span>` inevitably would.
|
|
574
|
+
*/
|
|
575
|
+
declare function EditFieldError({ id, message }: {
|
|
576
|
+
id: string;
|
|
577
|
+
message: string;
|
|
578
|
+
}): ReactElement;
|
|
579
|
+
|
|
580
|
+
/** Default inline editor for `type: "boolean"` columns: a single checkbox. */
|
|
581
|
+
declare function BooleanEditor<TRow>({ column, rowId, value, onChange, error, autoFocus, }: EditWidgetProps<BooleanColumn<TRow>>): ReactElement;
|
|
582
|
+
|
|
583
|
+
/**
|
|
584
|
+
* Default inline editor for `type: "date"` / `type: "datetime"` columns: a
|
|
585
|
+
* native `<input type="date">`/`<input type="datetime-local">`. Emits a
|
|
586
|
+
* `Date` (or `null` for an emptied field), via `parseISO` rather than the
|
|
587
|
+
* bare `new Date(...)` constructor — same convention `DateRangeFilter`'s
|
|
588
|
+
* `parseBound` and `format.ts`'s `toDate` already use, since a native date
|
|
589
|
+
* input's value is a date-only `"YYYY-MM-DD"` string for `type: "date"`,
|
|
590
|
+
* which the JS spec would otherwise parse as UTC midnight instead of local
|
|
591
|
+
* midnight.
|
|
592
|
+
*/
|
|
593
|
+
declare function DateEditor<TRow>({ column, rowId, value, onChange, error, autoFocus, }: EditWidgetProps<DateColumn<TRow>>): ReactElement;
|
|
594
|
+
|
|
595
|
+
/** Default inline editor for `type: "enum"` columns: a single-value select over `column.options`. */
|
|
596
|
+
declare function EnumEditor<TRow>({ column, rowId, value, onChange, error, autoFocus, }: EditWidgetProps<EnumColumn<TRow>>): ReactElement;
|
|
597
|
+
|
|
598
|
+
/**
|
|
599
|
+
* Default inline editor for `type: "number"` / `type: "currency"` columns: a
|
|
600
|
+
* native number input. Emits `null` for an emptied field (not `NaN` or `""`)
|
|
601
|
+
* so `validateEdit`/`onSave` see an explicit "cleared" value; otherwise emits
|
|
602
|
+
* a real `number`, never the input's raw string.
|
|
603
|
+
*/
|
|
604
|
+
declare function NumberEditor<TRow>({ column, rowId, value, onChange, error, autoFocus, }: EditWidgetProps<NumberColumn<TRow>>): ReactElement;
|
|
605
|
+
|
|
606
|
+
/** Default inline editor for `type: "string"` columns: a plain text input. */
|
|
607
|
+
declare function StringEditor<TRow>({ column, rowId, value, onChange, error, autoFocus, }: EditWidgetProps<StringColumn<TRow>>): ReactElement;
|
|
608
|
+
|
|
609
|
+
/**
|
|
610
|
+
* Picks and renders the default inline-edit widget for a column, based
|
|
611
|
+
* purely on `column.type` — the `renderEditCell` equivalent of
|
|
612
|
+
* `filter/registry.tsx`'s `renderDefaultFilterWidget`. `<DataGrid>` calls
|
|
613
|
+
* this itself for any editable column that doesn't set its own
|
|
614
|
+
* `renderEditCell`; a consuming app only reaches for it directly to wrap or
|
|
615
|
+
* extend one of these defaults rather than writing an editor from scratch.
|
|
616
|
+
*/
|
|
617
|
+
declare function renderDefaultEditWidget<TRow>(column: ColumnDef<TRow>, rowId: string, value: unknown, onChange: (next: unknown) => void, error?: string, autoFocus?: boolean): ReactElement;
|
|
618
|
+
|
|
460
619
|
/**
|
|
461
620
|
* Column visibility keyed by `ColumnDef.id`. A missing key means visible —
|
|
462
621
|
* this matches TanStack Table's own `VisibilityState` convention, so a
|
|
@@ -616,6 +775,56 @@ interface DataGridVirtualizeOptions {
|
|
|
616
775
|
/** Whether more rows exist beyond what's currently loaded. `onEndReached` never fires while this is `false`. Defaults to `true`. */
|
|
617
776
|
hasMore?: boolean;
|
|
618
777
|
}
|
|
778
|
+
/**
|
|
779
|
+
* Drives `<DataGrid>`'s built-in inline-editing workflow: cells in a column
|
|
780
|
+
* with `editable` set become interactive editors, and every change
|
|
781
|
+
* accumulates locally (never written back onto the caller's `data`, never
|
|
782
|
+
* sent anywhere on its own) until the user clicks the Save button this
|
|
783
|
+
* renders in a bar above the grid — or Discard, to drop everything back to
|
|
784
|
+
* unedited. There is no partial/per-cell autosave; see `onSave` below for
|
|
785
|
+
* the all-or-nothing commit point.
|
|
786
|
+
*
|
|
787
|
+
* This package has no translation/i18n layer anywhere — `saveLabel`/
|
|
788
|
+
* `discardLabel` are plain strings (or a count-aware function) you supply
|
|
789
|
+
* directly, the same convention every other caller-facing string in this
|
|
790
|
+
* package already follows (`header`, menu item labels, etc.).
|
|
791
|
+
*/
|
|
792
|
+
interface DataGridEditingOptions<TRow> {
|
|
793
|
+
/**
|
|
794
|
+
* Called once, when the user clicks Save, with every row currently
|
|
795
|
+
* holding at least one pending edit and no validation error
|
|
796
|
+
* (`validateEdit`-failing rows are excluded — Save itself stays disabled
|
|
797
|
+
* while ANY row has one, so in practice this only ever fires once none
|
|
798
|
+
* do). `<DataGrid>` keeps its pending-edit state exactly as it was until
|
|
799
|
+
* this resolves: **throw or reject to leave every pending edit in place**
|
|
800
|
+
* (e.g. your own save request failed) rather than losing the user's
|
|
801
|
+
* in-progress edits — `<DataGrid>` surfaces nothing of its own for that
|
|
802
|
+
* case, so show your own error UI. Resolve (or return) normally to clear
|
|
803
|
+
* every pending edit that was included in this call.
|
|
804
|
+
*/
|
|
805
|
+
onSave: (edits: EditedRow<TRow>[]) => void | Promise<void>;
|
|
806
|
+
/** Called after the built-in Discard button clears every pending edit. Omit for no extra behavior beyond that clear. */
|
|
807
|
+
onDiscard?: () => void;
|
|
808
|
+
/**
|
|
809
|
+
* Label for the Save button. A plain string renders as-is — no
|
|
810
|
+
* placeholder substitution, since there's no templating/i18n layer here.
|
|
811
|
+
* Pass a function instead for a count-aware label, e.g. `(count) =>
|
|
812
|
+
* `Apply ${count} change${count === 1 ? "" : "s"}``. Defaults to that
|
|
813
|
+
* exact "Save N change(s)" function.
|
|
814
|
+
*/
|
|
815
|
+
saveLabel?: string | ((changedRowCount: number) => ReactNode);
|
|
816
|
+
/** Label for the Discard button. Same convention as `saveLabel`. Defaults to `"Discard"`. */
|
|
817
|
+
discardLabel?: string | ((changedRowCount: number) => ReactNode);
|
|
818
|
+
/**
|
|
819
|
+
* Disables the Save and Discard buttons and shows Save in a pending
|
|
820
|
+
* state — set this while your own `onSave` promise is in flight (a
|
|
821
|
+
* caller-driven flag, not something `<DataGrid>` infers on its own, since
|
|
822
|
+
* `onSave` may resolve without `<DataGrid>` ever finding out your own
|
|
823
|
+
* server call afterward e.g. still triggered a background refetch).
|
|
824
|
+
* Defaults to false.
|
|
825
|
+
*/
|
|
826
|
+
saving?: boolean;
|
|
827
|
+
}
|
|
619
828
|
interface DataGridProps<TRow> {
|
|
620
829
|
columns: ColumnDef<TRow>[];
|
|
621
830
|
dataSource: DataSource<TRow>;
|
|
@@ -795,6 +1004,16 @@ interface DataGridProps<TRow> {
|
|
|
795
1004
|
onExpandedGroupsChange?: (expanded: Record<string, boolean>) => void;
|
|
796
1005
|
/** Alternates body row backgrounds for readability on wide/dense tables. Defaults to true. */
|
|
797
1006
|
zebra?: boolean;
|
|
1007
|
+
/**
|
|
1008
|
+
* Enables the built-in inline-editing workflow: any column with
|
|
1009
|
+
* `editable` set renders as an interactive editor, edits accumulate
|
|
1010
|
+
* locally, and a Save/Discard bar appears above the grid once at least
|
|
1011
|
+
* one exists. Omit entirely to disable — every `editable` column then
|
|
1012
|
+
* just falls back to its normal static `cell`/`defaultFormat` rendering,
|
|
1013
|
+
* same as if `editable` were never set. See `DataGridEditingOptions` for
|
|
1014
|
+
* the full contract.
|
|
1015
|
+
*/
|
|
1016
|
+
editing?: DataGridEditingOptions<TRow>;
|
|
798
1017
|
}
|
|
799
1018
|
|
|
800
1019
|
/**
|
|
@@ -805,7 +1024,7 @@ interface DataGridProps<TRow> {
|
|
|
805
1024
|
* (`"server"`). Column filter UI defaults to the type-appropriate widget
|
|
806
1025
|
* from `src/filter` unless a column supplies its own `cell` renderer.
|
|
807
1026
|
*/
|
|
808
|
-
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, }: DataGridProps<TRow>): ReactElement;
|
|
1027
|
+
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;
|
|
809
1028
|
|
|
810
1029
|
interface GridStateController {
|
|
811
1030
|
state: GridState;
|
|
@@ -1126,4 +1345,4 @@ interface UseTreeStateOptions<TRow> extends TreeAccessors<TRow> {
|
|
|
1126
1345
|
*/
|
|
1127
1346
|
declare function useTreeState<TRow>({ data, getRowId, getChildren, hasChildren, onLoadChildren, expanded: controlledExpanded, onExpandedChange, childrenMap: controlledChildrenMap, onChildrenMapChange, }: UseTreeStateOptions<TRow>): TreeStateController<TRow>;
|
|
1128
1347
|
|
|
1129
|
-
export { ActionsMenu, type BaseColumn, type BooleanColumn, BooleanFilter, type ClientProcessingResult, type ColumnAlign, type ColumnDef, type ColumnGroup, ColumnSelector, type ColumnSelectorProps, type ColumnVisibility, type CompositeFilterDescriptor, DataGrid, type DataGridProps, type DataSource, type DateColumn, DateRangeFilter, type DebouncedCallback, type EnumColumn, EnumFilter, type EnumOption, type FilterDescriptor, type FilterOperator, type FilterWidgetProps, type FlatTreeRow, type GridState, type GridStateController, type MenuItem, type MenuItemContext, type NumberColumn, NumberComparisonFilter, NumberHistogramFilter, type NumberHistogramFilterProps, NumberRangeFilter, type ResolvedMenuItem, type SortDescriptor, type StringColumn, StringFilter, type TreeAccessors, TreeDataGrid, type TreeDataGridProps, type TreeStateController, UNARY_OPERATORS, type UseTreeStateOptions, alignClassName, canHideColumn, canHideGroup, countVisible, defaultAlign, defaultFormat, evaluateFilter, facetedNumberValues, fieldKey, flattenTree, getColumnValue, groupColumns, isColumnVisible, isCompositeFilterDescriptor, isFilterDescriptor, isFilterable, isSortable, processClientData, renderDefaultFilterWidget, resolveMenuItems, storageKeyFor, useDebouncedCallback, useGridState, useTreeState };
|
|
1348
|
+
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 DataGridEditingOptions, type DataGridProps, type DataSource, type DateColumn, DateEditor, DateRangeFilter, type DebouncedCallback, EditFieldError, type EditWidgetProps, type EditedRow, type EnumColumn, EnumEditor, EnumFilter, type EnumOption, type FilterDescriptor, type FilterOperator, type FilterWidgetProps, type FlatTreeRow, type GridState, type GridStateController, type MenuItem, type MenuItemContext, type NumberColumn, NumberComparisonFilter, NumberEditor, NumberHistogramFilter, type NumberHistogramFilterProps, NumberRangeFilter, type ResolvedMenuItem, type SortDescriptor, 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, resolveMenuItems, storageKeyFor, toDate, useDebouncedCallback, useGridState, useTreeState };
|