@lavalogic/scoria 0.40.0 → 0.40.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.
Files changed (137) hide show
  1. package/README.md +58 -58
  2. package/dist/Components/AccordionGroup.svelte +46 -46
  3. package/dist/Components/AccordionGroupButton.svelte +76 -76
  4. package/dist/Components/Action.svelte +136 -136
  5. package/dist/Components/AlertModal.svelte +195 -195
  6. package/dist/Components/AppointmentCalendar/AppointmentCalendar.svelte +729 -729
  7. package/dist/Components/Base/BaseModal.svelte +125 -125
  8. package/dist/Components/Base/ContextWrapper.svelte +72 -72
  9. package/dist/Components/Base/Pagination.svelte +198 -198
  10. package/dist/Components/Base/Snippets.svelte +36 -36
  11. package/dist/Components/BigRadioSet.svelte +38 -38
  12. package/dist/Components/Bubble.svelte +101 -101
  13. package/dist/Components/Button.svelte +209 -209
  14. package/dist/Components/Checkbox.svelte +86 -86
  15. package/dist/Components/CollapsibleCard.svelte +78 -78
  16. package/dist/Components/Contexts/ContextMenu.svelte +164 -164
  17. package/dist/Components/Contexts/ContextMenuDivider.svelte +15 -15
  18. package/dist/Components/Contexts/ContextMenuOption.svelte +60 -60
  19. package/dist/Components/Contexts/Toast.svelte +86 -86
  20. package/dist/Components/Contexts/ToastContainer.svelte +65 -65
  21. package/dist/Components/Contexts/Tooltip.svelte +37 -37
  22. package/dist/Components/DataMatrixIcon.svelte +112 -112
  23. package/dist/Components/DateInput.svelte +148 -148
  24. package/dist/Components/DatePicker.svelte +300 -300
  25. package/dist/Components/DesktopModal.svelte +90 -90
  26. package/dist/Components/Dial.svelte +204 -204
  27. package/dist/Components/DimensionInput.svelte +170 -170
  28. package/dist/Components/DragMenu/DragMenuHolder.svelte +119 -119
  29. package/dist/Components/DragMenu/DraggableCard.svelte +77 -77
  30. package/dist/Components/FileCard.svelte +24 -24
  31. package/dist/Components/FileUpload.svelte +236 -236
  32. package/dist/Components/GridInput.svelte +196 -196
  33. package/dist/Components/GridInputSet.svelte +29 -29
  34. package/dist/Components/HorizontalTabGroup.svelte +82 -82
  35. package/dist/Components/HorizontalTabGroupButton.svelte +44 -44
  36. package/dist/Components/Icon.svelte +128 -128
  37. package/dist/Components/Icons.js +357 -357
  38. package/dist/Components/InfoAlert.svelte +35 -35
  39. package/dist/Components/LoadingAnimation.svelte +29 -29
  40. package/dist/Components/LoadingModal.svelte +45 -45
  41. package/dist/Components/LoadingOverlay.svelte +25 -25
  42. package/dist/Components/Modal.svelte +258 -258
  43. package/dist/Components/MultiSelect.svelte +220 -220
  44. package/dist/Components/Nav/Nav.svelte +110 -110
  45. package/dist/Components/Nav/NavServiceMenuList.svelte +43 -43
  46. package/dist/Components/Nav/NavTab.svelte +62 -62
  47. package/dist/Components/Nav/ServiceMenuItem.svelte +112 -112
  48. package/dist/Components/Nav/ServicesNav.svelte +80 -80
  49. package/dist/Components/NumberInput.svelte +157 -157
  50. package/dist/Components/PageHeading.svelte +25 -25
  51. package/dist/Components/PasswordInput.svelte +88 -88
  52. package/dist/Components/Portal.svelte +36 -36
  53. package/dist/Components/ProgressBubble.svelte +107 -107
  54. package/dist/Components/QuerySelect.svelte +366 -366
  55. package/dist/Components/SingleSelect.svelte +250 -250
  56. package/dist/Components/StepButton.svelte +70 -70
  57. package/dist/Components/StepForm.svelte +140 -140
  58. package/dist/Components/Switch.svelte +69 -69
  59. package/dist/Components/Table/ARCHITECTURE.md +298 -298
  60. package/dist/Components/Table/Body/QuickSearchCell.svelte +679 -679
  61. package/dist/Components/Table/Body/Rows/ColumnHighlight.svelte +51 -51
  62. package/dist/Components/Table/Body/Rows/ColumnList.svelte +59 -59
  63. package/dist/Components/Table/Body/Rows/ColumnListRow.svelte +454 -454
  64. package/dist/Components/Table/Body/Rows/Columns/AccessorComponent.svelte +79 -79
  65. package/dist/Components/Table/Body/Rows/Columns/ActionsCell.svelte +185 -185
  66. package/dist/Components/Table/Body/Rows/Columns/BubbleCell.svelte +124 -124
  67. package/dist/Components/Table/Body/Rows/Columns/ExpandCell.svelte +131 -120
  68. package/dist/Components/Table/Body/Rows/Columns/FocusableImmutableCell.svelte +234 -234
  69. package/dist/Components/Table/Body/Rows/Columns/ProgressCell.svelte +105 -105
  70. package/dist/Components/Table/Body/Rows/Columns/TableAction.svelte +87 -87
  71. package/dist/Components/Table/Body/Rows/Columns/TableCheckbox.svelte +126 -126
  72. package/dist/Components/Table/Body/Rows/Columns/TableColumn.svelte +159 -159
  73. package/dist/Components/Table/Body/Rows/Columns/TableDatePicker.svelte +246 -246
  74. package/dist/Components/Table/Body/Rows/Columns/TableNumberInput.svelte +216 -216
  75. package/dist/Components/Table/Body/Rows/Columns/TableQuerySelect.svelte +252 -252
  76. package/dist/Components/Table/Body/Rows/Columns/TableRowSelectionCheckbox.svelte +179 -179
  77. package/dist/Components/Table/Body/Rows/Columns/TableSelect.svelte +221 -221
  78. package/dist/Components/Table/Body/Rows/Columns/TableTextInput.svelte +197 -197
  79. package/dist/Components/Table/Body/Rows/Columns/ValidityCell.svelte +190 -190
  80. package/dist/Components/Table/Body/Rows/TableRow.svelte +290 -290
  81. package/dist/Components/Table/Body/TableBody.svelte +155 -155
  82. package/dist/Components/Table/ColumnFactory.svelte.js +1 -0
  83. package/dist/Components/Table/Headers/HighlightAllHeader.svelte +41 -41
  84. package/dist/Components/Table/Headers/SelectAllHeader.svelte +30 -30
  85. package/dist/Components/Table/Headers/TableHead.svelte +415 -415
  86. package/dist/Components/Table/Misc/ColumnPanel.svelte +39 -39
  87. package/dist/Components/Table/Misc/ColumnPanelModal.svelte +39 -39
  88. package/dist/Components/Table/Misc/FilterInput.svelte +641 -641
  89. package/dist/Components/Table/Misc/FilterPanel.svelte +190 -190
  90. package/dist/Components/Table/Misc/FilterPanelModal.svelte +31 -31
  91. package/dist/Components/Table/Misc/ShareViewModal.svelte +291 -291
  92. package/dist/Components/Table/Misc/SidePanel.svelte +35 -35
  93. package/dist/Components/Table/Misc/TableConfigurationModal.svelte +644 -644
  94. package/dist/Components/Table/Misc/TableFooter.svelte +340 -340
  95. package/dist/Components/Table/Misc/TableHorizontalBar.svelte +140 -140
  96. package/dist/Components/Table/Misc/TableSidebar.svelte +200 -200
  97. package/dist/Components/Table/Misc/TableViewDropdown.svelte +105 -105
  98. package/dist/Components/Table/Misc/ToolboxPanel.svelte +100 -100
  99. package/dist/Components/Table/Misc/ToolboxPanelModal.svelte +107 -107
  100. package/dist/Components/Table/Misc/UpdateViewOptionsModal.svelte +192 -192
  101. package/dist/Components/Table/NestedTable.svelte +130 -130
  102. package/dist/Components/Table/Table.svelte +692 -692
  103. package/dist/Components/Table/Types/Columns/Definitions/Expand/ExpandDef.svelte.d.ts +5 -0
  104. package/dist/Components/Table/Types/Columns/Definitions/Expand/ExpandDef.svelte.js +3 -0
  105. package/dist/Components/Table/Types/Public/ColumnOptions.d.ts +10 -0
  106. package/dist/Components/Test/TestContextConsumer.svelte +13 -13
  107. package/dist/Components/TextArea.svelte +130 -130
  108. package/dist/Components/TextInput.svelte +176 -176
  109. package/dist/Components/ThreeStateRadio.svelte +131 -131
  110. package/dist/Components/Touch/BoolCard.svelte +45 -45
  111. package/dist/Components/Touch/DateModal.svelte +209 -209
  112. package/dist/Components/Touch/EditCard.svelte +59 -59
  113. package/dist/Components/Touch/InfoCard.svelte +31 -31
  114. package/dist/Components/Touch/InfoTextCard.svelte +28 -28
  115. package/dist/Components/Touch/ModalExplanation.svelte +17 -17
  116. package/dist/Components/Touch/NumberKeyboard.svelte +225 -225
  117. package/dist/Components/Touch/NumberModal.svelte +79 -79
  118. package/dist/Components/Touch/PlusMinusCard.svelte +46 -46
  119. package/dist/Components/Touch/SelectModal.svelte +127 -127
  120. package/dist/Components/Touch/SummaryCard.svelte +93 -93
  121. package/dist/Components/Touch/TextAreaModal.svelte +95 -95
  122. package/dist/Components/Touch/TextModal.svelte +106 -106
  123. package/dist/Components/Touch/TouchCard.svelte +33 -33
  124. package/dist/Components/Touch/TouchModal.svelte +274 -274
  125. package/dist/Components/Touch/UtilityButton.svelte +109 -109
  126. package/dist/Components/VerticalTabGroup.svelte +79 -79
  127. package/dist/Components/VerticalTabGroupButton.svelte +58 -58
  128. package/dist/Helpers/Datamatrix.d.ts +19 -19
  129. package/dist/Helpers/Datamatrix.js +291 -291
  130. package/dist/Types/Examples/ExampleModal.svelte +35 -35
  131. package/dist/scss/_basics.scss +12 -12
  132. package/dist/scss/_colours.scss +134 -134
  133. package/dist/scss/_mixins.scss +3392 -3392
  134. package/dist/scss/_motion.scss +57 -57
  135. package/dist/scss/_sizing.scss +85 -85
  136. package/dist/scss/_transitions.scss +8 -8
  137. package/package.json +1 -1
@@ -1,292 +1,292 @@
1
- <svelte:options runes />
2
-
3
- <script
4
- lang="ts"
5
- generics="T extends object, RowIdType extends Primitive"
6
- >
7
- import type { ScoriaStorageKey } from '../../../../Types/Internal/Misc.js';
8
- import { dev } from '$app/environment';
9
- import { devCatch, generateWeakId } from '../../../../Helpers/Helpers.svelte.js';
10
- import { getContext, untrack } from 'svelte';
11
- import NestedTable from '../../NestedTable.svelte';
12
- import type { ExpandDef } from '../../Types/Columns/Definitions/Expand/ExpandDef.svelte.js';
13
- import type { DefsWrapper } from '../../Types/Columns/DefsWrapper.js';
14
- import type { TableCell } from '../../Types/Columns/TableCell.js';
15
- import { TableContext } from '../../Types/Context/TableContext.svelte.js';
16
- import { type Primitive } from '../../Types/Context/TableInitOptions.js';
17
- import ColumnHighlight from './ColumnHighlight.svelte';
18
- import TableColumn from './Columns/TableColumn.svelte';
19
- import type { TableRowProps } from './TableRowProps.js';
20
-
21
- const tableContext = getContext<TableContext<T, RowIdType>>(TableContext.identifier);
22
-
23
- const { row, odd = false, includeHighlight }: TableRowProps<T> = $props();
24
-
25
- const hoverable = $derived(tableContext.changeColourOnHover);
26
-
27
- // Visible cells in display order: left-pinned -> centre -> right-pinned.
28
- // The browser now handles row-height alignment natively because all
29
- // cells live in the same grid row, so the previous per-side fan-out
30
- // and height-reconciliation pool is gone.
31
- const leftCells: Array<TableCell<T>> = $derived(row.getLeftVisibleCells());
32
- const centreCells: Array<TableCell<T>> = $derived(row.getCenterVisibleCells());
33
- const rightCells: Array<TableCell<T>> = $derived(row.getRightVisibleCells());
34
-
35
- // Cumulative pinning offsets for the sticky-positioned cells. Reads
36
- // rendered widths from `_columnRenderedWidths` (populated by the
37
- // ResizeObserver in TableHead) so the sticky positions stay
38
- // accurate even though each pinned column track uses
39
- // `minmax(W, 1fr)` and the actual width can exceed `columnDef.width`.
40
- function renderedWidth(cell: TableCell<T>): number {
41
- return tableContext._columnRenderedWidths.get(cell.column.id) ?? cell.column.columnDef.width;
42
- }
43
-
44
- const leftOffsets: Array<number> = $derived.by(() => {
45
- void tableContext._columnRenderedWidths.size;
46
- const offsets: Array<number> = [];
47
- let cumulative = includeHighlight ? 20 : 0;
48
- for (const cell of leftCells) {
49
- offsets.push(cumulative);
50
- cumulative += renderedWidth(cell);
51
- }
52
- return offsets;
53
- });
54
-
55
- const rightOffsets: Array<number> = $derived.by(() => {
56
- void tableContext._columnRenderedWidths.size;
57
- const offsets = new Array<number>(rightCells.length).fill(0);
58
- let cumulative = 0;
59
- for (let i = rightCells.length - 1; i >= 0; i--) {
60
- offsets[i] = cumulative;
61
- cumulative += renderedWidth(rightCells[i]);
62
- }
63
- return offsets;
64
- });
65
-
66
- let expandedColumnDef: ExpandDef<T, object> | undefined = $state();
67
-
68
- $effect(() => {
69
- if (leftCells.length + centreCells.length + rightCells.length > 0) {
70
- void tableContext.table.data;
71
- void tableContext.paginationRepo?.paginationState.pageIndex;
72
- void tableContext.paginationRepo?.paginationState.pageSize;
73
- untrack(() => {
74
- expandedColumnDef = undefined;
75
- });
76
- }
77
- });
78
-
79
- let innerDataPromise: Array<object> | Promise<Array<object>> | undefined = $state();
80
- let innerColumnDefs: DefsWrapper<object> = $state({ defs: [] });
81
- let innerTableName: ScoriaStorageKey | undefined = $state();
82
-
83
- let prevExpandedColumnDef: ExpandDef<T, object> | undefined = $state();
84
-
85
- const firstCell = $derived(leftCells.at(0) ?? centreCells.at(0) ?? rightCells.at(0));
86
- const rowIndex = $derived(firstCell?.row.visibleIndex);
87
- let id = $state<RowIdType | undefined>();
88
- const highlighted = $derived(id != undefined && tableContext.highlightedItems.has(id));
89
-
90
- $effect(() => {
91
- void row.original;
92
- void tableContext.selectionExtractor;
93
-
94
- if (rowIndex != undefined) {
95
- const maybePromise = tableContext.selectionExtractor(row.original);
96
- if (maybePromise instanceof Promise) {
97
- maybePromise
98
- .then((it) => {
99
- id = it;
100
- })
101
- .catch(devCatch);
102
- } else {
103
- id = maybePromise;
104
- }
105
- } else {
106
- id = undefined;
107
- }
108
- });
109
-
110
- const showHighlightButton = $derived(rowIndex != null && includeHighlight);
111
-
112
- $effect(() => {
113
- void expandedColumnDef;
114
-
115
- untrack(() => {
116
- // Guard: if all columns have been hidden the cells arrays are
117
- // empty; `firstCell` would otherwise be undefined.
118
- if (!firstCell) {
119
- return;
120
- }
121
- if (expandedColumnDef && expandedColumnDef.id != prevExpandedColumnDef?.id) {
122
- prevExpandedColumnDef = expandedColumnDef;
123
- innerColumnDefs = expandedColumnDef.getInnerColumnDefs(
124
- firstCell.row.original,
125
- firstCell.row.originalIndex
126
- );
127
-
128
- innerDataPromise = expandedColumnDef.accessorFn(
129
- firstCell.row.original,
130
- firstCell.row.originalIndex
131
- ) as Promise<Array<object>>;
132
- innerTableName = expandedColumnDef.innerTableName;
133
- } else if (
134
- !expandedColumnDef ||
135
- tableContext.columnVisibility[expandedColumnDef.id] === false
136
- ) {
137
- innerTableName = undefined;
138
- expandedColumnDef = prevExpandedColumnDef = innerDataPromise = undefined;
139
- innerColumnDefs = { defs: [] };
140
- }
141
- });
142
- });
143
-
144
- function onExpandChange(columnDef: ExpandDef<T, object>) {
145
- if (expandedColumnDef?.id === columnDef.id) {
146
- expandedColumnDef = undefined;
147
- } else {
148
- expandedColumnDef = columnDef;
149
- }
150
- }
151
-
152
- // Stable fallback name used when an ExpandDef does not supply its own
153
- // `innerTableName`. Generating this once per row prevents localStorage
154
- // preset keys from accumulating UUID-keyed garbage every expand toggle.
155
- const fallbackInnerTableName = generateWeakId<ScoriaStorageKey>();
156
-
157
- /**
158
- * Inline style appended to a cell's `style="..."` when its column opts
159
- * into `wrapValue`. The hooks switch the leaf cell's `white-space`,
160
- * `overflow-x`, and `height` to wrap-friendly values. Implemented as
161
- * CSS-variable overrides so the table-cell-basic mixin in
162
- * `_mixins.scss` consumes them via `var(--cell-* , fallback)`.
163
- */
164
- function cellWrapStyle(cell: TableCell<T>): string {
165
- return cell.column.columnDef.wrapValue
166
- ? '--cell-white-space: normal; --cell-overflow-x: visible; --cell-height: auto; --cell-min-height: var(--height);'
167
- : '';
168
- }
169
- </script>
170
-
171
- <div
172
- role="row"
173
- class="datatable-row"
174
- class:hoverable
175
- class:alt={tableContext.alternateRowColours && odd}
176
- class:highlighted
177
- >
178
- {#if showHighlightButton}
179
- <div
180
- role="cell"
181
- class="cell highlight-cell pinned-left"
182
- style="left: 0px"
183
- >
184
- <ColumnHighlight
185
- rowIndex={rowIndex ??
186
- (() => {
187
- if (dev) {
188
- console.error(`column had invalid row index: ${rowIndex}`);
189
- }
190
- return -1;
191
- })()}
192
- {highlighted}
193
- toggleHighlightedRow={() => {
194
- tableContext.toggleHighlightedRow(row.original)?.catch(devCatch);
195
- }}
196
- />
197
- </div>
198
- {/if}
199
- {#each leftCells as cell, index (cell.column.id)}
200
- <div
201
- role="cell"
202
- class="cell pinned-left"
203
- style="left: {leftOffsets[index]}px; {cellWrapStyle(cell)}"
204
- >
205
- <TableColumn
206
- {cell}
207
- {expandedColumnDef}
208
- {onExpandChange}
209
- />
210
- </div>
211
- {/each}
212
- {#each centreCells as cell (cell.column.id)}
213
- <div
214
- role="cell"
215
- class="cell"
216
- style={cellWrapStyle(cell)}
217
- >
218
- <TableColumn
219
- {cell}
220
- {expandedColumnDef}
221
- {onExpandChange}
222
- />
223
- </div>
224
- {/each}
225
- {#each rightCells as cell, index (cell.column.id)}
226
- <div
227
- role="cell"
228
- class="cell pinned-right"
229
- style="right: {rightOffsets[index]}px; {cellWrapStyle(cell)}"
230
- >
231
- <TableColumn
232
- {cell}
233
- {expandedColumnDef}
234
- {onExpandChange}
235
- />
236
- </div>
237
- {/each}
238
- </div>
239
-
240
- {#if expandedColumnDef}
241
- <div
242
- role="row"
243
- class="datatable-row expand-row"
244
- >
245
- <div
246
- role="cell"
247
- class="cell expand-cell"
248
- >
249
- {#await innerDataPromise}
250
- loading&hellip;
251
- {:then data}
252
- {#if data && data.length}
253
- {@const options = expandedColumnDef.innerTableOptions}
254
- {#if innerTableName}
255
- {#key innerTableName}
256
- <NestedTable
257
- tableName={innerTableName}
258
- {data}
259
- columnDefWrapper={innerColumnDefs}
260
- {options}
261
- getUserId={tableContext.getUserId}
262
- />
263
- {/key}
264
- {:else}
265
- <NestedTable
266
- tableName={fallbackInnerTableName}
267
- {data}
268
- columnDefWrapper={innerColumnDefs}
269
- {options}
270
- getUserId={tableContext.getUserId}
271
- />
272
- {/if}
273
- {:else if !data}
274
- Error Fetching data
275
- {:else}
276
- No Data
277
- {/if}
278
- {:catch e}
279
- {#if dev}
280
- error: {e}
281
- <!-- eslint-disable-next-line svelte/no-at-debug-tags -->
282
- {@debug e}
283
- {/if}
284
- Error Fetching data
285
- {/await}
286
- </div>
287
- </div>
288
- {/if}
289
-
1
+ <svelte:options runes />
2
+
3
+ <script
4
+ lang="ts"
5
+ generics="T extends object, RowIdType extends Primitive"
6
+ >
7
+ import type { ScoriaStorageKey } from '../../../../Types/Internal/Misc.js';
8
+ import { dev } from '$app/environment';
9
+ import { devCatch, generateWeakId } from '../../../../Helpers/Helpers.svelte.js';
10
+ import { getContext, untrack } from 'svelte';
11
+ import NestedTable from '../../NestedTable.svelte';
12
+ import type { ExpandDef } from '../../Types/Columns/Definitions/Expand/ExpandDef.svelte.js';
13
+ import type { DefsWrapper } from '../../Types/Columns/DefsWrapper.js';
14
+ import type { TableCell } from '../../Types/Columns/TableCell.js';
15
+ import { TableContext } from '../../Types/Context/TableContext.svelte.js';
16
+ import { type Primitive } from '../../Types/Context/TableInitOptions.js';
17
+ import ColumnHighlight from './ColumnHighlight.svelte';
18
+ import TableColumn from './Columns/TableColumn.svelte';
19
+ import type { TableRowProps } from './TableRowProps.js';
20
+
21
+ const tableContext = getContext<TableContext<T, RowIdType>>(TableContext.identifier);
22
+
23
+ const { row, odd = false, includeHighlight }: TableRowProps<T> = $props();
24
+
25
+ const hoverable = $derived(tableContext.changeColourOnHover);
26
+
27
+ // Visible cells in display order: left-pinned -> centre -> right-pinned.
28
+ // The browser now handles row-height alignment natively because all
29
+ // cells live in the same grid row, so the previous per-side fan-out
30
+ // and height-reconciliation pool is gone.
31
+ const leftCells: Array<TableCell<T>> = $derived(row.getLeftVisibleCells());
32
+ const centreCells: Array<TableCell<T>> = $derived(row.getCenterVisibleCells());
33
+ const rightCells: Array<TableCell<T>> = $derived(row.getRightVisibleCells());
34
+
35
+ // Cumulative pinning offsets for the sticky-positioned cells. Reads
36
+ // rendered widths from `_columnRenderedWidths` (populated by the
37
+ // ResizeObserver in TableHead) so the sticky positions stay
38
+ // accurate even though each pinned column track uses
39
+ // `minmax(W, 1fr)` and the actual width can exceed `columnDef.width`.
40
+ function renderedWidth(cell: TableCell<T>): number {
41
+ return tableContext._columnRenderedWidths.get(cell.column.id) ?? cell.column.columnDef.width;
42
+ }
43
+
44
+ const leftOffsets: Array<number> = $derived.by(() => {
45
+ void tableContext._columnRenderedWidths.size;
46
+ const offsets: Array<number> = [];
47
+ let cumulative = includeHighlight ? 20 : 0;
48
+ for (const cell of leftCells) {
49
+ offsets.push(cumulative);
50
+ cumulative += renderedWidth(cell);
51
+ }
52
+ return offsets;
53
+ });
54
+
55
+ const rightOffsets: Array<number> = $derived.by(() => {
56
+ void tableContext._columnRenderedWidths.size;
57
+ const offsets = new Array<number>(rightCells.length).fill(0);
58
+ let cumulative = 0;
59
+ for (let i = rightCells.length - 1; i >= 0; i--) {
60
+ offsets[i] = cumulative;
61
+ cumulative += renderedWidth(rightCells[i]);
62
+ }
63
+ return offsets;
64
+ });
65
+
66
+ let expandedColumnDef: ExpandDef<T, object> | undefined = $state();
67
+
68
+ $effect(() => {
69
+ if (leftCells.length + centreCells.length + rightCells.length > 0) {
70
+ void tableContext.table.data;
71
+ void tableContext.paginationRepo?.paginationState.pageIndex;
72
+ void tableContext.paginationRepo?.paginationState.pageSize;
73
+ untrack(() => {
74
+ expandedColumnDef = undefined;
75
+ });
76
+ }
77
+ });
78
+
79
+ let innerDataPromise: Array<object> | Promise<Array<object>> | undefined = $state();
80
+ let innerColumnDefs: DefsWrapper<object> = $state({ defs: [] });
81
+ let innerTableName: ScoriaStorageKey | undefined = $state();
82
+
83
+ let prevExpandedColumnDef: ExpandDef<T, object> | undefined = $state();
84
+
85
+ const firstCell = $derived(leftCells.at(0) ?? centreCells.at(0) ?? rightCells.at(0));
86
+ const rowIndex = $derived(firstCell?.row.visibleIndex);
87
+ let id = $state<RowIdType | undefined>();
88
+ const highlighted = $derived(id != undefined && tableContext.highlightedItems.has(id));
89
+
90
+ $effect(() => {
91
+ void row.original;
92
+ void tableContext.selectionExtractor;
93
+
94
+ if (rowIndex != undefined) {
95
+ const maybePromise = tableContext.selectionExtractor(row.original);
96
+ if (maybePromise instanceof Promise) {
97
+ maybePromise
98
+ .then((it) => {
99
+ id = it;
100
+ })
101
+ .catch(devCatch);
102
+ } else {
103
+ id = maybePromise;
104
+ }
105
+ } else {
106
+ id = undefined;
107
+ }
108
+ });
109
+
110
+ const showHighlightButton = $derived(rowIndex != null && includeHighlight);
111
+
112
+ $effect(() => {
113
+ void expandedColumnDef;
114
+
115
+ untrack(() => {
116
+ // Guard: if all columns have been hidden the cells arrays are
117
+ // empty; `firstCell` would otherwise be undefined.
118
+ if (!firstCell) {
119
+ return;
120
+ }
121
+ if (expandedColumnDef && expandedColumnDef.id != prevExpandedColumnDef?.id) {
122
+ prevExpandedColumnDef = expandedColumnDef;
123
+ innerColumnDefs = expandedColumnDef.getInnerColumnDefs(
124
+ firstCell.row.original,
125
+ firstCell.row.originalIndex
126
+ );
127
+
128
+ innerDataPromise = expandedColumnDef.accessorFn(
129
+ firstCell.row.original,
130
+ firstCell.row.originalIndex
131
+ ) as Promise<Array<object>>;
132
+ innerTableName = expandedColumnDef.innerTableName;
133
+ } else if (
134
+ !expandedColumnDef ||
135
+ tableContext.columnVisibility[expandedColumnDef.id] === false
136
+ ) {
137
+ innerTableName = undefined;
138
+ expandedColumnDef = prevExpandedColumnDef = innerDataPromise = undefined;
139
+ innerColumnDefs = { defs: [] };
140
+ }
141
+ });
142
+ });
143
+
144
+ function onExpandChange(columnDef: ExpandDef<T, object>) {
145
+ if (expandedColumnDef?.id === columnDef.id) {
146
+ expandedColumnDef = undefined;
147
+ } else {
148
+ expandedColumnDef = columnDef;
149
+ }
150
+ }
151
+
152
+ // Stable fallback name used when an ExpandDef does not supply its own
153
+ // `innerTableName`. Generating this once per row prevents localStorage
154
+ // preset keys from accumulating UUID-keyed garbage every expand toggle.
155
+ const fallbackInnerTableName = generateWeakId<ScoriaStorageKey>();
156
+
157
+ /**
158
+ * Inline style appended to a cell's `style="..."` when its column opts
159
+ * into `wrapValue`. The hooks switch the leaf cell's `white-space`,
160
+ * `overflow-x`, and `height` to wrap-friendly values. Implemented as
161
+ * CSS-variable overrides so the table-cell-basic mixin in
162
+ * `_mixins.scss` consumes them via `var(--cell-* , fallback)`.
163
+ */
164
+ function cellWrapStyle(cell: TableCell<T>): string {
165
+ return cell.column.columnDef.wrapValue
166
+ ? '--cell-white-space: normal; --cell-overflow-x: visible; --cell-height: auto; --cell-min-height: var(--height);'
167
+ : '';
168
+ }
169
+ </script>
170
+
171
+ <div
172
+ role="row"
173
+ class="datatable-row"
174
+ class:hoverable
175
+ class:alt={tableContext.alternateRowColours && odd}
176
+ class:highlighted
177
+ >
178
+ {#if showHighlightButton}
179
+ <div
180
+ role="cell"
181
+ class="cell highlight-cell pinned-left"
182
+ style="left: 0px"
183
+ >
184
+ <ColumnHighlight
185
+ rowIndex={rowIndex ??
186
+ (() => {
187
+ if (dev) {
188
+ console.error(`column had invalid row index: ${rowIndex}`);
189
+ }
190
+ return -1;
191
+ })()}
192
+ {highlighted}
193
+ toggleHighlightedRow={() => {
194
+ tableContext.toggleHighlightedRow(row.original)?.catch(devCatch);
195
+ }}
196
+ />
197
+ </div>
198
+ {/if}
199
+ {#each leftCells as cell, index (cell.column.id)}
200
+ <div
201
+ role="cell"
202
+ class="cell pinned-left"
203
+ style="left: {leftOffsets[index]}px; {cellWrapStyle(cell)}"
204
+ >
205
+ <TableColumn
206
+ {cell}
207
+ {expandedColumnDef}
208
+ {onExpandChange}
209
+ />
210
+ </div>
211
+ {/each}
212
+ {#each centreCells as cell (cell.column.id)}
213
+ <div
214
+ role="cell"
215
+ class="cell"
216
+ style={cellWrapStyle(cell)}
217
+ >
218
+ <TableColumn
219
+ {cell}
220
+ {expandedColumnDef}
221
+ {onExpandChange}
222
+ />
223
+ </div>
224
+ {/each}
225
+ {#each rightCells as cell, index (cell.column.id)}
226
+ <div
227
+ role="cell"
228
+ class="cell pinned-right"
229
+ style="right: {rightOffsets[index]}px; {cellWrapStyle(cell)}"
230
+ >
231
+ <TableColumn
232
+ {cell}
233
+ {expandedColumnDef}
234
+ {onExpandChange}
235
+ />
236
+ </div>
237
+ {/each}
238
+ </div>
239
+
240
+ {#if expandedColumnDef}
241
+ <div
242
+ role="row"
243
+ class="datatable-row expand-row"
244
+ >
245
+ <div
246
+ role="cell"
247
+ class="cell expand-cell"
248
+ >
249
+ {#await innerDataPromise}
250
+ loading&hellip;
251
+ {:then data}
252
+ {#if data && data.length}
253
+ {@const options = expandedColumnDef.innerTableOptions}
254
+ {#if innerTableName}
255
+ {#key innerTableName}
256
+ <NestedTable
257
+ tableName={innerTableName}
258
+ {data}
259
+ columnDefWrapper={innerColumnDefs}
260
+ {options}
261
+ getUserId={tableContext.getUserId}
262
+ />
263
+ {/key}
264
+ {:else}
265
+ <NestedTable
266
+ tableName={fallbackInnerTableName}
267
+ {data}
268
+ columnDefWrapper={innerColumnDefs}
269
+ {options}
270
+ getUserId={tableContext.getUserId}
271
+ />
272
+ {/if}
273
+ {:else if !data}
274
+ Error Fetching data
275
+ {:else}
276
+ No Data
277
+ {/if}
278
+ {:catch e}
279
+ {#if dev}
280
+ error: {e}
281
+ <!-- eslint-disable-next-line svelte/no-at-debug-tags -->
282
+ {@debug e}
283
+ {/if}
284
+ Error Fetching data
285
+ {/await}
286
+ </div>
287
+ </div>
288
+ {/if}
289
+
290
290
  <style>.datatable-row {
291
291
  display: grid;
292
292
  grid-template-columns: var(--cols);
@@ -351,4 +351,4 @@
351
351
  padding: 0;
352
352
  display: block;
353
353
  width: 100%;
354
- }</style>
354
+ }</style>