@jielga/tmdatagrid 1.0.0 → 1.0.2
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/README.md +8 -8
- package/dist/index.d.ts +225 -225
- package/dist/index.js +58 -50
- package/dist/index.js.map +1 -1
- package/dist/styles.css +1 -1
- package/package.json +3 -2
- package/skills/appearance/SKILL.md +322 -0
- package/skills/cell-selection/SKILL.md +240 -0
- package/skills/columns/SKILL.md +261 -86
- package/skills/data/SKILL.md +289 -0
- package/skills/editing/SKILL.md +492 -0
- package/skills/editing/references/editing-api.md +124 -0
- package/skills/editing/references/editors-and-validation.md +198 -0
- package/skills/filtering/SKILL.md +344 -0
- package/skills/getting-started/SKILL.md +48 -27
- package/skills/grouping/SKILL.md +264 -0
- package/skills/options/SKILL.md +31 -20
- package/skills/rows/SKILL.md +369 -0
- package/skills/rows/references/rows-api.md +117 -0
- package/skills/server-side/SKILL.md +7 -7
- package/skills/testing/SKILL.md +12 -12
- package/src/tmdatagrid/TMDataGridContext.ts +2 -2
- package/src/tmdatagrid/components/TMDataGrid.module.css +2 -2
- package/src/tmdatagrid/components/TMDataGrid.tsx +5 -5
- package/src/tmdatagrid/components/TMDataGridCellEditor.tsx +4 -4
- package/src/tmdatagrid/components/TMDataGridColumnsPanel.tsx +2 -2
- package/src/tmdatagrid/components/TMDataGridDetailsColumn.tsx +6 -6
- package/src/tmdatagrid/components/TMDataGridEditActions.tsx +2 -2
- package/src/tmdatagrid/components/TMDataGridEditColumn.tsx +4 -4
- package/src/tmdatagrid/components/TMDataGridEntryRows.tsx +6 -6
- package/src/tmdatagrid/components/TMDataGridFilterPanel.tsx +6 -6
- package/src/tmdatagrid/components/TMDataGridFilterPills.module.css +2 -2
- package/src/tmdatagrid/components/TMDataGridFilterPills.tsx +1 -1
- package/src/tmdatagrid/components/TMDataGridFooter.module.css +1 -1
- package/src/tmdatagrid/components/TMDataGridFooter.tsx +12 -6
- package/src/tmdatagrid/components/TMDataGridGroupColumn.module.css +1 -1
- package/src/tmdatagrid/components/TMDataGridGroupColumn.tsx +5 -5
- package/src/tmdatagrid/components/TMDataGridHeaderCell.module.css +8 -8
- package/src/tmdatagrid/components/TMDataGridHeaderCell.tsx +12 -12
- package/src/tmdatagrid/components/TMDataGridRowNumberColumn.tsx +4 -4
- package/src/tmdatagrid/components/TMDataGridSearch.tsx +5 -5
- package/src/tmdatagrid/components/TMDataGridSelectColumn.tsx +8 -8
- package/src/tmdatagrid/components/TMDataGridTable.module.css +18 -18
- package/src/tmdatagrid/components/TMDataGridTable.tsx +116 -116
- package/src/tmdatagrid/components/TMDataGridToolbar.tsx +5 -5
- package/src/tmdatagrid/components/editors/TMDataGridBooleanEditor.tsx +1 -1
- package/src/tmdatagrid/components/editors/TMDataGridDateEditor.tsx +2 -2
- package/src/tmdatagrid/components/editors/TMDataGridMultiSelectEditor.tsx +1 -1
- package/src/tmdatagrid/components/editors/TMDataGridNumberEditor.tsx +1 -1
- package/src/tmdatagrid/components/editors/TMDataGridSelectEditor.tsx +2 -2
- package/src/tmdatagrid/components/editors/editorShared.ts +3 -3
- package/src/tmdatagrid/components/filters/DgDateRangeFilter.tsx +1 -1
- package/src/tmdatagrid/components/filters/DgRangeSliderFilter.tsx +1 -1
- package/src/tmdatagrid/components/filters/DgTriStateFilter.tsx +1 -1
- package/src/tmdatagrid/components/filters/TMDataGridFilterValueInput.tsx +2 -2
- package/src/tmdatagrid/components/sticky.module.css +8 -8
- package/src/tmdatagrid/core/autosize.ts +4 -4
- package/src/tmdatagrid/core/capabilities.ts +17 -17
- package/src/tmdatagrid/core/cellExport.ts +13 -13
- package/src/tmdatagrid/core/cellNavigation.ts +6 -6
- package/src/tmdatagrid/core/cellRange.ts +4 -4
- package/src/tmdatagrid/core/columnOptions.ts +2 -2
- package/src/tmdatagrid/core/columnOrdering.ts +2 -2
- package/src/tmdatagrid/core/columnUtils.ts +3 -3
- package/src/tmdatagrid/core/editEngine.ts +49 -49
- package/src/tmdatagrid/core/expanding.ts +5 -5
- package/src/tmdatagrid/core/filterControls.ts +5 -5
- package/src/tmdatagrid/core/filterOperators.ts +14 -14
- package/src/tmdatagrid/core/labels.ts +8 -8
- package/src/tmdatagrid/core/matchHighlight.ts +4 -4
- package/src/tmdatagrid/core/persistence.ts +8 -8
- package/src/tmdatagrid/core/quickSearch.ts +8 -8
- package/src/tmdatagrid/core/rowPinning.ts +3 -3
- package/src/tmdatagrid/core/rowSelection.ts +12 -12
- package/src/tmdatagrid/core/sizes.ts +1 -1
- package/src/tmdatagrid/core/summary.ts +3 -3
- package/src/tmdatagrid/useTMDataGrid.tsx +79 -79
- package/skills/features/SKILL.md +0 -352
|
@@ -55,8 +55,8 @@ export type TMDataGridSettingsSlice = (typeof SETTINGS_STATE_SLICES)[number];
|
|
|
55
55
|
/**
|
|
56
56
|
* A storage key, optionally narrowed to a subset of its group's slices.
|
|
57
57
|
*
|
|
58
|
-
* - `"employees.data"`
|
|
59
|
-
* - `["employees.data", ["sorting"]]`
|
|
58
|
+
* - `"employees.data"` - persists every slice in the group.
|
|
59
|
+
* - `["employees.data", ["sorting"]]` - persists only the listed slices.
|
|
60
60
|
*/
|
|
61
61
|
export type TMDataGridPersistKey<TSlice extends string> =
|
|
62
62
|
| string
|
|
@@ -83,7 +83,7 @@ export type TMDataGridPersistence = {
|
|
|
83
83
|
* collide with. A payload whose version does not match is dropped whole: a
|
|
84
84
|
* migration would be guessing at a shape this code no longer knows, and the
|
|
85
85
|
* cost of dropping is one lost layout. Payloads written before versioning
|
|
86
|
-
* existed (≤0.4.0) have no stamp and are dropped the same way
|
|
86
|
+
* existed (≤0.4.0) have no stamp and are dropped the same way - the 1.0
|
|
87
87
|
* wave's one-time break, named in its changeset.
|
|
88
88
|
*/
|
|
89
89
|
export const PERSIST_PAYLOAD_VERSION = 1;
|
|
@@ -163,7 +163,7 @@ const SLICE_GUARDS: Record<
|
|
|
163
163
|
(value: unknown) => boolean
|
|
164
164
|
> = {
|
|
165
165
|
columnFilters: (value) => isArrayOf(value, hasStringId),
|
|
166
|
-
// TanStack leaves the global filter value untyped
|
|
166
|
+
// TanStack leaves the global filter value untyped - the grid's own default
|
|
167
167
|
// filters on a string, but a consumer may store anything here.
|
|
168
168
|
globalFilter: () => true,
|
|
169
169
|
sorting: (value) =>
|
|
@@ -266,7 +266,7 @@ const defaultSerialize = (value: Partial<GridState>): string =>
|
|
|
266
266
|
* The leaf column ids a set of column defs will produce, by TanStack's own
|
|
267
267
|
* derivation: `id`, else `accessorKey` with dots replaced by underscores,
|
|
268
268
|
* else a string `header`. Mirrored here so restored state can be realigned
|
|
269
|
-
* against the columns that will actually exist
|
|
269
|
+
* against the columns that will actually exist - deriving ids any other way
|
|
270
270
|
* would realign against names the table never uses.
|
|
271
271
|
*/
|
|
272
272
|
export function collectLeafColumnIds(
|
|
@@ -295,7 +295,7 @@ export function collectLeafColumnIds(
|
|
|
295
295
|
* Drops restored entries that name columns the grid no longer has.
|
|
296
296
|
*
|
|
297
297
|
* A stored layout outlives the column set: a column removed between deploys
|
|
298
|
-
* would otherwise linger forever
|
|
298
|
+
* would otherwise linger forever - a ghost id in the order, a width for
|
|
299
299
|
* nothing, and worse, a *filter or sort that is active but has no column to
|
|
300
300
|
* show for itself*. New columns need no counterpart here: TanStack appends
|
|
301
301
|
* columns missing from `columnOrder` on its own, in definition order.
|
|
@@ -337,8 +337,8 @@ function realignToColumns(
|
|
|
337
337
|
/**
|
|
338
338
|
* State to merge into `initialState`, read once on mount.
|
|
339
339
|
*
|
|
340
|
-
* With `knownColumnIds`
|
|
341
|
-
* lanes included
|
|
340
|
+
* With `knownColumnIds` - every id the grid is about to construct, generated
|
|
341
|
+
* lanes included - the column-shaped slices are realigned first; see
|
|
342
342
|
* {@link realignToColumns}. Without it the payload is returned as stored.
|
|
343
343
|
*/
|
|
344
344
|
export function readPersistedState(
|
|
@@ -12,11 +12,11 @@ import {
|
|
|
12
12
|
type TableFeatures,
|
|
13
13
|
} from "@tanstack/react-table";
|
|
14
14
|
|
|
15
|
-
/** How the quick search matches
|
|
15
|
+
/** How the quick search matches - see `quickSearchMode` on the hook options. */
|
|
16
16
|
export type TMDataGridQuickSearchMode = "fuzzy" | "contains";
|
|
17
17
|
|
|
18
18
|
/**
|
|
19
|
-
* The fuzzy filter's registry name
|
|
19
|
+
* The fuzzy filter's registry name - what `globalFilterFn` resolves to while
|
|
20
20
|
* `quickSearchMode` is `"fuzzy"`. The rank ordering keys off this name, so an
|
|
21
21
|
* explicit `globalFilterFn` override switches the ordering off with it.
|
|
22
22
|
*/
|
|
@@ -37,8 +37,8 @@ function isFuzzyFilterMeta(value: unknown): value is FuzzyFilterMeta {
|
|
|
37
37
|
|
|
38
38
|
/**
|
|
39
39
|
* Match-sorter ranking as the global filter: a row passes when a globally
|
|
40
|
-
* filterable column ranks above match-sorter's threshold
|
|
41
|
-
* characters forgiven
|
|
40
|
+
* filterable column ranks above match-sorter's threshold - typos and skipped
|
|
41
|
+
* characters forgiven - and the rank is recorded for the ordering to read.
|
|
42
42
|
*
|
|
43
43
|
* TanStack stops probing a row's columns at the first passing one, so the
|
|
44
44
|
* recorded ranks cover the columns up to and including it; the best of those
|
|
@@ -81,7 +81,7 @@ function bestRank<TFeatures extends TableFeatures, TData extends RowData>(
|
|
|
81
81
|
|
|
82
82
|
/**
|
|
83
83
|
* Whether the ranked ordering applies: the fuzzy quick search is narrowing
|
|
84
|
-
* the grid, and nothing else claims an order
|
|
84
|
+
* the grid, and nothing else claims an order - no sort, no grouping.
|
|
85
85
|
*/
|
|
86
86
|
function isRankingActive<TFeatures extends TableFeatures, TData extends RowData>(
|
|
87
87
|
table: Table<TFeatures, TData>,
|
|
@@ -106,7 +106,7 @@ function isRankingActive<TFeatures extends TableFeatures, TData extends RowData>
|
|
|
106
106
|
|
|
107
107
|
/**
|
|
108
108
|
* The sorted row model, with one addition: while {@link isRankingActive},
|
|
109
|
-
* rows order by match quality, best first. Declarative
|
|
109
|
+
* rows order by match quality, best first. Declarative - the ordering is
|
|
110
110
|
* derived from filter state, never written into `sorting`, so no column
|
|
111
111
|
* claims `aria-sort`, the persisted slice stays untouched, and the user's
|
|
112
112
|
* next sort click suspends it just by existing.
|
|
@@ -121,8 +121,8 @@ export function createFuzzyRankedSortedRowModel<
|
|
|
121
121
|
const base = createSortedRowModel<TFeatures, TData>();
|
|
122
122
|
return (table) => {
|
|
123
123
|
const getSorted = base(table);
|
|
124
|
-
// One-slot memo: every input of the ordering
|
|
125
|
-
// sorting and grouping states
|
|
124
|
+
// One-slot memo: every input of the ordering - filter text, data, the
|
|
125
|
+
// sorting and grouping states - changes the sorted model's identity, so
|
|
126
126
|
// the model alone is the cache key.
|
|
127
127
|
let lastModel: RowModel<TFeatures, TData> | null = null;
|
|
128
128
|
let ranked: RowModel<TFeatures, TData> | null = null;
|
|
@@ -5,7 +5,7 @@ import type { TMDataGridFeatures, TMDataGridTable } from "../useTMDataGrid";
|
|
|
5
5
|
* The rows pinned to one edge, resolved safely and in pin order.
|
|
6
6
|
*
|
|
7
7
|
* Not TanStack's `getTopRows()`: that resolves each pinned id with
|
|
8
|
-
* `getRow(id, true)`, which throws once the row's data is gone
|
|
8
|
+
* `getRow(id, true)`, which throws once the row's data is gone - and pinned
|
|
9
9
|
* ids outlive data. A delete, a server-side page swap, a refetch that comes
|
|
10
10
|
* back without the row: any of these would take the whole grid down. Here a
|
|
11
11
|
* stale id is skipped instead; it stays in state, harmless, and the row
|
|
@@ -13,8 +13,8 @@ import type { TMDataGridFeatures, TMDataGridTable } from "../useTMDataGrid";
|
|
|
13
13
|
*
|
|
14
14
|
* The semantics are TanStack's `keepPinnedRows: true`: a pinned row stays at
|
|
15
15
|
* its edge even when a filter or the pager would have dropped it from the
|
|
16
|
-
* body. Ids resolve against the pre-pagination model first
|
|
17
|
-
* the live sort and filter context
|
|
16
|
+
* body. Ids resolve against the pre-pagination model first - those rows carry
|
|
17
|
+
* the live sort and filter context - with the core model as the fallback for
|
|
18
18
|
* rows the filters removed. A leaf whose group is collapsed stays hidden,
|
|
19
19
|
* as upstream does.
|
|
20
20
|
*/
|
|
@@ -5,17 +5,17 @@ import type { TMDataGridFeatures, TMDataGridTable } from "../useTMDataGrid";
|
|
|
5
5
|
|
|
6
6
|
/**
|
|
7
7
|
* Rows in the order they are displayed, which is the order a shift-click range
|
|
8
|
-
* is measured over
|
|
8
|
+
* is measured over - so a range follows the active sort and skips filtered-out
|
|
9
9
|
* rows. Under pagination it is the current page, so a range cannot cross a page
|
|
10
10
|
* boundary.
|
|
11
11
|
*
|
|
12
12
|
* Once a column is grouped this includes the group rows, and only the leaves of
|
|
13
|
-
* groups that are open
|
|
13
|
+
* groups that are open - and paging is suspended, so it is the whole tree. That
|
|
14
14
|
* is the right list for a range: it is what the user can see, and a range that
|
|
15
15
|
* swept collapsed rows would select things off screen. What a group row in the
|
|
16
16
|
* range contributes is decided by {@link getSelectableRowIds}.
|
|
17
17
|
*
|
|
18
|
-
* Rows pinned to an edge leave this list
|
|
18
|
+
* Rows pinned to an edge leave this list - they render in their own sticky
|
|
19
19
|
* blocks, outside the scrolling order a shift-click range or the virtualizer
|
|
20
20
|
* walks. See `readPinnedRows`.
|
|
21
21
|
*/
|
|
@@ -42,7 +42,7 @@ export function getDisplayedRows<TData extends RowData>(
|
|
|
42
42
|
* to go looking for, and counting only the top-level rows quietly redefines
|
|
43
43
|
* "rows per page" as groups per page, so a page of 25 can hold thousands of
|
|
44
44
|
* rows. Rather than pick, the grid renders the whole tree and leans on the
|
|
45
|
-
* virtualizer
|
|
45
|
+
* virtualizer - which is its default mode anyway, pagination being opt-in.
|
|
46
46
|
*
|
|
47
47
|
* `TMDataGrid.Footer` reads this too, and greys the pager out rather than
|
|
48
48
|
* hiding it, so the pager going quiet is visible instead of mysterious.
|
|
@@ -56,7 +56,7 @@ export function isPagingActive<TData extends RowData>(
|
|
|
56
56
|
|
|
57
57
|
/**
|
|
58
58
|
* Which modifiers were held. Named for what they mean rather than for the keys,
|
|
59
|
-
* because the keys differ per platform
|
|
59
|
+
* because the keys differ per platform - `toggle` is Ctrl on Windows/Linux and
|
|
60
60
|
* Cmd on macOS.
|
|
61
61
|
*/
|
|
62
62
|
export type TMDataGridRowClickModifiers = {
|
|
@@ -65,7 +65,7 @@ export type TMDataGridRowClickModifiers = {
|
|
|
65
65
|
};
|
|
66
66
|
|
|
67
67
|
export type ResolveRowSelectionClickArgs<TData extends RowData> = {
|
|
68
|
-
/** Displayed order
|
|
68
|
+
/** Displayed order - see {@link getDisplayedRows}. */
|
|
69
69
|
rows: ReadonlyArray<Row<TMDataGridFeatures, TData>>;
|
|
70
70
|
rowId: string;
|
|
71
71
|
/** The pivot a shift-click extends from. */
|
|
@@ -76,7 +76,7 @@ export type ResolveRowSelectionClickArgs<TData extends RowData> = {
|
|
|
76
76
|
* Whether this gesture is allowed to clear rows it did not touch.
|
|
77
77
|
*
|
|
78
78
|
* `true` for a bare row click, where replacing is the whole point. `false` for
|
|
79
|
-
* a checkbox, which is only ever additive
|
|
79
|
+
* a checkbox, which is only ever additive - ticking one box has never cleared
|
|
80
80
|
* the others, and shift-clicking one adds the range rather than becoming it.
|
|
81
81
|
*/
|
|
82
82
|
canReplaceSelection: boolean;
|
|
@@ -138,7 +138,7 @@ export function resolveRowSelectionClick<TData extends RowData>({
|
|
|
138
138
|
}: ResolveRowSelectionClickArgs<TData>): ResolvedRowSelection {
|
|
139
139
|
const index = rows.findIndex((row) => row.id === rowId);
|
|
140
140
|
const clickedRow = rows[index];
|
|
141
|
-
// Clicked row is not in the displayed set
|
|
141
|
+
// Clicked row is not in the displayed set - nothing sensible to resolve.
|
|
142
142
|
if (index === -1 || clickedRow === undefined) return { selection, anchorRowId };
|
|
143
143
|
|
|
144
144
|
const targets = getSelectableRowIds(clickedRow);
|
|
@@ -152,7 +152,7 @@ export function resolveRowSelectionClick<TData extends RowData>({
|
|
|
152
152
|
//
|
|
153
153
|
// This has to be enforced here. Rebuilding the map and handing it to
|
|
154
154
|
// `setRowSelection` skips `mutateRowIsSelected`, which is where TanStack
|
|
155
|
-
// clears the other rows
|
|
155
|
+
// clears the other rows - so without this, Ctrl and Shift would quietly
|
|
156
156
|
// produce the multi-selection the option ruled out.
|
|
157
157
|
if (!clickedRow.getCanMultiSelect()) {
|
|
158
158
|
// A group stands for several rows, which single-select cannot express. The
|
|
@@ -179,12 +179,12 @@ export function resolveRowSelectionClick<TData extends RowData>({
|
|
|
179
179
|
const from = Math.min(anchorIndex, index);
|
|
180
180
|
const to = Math.max(anchorIndex, index);
|
|
181
181
|
// Ctrl+Shift adds to what is already selected; Shift alone becomes the
|
|
182
|
-
// range
|
|
182
|
+
// range - unless the gesture may not replace, in which case it also adds.
|
|
183
183
|
const next: RowSelectionState =
|
|
184
184
|
modifiers.toggle || !canReplaceSelection ? { ...selection } : {};
|
|
185
185
|
for (const row of rows.slice(from, to + 1)) {
|
|
186
186
|
// A group row inside the range brings its whole subtree, including leaves
|
|
187
|
-
// that are collapsed out of `rows`
|
|
187
|
+
// that are collapsed out of `rows` - sweeping past a closed group selects
|
|
188
188
|
// it entire, which is the only reading that matches what it displays.
|
|
189
189
|
for (const id of getSelectableRowIds(row)) next[id] = true;
|
|
190
190
|
}
|
|
@@ -195,7 +195,7 @@ export function resolveRowSelectionClick<TData extends RowData>({
|
|
|
195
195
|
if (modifiers.toggle || !canReplaceSelection) {
|
|
196
196
|
const next: RowSelectionState = { ...selection };
|
|
197
197
|
// Asked of the targets rather than of `rowId`: a group row carries no id in
|
|
198
|
-
// the map, so it counts as selected exactly when all of its leaves do
|
|
198
|
+
// the map, so it counts as selected exactly when all of its leaves do -
|
|
199
199
|
// which is also when its checkbox shows a tick rather than a dash.
|
|
200
200
|
const allSelected = targets.every((id) => selection[id] === true);
|
|
201
201
|
for (const id of targets) {
|
|
@@ -7,7 +7,7 @@ export const DEFAULT_TMDATAGRID_SIZE: TMDataGridSize = "md";
|
|
|
7
7
|
/**
|
|
8
8
|
* Row height per size, in px.
|
|
9
9
|
*
|
|
10
|
-
* The virtualizer needs this as a number
|
|
10
|
+
* The virtualizer needs this as a number - it cannot read the CSS variable -
|
|
11
11
|
* so the scale lives here and `TMDataGrid.module.css` mirrors it. `meta.rowHeight`
|
|
12
12
|
* overrides it when a grid needs a height the scale doesn't offer.
|
|
13
13
|
*/
|
|
@@ -2,11 +2,11 @@ import { aggregationFns, type RowData } from "@tanstack/react-table";
|
|
|
2
2
|
import type { TMDataGridRowData } from "../TMDataGridContext";
|
|
3
3
|
import type { TMDataGridTable } from "../useTMDataGrid";
|
|
4
4
|
|
|
5
|
-
/** The registered aggregation names
|
|
5
|
+
/** The registered aggregation names - the same set `aggregationFn` accepts. */
|
|
6
6
|
export type TMDataGridAggregationName = keyof typeof aggregationFns;
|
|
7
7
|
|
|
8
8
|
/**
|
|
9
|
-
* One column aggregated over every filtered row
|
|
9
|
+
* One column aggregated over every filtered row - the number a summary-row
|
|
10
10
|
* `footer` wants:
|
|
11
11
|
*
|
|
12
12
|
* ```tsx
|
|
@@ -16,7 +16,7 @@ export type TMDataGridAggregationName = keyof typeof aggregationFns;
|
|
|
16
16
|
* ```
|
|
17
17
|
*
|
|
18
18
|
* Filtered rather than paginated rows, so the total covers everything the
|
|
19
|
-
* filters left
|
|
19
|
+
* filters left (all pages), and follows the filters as they change. Reuses
|
|
20
20
|
* TanStack's registered aggregation functions; `fn` defaults to `"sum"`.
|
|
21
21
|
*/
|
|
22
22
|
export function aggregateColumn<TData extends RowData>({
|