@beeblock/svelar-datatable 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.
Files changed (44) hide show
  1. package/README.md +149 -0
  2. package/dist/SvelarDatatablePlugin.d.ts +13 -0
  3. package/dist/export/ExportManager.d.ts +4 -0
  4. package/dist/export/clipboard.d.ts +2 -0
  5. package/dist/export/csv.d.ts +4 -0
  6. package/dist/export/excel.d.ts +2 -0
  7. package/dist/export/index.d.ts +6 -0
  8. package/dist/export/pdf.d.ts +2 -0
  9. package/dist/export/print.d.ts +2 -0
  10. package/dist/index.d.ts +5 -0
  11. package/dist/index.js +19 -0
  12. package/dist/server/DataTableController.d.ts +4 -0
  13. package/dist/server/DataTableRequest.d.ts +3 -0
  14. package/dist/server/DataTableService.d.ts +25 -0
  15. package/dist/server/index.d.ts +3 -0
  16. package/dist/server/index.js +1 -0
  17. package/dist/state/DataTableStore.d.ts +64 -0
  18. package/dist/state/ServerDataTableStore.d.ts +23 -0
  19. package/dist/state/index.d.ts +2 -0
  20. package/dist/types.d.ts +208 -0
  21. package/dist/types.js +0 -0
  22. package/dist/ui/index.d.ts +20 -0
  23. package/package.json +45 -0
  24. package/src/ui/DataTable.svelte +385 -0
  25. package/src/ui/DataTableBody.svelte +180 -0
  26. package/src/ui/DataTableBubbleEditor.svelte +93 -0
  27. package/src/ui/DataTableButtons.svelte +139 -0
  28. package/src/ui/DataTableCell.svelte +381 -0
  29. package/src/ui/DataTableColumnToggle.svelte +111 -0
  30. package/src/ui/DataTableEditor.svelte +27 -0
  31. package/src/ui/DataTableEditorField.svelte +190 -0
  32. package/src/ui/DataTableEditorForm.svelte +94 -0
  33. package/src/ui/DataTableEmpty.svelte +40 -0
  34. package/src/ui/DataTableExpandedRow.svelte +37 -0
  35. package/src/ui/DataTableFooter.svelte +65 -0
  36. package/src/ui/DataTableHead.svelte +169 -0
  37. package/src/ui/DataTableLoading.svelte +44 -0
  38. package/src/ui/DataTableModalEditor.svelte +126 -0
  39. package/src/ui/DataTablePagination.svelte +205 -0
  40. package/src/ui/DataTableRow.svelte +192 -0
  41. package/src/ui/DataTableSearch.svelte +95 -0
  42. package/src/ui/DataTableToolbar.svelte +164 -0
  43. package/src/ui/index.ts +20 -0
  44. package/src/ui/virtual/VirtualScroller.svelte +62 -0
@@ -0,0 +1,164 @@
1
+ <script lang="ts">
2
+ import type { ColumnDef, ButtonDef, ExportFormat, DataTableStore, EditorMode, DataTableClassNames } from '../index.js';
3
+ import DataTableSearch from './DataTableSearch.svelte';
4
+ import DataTableColumnToggle from './DataTableColumnToggle.svelte';
5
+ import DataTableButtons from './DataTableButtons.svelte';
6
+
7
+ interface Props {
8
+ store: DataTableStore;
9
+ columns: ColumnDef[];
10
+ searchable?: boolean;
11
+ searchDebounceMs?: number;
12
+ buttons?: (ButtonDef | ExportFormat)[];
13
+ editorMode?: EditorMode;
14
+ classNames?: DataTableClassNames;
15
+ onCreateClick?: () => void;
16
+ onEditClick?: (rows: any[]) => void;
17
+ onDeleteClick?: (rows: any[]) => void;
18
+ }
19
+ let {
20
+ store,
21
+ columns,
22
+ searchable = true,
23
+ searchDebounceMs = 300,
24
+ buttons,
25
+ editorMode,
26
+ classNames = {},
27
+ onCreateClick,
28
+ onEditClick,
29
+ onDeleteClick,
30
+ }: Props = $props();
31
+
32
+ let state = $state(store.getState());
33
+ $effect(() => {
34
+ return store.subscribe(() => {
35
+ state = store.getState();
36
+ });
37
+ });
38
+
39
+ let selectedCount = $derived(state.selectedIds.size);
40
+
41
+ function handleCreate() {
42
+ if (onCreateClick) {
43
+ onCreateClick();
44
+ } else {
45
+ // Create always uses modal — bubble/inline don't support create forms
46
+ store.openEditor(null, null, 'modal');
47
+ }
48
+ }
49
+
50
+ function handleEdit() {
51
+ const selected = store.getSelectedRows();
52
+ if (onEditClick) {
53
+ onEditClick(selected);
54
+ } else if (selected.length === 1) {
55
+ const mode = editorMode === 'bubble' ? 'bubble' : 'modal';
56
+ store.openEditor(store.getRowId(selected[0]), null, mode);
57
+ }
58
+ }
59
+
60
+ function handleDelete() {
61
+ const selected = store.getSelectedRows();
62
+ if (onDeleteClick) {
63
+ onDeleteClick(selected);
64
+ }
65
+ }
66
+ </script>
67
+
68
+ <div class="sdt-toolbar {classNames.toolbar ?? ''}">
69
+ <div class="sdt-toolbar-left {classNames.toolbarLeft ?? ''}">
70
+ {#if searchable}
71
+ <DataTableSearch {store} debounceMs={searchDebounceMs} searchInputClass={classNames.searchInput} />
72
+ {/if}
73
+ </div>
74
+
75
+ <div class="sdt-toolbar-right {classNames.toolbarRight ?? ''}">
76
+ {#if editorMode && editorMode !== 'excel'}
77
+ <button type="button" class="sdt-toolbar-btn sdt-toolbar-btn-create {classNames.btnCreate ?? ''}" onclick={handleCreate}>
78
+ <svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" width="14" height="14">
79
+ <path d="M12 5v14M5 12h14" />
80
+ </svg>
81
+ New
82
+ </button>
83
+ {#if selectedCount === 1}
84
+ <button type="button" class="sdt-toolbar-btn sdt-toolbar-btn-edit {classNames.btnEdit ?? ''}" onclick={handleEdit}>
85
+ <svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" width="14" height="14">
86
+ <path d="M11 4H4a2 2 0 0 0-2 2v14a2 2 0 0 0 2 2h14a2 2 0 0 0 2-2v-7" />
87
+ <path d="M18.5 2.5a2.121 2.121 0 0 1 3 3L12 15l-4 1 1-4 9.5-9.5z" />
88
+ </svg>
89
+ Edit
90
+ </button>
91
+ {/if}
92
+ {#if selectedCount > 0 && onDeleteClick}
93
+ <button type="button" class="sdt-toolbar-btn sdt-toolbar-btn-delete {classNames.btnDelete ?? ''}" onclick={handleDelete}>
94
+ <svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" width="14" height="14">
95
+ <path d="M3 6h18M19 6v14a2 2 0 0 1-2 2H7a2 2 0 0 1-2-2V6m3 0V4a2 2 0 0 1 2-2h4a2 2 0 0 1 2 2v2" />
96
+ </svg>
97
+ Delete ({selectedCount})
98
+ </button>
99
+ {/if}
100
+ {/if}
101
+ {#if buttons && buttons.length > 0}
102
+ <DataTableButtons {buttons} {store} {columns} />
103
+ {/if}
104
+ <DataTableColumnToggle {store} {columns} />
105
+ </div>
106
+ </div>
107
+
108
+ <style>
109
+ .sdt-toolbar {
110
+ display: flex;
111
+ align-items: center;
112
+ justify-content: space-between;
113
+ padding: 0.75rem 1rem;
114
+ gap: 0.75rem;
115
+ flex-wrap: wrap;
116
+ }
117
+ .sdt-toolbar-left {
118
+ display: flex;
119
+ align-items: center;
120
+ gap: 0.5rem;
121
+ flex: 1;
122
+ min-width: 0;
123
+ }
124
+ .sdt-toolbar-right {
125
+ display: flex;
126
+ align-items: center;
127
+ gap: 0.5rem;
128
+ flex-shrink: 0;
129
+ }
130
+ .sdt-toolbar-btn {
131
+ display: inline-flex;
132
+ align-items: center;
133
+ gap: 0.25rem;
134
+ padding: 0.5rem 0.75rem;
135
+ border-radius: 0.375rem;
136
+ font-size: 0.8125rem;
137
+ font-weight: 500;
138
+ cursor: pointer;
139
+ border: 1px solid transparent;
140
+ transition: background-color 0.15s;
141
+ }
142
+ .sdt-toolbar-btn-create {
143
+ background: var(--sdt-primary, #3b82f6);
144
+ color: #fff;
145
+ }
146
+ .sdt-toolbar-btn-create:hover {
147
+ background: var(--sdt-primary-hover, #2563eb);
148
+ }
149
+ .sdt-toolbar-btn-edit {
150
+ background: var(--sdt-input-bg, #fff);
151
+ border-color: var(--sdt-border, #e5e7eb);
152
+ color: var(--sdt-text, #111827);
153
+ }
154
+ .sdt-toolbar-btn-edit:hover {
155
+ background: var(--sdt-hover, #f3f4f6);
156
+ }
157
+ .sdt-toolbar-btn-delete {
158
+ background: #ef4444;
159
+ color: #fff;
160
+ }
161
+ .sdt-toolbar-btn-delete:hover {
162
+ background: #dc2626;
163
+ }
164
+ </style>
@@ -0,0 +1,20 @@
1
+ export { default as DataTable } from './DataTable.svelte';
2
+ export { default as DataTableHead } from './DataTableHead.svelte';
3
+ export { default as DataTableBody } from './DataTableBody.svelte';
4
+ export { default as DataTableRow } from './DataTableRow.svelte';
5
+ export { default as DataTableCell } from './DataTableCell.svelte';
6
+ export { default as DataTableExpandedRow } from './DataTableExpandedRow.svelte';
7
+ export { default as DataTableFooter } from './DataTableFooter.svelte';
8
+ export { default as DataTablePagination } from './DataTablePagination.svelte';
9
+ export { default as DataTableSearch } from './DataTableSearch.svelte';
10
+ export { default as DataTableToolbar } from './DataTableToolbar.svelte';
11
+ export { default as DataTableColumnToggle } from './DataTableColumnToggle.svelte';
12
+ export { default as DataTableButtons } from './DataTableButtons.svelte';
13
+ export { default as DataTableEditor } from './DataTableEditor.svelte';
14
+ export { default as DataTableEditorForm } from './DataTableEditorForm.svelte';
15
+ export { default as DataTableEditorField } from './DataTableEditorField.svelte';
16
+ export { default as DataTableModalEditor } from './DataTableModalEditor.svelte';
17
+ export { default as DataTableBubbleEditor } from './DataTableBubbleEditor.svelte';
18
+ export { default as DataTableLoading } from './DataTableLoading.svelte';
19
+ export { default as DataTableEmpty } from './DataTableEmpty.svelte';
20
+ export { default as VirtualScroller } from './virtual/VirtualScroller.svelte';
@@ -0,0 +1,62 @@
1
+ <script lang="ts">
2
+ import type { Snippet } from 'svelte';
3
+
4
+ interface Props {
5
+ items: any[];
6
+ rowHeight: number;
7
+ containerHeight?: number;
8
+ overscan?: number;
9
+ renderRow: Snippet<[{ item: any; index: number; style: string }]>;
10
+ }
11
+ let {
12
+ items,
13
+ rowHeight,
14
+ containerHeight = 500,
15
+ overscan = 5,
16
+ renderRow,
17
+ }: Props = $props();
18
+
19
+ let scrollTop = $state(0);
20
+ let containerEl: HTMLDivElement | undefined = $state();
21
+
22
+ let totalHeight = $derived(items.length * rowHeight);
23
+
24
+ let visibleStart = $derived(Math.max(0, Math.floor(scrollTop / rowHeight) - overscan));
25
+ let visibleEnd = $derived(
26
+ Math.min(items.length, Math.ceil((scrollTop + containerHeight) / rowHeight) + overscan)
27
+ );
28
+
29
+ let visibleItems = $derived(
30
+ items.slice(visibleStart, visibleEnd).map((item, i) => ({
31
+ item,
32
+ index: visibleStart + i,
33
+ style: `position: absolute; top: ${(visibleStart + i) * rowHeight}px; width: 100%; height: ${rowHeight}px;`,
34
+ }))
35
+ );
36
+
37
+ function handleScroll(e: Event) {
38
+ scrollTop = (e.target as HTMLDivElement).scrollTop;
39
+ }
40
+ </script>
41
+
42
+ <div
43
+ class="sdt-virtual-container"
44
+ style="height: {containerHeight}px; overflow-y: auto;"
45
+ onscroll={handleScroll}
46
+ bind:this={containerEl}
47
+ >
48
+ <div class="sdt-virtual-spacer" style="height: {totalHeight}px; position: relative;">
49
+ {#each visibleItems as { item, index, style } (index)}
50
+ {@render renderRow({ item, index, style })}
51
+ {/each}
52
+ </div>
53
+ </div>
54
+
55
+ <style>
56
+ .sdt-virtual-container {
57
+ overflow-x: auto;
58
+ }
59
+ .sdt-virtual-spacer {
60
+ width: 100%;
61
+ }
62
+ </style>