flexdesk 0.2.0 → 0.3.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/css/base.css +1484 -181
- package/css/flexdesk.css +1311 -18
- package/css/overrides.css +44 -0
- package/css/tokens.css +45 -0
- package/dist/charts.js +5 -3
- package/dist/charts.js.map +1 -1
- package/dist/{chunk-DVU44T77.js → chunk-ELXVW542.js} +196 -75
- package/dist/chunk-ELXVW542.js.map +7 -0
- package/dist/chunk-LH5TSOZW.js +1237 -0
- package/dist/chunk-LH5TSOZW.js.map +7 -0
- package/dist/{chunk-TLZUUFOE.js → chunk-O5OHMWBB.js} +10 -2
- package/dist/chunk-O5OHMWBB.js.map +7 -0
- package/dist/{chunk-CT4YXXLP.js → chunk-QIU5S2RU.js} +371 -73
- package/dist/chunk-QIU5S2RU.js.map +7 -0
- package/dist/chunk-QNQHQ24V.js +408 -0
- package/dist/chunk-QNQHQ24V.js.map +7 -0
- package/dist/{chunk-DRYCDMEG.js → chunk-XKDTIT4Q.js} +168 -12
- package/dist/chunk-XKDTIT4Q.js.map +7 -0
- package/dist/editor.js +3 -380
- package/dist/editor.js.map +3 -3
- package/dist/flexdesk.css +1311 -18
- package/dist/tiles.js +168 -41
- package/dist/tiles.js.map +2 -2
- package/dist/tokens.css +45 -0
- package/dist/widgets.js +44 -14
- package/dist/widgets.js.map +2 -2
- package/dist/wm.js +2983 -142
- package/dist/wm.js.map +4 -4
- package/package.json +3 -2
- package/src/charts/chart_types.js +167 -0
- package/src/charts/plotly_wrapper.js +178 -10
- package/src/editor/notebook_tab_bar.js +39 -3
- package/src/tiles/tile_base.js +143 -35
- package/src/tiles/tile_grid.js +52 -1
- package/src/tiling/command_palette.js +71 -18
- package/src/tiling/desktops.js +36 -12
- package/src/tiling/keymap.js +24 -4
- package/src/tiling/shell.js +135 -24
- package/src/tiling/tab_strip.js +184 -0
- package/src/tiling/tile_breadcrumb.js +34 -2
- package/src/tiling/tile_renderer.js +1386 -21
- package/src/tiling/tile_tab_menu.js +101 -0
- package/src/tiling/tile_tree.js +82 -0
- package/src/tiling/wm.js +2352 -74
- package/src/ui/components/action_dropdown.js +34 -3
- package/src/ui/components/autocomplete_field.js +65 -13
- package/src/ui/components/context_menu.js +79 -8
- package/src/ui/components/data_table.js +508 -84
- package/src/ui/components/managed_window.js +928 -36
- package/src/ui/components/modal.js +214 -8
- package/dist/chunk-CT4YXXLP.js.map +0 -7
- package/dist/chunk-DRYCDMEG.js.map +0 -7
- package/dist/chunk-DVU44T77.js.map +0 -7
- package/dist/chunk-TLZUUFOE.js.map +0 -7
- package/dist/chunk-UCJ2WD4D.js +0 -625
- package/dist/chunk-UCJ2WD4D.js.map +0 -7
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
{
|
|
2
|
+
"version": 3,
|
|
3
|
+
"sources": ["../src/ui/utils/raf_resize_observer.js", "../src/ui/components/data_table.js"],
|
|
4
|
+
"sourcesContent": ["/**\n * rAF-coalesced ResizeObserver.\n *\n * Running layout-mutating work \u2014 `Plotly.Plots.resize()`, Monaco's\n * `editor.layout()`, a canvas resize, or a re-render \u2014 *synchronously* inside a\n * ResizeObserver callback makes the engine emit the (spec-defined, benign but\n * console-error-level) \"ResizeObserver loop completed with undelivered\n * notifications\" warning: the callback mutates layout, which produces more\n * resize notifications it can't deliver in the same dispatch.\n *\n * Deferring the work to the next animation frame is the root-cause fix \u2014 the\n * engine delivers all pending notifications first, so there's nothing left\n * \"undelivered\" \u2014 and coalescing collapses a burst of resize events into a\n * single render.\n *\n * @param {(entries: ResizeObserverEntry[]) => void} callback\n * @returns {ResizeObserver}\n */\nexport function createRafResizeObserver(callback) {\n let scheduled = false;\n let latestEntries = [];\n return new ResizeObserver((entries) => {\n latestEntries = entries;\n if (scheduled) return;\n scheduled = true;\n requestAnimationFrame(() => {\n scheduled = false;\n callback(latestEntries);\n });\n });\n}\n", "/**\n * data_table.js\n *\n * Unified, reusable data table component with support for:\n * - Pagination (first/prev/next/last/jump to row)\n * - Row selection (single, range with Shift, toggle with Ctrl/Cmd)\n * - Keyboard shortcuts (Ctrl+A, Ctrl+C, Shift+Ctrl+C, Esc)\n * - Context menu (copy as TSV/CSV)\n * - Column sorting (internal or external via callback)\n * - Column drag-to-resize, and double-click-to-auto-size on the same grip\n * - Per-column filtering (numeric operators, text substring)\n * - Column type detection (numeric/text alignment)\n * - Header icons\n * - Read-only mode\n * - CSV download through the host port (native save dialog), with a\n * Blob + <a download> fallback when no host is supplied\n *\n * Used by: DataPage, PlotPopoutWindow, StatisticsTable, Import Wizard\n */\n\nimport { createRafResizeObserver } from '../utils/raf_resize_observer.js';\n\nconst DEFAULT_PAGE_SIZE = 100;\n\n/** How wide auto-sizing a column is allowed to make it.\n *\n * 520px, which is `_fitColumnWidths`' FIRST_CAP \u2014 the most generous ceiling\n * this file already sanctions for a single column. Auto-size is an explicit\n * gesture asking to see a column's content, so it is not held to the tighter\n * 360px the automatic fit pass applies to the columns it is squeezing; but it\n * is held to SOMETHING, because one 4,000-character note in one cell would\n * otherwise produce a column nobody can scroll past. */\nconst AUTOSIZE_MAX_PX = 520;\n\n/**\n * Configuration options for DataTable\n * @typedef {Object} DataTableConfig\n * @property {string[]} headers - Column headers\n * @property {Array<Array>} rows - Row data (array of arrays)\n * @property {number} [pageSize=100] - Rows per page\n * @property {boolean} [pagination=true] - Enable pagination controls\n * @property {boolean} [selectable=true] - Enable row selection\n * @property {boolean} [copyable=true] - Enable copy shortcuts and context menu\n * @property {boolean} [sortable=false] - Enable column sorting\n * @property {boolean} [filterable=false] - Enable per-column filter inputs\n * @property {boolean} [readonly=false] - Read-only mode (no selection/hover effects)\n * @property {boolean} [showRowNumbers=false] - Show row number column\n * @property {string} [emptyMessage='No data'] - Message when no data\n * @property {Function} [onSort] - Callback when sort changes: (column, ascending) => void\n * @property {Function} [onSelectionChange] - Callback when selection changes: (selectedIndices) => void\n * @property {Function} [formatValue] - Custom value formatter: (value, colIndex) => string\n * @property {Function} [getHeaderIcon] - Get icon for header: (header, colIndex) => {icon, title}\n * @property {Function} [getColumnType] - Get column type: (colIndex, rows) => 'num'|'text'\n * @property {Object} [services] - App services { eventBus, logger } for notifications\n * @property {number} [totalCount] - Total row count for server-side pagination (when rows only contains current page)\n * @property {number} [offset=0] - Current offset for server-side pagination\n * @property {Function} [onPageChange] - Callback for server-side pagination: (offset, limit) => void\n * @property {Function} [onJumpToRow] - Callback for jump to row: (rowIndex) => void\n * @property {Function} [renderCell] - Custom cell renderer: (td, value, colIdx, rowIdx, row) => boolean (return true if handled)\n * @property {'normal'|'compact'} [mode='normal'] - Rendering density. 'compact' adds `data-table-component--compact` to the wrapper (tighter padding + smaller font for the bottom-panel use case).\n * @property {Function} [onRowClick] - Row click handler: (rowIdx, row, ev) => void. Receives the original (unfiltered) row index.\n * @property {Function} [onRowContextMenu] - Row right-click handler: (rowIdx, row, ev) => void. Fires before the default context menu; call ev.preventDefault() to suppress the default.\n * @property {Function} [onCellContextMenu] - Cell right-click handler: (colIdx, rowIdx, value, td, ev) => void. Fires before onRowContextMenu; same suppression semantics.\n * @property {boolean} [showExportButton=false] - Adds a \"CSV\" download button to the pagination strip that invokes `downloadCSV()`.\n * @property {Object} [host] - A Host (see ui/js/host/host.js). Its `dialogs` capability backs `downloadCSV()`'s native save dialog; without it CSV export falls back to a Blob download.\n * @property {Object} [stateStore] - `{ ready(), get(key), set(key, state) }` \u2014 REQUIRED when `persistKey` is set. Built by `createTableStateStore()`.\n * @property {'container'|'content'} [columnFit='container'] - How the automatic fit pass sizes a column the user has NOT dragged. 'container' squeezes every column into the wrap: a 360px cap, a more generous one for the first column, and water-fill-shrink toward the 40px floor when they do not fit. 'content' sizes each column to its own content through the same `_autoWidth` a grip double-click uses (520px cap) and lets the body scroll sideways rather than squeezing. A pinned column is honoured verbatim under both.\n */\n\nexport class DataTable {\n /**\n * Create a DataTable instance\n * @param {HTMLElement} container - Container element to render into\n * @param {DataTableConfig} config - Configuration options\n */\n constructor(container, config = {}) {\n this.container = container;\n this.config = {\n headers: [],\n rows: [],\n pageSize: DEFAULT_PAGE_SIZE,\n pagination: true,\n selectable: true,\n copyable: true,\n sortable: false,\n filterable: false,\n readonly: false,\n showRowNumbers: false,\n emptyMessage: 'No data',\n onSort: null,\n onSelectionChange: null,\n formatValue: null,\n getHeaderIcon: null,\n getColumnType: null,\n services: null,\n // Server-side pagination\n totalCount: null,\n offset: 0,\n onPageChange: null,\n onJumpToRow: null,\n // Custom cell rendering\n renderCell: null,\n // Rendering density + bottom-panel hooks (P2)\n mode: 'normal',\n onRowClick: null,\n onRowContextMenu: null,\n onCellContextMenu: null,\n showExportButton: false,\n // The host port. TOP LEVEL, deliberately \u2014 NOT inside `services`,\n // which most call sites never pass. Supplies the native save\n // dialog for downloadCSV(); absent => Blob fallback.\n host: null,\n // Opt-in persistence: when set, this table's sort, filters, and\n // column widths survive teardown/reload, keyed by this string\n // inside the injected `stateStore`. Omit it and the table stays\n // ephemeral. WHERE the store persists is the embedder's business.\n persistKey: null,\n stateStore: null,\n // How the automatic fit pass sizes an undragged column \u2014 see the\n // typedef. 'container' is exactly what every consumer got before\n // this key existed, so the default is not a preference: it is the\n // promise that adding the key changed no existing layout by a\n // pixel. Only a consumer that asks for 'content' sees anything new.\n columnFit: 'container',\n ...config,\n };\n\n // A persistKey with nowhere to persist is a wiring bug, not a\n // degraded mode. Fail loud at construction: a silent no-op here\n // reads as \"my filters randomly stopped sticking\" months later.\n if (this.config.persistKey && !this.config.stateStore) {\n throw new Error(`DataTable: persistKey \"${this.config.persistKey}\" requires { stateStore }`);\n }\n\n // State\n this._state = {\n offset: 0,\n selected: new Set(),\n anchorIndex: null,\n sortColumn: null,\n sortAscending: true,\n filters: new Map(),\n };\n\n // Column types cache\n this._columnTypes = [];\n\n // Processed rows cache (filtered + sorted)\n this._processedRows = null;\n this._processedIndexMap = null;\n this._filterDebounceTimer = null;\n\n // DOM references\n this._wrapperEl = null;\n this._paginationEl = null;\n this._tableEl = null;\n this._tbodyEl = null;\n this._contextMenuEl = null;\n this._filterDropdownEl = null;\n this._filterDropdownCleanup = null;\n\n // User column-resize overrides, keyed by DOM column index (the\n // row-number column, when shown, is index 0). Persists across\n // re-renders; reset when the header signature changes.\n this._colWidths = {};\n this._colWidthsSig = null;\n\n // Event cleanup\n this._disposers = [];\n this._contextMenuGlobals = [];\n\n // Persistence: seed from whatever's already cached, then \u2014 once\n // the on-disk blob has loaded \u2014 re-apply and re-render if state\n // arrived after this table first painted.\n if (this.config.persistKey) {\n const store = this.config.stateStore;\n this._restorePersisted(store.get(this.config.persistKey));\n store.ready().then(() => {\n const late = store.get(this.config.persistKey);\n if (late && this._restorePersisted(late) && this._wrapperEl) {\n this._invalidateProcessedCache?.();\n this.render();\n }\n });\n }\n }\n\n /** Apply a persisted blob ({sort, asc, filters, widths}) onto this\n * table's live state. Returns true if anything was applied. */\n _restorePersisted(blob) {\n if (!blob) return false;\n let applied = false;\n if (typeof blob.sortColumn === 'number' || blob.sortColumn === null) {\n this._state.sortColumn = blob.sortColumn;\n this._state.sortAscending = blob.sortAscending !== false;\n applied = true;\n }\n if (Array.isArray(blob.filters)) {\n this._state.filters = new Map(blob.filters);\n applied = true;\n }\n if (blob.colWidths && typeof blob.colWidths === 'object') {\n // Stored under string keys (JSON) \u2192 coerce back to ints.\n this._colWidths = {};\n for (const [k, v] of Object.entries(blob.colWidths)) {\n this._colWidths[Number(k)] = v;\n }\n // Stamp the matching signature so the next render keeps these\n // widths instead of treating them as stale.\n this._colWidthsSig = this._colSig();\n applied = true;\n }\n return applied;\n }\n\n /** Identity of the current column set \u2014 restored widths/sort are\n * keyed by position, so a schema change invalidates them. */\n _colSig() {\n return (this.config.headers || []).join('\\x01')\n + (this.config.showRowNumbers ? '|#' : '');\n }\n\n /** Snapshot the persistable slice of state to the project store.\n * No-op unless `persistKey` is set. Debounced inside the store. */\n _savePersisted() {\n if (!this.config.persistKey) return;\n this.config.stateStore.set(this.config.persistKey, {\n sortColumn: this._state.sortColumn,\n sortAscending: this._state.sortAscending,\n filters: [...this._state.filters.entries()],\n colWidths: { ...this._colWidths },\n });\n }\n\n /**\n * Update data and re-render\n * @param {Object} updates - Partial config updates (headers, rows, etc.)\n */\n setData(updates) {\n // Clear filters if headers changed\n if (updates.headers && this._state.filters.size > 0) {\n const oldHeaders = this.config.headers;\n const newHeaders = updates.headers;\n if (oldHeaders.length !== newHeaders.length ||\n oldHeaders.some((h, i) => h !== newHeaders[i])) {\n this._state.filters.clear();\n }\n }\n\n Object.assign(this.config, updates);\n\n // Reset state if rows changed\n if (updates.rows) {\n this._state.selected.clear();\n this._state.anchorIndex = null;\n if (this._state.offset >= updates.rows.length) {\n this._state.offset = 0;\n }\n this._columnTypes = this._detectColumnTypes();\n }\n\n // Invalidate processed cache\n this._processedRows = null;\n this._processedIndexMap = null;\n\n this.render();\n }\n\n /**\n * Show / hide a translucent loading overlay over the table body.\n * Used by server-side consumers between firing a fetch and\n * receiving the new rows so the UI doesn't appear frozen.\n * Callers either:\n * - call `setLoading(true)` before their fetch, `setLoading(false)` after, OR\n * - return a Promise from `onPageChange` / `onSort` callbacks\n * \u2014 the overlay auto-shows during the await.\n * @param {boolean} on\n */\n setLoading(on) {\n if (!this._wrapperEl) return;\n let overlay = this._wrapperEl.querySelector('.twm-data-table__loading');\n if (on) {\n if (!overlay) {\n overlay = document.createElement('div');\n overlay.className = 'twm-data-table__loading';\n overlay.innerHTML =\n '<div class=\"twm-data-table__spinner\"></div>';\n // Ensure positioning context.\n if (!this._wrapperEl.style.position) {\n this._wrapperEl.style.position = 'relative';\n }\n this._wrapperEl.appendChild(overlay);\n }\n } else if (overlay) {\n overlay.remove();\n }\n }\n\n /**\n * Get current selection indices\n * @returns {number[]} Array of selected row indices\n */\n getSelection() {\n return Array.from(this._state.selected).sort((a, b) => a - b);\n }\n\n /**\n * Set selection programmatically\n * @param {number[]} indices - Row indices to select\n */\n setSelection(indices) {\n this._state.selected.clear();\n for (const idx of indices) {\n if (idx >= 0 && idx < this.config.rows.length) {\n this._state.selected.add(idx);\n }\n }\n this._updateRowSelection();\n this._notifySelectionChange();\n }\n\n /**\n * Clear selection\n */\n clearSelection() {\n this._state.selected.clear();\n this._state.anchorIndex = null;\n this._updateRowSelection();\n this._notifySelectionChange();\n }\n\n /**\n * Go to specific page\n * @param {number} page - Page number (0-indexed)\n */\n goToPage(page) {\n const rowCount = this._getProcessedRows().length;\n const maxPage = Math.ceil(rowCount / this.config.pageSize) - 1;\n this._state.offset = Math.max(0, Math.min(page, maxPage)) * this.config.pageSize;\n this.render();\n }\n\n /**\n * Go to specific row\n * @param {number} rowIndex - Row index\n */\n goToRow(rowIndex) {\n const rowCount = this._getProcessedRows().length;\n const idx = Math.max(0, Math.min(rowIndex, rowCount - 1));\n this._state.offset = Math.floor(idx / this.config.pageSize) * this.config.pageSize;\n this.render();\n }\n\n /**\n * Sort by column\n * @param {number} colIndex - Column index\n * @param {boolean} [ascending] - Sort direction (toggles if same column)\n */\n sortBy(colIndex, ascending) {\n if (this._state.sortColumn === colIndex && ascending === undefined) {\n this._state.sortAscending = !this._state.sortAscending;\n } else {\n this._state.sortColumn = colIndex;\n this._state.sortAscending = ascending ?? true;\n }\n\n // Invalidate processed cache\n this._processedRows = null;\n this._processedIndexMap = null;\n\n // Auto-spinner: if the sort handler returns a Promise (i.e.\n // it does a server-side refetch), show the loading overlay\n // until it resolves so the user gets visible feedback.\n const ret = this.config.onSort?.(colIndex, this._state.sortAscending);\n this._awaitWithSpinner(ret);\n this._savePersisted();\n this.render();\n }\n\n /** Internal: if `maybePromise` is a Promise (or thenable),\n * toggle the loading overlay around it. No-op otherwise. */\n _awaitWithSpinner(maybePromise) {\n if (!maybePromise || typeof maybePromise.then !== 'function') return;\n this.setLoading(true);\n Promise.resolve(maybePromise).finally(() => this.setLoading(false));\n }\n\n /**\n * Clear all column filters\n */\n clearFilters() {\n this._state.filters.clear();\n this._processedRows = null;\n this._processedIndexMap = null;\n this._state.offset = 0;\n this._savePersisted();\n this.render();\n }\n\n /**\n * Get the number of rows after filtering\n * @returns {number}\n */\n getFilteredRowCount() {\n return this._getProcessedRows().length;\n }\n\n /**\n * Render the table\n */\n render() {\n // Capture active filter input before re-render\n const activeFilterColIdx = this._getActiveFilterColIdx();\n\n this._cleanup();\n this.container.innerHTML = '';\n\n const { rows, pagination, emptyMessage } = this.config;\n\n // Drop stale column-resize overrides when the columns change \u2014\n // widths are keyed by position, so a different schema must start\n // from natural widths rather than inherit the old ones. (Restore\n // stamps the matching signature so persisted widths survive the\n // first render.)\n const colSig = this._colSig();\n if (this._colWidthsSig !== colSig) {\n this._colWidths = {};\n this._colWidthsSig = colSig;\n }\n\n // Detect column types if not cached\n if (this._columnTypes.length === 0) {\n this._columnTypes = this._detectColumnTypes();\n }\n\n // Create wrapper. Compact mode adds a modifier class that the\n // CSS uses to tighten padding + drop font size \u2014 opt-in so\n // existing landing/tab use sites stay identical.\n this._wrapperEl = document.createElement('div');\n this._wrapperEl.className = 'twm-data-table-component'\n + (this.config.mode === 'compact' ? ' twm-data-table-component--compact' : '');\n this._wrapperEl.style.cssText = 'display:flex; flex-direction:column; height:100%; min-height:0;';\n\n // Pagination (top). `_createPagination` returns null when the\n // strip would be uninformative (single page, no active filter).\n if (pagination && rows.length > 0) {\n this._paginationEl = this._createPagination();\n if (this._paginationEl) this._wrapperEl.appendChild(this._paginationEl);\n }\n\n // \u2500\u2500 Structural split: thead and tbody live in separate\n // containers so the scrollbar appears only over the body,\n // never over the header / filter row. Column widths are\n // measured from the body after layout and applied to the\n // header via `table-layout: fixed` + explicit cell widths.\n const tableWrap = document.createElement('div');\n tableWrap.className = this.config.readonly\n ? 'twm-preview-table-wrap twm-preview-table-wrap--wizard'\n : 'twm-preview-table-wrap';\n tableWrap.style.cssText = 'flex:1 1 0; min-height:0; min-width:0; overflow:auto;';\n\n if (rows.length === 0) {\n // Empty state \u2014 render the same chrome as the data table\n // (header row in its own non-scrolling wrap) followed by a\n // single virtual row spanning every column with the empty\n // message in italics. NO filter row: there's nothing to\n // filter, so it'd only mislead the user.\n const { headers, showRowNumbers } = this.config;\n const headerWrap = document.createElement('div');\n headerWrap.className = 'twm-preview-table-header-wrap';\n headerWrap.style.cssText\n = 'flex:0 0 auto; overflow:hidden; min-width:0;';\n const headerTable = document.createElement('table');\n headerTable.className = this.config.readonly\n ? 'twm-preview-table twm-preview-table--readonly'\n : 'twm-preview-table';\n const thead = document.createElement('thead');\n const tr = document.createElement('tr');\n if (showRowNumbers) {\n const th = document.createElement('th');\n th.className = 'num';\n th.textContent = '#';\n tr.appendChild(th);\n }\n headers.forEach((h, colIdx) => {\n const th = document.createElement('th');\n th.className = this._columnTypes[colIdx] || 'text';\n th.textContent = h;\n tr.appendChild(th);\n });\n thead.appendChild(tr);\n headerTable.appendChild(thead);\n headerWrap.appendChild(headerTable);\n this._wrapperEl.appendChild(headerWrap);\n this._headerWrapEl = headerWrap;\n this._headerTableEl = headerTable;\n\n // Body: one virtual row across every column with the empty\n // message in italics. Wraps in the standard scroll container\n // so the placeholder sits where data rows would.\n const bodyTable = document.createElement('table');\n bodyTable.className = headerTable.className;\n const tbody = document.createElement('tbody');\n const emptyTr = document.createElement('tr');\n emptyTr.className = 'data-preview-row data-table__empty-row';\n const colCount = headers.length + (showRowNumbers ? 1 : 0);\n const emptyTd = document.createElement('td');\n emptyTd.colSpan = colCount;\n emptyTd.style.cssText\n = 'text-align:center; font-style:italic; color:#888; padding:16px;';\n emptyTd.textContent = emptyMessage;\n emptyTr.appendChild(emptyTd);\n tbody.appendChild(emptyTr);\n bodyTable.appendChild(tbody);\n tableWrap.appendChild(bodyTable);\n this._wrapperEl.appendChild(tableWrap);\n this._tableEl = bodyTable;\n this._tableWrapEl = tableWrap;\n // No column-width sync needed \u2014 the body row has colspan=N\n // so there's nothing per-column to align against.\n } else {\n const fullTable = this._createTable();\n this._tableEl = fullTable;\n // Extract thead \u2192 header table in its own non-scrolling\n // container. The body table keeps tbody only.\n const thead = fullTable.querySelector('thead');\n if (thead) {\n const headerWrap = document.createElement('div');\n headerWrap.className = 'twm-preview-table-header-wrap';\n headerWrap.style.cssText\n = 'flex:0 0 auto; overflow:hidden; min-width:0;';\n const headerTable = document.createElement('table');\n headerTable.className = fullTable.className;\n headerTable.appendChild(thead);\n headerWrap.appendChild(headerTable);\n this._wrapperEl.appendChild(headerWrap);\n this._headerTableEl = headerTable;\n this._headerWrapEl = headerWrap;\n } else {\n this._headerTableEl = null;\n }\n tableWrap.appendChild(fullTable);\n this._wrapperEl.appendChild(tableWrap);\n }\n\n this._tableWrapEl = tableWrap;\n this.container.appendChild(this._wrapperEl);\n\n // Sync header column widths to body after layout. Two-pass: the\n // first frame lets the browser settle natural widths from the\n // body's auto layout, then we lock both tables to those widths\n // via table-layout:fixed + explicit cell widths.\n if (this._headerTableEl && this._tableEl) {\n requestAnimationFrame(() => this._syncHeaderWidths());\n // Re-sync on container resize so columns stay aligned when\n // the parent flex / grid layout changes (window resize,\n // splitter drag, etc.).\n if (this._resizeObserver) {\n try { this._resizeObserver.disconnect(); } catch (_) {}\n }\n if (typeof ResizeObserver !== 'undefined') {\n this._resizeObserver = createRafResizeObserver(\n () => this._syncHeaderWidths());\n this._resizeObserver.observe(this._wrapperEl);\n }\n // The header lives in its own non-scrolling wrap (so it can't\n // escape vertically), but that means it also won't follow the\n // body's HORIZONTAL scroll on its own \u2014 translate it to match.\n this._installHeaderScrollSync();\n // Drag-to-resize handles on each header cell. Only meaningful\n // when there are body rows to size against.\n if (rows.length > 0) this._installColumnResizers();\n }\n\n // Install interactions (readonly only prevents editing, not selection/copy)\n if (rows.length > 0 && (this.config.selectable || this.config.copyable || !this.config.readonly)) {\n this._installInteractions();\n }\n\n // Restore focus to filter input if it was active\n if (activeFilterColIdx !== null) {\n this._restoreFilterFocus(activeFilterColIdx);\n }\n }\n\n /**\n * Copy selected rows to clipboard\n * @param {'tsv'|'csv'} [format='tsv'] - Output format\n */\n async copyToClipboard(format = 'tsv') {\n const indices = this.getSelection();\n if (indices.length === 0) {\n this._notify('Copy', 'No rows selected.', 'warn');\n return;\n }\n\n const { headers, rows } = this.config;\n const matrix = [headers];\n\n for (const idx of indices) {\n const row = rows[idx];\n if (row) {\n matrix.push(row.map((val, colIdx) => this._formatValue(val, colIdx)));\n }\n }\n\n const separator = format === 'csv' ? ',' : '\\t';\n const text = format === 'csv'\n ? matrix.map(row => row.map(cell => this._csvEscape(cell)).join(separator)).join('\\n')\n : matrix.map(row => row.join(separator)).join('\\n');\n\n let ok = false;\n try {\n await navigator.clipboard.writeText(text);\n ok = true;\n } catch (_) {\n ok = this._fallbackCopy(text);\n }\n\n if (ok) {\n const desc = indices.length === 1 ? 'row' : 'rows';\n const suffix = format === 'csv' ? ' as CSV' : '';\n this._notify('Copy', `Copied ${indices.length} ${desc}${suffix}.`, 'info');\n } else {\n this._notify('Copy', 'Clipboard unavailable.', 'warn');\n }\n\n this._hideContextMenu();\n }\n\n /**\n * Download all data as CSV\n * @param {string} [filename='data.csv'] - Filename for download\n */\n async downloadCSV(filename = 'data.csv') {\n const { headers, rows } = this.config;\n if (rows.length === 0) {\n this._notify('Download', 'No data to download.', 'warn');\n return;\n }\n\n const lines = [headers.join(',')];\n for (const row of rows) {\n lines.push(row.map((val, colIdx) =>\n this._csvEscape(this._formatValue(val, colIdx))\n ).join(','));\n }\n\n const csv = lines.join('\\n');\n\n // Native save dialog when the embedder supplies one.\n //\n // `saveFile` resolves to null when a host advertises `dialogs` but its\n // transport has no save dialog behind it (host.js: null <=> unavailable).\n // That is NOT a failed save \u2014 it means \"I can't do this, use your own\n // way\", so it must reach the Blob fallback below, not the error toast.\n const dialogs = this.config.host?.dialogs;\n let result = null;\n if (dialogs) {\n try {\n // Send plain text CSV - Python handles text files directly (no base64)\n result = await dialogs.saveFile({ data: csv, filename, kind: 'csv' });\n } catch (err) {\n console.error('[DataTable] CSV download failed:', err);\n this._notify('Download', 'Failed to save file', 'error');\n return;\n }\n }\n if (result) {\n if (result.ok) {\n this._notify('Download', `Saved ${rows.length} rows to ${result.path}`, 'success');\n } else if (!result.cancelled) {\n this._notify('Download', result.error || 'Failed to save file', 'error');\n }\n return;\n }\n\n // Fallback: no `dialogs` capability at all, or a host that has one but\n // cannot actually save. Both mean \"download it yourself\".\n const blob = new Blob([csv], { type: 'text/csv;charset=utf-8;' });\n const url = URL.createObjectURL(blob);\n const link = document.createElement('a');\n link.href = url;\n link.download = filename;\n link.click();\n URL.revokeObjectURL(url);\n this._notify('Download', 'Download started', 'info');\n }\n\n /**\n * Dispose and cleanup\n */\n dispose() {\n this._cleanup();\n this._closeFilterDropdown();\n this._teardownContextMenu();\n if (this._resizeObserver) {\n try { this._resizeObserver.disconnect(); } catch (_) {}\n this._resizeObserver = null;\n }\n if (this._onBodyScroll && this._scrollSyncEl) {\n try {\n this._scrollSyncEl.removeEventListener('scroll', this._onBodyScroll);\n } catch (_) {}\n this._onBodyScroll = null;\n this._scrollSyncEl = null;\n }\n this.container.innerHTML = '';\n this._wrapperEl = null;\n this._paginationEl = null;\n this._tableEl = null;\n this._tbodyEl = null;\n this._headerTableEl = null;\n this._headerWrapEl = null;\n this._tableWrapEl = null;\n this._processedRows = null;\n this._processedIndexMap = null;\n }\n\n // \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\n // Processed rows pipeline (filter \u2192 sort \u2192 cache)\n // \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\n\n _getProcessedRows() {\n if (this._processedRows !== null) return this._processedRows;\n\n const isServerSide = typeof this.config.onPageChange === 'function';\n let rows = this.config.rows;\n let indexMap = rows.map((_, i) => i);\n\n // Apply filters (client-side only)\n if (!isServerSide && this._state.filters.size > 0) {\n const result = this._applyFilters(rows, indexMap);\n rows = result.rows;\n indexMap = result.indexMap;\n }\n\n // Apply sort (client-side, only when no external onSort handler)\n if (!isServerSide && this.config.sortable && this._state.sortColumn !== null && !this.config.onSort) {\n const result = this._applySorting(rows, indexMap);\n rows = result.rows;\n indexMap = result.indexMap;\n }\n\n this._processedRows = rows;\n this._processedIndexMap = indexMap;\n return rows;\n }\n\n _applyFilters(rows, indexMap) {\n const filters = this._state.filters;\n const filteredRows = [];\n const filteredMap = [];\n\n for (let i = 0; i < rows.length; i++) {\n const row = rows[i];\n let pass = true;\n\n for (const [colIdx, filterText] of filters) {\n if (!filterText) continue;\n const value = row[colIdx];\n const colType = this._columnTypes[colIdx];\n\n if (colType === 'num') {\n if (!this._matchNumericFilter(value, filterText)) { pass = false; break; }\n } else {\n if (!this._matchTextFilter(value, filterText)) { pass = false; break; }\n }\n }\n\n if (pass) {\n filteredRows.push(row);\n filteredMap.push(indexMap[i]);\n }\n }\n\n return { rows: filteredRows, indexMap: filteredMap };\n }\n\n _applySorting(rows, indexMap) {\n const colIdx = this._state.sortColumn;\n const asc = this._state.sortAscending;\n\n // Build paired array for stable sort with index tracking\n const paired = rows.map((row, i) => ({ row, origIdx: indexMap[i] }));\n const isNumeric = this._columnTypes[colIdx] === 'num';\n\n paired.sort((a, b) => {\n let valA = a.row[colIdx];\n let valB = b.row[colIdx];\n\n if (valA == null && valB == null) return 0;\n if (valA == null) return 1;\n if (valB == null) return -1;\n\n if (isNumeric) {\n valA = typeof valA === 'number' ? valA : parseFloat(valA);\n valB = typeof valB === 'number' ? valB : parseFloat(valB);\n if (!Number.isFinite(valA)) return 1;\n if (!Number.isFinite(valB)) return -1;\n } else {\n valA = String(valA).toLowerCase();\n valB = String(valB).toLowerCase();\n }\n\n let cmp = 0;\n if (valA < valB) cmp = -1;\n else if (valA > valB) cmp = 1;\n\n return asc ? cmp : -cmp;\n });\n\n return {\n rows: paired.map(p => p.row),\n indexMap: paired.map(p => p.origIdx),\n };\n }\n\n _matchNumericFilter(value, filterText) {\n const text = filterText.trim();\n if (!text) return true;\n\n const numVal = (typeof value === 'number') ? value : parseFloat(value);\n if (!Number.isFinite(numVal)) return false;\n\n // Range: \"10..100\"\n const rangeMatch = text.match(/^(-?[\\d.]+)\\.\\.(-?[\\d.]+)$/);\n if (rangeMatch) {\n const lo = parseFloat(rangeMatch[1]);\n const hi = parseFloat(rangeMatch[2]);\n return numVal >= lo && numVal <= hi;\n }\n\n // Operator prefix: >=, <=, !=, >, <, =\n const opMatch = text.match(/^(>=|<=|!=|>|<|=)\\s*(-?[\\d.]+)$/);\n if (opMatch) {\n const op = opMatch[1];\n const target = parseFloat(opMatch[2]);\n if (!Number.isFinite(target)) return true;\n switch (op) {\n case '>': return numVal > target;\n case '<': return numVal < target;\n case '>=': return numVal >= target;\n case '<=': return numVal <= target;\n case '!=': return Math.abs(numVal - target) > 1e-9;\n case '=': return Math.abs(numVal - target) <= 1e-9;\n }\n }\n\n // Plain number: equality\n const plain = parseFloat(text);\n if (Number.isFinite(plain)) {\n return Math.abs(numVal - plain) <= 1e-9;\n }\n\n return true;\n }\n\n _matchTextFilter(value, filterText) {\n if (!filterText) return true;\n const haystack = (value == null ? '' : String(value)).toLowerCase();\n const text = filterText.trim();\n\n // Exact match: =\"value\"\n if (text.startsWith('=\"') && text.endsWith('\"')) {\n return haystack === text.slice(2, -1).toLowerCase();\n }\n // Not contains: !value\n if (text.startsWith('!')) {\n return !haystack.includes(text.slice(1).toLowerCase());\n }\n // Starts with: ^value\n if (text.startsWith('^')) {\n return haystack.startsWith(text.slice(1).toLowerCase());\n }\n // Ends with: value$\n if (text.endsWith('$')) {\n return haystack.endsWith(text.slice(0, -1).toLowerCase());\n }\n // Contains (default)\n return haystack.includes(text.toLowerCase());\n }\n\n _invalidateProcessedCache() {\n this._processedRows = null;\n this._processedIndexMap = null;\n }\n\n // \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\n // Filter row\n // \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\n\n _createFilterRow(headers) {\n const { showRowNumbers } = this.config;\n const tr = document.createElement('tr');\n tr.className = 'twm-data-table__filter-row';\n\n if (showRowNumbers) {\n const th = document.createElement('th');\n th.className = 'data-table__filter-cell data-table__filter-cell--empty';\n tr.appendChild(th);\n }\n\n headers.forEach((header, colIdx) => {\n const th = document.createElement('th');\n th.className = 'data-table__filter-cell';\n\n const wrapper = document.createElement('div');\n wrapper.className = 'twm-data-table__filter-wrapper';\n\n const input = document.createElement('input');\n input.type = 'text';\n input.className = 'twm-data-table__filter-input';\n const isNumeric = this._columnTypes[colIdx] === 'num';\n input.placeholder = isNumeric ? 'e.g. >100' : 'Filter...';\n\n // Restore existing filter value\n const existingFilter = this._state.filters.get(colIdx);\n if (existingFilter) {\n input.value = existingFilter;\n }\n\n // Dropdown trigger button\n const dropdownBtn = document.createElement('button');\n dropdownBtn.type = 'button';\n dropdownBtn.className = 'twm-data-table__filter-dropdown-btn';\n dropdownBtn.innerHTML = '<span class=\"material-symbols-outlined\" style=\"font-size:14px;\">tune</span>';\n dropdownBtn.addEventListener('click', (e) => {\n e.stopPropagation();\n this._openFilterDropdown(colIdx, th, input);\n });\n\n // Clear button\n const clearBtn = document.createElement('button');\n clearBtn.type = 'button';\n clearBtn.className = 'twm-data-table__filter-clear';\n clearBtn.innerHTML = '<span class=\"material-symbols-outlined\" style=\"font-size:12px;\">close</span>';\n clearBtn.style.display = existingFilter ? '' : 'none';\n clearBtn.addEventListener('click', (e) => {\n e.stopPropagation();\n input.value = '';\n this._onFilterInput(colIdx, '');\n clearBtn.style.display = 'none';\n input.focus();\n });\n\n input.addEventListener('input', () => {\n clearBtn.style.display = input.value ? '' : 'none';\n this._onFilterInputDebounced(colIdx, input.value);\n });\n\n // Prevent sort from triggering when clicking in filter cell\n th.addEventListener('click', (e) => e.stopPropagation());\n\n wrapper.appendChild(input);\n wrapper.appendChild(dropdownBtn);\n wrapper.appendChild(clearBtn);\n th.appendChild(wrapper);\n tr.appendChild(th);\n });\n\n return tr;\n }\n\n // \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\n // Filter dropdown\n // \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\n\n _openFilterDropdown(colIdx, anchorEl, filterInput) {\n // Close any existing dropdown\n this._closeFilterDropdown();\n\n const isNumeric = this._columnTypes[colIdx] === 'num';\n const currentFilter = this._state.filters.get(colIdx) || '';\n const parsed = this._parseFilterForDropdown(currentFilter, isNumeric);\n\n // Build dropdown panel\n const panel = document.createElement('div');\n panel.className = 'twm-data-table__filter-dropdown';\n\n // Operator/mode select\n const selectLabel = document.createElement('label');\n selectLabel.className = 'twm-data-table__filter-dropdown-label';\n selectLabel.textContent = isNumeric ? 'Operator' : 'Mode';\n\n const select = document.createElement('select');\n select.className = 'twm-data-table__filter-dropdown-select';\n\n const options = isNumeric\n ? [\n { value: '=', label: 'Equals' },\n { value: '!=', label: 'Not equals' },\n { value: '>', label: 'Greater than' },\n { value: '>=', label: 'Greater or equal' },\n { value: '<', label: 'Less than' },\n { value: '<=', label: 'Less or equal' },\n { value: '..', label: 'Between' },\n ]\n : [\n { value: 'contains', label: 'Contains' },\n { value: 'equals', label: 'Equals' },\n { value: 'starts', label: 'Starts with' },\n { value: 'ends', label: 'Ends with' },\n { value: 'not', label: 'Not contains' },\n ];\n\n for (const opt of options) {\n const optEl = document.createElement('option');\n optEl.value = opt.value;\n optEl.textContent = opt.label;\n if (opt.value === parsed.operator) optEl.selected = true;\n select.appendChild(optEl);\n }\n\n // Value input\n const valueLabel = document.createElement('label');\n valueLabel.className = 'twm-data-table__filter-dropdown-label';\n valueLabel.textContent = 'Value';\n\n const valueInput = document.createElement('input');\n valueInput.type = isNumeric ? 'number' : 'text';\n valueInput.className = 'twm-data-table__filter-dropdown-input';\n valueInput.placeholder = isNumeric ? 'Number...' : 'Text...';\n valueInput.value = parsed.value;\n\n // Second value input (for \"between\")\n const value2Label = document.createElement('label');\n value2Label.className = 'twm-data-table__filter-dropdown-label';\n value2Label.textContent = 'And';\n\n const value2Input = document.createElement('input');\n value2Input.type = 'number';\n value2Input.className = 'twm-data-table__filter-dropdown-input';\n value2Input.placeholder = 'Number...';\n value2Input.value = parsed.value2;\n\n const value2Container = document.createElement('div');\n value2Container.className = 'twm-data-table__filter-dropdown-between';\n value2Container.style.display = (isNumeric && parsed.operator === '..') ? '' : 'none';\n value2Container.appendChild(value2Label);\n value2Container.appendChild(value2Input);\n\n // Toggle between fields when operator changes\n select.addEventListener('change', () => {\n value2Container.style.display = (isNumeric && select.value === '..') ? '' : 'none';\n });\n\n // Actions\n const actions = document.createElement('div');\n actions.className = 'twm-data-table__filter-dropdown-actions';\n\n const clearBtn = document.createElement('button');\n clearBtn.type = 'button';\n clearBtn.className = 'twm-data-table__filter-dropdown-btn-action twm-data-table__filter-dropdown-btn-action--clear';\n clearBtn.textContent = 'Clear';\n clearBtn.addEventListener('click', (e) => {\n e.stopPropagation();\n filterInput.value = '';\n this._onFilterInput(colIdx, '');\n this._closeFilterDropdown();\n });\n\n const applyBtn = document.createElement('button');\n applyBtn.type = 'button';\n applyBtn.className = 'twm-data-table__filter-dropdown-btn-action twm-data-table__filter-dropdown-btn-action--apply';\n applyBtn.textContent = 'Apply';\n applyBtn.addEventListener('click', (e) => {\n e.stopPropagation();\n const composed = this._composeFilterString(select.value, valueInput.value, value2Input.value, isNumeric);\n filterInput.value = composed;\n this._onFilterInput(colIdx, composed);\n this._closeFilterDropdown();\n });\n\n actions.appendChild(clearBtn);\n actions.appendChild(applyBtn);\n\n // Assemble panel\n panel.appendChild(selectLabel);\n panel.appendChild(select);\n panel.appendChild(valueLabel);\n panel.appendChild(valueInput);\n panel.appendChild(value2Container);\n panel.appendChild(actions);\n\n // Add to document and position\n document.body.appendChild(panel);\n\n const anchorRect = anchorEl.getBoundingClientRect();\n let left = anchorRect.left;\n let top = anchorRect.bottom + 4;\n\n // Viewport boundary check\n const panelRect = panel.getBoundingClientRect();\n if (left + panelRect.width > window.innerWidth) {\n left = window.innerWidth - panelRect.width - 8;\n }\n if (top + panelRect.height > window.innerHeight) {\n top = anchorRect.top - panelRect.height - 4;\n }\n\n panel.style.left = `${left}px`;\n panel.style.top = `${top}px`;\n\n // Focus the value input\n requestAnimationFrame(() => valueInput.focus());\n\n // Close on outside click (capture phase)\n const handleOutsideClick = (e) => {\n if (!panel.contains(e.target)) {\n this._closeFilterDropdown();\n }\n };\n const handleEscape = (e) => {\n if (e.key === 'Escape') {\n this._closeFilterDropdown();\n }\n };\n // Enter key applies the filter\n const handleEnter = (e) => {\n if (e.key === 'Enter') {\n e.preventDefault();\n const composed = this._composeFilterString(select.value, valueInput.value, value2Input.value, isNumeric);\n filterInput.value = composed;\n this._onFilterInput(colIdx, composed);\n this._closeFilterDropdown();\n }\n };\n\n // Delay attaching outside-click to avoid catching the trigger click\n setTimeout(() => {\n document.addEventListener('click', handleOutsideClick, true);\n }, 0);\n document.addEventListener('keydown', handleEscape);\n panel.addEventListener('keydown', handleEnter);\n\n this._filterDropdownEl = panel;\n this._filterDropdownCleanup = () => {\n document.removeEventListener('click', handleOutsideClick, true);\n document.removeEventListener('keydown', handleEscape);\n };\n }\n\n _closeFilterDropdown() {\n if (this._filterDropdownEl?.parentNode) {\n this._filterDropdownEl.parentNode.removeChild(this._filterDropdownEl);\n }\n this._filterDropdownCleanup?.();\n this._filterDropdownEl = null;\n this._filterDropdownCleanup = null;\n }\n\n _parseFilterForDropdown(filterText, isNumeric) {\n const text = (filterText || '').trim();\n if (!text) {\n return { operator: isNumeric ? '=' : 'contains', value: '', value2: '' };\n }\n\n if (isNumeric) {\n // Range: \"10..100\"\n const rangeMatch = text.match(/^(-?[\\d.]+)\\.\\.(-?[\\d.]+)$/);\n if (rangeMatch) {\n return { operator: '..', value: rangeMatch[1], value2: rangeMatch[2] };\n }\n // Operator prefix: >=, <=, !=, >, <, =\n const opMatch = text.match(/^(>=|<=|!=|>|<|=)\\s*(-?[\\d.]+)$/);\n if (opMatch) {\n return { operator: opMatch[1], value: opMatch[2], value2: '' };\n }\n // Plain number\n return { operator: '=', value: text, value2: '' };\n }\n\n // Text modes\n if (text.startsWith('=\"') && text.endsWith('\"')) {\n return { operator: 'equals', value: text.slice(2, -1), value2: '' };\n }\n if (text.startsWith('!')) {\n return { operator: 'not', value: text.slice(1), value2: '' };\n }\n if (text.startsWith('^')) {\n return { operator: 'starts', value: text.slice(1), value2: '' };\n }\n if (text.endsWith('$')) {\n return { operator: 'ends', value: text.slice(0, -1), value2: '' };\n }\n return { operator: 'contains', value: text, value2: '' };\n }\n\n _composeFilterString(operator, value, value2, isNumeric) {\n if (!value && operator !== '..') return '';\n\n if (isNumeric) {\n if (operator === '..') {\n return (value && value2) ? `${value}..${value2}` : '';\n }\n if (operator === '=') return value;\n return `${operator}${value}`;\n }\n\n // Text modes\n switch (operator) {\n case 'contains': return value;\n case 'equals': return value ? `=\"${value}\"` : '';\n case 'starts': return value ? `^${value}` : '';\n case 'ends': return value ? `${value}$` : '';\n case 'not': return value ? `!${value}` : '';\n default: return value;\n }\n }\n\n _onFilterInputDebounced(colIdx, value) {\n if (this._filterDebounceTimer) {\n clearTimeout(this._filterDebounceTimer);\n }\n this._filterDebounceTimer = setTimeout(() => {\n this._onFilterInput(colIdx, value);\n }, 200);\n }\n\n _onFilterInput(colIdx, value) {\n if (value) {\n this._state.filters.set(colIdx, value);\n } else {\n this._state.filters.delete(colIdx);\n }\n\n this._invalidateProcessedCache();\n this._state.offset = 0;\n this._state.selected.clear();\n this._state.anchorIndex = null;\n\n this._savePersisted();\n this.render();\n }\n\n _getActiveFilterColIdx() {\n const active = document.activeElement;\n if (!active || !active.classList.contains('twm-data-table__filter-input')) return null;\n const cell = active.closest('.data-table__filter-cell');\n if (!cell) return null;\n const row = cell.parentElement;\n if (!row) return null;\n const cells = Array.from(row.children);\n const idx = cells.indexOf(cell);\n return this.config.showRowNumbers ? idx - 1 : idx;\n }\n\n _restoreFilterFocus(colIdx) {\n const filterRow = this._wrapperEl?.querySelector('.twm-data-table__filter-row');\n if (!filterRow) return;\n const cellIdx = this.config.showRowNumbers ? colIdx + 1 : colIdx;\n const cell = filterRow.children[cellIdx];\n const input = cell?.querySelector('.twm-data-table__filter-input');\n if (input) {\n input.focus();\n input.setSelectionRange(input.value.length, input.value.length);\n }\n }\n\n // \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\n // Private methods\n // \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\n\n _cleanup() {\n this._disposers.forEach(dispose => {\n try { dispose?.(); } catch (_) {}\n });\n this._disposers = [];\n this._closeFilterDropdown();\n if (this._filterDebounceTimer) {\n clearTimeout(this._filterDebounceTimer);\n this._filterDebounceTimer = null;\n }\n }\n\n _detectColumnTypes() {\n const { headers, rows, getColumnType } = this.config;\n const types = [];\n\n for (let colIdx = 0; colIdx < headers.length; colIdx++) {\n if (getColumnType) {\n types.push(getColumnType(colIdx, rows));\n continue;\n }\n\n // Auto-detect by sampling first 10 rows\n let numericCount = 0;\n let sampleCount = 0;\n const maxSamples = Math.min(10, rows.length);\n\n for (let i = 0; i < maxSamples; i++) {\n const value = rows[i]?.[colIdx];\n if (value != null && value !== '') {\n sampleCount++;\n if (typeof value === 'number' || /^-?[\\d,.]+%?$/.test(String(value).trim())) {\n numericCount++;\n }\n }\n }\n\n types.push(sampleCount > 0 && numericCount / sampleCount > 0.5 ? 'num' : 'text');\n }\n\n return types;\n }\n\n _createPagination() {\n const { rows, pageSize, totalCount: configTotalCount, offset: configOffset, onPageChange, onJumpToRow } = this.config;\n\n // Server-side pagination uses config offset, client-side uses state offset\n const isServerSide = typeof onPageChange === 'function';\n const offset = isServerSide ? (configOffset || 0) : this._state.offset;\n\n // For client-side, use processed (filtered+sorted) row count\n const processedRows = isServerSide ? rows : this._getProcessedRows();\n const effectiveTotal = isServerSide ? (configTotalCount || rows.length) : processedRows.length;\n const unfilteredTotal = isServerSide ? (configTotalCount || rows.length) : rows.length;\n const isFiltered = !isServerSide && this._state.filters.size > 0;\n\n const displayedRows = isServerSide ? rows.length : Math.min(pageSize, effectiveTotal - offset);\n const endRow = Math.min(offset + displayedRows, effectiveTotal);\n const totalPages = Math.max(1, Math.ceil(effectiveTotal / pageSize));\n // Don't render the strip when there's only one page \u2014 the row\n // count is uninformative (the table itself shows every row) and\n // the nav buttons would all be disabled.\n if (totalPages <= 1 && !isFiltered) return null;\n const currentPage = Math.floor(offset / pageSize) + 1;\n const hasPrev = offset > 0;\n const hasNext = offset + pageSize < effectiveTotal;\n\n const el = document.createElement('div');\n el.className = 'twm-pagination-controls';\n el.style.cssText = 'display:flex; align-items:center; gap:6px; padding:2px 8px; border-bottom:1px solid #2a2a2a; font-size:11px;';\n\n // Info\n const info = document.createElement('span');\n info.style.cssText = 'color:#aaa; white-space:nowrap;';\n if (effectiveTotal === 0) {\n info.textContent = isFiltered\n ? `0 of ${unfilteredTotal.toLocaleString()} rows match`\n : 'No rows';\n } else if (isFiltered) {\n info.textContent = `Rows ${offset + 1}\\u2013${endRow} of ${effectiveTotal.toLocaleString()} (${unfilteredTotal.toLocaleString()} total)`;\n } else {\n info.textContent = `Rows ${offset + 1}\\u2013${endRow} of ${effectiveTotal.toLocaleString()}`;\n }\n\n // Spacer\n const spacer = document.createElement('div');\n spacer.style.flex = '1';\n\n // Page change handler - supports both client-side and server-side pagination\n const handlePageChange = (newOffset) => {\n if (isServerSide) {\n // Auto-spinner if the consumer returns a Promise.\n this._awaitWithSpinner(onPageChange(newOffset, pageSize));\n } else {\n this._state.offset = newOffset;\n this.render();\n }\n };\n\n // Navigation buttons\n const firstBtn = this._createPaginationBtn('first_page', 'First page', !hasPrev, () => {\n handlePageChange(0);\n });\n\n const prevBtn = this._createPaginationBtn('chevron_left', 'Previous page', !hasPrev, () => {\n handlePageChange(Math.max(0, offset - pageSize));\n });\n\n const pageInfo = document.createElement('span');\n pageInfo.style.cssText = 'color:#aaa; font-size:10px; min-width:72px; text-align:center;';\n pageInfo.textContent = `Page ${currentPage} of ${totalPages}`;\n\n const nextBtn = this._createPaginationBtn('chevron_right', 'Next page', !hasNext, () => {\n handlePageChange(offset + pageSize);\n });\n\n const lastBtn = this._createPaginationBtn('last_page', 'Last page', !hasNext, () => {\n handlePageChange(Math.floor((effectiveTotal - 1) / pageSize) * pageSize);\n });\n\n // Jump to row\n const jumpInput = document.createElement('input');\n jumpInput.type = 'number';\n jumpInput.className = 'twm-pagination-input';\n jumpInput.style.cssText = 'width:54px; padding:1px 4px; border:1px solid #444; background:#2a2a2a; color:#ccc; font-size:10px;';\n jumpInput.min = '1';\n jumpInput.max = String(effectiveTotal);\n jumpInput.placeholder = 'Row #';\n\n const jumpBtn = this._createPaginationBtn(null, 'Go to row', false, () => {\n const target = Number(jumpInput.value);\n if (Number.isFinite(target) && target >= 1) {\n if (isServerSide && onJumpToRow) {\n onJumpToRow(target - 1);\n } else if (isServerSide) {\n // Default: calculate page offset for the target row\n const newOffset = Math.floor((target - 1) / pageSize) * pageSize;\n handlePageChange(newOffset);\n } else {\n this.goToRow(target - 1);\n }\n }\n }, 'Go');\n\n el.appendChild(info);\n el.appendChild(spacer);\n el.appendChild(firstBtn);\n el.appendChild(prevBtn);\n el.appendChild(pageInfo);\n el.appendChild(nextBtn);\n el.appendChild(lastBtn);\n el.appendChild(jumpInput);\n el.appendChild(jumpBtn);\n\n // CSV export button (opt-in). Re-uses the existing downloadCSV\n // method which already handles the host save dialog + browser\n // fallback.\n if (this.config.showExportButton) {\n const exportBtn = this._createPaginationBtn(\n 'download', 'Download visible rows as CSV', false,\n () => this.downloadCSV('data.csv'));\n el.appendChild(exportBtn);\n }\n\n return el;\n }\n\n _createPaginationBtn(icon, tooltip, disabled, onClick, textLabel = null) {\n const btn = document.createElement('button');\n btn.type = 'button';\n btn.className = 'hoverbutton twm-pagination-btn twm-has-tooltip';\n btn.setAttribute('data-tooltip', tooltip);\n btn.disabled = disabled;\n btn.style.cssText = 'padding:1px 3px; background:transparent; border:1px solid #444; color:#aaa; cursor:pointer; display:flex; align-items:center; justify-content:center; line-height:1;';\n\n if (disabled) {\n btn.style.opacity = '0.4';\n btn.style.cursor = 'not-allowed';\n }\n\n if (icon) {\n const iconEl = document.createElement('span');\n iconEl.className = 'material-symbols-outlined';\n iconEl.style.fontSize = '14px';\n iconEl.textContent = icon;\n btn.appendChild(iconEl);\n } else if (textLabel) {\n btn.textContent = textLabel;\n btn.style.fontSize = '10px';\n btn.style.padding = '1px 6px';\n }\n\n btn.addEventListener('click', onClick);\n return btn;\n }\n\n _createTable() {\n const { headers, rows, pageSize, sortable, filterable, showRowNumbers, readonly, getHeaderIcon, onPageChange, offset: configOffset } = this.config;\n const { selected, sortColumn, sortAscending } = this._state;\n\n // Server-side pagination: rows already represent current page, use config offset for row numbering\n // Client-side pagination: use processed (filtered+sorted) rows, then slice for current page\n const isServerSide = typeof onPageChange === 'function';\n const processedRows = isServerSide ? rows : this._getProcessedRows();\n const offset = isServerSide ? (configOffset || 0) : this._state.offset;\n const pageRows = isServerSide ? processedRows : processedRows.slice(offset, offset + pageSize);\n\n const table = document.createElement('table');\n table.className = readonly ? 'twm-preview-table twm-preview-table--readonly' : 'twm-preview-table';\n table.tabIndex = 0;\n\n // Header\n const thead = document.createElement('thead');\n const headerRow = document.createElement('tr');\n\n if (showRowNumbers) {\n const th = document.createElement('th');\n th.className = 'num';\n th.textContent = '#';\n headerRow.appendChild(th);\n }\n\n headers.forEach((header, colIdx) => {\n const th = document.createElement('th');\n th.className = this._columnTypes[colIdx] || 'text';\n\n if (sortable) {\n th.classList.add('sortable');\n th.style.cursor = 'pointer';\n }\n\n // Header icon\n if (getHeaderIcon) {\n const iconInfo = getHeaderIcon(header, colIdx);\n if (iconInfo) {\n const iconSpan = document.createElement('span');\n iconSpan.className = 'material-symbols-outlined twm-header-icon twm-has-tooltip';\n iconSpan.setAttribute('data-tooltip', iconInfo.title || '');\n iconSpan.style.cssText = 'font-size:16px; vertical-align:middle; margin-right:4px; opacity:0.7;';\n iconSpan.textContent = iconInfo.icon;\n th.appendChild(iconSpan);\n }\n }\n\n th.appendChild(document.createTextNode(header));\n\n // Sort indicator\n if (sortable) {\n const sortIcon = document.createElement('span');\n sortIcon.className = 'material-symbols-outlined twm-sort-icon';\n sortIcon.style.cssText = 'font-size:14px; margin-left:4px; opacity:0.5;';\n if (sortColumn === colIdx) {\n sortIcon.textContent = sortAscending ? 'arrow_upward' : 'arrow_downward';\n sortIcon.style.opacity = '1';\n } else {\n sortIcon.textContent = 'unfold_more';\n }\n th.appendChild(sortIcon);\n\n th.addEventListener('click', () => this.sortBy(colIdx));\n }\n\n th.title = header;\n headerRow.appendChild(th);\n });\n\n thead.appendChild(headerRow);\n\n // Filter row (below header)\n if (filterable) {\n const filterRow = this._createFilterRow(headers);\n thead.appendChild(filterRow);\n }\n\n table.appendChild(thead);\n\n // Body\n const tbody = document.createElement('tbody');\n pageRows.forEach((row, localIdx) => {\n const processedIdx = offset + localIdx;\n // Map back to original config.rows index for selection tracking\n const globalIdx = isServerSide\n ? (configOffset || 0) + localIdx\n : (this._processedIndexMap?.[processedIdx] ?? processedIdx);\n const tr = document.createElement('tr');\n tr.__rowIndex = globalIdx;\n tr.className = 'data-preview-row';\n\n if (selected.has(globalIdx)) {\n tr.classList.add('selected');\n }\n\n this._fillRowCells(tr, row, globalIdx, showRowNumbers);\n\n // Row-level click + right-click hooks (P2). Bound after\n // cells so per-cell handlers run first.\n if (this.config.onRowClick) {\n tr.addEventListener('click', (ev) => {\n this.config.onRowClick(globalIdx, row, ev);\n });\n }\n if (this.config.onRowContextMenu) {\n tr.addEventListener('contextmenu', (ev) => {\n this.config.onRowContextMenu(globalIdx, row, ev);\n });\n }\n\n tbody.appendChild(tr);\n });\n\n table.appendChild(tbody);\n this._tbodyEl = tbody;\n\n return table;\n }\n\n /** Build (or rebuild) one row's cells in place.\n *\n * Extracted from the body loop so that `updateRow` and the initial\n * render share ONE cell-building path. Two paths would drift, and the\n * drift would show as a cell that renders differently after a live\n * update than it did on load. */\n _fillRowCells(tr, row, globalIdx, showRowNumbers) {\n tr.replaceChildren();\n\n if (showRowNumbers) {\n const td = document.createElement('td');\n td.className = 'num';\n td.textContent = String(globalIdx + 1);\n tr.appendChild(td);\n }\n\n for (let colIdx = 0; colIdx < row.length; colIdx++) {\n const td = document.createElement('td');\n td.className = this._columnTypes[colIdx] || 'text';\n\n // Use custom cell renderer if provided\n const value = row[colIdx];\n if (this.config.renderCell) {\n const handled = this.config.renderCell(td, value, colIdx, globalIdx, row);\n if (!handled) {\n td.textContent = this._formatValue(value, colIdx);\n }\n } else {\n td.textContent = this._formatValue(value, colIdx);\n }\n\n // Cell-level right-click hook (P2). Fires before the row-level\n // hook and the built-in context menu \u2014 the caller can\n // ev.preventDefault() to suppress the default copy menu on this\n // cell only.\n if (this.config.onCellContextMenu) {\n const cellColIdx = colIdx;\n td.addEventListener('contextmenu', (ev) => {\n this.config.onCellContextMenu(\n cellColIdx, globalIdx, value, td, ev);\n });\n }\n\n tr.appendChild(td);\n }\n }\n\n /** Re-render ONE row in place, preserving everything around it.\n *\n * `render()` rebuilds the entire `<tbody>`, which takes the scroll\n * position, any open editor, the keyboard focus and the measured column\n * widths with it. That is fine for a sort or a page change and wrong for\n * a single-cell commit or a live update arriving over a socket \u2014 the\n * common case in an editable grid, where a full rebuild once per keystroke\n * is both visible and destructive.\n *\n * What survives, by construction:\n * - scroll position, because the tbody is not replaced;\n * - the separately-rendered thead/tbody column widths, because the\n * explicit widths live on the header cells and on the FIRST body row,\n * and all three of the properties `_setCellWidth` writes are re-applied\n * here when that first row is the one being replaced;\n * - selection, because the `selected` class is recomputed from the\n * selection set rather than carried on the old element;\n * - keyboard focus, because the focused element's position is recorded\n * before the replace and restored after.\n *\n * @param {number} index row index as tracked by `tr.__rowIndex`\n * @param {any[]} row the new cell values\n * @returns {boolean} false when the row is not currently rendered\n * (it is on another page, or outside the render\n * window) \u2014 which is NOT an error: the caller has\n * nothing to update on screen.\n */\n updateRow(index, row) {\n const tbody = this._tbodyEl;\n if (!tbody) return false;\n\n let tr = null;\n for (const candidate of tbody.children) {\n if (candidate.__rowIndex === index) { tr = candidate; break; }\n }\n if (!tr) return false;\n\n // Keep the caller's data in step, so a later full render agrees with\n // what is on screen. Server-side paging means config.rows may hold only\n // the current page; the index map is what resolves that.\n if (Array.isArray(this.config.rows) && this.config.rows[index]) {\n this.config.rows[index] = row;\n }\n\n // Record focus BEFORE the replace: `replaceChildren` detaches the\n // focused cell and the browser moves focus to <body>.\n const active = document.activeElement;\n let focusedCol = -1;\n if (active && tr.contains(active)) {\n focusedCol = Array.prototype.indexOf.call(tr.children, active.closest('td'));\n }\n\n // ALL THREE PROPERTIES, not just `width`. `_setCellWidth` writes\n // `width` together with `min-width: 0` and `max-width: none`, precisely\n // to escape the CSS floors on these cells (base.css pins the first\n // column at 120px/min 100px and gives every other column a 80px min).\n // Carrying the width across the rebuild and leaving the other two behind\n // let those floors back in \u2014 so a column measured narrower than its\n // floor SNAPPED WIDER the moment one of its cells was repainted, and\n // under `table-layout: fixed` this row is the column track, so the whole\n // column moved. In an editable grid that is one visible jump per saved\n // cell, which is what it looked like to the person doing the saving.\n const isFirstRow = tr === tbody.firstElementChild;\n const widths = isFirstRow\n ? Array.prototype.map.call(tr.children, (td) => ({\n width: td.style.width,\n minWidth: td.style.minWidth,\n maxWidth: td.style.maxWidth,\n }))\n : null;\n\n const showRowNumbers = this.config.showRowNumbers !== false\n && tr.firstElementChild?.classList.contains('num');\n this._fillRowCells(tr, row, index, showRowNumbers);\n\n // `_syncHeaderWidths` derives column widths from the FIRST body row.\n // Under a recycling virtualiser that row changes on every scroll \u2014 and\n // here it changes on every update \u2014 so the explicit widths have to be\n // carried across the rebuild or the columns jitter.\n if (widths) {\n widths.forEach((saved, i) => {\n const cell = tr.children[i];\n if (!saved.width || !cell) return;\n cell.style.width = saved.width;\n cell.style.minWidth = saved.minWidth;\n cell.style.maxWidth = saved.maxWidth;\n });\n }\n\n tr.classList.toggle('selected', this._state?.selected?.has(index) === true);\n\n if (focusedCol >= 0 && tr.children[focusedCol]) {\n tr.children[focusedCol].focus?.();\n }\n return true;\n }\n\n /** Sync the (separate) header table's column widths to the body\n * table's measured widths. Without this, the two tables compute\n * widths independently and the columns drift apart. Locks both\n * tables to `table-layout: fixed` and writes explicit width onto\n * each header cell of every header row (header + filter row). */\n /**\n * Measure every column's NATURAL content width, in one transient reflow.\n *\n * Extracted from `_syncHeaderWidths` so that auto-size can ask the same\n * question the fit pass asks, and get the same answer. Two measurement\n * passes would drift, and the drift would show as a double-click that\n * sized a column differently from the render that follows it.\n *\n * The pass ignores the CSS caps (the 150px-pinned first column, the 80px\n * min on the rest) and the filter-row inputs: `twm-dt-measuring` flips both\n * tables to `table-layout:auto; width:max-content` with those caps off (via\n * `!important`) for a single reflow, then reverts before paint \u2014 it is\n * never visible. Clearing inline widths first stops the last sync's forced\n * widths from constraining the measure.\n *\n * @returns {number[]|null} width per DOM column index, or null when there\n * is nothing laid out to measure.\n */\n _measureNaturalWidths() {\n const headerTable = this._headerTableEl;\n const bodyTable = this._tableEl;\n if (!headerTable || !bodyTable) return null;\n const firstRow = bodyTable.querySelector('tbody > tr');\n if (!firstRow) return null;\n const bodyCells = firstRow.children;\n if (!bodyCells.length) return null;\n\n headerTable.querySelectorAll('thead > tr').forEach((tr) => {\n for (const th of tr.children) this._clearCellWidth(th);\n });\n for (const td of bodyCells) this._clearCellWidth(td);\n headerTable.style.width = '';\n bodyTable.style.width = '';\n headerTable.classList.add('twm-dt-measuring');\n bodyTable.classList.add('twm-dt-measuring');\n // Force layout flush so measurements are current.\n // eslint-disable-next-line no-unused-expressions\n bodyTable.offsetWidth;\n\n // Natural width per column = the wider of its header label and its\n // body content. `max-content` already spans every rendered body\n // row, so the body cell of the first row reports the whole column.\n const labelRow = headerTable.querySelector('thead > tr');\n const cols = bodyCells.length;\n const natural = new Array(cols);\n // \u2500\u2500 AND CSS `zoom` IS DIVIDED BACK OUT \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\n //\n // `getBoundingClientRect()` reports CLIENT pixels, so under a `zoom`\n // anywhere above this table every width read here comes back multiplied\n // by that zoom \u2014 while `_setCellWidth` writes a plain `width` in the\n // cell's OWN pixels, which the same zoom then multiplies again. The two\n // halves of one measure-and-apply loop would be in different units:\n // measured at 200% a column is pinned twice as wide as its text needs,\n // and at 50% it is pinned half as wide and every value ellipsises. The\n // fit pass has the same split, because its `avail` is `clientWidth`,\n // which is NOT zoom-adjusted.\n //\n // `currentCSSZoom` is the effective zoom on this element \u2014 1 when\n // nothing above it zooms, and `undefined` in an engine that predates\n // the property \u2014 so this is exactly a no-op for every consumer that\n // does not zoom, which is all of them but the Tables grid.\n const zoom = bodyTable.currentCSSZoom || 1;\n for (let i = 0; i < cols; i++) {\n const body = bodyCells[i].getBoundingClientRect().width / zoom;\n const head = labelRow && labelRow.children[i]\n ? labelRow.children[i].getBoundingClientRect().width / zoom\n : 0;\n natural[i] = Math.max(body, head);\n }\n\n headerTable.classList.remove('twm-dt-measuring');\n bodyTable.classList.remove('twm-dt-measuring');\n return natural;\n }\n\n /**\n * Fit one column to its widest visible value and pin it there.\n *\n * The gesture is a double-click on the column's resize grip, which is where\n * every spreadsheet has put it \u2014 and the grip is this component's, which is\n * why the behaviour is too. A consumer that wanted this had no hook to hang\n * it on: `_installColumnResizers` bound `mousedown` and a `click` that only\n * suppressed the sort, and the measurement, the pin, the table-width\n * invariant and the write-through to `stateStore` are all private here.\n *\n * @param {number} domIdx column index INCLUDING the row-number column when\n * `showRowNumbers` is on \u2014 the same index space as `_colWidths`.\n * @param {{maxWidth?: number}} [opts] ceiling; defaults to AUTOSIZE_MAX_PX.\n * @returns {boolean} whether it had a layout to measure.\n */\n autoSizeColumn(domIdx, opts = {}) {\n const natural = this._measureNaturalWidths();\n if (!natural || domIdx < 0 || domIdx >= natural.length) return false;\n this._colWidths[domIdx] = this._autoWidth(natural[domIdx], opts);\n this._colWidthsSig = this._colSig();\n this._savePersisted();\n this._syncHeaderWidths();\n return true;\n }\n\n /**\n * The same for every column at once.\n *\n * It REPLACES existing drag overrides rather than sizing around them: \"fit\n * every column to its content\" that quietly excepted the three columns you\n * had dragged would be a button whose result depends on history nobody can\n * see.\n *\n * The result may well be wider than the container \u2014 forty columns of real\n * content usually are \u2014 and that is the intended answer, not a failure:\n * `_syncHeaderWidths` honours overrides verbatim, sizes both tables to their\n * total and the body wrap scrolls sideways with the header following it.\n * Squeezing them to fit is what the automatic fit pass does on every render\n * already, so a button that did that would be a button that does nothing.\n */\n autoSizeColumns(opts = {}) {\n const natural = this._measureNaturalWidths();\n if (!natural) return false;\n this._colWidths = {};\n for (let i = 0; i < natural.length; i++) {\n this._colWidths[i] = this._autoWidth(natural[i], opts);\n }\n this._colWidthsSig = this._colSig();\n this._savePersisted();\n this._syncHeaderWidths();\n return true;\n }\n\n /** One measured width, floored at the drag-resize minimum and capped, with\n * the same sub-pixel pad `_fitColumnWidths` adds against ellipsis. */\n _autoWidth(natural, opts = {}) {\n const max = opts.maxWidth ?? AUTOSIZE_MAX_PX;\n return Math.min(max, Math.max(40, Math.ceil((natural || 0) + 2)));\n }\n\n /**\n * Does every one of the `n` DOM columns already carry an override taken\n * against the column set that is on screen right now?\n *\n * The signature half is not belt-and-braces. `render()` drops `_colWidths`\n * when `_colSig` changes, but `_syncHeaderWidths` is also reached straight\n * from the ResizeObserver, which never goes through `render()` \u2014 so a set\n * of overrides measured against the PREVIOUS headers can still be sitting\n * in `_colWidths` when this is asked. Answering \"pinned\" then would skip\n * the measure and hand `_fitColumnWidths` widths keyed to columns that are\n * no longer there, each one landing on its neighbour.\n *\n * `== null` rather than a falsy test, to match `_fitColumnWidths`' own\n * `overrides[i] != null`: a legitimately-stored 0 must be read the same way\n * in both places or the two disagree about which columns are flexible.\n */\n _allColumnsPinned(n) {\n if (!n || this._colWidthsSig !== this._colSig()) return false;\n for (let i = 0; i < n; i++) {\n if (this._colWidths[i] == null) return false;\n }\n return true;\n }\n\n /** Sync the (separate) header table's column widths to the body\n * table's measured widths. Without this, the two tables compute\n * widths independently and the columns drift apart. Locks both\n * tables to `table-layout: fixed` and writes explicit width onto\n * each header cell of every header row (header + filter row). */\n _syncHeaderWidths() {\n const headerTable = this._headerTableEl;\n const bodyTable = this._tableEl;\n if (!headerTable || !bodyTable) return;\n const firstRow = bodyTable.querySelector('tbody > tr');\n if (!firstRow) return;\n const bodyCells = firstRow.children;\n if (!bodyCells.length) return;\n\n const headerRows = headerTable.querySelectorAll('thead > tr');\n // DO NOT MEASURE WHAT NOTHING WILL READ.\n //\n // `_measureNaturalWidths` flips BOTH tables to\n // `table-layout:auto; width:max-content` with the CSS caps lifted, for\n // a full synchronous reflow (`.twm-dt-measuring`, css/base.css). This\n // method is the ResizeObserver's callback, so that reflow fires once\n // per animation frame for the whole of a splitter drag \u2014 and an\n // embedder that pages a thousand rows at a time across twenty columns\n // re-lays-out ~20,000 cells per frame for it.\n //\n // When every column is pinned, `_fitColumnWidths` reads `natural[i]`\n // for no `i` at all: each column takes its override verbatim, and the\n // only thing left that the array supplies is `n`, which is its length.\n // So zeroes of the right length are not an approximation of the\n // measurement, they are indistinguishable from it.\n const natural = this._allColumnsPinned(bodyCells.length)\n ? new Array(bodyCells.length).fill(0)\n : this._measureNaturalWidths();\n if (!natural) return;\n\n // \u2500\u2500 Fit pass: turn natural widths into final widths that respect\n // the available space, favour the first column, and cap runaways.\n // User-dragged columns (`_colWidths`) are honored as-is inside.\n const wrap = this._tableWrapEl;\n const headerWrap = this._headerWrapEl;\n const avail = wrap ? wrap.clientWidth : 0;\n const firstIdx = this.config.showRowNumbers && bodyCells.length > 1 ? 1 : 0;\n const widths = this._fitColumnWidths(natural, avail, {\n firstIdx,\n overrides: this._colWidths,\n fit: this.config.columnFit,\n });\n const total = widths.reduce((a, b) => a + b, 0);\n\n // Apply measured widths to every header row at the matching\n // column index AND the body's first row, so both tables compute\n // the SAME column track. `_setCellWidth` also clears any CSS\n // min/max-width (e.g. the 150px-pinned first \"time\" column) so\n // the explicit width is actually honored.\n headerRows.forEach((tr) => {\n for (let i = 0; i < tr.children.length && i < widths.length; i++) {\n this._setCellWidth(tr.children[i], widths[i]);\n }\n });\n for (let i = 0; i < bodyCells.length && i < widths.length; i++) {\n this._setCellWidth(bodyCells[i], widths[i]);\n }\n\n // Lock both tables so the widths stick even when content changes.\n headerTable.style.tableLayout = 'fixed';\n bodyTable.style.tableLayout = 'fixed';\n\n // Size both tables to the explicit column TOTAL (not the CSS\n // `width: 100%`) so a widened column GROWS the table and the\n // body wrap scrolls horizontally, instead of squeezing into a\n // fixed budget and stealing from its neighbours. When the\n // columns fit and the user hasn't dragged, stay at 100% to fill\n // the container exactly with no phantom scrollbar.\n const hasOverride = Object.keys(this._colWidths).length > 0;\n if (hasOverride || total > avail + 1) {\n headerTable.style.width = `${total}px`;\n bodyTable.style.width = `${total}px`;\n } else {\n headerTable.style.width = '';\n bodyTable.style.width = '';\n }\n\n // Scrollbar gutter: when the body shows a vertical scrollbar, its\n // content is narrower than the wrap by `scrollbarW`. The header\n // wrap has no scrollbar, so pad it on the right to match.\n //\n // C29b. AND THE SAME NUMBER IS PUBLISHED AS A CUSTOM PROPERTY, because\n // padding does not help the one thing C29 was for. A `position: sticky`\n // cell pins to its scroll container's SCROLLPORT, and the scrollport of\n // a box with a classic scrollbar excludes that scrollbar while padding\n // is inside it \u2014 so `right: 0` in the body pins `sbw` px to the LEFT of\n // `right: 0` in the header, and a pinned trailing column would sit\n // visibly out of line with its own heading. There is nothing a\n // stylesheet can measure this from: it is the platform's scrollbar\n // width, known here and nowhere else. Written on the WRAPPER rather\n // than either box so a consumer's rule can read it from whichever of\n // the two it is styling, and written on every sync because a scrollbar\n // appears and disappears with the row count.\n if (wrap && headerWrap) {\n const sbw = Math.max(0, wrap.offsetWidth - wrap.clientWidth);\n headerWrap.style.paddingRight = sbw ? `${sbw}px` : '';\n this._wrapperEl?.style?.setProperty('--twm-dt-gutter', `${sbw}px`);\n }\n\n // Keep the header aligned with the body's current horizontal\n // scroll (a resize can clamp scrollLeft).\n this._syncHeaderScroll();\n\n // Columns are now fixed-width: any cell whose text was clipped\n // gets a hover tooltip carrying the full value.\n this._updateCellTooltips();\n }\n\n /**\n * Convert measured natural content widths into final column widths.\n *\n * Goals (the \"intelligent\" sizing):\n * - every column wants its content width (+a hair), clamped to a\n * sane [floor, cap]; the FIRST content column gets a more generous\n * cap so it shows its full value;\n * - user-dragged columns (`overrides`) are pinned, never grown/shrunk;\n * - if everything fits, grow the flexible columns evenly to fill the\n * width (no dead gap on the right);\n * - if it doesn't fit, protect the first column and water-fill-shrink\n * the rest (trim the widest first) until it fits; only if even the\n * floors overflow do we give up and let the body scroll sideways.\n *\n * Under `fit: 'content'` the first and last of those goals invert: each\n * unpinned column asks for its own content width through the same\n * `_autoWidth` the grip double-click uses, and an overflow is the answer\n * rather than a problem \u2014 the caller wanted a table that scrolls sideways,\n * not one squeezed toward the floor. The grow-to-fill branch is shared by\n * both, because a table narrower than its container leaves a dead gap on\n * the right under either reading.\n *\n * @param {number[]} natural measured content width per column (px)\n * @param {number} avail usable width of the body wrap (px)\n * @param {{firstIdx?:number, overrides?:Object, fit?:'container'|'content'}} [opts]\n * @returns {number[]} final width per column (px)\n */\n _fitColumnWidths(natural, avail, opts = {}) {\n const FLOOR = 40; // matches the drag-resize minimum\n const CAP = 360; // general per-column ceiling\n const FIRST_CAP = 520; // the first column may run wider\n const PAD = 2; // sub-pixel safety against ellipsis\n\n const n = natural.length;\n const firstIdx = opts.firstIdx ?? 0;\n const overrides = opts.overrides || {};\n // Anything that is not the literal opt-in is the historical behaviour.\n // Read once, so an embedder that passes a typo gets the old layout\n // rather than half of each.\n const toContent = opts.fit === 'content';\n\n // Desired (pre-fit) width per column. Pinned columns take their\n // override verbatim and sit out the grow/shrink redistribution.\n const desired = new Array(n);\n const pinned = new Array(n).fill(false);\n for (let i = 0; i < n; i++) {\n if (overrides[i] != null) {\n desired[i] = Math.max(FLOOR, Math.round(overrides[i]));\n pinned[i] = true;\n continue;\n }\n if (toContent) {\n // THE SAME CALL THE GRIP DOUBLE-CLICK MAKES \u2014 `autoSizeColumn`\n // \u2192 `_autoWidth` \u2014 and deliberately not a second arithmetic\n // that happens to agree with it today. Two width formulas\n // drift, and the drift shows up as a column that jumps the\n // first time anyone double-clicks its grip.\n //\n // FIRST_CAP has nothing to say here. It exists to favour one\n // column while the others are being squeezed; under a content\n // fit nothing is being squeezed, so there is no column to\n // favour and every one of them is held to the same ceiling.\n desired[i] = this._autoWidth(natural[i]);\n continue;\n }\n const cap = i === firstIdx ? FIRST_CAP : CAP;\n desired[i] = Math.min(cap, Math.max(FLOOR, Math.ceil(natural[i] + PAD)));\n }\n\n const widths = desired.slice();\n const sum = widths.reduce((a, b) => a + b, 0);\n\n // Not laid out yet (or content already exactly fits): hand back the\n // desired widths; the caller decides fill vs horizontal scroll.\n if (avail <= 1) return widths;\n\n if (sum <= avail) {\n // Grow flexible columns evenly to fill the remaining space so\n // the table doesn't leave a dead gap on the right. When EVERY\n // column is pinned (e.g. after the user has dragged a column \u2014\n // the resize freezes all columns as overrides), fall back to\n // the last column so the table still spans the full container:\n // the width invariant \u2014 a table never renders narrower than\n // 100% of its wrap.\n const flex = [];\n for (let i = 0; i < n; i++) if (!pinned[i]) flex.push(i);\n const slack = avail - sum;\n if (slack > 0) {\n const targets = flex.length ? flex : [n - 1];\n const per = Math.floor(slack / targets.length);\n for (const i of targets) widths[i] += per;\n widths[targets[targets.length - 1]] += slack - per * targets.length;\n }\n return widths;\n }\n\n // OVERFLOW IS THE ANSWER UNDER A CONTENT FIT, not a case to recover\n // from. Everything below squeezes the unprotected columns toward the\n // 40px floor so that forty columns can be made to fit a pane \u2014 which is\n // precisely the outcome `columnFit: 'content'` opted out of. Handing\n // back the content widths lets the caller's `total > avail + 1` test\n // size both tables to the total, and the body wrap then scrolls\n // sideways with the header following it.\n if (toContent) return widths;\n\n // Overflow: protect the first column + pinned columns, water-fill\n // the rest down toward the floor.\n let protectedSum = 0;\n const shrinkable = [];\n for (let i = 0; i < n; i++) {\n if (pinned[i] || i === firstIdx) protectedSum += widths[i];\n else shrinkable.push(i);\n }\n const budget = avail - protectedSum;\n if (budget < shrinkable.length * FLOOR) {\n // Even at the floor we overflow \u2192 let the body scroll sideways.\n for (const i of shrinkable) widths[i] = FLOOR;\n return widths;\n }\n // Max-min fair allocation: the narrow columns keep their content,\n // the widest share the remaining budget equally.\n shrinkable.sort((a, b) => desired[a] - desired[b]);\n let remaining = budget;\n for (let k = 0; k < shrinkable.length; k++) {\n const colsLeft = shrinkable.length - k;\n const fair = Math.floor(remaining / colsLeft);\n const i = shrinkable[k];\n if (desired[i] <= fair) {\n widths[i] = desired[i];\n remaining -= desired[i];\n } else {\n const level = Math.max(FLOOR, fair);\n for (let j = k; j < shrinkable.length; j++) {\n widths[shrinkable[j]] = level;\n }\n // Dump any rounding remainder onto the widest column.\n const leftover = remaining - colsLeft * level;\n if (leftover > 0) widths[shrinkable[shrinkable.length - 1]] += leftover;\n break;\n }\n }\n return widths;\n }\n\n /** Set an explicit width on a table cell, clearing any CSS min/max\n * width constraint so the width is honored exactly. The first\n * (\"time\") column is pinned to 150px by `min/max-width` in CSS;\n * without this, dragging it does nothing and the slack leaks to the\n * other columns. */\n _setCellWidth(cell, w) {\n cell.style.width = `${w}px`;\n cell.style.minWidth = '0';\n cell.style.maxWidth = 'none';\n }\n\n /** Undo `_setCellWidth` so a re-measure sees the cell's natural,\n * CSS-constrained width again. */\n _clearCellWidth(cell) {\n cell.style.width = '';\n cell.style.minWidth = '';\n cell.style.maxWidth = '';\n }\n\n /** Wire the body wrap's horizontal scroll to the header. The header\n * sits in an overflow:hidden wrap, so it can't scroll sideways on\n * its own \u2014 `_syncHeaderScroll` scrolls it programmatically to the\n * body's `scrollLeft`. Re-installed each render against the freshly-built\n * wrap. */\n _installHeaderScrollSync() {\n const wrap = this._tableWrapEl;\n if (!wrap) return;\n if (this._onBodyScroll && this._scrollSyncEl) {\n this._scrollSyncEl.removeEventListener('scroll', this._onBodyScroll);\n }\n this._onBodyScroll = () => this._syncHeaderScroll();\n this._scrollSyncEl = wrap;\n wrap.addEventListener('scroll', this._onBodyScroll, { passive: true });\n this._syncHeaderScroll();\n }\n\n /**\n * Scroll the header wrap to match the body's horizontal scroll so the\n * columns stay aligned when the table overflows sideways.\n *\n * \u2550\u2550 C29. A TRANSFORM IS WHAT MAKES A STICKY COLUMN IMPOSSIBLE \u2550\u2550\u2550\u2550\u2550\u2550\u2550\n *\n * This wrote `headerTable.style.transform = translateX(-scrollLeft)`. It\n * aligns the two tables perfectly and it forecloses `position: sticky`\n * entirely, because the two halves of the table then pin against different\n * things: a sticky cell in the BODY pins to the body wrap's scrollport,\n * while its header counterpart is moved by a transform inside a box that\n * never scrolls at all. Scroll sideways and the pinned body column stands\n * still while its header slides away with everything else \u2014 so a table\n * with a trailing verb column (the row-actions column Tables needs pinned\n * to the right edge) can have a sticky body or an aligned header, never\n * both. A transform also establishes a containing block for fixed/sticky\n * descendants, which breaks the header cell independently of the offset.\n *\n * AN `overflow: hidden` BOX IS STILL A SCROLL CONTAINER. It has no\n * scrollbar and no user affordance, and `scrollLeft` moves it exactly like\n * any other. Scrolling the wrap rather than transforming its child gives\n * the header a real scrollport at the same offset as the body's, which is\n * the one arrangement in which a sticky cell on each side pins to the same\n * place. Identical for ordinary content: same pixels, no transform, no new\n * containing block.\n *\n * THE CLAMP IS ALREADY PAID FOR. A scroll container clamps `scrollLeft` to\n * `scrollWidth - clientWidth`, and the body wrap carries a vertical\n * scrollbar the header wrap does not \u2014 so the header would clamp short by\n * the scrollbar width and desync at the far right. `_syncHeaderWidths`\n * already pads the header wrap by exactly that gutter (`paddingRight`,\n * :1905), and end padding counts toward `scrollWidth`, so the two maxima\n * coincide. The residual below is the honest belt for the day some engine\n * disagrees about that: it is zero in the ordinary case, so the transform\n * is not set and sticky keeps working, and it is the difference rather\n * than the whole offset if it is ever not.\n */\n _syncHeaderScroll() {\n const wrap = this._tableWrapEl;\n const headerTable = this._headerTableEl;\n if (!wrap || !headerTable) return;\n const x = wrap.scrollLeft;\n const headerWrap = this._headerWrapEl;\n if (!headerWrap) {\n // No wrap to scroll \u2014 a consumer that built the header some other\n // way still gets the behaviour it always had.\n headerTable.style.transform = x ? `translateX(${-x}px)` : '';\n return;\n }\n headerWrap.scrollLeft = x;\n const residual = x - headerWrap.scrollLeft;\n headerTable.style.transform = residual ? `translateX(${-residual}px)` : '';\n }\n\n /** Drag-to-resize: hang a thin grab handle off the right edge of\n * every header cell. Dragging it writes a per-column width override\n * (keyed by DOM index) that `_syncHeaderWidths` then honors. */\n _installColumnResizers() {\n const headerTable = this._headerTableEl;\n if (!headerTable) return;\n const headRow = headerTable.querySelector('thead > tr');\n if (!headRow) return;\n [...headRow.children].forEach((th, domIdx) => {\n if (th.querySelector('.twm-dt-col-resizer')) return;\n th.classList.add('twm-dt-col');\n const grip = document.createElement('div');\n grip.className = 'twm-dt-col-resizer';\n grip.addEventListener('mousedown',\n (ev) => this._beginColResize(ev, domIdx));\n // Keep a resize gesture from registering as a sort click.\n grip.addEventListener('click', (ev) => ev.stopPropagation());\n // Double-click the grip: fit the column to its content. The gesture\n // every spreadsheet has, on the affordance it has always been on.\n // Stopped as well as prevented, or a consumer that opens a column\n // menu from the header (Tables does) opens it on the way past.\n grip.addEventListener('dblclick', (ev) => {\n ev.preventDefault();\n ev.stopPropagation();\n this.autoSizeColumn(domIdx);\n });\n th.appendChild(grip);\n });\n }\n\n _beginColResize(ev, domIdx) {\n ev.preventDefault();\n ev.stopPropagation();\n const headerTable = this._headerTableEl;\n const bodyTable = this._tableEl;\n const headRow = headerTable && headerTable.querySelector('thead > tr');\n if (!headRow) return;\n\n // Freeze EVERY column at its current width on BOTH tables and\n // lock fixed layout up front, so the drag moves only the grabbed\n // column and a neighbour can never absorb it. Widths come from\n // the header row (the column source of truth); the body's first\n // row is pinned to match so the two tables stay in lock-step.\n const startWidths = [...headRow.children].map(\n (c) => c.getBoundingClientRect().width);\n headerTable.style.tableLayout = 'fixed';\n if (bodyTable) bodyTable.style.tableLayout = 'fixed';\n startWidths.forEach((w, i) => this._pinColumnWidth(i, w));\n this._applyTableWidth();\n\n const startX = ev.clientX;\n const MIN = 40;\n document.body.classList.add('twm-dt-col-resizing');\n const onMove = (mv) => {\n const w = Math.max(\n MIN, Math.round(startWidths[domIdx] + (mv.clientX - startX)));\n this._pinColumnWidth(domIdx, w);\n // Pass the dragged column so the fill invariant reclaims any\n // freed width into a DIFFERENT (flexible/last) column, never\n // shrinking the table below the container.\n this._applyTableWidth(domIdx);\n this._syncHeaderScroll();\n };\n const onUp = () => {\n document.removeEventListener('mousemove', onMove);\n document.removeEventListener('mouseup', onUp);\n document.body.classList.remove('twm-dt-col-resizing');\n this._updateCellTooltips();\n this._savePersisted();\n };\n document.addEventListener('mousemove', onMove);\n document.addEventListener('mouseup', onUp);\n }\n\n /** Pin one column to an explicit width across BOTH tables (every\n * header row + the body's first row) and record it as a user\n * override so `_syncHeaderWidths` honors it on later renders. The\n * single place that writes a column width during a drag / fill. */\n _pinColumnWidth(i, w) {\n const headerTable = this._headerTableEl;\n const bodyTable = this._tableEl;\n if (!headerTable) return;\n this._colWidths[i] = w;\n headerTable.querySelectorAll('thead > tr').forEach((tr) => {\n if (tr.children[i]) this._setCellWidth(tr.children[i], w);\n });\n const bodyRow = bodyTable && bodyTable.querySelector('tbody > tr');\n if (bodyRow && bodyRow.children[i]) this._setCellWidth(bodyRow.children[i], w);\n }\n\n /** Size both tables so a widened column grows the table (\u2192 horizontal\n * scroll) rather than stealing from its neighbours \u2014 while enforcing\n * the TABLE WIDTH INVARIANT: the table is never narrower than its\n * container. Any width freed by dragging a column in stretches a\n * flexible column (the last one, stepping off the column being\n * dragged) so the table always spans \u2265100% of the wrap.\n *\n * @param {number|null} dragIdx column the user is actively dragging,\n * so the fill lands on a DIFFERENT column and doesn't fight the\n * drag. Null (non-drag callers) lets the last column flex. */\n _applyTableWidth(dragIdx = null) {\n const headerTable = this._headerTableEl;\n const bodyTable = this._tableEl;\n const headRow = headerTable && headerTable.querySelector('thead > tr');\n if (!headRow) return;\n const cells = [...headRow.children];\n const cols = cells.length;\n if (cols === 0) return;\n\n const FLOOR = 40; // matches the drag-resize minimum\n const widthOf = (th) => {\n const px = parseFloat(th.style.width);\n return Number.isFinite(px) ? px : th.getBoundingClientRect().width;\n };\n const cur = cells.map(widthOf);\n\n // Fill invariant: pick a flexible column and stretch it to soak up\n // any freed width so the summed total is never below the container.\n const wrap = this._tableWrapEl;\n const avail = wrap ? wrap.clientWidth : 0;\n let flexIdx = cols - 1;\n if (dragIdx != null && flexIdx === dragIdx) flexIdx -= 1; // step off the dragged col\n if (avail > 1 && flexIdx >= 0 && flexIdx !== dragIdx) {\n let rest = 0;\n for (let i = 0; i < cols; i++) if (i !== flexIdx) rest += cur[i];\n const fill = Math.max(FLOOR, Math.round(avail - rest));\n if (Math.round(fill) !== Math.round(cur[flexIdx])) {\n this._pinColumnWidth(flexIdx, fill);\n cur[flexIdx] = fill;\n }\n }\n\n let total = 0;\n for (const w of cur) total += w;\n total = Math.ceil(total);\n headerTable.style.width = `${total}px`;\n if (bodyTable) bodyTable.style.width = `${total}px`;\n }\n\n /** Add a native `title` tooltip to any body cell whose text is\n * clipped by its column width; remove ours once it fits again.\n * Leaves caller-supplied titles (e.g. from renderCell) untouched. */\n _updateCellTooltips() {\n const bodyTable = this._tableEl;\n if (!bodyTable) return;\n bodyTable.querySelectorAll('tbody td').forEach((td) => {\n const clipped = td.scrollWidth > td.clientWidth + 1;\n if (clipped) {\n if (!td.title) td.title = td.textContent;\n } else if (td.title && td.title === td.textContent) {\n td.removeAttribute('title');\n }\n });\n }\n\n _installInteractions() {\n if (!this._tbodyEl || !this._tableEl) return;\n\n const { selectable, copyable } = this.config;\n const tbody = this._tbodyEl;\n const table = this._tableEl;\n\n if (selectable) {\n const handleRowClick = (event) => {\n const rowEl = event.target.closest('tr');\n if (!rowEl || rowEl.__rowIndex === undefined) return;\n\n const idx = rowEl.__rowIndex;\n const selected = this._state.selected;\n\n if (event.shiftKey && this._state.anchorIndex != null) {\n const start = Math.min(this._state.anchorIndex, idx);\n const end = Math.max(this._state.anchorIndex, idx);\n selected.clear();\n for (let i = start; i <= end; i++) selected.add(i);\n } else if (event.metaKey || event.ctrlKey) {\n if (selected.has(idx)) selected.delete(idx);\n else selected.add(idx);\n this._state.anchorIndex = idx;\n } else {\n selected.clear();\n selected.add(idx);\n this._state.anchorIndex = idx;\n }\n\n this._updateRowSelection();\n this._notifySelectionChange();\n try { table.focus({ preventScroll: true }); } catch (_) {}\n };\n\n tbody.addEventListener('click', handleRowClick);\n this._disposers.push(() => tbody.removeEventListener('click', handleRowClick));\n }\n\n if (copyable) {\n const handleContextMenu = (event) => {\n const rowEl = event.target.closest('tr');\n if (!rowEl) {\n this._hideContextMenu();\n return;\n }\n\n event.preventDefault();\n event.stopPropagation();\n\n const idx = rowEl.__rowIndex;\n if (idx !== undefined && !this._state.selected.has(idx)) {\n this._state.selected.clear();\n this._state.selected.add(idx);\n this._state.anchorIndex = idx;\n this._updateRowSelection();\n this._notifySelectionChange();\n }\n\n try { table.focus({ preventScroll: true }); } catch (_) {}\n setTimeout(() => this._showContextMenu(event.clientX, event.clientY), 0);\n };\n\n tbody.addEventListener('contextmenu', handleContextMenu);\n this._disposers.push(() => tbody.removeEventListener('contextmenu', handleContextMenu));\n\n const handleKeyDown = (event) => {\n const ctrlLike = event.ctrlKey || event.metaKey;\n if (ctrlLike && !event.altKey) {\n const key = String(event.key || '').toLowerCase();\n if (key === 'a' && selectable) {\n event.preventDefault();\n this._state.selected.clear();\n // Select only visible (filtered) rows via index map\n const indexMap = this._processedIndexMap;\n if (indexMap) {\n for (const originalIdx of indexMap) {\n this._state.selected.add(originalIdx);\n }\n } else {\n for (let i = 0; i < this.config.rows.length; i++) {\n this._state.selected.add(i);\n }\n }\n this._state.anchorIndex = this.config.rows.length - 1;\n this._updateRowSelection();\n this._notifySelectionChange();\n } else if (key === 'c') {\n event.preventDefault();\n this.copyToClipboard(event.shiftKey ? 'csv' : 'tsv');\n }\n } else if (event.key === 'Escape') {\n if (this._state.selected.size) {\n this.clearSelection();\n }\n this._hideContextMenu();\n }\n };\n\n table.addEventListener('keydown', handleKeyDown);\n this._disposers.push(() => table.removeEventListener('keydown', handleKeyDown));\n }\n }\n\n _updateRowSelection() {\n if (!this._tbodyEl) return;\n this._tbodyEl.querySelectorAll('tr').forEach(tr => {\n const idx = tr.__rowIndex;\n if (idx !== undefined) {\n tr.classList.toggle('selected', this._state.selected.has(idx));\n }\n });\n }\n\n _notifySelectionChange() {\n this.config.onSelectionChange?.(this.getSelection());\n }\n\n _ensureContextMenu() {\n if (this._contextMenuEl) return this._contextMenuEl;\n\n const menu = document.createElement('div');\n menu.className = 'twm-context-menu data-context-menu';\n menu.style.display = 'none';\n menu.style.position = 'fixed';\n menu.style.zIndex = '10001';\n menu.innerHTML = `\n <div class=\"twm-context-menu-item\" data-action=\"copy-tsv\">\n <span class=\"material-symbols-outlined\">content_copy</span>\n <span class=\"label\">Copy Row(s)</span>\n </div>\n <div class=\"twm-context-menu-item\" data-action=\"copy-csv\">\n <span class=\"material-symbols-outlined\">table</span>\n <span class=\"label\">Copy as CSV</span>\n </div>\n `;\n document.body.appendChild(menu);\n\n menu.addEventListener('click', (event) => {\n const item = event.target.closest('.twm-context-menu-item');\n if (!item || item.classList.contains('disabled')) return;\n const action = item.getAttribute('data-action');\n if (action === 'copy-tsv') this.copyToClipboard('tsv');\n else if (action === 'copy-csv') this.copyToClipboard('csv');\n event.stopPropagation();\n event.preventDefault();\n }, { capture: true });\n\n menu.addEventListener('contextmenu', (e) => {\n e.preventDefault();\n e.stopPropagation();\n });\n\n const hideOnGlobal = (event) => {\n if (event?.target && menu.contains(event.target)) return;\n this._hideContextMenu();\n };\n const hideOnEscape = (event) => {\n if (event.key === 'Escape') this._hideContextMenu();\n };\n const hideOnResize = () => this._hideContextMenu();\n\n document.addEventListener('click', hideOnGlobal, true);\n document.addEventListener('scroll', hideOnGlobal, true);\n window.addEventListener('resize', hideOnResize);\n document.addEventListener('keydown', hideOnEscape);\n\n this._contextMenuGlobals.push(() => document.removeEventListener('click', hideOnGlobal, true));\n this._contextMenuGlobals.push(() => document.removeEventListener('scroll', hideOnGlobal, true));\n this._contextMenuGlobals.push(() => document.removeEventListener('keydown', hideOnEscape));\n this._contextMenuGlobals.push(() => window.removeEventListener('resize', hideOnResize));\n\n this._contextMenuEl = menu;\n return menu;\n }\n\n _hideContextMenu() {\n if (this._contextMenuEl) {\n this._contextMenuEl.style.display = 'none';\n }\n }\n\n _showContextMenu(clientX, clientY) {\n const menu = this._ensureContextMenu();\n const hasSelection = this._state.selected.size > 0;\n\n menu.querySelectorAll('.twm-context-menu-item').forEach(item => {\n item.classList.toggle('disabled', !hasSelection);\n item.style.pointerEvents = hasSelection ? '' : 'none';\n });\n\n menu.style.display = 'block';\n const rect = menu.getBoundingClientRect();\n let left = clientX;\n let top = clientY;\n\n if (left + rect.width > window.innerWidth) {\n left = window.innerWidth - rect.width - 8;\n }\n if (top + rect.height > window.innerHeight) {\n top = window.innerHeight - rect.height - 8;\n }\n\n menu.style.left = `${left}px`;\n menu.style.top = `${top}px`;\n }\n\n _teardownContextMenu() {\n this._contextMenuGlobals.forEach(dispose => {\n try { dispose?.(); } catch (_) {}\n });\n this._contextMenuGlobals = [];\n if (this._contextMenuEl?.parentNode) {\n this._contextMenuEl.parentNode.removeChild(this._contextMenuEl);\n }\n this._contextMenuEl = null;\n }\n\n _formatValue(value, colIndex) {\n if (this.config.formatValue) {\n return this.config.formatValue(value, colIndex);\n }\n if (value === undefined || value === null) return '-';\n if (typeof value === 'number') {\n if (!Number.isFinite(value)) return '-';\n return Number(value.toFixed(4)).toString();\n }\n return String(value);\n }\n\n _csvEscape(value) {\n if (value == null) return '';\n const str = String(value);\n if (/[\",\\n]/.test(str)) {\n return `\"${str.replace(/\"/g, '\"\"')}\"`;\n }\n return str;\n }\n\n _fallbackCopy(text) {\n try {\n const textarea = document.createElement('textarea');\n textarea.value = text;\n textarea.setAttribute('readonly', '');\n textarea.style.position = 'absolute';\n textarea.style.left = '-9999px';\n document.body.appendChild(textarea);\n textarea.select();\n const ok = document.execCommand('copy');\n document.body.removeChild(textarea);\n return ok;\n } catch (_) {\n return false;\n }\n }\n\n _notify(title, message, type = 'info') {\n this.config.services?.eventBus?.emit?.('toast:show', { title, message, type });\n }\n}\n\nexport default DataTable;\n"],
|
|
5
|
+
"mappings": "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",
|
|
6
|
+
"names": []
|
|
7
|
+
}
|