@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
package/README.md ADDED
@@ -0,0 +1,149 @@
1
+ # @beeblock/svelar-datatable
2
+
3
+ Full-featured DataTable plugin for [Svelar](https://svelar.dev) / SvelteKit 2 with Svelte 5.
4
+
5
+ ## Features
6
+
7
+ - **Sorting** — single-click or multi-sort (Shift+click)
8
+ - **Searching** — global search with debounce
9
+ - **Pagination** — configurable per-page options, page navigation
10
+ - **Selection** — single, multi, range (Shift+click), select all
11
+ - **Column management** — visibility toggle, reorder, resize
12
+ - **Editing** — four modes: modal, bubble (popover), inline (double-click), excel (spreadsheet)
13
+ - **Export** — CSV, clipboard, print (Excel/PDF with optional deps)
14
+ - **Virtual scroll** — render 10,000+ rows with only visible DOM nodes
15
+ - **Row grouping** — group rows by any column value
16
+ - **Per-column filters** — programmatic column-level filtering
17
+ - **Custom cells** — Svelte 5 snippets for full cell rendering control
18
+ - **Row customization** — `rowClass`, `rowId` function, expandable detail rows
19
+ - **Server-side** — jQuery DataTables wire protocol compatible, GET or POST
20
+ - **State persistence** — save sort/filter/page/column state to localStorage
21
+ - **Tailwind CSS** — `classNames` prop for pure Tailwind customization of every element
22
+ - **CSS variables** — 12+ CSS custom properties for quick theming
23
+ - **Footer aggregation** — per-column footer with custom functions
24
+ - **Responsive** — horizontal scroll for small screens
25
+
26
+ ## Install
27
+
28
+ ```bash
29
+ npm install @beeblock/svelar-datatable
30
+ ```
31
+
32
+ Peer dependencies: `@beeblock/svelar >= 0.4.0`, `svelte ^5.0.0`
33
+
34
+ ## Quick Start
35
+
36
+ ```svelte
37
+ <script lang="ts">
38
+ import { DataTable } from '@beeblock/svelar-datatable/ui';
39
+ import type { ColumnDef } from '@beeblock/svelar-datatable';
40
+
41
+ const columns: ColumnDef[] = [
42
+ { key: 'id', header: 'ID', type: 'number', sortable: true },
43
+ { key: 'name', header: 'Name', sortable: true, searchable: true },
44
+ { key: 'email', header: 'Email', sortable: true, searchable: true },
45
+ ];
46
+
47
+ const data = [
48
+ { id: 1, name: 'Alice', email: 'alice@example.com' },
49
+ { id: 2, name: 'Bob', email: 'bob@example.com' },
50
+ ];
51
+ </script>
52
+
53
+ <DataTable {data} {columns} sortable searchable paginate perPage={10} />
54
+ ```
55
+
56
+ ## Server-Side
57
+
58
+ ```svelte
59
+ <!-- Frontend -->
60
+ <DataTable
61
+ serverUrl="/api/datatable/users"
62
+ columns={columns}
63
+ sortable
64
+ searchable
65
+ paginate
66
+ perPage={25}
67
+ />
68
+ ```
69
+
70
+ ```ts
71
+ // src/routes/api/datatable/users/+server.ts
72
+ import { DataTableController } from '@beeblock/svelar-datatable/server';
73
+ import { User } from '$lib/models/User';
74
+
75
+ const dt = new DataTableController(User);
76
+ export const GET = dt.handle();
77
+ ```
78
+
79
+ The server controller handles pagination, sorting, searching, and filtering — compatible with the jQuery DataTables wire protocol.
80
+
81
+ ## Editing
82
+
83
+ Four editor modes, configured via `editorMode`:
84
+
85
+ ```svelte
86
+ <!-- Modal editor -->
87
+ <DataTable editorMode="modal" editorFields={fields} onEdit={save} onCreate={create} />
88
+
89
+ <!-- Bubble (popover anchored to row) -->
90
+ <DataTable editorMode="bubble" editorFields={fields} onEdit={save} />
91
+
92
+ <!-- Inline (double-click a cell) -->
93
+ <DataTable editorMode="inline" onCellEdit={saveCellEdit} />
94
+
95
+ <!-- Excel (spreadsheet navigation) -->
96
+ <DataTable editorMode="excel" onCellEdit={saveCellEdit} />
97
+ ```
98
+
99
+ ## Tailwind Customization
100
+
101
+ Style every element with Tailwind utility classes via the `classNames` prop:
102
+
103
+ ```svelte
104
+ <DataTable
105
+ {data}
106
+ {columns}
107
+ striped={false}
108
+ hover={false}
109
+ classNames={{
110
+ container: '!bg-slate-900 !border-slate-800',
111
+ thead: '!bg-slate-950',
112
+ th: '!bg-slate-950 !text-slate-400 !tracking-widest',
113
+ tr: 'hover:!bg-slate-800',
114
+ td: '!text-slate-300 !border-b-slate-800',
115
+ pagination: '!border-t-slate-800 !text-slate-400 !bg-slate-900',
116
+ pageButton: '!bg-slate-800 !text-slate-400 !border-slate-700',
117
+ searchInput: '!bg-slate-800 !text-slate-200 !border-slate-700',
118
+ }}
119
+ />
120
+ ```
121
+
122
+ All 39 keys from `DataTableClassNames` are wired: `container`, `toolbar`, `toolbarLeft`, `toolbarRight`, `searchInput`, `thead`, `th`, `tbody`, `tr`, `trSelected`, `trEven`, `td`, `tfoot`, `tf`, `pagination`, `paginationInfo`, `paginationControls`, `pageButton`, `pageButtonActive`, `perPageSelect`, `btn`, `btnCreate`, `btnEdit`, `btnDelete`, `editorModal`, `editorBackdrop`, `editorField`, `editorInput`, `editorLabel`, `loading`, `empty`, `error`.
123
+
124
+ ## Imports
125
+
126
+ ```ts
127
+ // UI component (Svelte source — not compiled)
128
+ import { DataTable } from '@beeblock/svelar-datatable/ui';
129
+
130
+ // Types
131
+ import type {
132
+ ColumnDef, EditorFieldDef, ButtonDef, DataTableClassNames,
133
+ DataTableConfig, DataTableState, ExportFormat,
134
+ } from '@beeblock/svelar-datatable';
135
+
136
+ // Stores
137
+ import { DataTableStore, ServerDataTableStore } from '@beeblock/svelar-datatable';
138
+
139
+ // Server controller (API routes)
140
+ import { DataTableController, DataTableService } from '@beeblock/svelar-datatable/server';
141
+ ```
142
+
143
+ ## Documentation
144
+
145
+ Full documentation with all props, callbacks, store API, and examples: [svelar.dev/docs/datatable](https://svelar.dev/docs/datatable)
146
+
147
+ ## License
148
+
149
+ MIT
@@ -0,0 +1,13 @@
1
+ import type { DataTableConfig } from './types.js';
2
+ interface DatatablePluginConfig {
3
+ prefix?: string;
4
+ defaults?: Partial<DataTableConfig>;
5
+ }
6
+ export declare class SvelarDatatablePlugin {
7
+ private _config;
8
+ constructor(config?: DatatablePluginConfig);
9
+ get name(): string;
10
+ get config(): DatatablePluginConfig;
11
+ static defaults(): Partial<DataTableConfig>;
12
+ }
13
+ export {};
@@ -0,0 +1,4 @@
1
+ import type { ColumnDef, ExportFormat } from '../types.js';
2
+ export declare class ExportManager<T = any> {
3
+ export(format: ExportFormat, data: T[], columns: ColumnDef<T>[], filename?: string): Promise<void>;
4
+ }
@@ -0,0 +1,2 @@
1
+ import type { ColumnDef } from '../types.js';
2
+ export declare function copyToClipboard<T>(data: T[], columns: ColumnDef<T>[]): Promise<void>;
@@ -0,0 +1,4 @@
1
+ import type { ColumnDef } from '../types.js';
2
+ export declare function generateCSV<T>(data: T[], columns: ColumnDef<T>[]): string;
3
+ export declare function downloadCSV(content: string, filename?: string): void;
4
+ export declare function downloadBlob(blob: Blob, filename: string): void;
@@ -0,0 +1,2 @@
1
+ import type { ColumnDef } from '../types.js';
2
+ export declare function exportExcel<T>(data: T[], columns: ColumnDef<T>[], filename?: string): Promise<void>;
@@ -0,0 +1,6 @@
1
+ export { generateCSV, downloadCSV, downloadBlob } from './csv.js';
2
+ export { copyToClipboard } from './clipboard.js';
3
+ export { printTable } from './print.js';
4
+ export { exportExcel } from './excel.js';
5
+ export { exportPdf } from './pdf.js';
6
+ export { ExportManager } from './ExportManager.js';
@@ -0,0 +1,2 @@
1
+ import type { ColumnDef } from '../types.js';
2
+ export declare function exportPdf<T>(data: T[], columns: ColumnDef<T>[], filename?: string): void;
@@ -0,0 +1,2 @@
1
+ import type { ColumnDef } from '../types.js';
2
+ export declare function printTable<T>(data: T[], columns: ColumnDef<T>[], title?: string): void;
@@ -0,0 +1,5 @@
1
+ export { SvelarDatatablePlugin } from './SvelarDatatablePlugin.js';
2
+ export { DataTableStore } from './state/DataTableStore.js';
3
+ export { ServerDataTableStore } from './state/ServerDataTableStore.js';
4
+ export { ExportManager } from './export/ExportManager.js';
5
+ export type { ColumnDef, ColumnType, FilterOperator, SelectionMode, EditorMode, FieldType, ExportFormat, SortState, FilterState, PaginationState, DataTableRequest, DataTableResponse, EditorFieldDef, ButtonDef, DataTableConfig, DataTableClassNames, DataTableState, } from './types.js';
package/dist/index.js ADDED
@@ -0,0 +1,19 @@
1
+ var y={prefix:"/api",defaults:{perPage:15,perPageOptions:[10,15,25,50,100],searchDebounceMs:300,sortable:!0,searchable:!0,paginate:!0,selectable:"none",striped:!0,hover:!0,bordered:!1,compact:!1,responsive:!0,virtualScroll:!1,virtualRowHeight:48}},S=class{_config;constructor(t={}){this._config={...y,...t,defaults:{...y.defaults,...t.defaults}}}get name(){return"svelar-datatable"}get config(){return this._config}static defaults(){return{...y.defaults}}};var m=class{_state;_listeners=new Set;_columns=[];_rowIdFn;_stateSaveKey=null;_lastSelectedId=null;_paginate=!0;constructor(t){this._columns=t.columns,this._stateSaveKey=t.stateSaveKey??null,this._paginate=t.paginate!==!1,this._rowIdFn=typeof t.rowId=="function"?t.rowId:s=>s[t.rowId??"id"];let e=this._loadState();this._state={allRows:t.data??[],filteredRows:[],sortedRows:[],paginatedRows:[],sort:e?.sort??[],filters:e?.filters??[],globalSearch:e?.globalSearch??"",pagination:{page:e?.page??1,perPage:t.perPage??15,total:0,lastPage:1},selectedIds:new Set,columnVisibility:e?.columnVisibility??Object.fromEntries(t.columns.map(s=>[s.key,s.visible!==!1])),columnOrder:e?.columnOrder??t.columns.map(s=>s.key),loading:!1,error:null,editingRowId:null,editingColumn:null,editorMode:null,formData:{},validationErrors:{},draw:0,excelFocusedCell:null,excelEditingCell:null,excelEditValue:""},this._recompute()}subscribe(t){return this._listeners.add(t),()=>this._listeners.delete(t)}getState(){return this._state}_notify(){for(let t of this._listeners)t()}_saveState(){if(this._stateSaveKey)try{let t={sort:this._state.sort,filters:this._state.filters,globalSearch:this._state.globalSearch,page:this._state.pagination.page,columnVisibility:this._state.columnVisibility,columnOrder:this._state.columnOrder};localStorage.setItem(this._stateSaveKey,JSON.stringify(t))}catch{}}_loadState(){if(!this._stateSaveKey)return null;try{let t=localStorage.getItem(this._stateSaveKey);return t?JSON.parse(t):null}catch{return null}}setData(t){this._state={...this._state,allRows:t},this._recompute()}setSort(t){this._state={...this._state,sort:t,pagination:{...this._state.pagination,page:1}},this._recompute(),this._saveState()}toggleSort(t,e=!1){let s=this._state.sort.find(i=>i.column===t),a;s?s.direction==="asc"?a=e?this._state.sort.map(i=>i.column===t?{...i,direction:"desc"}:i):[{column:t,direction:"desc"}]:a=e?this._state.sort.filter(i=>i.column!==t):[]:a=e?[...this._state.sort,{column:t,direction:"asc"}]:[{column:t,direction:"asc"}],this.setSort(a)}setGlobalSearch(t){this._state={...this._state,globalSearch:t,pagination:{...this._state.pagination,page:1}},this._recompute(),this._saveState()}setFilters(t){this._state={...this._state,filters:t,pagination:{...this._state.pagination,page:1}},this._recompute(),this._saveState()}setColumnFilter(t,e,s="like"){let a=this._state.filters.filter(i=>i.column!==t);e!==""&&e!==null&&e!==void 0&&a.push({column:t,value:e,operator:s}),this.setFilters(a)}setPage(t){let e=this._state.pagination.lastPage,s=Math.max(1,Math.min(t,e));this._state={...this._state,pagination:{...this._state.pagination,page:s}},this._recompute(),this._saveState()}setPerPage(t){this._state={...this._state,pagination:{...this._state.pagination,perPage:t,page:1}},this._recompute(),this._saveState()}toggleColumnVisibility(t){let e={...this._state.columnVisibility};e[t]=!e[t],this._state={...this._state,columnVisibility:e},this._notify(),this._saveState()}setColumnVisibility(t){this._state={...this._state,columnVisibility:t},this._notify(),this._saveState()}reorderColumns(t){this._state={...this._state,columnOrder:t},this._notify(),this._saveState()}getRowId(t){return this._rowIdFn(t)}toggleSelect(t){let e=new Set(this._state.selectedIds);e.has(t)?e.delete(t):e.add(t),this._lastSelectedId=t,this._state={...this._state,selectedIds:e},this._notify()}getLastSelectedId(){return this._lastSelectedId}selectSingle(t){this._state={...this._state,selectedIds:new Set([t])},this._notify()}selectAll(){let t=this._state.filteredRows.map(e=>this.getRowId(e));this._state={...this._state,selectedIds:new Set(t)},this._notify()}deselectAll(){this._state={...this._state,selectedIds:new Set},this._notify()}selectRange(t,e){let s=this._state.sortedRows,a=s.findIndex(n=>this.getRowId(n)===t),i=s.findIndex(n=>this.getRowId(n)===e);if(a===-1||i===-1)return;let o=Math.min(a,i),u=Math.max(a,i),r=new Set(this._state.selectedIds);for(let n=o;n<=u;n++)r.add(this.getRowId(s[n]));this._state={...this._state,selectedIds:r},this._notify()}getSelectedRows(){return this._state.allRows.filter(t=>this._state.selectedIds.has(this.getRowId(t)))}openEditor(t,e,s){let a=t!==null?this._state.allRows.find(o=>this.getRowId(o)===t):null,i=a?{...a}:{};this._state={...this._state,editingRowId:t,editingColumn:e,editorMode:s,formData:i,validationErrors:{}},this._notify()}closeEditor(){this._state={...this._state,editingRowId:null,editingColumn:null,editorMode:null,formData:{},validationErrors:{}},this._notify()}setFormField(t,e){this._state={...this._state,formData:{...this._state.formData,[t]:e}},this._notify()}setValidationErrors(t){this._state={...this._state,validationErrors:t},this._notify()}setLoading(t){this._state={...this._state,loading:t},this._notify()}setError(t){this._state={...this._state,error:t},this._notify()}setServerResponse(t){this._state={...this._state,allRows:t.data,filteredRows:t.data,sortedRows:t.data,paginatedRows:t.data,loading:!1,draw:t.draw,pagination:{...this._state.pagination,total:t.recordsFiltered,lastPage:Math.ceil(t.recordsFiltered/this._state.pagination.perPage)||1}},this._notify()}resetState(){if(this._state={...this._state,sort:[],filters:[],globalSearch:"",pagination:{...this._state.pagination,page:1},selectedIds:new Set},this._recompute(),this._stateSaveKey)try{localStorage.removeItem(this._stateSaveKey)}catch{}}focusCell(t,e){this._state={...this._state,excelFocusedCell:{rowIndex:t,columnKey:e}},this._notify()}startCellEdit(){let t=this._state.excelFocusedCell;if(!t)return;let e=this._state.paginatedRows[t.rowIndex];if(!e)return;let s=this._columns.find(a=>a.key===t.columnKey);!s||s.editable===!1||(this._state={...this._state,excelEditingCell:{...t},excelEditValue:e[t.columnKey]!=null?String(e[t.columnKey]):""},this._notify())}setExcelEditValue(t){this._state={...this._state,excelEditValue:t}}commitCellEdit(){let t=this._state.excelEditingCell;if(!t)return null;let e=this._state.paginatedRows[t.rowIndex];if(!e)return this.cancelCellEdit(),null;let s=this._columns.find(o=>o.key===t.columnKey),a=e[t.columnKey],i=this._state.excelEditValue;return s?.type==="number"?i=i===""?null:Number(i):s?.type==="boolean"?i=i==="true"||i==="1":i===""&&(i=null),this._state={...this._state,excelEditingCell:null,excelEditValue:""},i===a||i===null&&a==null?(this._notify(),null):(e[t.columnKey]=i,this._notify(),{row:e,columnKey:t.columnKey,oldValue:a,newValue:i})}cancelCellEdit(){this._state={...this._state,excelEditingCell:null,excelEditValue:""},this._notify()}clearExcelFocus(){this._state={...this._state,excelFocusedCell:null,excelEditingCell:null,excelEditValue:""},this._notify()}getVisibleColumns(){return this._state.columnOrder.filter(t=>this._state.columnVisibility[t]!==!1).map(t=>this._columns.find(e=>e.key===t)).filter(Boolean)}navigateCell(t){let e=this._state.excelFocusedCell,s=this._state.paginatedRows,a=this.getVisibleColumns();if(a.length===0)return null;if(!e){let r=a.find(n=>n.editable!==!1);return r&&s.length>0&&this.focusCell(0,r.key),null}let{rowIndex:i,columnKey:o}=e,u=a.findIndex(r=>r.key===o);if(u===-1)return null;switch(t){case"left":{for(let r=u-1;r>=0;r--)if(a[r].editable!==!1)return this.focusCell(i,a[r].key),null;for(let r=a.length-1;r>=0;r--)if(a[r].editable!==!1)return i>0?(this.focusCell(i-1,a[r].key),null):"page-prev";return null}case"right":{for(let r=u+1;r<a.length;r++)if(a[r].editable!==!1)return this.focusCell(i,a[r].key),null;for(let r=0;r<a.length;r++)if(a[r].editable!==!1)return i<s.length-1?(this.focusCell(i+1,a[r].key),null):"page-next";return null}case"up":return i>0?(this.focusCell(i-1,o),null):"page-prev";case"down":return i<s.length-1?(this.focusCell(i+1,o),null):"page-next"}}_recompute(){let t=[...this._state.allRows];if(this._state.globalSearch){let n=this._state.globalSearch.toLowerCase(),d=this._columns.filter(l=>l.searchable!==!1);t=t.filter(l=>d.some(p=>{let h=l[p.key];return h!=null&&String(h).toLowerCase().includes(n)}))}for(let n of this._state.filters)t=t.filter(d=>{let l=d[n.column];switch(n.operator){case"=":return l==n.value;case"!=":return l!=n.value;case">":return l>n.value;case"<":return l<n.value;case">=":return l>=n.value;case"<=":return l<=n.value;case"like":return l!=null&&String(l).toLowerCase().includes(String(n.value).toLowerCase());case"not_like":return l==null||!String(l).toLowerCase().includes(String(n.value).toLowerCase());case"in":return Array.isArray(n.value)&&n.value.includes(l);case"between":return Array.isArray(n.value)&&l>=n.value[0]&&l<=n.value[1];case"null":return l==null;case"not_null":return l!=null;default:return!0}});let e=t;this._state.sort.length>0&&(t=[...t].sort((n,d)=>{for(let l of this._state.sort){let p=this._columns.find(k=>k.key===l.column),h=n[l.column],g=d[l.column],f=0;if(h==null?f=-1:g==null?f=1:p?.type==="number"?f=Number(h)-Number(g):p?.type==="date"?f=new Date(h).getTime()-new Date(g).getTime():p?.type==="boolean"?f=(h?1:0)-(g?1:0):f=String(h).localeCompare(String(g)),f!==0)return l.direction==="desc"?-f:f}return 0}));let s=t,a=e.length,i=this._state.pagination.perPage,o,u,r;if(this._paginate){r=Math.ceil(a/i)||1,u=Math.min(this._state.pagination.page,r);let n=(u-1)*i;o=s.slice(n,n+i)}else o=s,u=1,r=1;this._state={...this._state,filteredRows:e,sortedRows:s,paginatedRows:o,pagination:{page:u,perPage:i,total:a,lastPage:r}},this._notify()}};function I(c="XSRF-TOKEN"){if(typeof document>"u")return null;let t=c.replace(/[.*+?^${}()|[\]\\]/g,"\\$&"),e=document.cookie.match(new RegExp(`(?:^|;\\s*)${t}=([^;]*)`));return e?decodeURIComponent(e[1]):null}var v=class extends m{_serverUrl;_serverMethod;_drawCounter=0;_abortController=null;_fetchDebounceTimer=null;_serverColumns;_csrfCookieName;_csrfHeaderName;constructor(t){super(t),this._serverUrl=t.serverUrl,this._serverMethod=t.serverMethod??"GET",this._csrfCookieName=t.csrfCookieName??"XSRF-TOKEN",this._csrfHeaderName=t.csrfHeaderName??"X-CSRF-Token",this._serverColumns=t.columns.map(e=>({data:e.key,name:e.key,searchable:e.searchable!==!1,orderable:e.sortable!==!1}))}_buildHeaders(t={}){let e={...t},s=I(this._csrfCookieName);return s&&(e[this._csrfHeaderName]=s),e}setSort(t){let e=this.getState();this._state={...e,sort:t,pagination:{...e.pagination,page:1}},this._debouncedFetch()}setGlobalSearch(t){let e=this.getState();this._state={...e,globalSearch:t,pagination:{...e.pagination,page:1}},this._debouncedFetch()}setFilters(t){let e=this.getState();this._state={...e,filters:t,pagination:{...e.pagination,page:1}},this._debouncedFetch()}setPage(t){let e=this.getState();this._state={...e,pagination:{...e.pagination,page:t}},this._fetchFromServer()}setPerPage(t){let e=this.getState();this._state={...e,pagination:{...e.pagination,perPage:t,page:1}},this._fetchFromServer()}_debouncedFetch(){this._fetchDebounceTimer&&clearTimeout(this._fetchDebounceTimer),this._fetchDebounceTimer=setTimeout(()=>this._fetchFromServer(),300)}async _fetchFromServer(){this._abortController&&this._abortController.abort(),this._abortController=new AbortController;let t=this.getState();this.setLoading(!0),this.setError(null);let e=++this._drawCounter,s={draw:e,start:(t.pagination.page-1)*t.pagination.perPage,length:t.pagination.perPage,search:{value:t.globalSearch,regex:!1},order:t.sort.map(a=>({column:this._serverColumns.findIndex(i=>i.data===a.column),dir:a.direction})),columns:this._serverColumns.map(a=>({...a,search:{value:t.filters.find(i=>i.column===a.data)?.value??"",regex:!1}}))};try{let a;if(this._serverMethod==="POST")a=await fetch(this._serverUrl,{method:"POST",headers:this._buildHeaders({"Content-Type":"application/json"}),body:JSON.stringify(s),signal:this._abortController.signal});else{let o=new URLSearchParams;o.set("draw",String(s.draw)),o.set("start",String(s.start)),o.set("length",String(s.length)),o.set("search[value]",s.search.value),o.set("search[regex]",String(s.search.regex)),s.order.forEach((r,n)=>{o.set(`order[${n}][column]`,String(r.column)),o.set(`order[${n}][dir]`,r.dir)}),s.columns.forEach((r,n)=>{o.set(`columns[${n}][data]`,r.data),o.set(`columns[${n}][name]`,r.name),o.set(`columns[${n}][searchable]`,String(r.searchable)),o.set(`columns[${n}][orderable]`,String(r.orderable)),o.set(`columns[${n}][search][value]`,r.search.value),o.set(`columns[${n}][search][regex]`,String(r.search.regex))});let u=`${this._serverUrl}?${o.toString()}`;a=await fetch(u,{signal:this._abortController.signal})}if(!a.ok)throw new Error(`Server responded with ${a.status}`);let i=await a.json();i.draw===e&&this.setServerResponse(i)}catch(a){if(a.name==="AbortError")return;this.setLoading(!1),this.setError(a.message??"Failed to fetch data")}}async initialFetch(){await this._fetchFromServer()}destroy(){this._abortController&&this._abortController.abort(),this._fetchDebounceTimer&&clearTimeout(this._fetchDebounceTimer)}};function x(c){if(c==null)return"";let t=String(c);return t.includes(",")||t.includes('"')||t.includes(`
2
+ `)||t.includes("\r")?'"'+t.replace(/"/g,'""')+'"':t}function T(c,t){let e=t.filter(i=>i.visible!==!1),s=e.map(i=>x(i.header)).join(","),a=c.map(i=>e.map(o=>x(i[o.key])).join(","));return"\uFEFF"+[s,...a].join(`\r
3
+ `)}function D(c,t="export.csv"){let e=new Blob([c],{type:"text/csv;charset=utf-8;"});w(e,t)}function w(c,t){let e=URL.createObjectURL(c),s=document.createElement("a");s.href=e,s.download=t,document.body.appendChild(s),s.click(),document.body.removeChild(s),URL.revokeObjectURL(e)}async function R(c,t){let e=t.filter(o=>o.visible!==!1),s=e.map(o=>o.header).join(" "),a=c.map(o=>e.map(u=>{let r=o[u.key];return r==null?"":String(r)}).join(" ")),i=[s,...a].join(`
4
+ `);await navigator.clipboard.writeText(i)}function b(c,t,e){let s=t.filter(r=>r.visible!==!1),a=s.map(r=>`<th style="border:1px solid #ddd;padding:8px 12px;text-align:left;background:#f5f5f5;font-weight:600;">${_(r.header)}</th>`).join(""),i=c.map(r=>`<tr>${s.map(d=>{let l=r[d.key];return`<td style="border:1px solid #ddd;padding:8px 12px;">${_(l==null?"":String(l))}</td>`}).join("")}</tr>`).join(""),o=`<!DOCTYPE html>
5
+ <html><head>
6
+ <title>${_(e??"Data Export")}</title>
7
+ <style>
8
+ body { font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', sans-serif; margin: 20px; }
9
+ table { border-collapse: collapse; width: 100%; font-size: 13px; }
10
+ h1 { font-size: 18px; margin-bottom: 16px; }
11
+ @media print { h1 { margin-top: 0; } }
12
+ </style>
13
+ </head><body>
14
+ ${e?`<h1>${_(e)}</h1>`:""}
15
+ <table>
16
+ <thead><tr>${a}</tr></thead>
17
+ <tbody>${i}</tbody>
18
+ </table>
19
+ </body></html>`,u=window.open("","_blank");u&&(u.document.write(o),u.document.close(),u.focus(),setTimeout(()=>u.print(),250))}function _(c){return c.replace(/&/g,"&amp;").replace(/</g,"&lt;").replace(/>/g,"&gt;").replace(/"/g,"&quot;")}async function E(c,t,e="export.xlsx"){let s;try{s=await import("exceljs")}catch{throw new Error("exceljs is required for Excel export. Install it: npm install exceljs")}let a=new s.Workbook,i=a.addWorksheet("Data"),o=t.filter(d=>d.visible!==!1);i.columns=o.map(d=>({header:d.header,key:d.key,width:20}));let u=i.getRow(1);u.font={bold:!0},u.fill={type:"pattern",pattern:"solid",fgColor:{argb:"FFF0F0F0"}};for(let d of c){let l={};for(let p of o)l[p.key]=d[p.key]??"";i.addRow(l)}let r=await a.xlsx.writeBuffer(),n=new Blob([r],{type:"application/vnd.openxmlformats-officedocument.spreadsheetml.sheet"});w(n,e)}function F(c,t,e="export.pdf"){b(c,t,e.replace(".pdf",""))}var C=class{async export(t,e,s,a){switch(t){case"csv":{let i=T(e,s);D(i,a??"export.csv");break}case"excel":await E(e,s,a??"export.xlsx");break;case"pdf":F(e,s,a??"export.pdf");break;case"clipboard":await R(e,s);break;case"print":b(e,s);break}}};export{m as DataTableStore,C as ExportManager,v as ServerDataTableStore,S as SvelarDatatablePlugin};
@@ -0,0 +1,4 @@
1
+ import { type DataTableServiceOptions } from './DataTableService.js';
2
+ export declare class DataTableController {
3
+ static handle(event: any, model: any, options?: DataTableServiceOptions): Promise<Response>;
4
+ }
@@ -0,0 +1,3 @@
1
+ import type { DataTableRequest } from '../types.js';
2
+ export declare function parseDataTableRequest(params: URLSearchParams): DataTableRequest;
3
+ export declare function parseDataTableRequestFromBody(request: Request): Promise<DataTableRequest>;
@@ -0,0 +1,25 @@
1
+ import type { DataTableRequest, DataTableResponse } from '../types.js';
2
+ export interface DataTableServiceOptions {
3
+ searchable?: string[];
4
+ orderable?: string[];
5
+ baseQuery?: (query: any) => any;
6
+ scopes?: Record<string, (query: any) => any>;
7
+ computedColumns?: Record<string, string>;
8
+ }
9
+ export declare class DataTableService<T = any> {
10
+ private _model;
11
+ private _searchable;
12
+ private _orderable;
13
+ private _baseQueryFn;
14
+ private _scopes;
15
+ private _computedColumns;
16
+ private _activeScopes;
17
+ constructor(model: any, options?: DataTableServiceOptions);
18
+ searchable(columns: string[]): this;
19
+ orderable(columns: string[]): this;
20
+ setBaseQuery(fn: (query: any) => any): this;
21
+ addScope(name: string, fn: (query: any) => any): this;
22
+ applyScope(name: string): this;
23
+ addComputedColumn(name: string, sqlExpr: string): this;
24
+ process(request: DataTableRequest): Promise<DataTableResponse<T>>;
25
+ }
@@ -0,0 +1,3 @@
1
+ export { DataTableService, type DataTableServiceOptions } from './DataTableService.js';
2
+ export { DataTableController } from './DataTableController.js';
3
+ export { parseDataTableRequest, parseDataTableRequestFromBody } from './DataTableRequest.js';
@@ -0,0 +1 @@
1
+ var h=class{_model;_searchable=[];_orderable=[];_baseQueryFn=null;_scopes={};_computedColumns={};_activeScopes=[];constructor(e,t){this._model=e,t?.searchable&&(this._searchable=t.searchable),t?.orderable&&(this._orderable=t.orderable),t?.baseQuery&&(this._baseQueryFn=t.baseQuery),t?.scopes&&(this._scopes=t.scopes),t?.computedColumns&&(this._computedColumns=t.computedColumns)}searchable(e){return this._searchable=e,this}orderable(e){return this._orderable=e,this}setBaseQuery(e){return this._baseQueryFn=e,this}addScope(e,t){return this._scopes[e]=t,this}applyScope(e){return this._activeScopes.push(e),this}addComputedColumn(e,t){return this._computedColumns[e]=t,this}async process(e){try{let t=this._model.query();this._baseQueryFn&&this._baseQueryFn(t);let u=await t.count(),a=this._model.query();this._baseQueryFn&&this._baseQueryFn(a);for(let r of this._activeScopes){let o=this._scopes[r];o&&o(a)}for(let[r,o]of Object.entries(this._computedColumns))a=a.selectRaw(`(${o}) as ${r}`);if(e.search.value){let r=e.search.value,o=this._searchable.length>0?this._searchable:e.columns.filter(i=>i.searchable).map(i=>i.data);o.length>0&&(a=a.whereNested(i=>{for(let l=0;l<o.length;l++){let m=o[l];l===0?i.where(m,"LIKE",`%${r}%`):i.orWhere(m,"LIKE",`%${r}%`)}}))}for(let r of e.columns)r.search.value&&r.searchable&&(a=a.where(r.data,"LIKE",`%${r.search.value}%`));let c=await a.clone().count();for(let r of e.order){let o=e.columns[r.column];o&&(this._orderable.length>0?this._orderable:e.columns.filter(l=>l.orderable).map(l=>l.data)).includes(o.data)&&(a=a.orderBy(o.data,r.dir))}a=a.offset(e.start).limit(e.length);let d=await a.get();return{draw:e.draw,recordsTotal:u,recordsFiltered:c,data:d}}catch(t){return{draw:e.draw,recordsTotal:0,recordsFiltered:0,data:[],error:t.message??"Server error"}}}};function p(s){let e=parseInt(s.get("draw")??"1",10),t=parseInt(s.get("start")??"0",10),u=parseInt(s.get("length")??"15",10),a={value:s.get("search[value]")??"",regex:s.get("search[regex]")==="true"},n=[],c=0;for(;s.has(`order[${c}][column]`);)n.push({column:parseInt(s.get(`order[${c}][column]`)??"0",10),dir:s.get(`order[${c}][dir]`)??"asc"}),c++;let d=[],r=0;for(;s.has(`columns[${r}][data]`);)d.push({data:s.get(`columns[${r}][data]`)??"",name:s.get(`columns[${r}][name]`)??"",searchable:s.get(`columns[${r}][searchable]`)!=="false",orderable:s.get(`columns[${r}][orderable]`)!=="false",search:{value:s.get(`columns[${r}][search][value]`)??"",regex:s.get(`columns[${r}][search][regex]`)==="true"}}),r++;return{draw:e,start:t,length:u,search:a,order:n,columns:d}}async function y(s){return await s.json()}var b=class{static async handle(e,t,u){try{let a=new h(t,u),n;e.request.method==="POST"?n=await y(e.request):n=p(e.url.searchParams);let c=await a.process(n);return new Response(JSON.stringify(c),{status:200,headers:{"Content-Type":"application/json"}})}catch(a){let n={draw:0,recordsTotal:0,recordsFiltered:0,data:[],error:a.message??"Internal server error"};return new Response(JSON.stringify(n),{status:500,headers:{"Content-Type":"application/json"}})}}};export{b as DataTableController,h as DataTableService,p as parseDataTableRequest,y as parseDataTableRequestFromBody};
@@ -0,0 +1,64 @@
1
+ import type { ColumnDef, DataTableConfig, DataTableState, FilterState, SortState } from '../types.js';
2
+ type Listener = () => void;
3
+ export declare class DataTableStore<T = any> {
4
+ private _state;
5
+ private _listeners;
6
+ private _columns;
7
+ private _rowIdFn;
8
+ private _stateSaveKey;
9
+ private _lastSelectedId;
10
+ private _paginate;
11
+ constructor(config: DataTableConfig<T>);
12
+ subscribe(listener: Listener): () => void;
13
+ getState(): DataTableState<T>;
14
+ private _notify;
15
+ private _saveState;
16
+ private _loadState;
17
+ setData(rows: T[]): void;
18
+ setSort(sort: SortState[]): void;
19
+ toggleSort(column: string, multiSort?: boolean): void;
20
+ setGlobalSearch(search: string): void;
21
+ setFilters(filters: FilterState[]): void;
22
+ setColumnFilter(column: string, value: any, operator?: FilterState['operator']): void;
23
+ setPage(page: number): void;
24
+ setPerPage(perPage: number): void;
25
+ toggleColumnVisibility(column: string): void;
26
+ setColumnVisibility(visibility: Record<string, boolean>): void;
27
+ reorderColumns(columnOrder: string[]): void;
28
+ getRowId(row: T): string | number;
29
+ toggleSelect(rowId: string | number): void;
30
+ getLastSelectedId(): string | number | null;
31
+ selectSingle(rowId: string | number): void;
32
+ selectAll(): void;
33
+ deselectAll(): void;
34
+ selectRange(fromId: string | number, toId: string | number): void;
35
+ getSelectedRows(): T[];
36
+ openEditor(rowId: string | number | null, column: string | null, mode: 'inline' | 'bubble' | 'modal'): void;
37
+ closeEditor(): void;
38
+ setFormField(name: string, value: any): void;
39
+ setValidationErrors(errors: Record<string, string>): void;
40
+ setLoading(loading: boolean): void;
41
+ setError(error: string | null): void;
42
+ setServerResponse(response: {
43
+ data: T[];
44
+ recordsTotal: number;
45
+ recordsFiltered: number;
46
+ draw: number;
47
+ }): void;
48
+ resetState(): void;
49
+ focusCell(rowIndex: number, columnKey: string): void;
50
+ startCellEdit(): void;
51
+ setExcelEditValue(value: string): void;
52
+ commitCellEdit(): {
53
+ row: any;
54
+ columnKey: string;
55
+ oldValue: any;
56
+ newValue: any;
57
+ } | null;
58
+ cancelCellEdit(): void;
59
+ clearExcelFocus(): void;
60
+ getVisibleColumns(): ColumnDef[];
61
+ navigateCell(direction: 'up' | 'down' | 'left' | 'right'): 'page-next' | 'page-prev' | null;
62
+ private _recompute;
63
+ }
64
+ export {};
@@ -0,0 +1,23 @@
1
+ import type { DataTableConfig, FilterState, SortState } from '../types.js';
2
+ import { DataTableStore } from './DataTableStore.js';
3
+ export declare class ServerDataTableStore<T = any> extends DataTableStore<T> {
4
+ private _serverUrl;
5
+ private _serverMethod;
6
+ private _drawCounter;
7
+ private _abortController;
8
+ private _fetchDebounceTimer;
9
+ private _serverColumns;
10
+ private _csrfCookieName;
11
+ private _csrfHeaderName;
12
+ constructor(config: DataTableConfig<T>);
13
+ private _buildHeaders;
14
+ setSort(sort: SortState[]): void;
15
+ setGlobalSearch(search: string): void;
16
+ setFilters(filters: FilterState[]): void;
17
+ setPage(page: number): void;
18
+ setPerPage(perPage: number): void;
19
+ private _debouncedFetch;
20
+ _fetchFromServer(): Promise<void>;
21
+ initialFetch(): Promise<void>;
22
+ destroy(): void;
23
+ }
@@ -0,0 +1,2 @@
1
+ export { DataTableStore } from './DataTableStore.js';
2
+ export { ServerDataTableStore } from './ServerDataTableStore.js';
@@ -0,0 +1,208 @@
1
+ import type { Component } from 'svelte';
2
+ export type ColumnType = 'string' | 'number' | 'date' | 'boolean' | 'html' | 'custom';
3
+ export type FilterOperator = '=' | '!=' | '>' | '<' | '>=' | '<=' | 'like' | 'not_like' | 'in' | 'between' | 'null' | 'not_null';
4
+ export type SelectionMode = 'none' | 'single' | 'multi';
5
+ export type EditorMode = 'inline' | 'bubble' | 'modal' | 'excel';
6
+ export type FieldType = 'text' | 'textarea' | 'number' | 'select' | 'multi-select' | 'checkbox' | 'radio' | 'date' | 'datetime' | 'upload' | 'hidden' | 'readonly';
7
+ export type ExportFormat = 'csv' | 'excel' | 'pdf' | 'clipboard' | 'print';
8
+ export interface ColumnDef<T = any> {
9
+ key: string;
10
+ header: string;
11
+ type?: ColumnType;
12
+ sortable?: boolean;
13
+ searchable?: boolean;
14
+ filterable?: boolean;
15
+ visible?: boolean;
16
+ width?: string;
17
+ minWidth?: string;
18
+ maxWidth?: string;
19
+ className?: string;
20
+ headerClassName?: string;
21
+ orderable?: boolean;
22
+ defaultSort?: 'asc' | 'desc';
23
+ footer?: string | ((rows: T[]) => string | number);
24
+ editable?: boolean;
25
+ editorField?: EditorFieldDef;
26
+ }
27
+ export interface SortState {
28
+ column: string;
29
+ direction: 'asc' | 'desc';
30
+ }
31
+ export interface FilterState {
32
+ column: string;
33
+ value: any;
34
+ operator: FilterOperator;
35
+ }
36
+ export interface PaginationState {
37
+ page: number;
38
+ perPage: number;
39
+ total: number;
40
+ lastPage: number;
41
+ }
42
+ export interface DataTableRequest {
43
+ draw: number;
44
+ start: number;
45
+ length: number;
46
+ search: {
47
+ value: string;
48
+ regex: boolean;
49
+ };
50
+ order: {
51
+ column: number;
52
+ dir: 'asc' | 'desc';
53
+ }[];
54
+ columns: {
55
+ data: string;
56
+ name: string;
57
+ searchable: boolean;
58
+ orderable: boolean;
59
+ search: {
60
+ value: string;
61
+ regex: boolean;
62
+ };
63
+ }[];
64
+ }
65
+ export interface DataTableResponse<T = any> {
66
+ draw: number;
67
+ recordsTotal: number;
68
+ recordsFiltered: number;
69
+ data: T[];
70
+ error?: string;
71
+ }
72
+ export interface EditorFieldDef {
73
+ name: string;
74
+ type: FieldType;
75
+ label: string;
76
+ placeholder?: string;
77
+ options?: {
78
+ label: string;
79
+ value: any;
80
+ }[];
81
+ multiple?: boolean;
82
+ required?: boolean;
83
+ disabled?: boolean;
84
+ className?: string;
85
+ dependsOn?: string;
86
+ dependsOnValue?: any;
87
+ showWhen?: (formData: Record<string, any>) => boolean;
88
+ defaultValue?: any;
89
+ }
90
+ export interface ButtonDef {
91
+ key: string;
92
+ label: string;
93
+ icon?: Component<any>;
94
+ action?: string | ((selectedRows: any[], allData: any[]) => void | Promise<void>);
95
+ variant?: 'default' | 'destructive' | 'outline' | 'secondary' | 'ghost';
96
+ disabled?: boolean | ((selectedRows: any[]) => boolean);
97
+ collection?: ButtonDef[];
98
+ }
99
+ export interface DataTableClassNames {
100
+ container?: string;
101
+ toolbar?: string;
102
+ toolbarLeft?: string;
103
+ toolbarRight?: string;
104
+ searchInput?: string;
105
+ table?: string;
106
+ thead?: string;
107
+ th?: string;
108
+ thSortable?: string;
109
+ tbody?: string;
110
+ tr?: string;
111
+ trSelected?: string;
112
+ trEven?: string;
113
+ td?: string;
114
+ tfoot?: string;
115
+ tf?: string;
116
+ pagination?: string;
117
+ paginationInfo?: string;
118
+ paginationControls?: string;
119
+ pageButton?: string;
120
+ pageButtonActive?: string;
121
+ perPageSelect?: string;
122
+ btn?: string;
123
+ btnCreate?: string;
124
+ btnEdit?: string;
125
+ btnDelete?: string;
126
+ editorModal?: string;
127
+ editorBackdrop?: string;
128
+ editorField?: string;
129
+ editorInput?: string;
130
+ editorLabel?: string;
131
+ loading?: string;
132
+ empty?: string;
133
+ error?: string;
134
+ }
135
+ export interface DataTableConfig<T = any> {
136
+ data?: T[];
137
+ serverUrl?: string;
138
+ serverMethod?: 'GET' | 'POST';
139
+ csrfCookieName?: string;
140
+ csrfHeaderName?: string;
141
+ columns: ColumnDef<T>[];
142
+ sortable?: boolean;
143
+ searchable?: boolean;
144
+ paginate?: boolean;
145
+ selectable?: SelectionMode;
146
+ perPage?: number;
147
+ perPageOptions?: number[];
148
+ searchDebounceMs?: number;
149
+ stateSaveKey?: string;
150
+ rowId?: string | ((row: T) => string | number);
151
+ rowClass?: string | ((row: T, index: number) => string);
152
+ buttons?: (ButtonDef | ExportFormat)[];
153
+ editorMode?: EditorMode;
154
+ editorFields?: EditorFieldDef[];
155
+ onSort?: (sort: SortState[]) => void;
156
+ onFilter?: (filters: FilterState[]) => void;
157
+ onPageChange?: (page: number, perPage: number) => void;
158
+ onSelect?: (selectedRows: T[]) => void;
159
+ onRowClick?: (row: T, event: MouseEvent) => void;
160
+ onEdit?: (row: T, data: Record<string, any>) => void | Promise<void>;
161
+ onCellEdit?: (row: T, columnKey: string, newValue: any, oldValue: any) => void | Promise<void>;
162
+ onCreate?: (data: Record<string, any>) => void | Promise<void>;
163
+ onDelete?: (rows: T[]) => void | Promise<void>;
164
+ virtualScroll?: boolean;
165
+ virtualRowHeight?: number;
166
+ responsive?: boolean;
167
+ groupBy?: string;
168
+ expandable?: boolean;
169
+ emptyText?: string;
170
+ loadingText?: string;
171
+ className?: string;
172
+ compact?: boolean;
173
+ striped?: boolean;
174
+ hover?: boolean;
175
+ bordered?: boolean;
176
+ classNames?: DataTableClassNames;
177
+ unstyled?: boolean;
178
+ }
179
+ export interface DataTableState<T = any> {
180
+ allRows: T[];
181
+ filteredRows: T[];
182
+ sortedRows: T[];
183
+ paginatedRows: T[];
184
+ sort: SortState[];
185
+ filters: FilterState[];
186
+ globalSearch: string;
187
+ pagination: PaginationState;
188
+ selectedIds: Set<string | number>;
189
+ columnVisibility: Record<string, boolean>;
190
+ columnOrder: string[];
191
+ loading: boolean;
192
+ error: string | null;
193
+ editingRowId: string | number | null;
194
+ editingColumn: string | null;
195
+ editorMode: EditorMode | null;
196
+ formData: Record<string, any>;
197
+ validationErrors: Record<string, string>;
198
+ draw: number;
199
+ excelFocusedCell: {
200
+ rowIndex: number;
201
+ columnKey: string;
202
+ } | null;
203
+ excelEditingCell: {
204
+ rowIndex: number;
205
+ columnKey: string;
206
+ } | null;
207
+ excelEditValue: string;
208
+ }
package/dist/types.js ADDED
File without changes
@@ -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';