@beeblock/svelar-datatable 0.1.0 → 0.1.1

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/README.md CHANGED
@@ -23,10 +23,15 @@ Full-featured DataTable plugin for [Svelar](https://svelar.dev) / SvelteKit 2 wi
23
23
  - **Footer aggregation** — per-column footer with custom functions
24
24
  - **Responsive** — horizontal scroll for small screens
25
25
 
26
- ## Install
26
+ ## Installation
27
27
 
28
28
  ```bash
29
+ # Install and publish route stubs
30
+ npx svelar plugin:install @beeblock/svelar-datatable
31
+
32
+ # Or manual install
29
33
  npm install @beeblock/svelar-datatable
34
+ npx svelar plugin:publish @beeblock/svelar-datatable
30
35
  ```
31
36
 
32
37
  Peer dependencies: `@beeblock/svelar >= 0.4.0`, `svelte ^5.0.0`
@@ -9,5 +9,12 @@ export declare class SvelarDatatablePlugin {
9
9
  get name(): string;
10
10
  get config(): DatatablePluginConfig;
11
11
  static defaults(): Partial<DataTableConfig>;
12
+ publishables(): {
13
+ routes: {
14
+ source: string;
15
+ dest: string;
16
+ type: "asset";
17
+ }[];
18
+ };
12
19
  }
13
20
  export {};
package/dist/index.js CHANGED
@@ -1,4 +1,4 @@
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(`
1
+ import{fileURLToPath as I}from"url";import{dirname as P,join as V}from"path";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}}publishables(){let t=P(I(import.meta.url));return{routes:[{source:V(t,"publishable/routes/datatable.ts"),dest:"src/routes/api/datatable/+server.ts",type:"asset"}]}}};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 j(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=j(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
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
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
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>
package/package.json CHANGED
@@ -1,9 +1,15 @@
1
1
  {
2
2
  "name": "@beeblock/svelar-datatable",
3
- "version": "0.1.0",
3
+ "version": "0.1.1",
4
4
  "description": "Full-featured DataTable plugin for Svelar — sorting, searching, pagination, inline editing, export, and server-side processing",
5
5
  "type": "module",
6
- "keywords": ["svelar-plugin", "datatable", "svelte", "sveltekit", "data-grid"],
6
+ "keywords": [
7
+ "svelar-plugin",
8
+ "datatable",
9
+ "svelte",
10
+ "sveltekit",
11
+ "data-grid"
12
+ ],
7
13
  "license": "MIT",
8
14
  "main": "dist/index.js",
9
15
  "types": "dist/index.d.ts",
@@ -24,7 +30,12 @@
24
30
  "./ui": "./src/ui/index.ts",
25
31
  "./ui/*": "./src/ui/*"
26
32
  },
27
- "files": ["dist", "src/ui", "LICENSE"],
33
+ "files": [
34
+ "dist",
35
+ "src/ui",
36
+ "src/publishable",
37
+ "LICENSE"
38
+ ],
28
39
  "scripts": {
29
40
  "build": "tsup && (tsc --emitDeclarationOnly || echo 'Warning: tsc declaration emit had errors')",
30
41
  "dev": "tsup --watch"
@@ -34,8 +45,12 @@
34
45
  "svelte": "^5.0.0"
35
46
  },
36
47
  "peerDependenciesMeta": {
37
- "exceljs": { "optional": true },
38
- "@beeblock/svelar": { "optional": false }
48
+ "exceljs": {
49
+ "optional": true
50
+ },
51
+ "@beeblock/svelar": {
52
+ "optional": false
53
+ }
39
54
  },
40
55
  "devDependencies": {
41
56
  "tsup": "^8.5.0",
@@ -0,0 +1,30 @@
1
+ // API routes for @beeblock/svelar-datatable
2
+ // Copy to: src/routes/api/datatable/+server.ts
3
+
4
+ import { DataTableController } from '@beeblock/svelar-datatable/server';
5
+ import type { RequestHandler } from './$types';
6
+
7
+ // Replace `YourModel` with your actual Eloquent-style model import.
8
+ // Options let you customise searchable columns, sorting, etc.
9
+ //
10
+ // import { User } from '$lib/models/User';
11
+ //
12
+ // export const GET: RequestHandler = (event) =>
13
+ // DataTableController.handle(event, User, {
14
+ // searchable: ['name', 'email'],
15
+ // sortable: ['name', 'email', 'created_at'],
16
+ // });
17
+ //
18
+ // POST is also supported for complex filter payloads:
19
+ // export const POST: RequestHandler = (event) =>
20
+ // DataTableController.handle(event, User);
21
+
22
+ export const GET: RequestHandler = (event) => {
23
+ // TODO: replace with your model and options
24
+ throw new Error('Configure your model in this route before using DataTableController.handle()');
25
+ };
26
+
27
+ export const POST: RequestHandler = (event) => {
28
+ // TODO: replace with your model and options
29
+ throw new Error('Configure your model in this route before using DataTableController.handle()');
30
+ };