@smartnet360/svelte-components 0.0.134 → 0.0.135
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/core/CellHistory/CellHistoryPanel.svelte +178 -0
- package/dist/core/CellHistory/CellHistoryPanel.svelte.d.ts +4 -0
- package/dist/core/CellHistory/column-config.d.ts +26 -0
- package/dist/core/CellHistory/column-config.js +120 -0
- package/dist/core/CellHistory/index.d.ts +9 -0
- package/dist/core/CellHistory/index.js +10 -0
- package/dist/core/CellHistory/transformers.d.ts +16 -0
- package/dist/core/CellHistory/transformers.js +76 -0
- package/dist/core/CellHistory/types.d.ts +54 -0
- package/dist/core/CellHistory/types.js +6 -0
- package/dist/core/CellTable/column-config.js +3 -1
- package/dist/core/CellTableV2/CellTable.svelte +601 -0
- package/dist/core/CellTableV2/CellTable.svelte.d.ts +43 -0
- package/dist/core/CellTableV2/CellTablePanel.svelte +685 -0
- package/dist/core/CellTableV2/CellTablePanel.svelte.d.ts +98 -0
- package/dist/core/CellTableV2/CellTableToolbar.svelte +322 -0
- package/dist/core/CellTableV2/CellTableToolbar.svelte.d.ts +59 -0
- package/dist/core/CellTableV2/ColumnPicker.svelte +214 -0
- package/dist/core/CellTableV2/ColumnPicker.svelte.d.ts +26 -0
- package/dist/core/CellTableV2/column-config.d.ts +120 -0
- package/dist/core/CellTableV2/column-config.js +671 -0
- package/dist/core/CellTableV2/composables/index.d.ts +12 -0
- package/dist/core/CellTableV2/composables/index.js +9 -0
- package/dist/core/CellTableV2/composables/useColumnVisibility.svelte.d.ts +45 -0
- package/dist/core/CellTableV2/composables/useColumnVisibility.svelte.js +98 -0
- package/dist/core/CellTableV2/composables/usePersistence.svelte.d.ts +28 -0
- package/dist/core/CellTableV2/composables/usePersistence.svelte.js +101 -0
- package/dist/core/CellTableV2/composables/useScrollSpy.svelte.d.ts +44 -0
- package/dist/core/CellTableV2/composables/useScrollSpy.svelte.js +91 -0
- package/dist/core/CellTableV2/index.d.ts +12 -0
- package/dist/core/CellTableV2/index.js +14 -0
- package/dist/core/CellTableV2/types.d.ts +172 -0
- package/dist/core/CellTableV2/types.js +6 -0
- package/dist/core/index.d.ts +2 -0
- package/dist/core/index.js +5 -0
- package/package.json +1 -1
|
@@ -0,0 +1,601 @@
|
|
|
1
|
+
<script lang="ts">
|
|
2
|
+
import { onMount, onDestroy } from 'svelte';
|
|
3
|
+
import { TabulatorFull as Tabulator } from 'tabulator-tables';
|
|
4
|
+
// Import Bootstrap 5 theme for proper styling
|
|
5
|
+
import 'tabulator-tables/dist/css/tabulator_bootstrap5.min.css';
|
|
6
|
+
import type { Options, RowComponent } from 'tabulator-tables';
|
|
7
|
+
import type { ColumnDefinition } from 'tabulator-tables';
|
|
8
|
+
import type {
|
|
9
|
+
CellTableProps,
|
|
10
|
+
CellData,
|
|
11
|
+
RowSelectionEvent,
|
|
12
|
+
RowClickEvent,
|
|
13
|
+
RowDblClickEvent,
|
|
14
|
+
RowContextMenuEvent,
|
|
15
|
+
DataChangeEvent
|
|
16
|
+
} from './types';
|
|
17
|
+
import {
|
|
18
|
+
getColumnsForPreset,
|
|
19
|
+
getGroupHeaderFormatter,
|
|
20
|
+
DEFAULT_TECH_COLORS,
|
|
21
|
+
DEFAULT_STATUS_COLORS,
|
|
22
|
+
cellDataSorter
|
|
23
|
+
} from './column-config';
|
|
24
|
+
|
|
25
|
+
// Type for Tabulator group component (not exported from tabulator-tables)
|
|
26
|
+
interface TabulatorGroup {
|
|
27
|
+
getKey(): string | number | boolean;
|
|
28
|
+
getRows(): RowComponent[];
|
|
29
|
+
scrollTo(): Promise<void>;
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
interface Props extends CellTableProps {
|
|
33
|
+
/** Custom column definitions (overrides columnPreset when provided) */
|
|
34
|
+
customColumns?: ColumnDefinition[];
|
|
35
|
+
/** Row selection change event */
|
|
36
|
+
onselectionchange?: (event: RowSelectionEvent) => void;
|
|
37
|
+
/** Row click event */
|
|
38
|
+
onrowclick?: (event: RowClickEvent) => void;
|
|
39
|
+
/** Row double-click event */
|
|
40
|
+
onrowdblclick?: (event: RowDblClickEvent) => void;
|
|
41
|
+
/** Row context menu (right-click) event */
|
|
42
|
+
onrowcontextmenu?: (event: RowContextMenuEvent) => void;
|
|
43
|
+
/** Data change event (filter, sort, etc.) */
|
|
44
|
+
ondatachange?: (event: DataChangeEvent) => void;
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
let {
|
|
48
|
+
cells = [],
|
|
49
|
+
groupBy = 'none',
|
|
50
|
+
columnPreset = 'default',
|
|
51
|
+
customColumns,
|
|
52
|
+
columnVisibility,
|
|
53
|
+
selectable = false,
|
|
54
|
+
multiSelect = true,
|
|
55
|
+
height = '100%',
|
|
56
|
+
virtualDom = true,
|
|
57
|
+
tabulatorOptions,
|
|
58
|
+
techColors = DEFAULT_TECH_COLORS,
|
|
59
|
+
statusColors = DEFAULT_STATUS_COLORS,
|
|
60
|
+
headerFilters = true,
|
|
61
|
+
resizableColumns = true,
|
|
62
|
+
movableColumns = true,
|
|
63
|
+
persistLayout = true,
|
|
64
|
+
storageKey = 'cell-table-layout',
|
|
65
|
+
onselectionchange,
|
|
66
|
+
onrowclick,
|
|
67
|
+
onrowdblclick,
|
|
68
|
+
onrowcontextmenu,
|
|
69
|
+
ondatachange
|
|
70
|
+
}: Props = $props();
|
|
71
|
+
|
|
72
|
+
let tableContainer: HTMLDivElement;
|
|
73
|
+
let table: Tabulator | null = null;
|
|
74
|
+
let isInitialized = $state(false);
|
|
75
|
+
|
|
76
|
+
// Reactive column configuration - uses customColumns if provided, otherwise preset
|
|
77
|
+
let columns = $derived.by(() => {
|
|
78
|
+
// Use custom columns if provided, otherwise get from preset
|
|
79
|
+
const baseColumns = customColumns ?? getColumnsForPreset(columnPreset, techColors, statusColors, headerFilters);
|
|
80
|
+
|
|
81
|
+
// Add row selection checkbox column if selectable
|
|
82
|
+
if (selectable) {
|
|
83
|
+
const selectColumn = {
|
|
84
|
+
title: '',
|
|
85
|
+
formatter: 'rowSelection',
|
|
86
|
+
titleFormatter: multiSelect ? 'rowSelection' : undefined,
|
|
87
|
+
hozAlign: 'center' as const,
|
|
88
|
+
headerSort: false,
|
|
89
|
+
width: 40,
|
|
90
|
+
frozen: true,
|
|
91
|
+
cssClass: 'cell-table-select-column',
|
|
92
|
+
};
|
|
93
|
+
return [selectColumn, ...baseColumns];
|
|
94
|
+
}
|
|
95
|
+
|
|
96
|
+
return baseColumns;
|
|
97
|
+
});
|
|
98
|
+
|
|
99
|
+
// Pre-sort data using our custom multi-level sorter
|
|
100
|
+
let sortedCells = $derived.by(() => {
|
|
101
|
+
return [...cells].sort(cellDataSorter);
|
|
102
|
+
});
|
|
103
|
+
|
|
104
|
+
// Build Tabulator options
|
|
105
|
+
function buildOptions(): Options {
|
|
106
|
+
const baseOptions: Options = {
|
|
107
|
+
data: sortedCells,
|
|
108
|
+
columns: columns,
|
|
109
|
+
layout: 'fitDataFill',
|
|
110
|
+
height: height,
|
|
111
|
+
placeholder: 'No cells to display',
|
|
112
|
+
|
|
113
|
+
// Virtual DOM for performance with large datasets
|
|
114
|
+
renderVertical: virtualDom ? 'virtual' : 'basic',
|
|
115
|
+
|
|
116
|
+
// Interactivity
|
|
117
|
+
resizableColumns: resizableColumns,
|
|
118
|
+
movableColumns: movableColumns,
|
|
119
|
+
|
|
120
|
+
// No initialSort - data is pre-sorted by cellDataSorter (tech → fband → sector)
|
|
121
|
+
|
|
122
|
+
// Row selection
|
|
123
|
+
selectable: selectable ? (multiSelect ? true : 1) : false,
|
|
124
|
+
selectableRangeMode: 'click',
|
|
125
|
+
|
|
126
|
+
// Persistence - save column widths, order, visibility and group settings
|
|
127
|
+
persistence: persistLayout ? {
|
|
128
|
+
columns: ['width', 'visible', 'order'],
|
|
129
|
+
group: true,
|
|
130
|
+
} : false,
|
|
131
|
+
persistenceMode: persistLayout ? 'local' : undefined,
|
|
132
|
+
persistenceID: persistLayout ? storageKey : undefined,
|
|
133
|
+
|
|
134
|
+
// Grouping
|
|
135
|
+
...(groupBy !== 'none' ? {
|
|
136
|
+
groupBy: groupBy,
|
|
137
|
+
groupStartOpen: true,
|
|
138
|
+
groupHeader: getGroupHeaderFormatter(groupBy),
|
|
139
|
+
groupToggleElement: 'header',
|
|
140
|
+
} : {}),
|
|
141
|
+
|
|
142
|
+
// Pagination (optional, disabled by default for virtual scrolling)
|
|
143
|
+
// pagination: true,
|
|
144
|
+
// paginationSize: 50,
|
|
145
|
+
|
|
146
|
+
// Clipboard
|
|
147
|
+
clipboard: true,
|
|
148
|
+
clipboardCopyRowRange: 'selected',
|
|
149
|
+
};
|
|
150
|
+
|
|
151
|
+
// Merge with custom options
|
|
152
|
+
return { ...baseOptions, ...tabulatorOptions };
|
|
153
|
+
}
|
|
154
|
+
|
|
155
|
+
// Initialize table
|
|
156
|
+
function initTable() {
|
|
157
|
+
if (!tableContainer) return;
|
|
158
|
+
|
|
159
|
+
const options = buildOptions();
|
|
160
|
+
table = new Tabulator(tableContainer, options);
|
|
161
|
+
|
|
162
|
+
// Bind events
|
|
163
|
+
table.on('rowClick', (e, row) => {
|
|
164
|
+
if (onrowclick) {
|
|
165
|
+
onrowclick({
|
|
166
|
+
row: (row as RowComponent).getData() as CellData,
|
|
167
|
+
event: e as MouseEvent
|
|
168
|
+
});
|
|
169
|
+
}
|
|
170
|
+
});
|
|
171
|
+
|
|
172
|
+
table.on('rowDblClick', (e, row) => {
|
|
173
|
+
if (onrowdblclick) {
|
|
174
|
+
onrowdblclick({
|
|
175
|
+
row: (row as RowComponent).getData() as CellData,
|
|
176
|
+
event: e as MouseEvent
|
|
177
|
+
});
|
|
178
|
+
}
|
|
179
|
+
});
|
|
180
|
+
|
|
181
|
+
table.on('rowContext', (e, row) => {
|
|
182
|
+
if (onrowcontextmenu) {
|
|
183
|
+
(e as MouseEvent).preventDefault();
|
|
184
|
+
onrowcontextmenu({
|
|
185
|
+
row: (row as RowComponent).getData() as CellData,
|
|
186
|
+
event: e as MouseEvent
|
|
187
|
+
});
|
|
188
|
+
}
|
|
189
|
+
});
|
|
190
|
+
|
|
191
|
+
table.on('rowSelectionChanged', (data, rows) => {
|
|
192
|
+
if (onselectionchange) {
|
|
193
|
+
const cellData = data as CellData[];
|
|
194
|
+
onselectionchange({
|
|
195
|
+
rows: cellData,
|
|
196
|
+
ids: cellData.map(d => d.id)
|
|
197
|
+
});
|
|
198
|
+
}
|
|
199
|
+
});
|
|
200
|
+
|
|
201
|
+
table.on('dataFiltered', (filters, rows) => {
|
|
202
|
+
if (ondatachange) {
|
|
203
|
+
ondatachange({
|
|
204
|
+
type: 'filter',
|
|
205
|
+
rowCount: cells.length,
|
|
206
|
+
filteredCount: (rows as RowComponent[]).length
|
|
207
|
+
});
|
|
208
|
+
}
|
|
209
|
+
});
|
|
210
|
+
|
|
211
|
+
table.on('dataSorted', () => {
|
|
212
|
+
if (ondatachange) {
|
|
213
|
+
ondatachange({
|
|
214
|
+
type: 'sort',
|
|
215
|
+
rowCount: cells.length,
|
|
216
|
+
filteredCount: table?.getDataCount('active') ?? 0
|
|
217
|
+
});
|
|
218
|
+
}
|
|
219
|
+
});
|
|
220
|
+
|
|
221
|
+
// Mark as initialized after table is ready
|
|
222
|
+
table.on('tableBuilt', () => {
|
|
223
|
+
isInitialized = true;
|
|
224
|
+
// Fire initial data change event
|
|
225
|
+
if (ondatachange) {
|
|
226
|
+
ondatachange({
|
|
227
|
+
type: 'load',
|
|
228
|
+
rowCount: cells.length,
|
|
229
|
+
filteredCount: cells.length
|
|
230
|
+
});
|
|
231
|
+
}
|
|
232
|
+
});
|
|
233
|
+
}
|
|
234
|
+
|
|
235
|
+
// Track previous values to avoid unnecessary updates
|
|
236
|
+
let prevCellsRef: unknown[] | null = null;
|
|
237
|
+
let prevGroupBy: string | null = null;
|
|
238
|
+
// Initialize with current preset to prevent setColumns on first load (which would override persisted layout)
|
|
239
|
+
let prevColumnPreset: string | null = columnPreset;
|
|
240
|
+
|
|
241
|
+
// Update table data when cells change (reference comparison)
|
|
242
|
+
$effect(() => {
|
|
243
|
+
// Track the cells array reference to detect any change
|
|
244
|
+
const currentRef = sortedCells;
|
|
245
|
+
|
|
246
|
+
// Update if reference changed (new array assignment)
|
|
247
|
+
if (isInitialized && table && currentRef !== prevCellsRef) {
|
|
248
|
+
prevCellsRef = currentRef;
|
|
249
|
+
table.replaceData(sortedCells);
|
|
250
|
+
ondatachange?.({
|
|
251
|
+
type: 'load',
|
|
252
|
+
rowCount: sortedCells.length,
|
|
253
|
+
filteredCount: sortedCells.length
|
|
254
|
+
});
|
|
255
|
+
}
|
|
256
|
+
});
|
|
257
|
+
|
|
258
|
+
// Update grouping when groupBy changes
|
|
259
|
+
$effect(() => {
|
|
260
|
+
if (isInitialized && table && groupBy !== prevGroupBy) {
|
|
261
|
+
prevGroupBy = groupBy;
|
|
262
|
+
if (groupBy === 'none') {
|
|
263
|
+
table.setGroupBy(false);
|
|
264
|
+
} else {
|
|
265
|
+
table.setGroupBy(groupBy);
|
|
266
|
+
table.setGroupHeader(getGroupHeaderFormatter(groupBy));
|
|
267
|
+
}
|
|
268
|
+
}
|
|
269
|
+
});
|
|
270
|
+
|
|
271
|
+
// Update columns when preset changes
|
|
272
|
+
$effect(() => {
|
|
273
|
+
if (isInitialized && table && columnPreset !== prevColumnPreset) {
|
|
274
|
+
prevColumnPreset = columnPreset;
|
|
275
|
+
table.setColumns(columns);
|
|
276
|
+
}
|
|
277
|
+
});
|
|
278
|
+
|
|
279
|
+
onMount(() => {
|
|
280
|
+
initTable();
|
|
281
|
+
});
|
|
282
|
+
|
|
283
|
+
onDestroy(() => {
|
|
284
|
+
if (table) {
|
|
285
|
+
table.destroy();
|
|
286
|
+
table = null;
|
|
287
|
+
}
|
|
288
|
+
});
|
|
289
|
+
|
|
290
|
+
// Public API methods
|
|
291
|
+
export function getTable(): Tabulator | null {
|
|
292
|
+
return table;
|
|
293
|
+
}
|
|
294
|
+
|
|
295
|
+
export function getSelectedRows(): CellData[] {
|
|
296
|
+
return table?.getSelectedData() as CellData[] ?? [];
|
|
297
|
+
}
|
|
298
|
+
|
|
299
|
+
export function clearSelection(): void {
|
|
300
|
+
table?.deselectRow();
|
|
301
|
+
}
|
|
302
|
+
|
|
303
|
+
export function selectRow(id: string): void {
|
|
304
|
+
const row = table?.getRow(id);
|
|
305
|
+
if (row) row.select();
|
|
306
|
+
}
|
|
307
|
+
|
|
308
|
+
export function scrollToRow(id: string): void {
|
|
309
|
+
table?.scrollToRow(id, 'top', true);
|
|
310
|
+
}
|
|
311
|
+
|
|
312
|
+
export function downloadCSV(filename: string = 'cells.csv'): void {
|
|
313
|
+
table?.download('csv', filename);
|
|
314
|
+
}
|
|
315
|
+
|
|
316
|
+
export function downloadJSON(filename: string = 'cells.json'): void {
|
|
317
|
+
table?.download('json', filename);
|
|
318
|
+
}
|
|
319
|
+
|
|
320
|
+
export function setFilter(field: string, type: string, value: unknown): void {
|
|
321
|
+
table?.setFilter(field, type as any, value);
|
|
322
|
+
}
|
|
323
|
+
|
|
324
|
+
export function clearFilters(): void {
|
|
325
|
+
if (!table) return;
|
|
326
|
+
// Clear programmatic filters
|
|
327
|
+
table.clearFilter();
|
|
328
|
+
// Clear header filter inputs
|
|
329
|
+
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
330
|
+
(table as any).clearHeaderFilter();
|
|
331
|
+
}
|
|
332
|
+
|
|
333
|
+
export function redraw(): void {
|
|
334
|
+
table?.redraw(true);
|
|
335
|
+
}
|
|
336
|
+
|
|
337
|
+
export function collapseAll(): void {
|
|
338
|
+
if (!table) return;
|
|
339
|
+
// Use setGroupStartOpen to collapse all groups, then refresh data to apply
|
|
340
|
+
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
341
|
+
(table as any).setGroupStartOpen(false);
|
|
342
|
+
table.setData(table.getData());
|
|
343
|
+
}
|
|
344
|
+
|
|
345
|
+
export function expandAll(): void {
|
|
346
|
+
if (!table) return;
|
|
347
|
+
// Use setGroupStartOpen to expand all groups, then refresh data to apply
|
|
348
|
+
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
349
|
+
(table as any).setGroupStartOpen(true);
|
|
350
|
+
table.setData(table.getData());
|
|
351
|
+
}
|
|
352
|
+
|
|
353
|
+
export function toggleHeaderFilters(visible: boolean): void {
|
|
354
|
+
if (!table) return;
|
|
355
|
+
const headerFiltersElement = tableContainer.querySelector('.tabulator-header-filter');
|
|
356
|
+
if (headerFiltersElement) {
|
|
357
|
+
// Toggle all header filter rows
|
|
358
|
+
const filterRows = tableContainer.querySelectorAll('.tabulator-col .tabulator-header-filter');
|
|
359
|
+
filterRows.forEach(el => {
|
|
360
|
+
(el as HTMLElement).style.display = visible ? '' : 'none';
|
|
361
|
+
});
|
|
362
|
+
table.redraw();
|
|
363
|
+
}
|
|
364
|
+
}
|
|
365
|
+
|
|
366
|
+
export function showColumn(field: string): void {
|
|
367
|
+
table?.showColumn(field);
|
|
368
|
+
}
|
|
369
|
+
|
|
370
|
+
export function hideColumn(field: string): void {
|
|
371
|
+
table?.hideColumn(field);
|
|
372
|
+
}
|
|
373
|
+
|
|
374
|
+
export function getVisibleColumns(): string[] {
|
|
375
|
+
if (!table) return [];
|
|
376
|
+
const columns = table.getColumns();
|
|
377
|
+
return columns
|
|
378
|
+
.filter(col => col.isVisible())
|
|
379
|
+
.map(col => col.getField())
|
|
380
|
+
.filter((field): field is string => !!field);
|
|
381
|
+
}
|
|
382
|
+
|
|
383
|
+
/** Get all group keys (when grouping is active) */
|
|
384
|
+
export function getGroups(): { key: string; count: number }[] {
|
|
385
|
+
if (!table || groupBy === 'none') return [];
|
|
386
|
+
try {
|
|
387
|
+
const groups = table.getGroups() as TabulatorGroup[];
|
|
388
|
+
return groups.map(g => ({
|
|
389
|
+
key: String(g.getKey()),
|
|
390
|
+
count: g.getRows().length
|
|
391
|
+
}));
|
|
392
|
+
} catch {
|
|
393
|
+
return [];
|
|
394
|
+
}
|
|
395
|
+
}
|
|
396
|
+
|
|
397
|
+
/** Scroll to a specific group by key */
|
|
398
|
+
export function scrollToGroup(key: string): void {
|
|
399
|
+
if (!table || groupBy === 'none') return;
|
|
400
|
+
try {
|
|
401
|
+
const groups = table.getGroups() as TabulatorGroup[];
|
|
402
|
+
const group = groups.find(g => String(g.getKey()) === key);
|
|
403
|
+
if (group) {
|
|
404
|
+
group.scrollTo();
|
|
405
|
+
}
|
|
406
|
+
} catch (e) {
|
|
407
|
+
console.warn('Failed to scroll to group:', e);
|
|
408
|
+
}
|
|
409
|
+
}
|
|
410
|
+
</script>
|
|
411
|
+
|
|
412
|
+
<div class="cell-table-container">
|
|
413
|
+
<div bind:this={tableContainer} class="cell-table"></div>
|
|
414
|
+
</div>
|
|
415
|
+
|
|
416
|
+
<style>
|
|
417
|
+
.cell-table-container {
|
|
418
|
+
width: 100%;
|
|
419
|
+
height: 100%;
|
|
420
|
+
display: flex;
|
|
421
|
+
flex-direction: column;
|
|
422
|
+
}
|
|
423
|
+
|
|
424
|
+
.cell-table {
|
|
425
|
+
flex: 1;
|
|
426
|
+
min-height: 0;
|
|
427
|
+
}
|
|
428
|
+
|
|
429
|
+
/* Bootstrap-aligned Tabulator theme overrides */
|
|
430
|
+
:global(.cell-table-container .tabulator) {
|
|
431
|
+
font-family: var(--bs-body-font-family, system-ui, -apple-system, "Segoe UI", Roboto, "Helvetica Neue", Arial, sans-serif);
|
|
432
|
+
font-size: 0.875rem;
|
|
433
|
+
border: 1px solid var(--bs-border-color, #dee2e6);
|
|
434
|
+
border-radius: var(--bs-border-radius, 0.375rem);
|
|
435
|
+
background-color: var(--bs-body-bg, #fff);
|
|
436
|
+
}
|
|
437
|
+
|
|
438
|
+
/* Header styling */
|
|
439
|
+
:global(.cell-table-container .tabulator-header) {
|
|
440
|
+
background-color: var(--bs-tertiary-bg, #f8f9fa);
|
|
441
|
+
border-bottom: 2px solid var(--bs-border-color, #dee2e6);
|
|
442
|
+
}
|
|
443
|
+
|
|
444
|
+
:global(.cell-table-container .tabulator-col) {
|
|
445
|
+
background-color: var(--bs-tertiary-bg, #f8f9fa);
|
|
446
|
+
border-right: 1px solid var(--bs-border-color, #dee2e6);
|
|
447
|
+
}
|
|
448
|
+
|
|
449
|
+
:global(.cell-table-container .tabulator-col-title) {
|
|
450
|
+
font-weight: 600;
|
|
451
|
+
color: var(--bs-body-color, #212529);
|
|
452
|
+
padding: 0.5rem 0.75rem;
|
|
453
|
+
}
|
|
454
|
+
|
|
455
|
+
:global(.cell-table-container .tabulator-col-sorter) {
|
|
456
|
+
color: var(--bs-secondary-color, #6c757d);
|
|
457
|
+
}
|
|
458
|
+
|
|
459
|
+
/* Header filter inputs */
|
|
460
|
+
:global(.cell-table-container .tabulator-header-filter input) {
|
|
461
|
+
font-size: 0.75rem;
|
|
462
|
+
padding: 0.25rem 0.5rem;
|
|
463
|
+
border: 1px solid var(--bs-border-color, #dee2e6);
|
|
464
|
+
border-radius: var(--bs-border-radius-sm, 0.25rem);
|
|
465
|
+
background-color: var(--bs-body-bg, #fff);
|
|
466
|
+
color: var(--bs-body-color, #212529);
|
|
467
|
+
}
|
|
468
|
+
|
|
469
|
+
:global(.cell-table-container .tabulator-header-filter input:focus) {
|
|
470
|
+
border-color: var(--bs-primary, #0d6efd);
|
|
471
|
+
outline: 0;
|
|
472
|
+
box-shadow: 0 0 0 0.2rem rgba(13, 110, 253, 0.25);
|
|
473
|
+
}
|
|
474
|
+
|
|
475
|
+
/* Row styling */
|
|
476
|
+
:global(.cell-table-container .tabulator-row) {
|
|
477
|
+
border-bottom: 1px solid var(--bs-border-color-translucent, rgba(0, 0, 0, 0.1));
|
|
478
|
+
}
|
|
479
|
+
|
|
480
|
+
:global(.cell-table-container .tabulator-row:hover) {
|
|
481
|
+
background-color: var(--bs-tertiary-bg, #f8f9fa);
|
|
482
|
+
}
|
|
483
|
+
|
|
484
|
+
:global(.cell-table-container .tabulator-row.tabulator-row-even) {
|
|
485
|
+
background-color: var(--bs-body-bg, #fff);
|
|
486
|
+
}
|
|
487
|
+
|
|
488
|
+
:global(.cell-table-container .tabulator-row.tabulator-row-odd) {
|
|
489
|
+
background-color: rgba(var(--bs-tertiary-bg-rgb, 248, 249, 250), 0.5);
|
|
490
|
+
}
|
|
491
|
+
|
|
492
|
+
:global(.cell-table-container .tabulator-row.tabulator-selected) {
|
|
493
|
+
background-color: rgba(var(--bs-primary-rgb, 13, 110, 253), 0.1);
|
|
494
|
+
}
|
|
495
|
+
|
|
496
|
+
:global(.cell-table-container .tabulator-row.tabulator-selected:hover) {
|
|
497
|
+
background-color: rgba(var(--bs-primary-rgb, 13, 110, 253), 0.15);
|
|
498
|
+
}
|
|
499
|
+
|
|
500
|
+
/* Cell styling */
|
|
501
|
+
:global(.cell-table-container .tabulator-cell) {
|
|
502
|
+
padding: 0.5rem 0.75rem;
|
|
503
|
+
border-right: 1px solid var(--bs-border-color-translucent, rgba(0, 0, 0, 0.05));
|
|
504
|
+
color: var(--bs-body-color, #212529);
|
|
505
|
+
}
|
|
506
|
+
|
|
507
|
+
:global(.cell-table-container .tabulator-cell.tabulator-frozen) {
|
|
508
|
+
background-color: var(--bs-tertiary-bg, #f8f9fa);
|
|
509
|
+
border-right: 2px solid var(--bs-border-color, #dee2e6);
|
|
510
|
+
}
|
|
511
|
+
|
|
512
|
+
/* Group header styling */
|
|
513
|
+
:global(.cell-table-container .tabulator-row.tabulator-group) {
|
|
514
|
+
background-color: var(--bs-secondary-bg, #e9ecef);
|
|
515
|
+
border-bottom: 1px solid var(--bs-border-color, #dee2e6);
|
|
516
|
+
font-weight: 500;
|
|
517
|
+
min-height: 36px;
|
|
518
|
+
}
|
|
519
|
+
|
|
520
|
+
:global(.cell-table-container .tabulator-row.tabulator-group:hover) {
|
|
521
|
+
background-color: var(--bs-secondary-bg, #e9ecef);
|
|
522
|
+
cursor: pointer;
|
|
523
|
+
}
|
|
524
|
+
|
|
525
|
+
:global(.cell-table-container .tabulator-row.tabulator-group span) {
|
|
526
|
+
color: var(--bs-body-color, #212529);
|
|
527
|
+
}
|
|
528
|
+
|
|
529
|
+
/* Group toggle arrow */
|
|
530
|
+
:global(.cell-table-container .tabulator-group-toggle) {
|
|
531
|
+
margin-right: 0.5rem;
|
|
532
|
+
}
|
|
533
|
+
|
|
534
|
+
/* Scrollbar styling */
|
|
535
|
+
:global(.cell-table-container .tabulator-tableholder::-webkit-scrollbar) {
|
|
536
|
+
width: 8px;
|
|
537
|
+
height: 8px;
|
|
538
|
+
}
|
|
539
|
+
|
|
540
|
+
:global(.cell-table-container .tabulator-tableholder::-webkit-scrollbar-track) {
|
|
541
|
+
background: var(--bs-tertiary-bg, #f8f9fa);
|
|
542
|
+
}
|
|
543
|
+
|
|
544
|
+
:global(.cell-table-container .tabulator-tableholder::-webkit-scrollbar-thumb) {
|
|
545
|
+
background: var(--bs-secondary-color, #6c757d);
|
|
546
|
+
border-radius: 4px;
|
|
547
|
+
}
|
|
548
|
+
|
|
549
|
+
:global(.cell-table-container .tabulator-tableholder::-webkit-scrollbar-thumb:hover) {
|
|
550
|
+
background: var(--bs-body-color, #212529);
|
|
551
|
+
}
|
|
552
|
+
|
|
553
|
+
/* Placeholder */
|
|
554
|
+
:global(.cell-table-container .tabulator-placeholder) {
|
|
555
|
+
color: var(--bs-secondary-color, #6c757d);
|
|
556
|
+
font-style: italic;
|
|
557
|
+
}
|
|
558
|
+
|
|
559
|
+
/* Resize handle */
|
|
560
|
+
:global(.cell-table-container .tabulator-col-resize-handle) {
|
|
561
|
+
width: 6px;
|
|
562
|
+
right: 0;
|
|
563
|
+
}
|
|
564
|
+
|
|
565
|
+
:global(.cell-table-container .tabulator-col-resize-handle:hover) {
|
|
566
|
+
background-color: var(--bs-primary, #0d6efd);
|
|
567
|
+
}
|
|
568
|
+
|
|
569
|
+
/* Footer/pagination (if enabled) */
|
|
570
|
+
:global(.cell-table-container .tabulator-footer) {
|
|
571
|
+
background-color: var(--bs-tertiary-bg, #f8f9fa);
|
|
572
|
+
border-top: 1px solid var(--bs-border-color, #dee2e6);
|
|
573
|
+
padding: 0.5rem;
|
|
574
|
+
}
|
|
575
|
+
|
|
576
|
+
:global(.cell-table-container .tabulator-page) {
|
|
577
|
+
padding: 0.25rem 0.5rem;
|
|
578
|
+
margin: 0 0.125rem;
|
|
579
|
+
border: 1px solid var(--bs-border-color, #dee2e6);
|
|
580
|
+
border-radius: var(--bs-border-radius-sm, 0.25rem);
|
|
581
|
+
background-color: var(--bs-body-bg, #fff);
|
|
582
|
+
color: var(--bs-body-color, #212529);
|
|
583
|
+
}
|
|
584
|
+
|
|
585
|
+
:global(.cell-table-container .tabulator-page:hover) {
|
|
586
|
+
background-color: var(--bs-tertiary-bg, #f8f9fa);
|
|
587
|
+
}
|
|
588
|
+
|
|
589
|
+
:global(.cell-table-container .tabulator-page.active) {
|
|
590
|
+
background-color: var(--bs-primary, #0d6efd);
|
|
591
|
+
border-color: var(--bs-primary, #0d6efd);
|
|
592
|
+
color: white;
|
|
593
|
+
}
|
|
594
|
+
|
|
595
|
+
/* Badge styling in cells */
|
|
596
|
+
:global(.cell-table-container .badge) {
|
|
597
|
+
font-weight: 500;
|
|
598
|
+
padding: 0.25em 0.5em;
|
|
599
|
+
border-radius: var(--bs-border-radius-sm, 0.25rem);
|
|
600
|
+
}
|
|
601
|
+
</style>
|
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
import { TabulatorFull as Tabulator } from 'tabulator-tables';
|
|
2
|
+
import 'tabulator-tables/dist/css/tabulator_bootstrap5.min.css';
|
|
3
|
+
import type { ColumnDefinition } from 'tabulator-tables';
|
|
4
|
+
import type { CellTableProps, CellData, RowSelectionEvent, RowClickEvent, RowDblClickEvent, RowContextMenuEvent, DataChangeEvent } from './types';
|
|
5
|
+
interface Props extends CellTableProps {
|
|
6
|
+
/** Custom column definitions (overrides columnPreset when provided) */
|
|
7
|
+
customColumns?: ColumnDefinition[];
|
|
8
|
+
/** Row selection change event */
|
|
9
|
+
onselectionchange?: (event: RowSelectionEvent) => void;
|
|
10
|
+
/** Row click event */
|
|
11
|
+
onrowclick?: (event: RowClickEvent) => void;
|
|
12
|
+
/** Row double-click event */
|
|
13
|
+
onrowdblclick?: (event: RowDblClickEvent) => void;
|
|
14
|
+
/** Row context menu (right-click) event */
|
|
15
|
+
onrowcontextmenu?: (event: RowContextMenuEvent) => void;
|
|
16
|
+
/** Data change event (filter, sort, etc.) */
|
|
17
|
+
ondatachange?: (event: DataChangeEvent) => void;
|
|
18
|
+
}
|
|
19
|
+
declare const CellTable: import("svelte").Component<Props, {
|
|
20
|
+
getTable: () => Tabulator | null;
|
|
21
|
+
getSelectedRows: () => CellData[];
|
|
22
|
+
clearSelection: () => void;
|
|
23
|
+
selectRow: (id: string) => void;
|
|
24
|
+
scrollToRow: (id: string) => void;
|
|
25
|
+
downloadCSV: (filename?: string) => void;
|
|
26
|
+
downloadJSON: (filename?: string) => void;
|
|
27
|
+
setFilter: (field: string, type: string, value: unknown) => void;
|
|
28
|
+
clearFilters: () => void;
|
|
29
|
+
redraw: () => void;
|
|
30
|
+
collapseAll: () => void;
|
|
31
|
+
expandAll: () => void;
|
|
32
|
+
toggleHeaderFilters: (visible: boolean) => void;
|
|
33
|
+
showColumn: (field: string) => void;
|
|
34
|
+
hideColumn: (field: string) => void;
|
|
35
|
+
getVisibleColumns: () => string[];
|
|
36
|
+
getGroups: () => {
|
|
37
|
+
key: string;
|
|
38
|
+
count: number;
|
|
39
|
+
}[];
|
|
40
|
+
scrollToGroup: (key: string) => void;
|
|
41
|
+
}, "">;
|
|
42
|
+
type CellTable = ReturnType<typeof CellTable>;
|
|
43
|
+
export default CellTable;
|