@jielga/tmdatagrid 1.0.0 → 1.0.1

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.
Files changed (68) hide show
  1. package/README.md +8 -8
  2. package/dist/index.d.ts +225 -225
  3. package/dist/index.js +58 -50
  4. package/dist/index.js.map +1 -1
  5. package/dist/styles.css +1 -1
  6. package/package.json +3 -2
  7. package/skills/columns/SKILL.md +4 -4
  8. package/skills/features/SKILL.md +30 -30
  9. package/skills/getting-started/SKILL.md +16 -16
  10. package/skills/options/SKILL.md +8 -8
  11. package/skills/server-side/SKILL.md +7 -7
  12. package/skills/testing/SKILL.md +12 -12
  13. package/src/tmdatagrid/TMDataGridContext.ts +2 -2
  14. package/src/tmdatagrid/components/TMDataGrid.module.css +2 -2
  15. package/src/tmdatagrid/components/TMDataGrid.tsx +5 -5
  16. package/src/tmdatagrid/components/TMDataGridCellEditor.tsx +4 -4
  17. package/src/tmdatagrid/components/TMDataGridColumnsPanel.tsx +2 -2
  18. package/src/tmdatagrid/components/TMDataGridDetailsColumn.tsx +6 -6
  19. package/src/tmdatagrid/components/TMDataGridEditActions.tsx +2 -2
  20. package/src/tmdatagrid/components/TMDataGridEditColumn.tsx +4 -4
  21. package/src/tmdatagrid/components/TMDataGridEntryRows.tsx +6 -6
  22. package/src/tmdatagrid/components/TMDataGridFilterPanel.tsx +6 -6
  23. package/src/tmdatagrid/components/TMDataGridFilterPills.module.css +2 -2
  24. package/src/tmdatagrid/components/TMDataGridFilterPills.tsx +1 -1
  25. package/src/tmdatagrid/components/TMDataGridFooter.module.css +1 -1
  26. package/src/tmdatagrid/components/TMDataGridFooter.tsx +12 -6
  27. package/src/tmdatagrid/components/TMDataGridGroupColumn.module.css +1 -1
  28. package/src/tmdatagrid/components/TMDataGridGroupColumn.tsx +5 -5
  29. package/src/tmdatagrid/components/TMDataGridHeaderCell.module.css +8 -8
  30. package/src/tmdatagrid/components/TMDataGridHeaderCell.tsx +12 -12
  31. package/src/tmdatagrid/components/TMDataGridRowNumberColumn.tsx +4 -4
  32. package/src/tmdatagrid/components/TMDataGridSearch.tsx +5 -5
  33. package/src/tmdatagrid/components/TMDataGridSelectColumn.tsx +8 -8
  34. package/src/tmdatagrid/components/TMDataGridTable.module.css +18 -18
  35. package/src/tmdatagrid/components/TMDataGridTable.tsx +116 -116
  36. package/src/tmdatagrid/components/TMDataGridToolbar.tsx +5 -5
  37. package/src/tmdatagrid/components/editors/TMDataGridBooleanEditor.tsx +1 -1
  38. package/src/tmdatagrid/components/editors/TMDataGridDateEditor.tsx +2 -2
  39. package/src/tmdatagrid/components/editors/TMDataGridMultiSelectEditor.tsx +1 -1
  40. package/src/tmdatagrid/components/editors/TMDataGridNumberEditor.tsx +1 -1
  41. package/src/tmdatagrid/components/editors/TMDataGridSelectEditor.tsx +2 -2
  42. package/src/tmdatagrid/components/editors/editorShared.ts +3 -3
  43. package/src/tmdatagrid/components/filters/DgDateRangeFilter.tsx +1 -1
  44. package/src/tmdatagrid/components/filters/DgRangeSliderFilter.tsx +1 -1
  45. package/src/tmdatagrid/components/filters/DgTriStateFilter.tsx +1 -1
  46. package/src/tmdatagrid/components/filters/TMDataGridFilterValueInput.tsx +2 -2
  47. package/src/tmdatagrid/components/sticky.module.css +8 -8
  48. package/src/tmdatagrid/core/autosize.ts +4 -4
  49. package/src/tmdatagrid/core/capabilities.ts +17 -17
  50. package/src/tmdatagrid/core/cellExport.ts +13 -13
  51. package/src/tmdatagrid/core/cellNavigation.ts +6 -6
  52. package/src/tmdatagrid/core/cellRange.ts +4 -4
  53. package/src/tmdatagrid/core/columnOptions.ts +2 -2
  54. package/src/tmdatagrid/core/columnOrdering.ts +2 -2
  55. package/src/tmdatagrid/core/columnUtils.ts +3 -3
  56. package/src/tmdatagrid/core/editEngine.ts +49 -49
  57. package/src/tmdatagrid/core/expanding.ts +5 -5
  58. package/src/tmdatagrid/core/filterControls.ts +5 -5
  59. package/src/tmdatagrid/core/filterOperators.ts +14 -14
  60. package/src/tmdatagrid/core/labels.ts +8 -8
  61. package/src/tmdatagrid/core/matchHighlight.ts +4 -4
  62. package/src/tmdatagrid/core/persistence.ts +8 -8
  63. package/src/tmdatagrid/core/quickSearch.ts +8 -8
  64. package/src/tmdatagrid/core/rowPinning.ts +3 -3
  65. package/src/tmdatagrid/core/rowSelection.ts +12 -12
  66. package/src/tmdatagrid/core/sizes.ts +1 -1
  67. package/src/tmdatagrid/core/summary.ts +3 -3
  68. package/src/tmdatagrid/useTMDataGrid.tsx +79 -79
@@ -26,7 +26,7 @@ export function TMDataGridToolbarSpacer() {
26
26
  /**
27
27
  * A small spinner shown while `meta.loading` is true, and nothing otherwise.
28
28
  *
29
- * The body only shows its loading state while the grid is *empty* — a
29
+ * The body only shows its loading state while the grid is *empty* - a
30
30
  * server-driven grid refetching with rows on screen keeps showing them, which
31
31
  * is right, but leaves nothing saying a fetch is running. This is that signal,
32
32
  * and the consumer decides where it sits by placing it in the toolbar:
@@ -48,7 +48,7 @@ export function TMDataGridLoadingIndicator() {
48
48
 
49
49
  /**
50
50
  * Visible rows over total rows. On a server-driven grid, set
51
- * `meta.totalRowCount` for the denominator — the client never sees every row.
51
+ * `meta.totalRowCount` for the denominator - the client never sees every row.
52
52
  */
53
53
  export function TMDataGridSummaryCount({ children }: { children?: ReactNode }) {
54
54
  const { table, controlSize } = useTMDataGridContext();
@@ -56,7 +56,7 @@ export function TMDataGridSummaryCount({ children }: { children?: ReactNode }) {
56
56
 
57
57
  if (children !== undefined) {
58
58
  return (
59
- <Text size={controlSize} c="dimmed" data-dg-part="summary-count">
59
+ <Text span size={controlSize} c="dimmed" data-dg-part="summary-count">
60
60
  {children}
61
61
  </Text>
62
62
  );
@@ -68,14 +68,14 @@ export function TMDataGridSummaryCount({ children }: { children?: ReactNode }) {
68
68
  table.getPreFilteredRowModel().rows.length;
69
69
 
70
70
  return (
71
- <Text size={controlSize} c="dimmed" data-dg-part="summary-count">
71
+ <Text span size={controlSize} c="dimmed" data-dg-part="summary-count">
72
72
  {shown} / {total}
73
73
  </Text>
74
74
  );
75
75
  }
76
76
 
77
77
  /**
78
- * Burger menu in the grid's top-right corner — opens "Manage columns".
78
+ * Burger menu in the grid's top-right corner - opens "Manage columns".
79
79
  * Renders nothing when no column can be hidden (`enableHiding: false`).
80
80
  */
81
81
  export function TMDataGridColumnsButton() {
@@ -4,7 +4,7 @@ import { getColumnLabel } from "../../core/columnUtils";
4
4
  import { useTMDataGridContext } from "../../TMDataGridContext";
5
5
  import { useFieldError, useFieldValue } from "./editorShared";
6
6
 
7
- /** The built-in editor for `meta.type: "boolean"` — a focused checkbox. */
7
+ /** The built-in editor for `meta.type: "boolean"` - a focused checkbox. */
8
8
  export function TMDataGridBooleanEditor({
9
9
  field,
10
10
  autoFocus,
@@ -6,7 +6,7 @@ import { useTMDataGridContext } from "../../TMDataGridContext";
6
6
  import { useFieldError, useFieldValue } from "./editorShared";
7
7
 
8
8
  /**
9
- * The built-in editor for `meta.type: "date"` — the native
9
+ * The built-in editor for `meta.type: "date"` - the native
10
10
  * `<input type="date">` styled by Mantine, no `@mantine/dates` involved. A
11
11
  * consumer wanting a real picker plugs one in through `meta.editor`.
12
12
  */
@@ -20,7 +20,7 @@ export function TMDataGridDateEditor({
20
20
  const value = useFieldValue(field);
21
21
  const error = useFieldError(field);
22
22
  // The cell's original shape decides what the editor writes back: a `Date`
23
- // cell keeps getting Dates, an ISO-string cell keeps getting strings —
23
+ // cell keeps getting Dates, an ISO-string cell keeps getting strings -
24
24
  // decided once at open, so clearing and retyping cannot flip the type.
25
25
  const writesDates = useRef(value instanceof Date);
26
26
 
@@ -9,7 +9,7 @@ import { useTMDataGridContext } from "../../TMDataGridContext";
9
9
  import { useFieldError, useFieldValue } from "./editorShared";
10
10
 
11
11
  /**
12
- * The built-in editor for `meta.type: "multiSelect"` — cells holding string
12
+ * The built-in editor for `meta.type: "multiSelect"` - cells holding string
13
13
  * arrays. Never commits on pick: building a set takes several, so the commit
14
14
  * stays on Enter/blur like a text edit.
15
15
  */
@@ -26,7 +26,7 @@ export function TMDataGridNumberEditor({
26
26
  value={typeof value === "number" ? value : ""}
27
27
  onChange={(next) =>
28
28
  // Mantine reports a number once one can be parsed, and a string while
29
- // it cannot. An empty cell is `null` — the honest "no value".
29
+ // it cannot. An empty cell is `null` - the honest "no value".
30
30
  field.handleChange(
31
31
  typeof next === "number" ? next : next === "" ? null : Number(next),
32
32
  )
@@ -10,7 +10,7 @@ import { useFieldError, useFieldValue } from "./editorShared";
10
10
 
11
11
  /**
12
12
  * The built-in editor for `meta.type: "select"`. Options come from the same
13
- * `meta.options` the filter panel reads — with the row in hand, so a
13
+ * `meta.options` the filter panel reads - with the row in hand, so a
14
14
  * function source can depend on the record being edited.
15
15
  */
16
16
  export function TMDataGridSelectEditor({
@@ -31,7 +31,7 @@ export function TMDataGridSelectEditor({
31
31
  w="100%"
32
32
  autoFocus={autoFocus}
33
33
  searchable
34
- // Inside the cell, so picking an option is not a click-away — the same
34
+ // Inside the cell, so picking an option is not a click-away - the same
35
35
  // reason the filter panel keeps its dropdowns unportalled.
36
36
  comboboxProps={{ withinPortal: false }}
37
37
  aria-label={labels.editCell(getColumnLabel(column))}
@@ -2,7 +2,7 @@ import { useStore } from "@tanstack/react-form";
2
2
  import type { TMDataGridEditField } from "../../core/editEngine";
3
3
 
4
4
  /**
5
- * The first error as text, whatever shape the validator produced — TanStack
5
+ * The first error as text, whatever shape the validator produced - TanStack
6
6
  * Form keeps errors verbatim, so a Zod issue arrives as `{ message }`, a
7
7
  * plain function's return arrives as it was, and a form-level schema's
8
8
  * pathless issues arrive keyed under an empty path (`{ "": [issues] }`).
@@ -29,7 +29,7 @@ export function firstErrorText(error: unknown): string | undefined {
29
29
  return undefined;
30
30
  }
31
31
 
32
- /** The field's live value — one subscription, on the field's own store. */
32
+ /** The field's live value - one subscription, on the field's own store. */
33
33
  export function useFieldValue(field: TMDataGridEditField): unknown {
34
34
  return useStore(field.store, (state) => state.value as unknown);
35
35
  }
@@ -41,7 +41,7 @@ export function useFieldError(field: TMDataGridEditField): string | undefined {
41
41
  );
42
42
  }
43
43
 
44
- /** Select-all on focus — F2/Enter open with the value ready to replace. */
44
+ /** Select-all on focus - F2/Enter open with the value ready to replace. */
45
45
  export function selectAllOnFocus(event: { currentTarget: unknown }): void {
46
46
  const target = event.currentTarget;
47
47
  if (target instanceof HTMLInputElement) target.select();
@@ -5,7 +5,7 @@ import { TMDataGridFilterValueInput } from "./TMDataGridFilterValueInput";
5
5
 
6
6
  /**
7
7
  * A built-in `meta.filterControl` for `date` columns: a From/To pair of
8
- * native date inputs writing the `between` pair — no `@mantine/dates`
8
+ * native date inputs writing the `between` pair - no `@mantine/dates`
9
9
  * involved, like the built-in date editor. Pair it with
10
10
  * `meta.defaultFilterOperator: "between"`; any non-range operator falls back
11
11
  * to the standard input.
@@ -16,7 +16,7 @@ export function DgRangeSliderFilter(args: TMDataGridFilterControlArgs) {
16
16
  return <TMDataGridFilterValueInput {...args} />;
17
17
  }
18
18
 
19
- // Bounds from the faceted index — the min and max actually in the data.
19
+ // Bounds from the faceted index - the min and max actually in the data.
20
20
  const numbers: number[] = [];
21
21
  for (const key of column.getFacetedUniqueValues().keys()) {
22
22
  const numeric = Number(key);
@@ -9,7 +9,7 @@ import { TMDataGridFilterValueInput } from "./TMDataGridFilterValueInput";
9
9
 
10
10
  /**
11
11
  * A built-in `meta.filterControl` for `boolean` columns: an All / Yes / No
12
- * segmented control — All clears the value, which deactivates the filter.
12
+ * segmented control - All clears the value, which deactivates the filter.
13
13
  * Set or range operators fall back to the standard input.
14
14
  */
15
15
  export function DgTriStateFilter(args: TMDataGridFilterControlArgs) {
@@ -9,7 +9,7 @@ import {
9
9
  } from "../../core/filterOperators";
10
10
 
11
11
  /**
12
- * The built-in value control of a filter-panel row — what renders when a
12
+ * The built-in value control of a filter-panel row - what renders when a
13
13
  * column declares no `meta.filterControl`. Shaped by the operator: a
14
14
  * multi-select for the set operators, a From/To pair for `between`, a Yes/No
15
15
  * dropdown for booleans, a typed input otherwise.
@@ -37,7 +37,7 @@ export function TMDataGridFilterValueInput({
37
37
  ? [String(value[0] ?? ""), String(value[1] ?? "")]
38
38
  : ["", ""];
39
39
  return (
40
- // The interval's two ends. Either may stay empty — an open end — and
40
+ // The interval's two ends. Either may stay empty (an open end), and
41
41
  // each writes its slot of the `[min, max]` pair.
42
42
  <Group gap={4} wrap="nowrap" align="flex-start">
43
43
  <TextInput
@@ -1,9 +1,9 @@
1
1
  /* Boundary of a pinned column group. Shared, because the edge is cast by both
2
- the header cell and every body cell in the same column — the two have to draw
2
+ the header cell and every body cell in the same column - the two have to draw
3
3
  an identical band or the seam shows at the header.
4
4
 
5
5
  A box-shadow is drawn per cell, and its blur fades in at each cell's own top
6
- and bottom edge — stacked down a column that reads as banding at every row
6
+ and bottom edge - stacked down a column that reads as banding at every row
7
7
  seam. Instead: a gradient pseudo element pinned to `top: 0; bottom: 0` so
8
8
  consecutive cells butt together into one unbroken band. Mantine sets
9
9
  `color-scheme` on the root, so light-dark() resolves without a second
@@ -11,7 +11,7 @@
11
11
 
12
12
  No border. A 1px line the colour of the grid's own borders drew a hard rule
13
13
  between the pinned lanes and the data, so the pinned columns read as a
14
- separate table rather than as part of this one — and at the system lanes,
14
+ separate table rather than as part of this one - and at the system lanes,
15
15
  which are only a control wide, it framed them like a sidebar. */
16
16
  .stickyLeft::after,
17
17
  .stickyRight::after {
@@ -24,7 +24,7 @@
24
24
  }
25
25
 
26
26
  /* Three stops rather than two. A straight linear ramp to `transparent` fades
27
- fastest at the start, so its own outer edge stays visible as a faint line —
27
+ fastest at the start, so its own outer edge stays visible as a faint line -
28
28
  the sharpness a hard border was blamed for. Front-loading the falloff puts
29
29
  the density against the pinned cell and lets the tail reach zero unnoticed. */
30
30
  .stickyLeft::after {
@@ -53,12 +53,12 @@
53
53
 
54
54
  Driven by the scroll position itself rather than by a listener writing a
55
55
  class. A scroll-driven animation is evaluated on the compositor, so the band
56
- tracks the scroll frame for frame without a single React render — and the
56
+ tracks the scroll frame for frame without a single React render - and the
57
57
  body re-renders on every scroll frame already, from virtualization.
58
58
 
59
59
  `scroll(nearest inline)` resolves to `.scrollContainer`, the one horizontal
60
- scroller above these cells. An inactive timeline — which is what a container
61
- with nothing to scroll gives — leaves the base style in place, so `opacity:
60
+ scroller above these cells. An inactive timeline - which is what a container
61
+ with nothing to scroll gives - leaves the base style in place, so `opacity:
62
62
  0` inside this block is also the answer for a grid that does not scroll. */
63
63
  @supports (animation-timeline: scroll()) {
64
64
  .stickyLeft::after,
@@ -79,7 +79,7 @@
79
79
 
80
80
  /* The mirror: on at rest, gone as the last column arrives. The range is
81
81
  measured from the end, and `both` holds the first value everywhere before
82
- it — so the band stays fully on until the scroller is within 20px of home.
82
+ it - so the band stays fully on until the scroller is within 20px of home.
83
83
  */
84
84
  .stickyRight::after {
85
85
  animation-name: stickyEdgeOut;
@@ -18,7 +18,7 @@ const CONTENT_ALLOWANCE = 2;
18
18
  * A Range over the children rather than the span's `scrollWidth`, because the
19
19
  * two disagree in opposite directions: a left-aligned cell stretches its
20
20
  * content span to fill the cell (`flex: 1 1 auto`), so `scrollWidth` reports
21
- * the stretched box and autosize could never *shrink* a column — while for
21
+ * the stretched box and autosize could never *shrink* a column - while for
22
22
  * clipped content both see past the `overflow: hidden`. The Range measures
23
23
  * the laid-out text and elements themselves, whatever box they sit in.
24
24
  *
@@ -41,14 +41,14 @@ function contentSpanWidth(content: HTMLElement): number {
41
41
  * Widest rendered content of one column, in px, measured from the DOM.
42
42
  *
43
43
  * Mounted cells only: under virtualization the unmounted rows do not exist to
44
- * be measured, so this reads the visible window plus overscan — the same
44
+ * be measured, so this reads the visible window plus overscan - the same
45
45
  * trade AG Grid's autosize makes by default.
46
46
  */
47
47
  export function measureColumnContentWidth({
48
48
  container,
49
49
  columnId,
50
50
  }: {
51
- /** The grid's scroll container — anything enclosing the column's cells. */
51
+ /** The grid's scroll container - anything enclosing the column's cells. */
52
52
  container: HTMLElement;
53
53
  columnId: string;
54
54
  }): number {
@@ -91,7 +91,7 @@ export function measureColumnContentWidth({
91
91
  }
92
92
 
93
93
  /**
94
- * Sizes a column to its widest mounted content — what double-clicking the
94
+ * Sizes a column to its widest mounted content - what double-clicking the
95
95
  * resize divider does, exported so a menu item or consumer code can trigger
96
96
  * the same thing.
97
97
  *
@@ -21,10 +21,10 @@ import type {
21
21
  * what applies the per-column overrides.
22
22
  */
23
23
  /**
24
- * How rows are selected — see `selectionMode` on {@link UseTMDataGridOptions}.
24
+ * How rows are selected - see `selectionMode` on {@link UseTMDataGridOptions}.
25
25
  *
26
- * One axis, because the two things a config could set independently — which
27
- * chrome selects, and what a bare row click does — cannot both be free: a click
26
+ * One axis, because the two things a config could set independently - which
27
+ * chrome selects, and what a bare row click does - cannot both be free: a click
28
28
  * can either toggle a multi-selection or move the highlight, never both. Folding
29
29
  * them into one value makes that conflict unrepresentable rather than something
30
30
  * to warn about.
@@ -36,11 +36,11 @@ export type TMDataGridSelectionMode =
36
36
  | "row"
37
37
  /** Checkbox column multi-selects, and a row click highlights one row. */
38
38
  | "checkboxAndHighlight"
39
- /** No selection at all — a row click only highlights. Master-detail. */
39
+ /** No selection at all - a row click only highlights. Master-detail. */
40
40
  | "highlight";
41
41
 
42
42
  /**
43
- * How cells are selected — see `cellSelection` on {@link UseTMDataGridOptions}.
43
+ * How cells are selected - see `cellSelection` on {@link UseTMDataGridOptions}.
44
44
  *
45
45
  * A mode rather than a pair of booleans, for the reason
46
46
  * {@link TMDataGridSelectionMode} is one: "cells can be selected" and "more
@@ -58,7 +58,7 @@ export type TMDataGridCellSelectionMode =
58
58
  export type TMDataGridFeatureFlags = {
59
59
  sorting: boolean;
60
60
  filtering: boolean;
61
- /** Whether the quick search may filter — `enableGlobalFilter`. */
61
+ /** Whether the quick search may filter - `enableGlobalFilter`. */
62
62
  globalFiltering: boolean;
63
63
  hiding: boolean;
64
64
  pinning: boolean;
@@ -73,7 +73,7 @@ export type TMDataGridFeatureFlags = {
73
73
  /** Whether a bare row click toggles the selection. Only under `"row"`. */
74
74
  rowClickSelects: boolean;
75
75
  /**
76
- * Whether more than one row can be selected at once — TanStack's
76
+ * Whether more than one row can be selected at once - TanStack's
77
77
  * `enableMultiRowSelection`. Off, the grid drops the select-all header
78
78
  * checkbox: TanStack's `toggleAllRowsSelected` only consults `getCanSelect`,
79
79
  * so that control would select every row and walk straight past the limit.
@@ -84,14 +84,14 @@ export type TMDataGridFeatureFlags = {
84
84
  /** Whether a selected row takes the highlight colour. Follows the mode. */
85
85
  showSelectedBackground: boolean;
86
86
  /**
87
- * The single highlighted row — clicking a row highlights it, for a detail
87
+ * The single highlighted row - clicking a row highlights it, for a detail
88
88
  * panel to follow. State of its own, not a slice of `rowSelection`, which is
89
89
  * what lets it coexist with a checkbox multi-selection.
90
90
  */
91
91
  highlightRow: boolean;
92
92
  /**
93
93
  * Whether cells can be selected at all. Off unless `cellSelection` asks for
94
- * it — it takes the body's tab stop off the row and puts it on a cell, and
94
+ * it - it takes the body's tab stop off the row and puts it on a cell, and
95
95
  * reports the grid to assistive technology as a `grid` rather than a `table`,
96
96
  * which is a different promise about what the keyboard does.
97
97
  */
@@ -109,7 +109,7 @@ export type TMDataGridFeatureFlags = {
109
109
  /**
110
110
  * Row grouping: the "Group by" items in the header menu and the generated
111
111
  * tree column. On unless `enableGrouping: false`, since an ungrouped grid
112
- * looks and behaves exactly as it did before — `grouping` starts empty, and
112
+ * looks and behaves exactly as it did before - `grouping` starts empty, and
113
113
  * an empty grouping state passes straight through the row model.
114
114
  *
115
115
  * The exception is `manualPagination`, where the client holds one page rather
@@ -118,14 +118,14 @@ export type TMDataGridFeatureFlags = {
118
118
  * its own grouping can still say `enableGrouping: true` to override.
119
119
  */
120
120
  grouping: boolean;
121
- /** Whether cells can be edited at all — `editMode` was set. */
121
+ /** Whether cells can be edited at all - `editMode` was set. */
122
122
  editing: boolean;
123
123
  /** The commit policy, or `null` while editing is off. */
124
124
  editMode: TMDataGridEditMode | null;
125
- /** The generated row-number gutter — `enableRowNumbers`. Off by default. */
125
+ /** The generated row-number gutter - `enableRowNumbers`. Off by default. */
126
126
  rowNumbers: boolean;
127
127
  /**
128
- * Whether rows can be pinned to the top or bottom edge — `enableRowPinning`,
128
+ * Whether rows can be pinned to the top or bottom edge - `enableRowPinning`,
129
129
  * boolean or per-row predicate. Off by default: pinning has no built-in
130
130
  * gesture, so a grid that never calls `row.pin()` has nothing to gain from
131
131
  * the body watching the state.
@@ -133,7 +133,7 @@ export type TMDataGridFeatureFlags = {
133
133
  rowPinning: boolean;
134
134
  /**
135
135
  * Whether cells highlight the matched text while a contains-family filter
136
- * or the quick search is active — `enableMatchHighlighting`. Off by
136
+ * or the quick search is active - `enableMatchHighlighting`. Off by
137
137
  * default, so a grid that has not asked pays nothing per cell.
138
138
  */
139
139
  matchHighlighting: boolean;
@@ -205,7 +205,7 @@ export function readFeatureFlags<TData extends RowData>(
205
205
  editing: options.editMode !== undefined,
206
206
  editMode: options.editMode ?? null,
207
207
  rowNumbers: options.enableRowNumbers === true,
208
- // A predicate counts as on — some rows may still pin.
208
+ // A predicate counts as on - some rows may still pin.
209
209
  rowPinning:
210
210
  options.enableRowPinning === true ||
211
211
  typeof options.enableRowPinning === "function",
@@ -246,7 +246,7 @@ export function getColumnCapabilities(
246
246
  canHide: features.hiding && column.getCanHide(),
247
247
  canPin: features.pinning && column.getCanPin(),
248
248
  canResize: features.resizing && column.getCanResize(),
249
- // Ordering has no TanStack capability method — see isColumnReorderable.
249
+ // Ordering has no TanStack capability method - see isColumnReorderable.
250
250
  canReorder: features.ordering && isColumnReorderable(column),
251
251
  // `getCanGroup()` also insists on an accessor, which is what keeps the
252
252
  // generated checkbox and tree columns from offering to group on themselves.
@@ -254,7 +254,7 @@ export function getColumnCapabilities(
254
254
  };
255
255
  }
256
256
 
257
- /** The same questions, asked of the whole grid — used to hide toolbar buttons. */
257
+ /** The same questions, asked of the whole grid - used to hide toolbar buttons. */
258
258
  export type TMDataGridCapabilities = {
259
259
  canSortAny: boolean;
260
260
  canFilterAny: boolean;
@@ -71,7 +71,7 @@ export function formatExportValue(
71
71
  .map((entry) => formatExportValue(entry, { decimalComma }))
72
72
  .join(", ");
73
73
  }
74
- // `sv-SE` is ISO-shaped — 2026-07-31, 2026-07-31 14:05:00 — which is both the
74
+ // `sv-SE` is ISO-shaped (2026-07-31, 2026-07-31 14:05:00), which is both the
75
75
  // Nordic form and the one Excel parses as a date rather than as text.
76
76
  if (value instanceof Date) {
77
77
  return Number.isNaN(value.getTime()) ? "" : value.toLocaleString("sv-SE");
@@ -90,7 +90,7 @@ export function formatExportValue(
90
90
 
91
91
  export type BuildCellMatrixArgs = {
92
92
  rows: ReadonlyArray<Row<TMDataGridFeatures, TMDataGridRowData>>;
93
- /** Every visible column, in render order — the same list the bounds index into. */
93
+ /** Every visible column, in render order - the same list the bounds index into. */
94
94
  columns: ReadonlyArray<Column<TMDataGridFeatures, TMDataGridRowData, unknown>>;
95
95
  bounds: TMDataGridRangeBounds;
96
96
  includeHeaders: boolean;
@@ -100,7 +100,7 @@ export type BuildCellMatrixArgs = {
100
100
  /**
101
101
  * The selected rectangle as rows of text.
102
102
  *
103
- * The generated lanes — the checkbox, the tree chevron, the details chevron —
103
+ * The generated lanes - the checkbox, the tree chevron, the details chevron -
104
104
  * are dropped even when the rectangle covers them. They hold controls rather
105
105
  * than data, so a column of empty strings is all they could contribute, and
106
106
  * pasting one into a spreadsheet only shifts everything to its right.
@@ -135,13 +135,13 @@ export function buildCellMatrix({
135
135
  }
136
136
 
137
137
  /**
138
- * The whole grid as rows of text: every filtered and sorted data row — all
139
- * pages, not the one on screen — by every visible non-control column, in
138
+ * The whole grid as rows of text: every filtered and sorted data row - all
139
+ * pages, not the one on screen - by every visible non-control column, in
140
140
  * render order.
141
141
  *
142
142
  * The values are the same ones a cell-range export writes; only the bounds
143
143
  * differ. Group rows are left out (their records are the rows themselves),
144
- * and hidden columns are not exported — what you see is what you get, minus
144
+ * and hidden columns are not exported - what you see is what you get, minus
145
145
  * paging.
146
146
  */
147
147
  export function buildGridCellMatrix<TData extends RowData>({
@@ -162,7 +162,7 @@ export function buildGridCellMatrix<TData extends RowData>({
162
162
  ...erased.getRightVisibleLeafColumns(),
163
163
  ];
164
164
  // The sorted model: after filtering, grouping and sorting, before expansion
165
- // and paging — so a paged grid exports the whole filtered set, and a grouped
165
+ // and paging - so a paged grid exports the whole filtered set, and a grouped
166
166
  // grid exports the records under every group whether or not it is open.
167
167
  //
168
168
  // Walked by hand rather than taken from `flatRows`: in table-core
@@ -195,7 +195,7 @@ export function buildGridCellMatrix<TData extends RowData>({
195
195
  }
196
196
 
197
197
  /**
198
- * Downloads the whole grid as a CSV for Excel — {@link buildGridCellMatrix}
198
+ * Downloads the whole grid as a CSV for Excel - {@link buildGridCellMatrix}
199
199
  * through {@link toExcelCsv}, with the same Nordic defaults and overrides as
200
200
  * the cell-range export.
201
201
  *
@@ -243,7 +243,7 @@ function escapeField(value: string, separator: string): string {
243
243
  * The clipboard format spreadsheets read: tab between cells, CRLF between rows.
244
244
  *
245
245
  * Tabs rather than commas because that is what Excel, Sheets and Numbers all
246
- * put on the clipboard themselves — paste it and the cells land in cells. A
246
+ * put on the clipboard themselves - paste it and the cells land in cells. A
247
247
  * comma-separated string pastes into a single column, which is the thing this
248
248
  * exists to avoid.
249
249
  */
@@ -260,12 +260,12 @@ export function toClipboardText(matrix: TMDataGridCellMatrix): string {
260
260
  *
261
261
  * | Part | Why |
262
262
  * | ---- | --- |
263
- * | `sep=;` first line | Excel's own directive — it stops guessing and uses this |
263
+ * | `sep=;` first line | Excel's own directive - it stops guessing and uses this |
264
264
  * | UTF-8 BOM | without it Excel reads the file as ANSI, and å ä ö arrive broken |
265
265
  * | CRLF line endings | what Excel writes, and what its importer is happiest with |
266
266
  *
267
267
  * The `sep=` line is Excel's alone; other readers show it as a first row. That
268
- * is the trade this makes — the file is for Excel, and "it just opens" is worth
268
+ * is the trade this makes - the file is for Excel, and "it just opens" is worth
269
269
  * more than being a well-behaved CSV nobody was going to feed to a parser.
270
270
  */
271
271
  export function toExcelCsv(
@@ -282,7 +282,7 @@ export function toExcelCsv(
282
282
  * Puts text on the clipboard, reporting whether it landed.
283
283
  *
284
284
  * The async clipboard API only resolves for a document that has the focus and a
285
- * user gesture behind it — both true when this runs off Ctrl+C or a menu item.
285
+ * user gesture behind it - both true when this runs off Ctrl+C or a menu item.
286
286
  * It is still allowed to reject (a permissions policy, a page that lost focus
287
287
  * mid-copy), so the result is a boolean rather than a promise nobody checks.
288
288
  */
@@ -297,7 +297,7 @@ export async function writeClipboardText(text: string): Promise<boolean> {
297
297
 
298
298
  /**
299
299
  * Downloads text as a file, through the one mechanism a library can use: an
300
- * anchor with an object URL behind it, clicked. Revoked on the next frame —
300
+ * anchor with an object URL behind it, clicked. Revoked on the next frame -
301
301
  * immediately would race the browser's own read of it.
302
302
  */
303
303
  export function downloadTextFile({
@@ -4,7 +4,7 @@
4
4
  * Ids, because every other thing the grid does moves cells around: sorting
5
5
  * reorders rows, filtering removes them, dragging a header reorders columns. A
6
6
  * coordinate pair would silently come to mean a different cell after any of
7
- * them, while a pair of ids either still resolves or does not resolve at all —
7
+ * them, while a pair of ids either still resolves or does not resolve at all -
8
8
  * and "does not resolve" is a state the grid can handle honestly.
9
9
  *
10
10
  * Indices are what navigation is actually computed in, so they are resolved
@@ -24,7 +24,7 @@ export type TMDataGridCellCoords = {
24
24
  export type ResolveCellMoveArgs = {
25
25
  /** `KeyboardEvent.key`. */
26
26
  key: string;
27
- /** Ctrl or Cmd — Home and End jump to the corner rather than the row end. */
27
+ /** Ctrl or Cmd - Home and End jump to the corner rather than the row end. */
28
28
  ctrlKey: boolean;
29
29
  from: TMDataGridCellCoords;
30
30
  rowCount: number;
@@ -45,7 +45,7 @@ const clamp = (value: number, max: number) =>
45
45
  * Moves clamp at the edges instead of wrapping. Wrapping suits a menu, where
46
46
  * the items are a short ring; a grid is a coordinate space, and a Right at the
47
47
  * last column that lands on the first column of the next row loses the one
48
- * thing arrow keys are for — knowing where you will end up without looking.
48
+ * thing arrow keys are for - knowing where you will end up without looking.
49
49
  *
50
50
  * A clamped move returns the position it started from rather than `null`. The
51
51
  * caller still needs to know the key was handled: an arrow at the last row must
@@ -82,7 +82,7 @@ export function resolveCellMove({
82
82
  return at(from.rowIndex + Math.max(pageRows, 1), from.columnIndex);
83
83
  case "PageUp":
84
84
  return at(from.rowIndex - Math.max(pageRows, 1), from.columnIndex);
85
- // Ctrl+Home / Ctrl+End address the grid, plain Home / End the row — the
85
+ // Ctrl+Home / Ctrl+End address the grid, plain Home / End the row - the
86
86
  // convention every spreadsheet and APG's own grid pattern share.
87
87
  case "Home":
88
88
  return ctrlKey ? at(0, 0) : at(from.rowIndex, 0);
@@ -104,13 +104,13 @@ export type NextEditableCellArgs = {
104
104
  };
105
105
 
106
106
  /**
107
- * The next editable cell in reading order, wrapping to the next row — and
107
+ * The next editable cell in reading order, wrapping to the next row - and
108
108
  * from the last cell of the grid back to the first. `null` when no other
109
109
  * cell is editable.
110
110
  *
111
111
  * Deliberately wrapping where {@link resolveCellMove} deliberately clamps:
112
112
  * arrows are a coordinate space and clamp so the destination is predictable,
113
- * but Tab mid-edit is the spreadsheet's "next field" — at the end of a row
113
+ * but Tab mid-edit is the spreadsheet's "next field" - at the end of a row
114
114
  * the next field is on the next row, which is a convention, not a surprise.
115
115
  */
116
116
  export function getNextEditableCell({
@@ -4,13 +4,13 @@ import type { TMDataGridCellPosition } from "./cellNavigation";
4
4
  * A selected rectangle of cells, held as the two cells that span it.
5
5
  *
6
6
  * Two corners rather than a list of cells, because a range is a gesture, not a
7
- * set: dragging over 40 columns of a 100k-row grid would otherwise build — and
8
- * rebuild, on every mouse move — a list with millions of entries in it. Two
7
+ * set: dragging over 40 columns of a 100k-row grid would otherwise build - and
8
+ * rebuild, on every mouse move - a list with millions of entries in it. Two
9
9
  * positions describe the same thing and cost nothing to extend.
10
10
  *
11
11
  * `anchor` is where the gesture started and stays put; `focus` is the end that
12
12
  * moves. Which of the two is top-left depends on the direction it was dragged,
13
- * so nothing here assumes an order — see {@link resolveRangeBounds}.
13
+ * so nothing here assumes an order - see {@link resolveRangeBounds}.
14
14
  */
15
15
  export type TMDataGridCellRange = {
16
16
  anchor: TMDataGridCellPosition;
@@ -37,7 +37,7 @@ export type ResolveRangeBoundsArgs = {
37
37
  * corner no longer exists.
38
38
  *
39
39
  * A corner goes missing whenever a filter drops its row or a column is hidden,
40
- * and the honest answer then is that there is no rectangle — better than
40
+ * and the honest answer then is that there is no rectangle - better than
41
41
  * guessing at a replacement corner and quietly copying cells the user never
42
42
  * selected. The range itself is left alone: clearing it here would throw away
43
43
  * a selection that comes straight back when the filter is lifted.
@@ -31,14 +31,14 @@ export type TMDataGridOptionsArgs = {
31
31
  };
32
32
 
33
33
  /**
34
- * Where a column's options come from — `meta.options`. One declaration feeds
34
+ * Where a column's options come from - `meta.options`. One declaration feeds
35
35
  * both the filter panel's value control and the cell editor.
36
36
  *
37
37
  * | Form | For |
38
38
  * | --- | --- |
39
39
  * | array | a known, fixed set |
40
40
  * | `"faceted"` | low-cardinality data columns: the distinct values present, via `getFacetedUniqueValues` |
41
- * | function | large or contextual sets — `row` is set when an editor asks, so options can depend on the record (city given country) |
41
+ * | function | large or contextual sets - `row` is set when an editor asks, so options can depend on the record (city given country) |
42
42
  */
43
43
  export type TMDataGridOptionsSource =
44
44
  | ReadonlyArray<TMDataGridOption | string>
@@ -12,7 +12,7 @@ type GridTable = TMDataGridTable<TMDataGridRowData>;
12
12
  * Pinning splits the grid into three, and TanStack sequences them from two
13
13
  * different state slices: `columnPinning.left` / `.right` order the pinned
14
14
  * lanes, `columnOrder` orders the centre. A move therefore always stays inside
15
- * one lane — moving a column into another one would be a pin, not a reorder.
15
+ * one lane - moving a column into another one would be a pin, not a reorder.
16
16
  */
17
17
  export type TMDataGridColumnRegion = "left" | "center" | "right";
18
18
 
@@ -104,7 +104,7 @@ export type ColumnStepArgs = {
104
104
  * The column a single step would swap with, or `null` when there is none.
105
105
  *
106
106
  * A neighbour that cannot be reordered acts as a wall rather than being skipped
107
- * — that is what keeps the checkbox column anchored at the start of the left
107
+ * - that is what keeps the checkbox column anchored at the start of the left
108
108
  * lane. Use it to enable or disable a "move" control.
109
109
  */
110
110
  export function getStepTargetColumn({
@@ -34,7 +34,7 @@ export function getColumnType(column: ColumnLike): TMDataGridColumnType {
34
34
  }
35
35
 
36
36
  /**
37
- * The operator a fresh filter on this column starts with —
37
+ * The operator a fresh filter on this column starts with -
38
38
  * `meta.defaultFilterOperator`, else the type's default.
39
39
  */
40
40
  export function getColumnDefaultOperator(
@@ -51,13 +51,13 @@ export function getColumnAlign(column: ColumnLike): "left" | "right" | "center"
51
51
  }
52
52
 
53
53
  /**
54
- * A generated lane holding one fixed-width thing — the checkbox, the details
54
+ * A generated lane holding one fixed-width thing - the checkbox, the details
55
55
  * chevron, the row number.
56
56
  *
57
57
  * They are laid out differently from every other column: cell padding is sized
58
58
  * for text and grows with the scale, which at `xl` squeezed a 16px checkbox out
59
59
  * of its track, so these lanes centre their content in an unpadded cell.
60
- * Their headers carry no column menu, and none of them is ever exported —
60
+ * Their headers carry no column menu, and none of them is ever exported -
61
61
  * they hold chrome, not values.
62
62
  *
63
63
  * The tree column is deliberately not one of them: it holds a label as well as a