@lavalogic/scoria 0.40.1 → 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.
- package/README.md +58 -58
- package/dist/Components/AccordionGroup.svelte +46 -46
- package/dist/Components/AccordionGroupButton.svelte +76 -76
- package/dist/Components/Action.svelte +136 -136
- package/dist/Components/AlertModal.svelte +195 -195
- package/dist/Components/AppointmentCalendar/AppointmentCalendar.svelte +729 -729
- package/dist/Components/Base/BaseModal.svelte +125 -125
- package/dist/Components/Base/ContextWrapper.svelte +72 -72
- package/dist/Components/Base/Pagination.svelte +198 -198
- package/dist/Components/Base/Snippets.svelte +36 -36
- package/dist/Components/BigRadioSet.svelte +38 -38
- package/dist/Components/Bubble.svelte +101 -101
- package/dist/Components/Button.svelte +209 -209
- package/dist/Components/Checkbox.svelte +86 -86
- package/dist/Components/CollapsibleCard.svelte +78 -78
- package/dist/Components/Contexts/ContextMenu.svelte +164 -164
- package/dist/Components/Contexts/ContextMenuDivider.svelte +15 -15
- package/dist/Components/Contexts/ContextMenuOption.svelte +60 -60
- package/dist/Components/Contexts/Toast.svelte +86 -86
- package/dist/Components/Contexts/ToastContainer.svelte +65 -65
- package/dist/Components/Contexts/Tooltip.svelte +37 -37
- package/dist/Components/DataMatrixIcon.svelte +112 -112
- package/dist/Components/DateInput.svelte +148 -148
- package/dist/Components/DatePicker.svelte +300 -300
- package/dist/Components/DesktopModal.svelte +90 -90
- package/dist/Components/Dial.svelte +204 -204
- package/dist/Components/DimensionInput.svelte +170 -170
- package/dist/Components/DragMenu/DragMenuHolder.svelte +119 -119
- package/dist/Components/DragMenu/DraggableCard.svelte +77 -77
- package/dist/Components/FileCard.svelte +24 -24
- package/dist/Components/FileUpload.svelte +236 -236
- package/dist/Components/GridInput.svelte +196 -196
- package/dist/Components/GridInputSet.svelte +29 -29
- package/dist/Components/HorizontalTabGroup.svelte +82 -82
- package/dist/Components/HorizontalTabGroupButton.svelte +44 -44
- package/dist/Components/Icon.svelte +128 -128
- package/dist/Components/Icons.js +357 -357
- package/dist/Components/InfoAlert.svelte +35 -35
- package/dist/Components/LoadingAnimation.svelte +29 -29
- package/dist/Components/LoadingModal.svelte +45 -45
- package/dist/Components/LoadingOverlay.svelte +25 -25
- package/dist/Components/Modal.svelte +258 -258
- package/dist/Components/MultiSelect.svelte +220 -220
- package/dist/Components/Nav/Nav.svelte +110 -110
- package/dist/Components/Nav/NavServiceMenuList.svelte +43 -43
- package/dist/Components/Nav/NavTab.svelte +62 -62
- package/dist/Components/Nav/ServiceMenuItem.svelte +112 -112
- package/dist/Components/Nav/ServicesNav.svelte +80 -80
- package/dist/Components/NumberInput.svelte +157 -157
- package/dist/Components/PageHeading.svelte +25 -25
- package/dist/Components/PasswordInput.svelte +88 -88
- package/dist/Components/Portal.svelte +36 -36
- package/dist/Components/ProgressBubble.svelte +107 -107
- package/dist/Components/QuerySelect.svelte +366 -366
- package/dist/Components/SingleSelect.svelte +250 -250
- package/dist/Components/StepButton.svelte +70 -70
- package/dist/Components/StepForm.svelte +140 -140
- package/dist/Components/Switch.svelte +69 -69
- package/dist/Components/Table/ARCHITECTURE.md +298 -298
- package/dist/Components/Table/Body/QuickSearchCell.svelte +679 -679
- package/dist/Components/Table/Body/Rows/ColumnHighlight.svelte +51 -51
- package/dist/Components/Table/Body/Rows/ColumnList.svelte +59 -59
- package/dist/Components/Table/Body/Rows/ColumnListRow.svelte +454 -454
- package/dist/Components/Table/Body/Rows/Columns/AccessorComponent.svelte +79 -79
- package/dist/Components/Table/Body/Rows/Columns/ActionsCell.svelte +185 -185
- package/dist/Components/Table/Body/Rows/Columns/BubbleCell.svelte +124 -124
- package/dist/Components/Table/Body/Rows/Columns/ExpandCell.svelte +131 -120
- package/dist/Components/Table/Body/Rows/Columns/FocusableImmutableCell.svelte +234 -234
- package/dist/Components/Table/Body/Rows/Columns/ProgressCell.svelte +105 -105
- package/dist/Components/Table/Body/Rows/Columns/TableAction.svelte +87 -87
- package/dist/Components/Table/Body/Rows/Columns/TableCheckbox.svelte +126 -126
- package/dist/Components/Table/Body/Rows/Columns/TableColumn.svelte +159 -159
- package/dist/Components/Table/Body/Rows/Columns/TableDatePicker.svelte +246 -246
- package/dist/Components/Table/Body/Rows/Columns/TableNumberInput.svelte +216 -216
- package/dist/Components/Table/Body/Rows/Columns/TableQuerySelect.svelte +252 -252
- package/dist/Components/Table/Body/Rows/Columns/TableRowSelectionCheckbox.svelte +179 -179
- package/dist/Components/Table/Body/Rows/Columns/TableSelect.svelte +221 -221
- package/dist/Components/Table/Body/Rows/Columns/TableTextInput.svelte +197 -197
- package/dist/Components/Table/Body/Rows/Columns/ValidityCell.svelte +190 -190
- package/dist/Components/Table/Body/Rows/TableRow.svelte +290 -290
- package/dist/Components/Table/Body/TableBody.svelte +155 -155
- package/dist/Components/Table/ColumnFactory.svelte.js +1 -0
- package/dist/Components/Table/Headers/HighlightAllHeader.svelte +41 -41
- package/dist/Components/Table/Headers/SelectAllHeader.svelte +30 -30
- package/dist/Components/Table/Headers/TableHead.svelte +415 -415
- package/dist/Components/Table/Misc/ColumnPanel.svelte +39 -39
- package/dist/Components/Table/Misc/ColumnPanelModal.svelte +39 -39
- package/dist/Components/Table/Misc/FilterInput.svelte +641 -641
- package/dist/Components/Table/Misc/FilterPanel.svelte +190 -190
- package/dist/Components/Table/Misc/FilterPanelModal.svelte +31 -31
- package/dist/Components/Table/Misc/ShareViewModal.svelte +291 -291
- package/dist/Components/Table/Misc/SidePanel.svelte +35 -35
- package/dist/Components/Table/Misc/TableConfigurationModal.svelte +644 -644
- package/dist/Components/Table/Misc/TableFooter.svelte +340 -340
- package/dist/Components/Table/Misc/TableHorizontalBar.svelte +140 -140
- package/dist/Components/Table/Misc/TableSidebar.svelte +200 -200
- package/dist/Components/Table/Misc/TableViewDropdown.svelte +105 -105
- package/dist/Components/Table/Misc/ToolboxPanel.svelte +100 -100
- package/dist/Components/Table/Misc/ToolboxPanelModal.svelte +107 -107
- package/dist/Components/Table/Misc/UpdateViewOptionsModal.svelte +192 -192
- package/dist/Components/Table/NestedTable.svelte +130 -130
- package/dist/Components/Table/Table.svelte +692 -692
- package/dist/Components/Table/Types/Columns/Definitions/Expand/ExpandDef.svelte.d.ts +5 -0
- package/dist/Components/Table/Types/Columns/Definitions/Expand/ExpandDef.svelte.js +3 -0
- package/dist/Components/Table/Types/Public/ColumnOptions.d.ts +10 -0
- package/dist/Components/Test/TestContextConsumer.svelte +13 -13
- package/dist/Components/TextArea.svelte +130 -130
- package/dist/Components/TextInput.svelte +176 -176
- package/dist/Components/ThreeStateRadio.svelte +131 -131
- package/dist/Components/Touch/BoolCard.svelte +45 -45
- package/dist/Components/Touch/DateModal.svelte +209 -209
- package/dist/Components/Touch/EditCard.svelte +59 -59
- package/dist/Components/Touch/InfoCard.svelte +31 -31
- package/dist/Components/Touch/InfoTextCard.svelte +28 -28
- package/dist/Components/Touch/ModalExplanation.svelte +17 -17
- package/dist/Components/Touch/NumberKeyboard.svelte +225 -225
- package/dist/Components/Touch/NumberModal.svelte +79 -79
- package/dist/Components/Touch/PlusMinusCard.svelte +46 -46
- package/dist/Components/Touch/SelectModal.svelte +127 -127
- package/dist/Components/Touch/SummaryCard.svelte +93 -93
- package/dist/Components/Touch/TextAreaModal.svelte +95 -95
- package/dist/Components/Touch/TextModal.svelte +106 -106
- package/dist/Components/Touch/TouchCard.svelte +33 -33
- package/dist/Components/Touch/TouchModal.svelte +274 -274
- package/dist/Components/Touch/UtilityButton.svelte +109 -109
- package/dist/Components/VerticalTabGroup.svelte +79 -79
- package/dist/Components/VerticalTabGroupButton.svelte +58 -58
- package/dist/Helpers/Datamatrix.d.ts +19 -19
- package/dist/Helpers/Datamatrix.js +291 -291
- package/dist/Types/Examples/ExampleModal.svelte +35 -35
- package/dist/scss/_basics.scss +12 -12
- package/dist/scss/_colours.scss +134 -134
- package/dist/scss/_mixins.scss +3392 -3392
- package/dist/scss/_motion.scss +57 -57
- package/dist/scss/_sizing.scss +85 -85
- package/dist/scss/_transitions.scss +8 -8
- 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…
|
|
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…
|
|
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>
|