@opencorestack/opengridx 2.1.0 → 3.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 (225) hide show
  1. package/CHANGELOG.md +399 -0
  2. package/README.md +95 -72
  3. package/dist/index.d.ts +590 -131
  4. package/dist/opengridx.css +1 -1
  5. package/dist/opengridx.es.js +7891 -5631
  6. package/dist/opengridx.es.js.map +1 -1
  7. package/dist/opengridx.umd.js +17 -23
  8. package/dist/opengridx.umd.js.map +1 -1
  9. package/docs/API_REFERENCE.md +348 -166
  10. package/docs/README.md +6 -1
  11. package/docs/architecture/datagrid-orchestration.md +81 -0
  12. package/docs/architecture/grid-row-meta.md +102 -0
  13. package/docs/architecture/use-grid-columns.md +128 -0
  14. package/docs/architecture/use-grid-controlled-state.md +157 -0
  15. package/docs/architecture/use-grid-row-pipeline.md +120 -0
  16. package/docs/architecture/use-grid-scroll-sync.md +111 -0
  17. package/docs/architecture/use-grid-state-snapshot.md +90 -0
  18. package/docs/architecture/use-grid-virtualization.md +115 -0
  19. package/docs/architecture/use-grid-visible-rows.md +85 -0
  20. package/docs/assets/banner-alt.png +0 -0
  21. package/docs/assets/banner.png +0 -0
  22. package/docs/assets/hero.png +0 -0
  23. package/docs/assets/logo.png +0 -0
  24. package/docs/components/aggregation-footer.md +15 -10
  25. package/docs/components/cell.md +16 -6
  26. package/docs/components/column-group-header.md +55 -28
  27. package/docs/components/column-resize.md +17 -13
  28. package/docs/components/column-visibility.md +6 -7
  29. package/docs/components/datagrid.md +15 -13
  30. package/docs/components/empty-state.md +2 -1
  31. package/docs/components/error-overlay.md +12 -7
  32. package/docs/components/filter-panel.md +28 -8
  33. package/docs/components/header.md +28 -9
  34. package/docs/components/pagination.md +14 -8
  35. package/docs/components/row.md +21 -5
  36. package/docs/components/toolbar.md +27 -9
  37. package/docs/components/tooltip.md +16 -7
  38. package/docs/customization/slots-api.md +90 -38
  39. package/docs/customization/theming.md +66 -18
  40. package/docs/features/aggregation-pivot.md +75 -9
  41. package/docs/features/cell-spanning.md +80 -125
  42. package/docs/features/clipboard.md +41 -16
  43. package/docs/features/custom-pagination.md +38 -18
  44. package/docs/features/data-source.md +36 -13
  45. package/docs/features/editing-reordering.md +125 -16
  46. package/docs/features/export-guide.md +126 -39
  47. package/docs/features/filtering.md +44 -6
  48. package/docs/features/infinite-scroll.md +54 -46
  49. package/docs/features/keyboard-navigation.md +83 -0
  50. package/docs/features/list-view.md +58 -5
  51. package/docs/features/loading-states.md +18 -20
  52. package/docs/features/master-detail.md +18 -5
  53. package/docs/features/pdf-export.md +72 -19
  54. package/docs/features/pinning.md +24 -5
  55. package/docs/features/selection.md +50 -10
  56. package/docs/features/sorting-pagination.md +64 -14
  57. package/docs/features/state-persistence.md +78 -10
  58. package/docs/features/toolbar-customization.md +26 -17
  59. package/docs/features/tree-data-grouping.md +36 -8
  60. package/docs/features/virtualization.md +37 -14
  61. package/docs/migration/v1-to-v2.md +115 -0
  62. package/docs/migration/v2-to-v3.md +1233 -0
  63. package/docs/performance.md +124 -0
  64. package/docs/roadmap.md +5 -5
  65. package/lib/components/Cell/Cell.css +17 -1
  66. package/lib/components/Cell/Cell.tsx +129 -57
  67. package/lib/components/Cell/CellErrorBoundary.tsx +12 -6
  68. package/lib/components/Cell/GridEditInputCell.tsx +114 -41
  69. package/lib/components/ColumnGroupHeader/ColumnGroupHeader.css +7 -1
  70. package/lib/components/ColumnResizeHandle/ColumnResizeHandle.css +15 -2
  71. package/lib/components/ColumnResizeHandle/ColumnResizeHandle.tsx +104 -38
  72. package/lib/components/ColumnResizeHandle/clampResizeWidth.ts +13 -0
  73. package/lib/components/ColumnVisibilityPanel/ColumnVisibilityPanel.css +6 -0
  74. package/lib/components/ColumnVisibilityPanel/ColumnVisibilityPanel.tsx +21 -13
  75. package/lib/components/DataGrid/DataGrid.css +85 -12
  76. package/lib/components/DataGrid/DataGrid.tsx +582 -876
  77. package/lib/components/DataGrid/GridAggregationFooter.tsx +53 -17
  78. package/lib/components/DataGrid/GridErrorOverlay.tsx +15 -12
  79. package/lib/components/DataGrid/GridListView.tsx +165 -24
  80. package/lib/components/DataGrid/GridLiveRegion.tsx +31 -0
  81. package/lib/components/DataGrid/GridLoadingOverlay.tsx +27 -0
  82. package/lib/components/DataGrid/GridPaginationArea.tsx +44 -0
  83. package/lib/components/DataGrid/GridPinnedRows.tsx +62 -11
  84. package/lib/components/DataGrid/GridStandaloneColumnPanel.tsx +40 -38
  85. package/lib/components/DataGrid/GridToolbarSlot.tsx +51 -0
  86. package/lib/components/DataGrid/GridVirtualRows.tsx +40 -24
  87. package/lib/components/DetailPanel/DetailPanel.css +0 -6
  88. package/lib/components/DetailPanel/DetailPanel.tsx +34 -5
  89. package/lib/components/DetailPanel/DetailPanelContent.tsx +17 -0
  90. package/lib/components/FilterPanel/FilterPanel.css +13 -2
  91. package/lib/components/FilterPanel/FilterPanel.tsx +272 -99
  92. package/lib/components/Header/ColumnMenu.tsx +91 -39
  93. package/lib/components/Header/Header.css +6 -3
  94. package/lib/components/Header/Header.tsx +181 -160
  95. package/lib/components/ListView/ListView.css +25 -0
  96. package/lib/components/ListView/ListViewRow.tsx +76 -10
  97. package/lib/components/Pagination/Pagination.tsx +15 -7
  98. package/lib/components/Row/Row.tsx +177 -77
  99. package/lib/components/Toolbar/GlobalSearch.css +6 -3
  100. package/lib/components/Toolbar/GlobalSearch.tsx +26 -27
  101. package/lib/components/Toolbar/GridToolbar.css +12 -11
  102. package/lib/components/Toolbar/GridToolbar.tsx +133 -89
  103. package/lib/components/Toolbar/PivotPanel.tsx +89 -49
  104. package/lib/components/Tooltip/Tooltip.css +20 -0
  105. package/lib/components/Tooltip/Tooltip.tsx +68 -35
  106. package/lib/components/ui/Button.tsx +3 -0
  107. package/lib/components/ui/Checkbox.tsx +2 -1
  108. package/lib/components/ui/ExpandIcon.css +0 -9
  109. package/lib/components/ui/ExpandIcon.tsx +4 -1
  110. package/lib/hooks/core/gridApiPlaceholder.ts +34 -0
  111. package/lib/hooks/core/gridToolbarHostContext.ts +14 -0
  112. package/lib/hooks/core/useDataGrid.ts +115 -173
  113. package/lib/hooks/core/useGridAggregationApi.ts +72 -0
  114. package/lib/hooks/core/useGridApiMethods.ts +115 -0
  115. package/lib/hooks/core/useGridApiRef.ts +19 -4
  116. package/lib/hooks/core/useGridApiRefBinding.ts +18 -0
  117. package/lib/hooks/core/useGridAriaRows.ts +38 -0
  118. package/lib/hooks/core/useGridClipboardApi.ts +38 -0
  119. package/lib/hooks/core/useGridColumnLookup.ts +30 -0
  120. package/lib/hooks/core/useGridColumns.tsx +279 -76
  121. package/lib/hooks/core/useGridColumnsPanel.ts +77 -0
  122. package/lib/hooks/core/useGridControlledState.ts +99 -6
  123. package/lib/hooks/core/useGridDetailPanel.ts +51 -0
  124. package/lib/hooks/core/useGridDevWarnings.ts +104 -5
  125. package/lib/hooks/core/useGridFocusHandlers.ts +50 -0
  126. package/lib/hooks/core/useGridGroupingColumn.ts +62 -0
  127. package/lib/hooks/core/useGridHeaderHandlers.ts +92 -0
  128. package/lib/hooks/core/useGridHierarchy.ts +81 -0
  129. package/lib/hooks/core/useGridKeyboardNavigation.ts +447 -243
  130. package/lib/hooks/core/useGridLiveRowSelection.ts +67 -0
  131. package/lib/hooks/core/useGridPageCorrection.ts +55 -0
  132. package/lib/hooks/core/useGridRowIdOf.ts +32 -0
  133. package/lib/hooks/core/useGridRowInteractions.ts +81 -0
  134. package/lib/hooks/core/useGridRowPipeline.ts +69 -39
  135. package/lib/hooks/core/useGridRowSelection.ts +91 -0
  136. package/lib/hooks/core/useGridScrollSync.ts +80 -32
  137. package/lib/hooks/core/useGridScrollToIndexesApi.ts +45 -0
  138. package/lib/hooks/core/useGridStateSnapshot.ts +40 -5
  139. package/lib/hooks/core/useGridThemeDimensions.ts +49 -0
  140. package/lib/hooks/core/useGridToolbarProps.ts +97 -0
  141. package/lib/hooks/core/useGridViewport.ts +38 -0
  142. package/lib/hooks/core/useGridViewportSize.ts +26 -0
  143. package/lib/hooks/core/useGridVisibleRows.ts +17 -5
  144. package/lib/hooks/core/useLayout.ts +215 -195
  145. package/lib/hooks/core/useRowsScrollEndLatch.ts +41 -0
  146. package/lib/hooks/core/useStableColumns.ts +34 -0
  147. package/lib/hooks/features/useAggregation.ts +82 -51
  148. package/lib/hooks/features/useColumnGroupReorderGuard.ts +34 -0
  149. package/lib/hooks/features/useDetailPanelHeights.ts +29 -0
  150. package/lib/hooks/features/useGridClipboard.ts +133 -73
  151. package/lib/hooks/features/useGridDataSource.ts +354 -128
  152. package/lib/hooks/features/useGridEditing.ts +211 -51
  153. package/lib/hooks/features/useGridPivot.ts +92 -0
  154. package/lib/hooks/features/useGridSpanRenderWindow.ts +104 -0
  155. package/lib/hooks/features/useGridSpanning.ts +410 -306
  156. package/lib/hooks/features/usePivot.ts +0 -0
  157. package/lib/hooks/features/useServerTreeChildren.ts +50 -0
  158. package/lib/hooks/useColumnReorder.ts +38 -44
  159. package/lib/hooks/useRowGrouping.ts +298 -160
  160. package/lib/hooks/useRowReorder.ts +62 -31
  161. package/lib/hooks/useTreeData.ts +287 -220
  162. package/lib/index.ts +28 -2
  163. package/lib/state/index.ts +1 -0
  164. package/lib/state/types.ts +7 -1
  165. package/lib/state/useGridStateStorage.ts +88 -29
  166. package/lib/theme/DataGridThemeProvider.tsx +143 -38
  167. package/lib/theme/gridThemeContext.ts +5 -0
  168. package/lib/theme/index.ts +5 -0
  169. package/lib/theme/presets.ts +5 -4
  170. package/lib/theme/types.ts +40 -2
  171. package/lib/types/index.ts +313 -116
  172. package/lib/utils/aggregation/index.ts +119 -24
  173. package/lib/utils/aria/index.ts +40 -0
  174. package/lib/utils/columnGroups.ts +110 -0
  175. package/lib/utils/columnLookup.ts +33 -0
  176. package/lib/utils/columnWidth.ts +22 -0
  177. package/lib/utils/dataSource/index.ts +46 -0
  178. package/lib/utils/detailPanel.ts +66 -0
  179. package/lib/utils/dragData.ts +44 -0
  180. package/lib/utils/editing/index.ts +30 -0
  181. package/lib/utils/export/exportShared.ts +197 -0
  182. package/lib/utils/export/exportToExcelAdvanced.ts +278 -139
  183. package/lib/utils/export/exportToPdf.ts +143 -92
  184. package/lib/utils/export/groupLabel.ts +14 -0
  185. package/lib/utils/export/index.ts +278 -272
  186. package/lib/utils/export/pdfText.ts +50 -0
  187. package/lib/utils/filtering/index.ts +277 -148
  188. package/lib/utils/focus/index.ts +115 -0
  189. package/lib/utils/gridApiRows.ts +35 -0
  190. package/lib/utils/gridModes.ts +77 -0
  191. package/lib/utils/grouping/groupedExportRows.ts +91 -0
  192. package/lib/utils/pagination/index.ts +56 -0
  193. package/lib/utils/pinning/index.ts +77 -33
  194. package/lib/utils/pivot/index.ts +368 -0
  195. package/lib/utils/scroll/index.ts +55 -5
  196. package/lib/utils/scroll/scrollEnd.ts +18 -0
  197. package/lib/utils/sorting/index.ts +154 -30
  198. package/lib/utils/syntheticRows.ts +12 -0
  199. package/lib/utils/values.ts +206 -0
  200. package/lib/utils/viewport.ts +14 -0
  201. package/llms.txt +261 -164
  202. package/package.json +13 -5
  203. package/lib/components/ColumnGroupHeader/ColumnGroupHeader.tsx +0 -220
  204. package/lib/components/ColumnVisibilityPanel/ColumnVisibilityPanel.test.tsx +0 -85
  205. package/lib/components/DataGrid/DataGrid.defects.test.tsx +0 -103
  206. package/lib/components/DataGrid/DataGrid.regression.test.tsx +0 -132
  207. package/lib/components/DataGrid/DataGrid.smoke.test.tsx +0 -58
  208. package/lib/components/DataGrid/DataGrid.v2.test.tsx +0 -127
  209. package/lib/components/DataGrid/DataGrid.virtualization.browser.test.tsx +0 -183
  210. package/lib/components/Header/Header.test.tsx +0 -135
  211. package/lib/components/Pagination/Pagination.test.tsx +0 -64
  212. package/lib/hooks/core/useDataGrid.regression.test.ts +0 -66
  213. package/lib/hooks/core/useGridControlledState.test.ts +0 -86
  214. package/lib/hooks/core/useGridKeyboardNavigation.test.ts +0 -176
  215. package/lib/hooks/core/useGridRowPipeline.test.ts +0 -117
  216. package/lib/hooks/features/useAggregation.test.ts +0 -175
  217. package/lib/hooks/features/usePivot.test.ts +0 -202
  218. package/lib/hooks/useRowGrouping.test.ts +0 -298
  219. package/lib/hooks/useTreeData.test.ts +0 -83
  220. package/lib/utils/aggregation/aggregation.test.ts +0 -16
  221. package/lib/utils/export/exportToExcelAdvanced.test.ts +0 -109
  222. package/lib/utils/export/exportToPdf.test.ts +0 -120
  223. package/lib/utils/export/groupedExport.test.ts +0 -144
  224. package/lib/utils/filtering/filtering.test.ts +0 -178
  225. package/lib/utils/sorting/sorting.test.ts +0 -88
@@ -0,0 +1,12 @@
1
+ import type { GridRowId, GridRowMeta } from '../types';
2
+ import { PIVOT_GRAND_TOTAL_ID } from './pivot';
3
+
4
+ /**
5
+ * True for a row the grid made rather than one of the consumer's rows: a row-grouping header or
6
+ * subtotal, an auto-created tree-data parent (`rowMeta.isGroupRow`), or the pivot Grand Total.
7
+ * Such rows are never selected (checkbox, click, keyboard, `apiRef`) and never start or carry a
8
+ * row span.
9
+ */
10
+ export function isSyntheticRowId(id: GridRowId, rowMetaMap?: ReadonlyMap<GridRowId, GridRowMeta>): boolean {
11
+ return id === PIVOT_GRAND_TOTAL_ID || rowMetaMap?.get(id)?.isGroupRow === true;
12
+ }
@@ -0,0 +1,206 @@
1
+ import type { GridColDef, GridRowModel } from '../types';
2
+
3
+ const warnedCallbacks = new Set<string>();
4
+
5
+ /**
6
+ * Warn once per key (callback kind and column), in development only, that a consumer callback
7
+ * threw and the grid fell back to a default instead of crashing.
8
+ */
9
+ export function warnCallbackFailure(key: string, message: string, error: unknown): void {
10
+ if (process.env.NODE_ENV === 'production' || warnedCallbacks.has(key)) return;
11
+ warnedCallbacks.add(key);
12
+ console.warn(`[OpenGridX] ${message}.`, error);
13
+ }
14
+
15
+ /**
16
+ * Call a consumer callback; when it throws, warn once per `key` (dev only) and return `fallback`.
17
+ * Used for callbacks whose failure has an obvious default (a detail-panel height, a group label).
18
+ */
19
+ export function callSafely<T>(fn: () => T, fallback: T, key: string, message: string): T {
20
+ try {
21
+ return fn();
22
+ } catch (error) {
23
+ warnCallbackFailure(key, message, error);
24
+ return fallback;
25
+ }
26
+ }
27
+
28
+ type ValueGetterColumn<R extends GridRowModel> = Pick<GridColDef<R>, 'valueGetter'>;
29
+
30
+ /**
31
+ * Read a cell through the column's `valueGetter` (or `row[field]`), returning a throw as `error`
32
+ * instead of swallowing it. The row renderer uses this to show the error in that one cell.
33
+ */
34
+ export function tryGetCellValue<R extends GridRowModel>(
35
+ row: R,
36
+ field: string,
37
+ colDef?: ValueGetterColumn<R>
38
+ ): { value: unknown; error?: unknown } {
39
+ const raw = row[field];
40
+ if (!colDef?.valueGetter) return { value: raw };
41
+ try {
42
+ return { value: colDef.valueGetter({ row, field, value: raw }) };
43
+ } catch (error) {
44
+ return { value: undefined, error: error ?? new Error('valueGetter failed') };
45
+ }
46
+ }
47
+
48
+ /**
49
+ * The value a cell holds before formatting: the column's `valueGetter` result when it has one,
50
+ * otherwise `row[field]`. Filtering, sorting, the quick filter, aggregation, row grouping, pivot,
51
+ * list view, clipboard and editing all read cells through this, so a computed column behaves the
52
+ * same everywhere. A `valueGetter` that throws reads as `undefined` (with a one-time dev warning
53
+ * per column), so one bad record cannot take the whole grid down.
54
+ */
55
+ export function getCellValue<R extends GridRowModel>(row: R, field: string, colDef?: ValueGetterColumn<R>): unknown {
56
+ const { value, error } = tryGetCellValue(row, field, colDef);
57
+ if (error !== undefined) {
58
+ warnCallbackFailure(`valueGetter:${field}`, `valueGetter for column "${field}" threw; the value is read as undefined`, error);
59
+ }
60
+ return value;
61
+ }
62
+
63
+ /**
64
+ * The column's `valueFormatter` text for `value`, or undefined when the column has no formatter
65
+ * or the formatter throws (with a one-time dev warning per column).
66
+ */
67
+ export function getFormattedValue<R extends GridRowModel>(
68
+ row: R,
69
+ field: string,
70
+ value: unknown,
71
+ colDef?: Pick<GridColDef<R>, 'valueFormatter'>
72
+ ): string | undefined {
73
+ const formatter = colDef?.valueFormatter;
74
+ if (!formatter) return undefined;
75
+ return callSafely(
76
+ () => formatter({ value, row, field }),
77
+ undefined,
78
+ `valueFormatter:${field}`,
79
+ `valueFormatter for column "${field}" threw; the value is shown unformatted`,
80
+ );
81
+ }
82
+
83
+ /**
84
+ * Coerce a cell or filter value to a number. Returns null for null/undefined, blank strings,
85
+ * NaN and anything that does not parse, so an empty cell is never read as 0.
86
+ */
87
+ export function toNumber(value: unknown): number | null {
88
+ if (value == null) return null;
89
+ if (typeof value === 'number') return Number.isNaN(value) ? null : value;
90
+ if (typeof value === 'string') {
91
+ const trimmed = value.trim();
92
+ if (trimmed === '') return null;
93
+ const n = Number(trimmed);
94
+ return Number.isNaN(n) ? null : n;
95
+ }
96
+ if (typeof value === 'boolean') return null;
97
+ if (value instanceof Date) {
98
+ const t = value.getTime();
99
+ return Number.isNaN(t) ? null : t;
100
+ }
101
+ if (typeof value === 'bigint') return Number(value);
102
+ return null;
103
+ }
104
+
105
+ const DATE_ONLY = /^(\d{4})-(\d{2})-(\d{2})$/;
106
+
107
+ /**
108
+ * Parse a Date object, epoch milliseconds or a date string. A plain `YYYY-MM-DD` string is read
109
+ * as a local calendar date: `new Date('2024-01-10')` is UTC midnight, which is the previous day
110
+ * west of UTC. Returns null for empty, unparsable or invalid values.
111
+ */
112
+ export function toDate(value: unknown): Date | null {
113
+ if (value == null) return null;
114
+ let date: Date;
115
+ if (value instanceof Date) {
116
+ date = value;
117
+ } else if (typeof value === 'number') {
118
+ date = new Date(value);
119
+ } else if (typeof value === 'string') {
120
+ const trimmed = value.trim();
121
+ if (trimmed === '') return null;
122
+ const match = DATE_ONLY.exec(trimmed);
123
+ if (match) {
124
+ const year = Number(match[1]);
125
+ const month = Number(match[2]) - 1;
126
+ const day = Number(match[3]);
127
+ date = new Date(year, month, day);
128
+ // Reject roll-overs such as 2024-02-31.
129
+ if (date.getMonth() !== month || date.getDate() !== day) return null;
130
+ } else {
131
+ date = new Date(trimmed);
132
+ }
133
+ } else {
134
+ return null;
135
+ }
136
+ return Number.isNaN(date.getTime()) ? null : date;
137
+ }
138
+
139
+ /** A sortable integer for the local calendar day of a date (YYYYMMDD), or null when unparsable. */
140
+ export function toLocalDayKey(value: unknown): number | null {
141
+ const date = toDate(value);
142
+ if (!date) return null;
143
+ return date.getFullYear() * 10000 + (date.getMonth() + 1) * 100 + date.getDate();
144
+ }
145
+
146
+ /** The local calendar day of a date as `YYYY-MM-DD`, or '' when unparsable. */
147
+ export function toLocalDateString(value: unknown): string {
148
+ const date = toDate(value);
149
+ if (!date) return '';
150
+ const y = String(date.getFullYear()).padStart(4, '0');
151
+ const m = String(date.getMonth() + 1).padStart(2, '0');
152
+ const d = String(date.getDate()).padStart(2, '0');
153
+ return `${y}-${m}-${d}`;
154
+ }
155
+
156
+ let localDateFormat: Intl.DateTimeFormat | null = null;
157
+
158
+ /**
159
+ * `date.toLocaleDateString()` (the default locale's numeric date), with the formatter created
160
+ * once: building a new one per call is several times slower on large grids.
161
+ */
162
+ export function formatLocalDate(date: Date): string {
163
+ localDateFormat ??= new Intl.DateTimeFormat();
164
+ return localDateFormat.format(date);
165
+ }
166
+
167
+ type ValueOption = string | number | { value: unknown; label: string };
168
+
169
+ /** The label of the `valueOptions` entry for `value`, or undefined when no option matches. */
170
+ export function getValueOptionLabel(options: readonly ValueOption[] | undefined, value: unknown): string | undefined {
171
+ if (!options) return undefined;
172
+ const optionValue = (option: ValueOption): unknown => (typeof option === 'object' ? option.value : option);
173
+ const optionLabel = (option: ValueOption): string => (typeof option === 'object' ? option.label : String(option));
174
+ // Exact match first; then by text, so a numeric option still labels a value read back as a string.
175
+ const match = options.find(option => Object.is(optionValue(option), value))
176
+ ?? options.find(option => String(optionValue(option)) === String(value));
177
+ return match === undefined ? undefined : optionLabel(match);
178
+ }
179
+
180
+ /**
181
+ * Default display text for a cell whose column has no `valueFormatter`, by column `type`:
182
+ * - `date`: the local calendar date (`toLocaleDateString()`) of a Date, timestamp or date string;
183
+ * text that does not parse as a date is shown as is.
184
+ * - `boolean`: `Yes` / `No` for `true` / `false`.
185
+ * - `singleSelect`: the matching `valueOptions` label; a value with no option is shown as is.
186
+ * - anything else (and `image`, whose cell renders an image of this URL): `String(value)`.
187
+ * null and undefined are ''. The grid cells and the text exporters (CSV, print, PDF) use this, so
188
+ * a file shows what the grid shows.
189
+ */
190
+ export function formatValueByType(value: unknown, colDef: Pick<GridColDef, 'type' | 'valueOptions'> | undefined): string {
191
+ if (value === null || value === undefined) return '';
192
+ switch (colDef?.type) {
193
+ case 'date': {
194
+ const date = toDate(value);
195
+ return date ? formatLocalDate(date) : String(value);
196
+ }
197
+ case 'boolean':
198
+ if (value === true) return 'Yes';
199
+ if (value === false) return 'No';
200
+ return String(value);
201
+ case 'singleSelect':
202
+ return getValueOptionLabel(colDef.valueOptions, value) ?? String(value);
203
+ default:
204
+ return String(value);
205
+ }
206
+ }
@@ -0,0 +1,14 @@
1
+ /**
2
+ * Size of the layout viewport that `position: fixed` offsets are measured from. Unlike
3
+ * `window.innerWidth` / `innerHeight` it excludes a classic (non-overlay) page scrollbar, so a
4
+ * panel placed with `right: getViewportWidth() - anchorRect.right` lines up with its anchor on
5
+ * Windows and Linux desktops too. Falls back to the window size where the document element
6
+ * reports no size (jsdom).
7
+ */
8
+ export function getViewportWidth(): number {
9
+ return document.documentElement.clientWidth || window.innerWidth;
10
+ }
11
+
12
+ export function getViewportHeight(): number {
13
+ return document.documentElement.clientHeight || window.innerHeight;
14
+ }