@lavalogic/scoria 0.37.55 → 0.38.0
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/dist/Components/Table/ARCHITECTURE.md +22 -22
- package/dist/Components/Table/Misc/ColumnPanel.svelte +1 -61
- package/dist/Components/Table/Misc/ColumnPanel.svelte.d.ts +2 -24
- package/dist/Components/Table/Misc/ColumnPanelModal.svelte +3 -92
- package/dist/Components/Table/Misc/ColumnPanelModal.svelte.d.ts +2 -24
- package/dist/Components/Table/Misc/ColumnPanelModalProps.d.ts +2 -2
- package/dist/Components/Table/Misc/TableConfigurationModal.svelte +644 -0
- package/dist/Components/Table/Misc/TableConfigurationModal.svelte.d.ts +26 -0
- package/dist/Components/Table/Misc/TableConfigurationModalProps.d.ts +13 -0
- package/dist/Components/Table/Misc/TableHorizontalBar.svelte +27 -0
- package/dist/Components/Table/Misc/TableSidebar.svelte +45 -2
- package/dist/Components/Table/Misc/TableViewDropdown.svelte +175 -0
- package/dist/Components/Table/Misc/TableViewDropdown.svelte.d.ts +25 -0
- package/dist/Components/Table/SubApis.svelte.js +0 -41
- package/dist/Components/Table/Types/Columns/JSONTableLayout.d.ts +5 -5
- package/dist/Components/Table/Types/Context/ColumnLayoutState.svelte.d.ts +5 -5
- package/dist/Components/Table/Types/Context/ColumnLayoutState.svelte.js +5 -5
- package/dist/Components/Table/Types/Context/PreferencesState.svelte.d.ts +106 -147
- package/dist/Components/Table/Types/Context/PreferencesState.svelte.js +156 -203
- package/dist/Components/Table/Types/Context/TableContext.svelte.d.ts +323 -44
- package/dist/Components/Table/Types/Context/TableContext.svelte.js +687 -187
- package/dist/Components/Table/Types/Context/TableInitOptions.d.ts +9 -0
- package/dist/Components/Table/Types/Context/ViewState.svelte.d.ts +152 -0
- package/dist/Components/Table/Types/Context/ViewState.svelte.js +223 -0
- package/dist/Components/Table/Types/ExpandedPanel.d.ts +9 -5
- package/dist/Components/Table/Types/ExpandedPanel.js +9 -5
- package/dist/Components/Table/Types/Persistence/DatatableView.d.ts +95 -0
- package/dist/Components/Table/Types/Persistence/DatatableViewEnvelope.d.ts +21 -0
- package/dist/Components/Table/Types/Persistence/DatatableViewEnvelope.js +1 -0
- package/dist/Components/Table/Types/Persistence/DatatableViewKind.d.ts +10 -0
- package/dist/Components/Table/Types/Persistence/DatatableViewKind.js +1 -0
- package/dist/Components/Table/Types/Persistence/JSONActiveView.d.ts +58 -0
- package/dist/Components/Table/Types/Persistence/JSONActiveView.js +41 -0
- package/dist/Components/Table/Types/Persistence/JSONTableFilter.d.ts +53 -0
- package/dist/Components/Table/Types/Persistence/JSONTableFilter.js +42 -0
- package/dist/Components/Table/Types/Persistence/RemoteTableLayoutAdapter.d.ts +47 -0
- package/dist/Components/Table/Types/Persistence/RemoteTableLayoutAdapter.js +1 -0
- package/dist/Components/Table/Types/Public/CreateTableOptions.d.ts +10 -0
- package/dist/Components/Table/Types/Public/TablePersistence.d.ts +1 -4
- package/dist/Components/Table/Types/Public/TableSubApis.d.ts +0 -18
- package/dist/Components/Table/Types/Public/index.d.ts +1 -1
- package/dist/Components/Table/createTable.svelte.js +2 -0
- package/dist/index.d.ts +8 -1
- package/dist/index.js +9 -0
- package/package.json +1 -1
- package/dist/Components/Table/Types/Columns/Definitions/ColumnDefSet.d.ts +0 -20
- package/dist/Components/Table/Types/Columns/Definitions/JSONColumnDefSet.d.ts +0 -25
- /package/dist/Components/Table/{Types/Columns/Definitions/ColumnDefSet.js → Misc/TableConfigurationModalProps.js} +0 -0
- /package/dist/Components/Table/Types/{Columns/Definitions/JSONColumnDefSet.js → Persistence/DatatableView.js} +0 -0
|
@@ -15,6 +15,8 @@
|
|
|
15
15
|
import { ExpandedPanel } from '../Types/ExpandedPanel.js';
|
|
16
16
|
import ColumnPanelModal from './ColumnPanelModal.svelte';
|
|
17
17
|
import FilterPanelModal from './FilterPanelModal.svelte';
|
|
18
|
+
import TableConfigurationModal from './TableConfigurationModal.svelte';
|
|
19
|
+
import TableViewDropdown from './TableViewDropdown.svelte';
|
|
18
20
|
import ToolboxPanelModal from './ToolboxPanelModal.svelte';
|
|
19
21
|
|
|
20
22
|
const tableContext = getContext<TableContext<T, IdType>>(TableContext.identifier);
|
|
@@ -24,6 +26,7 @@
|
|
|
24
26
|
[ExpandedPanel.Column]: ColumnPanelModal,
|
|
25
27
|
[ExpandedPanel.Filter]: FilterPanelModal,
|
|
26
28
|
[ExpandedPanel.Toolbox]: ToolboxPanelModal,
|
|
29
|
+
[ExpandedPanel.Configuration]: TableConfigurationModal,
|
|
27
30
|
} as const;
|
|
28
31
|
|
|
29
32
|
let expandedPanel = $state<ExpandedPanel | null>(null);
|
|
@@ -39,6 +42,9 @@
|
|
|
39
42
|
/>
|
|
40
43
|
{/if}
|
|
41
44
|
<div class="sidebar">
|
|
45
|
+
<div class="view-dropdown-slot">
|
|
46
|
+
<TableViewDropdown />
|
|
47
|
+
</div>
|
|
42
48
|
<Button
|
|
43
49
|
side={Side.Bottom}
|
|
44
50
|
onclick={() => {
|
|
@@ -89,6 +95,19 @@
|
|
|
89
95
|
name: 'category',
|
|
90
96
|
}}>My Tool Box</Button
|
|
91
97
|
>
|
|
98
|
+
<Button
|
|
99
|
+
size={Size.Small}
|
|
100
|
+
side={Side.Bottom}
|
|
101
|
+
toggled={expandedPanel === ExpandedPanel.Configuration}
|
|
102
|
+
onclick={() => {
|
|
103
|
+
expandedPanel =
|
|
104
|
+
expandedPanel === ExpandedPanel.Configuration ? null : ExpandedPanel.Configuration;
|
|
105
|
+
}}
|
|
106
|
+
variant={Variant.Toolbar}
|
|
107
|
+
iconTop={{
|
|
108
|
+
name: 'setting-cog',
|
|
109
|
+
}}>Table Configuration</Button
|
|
110
|
+
>
|
|
92
111
|
{#if tableContext.dataRepo.addEmptyRow}
|
|
93
112
|
<Button
|
|
94
113
|
size={Size.Small}
|
|
@@ -140,4 +159,12 @@
|
|
|
140
159
|
.sidebar .filler {
|
|
141
160
|
flex-grow: 2;
|
|
142
161
|
background-color: #ffffff;
|
|
162
|
+
}
|
|
163
|
+
.sidebar .view-dropdown-slot {
|
|
164
|
+
display: flex;
|
|
165
|
+
flex-flow: row nowrap;
|
|
166
|
+
align-items: center;
|
|
167
|
+
background-color: #ffffff;
|
|
168
|
+
padding: 0 0.5rem;
|
|
169
|
+
flex-shrink: 0;
|
|
143
170
|
}</style>
|
|
@@ -17,24 +17,39 @@
|
|
|
17
17
|
import ColumnPanel from './ColumnPanel.svelte';
|
|
18
18
|
import FilterPanel from './FilterPanel.svelte';
|
|
19
19
|
import SidePanel from './SidePanel.svelte';
|
|
20
|
+
import TableConfigurationModal from './TableConfigurationModal.svelte';
|
|
20
21
|
import ToolboxPanel from './ToolboxPanel.svelte';
|
|
21
22
|
|
|
22
23
|
const tableContext = getContext<TableContext<T, IdType>>(TableContext.identifier);
|
|
23
24
|
|
|
25
|
+
// `TableConfigurationModal` is a full `DesktopModal` rather than a
|
|
26
|
+
// side-panel body, so it is registered here but rendered standalone
|
|
27
|
+
// (outside `SidePanel`) below - `panels` only maps the side-panel
|
|
28
|
+
// kinds. Keeping the Configuration key in the map documents the
|
|
29
|
+
// relationship and mirrors `TableHorizontalBar`'s registration.
|
|
24
30
|
const panels = {
|
|
25
31
|
[ExpandedPanel.Column]: ColumnPanel,
|
|
26
32
|
[ExpandedPanel.Filter]: FilterPanel,
|
|
27
33
|
[ExpandedPanel.Toolbox]: ToolboxPanel,
|
|
34
|
+
[ExpandedPanel.Configuration]: TableConfigurationModal,
|
|
28
35
|
} as const;
|
|
29
36
|
|
|
30
37
|
let expandedPanel = $state<ExpandedPanel | null>(null);
|
|
31
38
|
|
|
32
39
|
$effect(() => {
|
|
33
|
-
|
|
40
|
+
// The Configuration modal owns its own overlay and must not shrink
|
|
41
|
+
// the table footer the way an inline side panel does.
|
|
42
|
+
tableContext.limitFooter = !!expandedPanel && expandedPanel !== ExpandedPanel.Configuration;
|
|
34
43
|
});
|
|
35
44
|
|
|
45
|
+
// Side-panel body for the inline panel kinds only; the Configuration
|
|
46
|
+
// kind is excluded and handled by the standalone modal block below.
|
|
36
47
|
let ExpandedPanelElement = $derived(
|
|
37
|
-
expandedPanel &&
|
|
48
|
+
expandedPanel &&
|
|
49
|
+
expandedPanel !== ExpandedPanel.None &&
|
|
50
|
+
expandedPanel !== ExpandedPanel.Configuration
|
|
51
|
+
? panels[expandedPanel]
|
|
52
|
+
: null
|
|
38
53
|
);
|
|
39
54
|
|
|
40
55
|
function handleClickOutside(e: MouseEvent) {
|
|
@@ -58,6 +73,12 @@
|
|
|
58
73
|
if (target.closest('[data-scoria-portal-dropdown]') != null) {
|
|
59
74
|
return;
|
|
60
75
|
}
|
|
76
|
+
// The Table Configuration modal owns its own backdrop + close
|
|
77
|
+
// affordances; a click inside its `.modal-root` must not be
|
|
78
|
+
// treated as a click-outside that dismisses the panel.
|
|
79
|
+
if (target.closest('.modal-root') != null) {
|
|
80
|
+
return;
|
|
81
|
+
}
|
|
61
82
|
expandedPanel = null;
|
|
62
83
|
}
|
|
63
84
|
|
|
@@ -78,6 +99,14 @@
|
|
|
78
99
|
<ExpandedPanelElement />
|
|
79
100
|
</SidePanel>
|
|
80
101
|
{/if}
|
|
102
|
+
|
|
103
|
+
{#if expandedPanel === ExpandedPanel.Configuration}
|
|
104
|
+
<TableConfigurationModal
|
|
105
|
+
onclose={() => {
|
|
106
|
+
expandedPanel = null;
|
|
107
|
+
}}
|
|
108
|
+
/>
|
|
109
|
+
{/if}
|
|
81
110
|
<div class="sidebar">
|
|
82
111
|
<Button
|
|
83
112
|
side={tableContext.toolbarPosition === ToolbarPosition.Left ? Side.Left : Side.Right}
|
|
@@ -133,6 +162,20 @@
|
|
|
133
162
|
}}
|
|
134
163
|
label="My Tool Box"
|
|
135
164
|
/>
|
|
165
|
+
<Button
|
|
166
|
+
side={tableContext.toolbarPosition === ToolbarPosition.Left ? Side.Left : Side.Right}
|
|
167
|
+
toggled={expandedPanel === ExpandedPanel.Configuration}
|
|
168
|
+
onclick={() => {
|
|
169
|
+
expandedPanel =
|
|
170
|
+
expandedPanel === ExpandedPanel.Configuration ? null : ExpandedPanel.Configuration;
|
|
171
|
+
}}
|
|
172
|
+
variant={Variant.Toolbar}
|
|
173
|
+
iconTop={{
|
|
174
|
+
name: 'setting-cog',
|
|
175
|
+
size: Size.Medium,
|
|
176
|
+
}}
|
|
177
|
+
label="Table Configuration"
|
|
178
|
+
/>
|
|
136
179
|
|
|
137
180
|
{#if tableContext.paginationRepo?.reload}
|
|
138
181
|
<Button
|
|
@@ -0,0 +1,175 @@
|
|
|
1
|
+
<svelte:options runes />
|
|
2
|
+
|
|
3
|
+
<script
|
|
4
|
+
lang="ts"
|
|
5
|
+
generics="T extends object, IdType extends Primitive"
|
|
6
|
+
>
|
|
7
|
+
import Button from '../../Button.svelte';
|
|
8
|
+
import SingleSelect from '../../SingleSelect.svelte';
|
|
9
|
+
import TextInput from '../../TextInput.svelte';
|
|
10
|
+
import { devCatch } from '../../../Helpers/Helpers.svelte.js';
|
|
11
|
+
import type { SelectOption } from '../../../Types/Internal/SelectOption.js';
|
|
12
|
+
import { Size } from '../../../Types/Internal/Size.js';
|
|
13
|
+
import { Variant } from '../../../Types/Internal/Variant.js';
|
|
14
|
+
import { getContext } from 'svelte';
|
|
15
|
+
import { TableContext } from '../Types/Context/TableContext.svelte.js';
|
|
16
|
+
import type { Primitive } from '../Types/Context/TableInitOptions.js';
|
|
17
|
+
|
|
18
|
+
const tableContext = getContext<TableContext<T, IdType>>(TableContext.identifier);
|
|
19
|
+
|
|
20
|
+
// Sentinel value for the "Default" option. A real saved view always
|
|
21
|
+
// carries a server-assigned, non-empty `id`, so an empty string never
|
|
22
|
+
// collides with one.
|
|
23
|
+
const DEFAULT_OPTION = '';
|
|
24
|
+
|
|
25
|
+
// The layout view-state slice, read live from the context.
|
|
26
|
+
const activeView = $derived(tableContext._viewState.activeView('layout'));
|
|
27
|
+
const isDirty = $derived(tableContext._viewState.isDirty('layout'));
|
|
28
|
+
const savedViews = $derived(tableContext._viewState.savedViews('layout'));
|
|
29
|
+
|
|
30
|
+
// Toolbar label: 'Default' / 'Custom (unsaved)' / '<name>' / '<name>
|
|
31
|
+
// (unsaved)'. Used as the displayed label of the currently-selected
|
|
32
|
+
// option so the dropdown reflects the dirty state exactly.
|
|
33
|
+
const dropdownLabel = $derived(tableContext._viewState.dropdownLabel('layout'));
|
|
34
|
+
|
|
35
|
+
// The value of the currently-active option: the sentinel for Default,
|
|
36
|
+
// otherwise the saved view's id.
|
|
37
|
+
const activeValue = $derived(activeView.kind === 'saved' ? activeView.id : DEFAULT_OPTION);
|
|
38
|
+
|
|
39
|
+
// Options for the select. The currently-active option's label is the
|
|
40
|
+
// `dropdownLabel` (so a dirty view reads "<name> (unsaved)"); every
|
|
41
|
+
// other option shows its plain name. "Default" is always first.
|
|
42
|
+
const options: Array<SelectOption<string>> = $derived([
|
|
43
|
+
{
|
|
44
|
+
label: activeValue === DEFAULT_OPTION ? dropdownLabel : 'Default',
|
|
45
|
+
value: DEFAULT_OPTION,
|
|
46
|
+
},
|
|
47
|
+
...savedViews.map((view) => ({
|
|
48
|
+
label: view.id === activeValue ? dropdownLabel : view.name,
|
|
49
|
+
value: view.id,
|
|
50
|
+
})),
|
|
51
|
+
]);
|
|
52
|
+
|
|
53
|
+
const selectedOption = $derived(options.find((o) => o.value === activeValue) ?? options[0]);
|
|
54
|
+
|
|
55
|
+
// Inline "name this layout" prompt state for the Save button.
|
|
56
|
+
let promptOpen = $state(false);
|
|
57
|
+
let pendingName = $state('');
|
|
58
|
+
|
|
59
|
+
/** Apply the option the user picked from the dropdown. */
|
|
60
|
+
function selectOption(option: SelectOption<string> | null): void {
|
|
61
|
+
if (!option) {
|
|
62
|
+
return;
|
|
63
|
+
}
|
|
64
|
+
if (option.value === DEFAULT_OPTION) {
|
|
65
|
+
tableContext.resetToDefault('layout');
|
|
66
|
+
return;
|
|
67
|
+
}
|
|
68
|
+
const view = savedViews.find((v) => v.id === option.value);
|
|
69
|
+
if (view) {
|
|
70
|
+
tableContext.applyDatatableView(view);
|
|
71
|
+
}
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
/**
|
|
75
|
+
* Handle the Save button. When the active layout is a saved view, save
|
|
76
|
+
* over it directly. When it is the Default (an unsaved custom layout),
|
|
77
|
+
* open the inline name prompt so the user can name a brand-new view.
|
|
78
|
+
*/
|
|
79
|
+
function onSaveClicked(): void {
|
|
80
|
+
if (activeView.kind === 'saved') {
|
|
81
|
+
tableContext.saveActiveView('layout').catch(devCatch);
|
|
82
|
+
return;
|
|
83
|
+
}
|
|
84
|
+
promptOpen = true;
|
|
85
|
+
pendingName = '';
|
|
86
|
+
}
|
|
87
|
+
|
|
88
|
+
/** Commit the inline name prompt as a brand-new saved layout. */
|
|
89
|
+
function commitNewView(): void {
|
|
90
|
+
const trimmed = pendingName.trim();
|
|
91
|
+
if (!trimmed) {
|
|
92
|
+
return;
|
|
93
|
+
}
|
|
94
|
+
tableContext.saveCurrentAsNewView(trimmed, 'layout').catch(devCatch);
|
|
95
|
+
promptOpen = false;
|
|
96
|
+
pendingName = '';
|
|
97
|
+
}
|
|
98
|
+
</script>
|
|
99
|
+
|
|
100
|
+
<div class="view-dropdown">
|
|
101
|
+
<div class="select">
|
|
102
|
+
<SingleSelect
|
|
103
|
+
label="Layout"
|
|
104
|
+
name="Layout"
|
|
105
|
+
{options}
|
|
106
|
+
labelProp="label"
|
|
107
|
+
valueProp="value"
|
|
108
|
+
value={selectedOption}
|
|
109
|
+
valueAsObject
|
|
110
|
+
searchable={false}
|
|
111
|
+
onchange={selectOption}
|
|
112
|
+
/>
|
|
113
|
+
</div>
|
|
114
|
+
|
|
115
|
+
{#if promptOpen}
|
|
116
|
+
<div class="save-prompt">
|
|
117
|
+
<TextInput
|
|
118
|
+
placeholder="Layout name"
|
|
119
|
+
bind:value={pendingName}
|
|
120
|
+
onkeydown={(e: KeyboardEvent) => {
|
|
121
|
+
if (e.key === 'Enter') {
|
|
122
|
+
e.preventDefault();
|
|
123
|
+
commitNewView();
|
|
124
|
+
} else if (e.key === 'Escape') {
|
|
125
|
+
promptOpen = false;
|
|
126
|
+
pendingName = '';
|
|
127
|
+
}
|
|
128
|
+
}}
|
|
129
|
+
/>
|
|
130
|
+
<Button
|
|
131
|
+
type="submit"
|
|
132
|
+
variant={Variant.Primary}
|
|
133
|
+
size={Size.MediumSmall}
|
|
134
|
+
nowrap
|
|
135
|
+
disabled={!pendingName.trim()}
|
|
136
|
+
onclick={commitNewView}>Save</Button
|
|
137
|
+
>
|
|
138
|
+
<Button
|
|
139
|
+
variant={Variant.Secondary}
|
|
140
|
+
size={Size.MediumSmall}
|
|
141
|
+
nowrap
|
|
142
|
+
onclick={() => {
|
|
143
|
+
promptOpen = false;
|
|
144
|
+
pendingName = '';
|
|
145
|
+
}}>Cancel</Button
|
|
146
|
+
>
|
|
147
|
+
</div>
|
|
148
|
+
{:else}
|
|
149
|
+
<Button
|
|
150
|
+
variant={Variant.Secondary}
|
|
151
|
+
size={Size.MediumSmall}
|
|
152
|
+
nowrap
|
|
153
|
+
disabled={!isDirty}
|
|
154
|
+
onclick={onSaveClicked}>Save</Button
|
|
155
|
+
>
|
|
156
|
+
{/if}
|
|
157
|
+
</div>
|
|
158
|
+
|
|
159
|
+
<style>.view-dropdown {
|
|
160
|
+
display: flex;
|
|
161
|
+
flex-flow: row nowrap;
|
|
162
|
+
align-items: end;
|
|
163
|
+
gap: 0.5rem;
|
|
164
|
+
}
|
|
165
|
+
|
|
166
|
+
.select {
|
|
167
|
+
min-width: 12rem;
|
|
168
|
+
}
|
|
169
|
+
|
|
170
|
+
.save-prompt {
|
|
171
|
+
display: flex;
|
|
172
|
+
flex-flow: row nowrap;
|
|
173
|
+
align-items: end;
|
|
174
|
+
gap: 0.375rem;
|
|
175
|
+
}</style>
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
import type { Primitive } from '../Types/Context/TableInitOptions.js';
|
|
2
|
+
declare function $$render<T extends object, IdType extends Primitive>(): {
|
|
3
|
+
props: Record<string, never>;
|
|
4
|
+
exports: {};
|
|
5
|
+
bindings: "";
|
|
6
|
+
slots: {};
|
|
7
|
+
events: {};
|
|
8
|
+
};
|
|
9
|
+
declare class __sveltets_Render<T extends object, IdType extends Primitive> {
|
|
10
|
+
props(): ReturnType<typeof $$render<T, IdType>>['props'];
|
|
11
|
+
events(): ReturnType<typeof $$render<T, IdType>>['events'];
|
|
12
|
+
slots(): ReturnType<typeof $$render<T, IdType>>['slots'];
|
|
13
|
+
bindings(): "";
|
|
14
|
+
exports(): {};
|
|
15
|
+
}
|
|
16
|
+
interface $$IsomorphicComponent {
|
|
17
|
+
new <T extends object, IdType extends Primitive>(options: import('svelte').ComponentConstructorOptions<ReturnType<__sveltets_Render<T, IdType>['props']>>): import('svelte').SvelteComponent<ReturnType<__sveltets_Render<T, IdType>['props']>, ReturnType<__sveltets_Render<T, IdType>['events']>, ReturnType<__sveltets_Render<T, IdType>['slots']>> & {
|
|
18
|
+
$$bindings?: ReturnType<__sveltets_Render<T, IdType>['bindings']>;
|
|
19
|
+
} & ReturnType<__sveltets_Render<T, IdType>['exports']>;
|
|
20
|
+
<T extends object, IdType extends Primitive>(internal: unknown, props: {}): ReturnType<__sveltets_Render<T, IdType>['exports']>;
|
|
21
|
+
z_$$bindings?: ReturnType<__sveltets_Render<any, any>['bindings']>;
|
|
22
|
+
}
|
|
23
|
+
declare const TableViewDropdown: $$IsomorphicComponent;
|
|
24
|
+
type TableViewDropdown<T extends object, IdType extends Primitive> = InstanceType<typeof TableViewDropdown<T, IdType>>;
|
|
25
|
+
export default TableViewDropdown;
|
|
@@ -237,48 +237,7 @@ export function makeFocusApi(ctx) {
|
|
|
237
237
|
// Preferences
|
|
238
238
|
// ─────────────────────────────────────────────────────────────────────────
|
|
239
239
|
export function makePreferencesApi(ctx) {
|
|
240
|
-
// Adapt the internal `ColumnDefSet<T>` shape to the public `SavedPreset`
|
|
241
|
-
// shape. `ColumnDefSet` has no `savedAt` timestamp or per-column sizing
|
|
242
|
-
// map, so `savedAt` is an epoch-zero placeholder and per-column `width`
|
|
243
|
-
// falls back to the def's `minSize`.
|
|
244
|
-
const adapt = (set) => ({
|
|
245
|
-
name: set.name,
|
|
246
|
-
// Literal placeholder, no reactivity needed.
|
|
247
|
-
// eslint-disable-next-line svelte/prefer-svelte-reactivity
|
|
248
|
-
savedAt: new Date(0).toISOString(),
|
|
249
|
-
columns: set.columnDefs.map((c) => ({
|
|
250
|
-
id: c.id,
|
|
251
|
-
visible: set.visibilityState[c.id] !== false,
|
|
252
|
-
width: c.minSize,
|
|
253
|
-
pinned: set.columnPinningState.left?.has(c.id)
|
|
254
|
-
? 'left'
|
|
255
|
-
: set.columnPinningState.right?.has(c.id)
|
|
256
|
-
? 'right'
|
|
257
|
-
: 'none',
|
|
258
|
-
})),
|
|
259
|
-
});
|
|
260
240
|
return Object.freeze({
|
|
261
|
-
get presets() {
|
|
262
|
-
return ctx._preferences.columnPresets.map(adapt);
|
|
263
|
-
},
|
|
264
|
-
get selectedPreset() {
|
|
265
|
-
const sel = ctx._preferences.selectedPreset;
|
|
266
|
-
return sel ? adapt(sel) : undefined;
|
|
267
|
-
},
|
|
268
|
-
savePreset(name) {
|
|
269
|
-
ctx._preferences.saveColumnPreset(name);
|
|
270
|
-
},
|
|
271
|
-
applyPreset(preset) {
|
|
272
|
-
const internal = ctx._preferences.columnPresets.find((p) => p.name === preset.name);
|
|
273
|
-
if (internal) {
|
|
274
|
-
ctx._preferences.setSelectedPreset(internal);
|
|
275
|
-
}
|
|
276
|
-
},
|
|
277
|
-
deletePreset(name) {
|
|
278
|
-
const next = ctx._preferences.columnPresets.filter((p) => p.name !== name);
|
|
279
|
-
ctx._preferences.setPresets(next);
|
|
280
|
-
ctx._preferences.persistPresets(next);
|
|
281
|
-
},
|
|
282
241
|
get settings() {
|
|
283
242
|
return Object.freeze({
|
|
284
243
|
isCompact: ctx.isCompact,
|
|
@@ -4,14 +4,14 @@ import type { VisibilityState } from './VisibilityState.js';
|
|
|
4
4
|
/**
|
|
5
5
|
* Persisted-to-localStorage snapshot of a table's *live* column layout -
|
|
6
6
|
* the order / visibility / pinning / width state a user builds up by
|
|
7
|
-
* dragging, hiding and resizing columns
|
|
8
|
-
*
|
|
7
|
+
* dragging, hiding and resizing columns. This is the working copy the
|
|
8
|
+
* FPM 403 datatable-view machine measures dirtiness against.
|
|
9
9
|
*
|
|
10
10
|
* `TableContext` writes this automatically on every layout change and
|
|
11
11
|
* re-applies it on the next mount, so a user's tweaks survive navigation
|
|
12
|
-
* and reloads
|
|
13
|
-
*
|
|
14
|
-
*
|
|
12
|
+
* and reloads - persisted until the browser storage is cleared or the
|
|
13
|
+
* table's column set changes (schema drift, which drops the stale
|
|
14
|
+
* snapshot).
|
|
15
15
|
*
|
|
16
16
|
* Only ids and primitive maps are stored - never the column-def objects
|
|
17
17
|
* themselves - so the snapshot stays small and is trivially validated.
|
|
@@ -50,8 +50,8 @@ export declare class ColumnLayoutState<T extends object> {
|
|
|
50
50
|
*
|
|
51
51
|
* Setter accepts any array of `ColumnDef<T>`; the parent
|
|
52
52
|
* `TableContext` is responsible for index normalisation when
|
|
53
|
-
* applying drag-drop or
|
|
54
|
-
* `moveColumnTo`, `
|
|
53
|
+
* applying drag-drop or a saved datatable-view layout (see
|
|
54
|
+
* `reorderColumn`, `moveColumnTo`, `_applyLayout`).
|
|
55
55
|
*/
|
|
56
56
|
get columnDefs(): Array<ColumnDef<T>>;
|
|
57
57
|
set columnDefs(v: Array<ColumnDef<T>>);
|
|
@@ -66,9 +66,9 @@ export declare class ColumnLayoutState<T extends object> {
|
|
|
66
66
|
set columnSizing(v: ColumnSizingState);
|
|
67
67
|
/**
|
|
68
68
|
* Per-column pin state (left / right). Setter is exposed publicly
|
|
69
|
-
* for direct assignment by the parent (e.g. `
|
|
70
|
-
*
|
|
71
|
-
*
|
|
69
|
+
* for direct assignment by the parent (e.g. `_applyLayout` and the
|
|
70
|
+
* init flow); the gated `setColumnPinning` updater below honours the
|
|
71
|
+
* `allowColumnReordering` master gate.
|
|
72
72
|
*/
|
|
73
73
|
get columnPinning(): ColumnPinningState;
|
|
74
74
|
set columnPinning(v: ColumnPinningState);
|
|
@@ -34,8 +34,8 @@ export class ColumnLayoutState {
|
|
|
34
34
|
*
|
|
35
35
|
* Setter accepts any array of `ColumnDef<T>`; the parent
|
|
36
36
|
* `TableContext` is responsible for index normalisation when
|
|
37
|
-
* applying drag-drop or
|
|
38
|
-
* `moveColumnTo`, `
|
|
37
|
+
* applying drag-drop or a saved datatable-view layout (see
|
|
38
|
+
* `reorderColumn`, `moveColumnTo`, `_applyLayout`).
|
|
39
39
|
*/
|
|
40
40
|
get columnDefs() {
|
|
41
41
|
return this._columnDefs;
|
|
@@ -58,9 +58,9 @@ export class ColumnLayoutState {
|
|
|
58
58
|
}
|
|
59
59
|
/**
|
|
60
60
|
* Per-column pin state (left / right). Setter is exposed publicly
|
|
61
|
-
* for direct assignment by the parent (e.g. `
|
|
62
|
-
*
|
|
63
|
-
*
|
|
61
|
+
* for direct assignment by the parent (e.g. `_applyLayout` and the
|
|
62
|
+
* init flow); the gated `setColumnPinning` updater below honours the
|
|
63
|
+
* `allowColumnReordering` master gate.
|
|
64
64
|
*/
|
|
65
65
|
get columnPinning() {
|
|
66
66
|
return this._columnPinning;
|