From c7503de11ee19634d9857735f4f80c8651b01676 Mon Sep 17 00:00:00 2001 From: Juergen Kunz Date: Tue, 7 Apr 2026 21:31:43 +0000 Subject: [PATCH] update --- .../00group-dataview/dees-table/dees-table.ts | 41 ++++++++++++++++--- .../00group-dataview/dees-table/types.ts | 1 + 2 files changed, 36 insertions(+), 6 deletions(-) diff --git a/ts_web/elements/00group-dataview/dees-table/dees-table.ts b/ts_web/elements/00group-dataview/dees-table/dees-table.ts index af8e962..ff9e116 100644 --- a/ts_web/elements/00group-dataview/dees-table/dees-table.ts +++ b/ts_web/elements/00group-dataview/dees-table/dees-table.ts @@ -768,7 +768,7 @@ export class DeesTable extends DeesElement { ${effectiveColumns .filter((c) => !c.hidden) .map((col) => { - const isSortable = !!col.sortable; + const isSortable = col.sortable !== false; const ariaSort = this.getAriaSort(col); return html` extends DeesElement { } } - // Active when the table top is above the stick line and the table bottom - // hasn't yet scrolled past it. - const shouldBeActive = - tableRect.top < stick.top && tableRect.bottom > stick.top + Math.min(headerHeight, 1); + // Active when the table top is above the stick line and any pixel of the + // table still sits below it. As the table's bottom edge approaches the + // stick line we shrink the floating container and slide the cloned header + // up inside it, so the header appears to scroll off with the table + // instead of snapping away in one frame. + const distance = tableRect.bottom - stick.top; + const shouldBeActive = tableRect.top < stick.top && distance > 0; if (shouldBeActive !== this.__floatingActive) { this.__floatingActive = shouldBeActive; fh.classList.toggle('active', shouldBeActive); + if (!shouldBeActive) { + // Reset inline geometry so the next activation starts clean. + fh.style.height = ''; + const ft = this.__floatingTableEl; + if (ft) ft.style.transform = ''; + } if (shouldBeActive) { // Clone subtree doesn't exist yet — wait for the next render to // materialize it, then complete geometry sync. @@ -1100,10 +1109,19 @@ export class DeesTable extends DeesElement { fh.style.left = `${clipLeft}px`; fh.style.width = `${clipWidth}px`; + // Exit animation: when the table's bottom edge is within `headerHeight` + // pixels of the stick line, shrink the container and translate the + // inner table up by the same amount. overflow:hidden on .floatingHeader + // clips the overflow, producing a scroll-off effect. + const visibleHeight = Math.min(headerHeight, distance); + const exitOffset = headerHeight - visibleHeight; + fh.style.height = `${visibleHeight}px`; + // The inner table is positioned so the visible region matches the real // table's left edge — shift it left when we clipped to the container. floatTable.style.width = `${tableRect.width}px`; floatTable.style.marginLeft = `${tableRect.left - clipLeft}px`; + floatTable.style.transform = exitOffset > 0 ? `translateY(-${exitOffset}px)` : ''; } public async disconnectedCallback() { @@ -1496,7 +1514,7 @@ export class DeesTable extends DeesElement { // Maximum exposed slot: one beyond the current cascade, capped at the // number of sortable columns. If the column is already in the cascade we // never need to grow the slot count. - const sortableColumnCount = effectiveColumns.filter((c) => !!c.sortable).length; + const sortableColumnCount = effectiveColumns.filter((c) => c.sortable !== false).length; const maxSlot = Math.min( Math.max(cascadeLen + (existing ? 0 : 1), 1), Math.max(sortableColumnCount, 1) @@ -1602,6 +1620,17 @@ export class DeesTable extends DeesElement { }); } + items.push({ divider: true }); + items.push({ + name: this.showColumnFilters ? 'Hide column filters' : 'Show column filters', + iconName: this.showColumnFilters ? 'lucide:filterX' : 'lucide:filter', + action: async () => { + this.showColumnFilters = !this.showColumnFilters; + this.requestUpdate(); + return null; + }, + }); + return items; } diff --git a/ts_web/elements/00group-dataview/dees-table/types.ts b/ts_web/elements/00group-dataview/dees-table/types.ts index e76b502..b8a433c 100644 --- a/ts_web/elements/00group-dataview/dees-table/types.ts +++ b/ts_web/elements/00group-dataview/dees-table/types.ts @@ -48,6 +48,7 @@ export interface Column { header?: string | TemplateResult; value?: (row: T) => any; renderer?: (value: any, row: T, ctx: { rowIndex: number; colIndex: number; column: Column }) => TemplateResult | string; + /** Whether this column can be sorted by clicking its header. Defaults to `true`; set to `false` to disable. */ sortable?: boolean; /** whether this column participates in per-column quick filtering (default: true) */ filterable?: boolean;