diff --git a/ts_web/elements/dees-table/data.ts b/ts_web/elements/dees-table/data.ts index fa86932..8d3eb28 100644 --- a/ts_web/elements/dees-table/data.ts +++ b/ts_web/elements/dees-table/data.ts @@ -41,19 +41,39 @@ export function getViewData( effectiveColumns: Column[], sortKey?: string, sortDir?: 'asc' | 'desc' | null, - filterText?: string + filterText?: string, + columnFilters?: Record ): T[] { let arr = data.slice(); const ft = (filterText || '').trim().toLowerCase(); - if (ft) { + const cf = columnFilters || {}; + const cfKeys = Object.keys(cf).filter((k) => (cf[k] ?? '').trim().length > 0); + if (ft || cfKeys.length > 0) { arr = arr.filter((row) => { - for (const col of effectiveColumns) { - if (col.hidden) continue; + // column filters (AND across columns) + for (const k of cfKeys) { + const col = effectiveColumns.find((c) => String(c.key) === k); + if (!col || col.hidden || col.filterable === false) continue; const val = getCellValue(row, col); const s = String(val ?? '').toLowerCase(); - if (s.includes(ft)) return true; + const needle = String(cf[k]).toLowerCase(); + if (!s.includes(needle)) return false; } - return false; + // global filter (OR across visible columns) + if (ft) { + let any = false; + for (const col of effectiveColumns) { + if (col.hidden) continue; + const val = getCellValue(row, col); + const s = String(val ?? '').toLowerCase(); + if (s.includes(ft)) { + any = true; + break; + } + } + if (!any) return false; + } + return true; }); } if (!sortKey || !sortDir) return arr; @@ -75,4 +95,3 @@ export function getViewData( }); return arr; } - diff --git a/ts_web/elements/dees-table/dees-table.demo.ts b/ts_web/elements/dees-table/dees-table.demo.ts index 07f053c..7df868c 100644 --- a/ts_web/elements/dees-table/dees-table.demo.ts +++ b/ts_web/elements/dees-table/dees-table.demo.ts @@ -505,6 +505,38 @@ export const demoFunc = () => html` dataName="items" > + +
+

Column Filters + Sticky Header (New)

+

Per-column quick filters and sticky header with internal scroll. Try filtering the Name column. Uses --table-max-height var.

+ + +
`; diff --git a/ts_web/elements/dees-table/dees-table.ts b/ts_web/elements/dees-table/dees-table.ts index 0fa95d8..249e0ff 100644 --- a/ts_web/elements/dees-table/dees-table.ts +++ b/ts_web/elements/dees-table/dees-table.ts @@ -3,7 +3,6 @@ import { demoFunc } from './dees-table.demo.js'; import { customElement, html, DeesElement, property, type TemplateResult, directives } from '@design.estate/dees-element'; import { DeesContextmenu } from '../dees-contextmenu.js'; -import * as plugins from '../00plugins.js'; import * as domtools from '@design.estate/dees-domtools'; import { type TIconKey } from '../dees-icon.js'; import { tableStyles } from './styles.js'; @@ -167,6 +166,13 @@ export class DeesTable extends DeesElement { // simple client-side filtering (Phase 1) @property({ type: String }) public filterText: string = ''; + // per-column quick filters + @property({ attribute: false }) + public columnFilters: Record = {}; + @property({ type: Boolean, attribute: 'show-column-filters' }) + public showColumnFilters: boolean = false; + @property({ type: Boolean, reflect: true, attribute: 'sticky-header' }) + public stickyHeader: boolean = false; // selection (Phase 1) @property({ type: String }) @@ -254,6 +260,7 @@ export class DeesTable extends DeesElement { ${this.data.length > 0 ? html` +
@@ -261,12 +268,15 @@ export class DeesTable extends DeesElement { ? html` ` @@ -293,9 +303,31 @@ export class DeesTable extends DeesElement { } })()} + ${this.showColumnFilters + ? html` + ${this.selectionMode !== 'none' + ? html`` + : html``} + ${effectiveColumns + .filter((c) => !c.hidden) + .map((col) => { + const key = String(col.key); + if (col.filterable === false) return html``; + return html``; + })} + ${(() => { + if (this.dataActions && this.dataActions.length > 0) { + return html` `; + } + })()} + ` + : html``} - ${getViewDataFn(this.data, effectiveColumns, this.sortKey, this.sortDir, this.filterText).map((itemArg, rowIndex) => { + ${getViewDataFn(this.data, effectiveColumns, this.sortKey, this.sortDir, this.filterText, this.columnFilters).map((itemArg, rowIndex) => { const getTr = (elementArg: HTMLElement): HTMLElement => { if (elementArg.tagName === 'TR') { return elementArg; @@ -370,14 +402,13 @@ export class DeesTable extends DeesElement { > ${this.selectionMode !== 'none' ? html`` : html``} ${effectiveColumns @@ -435,6 +466,7 @@ export class DeesTable extends DeesElement { })}
${this.selectionMode === 'multi' - ? html` { - e.stopPropagation(); - this.toggleSelectAll(); - }} />` + ? html` + ) => { + e.stopPropagation(); + this.setSelectAll(e.detail === true); + }} + > + ` : html``}
+ this.setColumnFilter(key, (e.target as HTMLInputElement).value)} /> +
- { + ) => { e.stopPropagation(); - this.toggleRowSelected(itemArg); + this.setRowSelected(itemArg, e.detail === true); }} - /> + >
+
` : html`
No data set!
`}