@jielga/tmdatagrid 2.1.0 → 2.1.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.
@@ -45,7 +45,7 @@ export const TMDATAGRID_LABELS_SV: TMDataGridLabels = {
45
45
  columnsShowHideAll: "Visa/dölj alla",
46
46
  columnsReset: "Återställ layout",
47
47
  columnsResetHint:
48
- "Återställer kolumnernas synlighet, ordning, bredder, fästning och gruppering",
48
+ "Återställer kolumnernas synlighet, ordning, bredd, låsning och gruppering",
49
49
  rowNumberColumnLabel: "Radnummer",
50
50
  noRows: "Inga rader att visa",
51
51
 
@@ -70,16 +70,16 @@ export const TMDATAGRID_LABELS_SV: TMDataGridLabels = {
70
70
  sortAsc: "Sortera stigande",
71
71
  sortDesc: "Sortera fallande",
72
72
  filterMenuItem: "Filtrera",
73
- groupBy: (column) => `Gruppera på ${column}`,
74
- ungroup: (column) => `Avgruppera ${column}`,
73
+ groupBy: (column) => `Gruppera efter ${column}`,
74
+ ungroup: (column) => `Sluta gruppera efter ${column}`,
75
75
  expandAllGroups: "Expandera alla grupper",
76
76
  collapseAllGroups: "Fäll ihop alla grupper",
77
- pinLeft: "Fäst till vänster",
78
- pinRight: "Fäst till höger",
79
- unpin: "Lossa",
77
+ pinLeft: "Lås till vänster",
78
+ pinRight: "Lås till höger",
79
+ unpin: "Lås upp",
80
80
  moveLeft: "Flytta åt vänster",
81
81
  moveRight: "Flytta åt höger",
82
- autosizeColumn: "Anpassa kolumnbredd",
82
+ autosizeColumn: "Autopassa kolumnbredd",
83
83
  hideColumn: "Dölj kolumn",
84
84
  filterOn: (column) => `Filtrera på ${column}`,
85
85
  sortColumn: (column) => `Sortera ${column}`,
@@ -91,7 +91,7 @@ export const TMDATAGRID_LABELS_SV: TMDataGridLabels = {
91
91
  pageCount < 0 ? `Sida ${page}` : `Sida ${page} av ${pageCount}`,
92
92
  groupedAllRows: (total) => `Grupperad · alla ${total} rader`,
93
93
  pagingSuspendedHint:
94
- "Sidindelningen är avstängd medan raderna är grupperade: hela trädet renderas och virtualiseras. Avgruppera för att bläddra igen.",
94
+ "Sidindelningen är avstängd medan raderna är grupperade, och alla rader visas. Sluta gruppera för att bläddra igen.",
95
95
  previousPage: "Föregående sida",
96
96
  nextPage: "Nästa sida",
97
97
 
@@ -107,11 +107,11 @@ export const TMDATAGRID_LABELS_SV: TMDataGridLabels = {
107
107
  cancelRowEdit: "Avbryt redigering",
108
108
  editRowErrors: "Åtgärda de markerade cellerna",
109
109
  saveAllEdits: (rows) => (rows === 1 ? "Spara 1 rad" : `Spara ${rows} rader`),
110
- discardAllEdits: "Förkasta",
110
+ discardAllEdits: "Ångra alla",
111
111
  editRowsStillOpen: (rows) =>
112
112
  rows === 1 ? "1 rad redigeras fortfarande" : `${rows} rader redigeras fortfarande`,
113
113
  confirmNewRow: "Lägg till rad",
114
- discardNewRow: "Släng ny rad",
114
+ discardNewRow: "Avbryt ny rad",
115
115
  deleteRow: "Ta bort rad",
116
116
  restoreRow: "Återställ rad",
117
117
  revertRow: "Ångra ändringar",
@@ -122,37 +122,37 @@ export const TMDATAGRID_LABELS_SV: TMDataGridLabels = {
122
122
  cellCount: (count) => (count === 1 ? "1 cell" : `${count} celler`),
123
123
  copy: "Kopiera",
124
124
  exportCells: "Exportera celler",
125
- includeHeaders: "Inkludera rubriker",
125
+ includeHeaders: "Ta med rubriker",
126
126
 
127
127
  exportAll: "Exportera alla rader",
128
128
  exportSelected: (count) =>
129
- count === 1 ? "Exportera 1 vald rad" : `Exportera ${count} valda rader`,
129
+ count === 1 ? "Exportera 1 markerad rad" : `Exportera ${count} markerade rader`,
130
130
  exportPickerTitle: (format) => `Exportera som ${format}`,
131
131
  exportPickerHint: (selected) =>
132
132
  selected === null
133
133
  ? "Välj kolumner att exportera"
134
134
  : selected === 1
135
- ? "Välj kolumner att exportera för den valda raden"
136
- : `Välj kolumner att exportera för de ${selected} valda raderna`,
135
+ ? "Välj kolumner att exportera för den markerade raden"
136
+ : `Välj kolumner att exportera för de ${selected} markerade raderna`,
137
137
  exportPickerConfirm: "Exportera",
138
138
  exportPickerCancel: "Avbryt",
139
- exportPickerSelectAll: "Välj alla",
139
+ exportPickerSelectAll: "Markera alla",
140
140
  exportPickerCount: (checked, total) => `${checked} av ${total}`,
141
141
  exportPickerHidden: "Dold",
142
142
 
143
- selectColumnLabel: "Kryssrutemarkering",
144
- selectAllRows: "Välj alla rader",
145
- selectRow: "Välj rad",
146
- selectGroup: "Välj grupp",
143
+ selectColumnLabel: "Radmarkering",
144
+ selectAllRows: "Markera alla rader",
145
+ selectRow: "Markera rad",
146
+ selectGroup: "Markera grupp",
147
147
 
148
148
  detailsColumnLabel: "Detaljer",
149
149
  showDetails: "Visa detaljer",
150
150
  hideDetails: "Dölj detaljer",
151
- expandAllDetails: "Expandera alla detaljer",
152
- collapseAllDetails: "Fäll ihop alla detaljer",
151
+ expandAllDetails: "Visa alla detaljer",
152
+ collapseAllDetails: "Dölj alla detaljer",
153
153
 
154
154
  groupColumnLabel: "Grupp",
155
- blankGroupValue: "(Tom)",
155
+ blankGroupValue: "(Tomt)",
156
156
  expandGroup: (label) => `Expandera ${label}`,
157
157
  collapseGroup: (label) => `Fäll ihop ${label}`,
158
158
  };
@@ -5,6 +5,7 @@ import {
5
5
  } from "@tanstack/match-sorter-utils";
6
6
  import {
7
7
  createSortedRowModel,
8
+ type Column,
8
9
  type Row,
9
10
  type RowData,
10
11
  type RowModel,
@@ -22,6 +23,57 @@ export type TMDataGridQuickSearchMode = "fuzzy" | "contains";
22
23
  */
23
24
  export const FUZZY_FILTER_FN_NAME = "tmDataGridFuzzy";
24
25
 
26
+ /**
27
+ * Which columns the quick search reads, per core row model: the answer only
28
+ * changes with the data, and the model's identity changes with the data.
29
+ */
30
+ const searchableColumns = new WeakMap<object, Map<string, boolean>>();
31
+
32
+ /**
33
+ * The grid's `getColumnCanGlobalFilter`: TanStack's own rule - a column takes
34
+ * part when its first non-empty value is a string or a number, or when it
35
+ * says `enableGlobalFilter: true` - computed once per data change.
36
+ *
37
+ * TanStack's default scans the rows for that first value on every call,
38
+ * building every cell of every row it passes, and the grid asks on every
39
+ * header render. A column empty in every row therefore cost a full scan per
40
+ * header per render. Here the scan reads values only, and its answer is kept
41
+ * until the data changes.
42
+ */
43
+ export function columnCanQuickSearch<
44
+ TFeatures extends TableFeatures,
45
+ TData extends RowData,
46
+ TValue,
47
+ >(column: Column<TFeatures, TData, TValue>): boolean {
48
+ const { enableGlobalFilter } = column.columnDef as {
49
+ enableGlobalFilter?: boolean;
50
+ };
51
+ if (enableGlobalFilter === true) return true;
52
+ // A display column has no value to search.
53
+ if (!column.accessorFn) return false;
54
+ // Off the table as a plain record, for the same generic-features reason as
55
+ // the options read in isRankingActive.
56
+ const model = (
57
+ column.table as unknown as { getCoreRowModel: () => RowModel<TFeatures, TData> }
58
+ ).getCoreRowModel();
59
+ let byColumn = searchableColumns.get(model);
60
+ if (byColumn === undefined) {
61
+ byColumn = new Map();
62
+ searchableColumns.set(model, byColumn);
63
+ }
64
+ const known = byColumn.get(column.id);
65
+ if (known !== undefined) return known;
66
+ let searchable = false;
67
+ for (const row of model.flatRows) {
68
+ const value = row.getValue(column.id);
69
+ if (value == null) continue;
70
+ searchable = typeof value === "string" || typeof value === "number";
71
+ break;
72
+ }
73
+ byColumn.set(column.id, searchable);
74
+ return searchable;
75
+ }
76
+
25
77
  /** What {@link fuzzyGlobalFilterFn} records per column via `addMeta`. */
26
78
  type FuzzyFilterMeta = { fuzzyRank: RankingInfo };
27
79
 
@@ -90,6 +90,7 @@ import {
90
90
  type TMDataGridFiltersSettings,
91
91
  } from "./core/filterSurface";
92
92
  import {
93
+ columnCanQuickSearch,
93
94
  createFuzzyRankedSortedRowModel,
94
95
  fuzzyGlobalFilterFn,
95
96
  type TMDataGridQuickSearchMode,
@@ -1082,19 +1083,6 @@ type TMDataGridColumnDef<TData extends RowData> = ColumnDef<
1082
1083
  unknown
1083
1084
  >;
1084
1085
 
1085
- /**
1086
- * Point every column at the operator-dispatching filter function, and take
1087
- * grouping's aggregation defaults back off, unless the column opted into its
1088
- * own. Anything the consumer set wins - it is spread over these.
1089
- *
1090
- * The aggregation pair needs explaining. TanStack's grouping feature hands
1091
- * every column `aggregationFn: "auto"` and an `aggregatedCell` that stringifies
1092
- * whatever comes out, so merely registering the feature would have every
1093
- * numeric column silently sum itself and every date column show a range the
1094
- * moment anything is grouped. That is a summary table, and "group by" is not a
1095
- * request for one. Cleared here, so a grouped grid is a tree until a column
1096
- * says otherwise - `aggregationFn: "sum"` on the column that wants it.
1097
- */
1098
1086
  /**
1099
1087
  * Drops the control lanes' entries from a visibility map.
1100
1088
  *
@@ -1115,6 +1103,19 @@ function withoutControlColumnVisibility(
1115
1103
  return scrubbed;
1116
1104
  }
1117
1105
 
1106
+ /**
1107
+ * Point every column at the operator-dispatching filter function, and take
1108
+ * the aggregation defaults back off, unless the column opted into its own.
1109
+ * Anything the consumer set wins - it is spread over these.
1110
+ *
1111
+ * The aggregation pair needs explaining. TanStack's row aggregation feature
1112
+ * hands every column `aggregationFn: "auto"` and an `aggregatedCell` that
1113
+ * stringifies whatever comes out, so merely registering the feature would have
1114
+ * every numeric column silently sum itself and every date column show a range
1115
+ * the moment anything is grouped. That is a summary table, and "group by" is
1116
+ * not a request for one. Cleared here, so a grouped grid is a tree until a
1117
+ * column says otherwise - `aggregationFn: "sum"` on the column that wants it.
1118
+ */
1118
1119
  function withTMDataGridDefaults<TData extends RowData>(
1119
1120
  columns: ReadonlyArray<TMDataGridColumnDef<TData>>,
1120
1121
  ): Array<TMDataGridColumnDef<TData>> {
@@ -1238,7 +1239,6 @@ export function useTMDataGrid<TData extends RowData>({
1238
1239
  ],
1239
1240
  );
1240
1241
 
1241
- const pinningEnabled = options.enableColumnPinning !== false;
1242
1242
  const selectColumnEnabled = features.selectColumn;
1243
1243
  const groupColumnEnabled = features.grouping;
1244
1244
  // The lane that opens the panels. Nothing to switch on: a grid with no
@@ -1270,13 +1270,15 @@ export function useTMDataGrid<TData extends RowData>({
1270
1270
  // and re-applied on top of anything restored: a snapshot cannot unpin one,
1271
1271
  // and a snapshot taken before `detailsColumnPosition` changed cannot pin the
1272
1272
  // details lane to the edge it has since left.
1273
+ //
1274
+ // Not gated on `enableColumnPinning`: that switch takes pinning away from the
1275
+ // user, not from the grid's own lanes, which hold the edges either way.
1273
1276
  const structuralPinning = (
1274
1277
  restored: Partial<ColumnPinningState> | undefined,
1275
1278
  ): ColumnPinningState => {
1276
1279
  const own = (ids: string[] | undefined) =>
1277
1280
  (ids ?? []).filter((id) => !isGeneratedColumn(id));
1278
- const lane = (enabled: boolean, id: string) =>
1279
- enabled && pinningEnabled ? [id] : [];
1281
+ const lane = (enabled: boolean, id: string) => (enabled ? [id] : []);
1280
1282
  const detailsOn = (edge: "left" | "right") =>
1281
1283
  detailsColumnEnabled && detailsColumnPosition === edge;
1282
1284
  return {
@@ -1476,6 +1478,11 @@ export function useTMDataGrid<TData extends RowData>({
1476
1478
  edit.store,
1477
1479
  (state) => state.committedValues,
1478
1480
  );
1481
+ // Subscribed for the re-render alone - the selection predicate below reads
1482
+ // the marks live. TanStack 9.2 caches a group row's "all / some selected"
1483
+ // on the predicate's identity, and only a render hands it a new one; without
1484
+ // this a mark would leave the group's checkbox on its old answer.
1485
+ useSelector(edit.store, (state) => state.deletedRowIds);
1479
1486
  const newRowsSticky = features.editNewRowsSticky;
1480
1487
  const editCreatedIds = useSelector(
1481
1488
  edit.store,
@@ -1577,6 +1584,9 @@ export function useTMDataGrid<TData extends RowData>({
1577
1584
  options.quickSearchMode === "contains"
1578
1585
  ? "includesString"
1579
1586
  : "tmDataGridFuzzy",
1587
+ // Which columns the quick search reads - TanStack's rule, computed once
1588
+ // per data change instead of once per call. See columnCanQuickSearch.
1589
+ getColumnCanGlobalFilter: columnCanQuickSearch,
1580
1590
  // Grouping by a column takes it out of the grid, the way AG Grid does it:
1581
1591
  // its values have moved into the tree column, so leaving it in place would
1582
1592
  // show every row the same value it was grouped under. Overridable - pass
@@ -1620,11 +1630,17 @@ export function useTMDataGrid<TData extends RowData>({
1620
1630
  getRowId: shownGetRowId,
1621
1631
  // Row details ride on `expanded`, the same state the tree uses - but a data
1622
1632
  // row answers `getCanExpand()` false, since TanStack's fallback is
1623
- // `subRows.length > 0`. `() => true` is the right answer for a group row
1624
- // too, so nothing here has to tell the two apart, and a consumer passing
1625
- // their own predicate still wins.
1626
- ...(renderDetails !== undefined
1627
- ? { getRowCanExpand: options.getRowCanExpand ?? (() => true) }
1633
+ // `subRows.length > 0`, so under `renderDetails` every row can expand.
1634
+ // A consumer's own predicate decides the data rows, never a group row:
1635
+ // TanStack builds a group row on its first child's record, and since 9.2
1636
+ // `toggleExpanded` refuses a row that cannot expand - so a predicate
1637
+ // rejecting that record would leave the group's chevron dead.
1638
+ ...(renderDetails !== undefined || options.getRowCanExpand !== undefined
1639
+ ? {
1640
+ getRowCanExpand: (row: Row<TMDataGridFeatures, TData>) =>
1641
+ row.getIsGrouped() ||
1642
+ (options.getRowCanExpand?.(row) ?? true),
1643
+ }
1628
1644
  : {}),
1629
1645
  // Always a predicate, never the passthrough: TanStack defaults the option
1630
1646
  // to `true` once the feature is registered, and the grid's default is off.