@shotleybuilder/svelte-table-kit 0.1.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/LICENSE +21 -0
- package/README.md +247 -0
- package/dist/TableKit.svelte +838 -0
- package/dist/TableKit.svelte.d.ts +31 -0
- package/dist/components/FilterBar.svelte +291 -0
- package/dist/components/FilterBar.svelte.d.ts +24 -0
- package/dist/components/FilterCondition.svelte +135 -0
- package/dist/components/FilterCondition.svelte.d.ts +23 -0
- package/dist/components/GroupBar.svelte +283 -0
- package/dist/components/GroupBar.svelte.d.ts +21 -0
- package/dist/index.d.ts +9 -0
- package/dist/index.js +15 -0
- package/dist/presets/index.d.ts +6 -0
- package/dist/presets/index.js +27 -0
- package/dist/stores/persistence.d.ts +58 -0
- package/dist/stores/persistence.js +127 -0
- package/dist/types.d.ts +85 -0
- package/dist/types.js +2 -0
- package/dist/utils/config.d.ts +18 -0
- package/dist/utils/config.js +32 -0
- package/dist/utils/filters.d.ts +21 -0
- package/dist/utils/filters.js +101 -0
- package/dist/utils/formatters.d.ts +16 -0
- package/dist/utils/formatters.js +39 -0
- package/package.json +78 -0
|
@@ -0,0 +1,283 @@
|
|
|
1
|
+
<script>export let columns;
|
|
2
|
+
export let grouping = [];
|
|
3
|
+
export let onGroupingChange;
|
|
4
|
+
const MAX_LEVELS = 3;
|
|
5
|
+
let isExpanded = false;
|
|
6
|
+
function addGroup() {
|
|
7
|
+
if (grouping.length >= MAX_LEVELS) return;
|
|
8
|
+
onGroupingChange([...grouping, ""]);
|
|
9
|
+
isExpanded = true;
|
|
10
|
+
}
|
|
11
|
+
function updateGroup(index, columnId) {
|
|
12
|
+
const newGrouping = [...grouping];
|
|
13
|
+
newGrouping[index] = columnId;
|
|
14
|
+
onGroupingChange(newGrouping);
|
|
15
|
+
}
|
|
16
|
+
function removeGroup(index) {
|
|
17
|
+
const newGrouping = grouping.filter((_, i) => i !== index);
|
|
18
|
+
onGroupingChange(newGrouping);
|
|
19
|
+
if (newGrouping.length === 0) {
|
|
20
|
+
isExpanded = false;
|
|
21
|
+
}
|
|
22
|
+
}
|
|
23
|
+
function clearAllGroups() {
|
|
24
|
+
onGroupingChange([]);
|
|
25
|
+
isExpanded = false;
|
|
26
|
+
}
|
|
27
|
+
$: availableColumns = columns.filter((col) => {
|
|
28
|
+
const columnId = col.accessorKey || col.id;
|
|
29
|
+
return columnId && col.enableGrouping !== false;
|
|
30
|
+
});
|
|
31
|
+
$: hasGroups = grouping.length > 0;
|
|
32
|
+
$: validGroupCount = grouping.filter((g) => g !== "").length;
|
|
33
|
+
$: canAddMore = grouping.length < MAX_LEVELS;
|
|
34
|
+
</script>
|
|
35
|
+
|
|
36
|
+
<div class="group-bar">
|
|
37
|
+
<!-- Compact Group Button -->
|
|
38
|
+
<button class="group-toggle-btn" on:click={() => (isExpanded = !isExpanded)}>
|
|
39
|
+
<svg class="icon" fill="none" stroke="currentColor" viewBox="0 0 24 24">
|
|
40
|
+
<path
|
|
41
|
+
stroke-linecap="round"
|
|
42
|
+
stroke-linejoin="round"
|
|
43
|
+
stroke-width="2"
|
|
44
|
+
d="M4 6h16M4 10h16M4 14h16M4 18h16"
|
|
45
|
+
/>
|
|
46
|
+
</svg>
|
|
47
|
+
Group
|
|
48
|
+
{#if validGroupCount > 0}
|
|
49
|
+
<span class="group-badge">{validGroupCount}</span>
|
|
50
|
+
{/if}
|
|
51
|
+
<svg
|
|
52
|
+
class="chevron"
|
|
53
|
+
class:expanded={isExpanded}
|
|
54
|
+
fill="none"
|
|
55
|
+
stroke="currentColor"
|
|
56
|
+
viewBox="0 0 24 24"
|
|
57
|
+
>
|
|
58
|
+
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M19 9l-7 7-7-7" />
|
|
59
|
+
</svg>
|
|
60
|
+
</button>
|
|
61
|
+
|
|
62
|
+
<!-- Expandable Group Panel -->
|
|
63
|
+
{#if isExpanded}
|
|
64
|
+
<div class="group-panel">
|
|
65
|
+
{#if hasGroups}
|
|
66
|
+
<div class="group-header">
|
|
67
|
+
<span class="group-label">Group by</span>
|
|
68
|
+
<button class="clear-all-btn" on:click={clearAllGroups}> Clear all </button>
|
|
69
|
+
</div>
|
|
70
|
+
|
|
71
|
+
<div class="group-levels">
|
|
72
|
+
{#each grouping as group, index (index)}
|
|
73
|
+
<div class="group-level">
|
|
74
|
+
<select
|
|
75
|
+
class="field-select"
|
|
76
|
+
value={group}
|
|
77
|
+
on:change={(e) => updateGroup(index, e.currentTarget.value)}
|
|
78
|
+
>
|
|
79
|
+
<option value="">Select field...</option>
|
|
80
|
+
{#each availableColumns as column}
|
|
81
|
+
{@const columnId = column.accessorKey || column.id}
|
|
82
|
+
<option value={columnId}>
|
|
83
|
+
{column.header || columnId}
|
|
84
|
+
</option>
|
|
85
|
+
{/each}
|
|
86
|
+
</select>
|
|
87
|
+
<button class="remove-btn" on:click={() => removeGroup(index)} title="Remove group">
|
|
88
|
+
<svg class="icon" fill="none" stroke="currentColor" viewBox="0 0 24 24">
|
|
89
|
+
<path
|
|
90
|
+
stroke-linecap="round"
|
|
91
|
+
stroke-linejoin="round"
|
|
92
|
+
stroke-width="2"
|
|
93
|
+
d="M6 18L18 6M6 6l12 12"
|
|
94
|
+
/>
|
|
95
|
+
</svg>
|
|
96
|
+
</button>
|
|
97
|
+
</div>
|
|
98
|
+
{/each}
|
|
99
|
+
</div>
|
|
100
|
+
{/if}
|
|
101
|
+
|
|
102
|
+
{#if canAddMore}
|
|
103
|
+
<button class="add-group-btn" on:click={addGroup}>
|
|
104
|
+
<svg class="icon" fill="none" stroke="currentColor" viewBox="0 0 24 24">
|
|
105
|
+
<path
|
|
106
|
+
stroke-linecap="round"
|
|
107
|
+
stroke-linejoin="round"
|
|
108
|
+
stroke-width="2"
|
|
109
|
+
d="M12 6v6m0 0v6m0-6h6m-6 0H6"
|
|
110
|
+
/>
|
|
111
|
+
</svg>
|
|
112
|
+
{hasGroups ? 'Add subgroup' : 'Add group'}
|
|
113
|
+
</button>
|
|
114
|
+
{/if}
|
|
115
|
+
</div>
|
|
116
|
+
{/if}
|
|
117
|
+
</div>
|
|
118
|
+
|
|
119
|
+
<style>
|
|
120
|
+
.group-bar {
|
|
121
|
+
position: relative;
|
|
122
|
+
}
|
|
123
|
+
|
|
124
|
+
/* Compact Group Toggle Button */
|
|
125
|
+
.group-toggle-btn {
|
|
126
|
+
display: inline-flex;
|
|
127
|
+
align-items: center;
|
|
128
|
+
gap: 0.5rem;
|
|
129
|
+
padding: 0.5rem 1rem;
|
|
130
|
+
font-size: 0.875rem;
|
|
131
|
+
font-weight: 500;
|
|
132
|
+
color: #374151;
|
|
133
|
+
background: white;
|
|
134
|
+
border: 1px solid #d1d5db;
|
|
135
|
+
border-radius: 0.375rem;
|
|
136
|
+
cursor: pointer;
|
|
137
|
+
transition: all 0.2s;
|
|
138
|
+
}
|
|
139
|
+
|
|
140
|
+
.group-toggle-btn:hover {
|
|
141
|
+
background: #f9fafb;
|
|
142
|
+
border-color: #9ca3af;
|
|
143
|
+
}
|
|
144
|
+
|
|
145
|
+
.group-badge {
|
|
146
|
+
display: inline-flex;
|
|
147
|
+
align-items: center;
|
|
148
|
+
justify-content: center;
|
|
149
|
+
min-width: 1.25rem;
|
|
150
|
+
height: 1.25rem;
|
|
151
|
+
padding: 0 0.375rem;
|
|
152
|
+
font-size: 0.75rem;
|
|
153
|
+
font-weight: 600;
|
|
154
|
+
color: white;
|
|
155
|
+
background: #059669;
|
|
156
|
+
border-radius: 0.75rem;
|
|
157
|
+
}
|
|
158
|
+
|
|
159
|
+
.chevron {
|
|
160
|
+
width: 1rem;
|
|
161
|
+
height: 1rem;
|
|
162
|
+
transition: transform 0.2s;
|
|
163
|
+
}
|
|
164
|
+
|
|
165
|
+
.chevron.expanded {
|
|
166
|
+
transform: rotate(180deg);
|
|
167
|
+
}
|
|
168
|
+
|
|
169
|
+
/* Expandable Group Panel */
|
|
170
|
+
.group-panel {
|
|
171
|
+
position: absolute;
|
|
172
|
+
top: calc(100% + 0.5rem);
|
|
173
|
+
left: 0;
|
|
174
|
+
z-index: 20;
|
|
175
|
+
min-width: 400px;
|
|
176
|
+
padding: 1rem;
|
|
177
|
+
background: white;
|
|
178
|
+
border: 1px solid #e5e7eb;
|
|
179
|
+
border-radius: 0.5rem;
|
|
180
|
+
box-shadow: 0 10px 15px -3px rgba(0, 0, 0, 0.1);
|
|
181
|
+
}
|
|
182
|
+
|
|
183
|
+
.group-header {
|
|
184
|
+
display: flex;
|
|
185
|
+
justify-content: space-between;
|
|
186
|
+
align-items: center;
|
|
187
|
+
margin-bottom: 0.75rem;
|
|
188
|
+
}
|
|
189
|
+
|
|
190
|
+
.group-label {
|
|
191
|
+
font-size: 0.875rem;
|
|
192
|
+
font-weight: 600;
|
|
193
|
+
color: #374151;
|
|
194
|
+
}
|
|
195
|
+
|
|
196
|
+
.clear-all-btn {
|
|
197
|
+
font-size: 0.75rem;
|
|
198
|
+
color: #6b7280;
|
|
199
|
+
background: none;
|
|
200
|
+
border: none;
|
|
201
|
+
cursor: pointer;
|
|
202
|
+
padding: 0.25rem 0.5rem;
|
|
203
|
+
border-radius: 0.25rem;
|
|
204
|
+
transition: all 0.2s;
|
|
205
|
+
}
|
|
206
|
+
|
|
207
|
+
.clear-all-btn:hover {
|
|
208
|
+
color: #dc2626;
|
|
209
|
+
background: #fee2e2;
|
|
210
|
+
}
|
|
211
|
+
|
|
212
|
+
.group-levels {
|
|
213
|
+
display: flex;
|
|
214
|
+
flex-direction: column;
|
|
215
|
+
gap: 0.5rem;
|
|
216
|
+
margin-bottom: 0.75rem;
|
|
217
|
+
}
|
|
218
|
+
|
|
219
|
+
.group-level {
|
|
220
|
+
display: flex;
|
|
221
|
+
align-items: center;
|
|
222
|
+
gap: 0.5rem;
|
|
223
|
+
padding: 0.5rem;
|
|
224
|
+
background: #f9fafb;
|
|
225
|
+
border-radius: 0.375rem;
|
|
226
|
+
}
|
|
227
|
+
|
|
228
|
+
.field-select {
|
|
229
|
+
flex: 1;
|
|
230
|
+
padding: 0.375rem 0.75rem;
|
|
231
|
+
font-size: 0.875rem;
|
|
232
|
+
border: 1px solid #d1d5db;
|
|
233
|
+
border-radius: 0.375rem;
|
|
234
|
+
background: white;
|
|
235
|
+
}
|
|
236
|
+
|
|
237
|
+
.field-select:focus {
|
|
238
|
+
outline: none;
|
|
239
|
+
border-color: #059669;
|
|
240
|
+
box-shadow: 0 0 0 3px rgba(5, 150, 105, 0.1);
|
|
241
|
+
}
|
|
242
|
+
|
|
243
|
+
.remove-btn {
|
|
244
|
+
flex-shrink: 0;
|
|
245
|
+
padding: 0.375rem;
|
|
246
|
+
background: none;
|
|
247
|
+
border: none;
|
|
248
|
+
color: #6b7280;
|
|
249
|
+
cursor: pointer;
|
|
250
|
+
border-radius: 0.25rem;
|
|
251
|
+
transition: all 0.2s;
|
|
252
|
+
}
|
|
253
|
+
|
|
254
|
+
.remove-btn:hover {
|
|
255
|
+
background: #fee2e2;
|
|
256
|
+
color: #dc2626;
|
|
257
|
+
}
|
|
258
|
+
|
|
259
|
+
.add-group-btn {
|
|
260
|
+
display: inline-flex;
|
|
261
|
+
align-items: center;
|
|
262
|
+
gap: 0.5rem;
|
|
263
|
+
padding: 0.5rem 0.75rem;
|
|
264
|
+
font-size: 0.875rem;
|
|
265
|
+
font-weight: 500;
|
|
266
|
+
color: #059669;
|
|
267
|
+
background: white;
|
|
268
|
+
border: 1px dashed #059669;
|
|
269
|
+
border-radius: 0.375rem;
|
|
270
|
+
cursor: pointer;
|
|
271
|
+
transition: all 0.2s;
|
|
272
|
+
}
|
|
273
|
+
|
|
274
|
+
.add-group-btn:hover {
|
|
275
|
+
background: #d1fae5;
|
|
276
|
+
border-style: solid;
|
|
277
|
+
}
|
|
278
|
+
|
|
279
|
+
.icon {
|
|
280
|
+
width: 1rem;
|
|
281
|
+
height: 1rem;
|
|
282
|
+
}
|
|
283
|
+
</style>
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
import { SvelteComponent } from "svelte";
|
|
2
|
+
import type { ColumnDef } from '@tanstack/svelte-table';
|
|
3
|
+
declare const __propDef: {
|
|
4
|
+
props: {
|
|
5
|
+
columns: ColumnDef<any>[];
|
|
6
|
+
grouping?: string[];
|
|
7
|
+
onGroupingChange: (grouping: string[]) => void;
|
|
8
|
+
};
|
|
9
|
+
events: {
|
|
10
|
+
[evt: string]: CustomEvent<any>;
|
|
11
|
+
};
|
|
12
|
+
slots: {};
|
|
13
|
+
exports?: {} | undefined;
|
|
14
|
+
bindings?: string | undefined;
|
|
15
|
+
};
|
|
16
|
+
export type GroupBarProps = typeof __propDef.props;
|
|
17
|
+
export type GroupBarEvents = typeof __propDef.events;
|
|
18
|
+
export type GroupBarSlots = typeof __propDef.slots;
|
|
19
|
+
export default class GroupBar extends SvelteComponent<GroupBarProps, GroupBarEvents, GroupBarSlots> {
|
|
20
|
+
}
|
|
21
|
+
export {};
|
package/dist/index.d.ts
ADDED
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
export { default as TableKit } from './TableKit.svelte';
|
|
2
|
+
export { default as FilterBar } from './components/FilterBar.svelte';
|
|
3
|
+
export { default as FilterCondition } from './components/FilterCondition.svelte';
|
|
4
|
+
export { default as GroupBar } from './components/GroupBar.svelte';
|
|
5
|
+
export type { TableKitProps, TableConfig, ViewPreset, FilterCondition, FilterOperator, FilterLogic, SortConfig, ClassNameMap, TableFeatures, TableState } from './types';
|
|
6
|
+
export { presets } from './presets';
|
|
7
|
+
export { generateTableConfig, validateTableConfig, mergeConfigs } from './utils/config';
|
|
8
|
+
export { createTextFilter, createSelectFilter, createNumericFilter, evaluateCondition, applyFilters } from './utils/filters';
|
|
9
|
+
export { formatDate, formatCurrency, formatNumber, formatPercent } from './utils/formatters';
|
package/dist/index.js
ADDED
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
// Main exports for @sertantai/svelte-table-kit
|
|
2
|
+
// Main component
|
|
3
|
+
export { default as TableKit } from './TableKit.svelte';
|
|
4
|
+
// Sub-components
|
|
5
|
+
export { default as FilterBar } from './components/FilterBar.svelte';
|
|
6
|
+
export { default as FilterCondition } from './components/FilterCondition.svelte';
|
|
7
|
+
export { default as GroupBar } from './components/GroupBar.svelte';
|
|
8
|
+
// Presets
|
|
9
|
+
export { presets } from './presets';
|
|
10
|
+
// Utilities for AI configuration
|
|
11
|
+
export { generateTableConfig, validateTableConfig, mergeConfigs } from './utils/config';
|
|
12
|
+
// Filter utilities
|
|
13
|
+
export { createTextFilter, createSelectFilter, createNumericFilter, evaluateCondition, applyFilters } from './utils/filters';
|
|
14
|
+
// Formatters
|
|
15
|
+
export { formatDate, formatCurrency, formatNumber, formatPercent } from './utils/formatters';
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
// Preset configurations for common use cases
|
|
2
|
+
export const presets = {
|
|
3
|
+
dashboard: {
|
|
4
|
+
id: 'dashboard',
|
|
5
|
+
version: '1.0.0',
|
|
6
|
+
pagination: {
|
|
7
|
+
pageSize: 10,
|
|
8
|
+
pageSizeOptions: [10, 25, 50]
|
|
9
|
+
}
|
|
10
|
+
},
|
|
11
|
+
dataGrid: {
|
|
12
|
+
id: 'data-grid',
|
|
13
|
+
version: '1.0.0',
|
|
14
|
+
pagination: {
|
|
15
|
+
pageSize: 50,
|
|
16
|
+
pageSizeOptions: [25, 50, 100, 200]
|
|
17
|
+
}
|
|
18
|
+
},
|
|
19
|
+
readonly: {
|
|
20
|
+
id: 'readonly',
|
|
21
|
+
version: '1.0.0',
|
|
22
|
+
pagination: {
|
|
23
|
+
pageSize: 25,
|
|
24
|
+
pageSizeOptions: [25, 50, 100]
|
|
25
|
+
}
|
|
26
|
+
}
|
|
27
|
+
};
|
|
@@ -0,0 +1,58 @@
|
|
|
1
|
+
import type { VisibilityState, ColumnSizingState, ColumnFiltersState, ColumnOrderState, SortingState, PaginationState } from '@tanstack/svelte-table';
|
|
2
|
+
/**
|
|
3
|
+
* Check if we're in a browser environment
|
|
4
|
+
* Note: In SvelteKit apps, import from '$app/environment'
|
|
5
|
+
*/
|
|
6
|
+
export declare const isBrowser: boolean;
|
|
7
|
+
/**
|
|
8
|
+
* Load column visibility state from localStorage
|
|
9
|
+
*/
|
|
10
|
+
export declare function loadColumnVisibility(storageKey: string): VisibilityState;
|
|
11
|
+
/**
|
|
12
|
+
* Save column visibility state to localStorage
|
|
13
|
+
*/
|
|
14
|
+
export declare function saveColumnVisibility(storageKey: string, state: VisibilityState): void;
|
|
15
|
+
/**
|
|
16
|
+
* Load column sizing state from localStorage
|
|
17
|
+
*/
|
|
18
|
+
export declare function loadColumnSizing(storageKey: string): ColumnSizingState;
|
|
19
|
+
/**
|
|
20
|
+
* Save column sizing state to localStorage
|
|
21
|
+
*/
|
|
22
|
+
export declare function saveColumnSizing(storageKey: string, state: ColumnSizingState): void;
|
|
23
|
+
/**
|
|
24
|
+
* Load column filters state from localStorage
|
|
25
|
+
*/
|
|
26
|
+
export declare function loadColumnFilters(storageKey: string): ColumnFiltersState;
|
|
27
|
+
/**
|
|
28
|
+
* Save column filters state to localStorage
|
|
29
|
+
*/
|
|
30
|
+
export declare function saveColumnFilters(storageKey: string, state: ColumnFiltersState): void;
|
|
31
|
+
/**
|
|
32
|
+
* Load column order state from localStorage
|
|
33
|
+
*/
|
|
34
|
+
export declare function loadColumnOrder(storageKey: string): ColumnOrderState;
|
|
35
|
+
/**
|
|
36
|
+
* Save column order state to localStorage
|
|
37
|
+
*/
|
|
38
|
+
export declare function saveColumnOrder(storageKey: string, state: ColumnOrderState): void;
|
|
39
|
+
/**
|
|
40
|
+
* Load sorting state from localStorage
|
|
41
|
+
*/
|
|
42
|
+
export declare function loadSorting(storageKey: string): SortingState;
|
|
43
|
+
/**
|
|
44
|
+
* Save sorting state to localStorage
|
|
45
|
+
*/
|
|
46
|
+
export declare function saveSorting(storageKey: string, state: SortingState): void;
|
|
47
|
+
/**
|
|
48
|
+
* Load pagination state from localStorage
|
|
49
|
+
*/
|
|
50
|
+
export declare function loadPagination(storageKey: string, defaultPageSize?: number): PaginationState;
|
|
51
|
+
/**
|
|
52
|
+
* Save pagination state to localStorage
|
|
53
|
+
*/
|
|
54
|
+
export declare function savePagination(storageKey: string, state: PaginationState): void;
|
|
55
|
+
/**
|
|
56
|
+
* Clear all table state from localStorage
|
|
57
|
+
*/
|
|
58
|
+
export declare function clearTableState(storageKey: string): void;
|
|
@@ -0,0 +1,127 @@
|
|
|
1
|
+
// LocalStorage persistence utilities
|
|
2
|
+
/**
|
|
3
|
+
* Check if we're in a browser environment
|
|
4
|
+
* Note: In SvelteKit apps, import from '$app/environment'
|
|
5
|
+
*/
|
|
6
|
+
export const isBrowser = typeof window !== 'undefined' && typeof localStorage !== 'undefined';
|
|
7
|
+
/**
|
|
8
|
+
* Generic localStorage loader with error handling
|
|
9
|
+
*/
|
|
10
|
+
function loadFromStorage(key, defaultValue) {
|
|
11
|
+
if (!isBrowser)
|
|
12
|
+
return defaultValue;
|
|
13
|
+
try {
|
|
14
|
+
const saved = localStorage.getItem(key);
|
|
15
|
+
return saved ? JSON.parse(saved) : defaultValue;
|
|
16
|
+
}
|
|
17
|
+
catch (error) {
|
|
18
|
+
console.warn(`Failed to load ${key} from localStorage:`, error);
|
|
19
|
+
return defaultValue;
|
|
20
|
+
}
|
|
21
|
+
}
|
|
22
|
+
/**
|
|
23
|
+
* Generic localStorage saver with error handling
|
|
24
|
+
*/
|
|
25
|
+
function saveToStorage(key, value) {
|
|
26
|
+
if (!isBrowser)
|
|
27
|
+
return;
|
|
28
|
+
try {
|
|
29
|
+
localStorage.setItem(key, JSON.stringify(value));
|
|
30
|
+
}
|
|
31
|
+
catch (error) {
|
|
32
|
+
console.error(`Failed to save ${key} to localStorage:`, error);
|
|
33
|
+
}
|
|
34
|
+
}
|
|
35
|
+
/**
|
|
36
|
+
* Load column visibility state from localStorage
|
|
37
|
+
*/
|
|
38
|
+
export function loadColumnVisibility(storageKey) {
|
|
39
|
+
return loadFromStorage(`${storageKey}_column_visibility`, {});
|
|
40
|
+
}
|
|
41
|
+
/**
|
|
42
|
+
* Save column visibility state to localStorage
|
|
43
|
+
*/
|
|
44
|
+
export function saveColumnVisibility(storageKey, state) {
|
|
45
|
+
saveToStorage(`${storageKey}_column_visibility`, state);
|
|
46
|
+
}
|
|
47
|
+
/**
|
|
48
|
+
* Load column sizing state from localStorage
|
|
49
|
+
*/
|
|
50
|
+
export function loadColumnSizing(storageKey) {
|
|
51
|
+
return loadFromStorage(`${storageKey}_column_sizing`, {});
|
|
52
|
+
}
|
|
53
|
+
/**
|
|
54
|
+
* Save column sizing state to localStorage
|
|
55
|
+
*/
|
|
56
|
+
export function saveColumnSizing(storageKey, state) {
|
|
57
|
+
saveToStorage(`${storageKey}_column_sizing`, state);
|
|
58
|
+
}
|
|
59
|
+
/**
|
|
60
|
+
* Load column filters state from localStorage
|
|
61
|
+
*/
|
|
62
|
+
export function loadColumnFilters(storageKey) {
|
|
63
|
+
return loadFromStorage(`${storageKey}_column_filters`, []);
|
|
64
|
+
}
|
|
65
|
+
/**
|
|
66
|
+
* Save column filters state to localStorage
|
|
67
|
+
*/
|
|
68
|
+
export function saveColumnFilters(storageKey, state) {
|
|
69
|
+
saveToStorage(`${storageKey}_column_filters`, state);
|
|
70
|
+
}
|
|
71
|
+
/**
|
|
72
|
+
* Load column order state from localStorage
|
|
73
|
+
*/
|
|
74
|
+
export function loadColumnOrder(storageKey) {
|
|
75
|
+
return loadFromStorage(`${storageKey}_column_order`, []);
|
|
76
|
+
}
|
|
77
|
+
/**
|
|
78
|
+
* Save column order state to localStorage
|
|
79
|
+
*/
|
|
80
|
+
export function saveColumnOrder(storageKey, state) {
|
|
81
|
+
saveToStorage(`${storageKey}_column_order`, state);
|
|
82
|
+
}
|
|
83
|
+
/**
|
|
84
|
+
* Load sorting state from localStorage
|
|
85
|
+
*/
|
|
86
|
+
export function loadSorting(storageKey) {
|
|
87
|
+
return loadFromStorage(`${storageKey}_sorting`, []);
|
|
88
|
+
}
|
|
89
|
+
/**
|
|
90
|
+
* Save sorting state to localStorage
|
|
91
|
+
*/
|
|
92
|
+
export function saveSorting(storageKey, state) {
|
|
93
|
+
saveToStorage(`${storageKey}_sorting`, state);
|
|
94
|
+
}
|
|
95
|
+
/**
|
|
96
|
+
* Load pagination state from localStorage
|
|
97
|
+
*/
|
|
98
|
+
export function loadPagination(storageKey, defaultPageSize = 10) {
|
|
99
|
+
return loadFromStorage(`${storageKey}_pagination`, {
|
|
100
|
+
pageIndex: 0,
|
|
101
|
+
pageSize: defaultPageSize
|
|
102
|
+
});
|
|
103
|
+
}
|
|
104
|
+
/**
|
|
105
|
+
* Save pagination state to localStorage
|
|
106
|
+
*/
|
|
107
|
+
export function savePagination(storageKey, state) {
|
|
108
|
+
saveToStorage(`${storageKey}_pagination`, state);
|
|
109
|
+
}
|
|
110
|
+
/**
|
|
111
|
+
* Clear all table state from localStorage
|
|
112
|
+
*/
|
|
113
|
+
export function clearTableState(storageKey) {
|
|
114
|
+
if (!isBrowser)
|
|
115
|
+
return;
|
|
116
|
+
try {
|
|
117
|
+
localStorage.removeItem(`${storageKey}_column_visibility`);
|
|
118
|
+
localStorage.removeItem(`${storageKey}_column_sizing`);
|
|
119
|
+
localStorage.removeItem(`${storageKey}_column_filters`);
|
|
120
|
+
localStorage.removeItem(`${storageKey}_column_order`);
|
|
121
|
+
localStorage.removeItem(`${storageKey}_sorting`);
|
|
122
|
+
localStorage.removeItem(`${storageKey}_pagination`);
|
|
123
|
+
}
|
|
124
|
+
catch (error) {
|
|
125
|
+
console.error('Failed to clear table state:', error);
|
|
126
|
+
}
|
|
127
|
+
}
|
package/dist/types.d.ts
ADDED
|
@@ -0,0 +1,85 @@
|
|
|
1
|
+
import type { ColumnDef } from '@tanstack/svelte-table';
|
|
2
|
+
export interface TableKitProps<T = any> {
|
|
3
|
+
data: T[];
|
|
4
|
+
columns: ColumnDef<T>[];
|
|
5
|
+
config?: TableConfig;
|
|
6
|
+
features?: TableFeatures;
|
|
7
|
+
storageKey?: string;
|
|
8
|
+
persistState?: boolean;
|
|
9
|
+
theme?: 'light' | 'dark' | 'auto';
|
|
10
|
+
classNames?: Partial<ClassNameMap>;
|
|
11
|
+
onRowClick?: (row: T) => void;
|
|
12
|
+
onRowSelect?: (rows: T[]) => void;
|
|
13
|
+
onStateChange?: (state: TableState) => void;
|
|
14
|
+
}
|
|
15
|
+
export interface TableFeatures {
|
|
16
|
+
columnVisibility?: boolean;
|
|
17
|
+
columnResizing?: boolean;
|
|
18
|
+
columnReordering?: boolean;
|
|
19
|
+
filtering?: boolean;
|
|
20
|
+
sorting?: boolean;
|
|
21
|
+
pagination?: boolean;
|
|
22
|
+
rowSelection?: boolean;
|
|
23
|
+
grouping?: boolean;
|
|
24
|
+
columnPinning?: boolean;
|
|
25
|
+
}
|
|
26
|
+
export interface TableConfig {
|
|
27
|
+
id: string;
|
|
28
|
+
version: string;
|
|
29
|
+
defaultVisibleColumns?: string[];
|
|
30
|
+
defaultColumnOrder?: string[];
|
|
31
|
+
defaultColumnSizing?: Record<string, number>;
|
|
32
|
+
pinnedColumns?: {
|
|
33
|
+
left?: string[];
|
|
34
|
+
right?: string[];
|
|
35
|
+
};
|
|
36
|
+
defaultFilters?: FilterCondition[];
|
|
37
|
+
defaultSorting?: SortConfig[];
|
|
38
|
+
pagination?: {
|
|
39
|
+
pageSize: number;
|
|
40
|
+
pageSizeOptions?: number[];
|
|
41
|
+
};
|
|
42
|
+
presets?: ViewPreset[];
|
|
43
|
+
}
|
|
44
|
+
export interface ViewPreset {
|
|
45
|
+
id: string;
|
|
46
|
+
name: string;
|
|
47
|
+
description?: string;
|
|
48
|
+
config: Partial<TableConfig>;
|
|
49
|
+
}
|
|
50
|
+
export type FilterOperator = 'equals' | 'not_equals' | 'contains' | 'not_contains' | 'starts_with' | 'ends_with' | 'is_empty' | 'is_not_empty' | 'greater_than' | 'less_than' | 'greater_or_equal' | 'less_or_equal' | 'is_before' | 'is_after';
|
|
51
|
+
export type FilterLogic = 'and' | 'or';
|
|
52
|
+
export interface FilterCondition {
|
|
53
|
+
id: string;
|
|
54
|
+
field: string;
|
|
55
|
+
operator: FilterOperator;
|
|
56
|
+
value: any;
|
|
57
|
+
}
|
|
58
|
+
export interface SortConfig {
|
|
59
|
+
columnId: string;
|
|
60
|
+
direction: 'asc' | 'desc';
|
|
61
|
+
}
|
|
62
|
+
export interface ClassNameMap {
|
|
63
|
+
container: string;
|
|
64
|
+
table: string;
|
|
65
|
+
thead: string;
|
|
66
|
+
tbody: string;
|
|
67
|
+
tfoot: string;
|
|
68
|
+
tr: string;
|
|
69
|
+
th: string;
|
|
70
|
+
td: string;
|
|
71
|
+
pagination: string;
|
|
72
|
+
filterBar: string;
|
|
73
|
+
columnPicker: string;
|
|
74
|
+
}
|
|
75
|
+
export interface TableState {
|
|
76
|
+
columnVisibility: Record<string, boolean>;
|
|
77
|
+
columnOrder: string[];
|
|
78
|
+
columnSizing: Record<string, number>;
|
|
79
|
+
columnFilters: FilterCondition[];
|
|
80
|
+
sorting: SortConfig[];
|
|
81
|
+
pagination: {
|
|
82
|
+
pageIndex: number;
|
|
83
|
+
pageSize: number;
|
|
84
|
+
};
|
|
85
|
+
}
|
package/dist/types.js
ADDED
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
import type { TableConfig } from '../types';
|
|
2
|
+
/**
|
|
3
|
+
* Generate table configuration from AI parameters
|
|
4
|
+
* This is a placeholder for AI integration
|
|
5
|
+
*/
|
|
6
|
+
export declare function generateTableConfig(params: {
|
|
7
|
+
query: string;
|
|
8
|
+
availableColumns: any[];
|
|
9
|
+
userData?: Record<string, any>;
|
|
10
|
+
}): Partial<TableConfig>;
|
|
11
|
+
/**
|
|
12
|
+
* Validate table configuration against schema
|
|
13
|
+
*/
|
|
14
|
+
export declare function validateTableConfig(config: Partial<TableConfig>): boolean;
|
|
15
|
+
/**
|
|
16
|
+
* Merge multiple table configurations
|
|
17
|
+
*/
|
|
18
|
+
export declare function mergeConfigs(...configs: Partial<TableConfig>[]): TableConfig;
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
// Utilities for AI configuration generation and validation
|
|
2
|
+
/**
|
|
3
|
+
* Generate table configuration from AI parameters
|
|
4
|
+
* This is a placeholder for AI integration
|
|
5
|
+
*/
|
|
6
|
+
export function generateTableConfig(params) {
|
|
7
|
+
// TODO: Implement AI configuration generation
|
|
8
|
+
// This will be connected to Issue #4 (NL query AI agent)
|
|
9
|
+
console.log('Generating config for query:', params.query);
|
|
10
|
+
return {
|
|
11
|
+
id: 'ai-generated',
|
|
12
|
+
version: '1.0.0'
|
|
13
|
+
};
|
|
14
|
+
}
|
|
15
|
+
/**
|
|
16
|
+
* Validate table configuration against schema
|
|
17
|
+
*/
|
|
18
|
+
export function validateTableConfig(config) {
|
|
19
|
+
// TODO: Implement JSON schema validation
|
|
20
|
+
return !!config.id;
|
|
21
|
+
}
|
|
22
|
+
/**
|
|
23
|
+
* Merge multiple table configurations
|
|
24
|
+
*/
|
|
25
|
+
export function mergeConfigs(...configs) {
|
|
26
|
+
// TODO: Implement deep merge logic
|
|
27
|
+
return {
|
|
28
|
+
id: 'merged',
|
|
29
|
+
version: '1.0.0',
|
|
30
|
+
...Object.assign({}, ...configs)
|
|
31
|
+
};
|
|
32
|
+
}
|