@toolbox-web/grid 1.13.0 → 1.14.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.
Files changed (91) hide show
  1. package/all.js +1850 -1742
  2. package/all.js.map +1 -1
  3. package/index.js +159 -139
  4. package/index.js.map +1 -1
  5. package/lib/core/grid.d.ts.map +1 -1
  6. package/lib/core/internal/loading.d.ts +2 -0
  7. package/lib/core/internal/loading.d.ts.map +1 -1
  8. package/lib/core/internal/row-animation.d.ts.map +1 -1
  9. package/lib/core/internal/rows.d.ts.map +1 -1
  10. package/lib/core/plugin/types.d.ts +1 -1
  11. package/lib/core/plugin/types.d.ts.map +1 -1
  12. package/lib/core/types.d.ts +44 -1
  13. package/lib/core/types.d.ts.map +1 -1
  14. package/lib/plugins/clipboard/ClipboardPlugin.d.ts +69 -8
  15. package/lib/plugins/clipboard/ClipboardPlugin.d.ts.map +1 -1
  16. package/lib/plugins/clipboard/index.d.ts +1 -1
  17. package/lib/plugins/clipboard/index.d.ts.map +1 -1
  18. package/lib/plugins/clipboard/index.js +257 -192
  19. package/lib/plugins/clipboard/index.js.map +1 -1
  20. package/lib/plugins/clipboard/types.d.ts +31 -0
  21. package/lib/plugins/clipboard/types.d.ts.map +1 -1
  22. package/lib/plugins/column-virtualization/index.js.map +1 -1
  23. package/lib/plugins/context-menu/ContextMenuPlugin.d.ts +8 -0
  24. package/lib/plugins/context-menu/ContextMenuPlugin.d.ts.map +1 -1
  25. package/lib/plugins/context-menu/index.js +75 -60
  26. package/lib/plugins/context-menu/index.js.map +1 -1
  27. package/lib/plugins/context-menu/types.d.ts +7 -0
  28. package/lib/plugins/context-menu/types.d.ts.map +1 -1
  29. package/lib/plugins/editing/EditingPlugin.d.ts.map +1 -1
  30. package/lib/plugins/editing/editors.d.ts +2 -2
  31. package/lib/plugins/editing/editors.d.ts.map +1 -1
  32. package/lib/plugins/editing/index.js +420 -381
  33. package/lib/plugins/editing/index.js.map +1 -1
  34. package/lib/plugins/editing/types.d.ts +6 -23
  35. package/lib/plugins/editing/types.d.ts.map +1 -1
  36. package/lib/plugins/export/ExportPlugin.d.ts.map +1 -1
  37. package/lib/plugins/export/index.js +75 -66
  38. package/lib/plugins/export/index.js.map +1 -1
  39. package/lib/plugins/filtering/FilteringPlugin.d.ts +2 -0
  40. package/lib/plugins/filtering/FilteringPlugin.d.ts.map +1 -1
  41. package/lib/plugins/filtering/filter-model.d.ts.map +1 -1
  42. package/lib/plugins/filtering/index.d.ts +1 -1
  43. package/lib/plugins/filtering/index.d.ts.map +1 -1
  44. package/lib/plugins/filtering/index.js +319 -290
  45. package/lib/plugins/filtering/index.js.map +1 -1
  46. package/lib/plugins/grouping-columns/index.js.map +1 -1
  47. package/lib/plugins/grouping-rows/index.js.map +1 -1
  48. package/lib/plugins/master-detail/index.js.map +1 -1
  49. package/lib/plugins/multi-sort/index.js.map +1 -1
  50. package/lib/plugins/pinned-columns/index.js.map +1 -1
  51. package/lib/plugins/pinned-rows/PinnedRowsPlugin.d.ts +1 -0
  52. package/lib/plugins/pinned-rows/PinnedRowsPlugin.d.ts.map +1 -1
  53. package/lib/plugins/pinned-rows/index.js +118 -87
  54. package/lib/plugins/pinned-rows/index.js.map +1 -1
  55. package/lib/plugins/pinned-rows/pinned-rows.d.ts +2 -1
  56. package/lib/plugins/pinned-rows/pinned-rows.d.ts.map +1 -1
  57. package/lib/plugins/pinned-rows/types.d.ts +23 -2
  58. package/lib/plugins/pinned-rows/types.d.ts.map +1 -1
  59. package/lib/plugins/pivot/index.js.map +1 -1
  60. package/lib/plugins/print/index.js.map +1 -1
  61. package/lib/plugins/reorder/index.js.map +1 -1
  62. package/lib/plugins/responsive/index.js.map +1 -1
  63. package/lib/plugins/row-reorder/index.js.map +1 -1
  64. package/lib/plugins/selection/SelectionPlugin.d.ts.map +1 -1
  65. package/lib/plugins/selection/index.js +94 -86
  66. package/lib/plugins/selection/index.js.map +1 -1
  67. package/lib/plugins/server-side/index.js.map +1 -1
  68. package/lib/plugins/shared/data-collection.d.ts +33 -0
  69. package/lib/plugins/shared/data-collection.d.ts.map +1 -0
  70. package/lib/plugins/tree/index.js.map +1 -1
  71. package/lib/plugins/undo-redo/index.js.map +1 -1
  72. package/lib/plugins/visibility/index.js.map +1 -1
  73. package/package.json +1 -1
  74. package/umd/grid.all.umd.js +31 -31
  75. package/umd/grid.all.umd.js.map +1 -1
  76. package/umd/grid.umd.js +4 -4
  77. package/umd/grid.umd.js.map +1 -1
  78. package/umd/plugins/clipboard.umd.js +5 -5
  79. package/umd/plugins/clipboard.umd.js.map +1 -1
  80. package/umd/plugins/context-menu.umd.js +1 -1
  81. package/umd/plugins/context-menu.umd.js.map +1 -1
  82. package/umd/plugins/editing.umd.js +1 -1
  83. package/umd/plugins/editing.umd.js.map +1 -1
  84. package/umd/plugins/export.umd.js +7 -7
  85. package/umd/plugins/export.umd.js.map +1 -1
  86. package/umd/plugins/filtering.umd.js +1 -1
  87. package/umd/plugins/filtering.umd.js.map +1 -1
  88. package/umd/plugins/pinned-rows.umd.js +1 -1
  89. package/umd/plugins/pinned-rows.umd.js.map +1 -1
  90. package/umd/plugins/selection.umd.js +2 -2
  91. package/umd/plugins/selection.umd.js.map +1 -1
@@ -1,14 +1,14 @@
1
- (function(a,p){typeof exports=="object"&&typeof module<"u"?p(exports,require("../../core/plugin/base-plugin")):typeof define=="function"&&define.amd?define(["exports","../../core/plugin/base-plugin"],p):(a=typeof globalThis<"u"?globalThis:a||self,p(a.TbwGridPlugin_export={},a.TbwGrid))})(this,(function(a,p){"use strict";function b(i,t=!0){if(i==null)return"";if(i instanceof Date)return i.toISOString();if(typeof i=="object")return JSON.stringify(i);const e=String(i);return t&&(e.includes(",")||e.includes('"')||e.includes(`
2
- `)||e.includes("\r"))?`"${e.replace(/"/g,'""')}"`:e}function y(i,t,e,o={}){const c=o.delimiter??",",r=o.newline??`
3
- `,s=[],l=o.bom?"\uFEFF":"";if(e.includeHeaders!==!1){const n=t.map(f=>{const d=f.header||f.field,u=e.processHeader?e.processHeader(d,f.field):d;return b(u)});s.push(n.join(c))}for(const n of i){const f=t.map(d=>{let u=n[d.field];return e.processCell&&(u=e.processCell(u,d.field,n)),b(u)});s.push(f.join(c))}return l+s.join(r)}function h(i,t){const e=URL.createObjectURL(i),o=document.createElement("a");o.href=e,o.download=t,o.style.display="none",document.body.appendChild(o),o.click(),document.body.removeChild(o),URL.revokeObjectURL(e)}function S(i,t){const e=new Blob([i],{type:"text/csv;charset=utf-8;"});h(e,t)}function m(i){return i.replace(/&/g,"&amp;").replace(/</g,"&lt;").replace(/>/g,"&gt;").replace(/"/g,"&quot;").replace(/'/g,"&apos;")}function C(i,t,e){let o=`<?xml version="1.0" encoding="UTF-8"?>
1
+ (function(d,p){typeof exports=="object"&&typeof module<"u"?p(exports,require("../../core/plugin/base-plugin")):typeof define=="function"&&define.amd?define(["exports","../../core/plugin/base-plugin"],p):(d=typeof globalThis<"u"?globalThis:d||self,p(d.TbwGridPlugin_export={},d.TbwGrid))})(this,(function(d,p){"use strict";function S(o,n,e=!0){let t=o;if(e&&(t=t.filter(i=>!i.hidden&&!i.field.startsWith("__")&&i.meta?.utility!==!0)),n?.length){const i=new Set(n);t=t.filter(c=>i.has(c.field))}return t}function m(o,n){return n?.length?[...n].sort((e,t)=>e-t).map(e=>o[e]).filter(e=>e!=null):o}function b(o,n=!0){if(o==null)return"";if(o instanceof Date)return o.toISOString();if(typeof o=="object")return JSON.stringify(o);const e=String(o);return n&&(e.includes(",")||e.includes('"')||e.includes(`
2
+ `)||e.includes("\r"))?`"${e.replace(/"/g,'""')}"`:e}function C(o,n,e,t={}){const i=t.delimiter??",",c=t.newline??`
3
+ `,s=[],l=t.bom?"\uFEFF":"";if(e.includeHeaders!==!1){const r=n.map(u=>{const a=u.header||u.field,f=e.processHeader?e.processHeader(a,u.field):a;return b(f)});s.push(r.join(i))}for(const r of o){const u=n.map(a=>{let f=r[a.field];return e.processCell&&(f=e.processCell(f,a.field,r)),b(f)});s.push(u.join(i))}return l+s.join(c)}function h(o,n){const e=URL.createObjectURL(o),t=document.createElement("a");t.href=e,t.download=n,t.style.display="none",document.body.appendChild(t),t.click(),document.body.removeChild(t),URL.revokeObjectURL(e)}function E(o,n){const e=new Blob([o],{type:"text/csv;charset=utf-8;"});h(e,n)}function w(o){return o.replace(/&/g,"&amp;").replace(/</g,"&lt;").replace(/>/g,"&gt;").replace(/"/g,"&quot;").replace(/'/g,"&apos;")}function j(o,n,e){let t=`<?xml version="1.0" encoding="UTF-8"?>
4
4
  <?mso-application progid="Excel.Sheet"?>
5
5
  <Workbook xmlns="urn:schemas-microsoft-com:office:spreadsheet"
6
6
  xmlns:ss="urn:schemas-microsoft-com:office:spreadsheet">
7
7
  <Worksheet ss:Name="Sheet1">
8
- <Table>`;if(e.includeHeaders!==!1){o+=`
9
- <Row>`;for(const c of t){const r=c.header||c.field,s=e.processHeader?e.processHeader(r,c.field):r;o+=`<Cell><Data ss:Type="String">${m(s)}</Data></Cell>`}o+="</Row>"}for(const c of i){o+=`
10
- <Row>`;for(const r of t){let s=c[r.field];e.processCell&&(s=e.processCell(s,r.field,c));let l="String",n="";s==null?n="":typeof s=="number"&&!isNaN(s)?(l="Number",n=String(s)):s instanceof Date?(l="DateTime",n=s.toISOString()):n=m(String(s)),o+=`<Cell><Data ss:Type="${l}">${n}</Data></Cell>`}o+="</Row>"}return o+=`
8
+ <Table>`;if(e.includeHeaders!==!1){t+=`
9
+ <Row>`;for(const i of n){const c=i.header||i.field,s=e.processHeader?e.processHeader(c,i.field):c;t+=`<Cell><Data ss:Type="String">${w(s)}</Data></Cell>`}t+="</Row>"}for(const i of o){t+=`
10
+ <Row>`;for(const c of n){let s=i[c.field];e.processCell&&(s=e.processCell(s,c.field,i));let l="String",r="";s==null?r="":typeof s=="number"&&!isNaN(s)?(l="Number",r=String(s)):s instanceof Date?(l="DateTime",r=s.toISOString()):r=w(String(s)),t+=`<Cell><Data ss:Type="${l}">${r}</Data></Cell>`}t+="</Row>"}return t+=`
11
11
  </Table>
12
12
  </Worksheet>
13
- </Workbook>`,o}function E(i,t){const e=t.endsWith(".xls")?t:`${t}.xls`,o=new Blob([i],{type:"application/vnd.ms-excel;charset=utf-8;"});h(o,e)}class j extends p.BaseGridPlugin{name="export";get defaultConfig(){return{fileName:"export",includeHeaders:!0,onlyVisible:!0,onlySelected:!1}}isExportingFlag=!1;lastExportInfo=null;performExport(t,e){const o=this.config,c={format:t,fileName:e?.fileName??o.fileName??"export",includeHeaders:e?.includeHeaders??o.includeHeaders,processCell:e?.processCell,processHeader:e?.processHeader,columns:e?.columns,rowIndices:e?.rowIndices};let r=[...this.columns];if(o.onlyVisible&&(r=r.filter(n=>!n.hidden&&!n.field.startsWith("__"))),e?.columns){const n=new Set(e.columns);r=r.filter(f=>n.has(f.field))}let s=[...this.rows];if(o.onlySelected){const n=this.getSelectionState();n?.selected?.size&&(s=[...n.selected].sort((d,u)=>d-u).map(d=>this.rows[d]).filter(Boolean))}e?.rowIndices&&(s=e.rowIndices.map(n=>this.rows[n]).filter(Boolean)),this.isExportingFlag=!0;let l=c.fileName;try{switch(t){case"csv":{const n=y(s,r,c,{bom:!0});l=l.endsWith(".csv")?l:`${l}.csv`,S(n,l);break}case"excel":{const n=C(s,r,c);l=l.endsWith(".xls")?l:`${l}.xls`,E(n,l);break}case"json":{const n=s.map(u=>{const w={};for(const g of r){let x=u[g.field];c.processCell&&(x=c.processCell(x,g.field,u)),w[g.field]=x}return w}),f=JSON.stringify(n,null,2);l=l.endsWith(".json")?l:`${l}.json`;const d=new Blob([f],{type:"application/json"});h(d,l);break}}this.lastExportInfo={format:t,timestamp:new Date},this.emit("export-complete",{format:t,fileName:l,rowCount:s.length,columnCount:r.length})}finally{this.isExportingFlag=!1}}getSelectionState(){try{return this.grid?.getPluginState?.("selection")??null}catch{return null}}exportCsv(t){this.performExport("csv",t)}exportExcel(t){this.performExport("excel",t)}exportJson(t){this.performExport("json",t)}isExporting(){return this.isExportingFlag}getLastExport(){return this.lastExportInfo}}a.ExportPlugin=j,Object.defineProperty(a,Symbol.toStringTag,{value:"Module"})}));
13
+ </Workbook>`,t}function v(o,n){const e=n.endsWith(".xls")?n:`${n}.xls`,t=new Blob([o],{type:"application/vnd.ms-excel;charset=utf-8;"});h(t,e)}class k extends p.BaseGridPlugin{name="export";get defaultConfig(){return{fileName:"export",includeHeaders:!0,onlyVisible:!0,onlySelected:!1}}isExportingFlag=!1;lastExportInfo=null;performExport(n,e){const t=this.config,i={format:n,fileName:e?.fileName??t.fileName??"export",includeHeaders:e?.includeHeaders??t.includeHeaders,processCell:e?.processCell,processHeader:e?.processHeader,columns:e?.columns,rowIndices:e?.rowIndices},c=S(this.columns,e?.columns,t.onlyVisible);let s;if(e?.rowIndices)s=m(this.rows,e.rowIndices);else if(t.onlySelected){const r=this.getSelectionState();r?.selected?.size?s=m(this.rows,[...r.selected]):s=[...this.rows]}else s=[...this.rows];this.isExportingFlag=!0;let l=i.fileName;try{switch(n){case"csv":{const r=C(s,c,i,{bom:!0});l=l.endsWith(".csv")?l:`${l}.csv`,E(r,l);break}case"excel":{const r=j(s,c,i);l=l.endsWith(".xls")?l:`${l}.xls`,v(r,l);break}case"json":{const r=s.map(f=>{const y={};for(const g of c){let x=f[g.field];i.processCell&&(x=i.processCell(x,g.field,f)),y[g.field]=x}return y}),u=JSON.stringify(r,null,2);l=l.endsWith(".json")?l:`${l}.json`;const a=new Blob([u],{type:"application/json"});h(a,l);break}}this.lastExportInfo={format:n,timestamp:new Date},this.emit("export-complete",{format:n,fileName:l,rowCount:s.length,columnCount:c.length})}finally{this.isExportingFlag=!1}}getSelectionState(){try{return this.grid?.getPluginState?.("selection")??null}catch{return null}}exportCsv(n){this.performExport("csv",n)}exportExcel(n){this.performExport("excel",n)}exportJson(n){this.performExport("json",n)}isExporting(){return this.isExportingFlag}getLastExport(){return this.lastExportInfo}}d.ExportPlugin=k,Object.defineProperty(d,Symbol.toStringTag,{value:"Module"})}));
14
14
  //# sourceMappingURL=export.umd.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"export.umd.js","sources":["../../../../../libs/grid/src/lib/plugins/export/csv.ts","../../../../../libs/grid/src/lib/plugins/export/excel.ts","../../../../../libs/grid/src/lib/plugins/export/ExportPlugin.ts"],"sourcesContent":["/**\n * CSV Export Utilities\n *\n * Functions for building and downloading CSV content.\n */\n\nimport type { ColumnConfig } from '../../core/types';\nimport type { ExportParams } from './types';\n\n/** CSV export options */\nexport interface CsvOptions {\n /** Field delimiter (default: ',') */\n delimiter?: string;\n /** Line separator (default: '\\n') */\n newline?: string;\n /** Whether to quote strings containing special characters (default: true) */\n quoteStrings?: boolean;\n /** Add UTF-8 BOM for Excel compatibility (default: false) */\n bom?: boolean;\n}\n\n/**\n * Format a value for CSV output.\n * Handles null, Date, objects, and strings with special characters.\n */\nexport function formatCsvValue(value: any, quote = true): string {\n if (value == null) return '';\n if (value instanceof Date) return value.toISOString();\n if (typeof value === 'object') return JSON.stringify(value);\n\n const str = String(value);\n\n // Quote if contains special characters (comma, quote, newline)\n if (quote && (str.includes(',') || str.includes('\"') || str.includes('\\n') || str.includes('\\r'))) {\n return `\"${str.replace(/\"/g, '\"\"')}\"`;\n }\n\n return str;\n}\n\n/**\n * Build CSV content from rows and columns.\n */\nexport function buildCsv(rows: any[], columns: ColumnConfig[], params: ExportParams, options: CsvOptions = {}): string {\n const delimiter = options.delimiter ?? ',';\n const newline = options.newline ?? '\\n';\n const lines: string[] = [];\n\n // UTF-8 BOM for Excel compatibility\n const bom = options.bom ? '\\uFEFF' : '';\n\n // Build header row\n if (params.includeHeaders !== false) {\n const headerRow = columns.map((col) => {\n const header = col.header || col.field;\n const processed = params.processHeader ? params.processHeader(header, col.field) : header;\n return formatCsvValue(processed);\n });\n lines.push(headerRow.join(delimiter));\n }\n\n // Build data rows\n for (const row of rows) {\n const cells = columns.map((col) => {\n let value = row[col.field];\n if (params.processCell) {\n value = params.processCell(value, col.field, row);\n }\n return formatCsvValue(value);\n });\n lines.push(cells.join(delimiter));\n }\n\n return bom + lines.join(newline);\n}\n\n/**\n * Download a Blob as a file.\n */\nexport function downloadBlob(blob: Blob, fileName: string): void {\n const url = URL.createObjectURL(blob);\n const link = document.createElement('a');\n link.href = url;\n link.download = fileName;\n link.style.display = 'none';\n document.body.appendChild(link);\n link.click();\n document.body.removeChild(link);\n URL.revokeObjectURL(url);\n}\n\n/**\n * Download CSV content as a file.\n */\nexport function downloadCsv(content: string, fileName: string): void {\n const blob = new Blob([content], { type: 'text/csv;charset=utf-8;' });\n downloadBlob(blob, fileName);\n}\n","/**\n * Excel Export Utilities\n *\n * Simple Excel XML format export (no external dependencies).\n * Produces XML Spreadsheet 2003 format which opens in Excel.\n */\n\nimport type { ColumnConfig } from '../../core/types';\nimport type { ExportParams } from './types';\nimport { downloadBlob } from './csv';\n\n/**\n * Escape XML special characters.\n */\nfunction escapeXml(str: string): string {\n return str\n .replace(/&/g, '&amp;')\n .replace(/</g, '&lt;')\n .replace(/>/g, '&gt;')\n .replace(/\"/g, '&quot;')\n .replace(/'/g, '&apos;');\n}\n\n/**\n * Build Excel XML content from rows and columns.\n * Uses XML Spreadsheet 2003 format for broad compatibility.\n */\nexport function buildExcelXml(rows: any[], columns: ColumnConfig[], params: ExportParams): string {\n let xml = `<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<?mso-application progid=\"Excel.Sheet\"?>\n<Workbook xmlns=\"urn:schemas-microsoft-com:office:spreadsheet\"\n xmlns:ss=\"urn:schemas-microsoft-com:office:spreadsheet\">\n<Worksheet ss:Name=\"Sheet1\">\n<Table>`;\n\n // Build header row\n if (params.includeHeaders !== false) {\n xml += '\\n<Row>';\n for (const col of columns) {\n const header = col.header || col.field;\n const processed = params.processHeader ? params.processHeader(header, col.field) : header;\n xml += `<Cell><Data ss:Type=\"String\">${escapeXml(processed)}</Data></Cell>`;\n }\n xml += '</Row>';\n }\n\n // Build data rows\n for (const row of rows) {\n xml += '\\n<Row>';\n for (const col of columns) {\n let value = row[col.field];\n if (params.processCell) {\n value = params.processCell(value, col.field, row);\n }\n\n // Determine cell type based on value\n let type: 'Number' | 'String' | 'DateTime' = 'String';\n let displayValue = '';\n\n if (value == null) {\n displayValue = '';\n } else if (typeof value === 'number' && !isNaN(value)) {\n type = 'Number';\n displayValue = String(value);\n } else if (value instanceof Date) {\n type = 'DateTime';\n displayValue = value.toISOString();\n } else {\n displayValue = escapeXml(String(value));\n }\n\n xml += `<Cell><Data ss:Type=\"${type}\">${displayValue}</Data></Cell>`;\n }\n xml += '</Row>';\n }\n\n xml += '\\n</Table>\\n</Worksheet>\\n</Workbook>';\n return xml;\n}\n\n/**\n * Download Excel XML content as a file.\n */\nexport function downloadExcel(content: string, fileName: string): void {\n const finalName = fileName.endsWith('.xls') ? fileName : `${fileName}.xls`;\n const blob = new Blob([content], {\n type: 'application/vnd.ms-excel;charset=utf-8;',\n });\n downloadBlob(blob, finalName);\n}\n","/**\n * Export Plugin (Class-based)\n *\n * Provides data export functionality for tbw-grid.\n * Supports CSV, Excel (XML), and JSON formats.\n */\n\n/* eslint-disable @typescript-eslint/no-explicit-any */\n\nimport { BaseGridPlugin } from '../../core/plugin/base-plugin';\nimport type { ColumnConfig } from '../../core/types';\nimport { buildCsv, downloadBlob, downloadCsv } from './csv';\nimport { buildExcelXml, downloadExcel } from './excel';\nimport type { ExportCompleteDetail, ExportConfig, ExportFormat, ExportParams } from './types';\n\n/** Selection plugin state interface for type safety */\ninterface SelectionPluginState {\n selected: Set<number>;\n}\n\n/**\n * Export Plugin for tbw-grid\n *\n * Lets users download grid data as CSV, Excel (XML), or JSON with a single click\n * or API call. Great for reporting, data backup, or letting users work with data\n * in Excel. Integrates with SelectionPlugin to export only selected rows.\n *\n * ## Installation\n *\n * ```ts\n * import { ExportPlugin } from '@toolbox-web/grid/plugins/export';\n * ```\n *\n * ## Configuration Options\n *\n * | Option | Type | Default | Description |\n * |--------|------|---------|-------------|\n * | `fileName` | `string` | `'export'` | Base filename (without extension) |\n * | `includeHeaders` | `boolean` | `true` | Include column headers in export |\n * | `onlyVisible` | `boolean` | `true` | Export only visible columns |\n * | `onlySelected` | `boolean` | `false` | Export only selected rows (requires SelectionPlugin) |\n *\n * ## Supported Formats\n *\n * | Format | Method | Description |\n * |--------|--------|-------------|\n * | CSV | `exportToCSV()` | Comma-separated values |\n * | Excel | `exportToExcel()` | Excel XML format (.xlsx) |\n * | JSON | `exportToJSON()` | JSON array of objects |\n *\n * ## Programmatic API\n *\n * | Method | Signature | Description |\n * |--------|-----------|-------------|\n * | `exportToCSV` | `(params?) => void` | Export as CSV file |\n * | `exportToExcel` | `(params?) => void` | Export as Excel file |\n * | `exportToJSON` | `(params?) => void` | Export as JSON file |\n * | `isExporting` | `() => boolean` | Check if export is in progress |\n *\n * @example Basic Export with Button\n * ```ts\n * import '@toolbox-web/grid';\n * import { ExportPlugin } from '@toolbox-web/grid/plugins/export';\n *\n * const grid = document.querySelector('tbw-grid');\n * grid.gridConfig = {\n * columns: [\n * { field: 'name', header: 'Name' },\n * { field: 'email', header: 'Email' },\n * ],\n * plugins: [new ExportPlugin({ fileName: 'employees', includeHeaders: true })],\n * };\n *\n * // Trigger export via button\n * document.getElementById('export-btn').addEventListener('click', () => {\n * grid.getPlugin(ExportPlugin).exportToCSV();\n * });\n * ```\n *\n * @example Export Selected Rows Only\n * ```ts\n * import { SelectionPlugin } from '@toolbox-web/grid/plugins/selection';\n *\n * grid.gridConfig = {\n * plugins: [\n * new SelectionPlugin({ mode: 'row' }),\n * new ExportPlugin({ onlySelected: true }),\n * ],\n * };\n * ```\n *\n * @see {@link ExportConfig} for all configuration options\n * @see {@link ExportParams} for method parameters\n * @see {@link SelectionPlugin} for exporting selected rows\n *\n * @internal Extends BaseGridPlugin\n */\nexport class ExportPlugin extends BaseGridPlugin<ExportConfig> {\n /** @internal */\n readonly name = 'export';\n\n /** @internal */\n protected override get defaultConfig(): Partial<ExportConfig> {\n return {\n fileName: 'export',\n includeHeaders: true,\n onlyVisible: true,\n onlySelected: false,\n };\n }\n\n // #region Internal State\n private isExportingFlag = false;\n private lastExportInfo: { format: ExportFormat; timestamp: Date } | null = null;\n // #endregion\n\n // #region Private Methods\n\n private performExport(format: ExportFormat, params?: Partial<ExportParams>): void {\n const config = this.config;\n\n // Build full params with defaults\n const fullParams: ExportParams = {\n format,\n fileName: params?.fileName ?? config.fileName ?? 'export',\n includeHeaders: params?.includeHeaders ?? config.includeHeaders,\n processCell: params?.processCell,\n processHeader: params?.processHeader,\n columns: params?.columns,\n rowIndices: params?.rowIndices,\n };\n\n // Get columns to export\n let columns = [...this.columns] as ColumnConfig[];\n if (config.onlyVisible) {\n columns = columns.filter((c) => !c.hidden && !c.field.startsWith('__'));\n }\n if (params?.columns) {\n const colSet = new Set(params.columns);\n columns = columns.filter((c) => colSet.has(c.field));\n }\n\n // Get rows to export\n let rows = [...this.rows] as Record<string, unknown>[];\n if (config.onlySelected) {\n const selectionState = this.getSelectionState();\n if (selectionState?.selected?.size) {\n const sortedIndices = [...selectionState.selected].sort((a, b) => a - b);\n rows = sortedIndices.map((i) => this.rows[i]).filter(Boolean) as Record<string, unknown>[];\n }\n }\n if (params?.rowIndices) {\n rows = params.rowIndices.map((i) => this.rows[i]).filter(Boolean) as Record<string, unknown>[];\n }\n\n this.isExportingFlag = true;\n let fileName = fullParams.fileName!;\n\n try {\n switch (format) {\n case 'csv': {\n const content = buildCsv(rows, columns, fullParams, { bom: true });\n fileName = fileName.endsWith('.csv') ? fileName : `${fileName}.csv`;\n downloadCsv(content, fileName);\n break;\n }\n\n case 'excel': {\n const content = buildExcelXml(rows, columns, fullParams);\n fileName = fileName.endsWith('.xls') ? fileName : `${fileName}.xls`;\n downloadExcel(content, fileName);\n break;\n }\n\n case 'json': {\n const jsonData = rows.map((row) => {\n const obj: Record<string, any> = {};\n for (const col of columns) {\n let value = row[col.field];\n if (fullParams.processCell) {\n value = fullParams.processCell(value, col.field, row);\n }\n obj[col.field] = value;\n }\n return obj;\n });\n const content = JSON.stringify(jsonData, null, 2);\n fileName = fileName.endsWith('.json') ? fileName : `${fileName}.json`;\n const blob = new Blob([content], { type: 'application/json' });\n downloadBlob(blob, fileName);\n break;\n }\n }\n\n this.lastExportInfo = { format, timestamp: new Date() };\n\n this.emit<ExportCompleteDetail>('export-complete', {\n format,\n fileName,\n rowCount: rows.length,\n columnCount: columns.length,\n });\n } finally {\n this.isExportingFlag = false;\n }\n }\n\n private getSelectionState(): SelectionPluginState | null {\n try {\n return (this.grid?.getPluginState?.('selection') as SelectionPluginState | null) ?? null;\n } catch {\n return null;\n }\n }\n // #endregion\n\n // #region Public API\n\n /**\n * Export data to CSV format.\n * @param params - Optional export parameters\n */\n exportCsv(params?: Partial<ExportParams>): void {\n this.performExport('csv', params);\n }\n\n /**\n * Export data to Excel format (XML Spreadsheet).\n * @param params - Optional export parameters\n */\n exportExcel(params?: Partial<ExportParams>): void {\n this.performExport('excel', params);\n }\n\n /**\n * Export data to JSON format.\n * @param params - Optional export parameters\n */\n exportJson(params?: Partial<ExportParams>): void {\n this.performExport('json', params);\n }\n\n /**\n * Check if an export is currently in progress.\n * @returns Whether export is in progress\n */\n isExporting(): boolean {\n return this.isExportingFlag;\n }\n\n /**\n * Get information about the last export.\n * @returns Export info or null if no export has occurred\n */\n getLastExport(): { format: ExportFormat; timestamp: Date } | null {\n return this.lastExportInfo;\n }\n // #endregion\n}\n"],"names":["formatCsvValue","value","quote","str","buildCsv","rows","columns","params","options","delimiter","newline","lines","bom","headerRow","col","header","processed","row","cells","downloadBlob","blob","fileName","url","link","downloadCsv","content","escapeXml","buildExcelXml","xml","type","displayValue","downloadExcel","finalName","ExportPlugin","BaseGridPlugin","format","config","fullParams","c","colSet","selectionState","a","b","i","jsonData","obj"],"mappings":"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"}
1
+ {"version":3,"file":"export.umd.js","sources":["../../../../../libs/grid/src/lib/plugins/shared/data-collection.ts","../../../../../libs/grid/src/lib/plugins/export/csv.ts","../../../../../libs/grid/src/lib/plugins/export/excel.ts","../../../../../libs/grid/src/lib/plugins/export/ExportPlugin.ts"],"sourcesContent":["/**\n * Shared Data Collection Utilities\n *\n * Pure functions for resolving columns and formatting values, shared between\n * the Clipboard and Export plugins. Each plugin bundles its own copy of this\n * module (no chunk splitting) since plugin builds inline sibling imports.\n *\n * @internal\n */\n\nimport type { ColumnConfig } from '../../core/types';\n\n/**\n * Resolve which columns to include in a data export or copy operation.\n *\n * Filters out hidden columns, utility columns (`meta.utility`), and\n * internal columns (`__`-prefixed fields). Optionally restricts to an\n * explicit set of field names.\n *\n * @param columns - All column configurations\n * @param fields - If provided, only include columns whose field is in this list\n * @param onlyVisible - When `true` (default), exclude hidden and internal columns\n * @returns Filtered column array preserving original order\n */\nexport function resolveColumns(\n columns: readonly ColumnConfig[],\n fields?: string[],\n onlyVisible = true,\n): ColumnConfig[] {\n let result = columns as ColumnConfig[];\n\n if (onlyVisible) {\n result = result.filter((c) => !c.hidden && !c.field.startsWith('__') && c.meta?.utility !== true);\n }\n\n if (fields?.length) {\n const fieldSet = new Set(fields);\n result = result.filter((c) => fieldSet.has(c.field));\n }\n\n return result;\n}\n\n/**\n * Resolve which rows to include, optionally filtered to specific indices.\n *\n * @param rows - All row data\n * @param indices - If provided, only include rows at these indices (sorted ascending)\n * @returns Filtered row array\n */\nexport function resolveRows<T>(rows: readonly T[], indices?: number[]): T[] {\n if (!indices?.length) return rows as T[];\n\n return [...indices]\n .sort((a, b) => a - b)\n .map((i) => rows[i])\n .filter((r): r is T => r != null);\n}\n\n/**\n * Format a raw cell value as a text string.\n *\n * Provides the common null / Date / object → string conversion shared by\n * both clipboard and export output builders.\n *\n * @param value - The cell value to format\n * @returns A plain-text representation of the value\n */\nexport function formatValueAsText(value: unknown): string {\n if (value == null) return '';\n if (value instanceof Date) return value.toISOString();\n if (typeof value === 'object') return JSON.stringify(value);\n return String(value);\n}\n","/**\n * CSV Export Utilities\n *\n * Functions for building and downloading CSV content.\n */\n\nimport type { ColumnConfig } from '../../core/types';\nimport type { ExportParams } from './types';\n\n/** CSV export options */\nexport interface CsvOptions {\n /** Field delimiter (default: ',') */\n delimiter?: string;\n /** Line separator (default: '\\n') */\n newline?: string;\n /** Whether to quote strings containing special characters (default: true) */\n quoteStrings?: boolean;\n /** Add UTF-8 BOM for Excel compatibility (default: false) */\n bom?: boolean;\n}\n\n/**\n * Format a value for CSV output.\n * Handles null, Date, objects, and strings with special characters.\n */\nexport function formatCsvValue(value: any, quote = true): string {\n if (value == null) return '';\n if (value instanceof Date) return value.toISOString();\n if (typeof value === 'object') return JSON.stringify(value);\n\n const str = String(value);\n\n // Quote if contains special characters (comma, quote, newline)\n if (quote && (str.includes(',') || str.includes('\"') || str.includes('\\n') || str.includes('\\r'))) {\n return `\"${str.replace(/\"/g, '\"\"')}\"`;\n }\n\n return str;\n}\n\n/**\n * Build CSV content from rows and columns.\n */\nexport function buildCsv(rows: any[], columns: ColumnConfig[], params: ExportParams, options: CsvOptions = {}): string {\n const delimiter = options.delimiter ?? ',';\n const newline = options.newline ?? '\\n';\n const lines: string[] = [];\n\n // UTF-8 BOM for Excel compatibility\n const bom = options.bom ? '\\uFEFF' : '';\n\n // Build header row\n if (params.includeHeaders !== false) {\n const headerRow = columns.map((col) => {\n const header = col.header || col.field;\n const processed = params.processHeader ? params.processHeader(header, col.field) : header;\n return formatCsvValue(processed);\n });\n lines.push(headerRow.join(delimiter));\n }\n\n // Build data rows\n for (const row of rows) {\n const cells = columns.map((col) => {\n let value = row[col.field];\n if (params.processCell) {\n value = params.processCell(value, col.field, row);\n }\n return formatCsvValue(value);\n });\n lines.push(cells.join(delimiter));\n }\n\n return bom + lines.join(newline);\n}\n\n/**\n * Download a Blob as a file.\n */\nexport function downloadBlob(blob: Blob, fileName: string): void {\n const url = URL.createObjectURL(blob);\n const link = document.createElement('a');\n link.href = url;\n link.download = fileName;\n link.style.display = 'none';\n document.body.appendChild(link);\n link.click();\n document.body.removeChild(link);\n URL.revokeObjectURL(url);\n}\n\n/**\n * Download CSV content as a file.\n */\nexport function downloadCsv(content: string, fileName: string): void {\n const blob = new Blob([content], { type: 'text/csv;charset=utf-8;' });\n downloadBlob(blob, fileName);\n}\n","/**\n * Excel Export Utilities\n *\n * Simple Excel XML format export (no external dependencies).\n * Produces XML Spreadsheet 2003 format which opens in Excel.\n */\n\nimport type { ColumnConfig } from '../../core/types';\nimport type { ExportParams } from './types';\nimport { downloadBlob } from './csv';\n\n/**\n * Escape XML special characters.\n */\nfunction escapeXml(str: string): string {\n return str\n .replace(/&/g, '&amp;')\n .replace(/</g, '&lt;')\n .replace(/>/g, '&gt;')\n .replace(/\"/g, '&quot;')\n .replace(/'/g, '&apos;');\n}\n\n/**\n * Build Excel XML content from rows and columns.\n * Uses XML Spreadsheet 2003 format for broad compatibility.\n */\nexport function buildExcelXml(rows: any[], columns: ColumnConfig[], params: ExportParams): string {\n let xml = `<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<?mso-application progid=\"Excel.Sheet\"?>\n<Workbook xmlns=\"urn:schemas-microsoft-com:office:spreadsheet\"\n xmlns:ss=\"urn:schemas-microsoft-com:office:spreadsheet\">\n<Worksheet ss:Name=\"Sheet1\">\n<Table>`;\n\n // Build header row\n if (params.includeHeaders !== false) {\n xml += '\\n<Row>';\n for (const col of columns) {\n const header = col.header || col.field;\n const processed = params.processHeader ? params.processHeader(header, col.field) : header;\n xml += `<Cell><Data ss:Type=\"String\">${escapeXml(processed)}</Data></Cell>`;\n }\n xml += '</Row>';\n }\n\n // Build data rows\n for (const row of rows) {\n xml += '\\n<Row>';\n for (const col of columns) {\n let value = row[col.field];\n if (params.processCell) {\n value = params.processCell(value, col.field, row);\n }\n\n // Determine cell type based on value\n let type: 'Number' | 'String' | 'DateTime' = 'String';\n let displayValue = '';\n\n if (value == null) {\n displayValue = '';\n } else if (typeof value === 'number' && !isNaN(value)) {\n type = 'Number';\n displayValue = String(value);\n } else if (value instanceof Date) {\n type = 'DateTime';\n displayValue = value.toISOString();\n } else {\n displayValue = escapeXml(String(value));\n }\n\n xml += `<Cell><Data ss:Type=\"${type}\">${displayValue}</Data></Cell>`;\n }\n xml += '</Row>';\n }\n\n xml += '\\n</Table>\\n</Worksheet>\\n</Workbook>';\n return xml;\n}\n\n/**\n * Download Excel XML content as a file.\n */\nexport function downloadExcel(content: string, fileName: string): void {\n const finalName = fileName.endsWith('.xls') ? fileName : `${fileName}.xls`;\n const blob = new Blob([content], {\n type: 'application/vnd.ms-excel;charset=utf-8;',\n });\n downloadBlob(blob, finalName);\n}\n","/**\n * Export Plugin (Class-based)\n *\n * Provides data export functionality for tbw-grid.\n * Supports CSV, Excel (XML), and JSON formats.\n */\n\n/* eslint-disable @typescript-eslint/no-explicit-any */\n\nimport { BaseGridPlugin } from '../../core/plugin/base-plugin';\nimport type { ColumnConfig } from '../../core/types';\nimport { resolveColumns, resolveRows } from '../shared/data-collection';\nimport { buildCsv, downloadBlob, downloadCsv } from './csv';\nimport { buildExcelXml, downloadExcel } from './excel';\nimport type { ExportCompleteDetail, ExportConfig, ExportFormat, ExportParams } from './types';\n\n/** Selection plugin state interface for type safety */\ninterface SelectionPluginState {\n selected: Set<number>;\n}\n\n/**\n * Export Plugin for tbw-grid\n *\n * Lets users download grid data as CSV, Excel (XML), or JSON with a single click\n * or API call. Great for reporting, data backup, or letting users work with data\n * in Excel. Integrates with SelectionPlugin to export only selected rows.\n *\n * ## Installation\n *\n * ```ts\n * import { ExportPlugin } from '@toolbox-web/grid/plugins/export';\n * ```\n *\n * ## Configuration Options\n *\n * | Option | Type | Default | Description |\n * |--------|------|---------|-------------|\n * | `fileName` | `string` | `'export'` | Base filename (without extension) |\n * | `includeHeaders` | `boolean` | `true` | Include column headers in export |\n * | `onlyVisible` | `boolean` | `true` | Export only visible columns |\n * | `onlySelected` | `boolean` | `false` | Export only selected rows (requires SelectionPlugin) |\n *\n * ## Supported Formats\n *\n * | Format | Method | Description |\n * |--------|--------|-------------|\n * | CSV | `exportToCSV()` | Comma-separated values |\n * | Excel | `exportToExcel()` | Excel XML format (.xlsx) |\n * | JSON | `exportToJSON()` | JSON array of objects |\n *\n * ## Programmatic API\n *\n * | Method | Signature | Description |\n * |--------|-----------|-------------|\n * | `exportToCSV` | `(params?) => void` | Export as CSV file |\n * | `exportToExcel` | `(params?) => void` | Export as Excel file |\n * | `exportToJSON` | `(params?) => void` | Export as JSON file |\n * | `isExporting` | `() => boolean` | Check if export is in progress |\n *\n * @example Basic Export with Button\n * ```ts\n * import '@toolbox-web/grid';\n * import { ExportPlugin } from '@toolbox-web/grid/plugins/export';\n *\n * const grid = document.querySelector('tbw-grid');\n * grid.gridConfig = {\n * columns: [\n * { field: 'name', header: 'Name' },\n * { field: 'email', header: 'Email' },\n * ],\n * plugins: [new ExportPlugin({ fileName: 'employees', includeHeaders: true })],\n * };\n *\n * // Trigger export via button\n * document.getElementById('export-btn').addEventListener('click', () => {\n * grid.getPlugin(ExportPlugin).exportToCSV();\n * });\n * ```\n *\n * @example Export Selected Rows Only\n * ```ts\n * import { SelectionPlugin } from '@toolbox-web/grid/plugins/selection';\n *\n * grid.gridConfig = {\n * plugins: [\n * new SelectionPlugin({ mode: 'row' }),\n * new ExportPlugin({ onlySelected: true }),\n * ],\n * };\n * ```\n *\n * @see {@link ExportConfig} for all configuration options\n * @see {@link ExportParams} for method parameters\n * @see {@link SelectionPlugin} for exporting selected rows\n *\n * @internal Extends BaseGridPlugin\n */\nexport class ExportPlugin extends BaseGridPlugin<ExportConfig> {\n /** @internal */\n readonly name = 'export';\n\n /** @internal */\n protected override get defaultConfig(): Partial<ExportConfig> {\n return {\n fileName: 'export',\n includeHeaders: true,\n onlyVisible: true,\n onlySelected: false,\n };\n }\n\n // #region Internal State\n private isExportingFlag = false;\n private lastExportInfo: { format: ExportFormat; timestamp: Date } | null = null;\n // #endregion\n\n // #region Private Methods\n\n private performExport(format: ExportFormat, params?: Partial<ExportParams>): void {\n const config = this.config;\n\n // Build full params with defaults\n const fullParams: ExportParams = {\n format,\n fileName: params?.fileName ?? config.fileName ?? 'export',\n includeHeaders: params?.includeHeaders ?? config.includeHeaders,\n processCell: params?.processCell,\n processHeader: params?.processHeader,\n columns: params?.columns,\n rowIndices: params?.rowIndices,\n };\n\n // Get columns to export (shared utility handles hidden/utility filtering)\n const columns = resolveColumns(this.columns, params?.columns, config.onlyVisible) as ColumnConfig[];\n\n // Get rows to export\n let rows: Record<string, unknown>[];\n if (params?.rowIndices) {\n rows = resolveRows(this.rows as Record<string, unknown>[], params.rowIndices);\n } else if (config.onlySelected) {\n const selectionState = this.getSelectionState();\n if (selectionState?.selected?.size) {\n rows = resolveRows(this.rows as Record<string, unknown>[], [...selectionState.selected]);\n } else {\n rows = [...this.rows] as Record<string, unknown>[];\n }\n } else {\n rows = [...this.rows] as Record<string, unknown>[];\n }\n\n this.isExportingFlag = true;\n let fileName = fullParams.fileName!;\n\n try {\n switch (format) {\n case 'csv': {\n const content = buildCsv(rows, columns, fullParams, { bom: true });\n fileName = fileName.endsWith('.csv') ? fileName : `${fileName}.csv`;\n downloadCsv(content, fileName);\n break;\n }\n\n case 'excel': {\n const content = buildExcelXml(rows, columns, fullParams);\n fileName = fileName.endsWith('.xls') ? fileName : `${fileName}.xls`;\n downloadExcel(content, fileName);\n break;\n }\n\n case 'json': {\n const jsonData = rows.map((row) => {\n const obj: Record<string, any> = {};\n for (const col of columns) {\n let value = row[col.field];\n if (fullParams.processCell) {\n value = fullParams.processCell(value, col.field, row);\n }\n obj[col.field] = value;\n }\n return obj;\n });\n const content = JSON.stringify(jsonData, null, 2);\n fileName = fileName.endsWith('.json') ? fileName : `${fileName}.json`;\n const blob = new Blob([content], { type: 'application/json' });\n downloadBlob(blob, fileName);\n break;\n }\n }\n\n this.lastExportInfo = { format, timestamp: new Date() };\n\n this.emit<ExportCompleteDetail>('export-complete', {\n format,\n fileName,\n rowCount: rows.length,\n columnCount: columns.length,\n });\n } finally {\n this.isExportingFlag = false;\n }\n }\n\n private getSelectionState(): SelectionPluginState | null {\n try {\n return (this.grid?.getPluginState?.('selection') as SelectionPluginState | null) ?? null;\n } catch {\n return null;\n }\n }\n // #endregion\n\n // #region Public API\n\n /**\n * Export data to CSV format.\n * @param params - Optional export parameters\n */\n exportCsv(params?: Partial<ExportParams>): void {\n this.performExport('csv', params);\n }\n\n /**\n * Export data to Excel format (XML Spreadsheet).\n * @param params - Optional export parameters\n */\n exportExcel(params?: Partial<ExportParams>): void {\n this.performExport('excel', params);\n }\n\n /**\n * Export data to JSON format.\n * @param params - Optional export parameters\n */\n exportJson(params?: Partial<ExportParams>): void {\n this.performExport('json', params);\n }\n\n /**\n * Check if an export is currently in progress.\n * @returns Whether export is in progress\n */\n isExporting(): boolean {\n return this.isExportingFlag;\n }\n\n /**\n * Get information about the last export.\n * @returns Export info or null if no export has occurred\n */\n getLastExport(): { format: ExportFormat; timestamp: Date } | null {\n return this.lastExportInfo;\n }\n // #endregion\n}\n"],"names":["resolveColumns","columns","fields","onlyVisible","result","c","fieldSet","resolveRows","rows","indices","a","b","i","r","formatCsvValue","value","quote","str","buildCsv","params","options","delimiter","newline","lines","bom","headerRow","col","header","processed","row","cells","downloadBlob","blob","fileName","url","link","downloadCsv","content","escapeXml","buildExcelXml","xml","type","displayValue","downloadExcel","finalName","ExportPlugin","BaseGridPlugin","format","config","fullParams","selectionState","jsonData","obj"],"mappings":"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"}
@@ -1,2 +1,2 @@
1
- (function(R,H){typeof exports=="object"&&typeof module<"u"?H(exports,require("../../core/internal/virtualization"),require("../../core/plugin/base-plugin"),require("../../core/plugin/expander-column")):typeof define=="function"&&define.amd?define(["exports","../../core/internal/virtualization","../../core/plugin/base-plugin","../../core/plugin/expander-column"],H):(R=typeof globalThis<"u"?globalThis:R||self,H(R.TbwGridPlugin_filtering={},R.TbwGrid,R.TbwGrid,R.TbwGrid))})(this,(function(R,H,O,Y){"use strict";function K(M,e,t=!1){const r=M[e.field];if(e.operator==="blank")return r==null||r==="";if(e.operator==="notBlank")return r!=null&&r!=="";if(r==null)return!1;const a=String(r),s=t?a:a.toLowerCase(),c=t?String(e.value):String(e.value).toLowerCase();switch(e.operator){case"contains":return s.includes(c);case"notContains":return!s.includes(c);case"equals":return s===c;case"notEquals":return s!==c;case"startsWith":return s.startsWith(c);case"endsWith":return s.endsWith(c);case"lessThan":return Number(r)<Number(e.value);case"lessThanOrEqual":return Number(r)<=Number(e.value);case"greaterThan":return Number(r)>Number(e.value);case"greaterThanOrEqual":return Number(r)>=Number(e.value);case"between":return Number(r)>=Number(e.value)&&Number(r)<=Number(e.valueTo);case"in":return Array.isArray(e.value)&&e.value.includes(r);case"notIn":return Array.isArray(e.value)&&!e.value.includes(r);default:return!0}}function $(M,e,t=!1){return e.length?M.filter(r=>e.every(a=>K(r,a,t))):M}function j(M){return JSON.stringify(M.map(e=>({field:e.field,operator:e.operator,value:e.value,valueTo:e.valueTo})))}function _(M,e){const t=new Set;for(const r of M){const a=r[e];a!=null&&t.add(a)}return[...t].sort((r,a)=>typeof r=="number"&&typeof a=="number"?r-a:String(r).localeCompare(String(a)))}const W='@layer tbw-plugins{tbw-grid .tbw-quick-filter-input{flex:1;max-width:300px;height:var(--tbw-input-height, 1.75rem);padding:var(--tbw-input-padding, 0 .5rem);border:1px solid var(--tbw-color-border);border-radius:var(--tbw-border-radius);background:var(--tbw-color-bg);color:var(--tbw-color-fg);font-size:var(--tbw-font-size-sm, .8125rem)}tbw-grid .tbw-quick-filter-input:focus{outline:none;border-color:var(--tbw-color-accent)}tbw-grid .header-cell.filtered:before{content:"";position:absolute;top:var(--tbw-spacing-xs, .25rem);right:var(--tbw-spacing-xs, .25rem);width:var(--tbw-indicator-size, .375rem);height:var(--tbw-indicator-size, .375rem);background:var(--tbw-filter-accent, var(--tbw-color-accent, #3b82f6));border-radius:50%}tbw-grid .tbw-filter-btn{display:var(--tbw-filter-btn-display, inline-flex);visibility:var(--tbw-filter-btn-visibility, visible);align-items:center;justify-content:center;background:transparent;border:none;cursor:pointer;padding:2px;margin-left:var(--tbw-spacing-xs, .25rem);opacity:.4;transition:opacity .15s,visibility 0s,display 0s allow-discrete;color:inherit;vertical-align:middle;transition-behavior:allow-discrete}tbw-grid .tbw-filter-btn:hover,tbw-grid .tbw-filter-btn.active{opacity:1;visibility:visible;display:inline-flex}tbw-grid .tbw-filter-btn.active{color:var(--tbw-filter-accent, var(--tbw-color-accent, #3b82f6))}tbw-grid .header-row .cell:hover .tbw-filter-btn,tbw-grid .header-row .cell.filtered .tbw-filter-btn{display:inline-flex;visibility:visible}}',U="@layer tbw-plugins{.tbw-filter-panel{position:fixed;background:var(--tbw-filter-panel-bg, var(--tbw-color-panel-bg, light-dark(#eeeeee, #222222)));color:var(--tbw-filter-panel-fg, var(--tbw-color-fg, light-dark(#222222, #eeeeee)));border:1px solid var(--tbw-filter-panel-border, var(--tbw-color-border, light-dark(#d0d0d4, #454545)));border-radius:var(--tbw-filter-panel-radius, var(--tbw-border-radius, .25rem));box-shadow:0 4px 16px var(--tbw-filter-panel-shadow, var(--tbw-color-shadow, light-dark(rgba(0, 0, 0, .1), rgba(0, 0, 0, .3))));padding:var(--tbw-panel-padding, var(--tbw-spacing-lg, .75rem));z-index:10000;min-width:200px;max-width:280px;max-height:350px;display:flex;flex-direction:column;font-family:var(--tbw-font-family, system-ui, sans-serif);font-size:var(--tbw-font-size, .8125rem);transform-origin:top center}.tbw-filter-panel.tbw-filter-panel-above{transform-origin:bottom center}.tbw-filter-panel.tbw-filter-panel-animated{animation:tbw-filter-panel-enter var(--tbw-animation-duration, .15s) var(--tbw-animation-easing, ease-out)}.tbw-filter-panel.tbw-filter-panel-above.tbw-filter-panel-animated{animation:tbw-filter-panel-enter-above var(--tbw-animation-duration, .15s) var(--tbw-animation-easing, ease-out)}@keyframes tbw-filter-panel-enter{0%{opacity:0;transform:scaleY(.3) translateY(-10px)}to{opacity:1;transform:scaleY(1) translateY(0)}}@keyframes tbw-filter-panel-enter-above{0%{opacity:0;transform:scaleY(.3) translateY(10px)}to{opacity:1;transform:scaleY(1) translateY(0)}}@supports (anchor-name: --test){.tbw-filter-panel{position-anchor:--tbw-filter-anchor;top:anchor(bottom);left:anchor(left);margin-top:4px;position-try-fallbacks:flip-inline,flip-block,flip-block flip-inline}}.tbw-filter-search{margin-bottom:var(--tbw-panel-gap, var(--tbw-spacing-md, .5rem));min-height:var(--tbw-filter-item-height, 28px)}.tbw-filter-search-input{height:var(--tbw-filter-item-height, 28px);width:100%;padding:var(--tbw-filter-search-padding, var(--tbw-spacing-sm, .375rem) var(--tbw-spacing-md, .5rem));background:var(--tbw-filter-input-bg, var(--tbw-color-bg, transparent));color:inherit;border:1px solid var(--tbw-filter-input-border, var(--tbw-color-border, light-dark(#d0d0d4, #454545)));border-radius:var(--tbw-filter-input-radius, var(--tbw-border-radius, .25rem));font-size:inherit;box-sizing:border-box}.tbw-filter-search-input:focus{outline:none;border-color:var(--tbw-filter-accent, var(--tbw-color-accent, #3b82f6));box-shadow:0 0 0 2px rgba(from var(--tbw-filter-accent, var(--tbw-color-accent, #3b82f6)) r g b / 15%)}.tbw-filter-actions{display:flex;padding:var(--tbw-button-padding-sm, .25rem .125rem);margin-bottom:var(--tbw-panel-gap, var(--tbw-spacing-md, .5rem));border-bottom:1px solid var(--tbw-filter-divider, var(--tbw-color-border, light-dark(#d0d0d4, #454545)));min-height:var(--tbw-filter-item-height, 28px)}.tbw-filter-actions .tbw-filter-value-item{flex:1}.tbw-filter-values{flex:1;overflow-y:auto;margin-bottom:var(--tbw-panel-gap, var(--tbw-spacing-md, .5rem));max-height:180px;position:relative}.tbw-filter-values-spacer{width:1px}.tbw-filter-values-content{position:absolute;top:0;left:0;right:0}.tbw-filter-value-item{display:flex;align-items:center;gap:var(--tbw-panel-gap, var(--tbw-spacing-md, .5rem));padding:var(--tbw-button-padding-sm, .25rem .125rem);cursor:pointer;border-radius:3px;height:var(--tbw-filter-item-height, 28px)}.tbw-filter-value-item:hover{background:var(--tbw-filter-hover, var(--tbw-color-row-hover, light-dark(#f0f6ff, #1c1c1c)))}.tbw-filter-checkbox{margin:0;cursor:pointer;accent-color:var(--tbw-filter-accent, var(--tbw-color-accent, #3b82f6))}.tbw-filter-no-match{color:var(--tbw-filter-muted, var(--tbw-color-fg-muted, light-dark(#555555, #aaaaaa)));padding:var(--tbw-panel-gap, var(--tbw-spacing-md, .5rem)) 0;text-align:center;font-style:italic}.tbw-filter-buttons{display:flex;gap:var(--tbw-panel-gap, var(--tbw-spacing-md, .5rem));padding-top:var(--tbw-panel-gap, var(--tbw-spacing-md, .5rem));border-top:1px solid var(--tbw-filter-divider, var(--tbw-color-border, light-dark(#d0d0d4, #454545)))}.tbw-filter-apply-btn{flex:1;padding:var(--tbw-filter-btn-padding, var(--tbw-button-padding, .375rem .75rem));background:var(--tbw-filter-accent, var(--tbw-color-accent, #3b82f6));color:var(--tbw-filter-accent-fg, var(--tbw-color-accent-fg, light-dark(#ffffff, #000000)));border:none;border-radius:var(--tbw-border-radius, .25rem);cursor:pointer;font-size:var(--tbw-font-size-sm, .8125rem);font-weight:var(--tbw-filter-btn-font-weight, 500);min-height:var(--tbw-filter-btn-min-height, auto)}.tbw-filter-apply-btn:hover{filter:brightness(.9)}.tbw-filter-clear-btn{flex:1;padding:var(--tbw-filter-btn-padding, var(--tbw-button-padding, .375rem .75rem));background:transparent;color:var(--tbw-filter-muted, var(--tbw-color-fg-muted, light-dark(#555555, #aaaaaa)));border:1px solid var(--tbw-filter-input-border, var(--tbw-color-border, light-dark(#d0d0d4, #454545)));border-radius:var(--tbw-border-radius, .25rem);cursor:pointer;font-size:var(--tbw-font-size-sm, .8125rem);font-weight:var(--tbw-filter-btn-font-weight, 500);min-height:var(--tbw-filter-btn-min-height, auto)}.tbw-filter-clear-btn:hover{background:var(--tbw-filter-hover, var(--tbw-color-row-hover, light-dark(#f0f6ff, #1c1c1c)))}.tbw-filter-range-inputs,.tbw-filter-date-range{display:flex;align-items:flex-end;gap:var(--tbw-spacing-sm, .375rem);margin-bottom:var(--tbw-panel-gap, var(--tbw-spacing-md, .5rem))}.tbw-filter-range-group,.tbw-filter-date-group{display:flex;flex-direction:column;gap:var(--tbw-spacing-xs, .25rem);flex:1}.tbw-filter-range-label{font-size:var(--tbw-font-size-xs, .75rem);color:var(--tbw-filter-muted, var(--tbw-color-fg-muted, light-dark(#555555, #aaaaaa)))}.tbw-filter-range-input,.tbw-filter-date-input{width:100%;height:var(--tbw-filter-item-height, 28px);padding:var(--tbw-spacing-xs, .25rem) var(--tbw-spacing-sm, .375rem);background:var(--tbw-filter-input-bg, var(--tbw-color-bg, transparent));color:inherit;border:1px solid var(--tbw-filter-input-border, var(--tbw-color-border, light-dark(#d0d0d4, #454545)));border-radius:var(--tbw-filter-input-radius, var(--tbw-border-radius, .25rem));font-size:inherit;box-sizing:border-box}.tbw-filter-range-input:focus,.tbw-filter-date-input:focus{outline:none;border-color:var(--tbw-filter-accent, var(--tbw-color-accent, #3b82f6));box-shadow:0 0 0 2px rgba(from var(--tbw-filter-accent, var(--tbw-color-accent, #3b82f6)) r g b / 15%)}.tbw-filter-range-separator{color:var(--tbw-filter-muted, var(--tbw-color-fg-muted, light-dark(#555555, #aaaaaa)));padding-bottom:var(--tbw-spacing-xs, .25rem)}.tbw-filter-range-slider{position:relative;height:24px;margin:var(--tbw-spacing-md, .5rem) 0 var(--tbw-panel-gap, var(--tbw-spacing-md, .5rem))}.tbw-filter-range-track{position:absolute;top:50%;left:0;right:0;height:4px;background:var(--tbw-filter-input-border, var(--tbw-color-border, light-dark(#d0d0d4, #454545)));border-radius:2px;transform:translateY(-50%)}.tbw-filter-range-fill{position:absolute;top:50%;height:4px;background:var(--tbw-filter-accent, var(--tbw-color-accent, #3b82f6));border-radius:2px;transform:translateY(-50%)}.tbw-filter-range-thumb{position:absolute;top:0;width:100%;height:100%;background:none;pointer-events:none;-webkit-appearance:none;appearance:none}.tbw-filter-range-thumb::-webkit-slider-thumb{-webkit-appearance:none;appearance:none;width:16px;height:16px;background:var(--tbw-filter-accent, var(--tbw-color-accent, #3b82f6));border:2px solid var(--tbw-filter-panel-bg, var(--tbw-color-panel-bg, light-dark(#eeeeee, #222222)));border-radius:50%;cursor:pointer;pointer-events:all;box-shadow:0 1px 3px #0003}.tbw-filter-range-thumb::-moz-range-thumb{width:16px;height:16px;background:var(--tbw-filter-accent, var(--tbw-color-accent, #3b82f6));border:2px solid var(--tbw-filter-panel-bg, var(--tbw-color-panel-bg, light-dark(#eeeeee, #222222)));border-radius:50%;cursor:pointer;pointer-events:all;box-shadow:0 1px 3px #0003}.tbw-filter-range-thumb::-webkit-slider-thumb:hover{transform:scale(1.1)}.tbw-filter-range-thumb::-moz-range-thumb:hover{transform:scale(1.1)}}";class I extends O.BaseGridPlugin{static manifest={events:[{type:"filter-applied",description:"Emitted when filter criteria change. Subscribers can react to row visibility changes."}]};name="filtering";styles=W;get defaultConfig(){return{debounceMs:300,caseSensitive:!1,trimInput:!0,useWorker:!0}}isFilteringEnabled(){return this.grid.effectiveConfig?.filterable!==!1}isColumnFilterable(e){return this.isFilteringEnabled()?e.filterable!==!1:!1}filters=new Map;cachedResult=null;cacheKey=null;openPanelField=null;panelElement=null;panelAnchorElement=null;searchText=new Map;excludedValues=new Map;panelAbortController=null;globalStylesInjected=!1;static DEFAULT_LIST_ITEM_HEIGHT=28;static LIST_OVERSCAN=3;static LIST_BYPASS_THRESHOLD=50;getListItemHeight(){if(this.panelElement){const e=getComputedStyle(this.panelElement).getPropertyValue("--tbw-filter-item-height");if(e&&e.trim()){const t=parseFloat(e);if(!isNaN(t)&&t>0)return t}}return I.DEFAULT_LIST_ITEM_HEIGHT}syncExcludedValues(e,t){t?t.type==="set"&&t.operator==="notIn"&&Array.isArray(t.value)?this.excludedValues.set(e,new Set(t.value)):t.type==="set"&&this.excludedValues.delete(e):this.excludedValues.delete(e)}attach(e){super.attach(e),this.injectGlobalStyles()}detach(){this.filters.clear(),this.cachedResult=null,this.cacheKey=null,this.openPanelField=null,this.panelElement&&(this.panelElement.remove(),this.panelElement=null),this.searchText.clear(),this.excludedValues.clear(),this.panelAbortController?.abort(),this.panelAbortController=null}processRows(e){const t=[...this.filters.values()];if(!t.length)return[...e];if(this.config.filterHandler)return this.cachedResult?this.cachedResult:[...e];const r=j(t);if(this.cacheKey===r&&this.cachedResult)return this.cachedResult;const a=$([...e],t,this.config.caseSensitive);return this.cachedResult=a,this.cacheKey=r,a}afterRender(){const e=this.gridElement;if(!e)return;e.querySelectorAll('[part~="header-cell"]').forEach(r=>{const a=r.getAttribute("data-col");if(a===null)return;const s=this.visibleColumns[parseInt(a,10)];if(!s||!this.isColumnFilterable(s)||Y.isUtilityColumn(s))return;const c=s.field;if(!c)return;const u=this.filters.has(c);let i=r.querySelector(".tbw-filter-btn");if(i){const w=i.classList.contains("active");if(i.classList.toggle("active",u),r.classList.toggle("filtered",u),w!==u){const d=u?"filterActive":"filter";this.setIcon(i,this.resolveIcon(d))}return}i=document.createElement("button"),i.className="tbw-filter-btn",i.setAttribute("aria-label",`Filter ${s.header??c}`);const m=u?"filterActive":"filter";this.setIcon(i,this.resolveIcon(m)),u&&(i.classList.add("active"),r.classList.add("filtered")),i.addEventListener("click",w=>{w.stopPropagation(),this.toggleFilterPanel(c,s,i)});const k=r.querySelector(".resize-handle");k?r.insertBefore(i,k):r.appendChild(i)})}setFilter(e,t){if(t===null)this.filters.delete(e),this.syncExcludedValues(e,null);else{const r={...t,field:e};this.filters.set(e,r),this.syncExcludedValues(e,r)}this.cachedResult=null,this.cacheKey=null,this.emit("filter-change",{filters:[...this.filters.values()],filteredRowCount:0}),this.emitPluginEvent("filter-applied",{filters:[...this.filters.values()]}),this.requestRender()}getFilter(e){return this.filters.get(e)}getFilters(){return[...this.filters.values()]}getFilterModel(){return this.getFilters()}setFilterModel(e){this.filters.clear(),this.excludedValues.clear();for(const t of e)this.filters.set(t.field,t),this.syncExcludedValues(t.field,t);this.cachedResult=null,this.cacheKey=null,this.emit("filter-change",{filters:[...this.filters.values()],filteredRowCount:0}),this.emitPluginEvent("filter-applied",{filters:[...this.filters.values()]}),this.requestRender()}clearAllFilters(){this.filters.clear(),this.excludedValues.clear(),this.searchText.clear(),this.applyFiltersInternal()}clearFieldFilter(e){this.filters.delete(e),this.excludedValues.delete(e),this.searchText.delete(e),this.applyFiltersInternal()}isFieldFiltered(e){return this.filters.has(e)}getFilteredRowCount(){return this.cachedResult?.length??this.rows.length}getActiveFilters(){return this.getFilters()}getUniqueValues(e){return _(this.sourceRows,e)}copyGridThemeContext(e){const t=this.gridElement;if(!t)return;for(const a of t.classList)a.startsWith("tbw-")||a==="selecting"||e.classList.add(a);const r=t.dataset.theme;r&&(e.dataset.theme=r)}injectGlobalStyles(){if(this.globalStylesInjected)return;if(document.getElementById("tbw-filter-panel-styles")){this.globalStylesInjected=!0;return}const e=document.createElement("style");e.id="tbw-filter-panel-styles",e.textContent=U,document.head.appendChild(e),this.globalStylesInjected=!0}toggleFilterPanel(e,t,r){if(this.openPanelField===e){this.closeFilterPanel();return}this.closeFilterPanel();const a=document.createElement("div");if(a.className="tbw-filter-panel",this.copyGridThemeContext(a),this.isAnimationEnabled&&a.classList.add("tbw-filter-panel-animated"),this.panelElement=a,this.openPanelField=e,this.config.valuesHandler){a.innerHTML='<div class="tbw-filter-loading">Loading...</div>',document.body.appendChild(a),this.positionPanel(a,r),this.setupPanelCloseHandler(a,r),this.config.valuesHandler(e,t).then(c=>{this.openPanelField!==e||!this.panelElement||(a.innerHTML="",this.renderPanelContent(e,t,a,c))});return}const s=_(this.sourceRows,e);document.body.appendChild(a),this.positionPanel(a,r),this.renderPanelContent(e,t,a,s),this.setupPanelCloseHandler(a,r)}renderPanelContent(e,t,r,a){let s=this.excludedValues.get(e);s||(s=new Set,this.excludedValues.set(e,s));const c=this.searchText.get(e)??"",u={field:e,column:t,uniqueValues:a,excludedValues:s,searchText:c,applySetFilter:m=>{this.applySetFilter(e,m),this.closeFilterPanel()},applyTextFilter:(m,k,w)=>{this.applyTextFilter(e,m,k,w),this.closeFilterPanel()},clearFilter:()=>{this.clearFieldFilter(e),this.closeFilterPanel()},closePanel:()=>this.closeFilterPanel()};let i=!1;if(this.config.filterPanelRenderer&&(this.config.filterPanelRenderer(r,u),i=r.children.length>0),!i&&t.type){const m=this.grid.effectiveConfig.typeDefaults?.[t.type];m?.filterPanelRenderer&&(m.filterPanelRenderer(r,u),i=r.children.length>0)}if(!i){const m=t.type;m==="number"?this.renderNumberFilterPanel(r,u,a):m==="date"?this.renderDateFilterPanel(r,u,a):this.renderDefaultFilterPanel(r,u,a,s)}}setupPanelCloseHandler(e,t){this.panelAbortController=new AbortController,setTimeout(()=>{document.addEventListener("click",r=>{!e.contains(r.target)&&r.target!==t&&this.closeFilterPanel()},{signal:this.panelAbortController?.signal})},0)}closeFilterPanel(){const e=this.panelElement;e&&(e.remove(),this.panelElement=null),this.panelAnchorElement&&(this.panelAnchorElement.style.anchorName="",this.panelAnchorElement=null),this.openPanelField=null,this.panelAbortController?.abort(),this.panelAbortController=null}static supportsAnchorPositioning=null;static checkAnchorPositioningSupport(){return I.supportsAnchorPositioning===null&&(I.supportsAnchorPositioning=CSS.supports("anchor-name","--test")),I.supportsAnchorPositioning}positionPanel(e,t){const a=t.closest(".cell")??t;if(a.style.anchorName="--tbw-filter-anchor",this.panelAnchorElement=a,I.checkAnchorPositioningSupport()){requestAnimationFrame(()=>{const c=e.getBoundingClientRect(),u=a.getBoundingClientRect();c.top<u.top&&e.classList.add("tbw-filter-panel-above")});return}const s=a.getBoundingClientRect();e.style.position="fixed",e.style.top=`${s.bottom+4}px`,e.style.left=`${s.left}px`,requestAnimationFrame(()=>{const c=e.getBoundingClientRect();c.right>window.innerWidth-8&&(e.style.left=`${s.right-c.width}px`),c.bottom>window.innerHeight-8&&(e.style.top=`${s.top-c.height-4}px`,e.classList.add("tbw-filter-panel-above"))})}renderDefaultFilterPanel(e,t,r,a){const{field:s}=t,c=this.getListItemHeight(),u=document.createElement("div");u.className="tbw-filter-search";const i=document.createElement("input");i.type="text",i.placeholder="Search...",i.className="tbw-filter-search-input",i.value=this.searchText.get(s)??"",u.appendChild(i),e.appendChild(u);const m=document.createElement("div");m.className="tbw-filter-actions";const k=document.createElement("label");k.className="tbw-filter-value-item",k.style.padding="0",k.style.margin="0";const w=document.createElement("input");w.type="checkbox",w.className="tbw-filter-checkbox";const d=document.createElement("span");d.textContent="Select All",k.appendChild(w),k.appendChild(d),m.appendChild(k);const v=()=>{const o=[...S.values()],b=o.every(n=>n),y=o.every(n=>!n);w.checked=b,w.indeterminate=!b&&!y};w.addEventListener("change",()=>{const o=w.checked;for(const b of S.keys())S.set(b,o);v(),L()}),e.appendChild(m);const E=document.createElement("div");E.className="tbw-filter-values";const g=document.createElement("div");g.className="tbw-filter-values-spacer",E.appendChild(g);const x=document.createElement("div");x.className="tbw-filter-values-content",E.appendChild(x);const S=new Map;r.forEach(o=>{const b=o==null?"__null__":String(o);S.set(b,!a.has(o))}),v();let C=[];const T=(o,b)=>{const y=o==null?"(Blank)":String(o),n=o==null?"__null__":String(o),l=document.createElement("label");l.className="tbw-filter-value-item",l.style.position="absolute",l.style.top=`calc(var(--tbw-filter-item-height, 28px) * ${b})`,l.style.left="0",l.style.right="0",l.style.boxSizing="border-box";const F=document.createElement("input");F.type="checkbox",F.className="tbw-filter-checkbox",F.checked=S.get(n)??!0,F.dataset.value=n,F.addEventListener("change",()=>{S.set(n,F.checked),v()});const V=document.createElement("span");return V.textContent=y,l.appendChild(F),l.appendChild(V),l},L=()=>{const o=C.length,b=E.clientHeight,y=E.scrollTop;if(g.style.height=`${o*c}px`,H.shouldBypassVirtualization(o,I.LIST_BYPASS_THRESHOLD/3)){x.innerHTML="",x.style.transform="translateY(0px)",C.forEach((l,F)=>{x.appendChild(T(l,F))});return}const n=H.computeVirtualWindow({totalRows:o,viewportHeight:b,scrollTop:y,rowHeight:c,overscan:I.LIST_OVERSCAN});x.style.transform=`translateY(${n.offsetY}px)`,x.innerHTML="";for(let l=n.start;l<n.end;l++)x.appendChild(T(C[l],l-n.start))},f=o=>{const b=this.config.caseSensitive??!1,y=b?o:o.toLowerCase();if(C=r.filter(n=>{const l=n==null?"(Blank)":String(n),F=b?l:l.toLowerCase();return!o||F.includes(y)}),C.length===0){g.style.height="0px",x.innerHTML="";const n=document.createElement("div");n.className="tbw-filter-no-match",n.textContent="No matching values",x.appendChild(n);return}L()};E.addEventListener("scroll",()=>{C.length>0&&L()},{passive:!0}),f(i.value),e.appendChild(E);let A;i.addEventListener("input",()=>{clearTimeout(A),A=setTimeout(()=>{this.searchText.set(s,i.value),f(i.value)},this.config.debounceMs??150)});const N=document.createElement("div");N.className="tbw-filter-buttons";const P=document.createElement("button");P.className="tbw-filter-apply-btn",P.textContent="Apply",P.addEventListener("click",()=>{const o=[];for(const[b,y]of S)if(!y)if(b==="__null__")o.push(null);else{const n=r.find(l=>String(l)===b);o.push(n!==void 0?n:b)}t.applySetFilter(o)}),N.appendChild(P);const p=document.createElement("button");p.className="tbw-filter-clear-btn",p.textContent="Clear Filter",p.addEventListener("click",()=>{t.clearFilter()}),N.appendChild(p),e.appendChild(N)}renderNumberFilterPanel(e,t,r){const{field:a,column:s}=t,c=s.filterParams,u=s.editorParams,i=(h,z)=>{if(typeof h=="number")return h;if(typeof h=="string"){const q=parseFloat(h);return isNaN(q)?z:q}return z},m=r.filter(h=>typeof h=="number"&&!isNaN(h)),k=m.length>0?Math.min(...m):0,w=m.length>0?Math.max(...m):100,d=i(c?.min??u?.min,k),v=i(c?.max??u?.max,w),E=c?.step??u?.step??1,g=this.filters.get(a);let x=d,S=v;g?.operator==="between"?(x=i(g.value,d),S=i(g.valueTo,v)):g?.operator==="greaterThanOrEqual"?x=i(g.value,d):g?.operator==="lessThanOrEqual"&&(S=i(g.value,v));const C=document.createElement("div");C.className="tbw-filter-range-inputs";const T=document.createElement("div");T.className="tbw-filter-range-group";const L=document.createElement("label");L.textContent="Min",L.className="tbw-filter-range-label";const f=document.createElement("input");f.type="number",f.className="tbw-filter-range-input",f.min=String(d),f.max=String(v),f.step=String(E),f.value=String(x),T.appendChild(L),T.appendChild(f),C.appendChild(T);const A=document.createElement("span");A.className="tbw-filter-range-separator",A.textContent="–",C.appendChild(A);const N=document.createElement("div");N.className="tbw-filter-range-group";const P=document.createElement("label");P.textContent="Max",P.className="tbw-filter-range-label";const p=document.createElement("input");p.type="number",p.className="tbw-filter-range-input",p.min=String(d),p.max=String(v),p.step=String(E),p.value=String(S),N.appendChild(P),N.appendChild(p),C.appendChild(N),e.appendChild(C);const o=document.createElement("div");o.className="tbw-filter-range-slider";const b=document.createElement("div");b.className="tbw-filter-range-track";const y=document.createElement("div");y.className="tbw-filter-range-fill";const n=document.createElement("input");n.type="range",n.className="tbw-filter-range-thumb tbw-filter-range-thumb-min",n.min=String(d),n.max=String(v),n.step=String(E),n.value=String(x);const l=document.createElement("input");l.type="range",l.className="tbw-filter-range-thumb tbw-filter-range-thumb-max",l.min=String(d),l.max=String(v),l.step=String(E),l.value=String(S),o.appendChild(b),o.appendChild(y),o.appendChild(n),o.appendChild(l),e.appendChild(o);const F=()=>{const h=parseFloat(n.value),z=parseFloat(l.value),q=v-d,G=(h-d)/q*100,J=(z-d)/q*100;y.style.left=`${G}%`,y.style.width=`${J-G}%`};n.addEventListener("input",()=>{const h=Math.min(parseFloat(n.value),parseFloat(l.value));n.value=String(h),f.value=String(h),F()}),l.addEventListener("input",()=>{const h=Math.max(parseFloat(l.value),parseFloat(n.value));l.value=String(h),p.value=String(h),F()}),f.addEventListener("input",()=>{let h=parseFloat(f.value)||d;h=Math.max(d,Math.min(h,parseFloat(p.value))),n.value=String(h),F()}),p.addEventListener("input",()=>{let h=parseFloat(p.value)||v;h=Math.min(v,Math.max(h,parseFloat(f.value))),l.value=String(h),F()}),F();const V=document.createElement("div");V.className="tbw-filter-buttons";const B=document.createElement("button");B.className="tbw-filter-apply-btn",B.textContent="Apply",B.addEventListener("click",()=>{const h=parseFloat(f.value),z=parseFloat(p.value);t.applyTextFilter("between",h,z)}),V.appendChild(B);const D=document.createElement("button");D.className="tbw-filter-clear-btn",D.textContent="Clear Filter",D.addEventListener("click",()=>{t.clearFilter()}),V.appendChild(D),e.appendChild(V)}renderDateFilterPanel(e,t,r){const{field:a,column:s}=t,c=s.filterParams,u=s.editorParams,i=r.filter(n=>n instanceof Date||typeof n=="string"&&!isNaN(Date.parse(n))).map(n=>n instanceof Date?n:new Date(n)).filter(n=>!isNaN(n.getTime())),m=i.length>0?new Date(Math.min(...i.map(n=>n.getTime()))):null,k=i.length>0?new Date(Math.max(...i.map(n=>n.getTime()))):null,w=n=>n?n.toISOString().split("T")[0]:"",d=n=>n?typeof n=="string"?n:typeof n=="number"?w(new Date(n)):"":"",v=d(c?.min)||d(u?.min)||w(m),E=d(c?.max)||d(u?.max)||w(k),g=this.filters.get(a);let x="",S="";g?.operator==="between"?(x=d(g.value)||"",S=d(g.valueTo)||""):g?.operator==="greaterThanOrEqual"?x=d(g.value)||"":g?.operator==="lessThanOrEqual"&&(S=d(g.value)||"");const C=document.createElement("div");C.className="tbw-filter-date-range";const T=document.createElement("div");T.className="tbw-filter-date-group";const L=document.createElement("label");L.textContent="From",L.className="tbw-filter-range-label";const f=document.createElement("input");f.type="date",f.className="tbw-filter-date-input",v&&(f.min=v),E&&(f.max=E),f.value=x,T.appendChild(L),T.appendChild(f),C.appendChild(T);const A=document.createElement("span");A.className="tbw-filter-range-separator",A.textContent="–",C.appendChild(A);const N=document.createElement("div");N.className="tbw-filter-date-group";const P=document.createElement("label");P.textContent="To",P.className="tbw-filter-range-label";const p=document.createElement("input");p.type="date",p.className="tbw-filter-date-input",v&&(p.min=v),E&&(p.max=E),p.value=S,N.appendChild(P),N.appendChild(p),C.appendChild(N),e.appendChild(C);const o=document.createElement("div");o.className="tbw-filter-buttons";const b=document.createElement("button");b.className="tbw-filter-apply-btn",b.textContent="Apply",b.addEventListener("click",()=>{const n=f.value,l=p.value;n&&l?t.applyTextFilter("between",n,l):n?t.applyTextFilter("greaterThanOrEqual",n):l?t.applyTextFilter("lessThanOrEqual",l):t.clearFilter()}),o.appendChild(b);const y=document.createElement("button");y.className="tbw-filter-clear-btn",y.textContent="Clear Filter",y.addEventListener("click",()=>{t.clearFilter()}),o.appendChild(y),e.appendChild(o)}applySetFilter(e,t){this.excludedValues.set(e,new Set(t)),t.length===0?this.filters.delete(e):this.filters.set(e,{field:e,type:"set",operator:"notIn",value:t}),this.applyFiltersInternal()}applyTextFilter(e,t,r,a){this.filters.set(e,{field:e,type:"text",operator:t,value:r,valueTo:a}),this.applyFiltersInternal()}applyFiltersInternal(){this.cachedResult=null,this.cacheKey=null;const e=[...this.filters.values()];if(this.config.filterHandler){const t=this.grid;t.setAttribute("aria-busy","true");const r=this.config.filterHandler(e,this.sourceRows),a=s=>{t.removeAttribute("aria-busy"),this.cachedResult=s,this.grid.rows=s,this.emit("filter-change",{filters:e,filteredRowCount:s.length}),this.emitPluginEvent("filter-applied",{filters:e}),this.requestRender()};r&&typeof r.then=="function"?r.then(a):a(r);return}this.emit("filter-change",{filters:e,filteredRowCount:0}),this.emitPluginEvent("filter-applied",{filters:e}),this.requestRender()}getColumnState(e){const t=this.filters.get(e);if(t)return{filter:{type:t.type,operator:t.operator,value:t.value,valueTo:t.valueTo}}}applyColumnState(e,t){if(!t.filter){this.filters.delete(e);return}const r={field:e,type:t.filter.type,operator:t.filter.operator,value:t.filter.value,valueTo:t.filter.valueTo};this.filters.set(e,r),this.cachedResult=null,this.cacheKey=null}}R.FilteringPlugin=I,Object.defineProperty(R,Symbol.toStringTag,{value:"Module"})}));
1
+ (function(H,q){typeof exports=="object"&&typeof module<"u"?q(exports,require("../../core/internal/virtualization"),require("../../core/plugin/base-plugin"),require("../../core/plugin/expander-column")):typeof define=="function"&&define.amd?define(["exports","../../core/internal/virtualization","../../core/plugin/base-plugin","../../core/plugin/expander-column"],q):(H=typeof globalThis<"u"?globalThis:H||self,q(H.TbwGridPlugin_filtering={},H.TbwGrid,H.TbwGrid,H.TbwGrid))})(this,(function(H,q,Y,K){"use strict";function R(L){if(L instanceof Date)return L.getTime();const e=Number(L);return isNaN(e)?new Date(L).getTime():e}function $(L,e,t=!1){const r=L[e.field];if(e.operator==="blank")return r==null||r==="";if(e.operator==="notBlank")return r!=null&&r!=="";if(r==null)return!1;const n=String(r),a=t?n:n.toLowerCase(),d=t?String(e.value):String(e.value).toLowerCase();switch(e.operator){case"contains":return a.includes(d);case"notContains":return!a.includes(d);case"equals":return a===d;case"notEquals":return a!==d;case"startsWith":return a.startsWith(d);case"endsWith":return a.endsWith(d);case"lessThan":return R(r)<R(e.value);case"lessThanOrEqual":return R(r)<=R(e.value);case"greaterThan":return R(r)>R(e.value);case"greaterThanOrEqual":return R(r)>=R(e.value);case"between":return R(r)>=R(e.value)&&R(r)<=R(e.valueTo);case"in":return Array.isArray(e.value)&&e.value.includes(r);case"notIn":return Array.isArray(e.value)&&!e.value.includes(r);default:return!0}}function j(L,e,t=!1){return e.length?L.filter(r=>e.every(n=>$(r,n,t))):L}function W(L){return JSON.stringify(L.map(e=>({field:e.field,operator:e.operator,value:e.value,valueTo:e.valueTo})))}function G(L,e){const t=new Set;for(const r of L){const n=r[e];n!=null&&t.add(n)}return[...t].sort((r,n)=>typeof r=="number"&&typeof n=="number"?r-n:String(r).localeCompare(String(n)))}const U='@layer tbw-plugins{tbw-grid .tbw-quick-filter-input{flex:1;max-width:300px;height:var(--tbw-input-height, 1.75rem);padding:var(--tbw-input-padding, 0 .5rem);border:1px solid var(--tbw-color-border);border-radius:var(--tbw-border-radius);background:var(--tbw-color-bg);color:var(--tbw-color-fg);font-size:var(--tbw-font-size-sm, .8125rem)}tbw-grid .tbw-quick-filter-input:focus{outline:none;border-color:var(--tbw-color-accent)}tbw-grid .header-cell.filtered:before{content:"";position:absolute;top:var(--tbw-spacing-xs, .25rem);right:var(--tbw-spacing-xs, .25rem);width:var(--tbw-indicator-size, .375rem);height:var(--tbw-indicator-size, .375rem);background:var(--tbw-filter-accent, var(--tbw-color-accent, #3b82f6));border-radius:50%}tbw-grid .tbw-filter-btn{display:var(--tbw-filter-btn-display, inline-flex);visibility:var(--tbw-filter-btn-visibility, visible);align-items:center;justify-content:center;background:transparent;border:none;cursor:pointer;padding:2px;margin-left:var(--tbw-spacing-xs, .25rem);opacity:.4;transition:opacity .15s,visibility 0s,display 0s allow-discrete;color:inherit;vertical-align:middle;transition-behavior:allow-discrete}tbw-grid .tbw-filter-btn:hover,tbw-grid .tbw-filter-btn.active{opacity:1;visibility:visible;display:inline-flex}tbw-grid .tbw-filter-btn.active{color:var(--tbw-filter-accent, var(--tbw-color-accent, #3b82f6))}tbw-grid .header-row .cell:hover .tbw-filter-btn,tbw-grid .header-row .cell.filtered .tbw-filter-btn{display:inline-flex;visibility:visible}}',J="@layer tbw-plugins{.tbw-filter-panel{position:fixed;background:var(--tbw-filter-panel-bg, var(--tbw-color-panel-bg, light-dark(#eeeeee, #222222)));color:var(--tbw-filter-panel-fg, var(--tbw-color-fg, light-dark(#222222, #eeeeee)));border:1px solid var(--tbw-filter-panel-border, var(--tbw-color-border, light-dark(#d0d0d4, #454545)));border-radius:var(--tbw-filter-panel-radius, var(--tbw-border-radius, .25rem));box-shadow:0 4px 16px var(--tbw-filter-panel-shadow, var(--tbw-color-shadow, light-dark(rgba(0, 0, 0, .1), rgba(0, 0, 0, .3))));padding:var(--tbw-panel-padding, var(--tbw-spacing-lg, .75rem));z-index:10000;min-width:200px;max-width:280px;max-height:350px;display:flex;flex-direction:column;font-family:var(--tbw-font-family, system-ui, sans-serif);font-size:var(--tbw-font-size, .8125rem);transform-origin:top center}.tbw-filter-panel.tbw-filter-panel-above{transform-origin:bottom center}.tbw-filter-panel.tbw-filter-panel-animated{animation:tbw-filter-panel-enter var(--tbw-animation-duration, .15s) var(--tbw-animation-easing, ease-out)}.tbw-filter-panel.tbw-filter-panel-above.tbw-filter-panel-animated{animation:tbw-filter-panel-enter-above var(--tbw-animation-duration, .15s) var(--tbw-animation-easing, ease-out)}@keyframes tbw-filter-panel-enter{0%{opacity:0;transform:scaleY(.3) translateY(-10px)}to{opacity:1;transform:scaleY(1) translateY(0)}}@keyframes tbw-filter-panel-enter-above{0%{opacity:0;transform:scaleY(.3) translateY(10px)}to{opacity:1;transform:scaleY(1) translateY(0)}}@supports (anchor-name: --test){.tbw-filter-panel{position-anchor:--tbw-filter-anchor;top:anchor(bottom);left:anchor(left);margin-top:4px;position-try-fallbacks:flip-inline,flip-block,flip-block flip-inline}}.tbw-filter-search{margin-bottom:var(--tbw-panel-gap, var(--tbw-spacing-md, .5rem));min-height:var(--tbw-filter-item-height, 28px)}.tbw-filter-search-input{height:var(--tbw-filter-item-height, 28px);width:100%;padding:var(--tbw-filter-search-padding, var(--tbw-spacing-sm, .375rem) var(--tbw-spacing-md, .5rem));background:var(--tbw-filter-input-bg, var(--tbw-color-bg, transparent));color:inherit;border:1px solid var(--tbw-filter-input-border, var(--tbw-color-border, light-dark(#d0d0d4, #454545)));border-radius:var(--tbw-filter-input-radius, var(--tbw-border-radius, .25rem));font-size:inherit;box-sizing:border-box}.tbw-filter-search-input:focus{outline:none;border-color:var(--tbw-filter-accent, var(--tbw-color-accent, #3b82f6));box-shadow:0 0 0 2px rgba(from var(--tbw-filter-accent, var(--tbw-color-accent, #3b82f6)) r g b / 15%)}.tbw-filter-actions{display:flex;padding:var(--tbw-button-padding-sm, .25rem .125rem);margin-bottom:var(--tbw-panel-gap, var(--tbw-spacing-md, .5rem));border-bottom:1px solid var(--tbw-filter-divider, var(--tbw-color-border, light-dark(#d0d0d4, #454545)));min-height:var(--tbw-filter-item-height, 28px)}.tbw-filter-actions .tbw-filter-value-item{flex:1}.tbw-filter-values{flex:1;overflow-y:auto;margin-bottom:var(--tbw-panel-gap, var(--tbw-spacing-md, .5rem));max-height:180px;position:relative}.tbw-filter-values-spacer{width:1px}.tbw-filter-values-content{position:absolute;top:0;left:0;right:0}.tbw-filter-value-item{display:flex;align-items:center;gap:var(--tbw-panel-gap, var(--tbw-spacing-md, .5rem));padding:var(--tbw-button-padding-sm, .25rem .125rem);cursor:pointer;border-radius:3px;height:var(--tbw-filter-item-height, 28px)}.tbw-filter-value-item:hover{background:var(--tbw-filter-hover, var(--tbw-color-row-hover, light-dark(#f0f6ff, #1c1c1c)))}.tbw-filter-checkbox{margin:0;cursor:pointer;accent-color:var(--tbw-filter-accent, var(--tbw-color-accent, #3b82f6))}.tbw-filter-no-match{color:var(--tbw-filter-muted, var(--tbw-color-fg-muted, light-dark(#555555, #aaaaaa)));padding:var(--tbw-panel-gap, var(--tbw-spacing-md, .5rem)) 0;text-align:center;font-style:italic}.tbw-filter-buttons{display:flex;gap:var(--tbw-panel-gap, var(--tbw-spacing-md, .5rem));padding-top:var(--tbw-panel-gap, var(--tbw-spacing-md, .5rem));border-top:1px solid var(--tbw-filter-divider, var(--tbw-color-border, light-dark(#d0d0d4, #454545)))}.tbw-filter-apply-btn{flex:1;padding:var(--tbw-filter-btn-padding, var(--tbw-button-padding, .375rem .75rem));background:var(--tbw-filter-accent, var(--tbw-color-accent, #3b82f6));color:var(--tbw-filter-accent-fg, var(--tbw-color-accent-fg, light-dark(#ffffff, #000000)));border:none;border-radius:var(--tbw-border-radius, .25rem);cursor:pointer;font-size:var(--tbw-font-size-sm, .8125rem);font-weight:var(--tbw-filter-btn-font-weight, 500);min-height:var(--tbw-filter-btn-min-height, auto)}.tbw-filter-apply-btn:hover{filter:brightness(.9)}.tbw-filter-clear-btn{flex:1;padding:var(--tbw-filter-btn-padding, var(--tbw-button-padding, .375rem .75rem));background:transparent;color:var(--tbw-filter-muted, var(--tbw-color-fg-muted, light-dark(#555555, #aaaaaa)));border:1px solid var(--tbw-filter-input-border, var(--tbw-color-border, light-dark(#d0d0d4, #454545)));border-radius:var(--tbw-border-radius, .25rem);cursor:pointer;font-size:var(--tbw-font-size-sm, .8125rem);font-weight:var(--tbw-filter-btn-font-weight, 500);min-height:var(--tbw-filter-btn-min-height, auto)}.tbw-filter-clear-btn:hover{background:var(--tbw-filter-hover, var(--tbw-color-row-hover, light-dark(#f0f6ff, #1c1c1c)))}.tbw-filter-range-inputs,.tbw-filter-date-range{display:flex;align-items:flex-end;gap:var(--tbw-spacing-sm, .375rem);margin-bottom:var(--tbw-panel-gap, var(--tbw-spacing-md, .5rem))}.tbw-filter-range-group,.tbw-filter-date-group{display:flex;flex-direction:column;gap:var(--tbw-spacing-xs, .25rem);flex:1}.tbw-filter-range-label{font-size:var(--tbw-font-size-xs, .75rem);color:var(--tbw-filter-muted, var(--tbw-color-fg-muted, light-dark(#555555, #aaaaaa)))}.tbw-filter-range-input,.tbw-filter-date-input{width:100%;height:var(--tbw-filter-item-height, 28px);padding:var(--tbw-spacing-xs, .25rem) var(--tbw-spacing-sm, .375rem);background:var(--tbw-filter-input-bg, var(--tbw-color-bg, transparent));color:inherit;border:1px solid var(--tbw-filter-input-border, var(--tbw-color-border, light-dark(#d0d0d4, #454545)));border-radius:var(--tbw-filter-input-radius, var(--tbw-border-radius, .25rem));font-size:inherit;box-sizing:border-box}.tbw-filter-range-input:focus,.tbw-filter-date-input:focus{outline:none;border-color:var(--tbw-filter-accent, var(--tbw-color-accent, #3b82f6));box-shadow:0 0 0 2px rgba(from var(--tbw-filter-accent, var(--tbw-color-accent, #3b82f6)) r g b / 15%)}.tbw-filter-range-separator{color:var(--tbw-filter-muted, var(--tbw-color-fg-muted, light-dark(#555555, #aaaaaa)));padding-bottom:var(--tbw-spacing-xs, .25rem)}.tbw-filter-blank-option{display:flex;align-items:center;gap:var(--tbw-spacing-sm, .375rem);padding:var(--tbw-spacing-xs, .25rem) 0;margin-bottom:var(--tbw-spacing-xs, .25rem);font-size:var(--tbw-font-size-sm, .8125rem);cursor:pointer;-webkit-user-select:none;user-select:none}.tbw-filter-blank-checkbox{accent-color:var(--tbw-filter-accent, var(--tbw-color-accent, #3b82f6));margin:0;cursor:pointer}.tbw-filter-date-range.tbw-filter-disabled{opacity:.4;pointer-events:none}.tbw-filter-range-slider{position:relative;height:24px;margin:var(--tbw-spacing-md, .5rem) 0 var(--tbw-panel-gap, var(--tbw-spacing-md, .5rem))}.tbw-filter-range-track{position:absolute;top:50%;left:0;right:0;height:4px;background:var(--tbw-filter-input-border, var(--tbw-color-border, light-dark(#d0d0d4, #454545)));border-radius:2px;transform:translateY(-50%)}.tbw-filter-range-fill{position:absolute;top:50%;height:4px;background:var(--tbw-filter-accent, var(--tbw-color-accent, #3b82f6));border-radius:2px;transform:translateY(-50%)}.tbw-filter-range-thumb{position:absolute;top:0;width:100%;height:100%;background:none;pointer-events:none;-webkit-appearance:none;appearance:none}.tbw-filter-range-thumb::-webkit-slider-thumb{-webkit-appearance:none;appearance:none;width:16px;height:16px;background:var(--tbw-filter-accent, var(--tbw-color-accent, #3b82f6));border:2px solid var(--tbw-filter-panel-bg, var(--tbw-color-panel-bg, light-dark(#eeeeee, #222222)));border-radius:50%;cursor:pointer;pointer-events:all;box-shadow:0 1px 3px #0003}.tbw-filter-range-thumb::-moz-range-thumb{width:16px;height:16px;background:var(--tbw-filter-accent, var(--tbw-color-accent, #3b82f6));border:2px solid var(--tbw-filter-panel-bg, var(--tbw-color-panel-bg, light-dark(#eeeeee, #222222)));border-radius:50%;cursor:pointer;pointer-events:all;box-shadow:0 1px 3px #0003}.tbw-filter-range-thumb::-webkit-slider-thumb:hover{transform:scale(1.1)}.tbw-filter-range-thumb::-moz-range-thumb:hover{transform:scale(1.1)}}";class z extends Y.BaseGridPlugin{static manifest={events:[{type:"filter-applied",description:"Emitted when filter criteria change. Subscribers can react to row visibility changes."}]};name="filtering";styles=U;get defaultConfig(){return{debounceMs:300,caseSensitive:!1,trimInput:!0,useWorker:!0}}isFilteringEnabled(){return this.grid.effectiveConfig?.filterable!==!1}isColumnFilterable(e){return this.isFilteringEnabled()?e.filterable!==!1:!1}filters=new Map;cachedResult=null;cacheKey=null;cachedInputSpot=null;openPanelField=null;panelElement=null;panelAnchorElement=null;searchText=new Map;excludedValues=new Map;panelAbortController=null;globalStylesInjected=!1;static DEFAULT_LIST_ITEM_HEIGHT=28;static LIST_OVERSCAN=3;static LIST_BYPASS_THRESHOLD=50;getListItemHeight(){if(this.panelElement){const e=getComputedStyle(this.panelElement).getPropertyValue("--tbw-filter-item-height");if(e&&e.trim()){const t=parseFloat(e);if(!isNaN(t)&&t>0)return t}}return z.DEFAULT_LIST_ITEM_HEIGHT}syncExcludedValues(e,t){t?t.type==="set"&&t.operator==="notIn"&&Array.isArray(t.value)?this.excludedValues.set(e,new Set(t.value)):t.type==="set"&&this.excludedValues.delete(e):this.excludedValues.delete(e)}attach(e){super.attach(e),this.injectGlobalStyles()}detach(){this.filters.clear(),this.cachedResult=null,this.cacheKey=null,this.cachedInputSpot=null,this.openPanelField=null,this.panelElement&&(this.panelElement.remove(),this.panelElement=null),this.searchText.clear(),this.excludedValues.clear(),this.panelAbortController?.abort(),this.panelAbortController=null}processRows(e){const t=[...this.filters.values()];if(!t.length)return[...e];if(this.config.filterHandler)return this.cachedResult?this.cachedResult:[...e];const r=W(t),n={len:e.length,first:e[0],mid:e[Math.floor(e.length/2)],last:e[e.length-1]},a=this.cachedInputSpot!=null&&n.len===this.cachedInputSpot.len&&n.first===this.cachedInputSpot.first&&n.mid===this.cachedInputSpot.mid&&n.last===this.cachedInputSpot.last;if(this.cacheKey===r&&this.cachedResult&&a)return this.cachedResult;const d=j([...e],t,this.config.caseSensitive);return this.cachedResult=d,this.cacheKey=r,this.cachedInputSpot=n,d}afterRender(){const e=this.gridElement;if(!e)return;e.querySelectorAll('[part~="header-cell"]').forEach(r=>{const n=r.getAttribute("data-col");if(n===null)return;const a=this.visibleColumns[parseInt(n,10)];if(!a||!this.isColumnFilterable(a)||K.isUtilityColumn(a))return;const d=a.field;if(!d)return;const b=this.filters.has(d);let l=r.querySelector(".tbw-filter-btn");if(l){const x=l.classList.contains("active");if(l.classList.toggle("active",b),r.classList.toggle("filtered",b),x!==b){const u=b?"filterActive":"filter";this.setIcon(l,this.resolveIcon(u))}return}l=document.createElement("button"),l.className="tbw-filter-btn",l.setAttribute("aria-label",`Filter ${a.header??d}`);const f=b?"filterActive":"filter";this.setIcon(l,this.resolveIcon(f)),b&&(l.classList.add("active"),r.classList.add("filtered")),l.addEventListener("click",x=>{x.stopPropagation(),this.toggleFilterPanel(d,a,l)});const F=r.querySelector(".resize-handle");F?r.insertBefore(l,F):r.appendChild(l)})}setFilter(e,t){if(t===null)this.filters.delete(e),this.syncExcludedValues(e,null);else{const r={...t,field:e};this.filters.set(e,r),this.syncExcludedValues(e,r)}this.cachedResult=null,this.cacheKey=null,this.cachedInputSpot=null,this.emit("filter-change",{filters:[...this.filters.values()],filteredRowCount:0}),this.emitPluginEvent("filter-applied",{filters:[...this.filters.values()]}),this.requestRender()}getFilter(e){return this.filters.get(e)}getFilters(){return[...this.filters.values()]}getFilterModel(){return this.getFilters()}setFilterModel(e){this.filters.clear(),this.excludedValues.clear();for(const t of e)this.filters.set(t.field,t),this.syncExcludedValues(t.field,t);this.cachedResult=null,this.cacheKey=null,this.cachedInputSpot=null,this.emit("filter-change",{filters:[...this.filters.values()],filteredRowCount:0}),this.emitPluginEvent("filter-applied",{filters:[...this.filters.values()]}),this.requestRender()}clearAllFilters(){this.filters.clear(),this.excludedValues.clear(),this.searchText.clear(),this.applyFiltersInternal()}clearFieldFilter(e){this.filters.delete(e),this.excludedValues.delete(e),this.searchText.delete(e),this.applyFiltersInternal()}isFieldFiltered(e){return this.filters.has(e)}getFilteredRowCount(){return this.cachedResult?.length??this.rows.length}getActiveFilters(){return this.getFilters()}getUniqueValues(e){return G(this.sourceRows,e)}copyGridThemeContext(e){const t=this.gridElement;if(!t)return;for(const n of t.classList)n.startsWith("tbw-")||n==="selecting"||e.classList.add(n);const r=t.dataset.theme;r&&(e.dataset.theme=r)}injectGlobalStyles(){if(this.globalStylesInjected)return;if(document.getElementById("tbw-filter-panel-styles")){this.globalStylesInjected=!0;return}const e=document.createElement("style");e.id="tbw-filter-panel-styles",e.textContent=J,document.head.appendChild(e),this.globalStylesInjected=!0}toggleFilterPanel(e,t,r){if(this.openPanelField===e){this.closeFilterPanel();return}this.closeFilterPanel();const n=document.createElement("div");if(n.className="tbw-filter-panel",this.copyGridThemeContext(n),this.isAnimationEnabled&&n.classList.add("tbw-filter-panel-animated"),this.panelElement=n,this.openPanelField=e,this.config.valuesHandler){n.innerHTML='<div class="tbw-filter-loading">Loading...</div>',document.body.appendChild(n),this.positionPanel(n,r),this.setupPanelCloseHandler(n,r),this.config.valuesHandler(e,t).then(d=>{this.openPanelField!==e||!this.panelElement||(n.innerHTML="",this.renderPanelContent(e,t,n,d))});return}const a=G(this.sourceRows,e);document.body.appendChild(n),this.positionPanel(n,r),this.renderPanelContent(e,t,n,a),this.setupPanelCloseHandler(n,r)}renderPanelContent(e,t,r,n){let a=this.excludedValues.get(e);a||(a=new Set,this.excludedValues.set(e,a));const d=this.searchText.get(e)??"",b={field:e,column:t,uniqueValues:n,excludedValues:a,searchText:d,applySetFilter:f=>{this.applySetFilter(e,f),this.closeFilterPanel()},applyTextFilter:(f,F,x)=>{this.applyTextFilter(e,f,F,x),this.closeFilterPanel()},clearFilter:()=>{this.clearFieldFilter(e),this.closeFilterPanel()},closePanel:()=>this.closeFilterPanel()};let l=!1;if(this.config.filterPanelRenderer&&(this.config.filterPanelRenderer(r,b),l=r.children.length>0),!l&&t.type){const f=this.grid.effectiveConfig.typeDefaults?.[t.type];f?.filterPanelRenderer&&(f.filterPanelRenderer(r,b),l=r.children.length>0)}if(!l){const f=t.type;f==="number"?this.renderNumberFilterPanel(r,b,n):f==="date"?this.renderDateFilterPanel(r,b,n):this.renderDefaultFilterPanel(r,b,n,a)}}setupPanelCloseHandler(e,t){this.panelAbortController=new AbortController,setTimeout(()=>{document.addEventListener("click",r=>{!e.contains(r.target)&&r.target!==t&&this.closeFilterPanel()},{signal:this.panelAbortController?.signal})},0)}closeFilterPanel(){const e=this.panelElement;e&&(e.remove(),this.panelElement=null),this.panelAnchorElement&&(this.panelAnchorElement.style.anchorName="",this.panelAnchorElement=null),this.openPanelField=null,this.panelAbortController?.abort(),this.panelAbortController=null}static supportsAnchorPositioning=null;static checkAnchorPositioningSupport(){return z.supportsAnchorPositioning===null&&(z.supportsAnchorPositioning=CSS.supports("anchor-name","--test")),z.supportsAnchorPositioning}positionPanel(e,t){const n=t.closest(".cell")??t;if(n.style.anchorName="--tbw-filter-anchor",this.panelAnchorElement=n,z.checkAnchorPositioningSupport()){requestAnimationFrame(()=>{const d=e.getBoundingClientRect(),b=n.getBoundingClientRect();d.top<b.top&&e.classList.add("tbw-filter-panel-above")});return}const a=n.getBoundingClientRect();e.style.position="fixed",e.style.top=`${a.bottom+4}px`,e.style.left=`${a.left}px`,requestAnimationFrame(()=>{const d=e.getBoundingClientRect();d.right>window.innerWidth-8&&(e.style.left=`${a.right-d.width}px`),d.bottom>window.innerHeight-8&&(e.style.top=`${a.top-d.height-4}px`,e.classList.add("tbw-filter-panel-above"))})}renderDefaultFilterPanel(e,t,r,n){const{field:a}=t,d=this.getListItemHeight(),b=document.createElement("div");b.className="tbw-filter-search";const l=document.createElement("input");l.type="text",l.placeholder="Search...",l.className="tbw-filter-search-input",l.value=this.searchText.get(a)??"",b.appendChild(l),e.appendChild(b);const f=document.createElement("div");f.className="tbw-filter-actions";const F=document.createElement("label");F.className="tbw-filter-value-item",F.style.padding="0",F.style.margin="0";const x=document.createElement("input");x.type="checkbox",x.className="tbw-filter-checkbox";const u=document.createElement("span");u.textContent="Select All",F.appendChild(x),F.appendChild(u),f.appendChild(F);const y=()=>{const i=[...k.values()],h=i.every(s=>s),m=i.every(s=>!s);x.checked=h,x.indeterminate=!h&&!m};x.addEventListener("change",()=>{const i=x.checked;for(const h of k.keys())k.set(h,i);y(),M()}),e.appendChild(f);const S=document.createElement("div");S.className="tbw-filter-values";const w=document.createElement("div");w.className="tbw-filter-values-spacer",S.appendChild(w);const C=document.createElement("div");C.className="tbw-filter-values-content",S.appendChild(C);const k=new Map;r.forEach(i=>{const h=i==null?"__null__":String(i);k.set(h,!n.has(i))}),y();let T=[];const P=(i,h)=>{const m=i==null?"(Blank)":String(i),s=i==null?"__null__":String(i),o=document.createElement("label");o.className="tbw-filter-value-item",o.style.position="absolute",o.style.top=`calc(var(--tbw-filter-item-height, 28px) * ${h})`,o.style.left="0",o.style.right="0",o.style.boxSizing="border-box";const g=document.createElement("input");g.type="checkbox",g.className="tbw-filter-checkbox",g.checked=k.get(s)??!0,g.dataset.value=s,g.addEventListener("change",()=>{k.set(s,g.checked),y()});const V=document.createElement("span");return V.textContent=m,o.appendChild(g),o.appendChild(V),o},M=()=>{const i=T.length,h=S.clientHeight,m=S.scrollTop;if(w.style.height=`${i*d}px`,q.shouldBypassVirtualization(i,z.LIST_BYPASS_THRESHOLD/3)){C.innerHTML="",C.style.transform="translateY(0px)",T.forEach((o,g)=>{C.appendChild(P(o,g))});return}const s=q.computeVirtualWindow({totalRows:i,viewportHeight:h,scrollTop:m,rowHeight:d,overscan:z.LIST_OVERSCAN});C.style.transform=`translateY(${s.offsetY}px)`,C.innerHTML="";for(let o=s.start;o<s.end;o++)C.appendChild(P(T[o],o-s.start))},E=i=>{const h=this.config.caseSensitive??!1,m=h?i:i.toLowerCase();if(T=r.filter(s=>{const o=s==null?"(Blank)":String(s),g=h?o:o.toLowerCase();return!i||g.includes(m)}),T.length===0){w.style.height="0px",C.innerHTML="";const s=document.createElement("div");s.className="tbw-filter-no-match",s.textContent="No matching values",C.appendChild(s);return}M()};S.addEventListener("scroll",()=>{T.length>0&&M()},{passive:!0}),E(l.value),e.appendChild(S);let N;l.addEventListener("input",()=>{clearTimeout(N),N=setTimeout(()=>{this.searchText.set(a,l.value),E(l.value)},this.config.debounceMs??150)});const I=document.createElement("div");I.className="tbw-filter-buttons";const A=document.createElement("button");A.className="tbw-filter-apply-btn",A.textContent="Apply",A.addEventListener("click",()=>{const i=[];for(const[h,m]of k)if(!m)if(h==="__null__")i.push(null);else{const s=r.find(o=>String(o)===h);i.push(s!==void 0?s:h)}t.applySetFilter(i)}),I.appendChild(A);const v=document.createElement("button");v.className="tbw-filter-clear-btn",v.textContent="Clear Filter",v.addEventListener("click",()=>{t.clearFilter()}),I.appendChild(v),e.appendChild(I)}renderNumberFilterPanel(e,t,r){const{field:n,column:a}=t,d=a.filterParams,b=a.editorParams,l=(p,B)=>{if(typeof p=="number")return p;if(typeof p=="string"){const _=parseFloat(p);return isNaN(_)?B:_}return B},f=r.filter(p=>typeof p=="number"&&!isNaN(p)),F=f.length>0?Math.min(...f):0,x=f.length>0?Math.max(...f):100,u=l(d?.min??b?.min,F),y=l(d?.max??b?.max,x),S=d?.step??b?.step??1,w=this.filters.get(n);let C=u,k=y;w?.operator==="between"?(C=l(w.value,u),k=l(w.valueTo,y)):w?.operator==="greaterThanOrEqual"?C=l(w.value,u):w?.operator==="lessThanOrEqual"&&(k=l(w.value,y));const T=document.createElement("div");T.className="tbw-filter-range-inputs";const P=document.createElement("div");P.className="tbw-filter-range-group";const M=document.createElement("label");M.textContent="Min",M.className="tbw-filter-range-label";const E=document.createElement("input");E.type="number",E.className="tbw-filter-range-input",E.min=String(u),E.max=String(y),E.step=String(S),E.value=String(C),P.appendChild(M),P.appendChild(E),T.appendChild(P);const N=document.createElement("span");N.className="tbw-filter-range-separator",N.textContent="–",T.appendChild(N);const I=document.createElement("div");I.className="tbw-filter-range-group";const A=document.createElement("label");A.textContent="Max",A.className="tbw-filter-range-label";const v=document.createElement("input");v.type="number",v.className="tbw-filter-range-input",v.min=String(u),v.max=String(y),v.step=String(S),v.value=String(k),I.appendChild(A),I.appendChild(v),T.appendChild(I),e.appendChild(T);const i=document.createElement("div");i.className="tbw-filter-range-slider";const h=document.createElement("div");h.className="tbw-filter-range-track";const m=document.createElement("div");m.className="tbw-filter-range-fill";const s=document.createElement("input");s.type="range",s.className="tbw-filter-range-thumb tbw-filter-range-thumb-min",s.min=String(u),s.max=String(y),s.step=String(S),s.value=String(C);const o=document.createElement("input");o.type="range",o.className="tbw-filter-range-thumb tbw-filter-range-thumb-max",o.min=String(u),o.max=String(y),o.step=String(S),o.value=String(k),i.appendChild(h),i.appendChild(m),i.appendChild(s),i.appendChild(o),e.appendChild(i);const g=()=>{const p=parseFloat(s.value),B=parseFloat(o.value),_=y-u,O=(p-u)/_*100,Q=(B-u)/_*100;m.style.left=`${O}%`,m.style.width=`${Q-O}%`};s.addEventListener("input",()=>{const p=Math.min(parseFloat(s.value),parseFloat(o.value));s.value=String(p),E.value=String(p),g()}),o.addEventListener("input",()=>{const p=Math.max(parseFloat(o.value),parseFloat(s.value));o.value=String(p),v.value=String(p),g()}),E.addEventListener("input",()=>{let p=parseFloat(E.value)||u;p=Math.max(u,Math.min(p,parseFloat(v.value))),s.value=String(p),g()}),v.addEventListener("input",()=>{let p=parseFloat(v.value)||y;p=Math.min(y,Math.max(p,parseFloat(E.value))),o.value=String(p),g()}),g();const V=document.createElement("div");V.className="tbw-filter-buttons";const D=document.createElement("button");D.className="tbw-filter-apply-btn",D.textContent="Apply",D.addEventListener("click",()=>{const p=parseFloat(E.value),B=parseFloat(v.value);t.applyTextFilter("between",p,B)}),V.appendChild(D);const c=document.createElement("button");c.className="tbw-filter-clear-btn",c.textContent="Clear Filter",c.addEventListener("click",()=>{t.clearFilter()}),V.appendChild(c),e.appendChild(V)}renderDateFilterPanel(e,t,r){const{field:n,column:a}=t,d=a.filterParams,b=a.editorParams,l=r.filter(c=>c instanceof Date||typeof c=="string"&&!isNaN(Date.parse(c))).map(c=>c instanceof Date?c:new Date(c)).filter(c=>!isNaN(c.getTime())),f=l.length>0?new Date(Math.min(...l.map(c=>c.getTime()))):null,F=l.length>0?new Date(Math.max(...l.map(c=>c.getTime()))):null,x=c=>c?c.toISOString().split("T")[0]:"",u=c=>c?typeof c=="string"?c:typeof c=="number"?x(new Date(c)):"":"",y=u(d?.min)||u(b?.min)||x(f),S=u(d?.max)||u(b?.max)||x(F),w=this.filters.get(n);let C="",k="";const T=w?.operator==="blank";w?.operator==="between"?(C=u(w.value)||"",k=u(w.valueTo)||""):w?.operator==="greaterThanOrEqual"?C=u(w.value)||"":w?.operator==="lessThanOrEqual"&&(k=u(w.value)||"");const P=document.createElement("div");P.className="tbw-filter-date-range";const M=document.createElement("div");M.className="tbw-filter-date-group";const E=document.createElement("label");E.textContent="From",E.className="tbw-filter-range-label";const N=document.createElement("input");N.type="date",N.className="tbw-filter-date-input",y&&(N.min=y),S&&(N.max=S),N.value=C,M.appendChild(E),M.appendChild(N),P.appendChild(M);const I=document.createElement("span");I.className="tbw-filter-range-separator",I.textContent="–",P.appendChild(I);const A=document.createElement("div");A.className="tbw-filter-date-group";const v=document.createElement("label");v.textContent="To",v.className="tbw-filter-range-label";const i=document.createElement("input");i.type="date",i.className="tbw-filter-date-input",y&&(i.min=y),S&&(i.max=S),i.value=k,A.appendChild(v),A.appendChild(i),P.appendChild(A),e.appendChild(P);const h=document.createElement("label");h.className="tbw-filter-blank-option";const m=document.createElement("input");m.type="checkbox",m.className="tbw-filter-blank-checkbox",m.checked=T;const s=document.createTextNode("Show only blank");h.appendChild(m),h.appendChild(s);const o=c=>{N.disabled=c,i.disabled=c,P.classList.toggle("tbw-filter-disabled",c)};o(T),m.addEventListener("change",()=>{o(m.checked)}),e.appendChild(h);const g=document.createElement("div");g.className="tbw-filter-buttons";const V=document.createElement("button");V.className="tbw-filter-apply-btn",V.textContent="Apply",V.addEventListener("click",()=>{if(m.checked){t.applyTextFilter("blank","");return}const c=N.value,p=i.value;c&&p?t.applyTextFilter("between",c,p):c?t.applyTextFilter("greaterThanOrEqual",c):p?t.applyTextFilter("lessThanOrEqual",p):t.clearFilter()}),g.appendChild(V);const D=document.createElement("button");D.className="tbw-filter-clear-btn",D.textContent="Clear Filter",D.addEventListener("click",()=>{t.clearFilter()}),g.appendChild(D),e.appendChild(g)}applySetFilter(e,t){this.excludedValues.set(e,new Set(t)),t.length===0?this.filters.delete(e):this.filters.set(e,{field:e,type:"set",operator:"notIn",value:t}),this.applyFiltersInternal()}applyTextFilter(e,t,r,n){this.filters.set(e,{field:e,type:"text",operator:t,value:r,valueTo:n}),this.applyFiltersInternal()}applyFiltersInternal(){this.cachedResult=null,this.cacheKey=null,this.cachedInputSpot=null;const e=[...this.filters.values()];if(this.config.filterHandler){const t=this.grid;t.setAttribute("aria-busy","true");const r=this.config.filterHandler(e,this.sourceRows),n=a=>{t.removeAttribute("aria-busy"),this.cachedResult=a,this.grid.rows=a,this.emit("filter-change",{filters:e,filteredRowCount:a.length}),this.emitPluginEvent("filter-applied",{filters:e}),this.requestRender()};r&&typeof r.then=="function"?r.then(n):n(r);return}this.emit("filter-change",{filters:e,filteredRowCount:0}),this.emitPluginEvent("filter-applied",{filters:e}),this.requestRender()}getColumnState(e){const t=this.filters.get(e);if(t)return{filter:{type:t.type,operator:t.operator,value:t.value,valueTo:t.valueTo}}}applyColumnState(e,t){if(!t.filter){this.filters.delete(e);return}const r={field:e,type:t.filter.type,operator:t.filter.operator,value:t.filter.value,valueTo:t.filter.valueTo};this.filters.set(e,r),this.cachedResult=null,this.cacheKey=null,this.cachedInputSpot=null}}H.FilteringPlugin=z,Object.defineProperty(H,Symbol.toStringTag,{value:"Module"})}));
2
2
  //# sourceMappingURL=filtering.umd.js.map