@lavalogic/scoria 0.40.13 → 0.40.15
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 +35 -46
- package/dist/Components/AccordionGroupButton.svelte +68 -76
- package/dist/Components/Action.svelte +103 -135
- package/dist/Components/AlertModal.svelte +171 -190
- package/dist/Components/AppointmentCalendar/AppointmentCalendar.svelte +614 -697
- package/dist/Components/Base/BaseModal.svelte +90 -116
- package/dist/Components/Base/ContextWrapper.svelte +67 -72
- package/dist/Components/Base/Pagination.svelte +173 -196
- package/dist/Components/Base/Snippets.svelte +34 -36
- package/dist/Components/BigRadioSet.svelte +36 -38
- package/dist/Components/Bubble.svelte +78 -101
- package/dist/Components/Button.svelte +175 -208
- package/dist/Components/Checkbox.svelte +75 -86
- package/dist/Components/CollapsibleCard.svelte +72 -87
- package/dist/Components/CollapsibleMenuGroup.svelte +53 -57
- package/dist/Components/ConditionBuilder/ConditionBuilder.svelte +39 -64
- package/dist/Components/Contexts/ContextMenu.svelte +141 -156
- package/dist/Components/Contexts/ContextMenuDivider.svelte +15 -15
- package/dist/Components/Contexts/ContextMenuOption.svelte +53 -60
- package/dist/Components/Contexts/Toast.svelte +81 -86
- package/dist/Components/Contexts/ToastContainer.svelte +58 -62
- package/dist/Components/Contexts/Tooltip.svelte +36 -37
- package/dist/Components/DataMatrixIcon.svelte +95 -108
- package/dist/Components/DateInput.svelte +118 -146
- package/dist/Components/DatePicker.svelte +255 -294
- package/dist/Components/DesktopModal.svelte +70 -90
- package/dist/Components/Dial.svelte +167 -197
- package/dist/Components/DimensionInput.svelte +124 -169
- package/dist/Components/DragMenu/DragMenuHolder.svelte +98 -114
- package/dist/Components/DragMenu/DraggableCard.svelte +64 -76
- package/dist/Components/FileCard.svelte +21 -24
- package/dist/Components/FileUpload.svelte +190 -225
- package/dist/Components/GridInput.svelte +159 -196
- package/dist/Components/GridInputSet.svelte +24 -29
- package/dist/Components/HorizontalTabGroup.svelte +73 -89
- package/dist/Components/HorizontalTabGroupButton.svelte +40 -44
- package/dist/Components/Icon.svelte +99 -128
- package/dist/Components/Icons.js +357 -357
- package/dist/Components/InfoAlert.svelte +35 -38
- package/dist/Components/LoadingAnimation.svelte +691 -755
- package/dist/Components/LoadingModal.svelte +36 -44
- package/dist/Components/LoadingOverlay.svelte +22 -26
- package/dist/Components/Modal.svelte +204 -254
- package/dist/Components/MultiSelect.svelte +186 -216
- package/dist/Components/Nav/Nav.svelte +94 -110
- package/dist/Components/Nav/NavServiceMenuList.svelte +57 -61
- package/dist/Components/Nav/NavTab.svelte +58 -62
- package/dist/Components/Nav/ServiceMenuItem.svelte +103 -111
- package/dist/Components/Nav/ServicesNav.svelte +72 -79
- package/dist/Components/NumberInput.svelte +121 -155
- package/dist/Components/OptionCards.svelte +62 -73
- package/dist/Components/PageHeading.svelte +23 -25
- package/dist/Components/PasswordInput.svelte +69 -88
- package/dist/Components/PopoverButton.svelte +151 -0
- package/dist/Components/PopoverButton.svelte.d.ts +9 -0
- package/dist/Components/PopoverButtonProps.d.ts +21 -0
- package/dist/Components/PopoverButtonProps.js +1 -0
- package/dist/Components/Portal.svelte +29 -35
- package/dist/Components/ProgressBubble.svelte +91 -106
- package/dist/Components/QuerySelect.svelte +260 -346
- package/dist/Components/SidebarPanel.svelte +34 -36
- package/dist/Components/SingleSelect.svelte +196 -244
- package/dist/Components/StepButton.svelte +65 -70
- package/dist/Components/StepForm.svelte +115 -135
- package/dist/Components/Switch.svelte +57 -69
- package/dist/Components/Table/ARCHITECTURE.md +298 -298
- package/dist/Components/Table/Body/QuickSearchCell.svelte +578 -655
- package/dist/Components/Table/Body/Rows/ColumnHighlight.svelte +42 -51
- package/dist/Components/Table/Body/Rows/ColumnList.svelte +42 -58
- package/dist/Components/Table/Body/Rows/ColumnListRow.svelte +403 -442
- package/dist/Components/Table/Body/Rows/Columns/AccessorComponent.svelte +51 -78
- package/dist/Components/Table/Body/Rows/Columns/ActionsCell.svelte +165 -184
- package/dist/Components/Table/Body/Rows/Columns/BubbleCell.svelte +110 -123
- package/dist/Components/Table/Body/Rows/Columns/ExpandCell.svelte +134 -160
- package/dist/Components/Table/Body/Rows/Columns/FocusableImmutableCell.svelte +190 -231
- package/dist/Components/Table/Body/Rows/Columns/ProgressCell.svelte +82 -104
- package/dist/Components/Table/Body/Rows/Columns/TableAction.svelte +52 -87
- package/dist/Components/Table/Body/Rows/Columns/TableCheckbox.svelte +122 -150
- package/dist/Components/Table/Body/Rows/Columns/TableColumn.svelte +132 -159
- package/dist/Components/Table/Body/Rows/Columns/TableDatePicker.svelte +190 -236
- package/dist/Components/Table/Body/Rows/Columns/TableNumberInput.svelte +173 -211
- package/dist/Components/Table/Body/Rows/Columns/TableQuerySelect.svelte +204 -244
- package/dist/Components/Table/Body/Rows/Columns/TableRowSelectionCheckbox.svelte +140 -177
- package/dist/Components/Table/Body/Rows/Columns/TableSelect.svelte +188 -217
- package/dist/Components/Table/Body/Rows/Columns/TableTextInput.svelte +173 -193
- package/dist/Components/Table/Body/Rows/Columns/ValidityCell.svelte +166 -187
- package/dist/Components/Table/Body/Rows/TableRow.svelte +245 -288
- package/dist/Components/Table/Body/TableBody.svelte +141 -154
- package/dist/Components/Table/Headers/HighlightAllHeader.svelte +35 -41
- package/dist/Components/Table/Headers/SelectAllHeader.svelte +24 -30
- package/dist/Components/Table/Headers/TableHead.svelte +348 -402
- package/dist/Components/Table/Misc/ColumnPanel.svelte +37 -39
- package/dist/Components/Table/Misc/ColumnPanelModal.svelte +35 -39
- package/dist/Components/Table/Misc/FilterInput.svelte +556 -619
- package/dist/Components/Table/Misc/FilterPanel.svelte +170 -183
- package/dist/Components/Table/Misc/FilterPanelModal.svelte +25 -31
- package/dist/Components/Table/Misc/ShareViewModal.svelte +252 -281
- package/dist/Components/Table/Misc/SidePanel.svelte +32 -35
- package/dist/Components/Table/Misc/TableConfigurationModal.svelte +574 -629
- package/dist/Components/Table/Misc/TableFooter.svelte +326 -332
- package/dist/Components/Table/Misc/TableHorizontalBar.svelte +134 -140
- package/dist/Components/Table/Misc/TableSidebar.svelte +183 -198
- package/dist/Components/Table/Misc/TableViewDropdown.svelte +83 -103
- package/dist/Components/Table/Misc/ToolboxPanel.svelte +83 -100
- package/dist/Components/Table/Misc/ToolboxPanelModal.svelte +88 -107
- package/dist/Components/Table/Misc/UpdateViewOptionsModal.svelte +163 -190
- package/dist/Components/Table/NestedTable.svelte +102 -128
- package/dist/Components/Table/Table.svelte +531 -663
- package/dist/Components/Test/TestContextConsumer.svelte +11 -13
- package/dist/Components/TextArea.svelte +95 -130
- package/dist/Components/TextInput.svelte +125 -176
- package/dist/Components/ThreeStateRadio.svelte +111 -130
- package/dist/Components/Touch/BoolCard.svelte +33 -45
- package/dist/Components/Touch/DateModal.svelte +164 -204
- package/dist/Components/Touch/EditCard.svelte +48 -59
- package/dist/Components/Touch/InfoCard.svelte +28 -31
- package/dist/Components/Touch/InfoTextCard.svelte +26 -28
- package/dist/Components/Touch/ModalExplanation.svelte +15 -17
- package/dist/Components/Touch/NumberKeyboard.svelte +181 -218
- package/dist/Components/Touch/NumberModal.svelte +59 -79
- package/dist/Components/Touch/PlusMinusCard.svelte +43 -46
- package/dist/Components/Touch/SelectModal.svelte +111 -126
- package/dist/Components/Touch/SummaryCard.svelte +80 -93
- package/dist/Components/Touch/TextAreaModal.svelte +72 -94
- package/dist/Components/Touch/TextModal.svelte +77 -105
- package/dist/Components/Touch/TouchCard.svelte +31 -33
- package/dist/Components/Touch/TouchModal.svelte +214 -270
- package/dist/Components/Touch/UtilityButton.svelte +88 -109
- package/dist/Components/VerticalTabGroup.svelte +60 -78
- package/dist/Components/VerticalTabGroupButton.svelte +54 -58
- package/dist/Helpers/Datamatrix.d.ts +19 -19
- package/dist/Helpers/Datamatrix.js +291 -291
- package/dist/Types/Examples/ExampleModal.svelte +31 -35
- package/dist/index.d.ts +2 -0
- package/dist/index.js +1 -0
- 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,194 +1,167 @@
|
|
|
1
|
-
<svelte:options runes />
|
|
2
|
-
|
|
3
|
-
<script
|
|
4
|
-
lang="ts"
|
|
5
|
-
generics="T extends object, IdType extends Primitive"
|
|
6
|
-
>
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
label: 'Public — anyone with access to this table can subscribe',
|
|
53
|
-
value: 'public',
|
|
54
|
-
},
|
|
55
|
-
];
|
|
56
|
-
|
|
57
|
-
const selectedVisibility: SelectOption<DatatableViewVisibility> = $derived(
|
|
58
|
-
visibilityOptions.find((o) => o.value === visibility) ?? visibilityOptions[0]
|
|
59
|
-
);
|
|
60
|
-
|
|
61
|
-
// Whether anything in the form differs from the initial values.
|
|
62
|
-
// Drives the Save button's disabled state so a no-op Save never
|
|
63
|
-
// hits the network (also enforced inside `updateViewOptions`).
|
|
64
|
-
const dirty = $derived(
|
|
65
|
-
name.trim() !== view.name || visibility !== (view.visibility ?? 'private')
|
|
66
|
-
);
|
|
67
|
-
|
|
68
|
-
/** Whether the name is valid for submission (non-empty, trimmed). */
|
|
69
|
-
const isValidName = $derived(name.trim().length > 0);
|
|
70
|
-
|
|
71
|
-
async function save(): Promise<void> {
|
|
72
|
-
if (!dirty) {
|
|
73
|
-
onclose();
|
|
74
|
-
return;
|
|
75
|
-
}
|
|
76
|
-
if (!isValidName) {
|
|
77
|
-
errorMessage = `Name cannot be empty.`;
|
|
78
|
-
return;
|
|
79
|
-
}
|
|
80
|
-
|
|
81
|
-
errorMessage = null;
|
|
82
|
-
saving = true;
|
|
83
|
-
try {
|
|
84
|
-
await tableContext.updateViewOptions(view, {
|
|
85
|
-
name: name.trim(),
|
|
86
|
-
visibility,
|
|
87
|
-
});
|
|
88
|
-
if (onsaved) {
|
|
89
|
-
await onsaved();
|
|
90
|
-
}
|
|
91
|
-
onclose();
|
|
92
|
-
} catch (e: unknown) {
|
|
93
|
-
console.error('[UpdateViewOptionsModal] save failed:', e);
|
|
94
|
-
errorMessage =
|
|
95
|
-
e instanceof Error
|
|
96
|
-
? `Could not update options. (${e.message})`
|
|
97
|
-
: 'Could not update options.';
|
|
98
|
-
} finally {
|
|
99
|
-
saving = false;
|
|
100
|
-
}
|
|
1
|
+
<svelte:options runes />
|
|
2
|
+
|
|
3
|
+
<script
|
|
4
|
+
lang="ts"
|
|
5
|
+
generics="T extends object, IdType extends Primitive"
|
|
6
|
+
>import DesktopModal from "../../DesktopModal.svelte";
|
|
7
|
+
import Icon from "../../Icon.svelte";
|
|
8
|
+
import InfoAlert from "../../InfoAlert.svelte";
|
|
9
|
+
import SingleSelect from "../../SingleSelect.svelte";
|
|
10
|
+
import TextInput from "../../TextInput.svelte";
|
|
11
|
+
import { cssLength } from "../../../Helpers/Helpers.svelte.js";
|
|
12
|
+
import { ColourSet } from "../../../scss/colours.js";
|
|
13
|
+
import { Size } from "../../../Types/Internal/Size.js";
|
|
14
|
+
import { getContext, onMount } from "svelte";
|
|
15
|
+
import { TableContext } from "../Types/Context/TableContext.svelte.js";
|
|
16
|
+
const { view, onclose, onsaved } = $props();
|
|
17
|
+
const tableContext = getContext(TableContext.identifier);
|
|
18
|
+
// Local form state. Seeded from the view's current values inside
|
|
19
|
+
// `onMount` so the modal opens populated with what's already saved
|
|
20
|
+
// without triggering Svelte's `state_referenced_locally` lint
|
|
21
|
+
// against the prop read; Save diffs against the view's current
|
|
22
|
+
// values to skip a no-op PATCH.
|
|
23
|
+
let name = $state("");
|
|
24
|
+
let visibility = $state("private");
|
|
25
|
+
onMount(() => {
|
|
26
|
+
name = view.name;
|
|
27
|
+
visibility = view.visibility ?? "private";
|
|
28
|
+
});
|
|
29
|
+
// User-visible error banner. Adapter rejections are routed here so
|
|
30
|
+
// the modal never throws into the host UI.
|
|
31
|
+
let errorMessage = $state(null);
|
|
32
|
+
// `true` while the PATCH is in flight, disables the footer buttons.
|
|
33
|
+
let saving = $state(false);
|
|
34
|
+
const visibilityOptions = [{
|
|
35
|
+
label: "Private — only owner and explicit subscribers",
|
|
36
|
+
value: "private"
|
|
37
|
+
}, {
|
|
38
|
+
label: "Public — anyone with access to this table can subscribe",
|
|
39
|
+
value: "public"
|
|
40
|
+
}];
|
|
41
|
+
const selectedVisibility = $derived(visibilityOptions.find((o) => o.value === visibility) ?? visibilityOptions[0]);
|
|
42
|
+
// Whether anything in the form differs from the initial values.
|
|
43
|
+
// Drives the Save button's disabled state so a no-op Save never
|
|
44
|
+
// hits the network (also enforced inside `updateViewOptions`).
|
|
45
|
+
const dirty = $derived(name.trim() !== view.name || visibility !== (view.visibility ?? "private"));
|
|
46
|
+
/** Whether the name is valid for submission (non-empty, trimmed). */
|
|
47
|
+
const isValidName = $derived(name.trim().length > 0);
|
|
48
|
+
async function save() {
|
|
49
|
+
if (!dirty) {
|
|
50
|
+
onclose();
|
|
51
|
+
return;
|
|
101
52
|
}
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
53
|
+
if (!isValidName) {
|
|
54
|
+
errorMessage = `Name cannot be empty.`;
|
|
55
|
+
return;
|
|
56
|
+
}
|
|
57
|
+
errorMessage = null;
|
|
58
|
+
saving = true;
|
|
59
|
+
try {
|
|
60
|
+
await tableContext.updateViewOptions(view, {
|
|
61
|
+
name: name.trim(),
|
|
62
|
+
visibility
|
|
63
|
+
});
|
|
64
|
+
if (onsaved) {
|
|
65
|
+
await onsaved();
|
|
110
66
|
}
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
67
|
+
onclose();
|
|
68
|
+
} catch (e) {
|
|
69
|
+
console.error("[UpdateViewOptionsModal] save failed:", e);
|
|
70
|
+
errorMessage = e instanceof Error ? `Could not update options. (${e.message})` : "Could not update options.";
|
|
71
|
+
} finally {
|
|
72
|
+
saving = false;
|
|
73
|
+
}
|
|
74
|
+
}
|
|
75
|
+
</script>
|
|
76
|
+
|
|
77
|
+
<DesktopModal
|
|
78
|
+
headerLabel={`Update Options - "${view.name}"`}
|
|
79
|
+
headerSubtitle={`Rename and change sharing for this ${view.kind === 'filter' ? 'filter' : 'layout'}.`}
|
|
80
|
+
onclose={() => {
|
|
81
|
+
if (!saving) {
|
|
82
|
+
onclose();
|
|
83
|
+
}
|
|
84
|
+
}}
|
|
85
|
+
width={cssLength('40vw')}
|
|
86
|
+
minWidth={cssLength('32rem')}
|
|
87
|
+
buttons={[
|
|
88
|
+
{
|
|
89
|
+
label: 'Cancel',
|
|
90
|
+
callback: () => {
|
|
91
|
+
if (!saving) {
|
|
92
|
+
onclose();
|
|
93
|
+
}
|
|
94
|
+
},
|
|
95
|
+
disabled: saving,
|
|
96
|
+
},
|
|
97
|
+
{
|
|
98
|
+
label: saving ? 'Saving…' : 'Save',
|
|
99
|
+
callback: () => {
|
|
100
|
+
void save();
|
|
101
|
+
},
|
|
102
|
+
colourSet: ColourSet.Primary,
|
|
103
|
+
disabled: saving || !dirty || !isValidName,
|
|
104
|
+
},
|
|
105
|
+
]}
|
|
106
|
+
>
|
|
107
|
+
<div class="options-body">
|
|
108
|
+
{#if errorMessage}
|
|
109
|
+
<div
|
|
110
|
+
class="error-banner"
|
|
111
|
+
role="alert"
|
|
112
|
+
>
|
|
113
|
+
<Icon
|
|
114
|
+
name="circle-exclamation"
|
|
115
|
+
size={Size.Small}
|
|
116
|
+
/>
|
|
117
|
+
<span>{errorMessage}</span>
|
|
118
|
+
</div>
|
|
119
|
+
{/if}
|
|
120
|
+
|
|
121
|
+
<InfoAlert>
|
|
122
|
+
Changes apply to every user who has access to this {view.kind === 'filter'
|
|
123
|
+
? 'filter'
|
|
124
|
+
: 'layout'}. Making it public allows any user with access to the table to subscribe.
|
|
125
|
+
</InfoAlert>
|
|
126
|
+
|
|
127
|
+
<div class="field">
|
|
128
|
+
<label
|
|
129
|
+
class="field-label"
|
|
130
|
+
for="update-view-name">Name</label
|
|
131
|
+
>
|
|
132
|
+
<TextInput
|
|
133
|
+
id="update-view-name"
|
|
134
|
+
bind:value={name}
|
|
135
|
+
placeholder={`${view.kind === 'filter' ? 'Filter' : 'Layout'} name`}
|
|
136
|
+
required
|
|
137
|
+
invalid={!isValidName}
|
|
138
|
+
/>
|
|
139
|
+
</div>
|
|
140
|
+
|
|
141
|
+
<div class="field">
|
|
142
|
+
<label
|
|
143
|
+
class="field-label"
|
|
144
|
+
for="update-view-visibility">Visibility</label
|
|
145
|
+
>
|
|
146
|
+
<SingleSelect
|
|
147
|
+
inputId="update-view-visibility"
|
|
148
|
+
name="Visibility"
|
|
149
|
+
options={visibilityOptions}
|
|
150
|
+
labelProp="label"
|
|
151
|
+
valueProp="value"
|
|
152
|
+
value={selectedVisibility}
|
|
153
|
+
valueAsObject
|
|
154
|
+
searchable={false}
|
|
155
|
+
onchange={(option: SelectOption<DatatableViewVisibility> | null) => {
|
|
156
|
+
if (option) {
|
|
157
|
+
visibility = option.value;
|
|
158
|
+
}
|
|
159
|
+
}}
|
|
160
|
+
/>
|
|
161
|
+
</div>
|
|
162
|
+
</div>
|
|
163
|
+
</DesktopModal>
|
|
164
|
+
|
|
192
165
|
<style>.options-body {
|
|
193
166
|
display: flex;
|
|
194
167
|
flex-flow: column nowrap;
|
|
@@ -222,4 +195,4 @@
|
|
|
222
195
|
font-size: 1.125rem;
|
|
223
196
|
font-weight: 600;
|
|
224
197
|
color: #3a4952;
|
|
225
|
-
}</style>
|
|
198
|
+
}</style>
|
|
@@ -1,132 +1,106 @@
|
|
|
1
|
-
<svelte:options runes />
|
|
2
|
-
|
|
3
|
-
<script
|
|
4
|
-
lang="ts"
|
|
5
|
-
module
|
|
6
|
-
>
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
const
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
let root: HTMLDivElement | undefined = $state();
|
|
66
|
-
|
|
67
|
-
// Track the parent `.datatable`'s visible width (clientWidth) via
|
|
68
|
-
// ResizeObserver. `.datatable` is the horizontal scroll container, so
|
|
69
|
-
// its `clientWidth` is the visible viewport regardless of how wide the
|
|
70
|
-
// inner `.datatable-grid` has grown via `min-width: max-content`. Do
|
|
71
|
-
// NOT measure `.flex_table` instead - flex `min-width: auto`
|
|
72
|
-
// propagates the scroll-content width and sizes the nested table to
|
|
73
|
-
// the full grid, breaking the sticky-fit behaviour.
|
|
74
|
-
//
|
|
75
|
-
// Reading layout inside a derivation would force a synchronous reflow
|
|
76
|
-
// on every reactive re-run; the ResizeObserver path keeps it out of
|
|
77
|
-
// the reactive graph.
|
|
78
|
-
let maxWidth: number | undefined = $state();
|
|
79
|
-
$effect(() => {
|
|
80
|
-
if (!root) {
|
|
81
|
-
return;
|
|
82
|
-
}
|
|
83
|
-
const scrollHost = root.closest('.datatable');
|
|
84
|
-
if (!(scrollHost instanceof HTMLElement)) {
|
|
85
|
-
return;
|
|
86
|
-
}
|
|
1
|
+
<svelte:options runes />
|
|
2
|
+
|
|
3
|
+
<script
|
|
4
|
+
lang="ts"
|
|
5
|
+
module
|
|
6
|
+
>import Table from "./Table.svelte";
|
|
7
|
+
import { TableContext } from "./Types/Context/TableContext.svelte.js";
|
|
8
|
+
import { LocalTableDataRepository } from "./Types/DataRepository/LocalTableDataRepository.svelte.js";
|
|
9
|
+
import { ToolbarPosition } from "./Types/Toolbar/ToolbarPosition.js";
|
|
10
|
+
/**
|
|
11
|
+
* Default `TableInitOptions` overrides applied to every nested table.
|
|
12
|
+
* Tuned for read-only inline display: copy, resize and column
|
|
13
|
+
* reordering are turned off, quick / advanced filtering remain on so
|
|
14
|
+
* the consumer can still narrow rows, the toolbar is hidden, and the
|
|
15
|
+
* footer is suppressed because pagination is rarely useful for inline
|
|
16
|
+
* nested data.
|
|
17
|
+
*
|
|
18
|
+
* Frozen so consumers cannot accidentally mutate the shared default
|
|
19
|
+
* object.
|
|
20
|
+
*/
|
|
21
|
+
const DEFAULT_NESTED_TABLE_OPTIONS = Object.freeze({
|
|
22
|
+
allowCopy: false,
|
|
23
|
+
enableResize: false,
|
|
24
|
+
allowColumnReordering: true,
|
|
25
|
+
allowQuickFiltering: true,
|
|
26
|
+
allowAdvancedFiltering: true,
|
|
27
|
+
toolbar: ToolbarPosition.None,
|
|
28
|
+
displayFooter: false
|
|
29
|
+
});
|
|
30
|
+
</script>
|
|
31
|
+
|
|
32
|
+
<script
|
|
33
|
+
lang="ts"
|
|
34
|
+
generics="T extends object,IdType extends Primitive"
|
|
35
|
+
>const { tableName, data, columnDefWrapper, options, oncontextmenu, getUserId } = $props();
|
|
36
|
+
// Reactive wrapper exposing the `data` prop as `.value` so the
|
|
37
|
+
// underlying LocalTableDataRepository can read it through its
|
|
38
|
+
// RefWrapper contract without us materialising a copy.
|
|
39
|
+
const wrapper = { get value() {
|
|
40
|
+
return data;
|
|
41
|
+
} };
|
|
42
|
+
let root = $state();
|
|
43
|
+
// Track the parent `.datatable`'s visible width (clientWidth) via
|
|
44
|
+
// ResizeObserver. `.datatable` is the horizontal scroll container, so
|
|
45
|
+
// its `clientWidth` is the visible viewport regardless of how wide the
|
|
46
|
+
// inner `.datatable-grid` has grown via `min-width: max-content`. Do
|
|
47
|
+
// NOT measure `.flex_table` instead - flex `min-width: auto`
|
|
48
|
+
// propagates the scroll-content width and sizes the nested table to
|
|
49
|
+
// the full grid, breaking the sticky-fit behaviour.
|
|
50
|
+
//
|
|
51
|
+
// Reading layout inside a derivation would force a synchronous reflow
|
|
52
|
+
// on every reactive re-run; the ResizeObserver path keeps it out of
|
|
53
|
+
// the reactive graph.
|
|
54
|
+
let maxWidth = $state();
|
|
55
|
+
$effect(() => {
|
|
56
|
+
if (!root) {
|
|
57
|
+
return;
|
|
58
|
+
}
|
|
59
|
+
const scrollHost = root.closest(".datatable");
|
|
60
|
+
if (!(scrollHost instanceof HTMLElement)) {
|
|
61
|
+
return;
|
|
62
|
+
}
|
|
63
|
+
maxWidth = scrollHost.clientWidth;
|
|
64
|
+
const ro = new ResizeObserver(() => {
|
|
87
65
|
maxWidth = scrollHost.clientWidth;
|
|
88
|
-
const ro = new ResizeObserver(() => {
|
|
89
|
-
maxWidth = scrollHost.clientWidth;
|
|
90
|
-
});
|
|
91
|
-
ro.observe(scrollHost);
|
|
92
|
-
return () => {
|
|
93
|
-
ro.disconnect();
|
|
94
|
-
};
|
|
95
66
|
});
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
67
|
+
ro.observe(scrollHost);
|
|
68
|
+
return () => {
|
|
69
|
+
ro.disconnect();
|
|
70
|
+
};
|
|
71
|
+
});
|
|
72
|
+
// These class instances have `$state`-backed internal fields, so they
|
|
73
|
+
// must NOT be wrapped in `$state(...)` (that would add a redundant
|
|
74
|
+
// reactive layer). The `dataRepo` and `tableContext` references must
|
|
75
|
+
// stay stable across updates: a fresh `dataRepo` would clear
|
|
76
|
+
// filter/sort state, and a fresh `tableContext` would tear down focus.
|
|
77
|
+
//
|
|
78
|
+
// svelte-ignore state_referenced_locally
|
|
79
|
+
const dataRepo = new LocalTableDataRepository(tableName, wrapper, () => getUserId());
|
|
80
|
+
// svelte-ignore state_referenced_locally
|
|
81
|
+
const tableContext = TableContext.init(columnDefWrapper, tableName, dataRepo, {
|
|
82
|
+
...DEFAULT_NESTED_TABLE_OPTIONS,
|
|
83
|
+
...options,
|
|
84
|
+
getUserId: () => getUserId()
|
|
85
|
+
});
|
|
86
|
+
</script>
|
|
87
|
+
|
|
88
|
+
<!-- svelte-ignore a11y_no_static_element_interactions -->
|
|
89
|
+
<div
|
|
90
|
+
class="limit-height"
|
|
91
|
+
bind:this={root}
|
|
92
|
+
style:width={maxWidth != null ? `${maxWidth}px` : null}
|
|
93
|
+
oncontextmenu={(e) => {
|
|
94
|
+
e.stopPropagation();
|
|
95
|
+
oncontextmenu?.(e);
|
|
96
|
+
}}
|
|
97
|
+
>
|
|
98
|
+
<Table
|
|
99
|
+
nested
|
|
100
|
+
{tableContext}
|
|
101
|
+
/>
|
|
102
|
+
</div>
|
|
103
|
+
|
|
130
104
|
<style>.limit-height {
|
|
131
105
|
position: sticky;
|
|
132
106
|
left: 0;
|
|
@@ -135,4 +109,4 @@
|
|
|
135
109
|
box-sizing: border-box;
|
|
136
110
|
background-color: #f4f7f9;
|
|
137
111
|
box-shadow: inset 0px 7px 5px -6px #cbd4da, inset 0px -7px 5px -6px #cbd4da;
|
|
138
|
-
}</style>
|
|
112
|
+
}</style>
|