@toolbox-web/grid 0.0.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/all.d.ts +3518 -0
- package/all.js +3762 -0
- package/all.js.map +1 -0
- package/index.d.ts +2367 -0
- package/index.js +3105 -0
- package/index.js.map +1 -0
- package/lib/plugins/clipboard/index.js +365 -0
- package/lib/plugins/clipboard/index.js.map +1 -0
- package/lib/plugins/column-virtualization/index.js +255 -0
- package/lib/plugins/column-virtualization/index.js.map +1 -0
- package/lib/plugins/context-menu/index.js +341 -0
- package/lib/plugins/context-menu/index.js.map +1 -0
- package/lib/plugins/export/index.js +305 -0
- package/lib/plugins/export/index.js.map +1 -0
- package/lib/plugins/filtering/index.js +759 -0
- package/lib/plugins/filtering/index.js.map +1 -0
- package/lib/plugins/grouping-columns/index.js +283 -0
- package/lib/plugins/grouping-columns/index.js.map +1 -0
- package/lib/plugins/grouping-rows/index.js +494 -0
- package/lib/plugins/grouping-rows/index.js.map +1 -0
- package/lib/plugins/master-detail/index.js +303 -0
- package/lib/plugins/master-detail/index.js.map +1 -0
- package/lib/plugins/multi-sort/index.js +270 -0
- package/lib/plugins/multi-sort/index.js.map +1 -0
- package/lib/plugins/pinned-columns/index.js +221 -0
- package/lib/plugins/pinned-columns/index.js.map +1 -0
- package/lib/plugins/pinned-rows/index.js +459 -0
- package/lib/plugins/pinned-rows/index.js.map +1 -0
- package/lib/plugins/pivot/index.js +326 -0
- package/lib/plugins/pivot/index.js.map +1 -0
- package/lib/plugins/reorder/index.js +260 -0
- package/lib/plugins/reorder/index.js.map +1 -0
- package/lib/plugins/selection/index.js +426 -0
- package/lib/plugins/selection/index.js.map +1 -0
- package/lib/plugins/server-side/index.js +241 -0
- package/lib/plugins/server-side/index.js.map +1 -0
- package/lib/plugins/tree/index.js +383 -0
- package/lib/plugins/tree/index.js.map +1 -0
- package/lib/plugins/undo-redo/index.js +289 -0
- package/lib/plugins/undo-redo/index.js.map +1 -0
- package/lib/plugins/visibility/index.js +430 -0
- package/lib/plugins/visibility/index.js.map +1 -0
- package/package.json +53 -0
- package/themes/dg-theme-contrast.css +43 -0
- package/themes/dg-theme-large.css +54 -0
- package/themes/dg-theme-standard.css +19 -0
- package/themes/dg-theme-vibrant.css +16 -0
- package/umd/grid.all.umd.js +660 -0
- package/umd/grid.all.umd.js.map +1 -0
- package/umd/grid.umd.js +105 -0
- package/umd/grid.umd.js.map +1 -0
- package/umd/plugins/clipboard.umd.js +9 -0
- package/umd/plugins/clipboard.umd.js.map +1 -0
- package/umd/plugins/column-virtualization.umd.js +2 -0
- package/umd/plugins/column-virtualization.umd.js.map +1 -0
- package/umd/plugins/context-menu.umd.js +53 -0
- package/umd/plugins/context-menu.umd.js.map +1 -0
- package/umd/plugins/export.umd.js +14 -0
- package/umd/plugins/export.umd.js.map +1 -0
- package/umd/plugins/filtering.umd.js +175 -0
- package/umd/plugins/filtering.umd.js.map +1 -0
- package/umd/plugins/grouping-columns.umd.js +29 -0
- package/umd/plugins/grouping-columns.umd.js.map +1 -0
- package/umd/plugins/grouping-rows.umd.js +40 -0
- package/umd/plugins/grouping-rows.umd.js.map +1 -0
- package/umd/plugins/master-detail.umd.js +27 -0
- package/umd/plugins/master-detail.umd.js.map +1 -0
- package/umd/plugins/multi-sort.umd.js +26 -0
- package/umd/plugins/multi-sort.umd.js.map +1 -0
- package/umd/plugins/pinned-columns.umd.js +2 -0
- package/umd/plugins/pinned-columns.umd.js.map +1 -0
- package/umd/plugins/pinned-rows.umd.js +73 -0
- package/umd/plugins/pinned-rows.umd.js.map +1 -0
- package/umd/plugins/pivot.umd.js +8 -0
- package/umd/plugins/pivot.umd.js.map +1 -0
- package/umd/plugins/reorder.umd.js +31 -0
- package/umd/plugins/reorder.umd.js.map +1 -0
- package/umd/plugins/selection.umd.js +34 -0
- package/umd/plugins/selection.umd.js.map +1 -0
- package/umd/plugins/server-side.umd.js +2 -0
- package/umd/plugins/server-side.umd.js.map +1 -0
- package/umd/plugins/tree.umd.js +11 -0
- package/umd/plugins/tree.umd.js.map +1 -0
- package/umd/plugins/undo-redo.umd.js +2 -0
- package/umd/plugins/undo-redo.umd.js.map +1 -0
- package/umd/plugins/visibility.umd.js +94 -0
- package/umd/plugins/visibility.umd.js.map +1 -0
package/all.js.map
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"all.js","sources":["../../../libs/grid/src/lib/plugins/clipboard/copy.ts","../../../libs/grid/src/lib/plugins/clipboard/paste.ts","../../../libs/grid/src/lib/plugins/clipboard/ClipboardPlugin.ts","../../../libs/grid/src/lib/plugins/column-virtualization/column-virtualization.ts","../../../libs/grid/src/lib/plugins/column-virtualization/ColumnVirtualizationPlugin.ts","../../../libs/grid/src/lib/plugins/context-menu/menu.ts","../../../libs/grid/src/lib/plugins/context-menu/ContextMenuPlugin.ts","../../../libs/grid/src/lib/plugins/export/csv.ts","../../../libs/grid/src/lib/plugins/export/excel.ts","../../../libs/grid/src/lib/plugins/export/ExportPlugin.ts","../../../libs/grid/src/lib/core/internal/virtualization.ts","../../../libs/grid/src/lib/plugins/filtering/filter-model.ts","../../../libs/grid/src/lib/plugins/filtering/FilteringPlugin.ts","../../../libs/grid/src/lib/plugins/grouping-columns/grouping-columns.ts","../../../libs/grid/src/lib/plugins/grouping-columns/GroupingColumnsPlugin.ts","../../../libs/grid/src/lib/plugins/grouping-rows/grouping-rows.ts","../../../libs/grid/src/lib/plugins/grouping-rows/GroupingRowsPlugin.ts","../../../libs/grid/src/lib/plugins/master-detail/master-detail.ts","../../../libs/grid/src/lib/plugins/master-detail/MasterDetailPlugin.ts","../../../libs/grid/src/lib/plugins/multi-sort/multi-sort.ts","../../../libs/grid/src/lib/plugins/multi-sort/MultiSortPlugin.ts","../../../libs/grid/src/lib/plugins/pinned-columns/pinned-columns.ts","../../../libs/grid/src/lib/plugins/pinned-columns/PinnedColumnsPlugin.ts","../../../libs/grid/src/lib/plugins/pinned-rows/pinned-rows.ts","../../../libs/grid/src/lib/plugins/pinned-rows/PinnedRowsPlugin.ts","../../../libs/grid/src/lib/plugins/pivot/pivot-model.ts","../../../libs/grid/src/lib/plugins/pivot/pivot-engine.ts","../../../libs/grid/src/lib/plugins/pivot/PivotPlugin.ts","../../../libs/grid/src/lib/plugins/reorder/column-drag.ts","../../../libs/grid/src/lib/plugins/reorder/ReorderPlugin.ts","../../../libs/grid/src/lib/plugins/server-side/datasource.ts","../../../libs/grid/src/lib/plugins/server-side/ServerSidePlugin.ts","../../../libs/grid/src/lib/plugins/undo-redo/history.ts","../../../libs/grid/src/lib/plugins/undo-redo/UndoRedoPlugin.ts","../../../libs/grid/src/lib/plugins/visibility/VisibilityPlugin.ts"],"sourcesContent":["/**\n * Clipboard Copy Logic\n *\n * Pure functions for copying grid data to clipboard.\n */\n\nimport type { ColumnConfig } from '../../core/types';\nimport type { ClipboardConfig } from './types';\n\n/** Parameters for building clipboard text */\nexport interface CopyParams {\n /** All grid rows */\n rows: unknown[];\n /** Column configurations */\n columns: ColumnConfig[];\n /** Selected row indices */\n selectedIndices: Set<number> | number[];\n /** Clipboard configuration */\n config: ClipboardConfig;\n}\n\n/**\n * Format a cell value for clipboard output.\n *\n * Uses custom processCell if provided, otherwise applies default formatting:\n * - null/undefined → empty string\n * - Date → ISO string\n * - Object → JSON string\n * - Other → String conversion with optional quoting\n *\n * @param value - The cell value to format\n * @param field - The field name\n * @param row - The full row object\n * @param config - Clipboard configuration\n * @returns Formatted string value\n */\nexport function formatCellValue(value: unknown, field: string, row: unknown, config: ClipboardConfig): string {\n if (config.processCell) {\n return config.processCell(value, field, row);\n }\n\n if (value == null) return '';\n if (value instanceof Date) return value.toISOString();\n if (typeof value === 'object') return JSON.stringify(value);\n\n const str = String(value);\n const delimiter = config.delimiter ?? '\\t';\n const newline = config.newline ?? '\\n';\n\n // Quote if contains delimiter, newline, or quotes (or if quoteStrings is enabled)\n if (config.quoteStrings || str.includes(delimiter) || str.includes(newline) || str.includes('\"')) {\n return `\"${str.replace(/\"/g, '\"\"')}\"`;\n }\n\n return str;\n}\n\n/**\n * Build clipboard text from selected rows and columns.\n *\n * @param params - Copy parameters including rows, columns, selection, and config\n * @returns Tab-separated (or custom delimiter) text ready for clipboard\n */\nexport function buildClipboardText(params: CopyParams): string {\n const { rows, columns, selectedIndices, config } = params;\n const delimiter = config.delimiter ?? '\\t';\n const newline = config.newline ?? '\\n';\n\n // Filter to visible columns (not hidden, not internal __ prefixed)\n const visibleColumns = columns.filter((c) => !c.hidden && !c.field.startsWith('__'));\n\n const lines: string[] = [];\n\n // Add header row if configured\n if (config.includeHeaders) {\n const headerCells = visibleColumns.map((c) => {\n const header = c.header || c.field;\n // Quote headers if they contain special characters\n if (header.includes(delimiter) || header.includes(newline) || header.includes('\"')) {\n return `\"${header.replace(/\"/g, '\"\"')}\"`;\n }\n return header;\n });\n lines.push(headerCells.join(delimiter));\n }\n\n // Convert indices to sorted array\n const indices = selectedIndices instanceof Set ? [...selectedIndices] : selectedIndices;\n const sortedIndices = [...indices].sort((a, b) => a - b);\n\n // Build data rows\n for (const idx of sortedIndices) {\n const row = rows[idx];\n if (!row) continue;\n\n const cells = visibleColumns.map((col) =>\n formatCellValue((row as Record<string, unknown>)[col.field], col.field, row, config)\n );\n lines.push(cells.join(delimiter));\n }\n\n return lines.join(newline);\n}\n\n/**\n * Copy text to the system clipboard.\n *\n * Uses the modern Clipboard API when available, with fallback\n * to execCommand for older browsers.\n *\n * @param text - The text to copy\n * @returns Promise resolving to true if successful, false otherwise\n */\nexport async function copyToClipboard(text: string): Promise<boolean> {\n try {\n await navigator.clipboard.writeText(text);\n return true;\n } catch {\n // Fallback for older browsers or when Clipboard API is not available\n const textarea = document.createElement('textarea');\n textarea.value = text;\n textarea.style.position = 'fixed';\n textarea.style.opacity = '0';\n textarea.style.pointerEvents = 'none';\n document.body.appendChild(textarea);\n textarea.select();\n const success = document.execCommand('copy');\n document.body.removeChild(textarea);\n return success;\n }\n}\n","/**\n * Clipboard Paste Logic\n *\n * Pure functions for reading and parsing clipboard data.\n */\n\nimport type { ClipboardConfig } from './types';\n\n/**\n * Parse clipboard text into a 2D array of cell values.\n *\n * Handles:\n * - Quoted values (with escaped double quotes \"\")\n * - Multi-line quoted values (newlines within quotes are preserved)\n * - Custom delimiters and newlines\n * - Empty lines (filtered out only if they contain no data)\n *\n * @param text - Raw clipboard text\n * @param config - Clipboard configuration\n * @returns 2D array where each sub-array is a row of cell values\n */\nexport function parseClipboardText(text: string, config: ClipboardConfig): string[][] {\n const delimiter = config.delimiter ?? '\\t';\n const newline = config.newline ?? '\\n';\n\n // Handle Windows CRLF line endings\n const normalizedText = text.replace(/\\r\\n/g, '\\n').replace(/\\r/g, '\\n');\n\n // Parse the entire text handling quoted fields that may span multiple lines\n const rows: string[][] = [];\n let currentRow: string[] = [];\n let currentCell = '';\n let inQuotes = false;\n\n for (let i = 0; i < normalizedText.length; i++) {\n const char = normalizedText[i];\n\n if (char === '\"' && !inQuotes) {\n // Start of quoted field\n inQuotes = true;\n } else if (char === '\"' && inQuotes) {\n // Check for escaped quote (\"\")\n if (normalizedText[i + 1] === '\"') {\n currentCell += '\"';\n i++; // Skip the second quote\n } else {\n // End of quoted field\n inQuotes = false;\n }\n } else if (char === delimiter && !inQuotes) {\n // Field separator\n currentRow.push(currentCell);\n currentCell = '';\n } else if (char === newline && !inQuotes) {\n // Row separator (only if not inside quotes)\n currentRow.push(currentCell);\n currentCell = '';\n // Only add non-empty rows (at least one non-empty cell or multiple cells)\n if (currentRow.length > 1 || currentRow.some((c) => c.trim() !== '')) {\n rows.push(currentRow);\n }\n currentRow = [];\n } else {\n currentCell += char;\n }\n }\n\n // Handle the last cell and row\n currentRow.push(currentCell);\n if (currentRow.length > 1 || currentRow.some((c) => c.trim() !== '')) {\n rows.push(currentRow);\n }\n\n return rows;\n}\n\n/**\n * Read text from the system clipboard.\n *\n * Uses the modern Clipboard API. Returns empty string if\n * the API is not available or permission is denied.\n *\n * @returns Promise resolving to clipboard text or empty string\n */\nexport async function readFromClipboard(): Promise<string> {\n try {\n return await navigator.clipboard.readText();\n } catch {\n // Permission denied or API not available\n return '';\n }\n}\n","/**\n * Clipboard Plugin (Class-based)\n *\n * Provides copy/paste functionality for tbw-grid.\n * Supports Ctrl+C/Cmd+C for copying and Ctrl+V/Cmd+V for pasting.\n *\n * **With Selection plugin:** Copy selected rows as a range\n * - includeHeaders: true → adds header row at top\n * - includeHeaders: false → data rows only\n *\n * **Without Selection plugin:** Copy focused cell only\n * - includeHeaders: true → \"Header: value\" format\n * - includeHeaders: false → value only\n */\n\nimport { BaseGridPlugin } from '../../core/plugin/base-plugin';\nimport { buildClipboardText, copyToClipboard } from './copy';\nimport { parseClipboardText, readFromClipboard } from './paste';\nimport type { ClipboardConfig, CopyDetail, PasteDetail } from './types';\n\n/**\n * Clipboard Plugin for tbw-grid\n *\n * @example\n * ```ts\n * new ClipboardPlugin({ includeHeaders: true })\n * ```\n */\nexport class ClipboardPlugin extends BaseGridPlugin<ClipboardConfig> {\n readonly name = 'clipboard';\n override readonly version = '1.0.0';\n\n protected override get defaultConfig(): Partial<ClipboardConfig> {\n return {\n enabled: true,\n includeHeaders: false,\n delimiter: '\\t',\n newline: '\\n',\n quoteStrings: false,\n };\n }\n\n // ===== Internal State =====\n /** The last copied text (for reference/debugging) */\n private lastCopied: { text: string; timestamp: number } | null = null;\n\n // ===== Lifecycle =====\n\n override detach(): void {\n this.lastCopied = null;\n }\n\n // ===== Event Handlers =====\n\n override onKeyDown(event: KeyboardEvent): boolean {\n if (this.config.enabled === false) return false;\n\n const isCopy = (event.ctrlKey || event.metaKey) && event.key === 'c';\n const isPaste = (event.ctrlKey || event.metaKey) && event.key === 'v';\n\n if (isCopy) {\n this.#handleCopy(event.target as HTMLElement);\n return true; // Prevent default browser behavior\n }\n\n if (isPaste) {\n this.#handlePaste();\n return true; // Prevent default browser behavior\n }\n\n return false;\n }\n\n // ===== Private Methods =====\n\n /**\n * Handle copy operation\n */\n #handleCopy(target: HTMLElement): void {\n // Try to get selection from selection plugin (if available)\n // Use dynamic import to avoid circular dependency issues\n const selectionPlugin = this.#getSelectionPlugin();\n\n // Check for different selection types\n const selectedRows = selectionPlugin?.getSelectedRows() ?? [];\n const hasRowSelection = selectedRows.length > 0;\n const ranges = selectionPlugin?.getRanges() ?? [];\n const hasRangeSelection = ranges.length > 0;\n const hasCellSelection = selectionPlugin?.getSelectedCell() != null;\n\n let text: string;\n let rowCount: number;\n let columnCount: number;\n\n if (hasRowSelection && selectionPlugin) {\n // Row selection mode - copy full rows\n text = buildClipboardText({\n rows: this.rows as unknown[],\n columns: [...this.columns],\n selectedIndices: selectedRows,\n config: this.config,\n });\n rowCount = selectedRows.length;\n columnCount = this.columns.filter((c) => !c.hidden && !c.field.startsWith('__')).length;\n } else if (hasRangeSelection && selectionPlugin) {\n // Range selection mode - copy rectangular range (use last range as active)\n const range = ranges[ranges.length - 1];\n const result = this.#buildRangeText({\n startRow: range.from.row,\n startCol: range.from.col,\n endRow: range.to.row,\n endCol: range.to.col,\n });\n text = result.text;\n rowCount = result.rowCount;\n columnCount = result.columnCount;\n } else if (hasCellSelection && selectionPlugin) {\n // Cell selection mode - copy single cell\n const cell = selectionPlugin.getSelectedCell()!;\n const result = this.#buildCellText(cell.row, cell.col);\n if (!result) return;\n text = result.text;\n rowCount = 1;\n columnCount = 1;\n } else {\n // Fallback: try to find focused cell from DOM\n const result = this.#buildSingleCellText(target);\n if (!result) return;\n text = result.text;\n rowCount = 1;\n columnCount = 1;\n }\n\n copyToClipboard(text).then(() => {\n this.lastCopied = { text, timestamp: Date.now() };\n this.emit<CopyDetail>('copy', { text, rowCount, columnCount });\n });\n }\n\n /**\n * Handle paste operation\n */\n #handlePaste(): void {\n readFromClipboard().then((text) => {\n if (!text) return;\n const parsed = parseClipboardText(text, this.config);\n this.emit<PasteDetail>('paste', { rows: parsed, text });\n });\n }\n\n /**\n * Get the selection plugin instance if available.\n */\n #getSelectionPlugin(): SelectionPluginInterface | undefined {\n // Dynamically get the SelectionPlugin class to avoid import order issues\n try {\n // Use getPlugin with the class - this requires the class to be imported\n // For now, we'll use a duck-typing approach via the grid's plugin registry\n const grid = this.grid as any;\n if (grid?._plugins) {\n for (const plugin of grid._plugins) {\n if (plugin.name === 'selection') {\n return plugin as SelectionPluginInterface;\n }\n }\n }\n } catch {\n // Selection plugin not available\n }\n return undefined;\n }\n\n /**\n * Build text for a single cell by row/col index.\n */\n #buildCellText(rowIndex: number, colIndex: number): { text: string } | null {\n const rowData = this.rows[rowIndex] as Record<string, unknown> | undefined;\n if (!rowData) return null;\n\n const column = this.columns[colIndex];\n if (!column) return null;\n\n const value = rowData[column.field];\n const header = column.header || column.field;\n\n let text: string;\n if (this.config.includeHeaders) {\n const formattedValue = value == null ? '' : String(value);\n text = `${header}: ${formattedValue}`;\n } else {\n text = value == null ? '' : String(value);\n }\n\n return { text };\n }\n\n /**\n * Build text for a rectangular range of cells.\n */\n #buildRangeText(range: { startRow: number; startCol: number; endRow: number; endCol: number }): {\n text: string;\n rowCount: number;\n columnCount: number;\n } {\n const { startRow, startCol, endRow, endCol } = range;\n const minRow = Math.min(startRow, endRow);\n const maxRow = Math.max(startRow, endRow);\n const minCol = Math.min(startCol, endCol);\n const maxCol = Math.max(startCol, endCol);\n\n const delimiter = this.config.delimiter ?? '\\t';\n const newline = this.config.newline ?? '\\n';\n const lines: string[] = [];\n\n // Get columns in the range\n const rangeColumns = this.columns.slice(minCol, maxCol + 1);\n\n // Add header row if configured\n if (this.config.includeHeaders) {\n const headerCells = rangeColumns.map((c) => c.header || c.field);\n lines.push(headerCells.join(delimiter));\n }\n\n // Add data rows\n for (let r = minRow; r <= maxRow; r++) {\n const rowData = this.rows[r] as Record<string, unknown> | undefined;\n if (!rowData) continue;\n\n const cells = rangeColumns.map((col) => {\n const value = rowData[col.field];\n if (value == null) return '';\n if (value instanceof Date) return value.toISOString();\n return String(value);\n });\n lines.push(cells.join(delimiter));\n }\n\n return {\n text: lines.join(newline),\n rowCount: maxRow - minRow + 1,\n columnCount: maxCol - minCol + 1,\n };\n }\n\n /**\n * Build text for a single focused cell from DOM.\n * Used when selection plugin is not available or no rows are selected.\n */\n #buildSingleCellText(target: HTMLElement): { text: string; field: string; value: unknown } | null {\n // Find the cell element - cells use data-field-cache for the field name\n const cell = target.closest('[data-field-cache]') as HTMLElement | null;\n if (!cell) return null;\n\n const field = cell.dataset.fieldCache;\n if (!field) return null;\n\n // Get row index from data-row attribute on the cell\n const rowIndexStr = cell.dataset.row;\n if (!rowIndexStr) return null;\n\n const rowIndex = parseInt(rowIndexStr, 10);\n if (isNaN(rowIndex)) return null;\n\n const rowData = this.rows[rowIndex] as Record<string, unknown> | undefined;\n if (!rowData) return null;\n\n const value = rowData[field];\n const column = this.columns.find((c) => c.field === field);\n const header = column?.header || field;\n\n // Format the text based on includeHeaders config\n let text: string;\n if (this.config.includeHeaders) {\n // Format: \"{header}: {value}\"\n const formattedValue = value == null ? '' : String(value);\n text = `${header}: ${formattedValue}`;\n } else {\n // Just the value\n text = value == null ? '' : String(value);\n }\n\n return { text, field, value };\n }\n\n // ===== Public API =====\n\n /**\n * Copy currently selected rows to clipboard.\n * @returns The copied text\n */\n async copy(): Promise<string> {\n const selectionPlugin = this.#getSelectionPlugin();\n const indices = selectionPlugin?.getSelectedRows() ?? [];\n\n const text = buildClipboardText({\n rows: this.rows as unknown[],\n columns: [...this.columns],\n selectedIndices: indices,\n config: this.config,\n });\n\n await copyToClipboard(text);\n this.lastCopied = { text, timestamp: Date.now() };\n return text;\n }\n\n /**\n * Copy specific rows by index to clipboard.\n * @param indices - Array of row indices to copy\n * @returns The copied text\n */\n async copyRows(indices: number[]): Promise<string> {\n const text = buildClipboardText({\n rows: this.rows as unknown[],\n columns: [...this.columns],\n selectedIndices: indices,\n config: this.config,\n });\n\n await copyToClipboard(text);\n this.lastCopied = { text, timestamp: Date.now() };\n return text;\n }\n\n /**\n * Read and parse clipboard content.\n * @returns Parsed 2D array of cell values, or null if clipboard is empty\n */\n async paste(): Promise<string[][] | null> {\n const text = await readFromClipboard();\n if (!text) return null;\n return parseClipboardText(text, this.config);\n }\n\n /**\n * Get the last copied text and timestamp.\n * @returns The last copied info or null\n */\n getLastCopied(): { text: string; timestamp: number } | null {\n return this.lastCopied;\n }\n}\n\n// ===== Internal Types =====\n\n/**\n * Interface for SelectionPlugin methods we need.\n * This avoids circular imports while providing type safety.\n */\ninterface SelectionPluginInterface {\n name: string;\n /** Get selected row indices (row mode) */\n getSelectedRows(): number[];\n /** Get all selected cell ranges (range mode) */\n getRanges(): Array<{ from: { row: number; col: number }; to: { row: number; col: number } }>;\n /** Get selected cell (cell mode) */\n getSelectedCell(): { row: number; col: number } | null;\n}\n\n// Re-export types\nexport type { ClipboardConfig, CopyDetail, PasteDetail } from './types';\n","/**\n * Column Virtualization Core Logic\n *\n * Pure functions for horizontal column virtualization operations.\n */\n\nimport type { ColumnConfig } from '../../core/types';\nimport type { ColumnVirtualizationViewport } from './types';\n\n/** Default column width when not specified */\nconst DEFAULT_COLUMN_WIDTH = 100;\n\n/**\n * Parse a column width value to pixels.\n * Handles number (px) and string formats.\n *\n * @param width - The width value from column config\n * @returns Width in pixels\n */\nexport function parseColumnWidth(width: string | number | undefined): number {\n if (width === undefined || width === null) {\n return DEFAULT_COLUMN_WIDTH;\n }\n\n if (typeof width === 'number') {\n return width;\n }\n\n // Handle string values - extract numeric part\n const numeric = parseFloat(width);\n if (!isNaN(numeric)) {\n return numeric;\n }\n\n return DEFAULT_COLUMN_WIDTH;\n}\n\n/**\n * Get array of column widths in pixels.\n *\n * @param columns - Column configurations\n * @returns Array of widths in pixels\n */\nexport function getColumnWidths(columns: readonly ColumnConfig[]): number[] {\n return columns.map((col) => parseColumnWidth(col.width));\n}\n\n/**\n * Compute cumulative left offsets for each column.\n *\n * @param columns - Column configurations\n * @returns Array of left offsets in pixels\n */\nexport function computeColumnOffsets(columns: readonly ColumnConfig[]): number[] {\n const offsets: number[] = [];\n let offset = 0;\n\n for (const col of columns) {\n offsets.push(offset);\n offset += parseColumnWidth(col.width);\n }\n\n return offsets;\n}\n\n/**\n * Compute total width of all columns.\n *\n * @param columns - Column configurations\n * @returns Total width in pixels\n */\nexport function computeTotalWidth(columns: readonly ColumnConfig[]): number {\n return columns.reduce((sum, col) => sum + parseColumnWidth(col.width), 0);\n}\n\n/**\n * Find the visible column range based on scroll position.\n * Uses binary search for efficient lookup in large column sets.\n *\n * @param scrollLeft - Current horizontal scroll position\n * @param viewportWidth - Width of the visible viewport\n * @param columnOffsets - Array of column left offsets\n * @param columnWidths - Array of column widths\n * @param overscan - Number of extra columns to render on each side\n * @returns Viewport information with visible column indices\n */\nexport function getVisibleColumnRange(\n scrollLeft: number,\n viewportWidth: number,\n columnOffsets: number[],\n columnWidths: number[],\n overscan: number\n): ColumnVirtualizationViewport {\n const columnCount = columnOffsets.length;\n\n if (columnCount === 0) {\n return { startCol: 0, endCol: 0, visibleColumns: [] };\n }\n\n // Binary search for first visible column\n let startCol = binarySearchFirstVisible(scrollLeft, columnOffsets, columnWidths);\n startCol = Math.max(0, startCol - overscan);\n\n // Find last visible column (without overscan first)\n const rightEdge = scrollLeft + viewportWidth;\n let endCol = startCol;\n\n for (let i = startCol; i < columnCount; i++) {\n if (columnOffsets[i] >= rightEdge) {\n endCol = i - 1;\n break;\n }\n endCol = i;\n }\n\n // Apply overscan to end (only once)\n endCol = Math.min(columnCount - 1, endCol + overscan);\n\n // Build array of visible column indices\n const visibleColumns: number[] = [];\n for (let i = startCol; i <= endCol; i++) {\n visibleColumns.push(i);\n }\n\n return { startCol, endCol, visibleColumns };\n}\n\n/**\n * Binary search to find the first column that is visible.\n *\n * @param scrollLeft - Current scroll position\n * @param columnOffsets - Array of column offsets\n * @param columnWidths - Array of column widths\n * @returns Index of first visible column\n */\nfunction binarySearchFirstVisible(scrollLeft: number, columnOffsets: number[], columnWidths: number[]): number {\n let low = 0;\n let high = columnOffsets.length - 1;\n\n while (low < high) {\n const mid = Math.floor((low + high) / 2);\n const colRight = columnOffsets[mid] + columnWidths[mid];\n\n if (colRight <= scrollLeft) {\n low = mid + 1;\n } else {\n high = mid;\n }\n }\n\n return low;\n}\n\n/**\n * Determine if column virtualization should be active.\n *\n * @param columnCount - Number of columns\n * @param threshold - Column count threshold\n * @param autoEnable - Whether auto-enable is configured\n * @returns True if virtualization should be active\n */\nexport function shouldVirtualize(columnCount: number, threshold: number, autoEnable: boolean): boolean {\n if (!autoEnable) return false;\n return columnCount > threshold;\n}\n","/**\n * Column Virtualization Plugin (Class-based)\n *\n * Provides horizontal column virtualization for grids with many columns.\n * Significantly improves rendering performance when dealing with >30 columns.\n */\n\nimport { BaseGridPlugin, ScrollEvent } from '../../core/plugin/base-plugin';\nimport type { ColumnConfig } from '../../core/types';\nimport {\n computeColumnOffsets,\n computeTotalWidth,\n getColumnWidths,\n getVisibleColumnRange,\n shouldVirtualize,\n} from './column-virtualization';\nimport type { ColumnVirtualizationConfig } from './types';\n\n/**\n * Column Virtualization Plugin for tbw-grid\n *\n * @example\n * ```ts\n * new ColumnVirtualizationPlugin({ threshold: 30, overscan: 3 })\n * ```\n */\nexport class ColumnVirtualizationPlugin extends BaseGridPlugin<ColumnVirtualizationConfig> {\n readonly name = 'columnVirtualization';\n override readonly version = '1.0.0';\n\n protected override get defaultConfig(): Partial<ColumnVirtualizationConfig> {\n return {\n enabled: true,\n autoEnable: true,\n threshold: 30,\n overscan: 3,\n };\n }\n\n // ===== Internal State =====\n private isVirtualized = false;\n private startCol = 0;\n private endCol = 0;\n private scrollLeft = 0;\n private totalWidth = 0;\n private columnWidths: number[] = [];\n private columnOffsets: number[] = [];\n\n // ===== Lifecycle =====\n\n override attach(grid: import('../../core/plugin/base-plugin').GridElement): void {\n super.attach(grid);\n\n // Initialize state from current columns\n const columns = this.columns;\n this.columnWidths = getColumnWidths(columns);\n this.columnOffsets = computeColumnOffsets(columns);\n this.totalWidth = computeTotalWidth(columns);\n this.endCol = columns.length - 1;\n }\n\n override detach(): void {\n this.columnWidths = [];\n this.columnOffsets = [];\n this.isVirtualized = false;\n this.startCol = 0;\n this.endCol = 0;\n this.scrollLeft = 0;\n this.totalWidth = 0;\n }\n\n // ===== Hooks =====\n\n override processColumns(columns: readonly ColumnConfig[]): ColumnConfig[] {\n const isVirtualized =\n this.config.enabled &&\n shouldVirtualize(columns.length, this.config.threshold ?? 30, this.config.autoEnable ?? true);\n\n // Update state with current column metrics\n this.isVirtualized = isVirtualized ?? false;\n this.columnWidths = getColumnWidths(columns);\n this.columnOffsets = computeColumnOffsets(columns);\n this.totalWidth = computeTotalWidth(columns);\n\n if (!isVirtualized) {\n this.startCol = 0;\n this.endCol = columns.length - 1;\n return [...columns];\n }\n\n // Get viewport width from grid element\n const viewportWidth = (this.grid as unknown as HTMLElement).clientWidth || 800;\n const viewport = getVisibleColumnRange(\n this.scrollLeft,\n viewportWidth,\n this.columnOffsets,\n this.columnWidths,\n this.config.overscan ?? 3\n );\n\n this.startCol = viewport.startCol;\n this.endCol = viewport.endCol;\n\n // Return only visible columns\n return viewport.visibleColumns.map((i) => columns[i]);\n }\n\n override afterRender(): void {\n if (!this.isVirtualized) return;\n\n const shadowRoot = this.shadowRoot;\n if (!shadowRoot) return;\n\n // Apply left padding to offset scrolled-out columns\n const leftPadding = this.columnOffsets[this.startCol] ?? 0;\n\n const headerRow = shadowRoot.querySelector('.header-row');\n const bodyRows = shadowRoot.querySelectorAll('.data-grid-row');\n\n if (headerRow) {\n (headerRow as HTMLElement).style.paddingLeft = `${leftPadding}px`;\n }\n\n bodyRows.forEach((row) => {\n (row as HTMLElement).style.paddingLeft = `${leftPadding}px`;\n });\n\n // Set total width for horizontal scrolling on the rows container\n const rowsContainer = shadowRoot.querySelector('.rows-viewport .rows');\n if (rowsContainer) {\n (rowsContainer as HTMLElement).style.width = `${this.totalWidth}px`;\n }\n }\n\n override onScroll(event: ScrollEvent): void {\n if (!this.isVirtualized) return;\n\n // Check if horizontal scroll position changed significantly\n const scrollDelta = Math.abs(event.scrollLeft - this.scrollLeft);\n if (scrollDelta < 1) return;\n\n // Update scroll position\n this.scrollLeft = event.scrollLeft;\n\n // Recalculate visible columns and request re-render\n this.requestRender();\n }\n\n // ===== Public API =====\n\n /**\n * Check if column virtualization is currently active.\n */\n getIsVirtualized(): boolean {\n return this.isVirtualized;\n }\n\n /**\n * Get the current visible column range.\n */\n getVisibleColumnRange(): { start: number; end: number } {\n return { start: this.startCol, end: this.endCol };\n }\n\n /**\n * Scroll the grid to bring a specific column into view.\n * @param columnIndex - Index of the column to scroll to\n */\n scrollToColumn(columnIndex: number): void {\n const offset = this.columnOffsets[columnIndex] ?? 0;\n const gridEl = this.grid as unknown as HTMLElement;\n // Scroll the grid element itself (it's the scroll container)\n gridEl.scrollLeft = offset;\n }\n\n /**\n * Get the left offset for a specific column.\n * @param columnIndex - Index of the column\n */\n getColumnOffset(columnIndex: number): number {\n return this.columnOffsets[columnIndex] ?? 0;\n }\n\n /**\n * Get the total width of all columns.\n */\n getTotalWidth(): number {\n return this.totalWidth;\n }\n}\n","/**\n * Context Menu Rendering Logic\n *\n * Pure functions for building and positioning context menus.\n */\n\nimport type { ContextMenuItem, ContextMenuParams } from './types';\n\n/**\n * Build the visible menu items by resolving dynamic items and filtering hidden ones.\n *\n * @param items - Menu items configuration (array or factory function)\n * @param params - Context menu parameters for evaluating dynamic properties\n * @returns Filtered array of visible menu items\n */\nexport function buildMenuItems(\n items: ContextMenuItem[] | ((params: ContextMenuParams) => ContextMenuItem[]),\n params: ContextMenuParams\n): ContextMenuItem[] {\n const menuItems = typeof items === 'function' ? items(params) : items;\n\n return menuItems.filter((item) => {\n if (item.hidden === true) return false;\n if (typeof item.hidden === 'function' && item.hidden(params)) return false;\n return true;\n });\n}\n\n/**\n * Check if a menu item is disabled.\n *\n * @param item - The menu item to check\n * @param params - Context menu parameters for evaluating dynamic disabled state\n * @returns True if the item is disabled\n */\nexport function isItemDisabled(item: ContextMenuItem, params: ContextMenuParams): boolean {\n if (item.disabled === true) return true;\n if (typeof item.disabled === 'function') return item.disabled(params);\n return false;\n}\n\n/**\n * Create the menu DOM element from a list of menu items.\n *\n * @param items - Array of menu items to render\n * @param params - Context menu parameters for evaluating dynamic properties\n * @param onAction - Callback when a menu item action is triggered\n * @returns The created menu element\n */\nexport function createMenuElement(\n items: ContextMenuItem[],\n params: ContextMenuParams,\n onAction: (item: ContextMenuItem) => void\n): HTMLElement {\n const menu = document.createElement('div');\n menu.className = 'tbw-context-menu';\n menu.setAttribute('role', 'menu');\n\n for (const item of items) {\n if (item.separator) {\n const separator = document.createElement('div');\n separator.className = 'tbw-context-menu-separator';\n separator.setAttribute('role', 'separator');\n menu.appendChild(separator);\n continue;\n }\n\n const menuItem = document.createElement('div');\n menuItem.className = 'tbw-context-menu-item';\n if (item.cssClass) menuItem.classList.add(item.cssClass);\n menuItem.setAttribute('role', 'menuitem');\n menuItem.setAttribute('data-id', item.id);\n\n const disabled = isItemDisabled(item, params);\n if (disabled) {\n menuItem.classList.add('disabled');\n menuItem.setAttribute('aria-disabled', 'true');\n }\n\n if (item.icon) {\n const icon = document.createElement('span');\n icon.className = 'tbw-context-menu-icon';\n icon.innerHTML = item.icon;\n menuItem.appendChild(icon);\n }\n\n const label = document.createElement('span');\n label.className = 'tbw-context-menu-label';\n label.textContent = item.name;\n menuItem.appendChild(label);\n\n if (item.shortcut) {\n const shortcut = document.createElement('span');\n shortcut.className = 'tbw-context-menu-shortcut';\n shortcut.textContent = item.shortcut;\n menuItem.appendChild(shortcut);\n }\n\n if (item.subMenu?.length) {\n const arrow = document.createElement('span');\n arrow.className = 'tbw-context-menu-arrow';\n arrow.textContent = '▶';\n menuItem.appendChild(arrow);\n\n // Add submenu on hover\n menuItem.addEventListener('mouseenter', () => {\n const existingSubMenu = menuItem.querySelector('.tbw-context-menu');\n if (existingSubMenu) return;\n if (!item.subMenu) return;\n\n const subMenuItems = buildMenuItems(item.subMenu, params);\n const subMenu = createMenuElement(subMenuItems, params, onAction);\n subMenu.classList.add('tbw-context-submenu');\n subMenu.style.position = 'absolute';\n subMenu.style.left = '100%';\n subMenu.style.top = '0';\n menuItem.style.position = 'relative';\n menuItem.appendChild(subMenu);\n });\n\n menuItem.addEventListener('mouseleave', () => {\n const subMenu = menuItem.querySelector('.tbw-context-menu');\n if (subMenu) subMenu.remove();\n });\n }\n\n if (!disabled && item.action && !item.subMenu) {\n menuItem.addEventListener('click', (e) => {\n e.stopPropagation();\n onAction(item);\n });\n }\n\n menu.appendChild(menuItem);\n }\n\n return menu;\n}\n\n/**\n * Position the menu at the given viewport coordinates.\n * Menu is rendered in document.body with fixed positioning for top-layer behavior.\n *\n * @param menu - The menu element to position\n * @param x - Desired X coordinate (viewport)\n * @param y - Desired Y coordinate (viewport)\n */\nexport function positionMenu(menu: HTMLElement, x: number, y: number): void {\n // Use fixed positioning for top-layer behavior\n menu.style.position = 'fixed';\n menu.style.left = `${x}px`;\n menu.style.top = `${y}px`;\n menu.style.visibility = 'hidden';\n menu.style.zIndex = '10000';\n\n // Force layout to get dimensions\n const menuRect = menu.getBoundingClientRect();\n\n // Calculate visible area within viewport\n const viewportWidth = window.innerWidth;\n const viewportHeight = window.innerHeight;\n\n let left = x;\n let top = y;\n\n // Check if menu overflows right edge of viewport\n if (x + menuRect.width > viewportWidth) {\n left = x - menuRect.width;\n }\n // Check if menu overflows bottom edge of viewport\n if (y + menuRect.height > viewportHeight) {\n top = y - menuRect.height;\n }\n\n // Ensure we don't go negative\n left = Math.max(0, left);\n top = Math.max(0, top);\n\n menu.style.left = `${left}px`;\n menu.style.top = `${top}px`;\n menu.style.visibility = 'visible';\n}\n","/**\n * Context Menu Plugin (Class-based)\n *\n * Provides right-click context menu functionality for tbw-grid.\n * Supports custom menu items, submenus, icons, shortcuts, and dynamic item generation.\n */\n\nimport { BaseGridPlugin } from '../../core/plugin/base-plugin';\nimport { buildMenuItems, createMenuElement, positionMenu } from './menu';\nimport type { ContextMenuConfig, ContextMenuItem, ContextMenuParams } from './types';\n\n/** Global click handler reference for cleanup */\nlet globalClickHandler: ((e: Event) => void) | null = null;\n/** Global keydown handler reference for cleanup */\nlet globalKeydownHandler: ((e: KeyboardEvent) => void) | null = null;\n/** Global stylesheet for context menu (injected once) */\nlet globalStyleSheet: HTMLStyleElement | null = null;\n\n/** Context menu styles for light DOM rendering */\nconst contextMenuStyles = `\n .tbw-context-menu {\n position: fixed;\n background: light-dark(#f5f5f5, #2a2a2a);\n color: light-dark(#222, #eee);\n border: 1px solid light-dark(#d0d0d4, #454545);\n border-radius: 4px;\n box-shadow: 0 2px 10px rgba(0, 0, 0, 0.15);\n min-width: 160px;\n padding: 4px 0;\n z-index: 10000;\n font-size: 13px;\n font-family: system-ui, sans-serif;\n }\n .tbw-context-menu-item {\n display: flex;\n align-items: center;\n padding: 6px 12px;\n cursor: pointer;\n gap: 8px;\n }\n .tbw-context-menu-item:hover:not(.disabled) {\n background: light-dark(#e8e8e8, #3a3a3a);\n }\n .tbw-context-menu-item.disabled {\n opacity: 0.5;\n cursor: default;\n }\n .tbw-context-menu-item.danger {\n color: light-dark(#c00, #f66);\n }\n .tbw-context-menu-icon {\n width: 16px;\n text-align: center;\n }\n .tbw-context-menu-label {\n flex: 1;\n }\n .tbw-context-menu-shortcut {\n color: light-dark(#888, #888);\n font-size: 11px;\n }\n .tbw-context-menu-arrow {\n font-size: 10px;\n color: light-dark(#888, #888);\n }\n .tbw-context-menu-separator {\n height: 1px;\n background: light-dark(#d0d0d4, #454545);\n margin: 4px 0;\n }\n`;\n\n/** Default menu items when none are configured */\nconst defaultItems: ContextMenuItem[] = [\n {\n id: 'copy',\n name: 'Copy',\n shortcut: 'Ctrl+C',\n action: (params) => {\n const grid = (params as ContextMenuParams & { grid?: { plugins?: { clipboard?: { copy?: () => void } } } }).grid;\n grid?.plugins?.clipboard?.copy?.();\n },\n },\n { separator: true, id: 'sep1', name: '' },\n {\n id: 'export-csv',\n name: 'Export CSV',\n action: (params) => {\n const grid = (params as ContextMenuParams & { grid?: { plugins?: { export?: { exportCsv?: () => void } } } })\n .grid;\n grid?.plugins?.export?.exportCsv?.();\n },\n },\n];\n\n/**\n * Context Menu Plugin for tbw-grid\n *\n * @example\n * ```ts\n * new ContextMenuPlugin({\n * enabled: true,\n * items: [\n * { id: 'edit', name: 'Edit', action: (params) => console.log('Edit', params) },\n * { separator: true, id: 'sep', name: '' },\n * { id: 'delete', name: 'Delete', action: (params) => console.log('Delete', params) },\n * ],\n * })\n * ```\n */\nexport class ContextMenuPlugin extends BaseGridPlugin<ContextMenuConfig> {\n readonly name = 'contextMenu';\n override readonly version = '1.0.0';\n\n protected override get defaultConfig(): Partial<ContextMenuConfig> {\n return {\n enabled: true,\n items: defaultItems,\n };\n }\n\n // ===== Internal State =====\n private isOpen = false;\n private position = { x: 0, y: 0 };\n private params: ContextMenuParams | null = null;\n private menuElement: HTMLElement | null = null;\n\n // ===== Lifecycle =====\n\n override attach(grid: import('../../core/plugin/base-plugin').GridElement): void {\n super.attach(grid);\n this.installGlobalHandlers();\n }\n\n override detach(): void {\n if (this.menuElement) {\n this.menuElement.remove();\n this.menuElement = null;\n }\n this.isOpen = false;\n this.params = null;\n }\n\n // ===== Private Methods =====\n\n private installGlobalHandlers(): void {\n // Inject global stylesheet for context menu (once)\n if (!globalStyleSheet && typeof document !== 'undefined') {\n globalStyleSheet = document.createElement('style');\n globalStyleSheet.id = 'tbw-context-menu-styles';\n globalStyleSheet.textContent = contextMenuStyles;\n document.head.appendChild(globalStyleSheet);\n }\n\n // Close menu on click outside\n if (!globalClickHandler) {\n globalClickHandler = () => {\n const menus = document.querySelectorAll('.tbw-context-menu');\n menus.forEach((menu) => menu.remove());\n };\n document.addEventListener('click', globalClickHandler);\n }\n\n // Close on escape\n if (!globalKeydownHandler) {\n globalKeydownHandler = (e: KeyboardEvent) => {\n if (e.key === 'Escape') {\n const menus = document.querySelectorAll('.tbw-context-menu');\n menus.forEach((menu) => menu.remove());\n }\n };\n document.addEventListener('keydown', globalKeydownHandler);\n }\n }\n\n // ===== Hooks =====\n\n override afterRender(): void {\n if (!this.config.enabled) return;\n\n const shadowRoot = this.shadowRoot;\n if (!shadowRoot) return;\n\n const container = shadowRoot.children[0];\n if (!container) return;\n\n // Check if handler already attached\n if (container.getAttribute('data-context-menu-bound') === 'true') return;\n container.setAttribute('data-context-menu-bound', 'true');\n\n container.addEventListener('contextmenu', (e: Event) => {\n if (!this.config.enabled) return;\n\n const event = e as MouseEvent;\n event.preventDefault();\n\n const target = event.target as HTMLElement;\n const cell = target.closest('[data-row][data-col]');\n const header = target.closest('.header-cell');\n\n let params: ContextMenuParams;\n\n if (cell) {\n const rowIndex = parseInt(cell.getAttribute('data-row') ?? '-1', 10);\n const colIndex = parseInt(cell.getAttribute('data-col') ?? '-1', 10);\n const column = this.columns[colIndex];\n const row = this.rows[rowIndex];\n\n params = {\n row,\n rowIndex,\n column,\n columnIndex: colIndex,\n field: column?.field ?? '',\n value: row?.[column?.field as keyof typeof row] ?? null,\n isHeader: false,\n event,\n };\n } else if (header) {\n const colIndex = parseInt(header.getAttribute('data-col') ?? '-1', 10);\n const column = this.columns[colIndex];\n\n params = {\n row: null,\n rowIndex: -1,\n column,\n columnIndex: colIndex,\n field: column?.field ?? '',\n value: null,\n isHeader: true,\n event,\n };\n } else {\n return;\n }\n\n this.params = params;\n this.position = { x: event.clientX, y: event.clientY };\n\n const items = buildMenuItems(this.config.items ?? defaultItems, params);\n if (!items.length) return;\n\n if (this.menuElement) {\n this.menuElement.remove();\n }\n\n this.menuElement = createMenuElement(items, params, (item) => {\n if (item.action) {\n item.action(params);\n }\n this.menuElement?.remove();\n this.menuElement = null;\n this.isOpen = false;\n });\n\n document.body.appendChild(this.menuElement);\n positionMenu(this.menuElement, event.clientX, event.clientY);\n this.isOpen = true;\n\n this.emit('context-menu-open', { params, items });\n });\n }\n\n // ===== Public API =====\n\n /**\n * Programmatically show the context menu at the specified position.\n * @param x - X coordinate\n * @param y - Y coordinate\n * @param params - Partial context menu parameters\n */\n showMenu(x: number, y: number, params: Partial<ContextMenuParams>): void {\n const fullParams: ContextMenuParams = {\n row: params.row ?? null,\n rowIndex: params.rowIndex ?? -1,\n column: params.column ?? null,\n columnIndex: params.columnIndex ?? -1,\n field: params.field ?? '',\n value: params.value ?? null,\n isHeader: params.isHeader ?? false,\n event: params.event ?? new MouseEvent('contextmenu'),\n };\n\n const items = buildMenuItems(this.config.items ?? defaultItems, fullParams);\n\n if (this.menuElement) {\n this.menuElement.remove();\n }\n\n this.menuElement = createMenuElement(items, fullParams, (item) => {\n if (item.action) item.action(fullParams);\n this.menuElement?.remove();\n this.menuElement = null;\n this.isOpen = false;\n });\n\n document.body.appendChild(this.menuElement);\n positionMenu(this.menuElement, x, y);\n this.isOpen = true;\n }\n\n /**\n * Hide the context menu.\n */\n hideMenu(): void {\n if (this.menuElement) {\n this.menuElement.remove();\n this.menuElement = null;\n this.isOpen = false;\n }\n }\n\n /**\n * Check if the context menu is currently open.\n * @returns Whether the menu is open\n */\n isMenuOpen(): boolean {\n return this.isOpen;\n }\n\n // Styles are injected globally via installGlobalHandlers() since menu renders in document.body\n}\n","/**\n * CSV Export Utilities\n *\n * Functions for building and downloading CSV content.\n */\n\nimport type { ColumnConfig } from '../../core/types';\nimport type { ExportParams } from './types';\n\n/** CSV export options */\nexport interface CsvOptions {\n /** Field delimiter (default: ',') */\n delimiter?: string;\n /** Line separator (default: '\\n') */\n newline?: string;\n /** Whether to quote strings containing special characters (default: true) */\n quoteStrings?: boolean;\n /** Add UTF-8 BOM for Excel compatibility (default: false) */\n bom?: boolean;\n}\n\n/**\n * Format a value for CSV output.\n * Handles null, Date, objects, and strings with special characters.\n */\nexport function formatCsvValue(value: any, quote = true): string {\n if (value == null) return '';\n if (value instanceof Date) return value.toISOString();\n if (typeof value === 'object') return JSON.stringify(value);\n\n const str = String(value);\n\n // Quote if contains special characters (comma, quote, newline)\n if (quote && (str.includes(',') || str.includes('\"') || str.includes('\\n') || str.includes('\\r'))) {\n return `\"${str.replace(/\"/g, '\"\"')}\"`;\n }\n\n return str;\n}\n\n/**\n * Build CSV content from rows and columns.\n */\nexport function buildCsv(rows: any[], columns: ColumnConfig[], params: ExportParams, options: CsvOptions = {}): string {\n const delimiter = options.delimiter ?? ',';\n const newline = options.newline ?? '\\n';\n const lines: string[] = [];\n\n // UTF-8 BOM for Excel compatibility\n const bom = options.bom ? '\\uFEFF' : '';\n\n // Build header row\n if (params.includeHeaders !== false) {\n const headerRow = columns.map((col) => {\n const header = col.header || col.field;\n const processed = params.processHeader ? params.processHeader(header, col.field) : header;\n return formatCsvValue(processed);\n });\n lines.push(headerRow.join(delimiter));\n }\n\n // Build data rows\n for (const row of rows) {\n const cells = columns.map((col) => {\n let value = row[col.field];\n if (params.processCell) {\n value = params.processCell(value, col.field, row);\n }\n return formatCsvValue(value);\n });\n lines.push(cells.join(delimiter));\n }\n\n return bom + lines.join(newline);\n}\n\n/**\n * Download a Blob as a file.\n */\nexport function downloadBlob(blob: Blob, fileName: string): void {\n const url = URL.createObjectURL(blob);\n const link = document.createElement('a');\n link.href = url;\n link.download = fileName;\n link.style.display = 'none';\n document.body.appendChild(link);\n link.click();\n document.body.removeChild(link);\n URL.revokeObjectURL(url);\n}\n\n/**\n * Download CSV content as a file.\n */\nexport function downloadCsv(content: string, fileName: string): void {\n const blob = new Blob([content], { type: 'text/csv;charset=utf-8;' });\n downloadBlob(blob, fileName);\n}\n","/**\n * Excel Export Utilities\n *\n * Simple Excel XML format export (no external dependencies).\n * Produces XML Spreadsheet 2003 format which opens in Excel.\n */\n\nimport type { ColumnConfig } from '../../core/types';\nimport type { ExportParams } from './types';\nimport { downloadBlob } from './csv';\n\n/**\n * Escape XML special characters.\n */\nfunction escapeXml(str: string): string {\n return str\n .replace(/&/g, '&')\n .replace(/</g, '<')\n .replace(/>/g, '>')\n .replace(/\"/g, '"')\n .replace(/'/g, ''');\n}\n\n/**\n * Build Excel XML content from rows and columns.\n * Uses XML Spreadsheet 2003 format for broad compatibility.\n */\nexport function buildExcelXml(rows: any[], columns: ColumnConfig[], params: ExportParams): string {\n let xml = `<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<?mso-application progid=\"Excel.Sheet\"?>\n<Workbook xmlns=\"urn:schemas-microsoft-com:office:spreadsheet\"\n xmlns:ss=\"urn:schemas-microsoft-com:office:spreadsheet\">\n<Worksheet ss:Name=\"Sheet1\">\n<Table>`;\n\n // Build header row\n if (params.includeHeaders !== false) {\n xml += '\\n<Row>';\n for (const col of columns) {\n const header = col.header || col.field;\n const processed = params.processHeader ? params.processHeader(header, col.field) : header;\n xml += `<Cell><Data ss:Type=\"String\">${escapeXml(processed)}</Data></Cell>`;\n }\n xml += '</Row>';\n }\n\n // Build data rows\n for (const row of rows) {\n xml += '\\n<Row>';\n for (const col of columns) {\n let value = row[col.field];\n if (params.processCell) {\n value = params.processCell(value, col.field, row);\n }\n\n // Determine cell type based on value\n let type: 'Number' | 'String' | 'DateTime' = 'String';\n let displayValue = '';\n\n if (value == null) {\n displayValue = '';\n } else if (typeof value === 'number' && !isNaN(value)) {\n type = 'Number';\n displayValue = String(value);\n } else if (value instanceof Date) {\n type = 'DateTime';\n displayValue = value.toISOString();\n } else {\n displayValue = escapeXml(String(value));\n }\n\n xml += `<Cell><Data ss:Type=\"${type}\">${displayValue}</Data></Cell>`;\n }\n xml += '</Row>';\n }\n\n xml += '\\n</Table>\\n</Worksheet>\\n</Workbook>';\n return xml;\n}\n\n/**\n * Download Excel XML content as a file.\n */\nexport function downloadExcel(content: string, fileName: string): void {\n const finalName = fileName.endsWith('.xls') ? fileName : `${fileName}.xls`;\n const blob = new Blob([content], {\n type: 'application/vnd.ms-excel;charset=utf-8;',\n });\n downloadBlob(blob, finalName);\n}\n","/**\n * Export Plugin (Class-based)\n *\n * Provides data export functionality for tbw-grid.\n * Supports CSV, Excel (XML), and JSON formats.\n */\n\n/* eslint-disable @typescript-eslint/no-explicit-any */\n\nimport { BaseGridPlugin } from '../../core/plugin/base-plugin';\nimport type { ColumnConfig } from '../../core/types';\nimport { buildCsv, downloadBlob, downloadCsv } from './csv';\nimport { buildExcelXml, downloadExcel } from './excel';\nimport type { ExportCompleteDetail, ExportConfig, ExportFormat, ExportParams } from './types';\n\n/** Selection plugin state interface for type safety */\ninterface SelectionPluginState {\n selected: Set<number>;\n}\n\n/**\n * Export Plugin for tbw-grid\n *\n * @example\n * ```ts\n * new ExportPlugin({\n * enabled: true,\n * fileName: 'my-data',\n * includeHeaders: true,\n * onlyVisible: true,\n * })\n * ```\n */\nexport class ExportPlugin extends BaseGridPlugin<ExportConfig> {\n readonly name = 'export';\n override readonly version = '1.0.0';\n\n protected override get defaultConfig(): Partial<ExportConfig> {\n return {\n enabled: true,\n fileName: 'export',\n includeHeaders: true,\n onlyVisible: true,\n onlySelected: false,\n };\n }\n\n // ===== Internal State =====\n private isExportingFlag = false;\n private lastExportInfo: { format: ExportFormat; timestamp: Date } | null = null;\n\n // ===== Private Methods =====\n\n private performExport(format: ExportFormat, params?: Partial<ExportParams>): void {\n const config = this.config;\n\n // Build full params with defaults\n const fullParams: ExportParams = {\n format,\n fileName: params?.fileName ?? config.fileName ?? 'export',\n includeHeaders: params?.includeHeaders ?? config.includeHeaders,\n processCell: params?.processCell,\n processHeader: params?.processHeader,\n columns: params?.columns,\n rowIndices: params?.rowIndices,\n };\n\n // Get columns to export\n let columns = [...this.columns] as ColumnConfig[];\n if (config.onlyVisible) {\n columns = columns.filter((c) => !c.hidden && !c.field.startsWith('__'));\n }\n if (params?.columns) {\n const colSet = new Set(params.columns);\n columns = columns.filter((c) => colSet.has(c.field));\n }\n\n // Get rows to export\n let rows = [...this.rows] as any[];\n if (config.onlySelected) {\n const selectionState = this.getSelectionState();\n if (selectionState?.selected?.size) {\n const sortedIndices = [...selectionState.selected].sort((a, b) => a - b);\n rows = sortedIndices.map((i) => this.rows[i]).filter(Boolean);\n }\n }\n if (params?.rowIndices) {\n rows = params.rowIndices.map((i) => this.rows[i]).filter(Boolean);\n }\n\n this.isExportingFlag = true;\n let fileName = fullParams.fileName!;\n\n try {\n switch (format) {\n case 'csv': {\n const content = buildCsv(rows, columns, fullParams, { bom: true });\n fileName = fileName.endsWith('.csv') ? fileName : `${fileName}.csv`;\n downloadCsv(content, fileName);\n break;\n }\n\n case 'excel': {\n const content = buildExcelXml(rows, columns, fullParams);\n fileName = fileName.endsWith('.xls') ? fileName : `${fileName}.xls`;\n downloadExcel(content, fileName);\n break;\n }\n\n case 'json': {\n const jsonData = rows.map((row) => {\n const obj: Record<string, any> = {};\n for (const col of columns) {\n let value = row[col.field];\n if (fullParams.processCell) {\n value = fullParams.processCell(value, col.field, row);\n }\n obj[col.field] = value;\n }\n return obj;\n });\n const content = JSON.stringify(jsonData, null, 2);\n fileName = fileName.endsWith('.json') ? fileName : `${fileName}.json`;\n const blob = new Blob([content], { type: 'application/json' });\n downloadBlob(blob, fileName);\n break;\n }\n }\n\n this.lastExportInfo = { format, timestamp: new Date() };\n\n this.emit<ExportCompleteDetail>('export-complete', {\n format,\n fileName,\n rowCount: rows.length,\n columnCount: columns.length,\n });\n } finally {\n this.isExportingFlag = false;\n }\n }\n\n private getSelectionState(): SelectionPluginState | null {\n try {\n const grid = this.grid as any;\n return grid?.getPluginState?.('selection') ?? null;\n } catch {\n return null;\n }\n }\n\n // ===== Public API =====\n\n /**\n * Export data to CSV format.\n * @param params - Optional export parameters\n */\n exportCsv(params?: Partial<ExportParams>): void {\n this.performExport('csv', params);\n }\n\n /**\n * Export data to Excel format (XML Spreadsheet).\n * @param params - Optional export parameters\n */\n exportExcel(params?: Partial<ExportParams>): void {\n this.performExport('excel', params);\n }\n\n /**\n * Export data to JSON format.\n * @param params - Optional export parameters\n */\n exportJson(params?: Partial<ExportParams>): void {\n this.performExport('json', params);\n }\n\n /**\n * Check if an export is currently in progress.\n * @returns Whether export is in progress\n */\n isExporting(): boolean {\n return this.isExportingFlag;\n }\n\n /**\n * Get information about the last export.\n * @returns Export info or null if no export has occurred\n */\n getLastExport(): { format: ExportFormat; timestamp: Date } | null {\n return this.lastExportInfo;\n }\n}\n","/**\n * Row Virtualization Core Logic\n *\n * Pure functions for vertical row virtualization operations.\n * Manages which rows are rendered based on scroll position and viewport size.\n */\n\n/** Result of computing a virtual window */\nexport interface VirtualWindow {\n /** First row index to render (inclusive) */\n start: number;\n /** Last row index to render (exclusive) */\n end: number;\n /** Pixel offset to apply to the rows container (translateY) */\n offsetY: number;\n /** Total height of the scrollable content */\n totalHeight: number;\n}\n\n/** Parameters for computing the virtual window */\nexport interface VirtualWindowParams {\n /** Total number of rows */\n totalRows: number;\n /** Height of the viewport in pixels */\n viewportHeight: number;\n /** Current scroll top position */\n scrollTop: number;\n /** Height of each row in pixels */\n rowHeight: number;\n /** Number of extra rows to render above/below viewport */\n overscan: number;\n /** Previous scroll position for velocity calculation */\n prevScrollTop?: number;\n}\n\n/**\n * Compute the virtual row window based on scroll position and viewport.\n * Uses directional overscan - renders more rows in the scroll direction.\n *\n * @param params - Parameters for computing the window\n * @returns VirtualWindow with start/end indices and transforms\n */\nexport function computeVirtualWindow(params: VirtualWindowParams): VirtualWindow {\n const { totalRows, viewportHeight, scrollTop, rowHeight, overscan } = params;\n\n // Simple approach: render a large fixed window centered on current position\n // This is more predictable than velocity-based sizing\n const visibleRows = Math.ceil(viewportHeight / rowHeight);\n\n // Render overscan rows in each direction (total window = visible + 2*overscan)\n let start = Math.floor(scrollTop / rowHeight) - overscan;\n if (start < 0) start = 0;\n\n let end = start + visibleRows + overscan * 2;\n if (end > totalRows) end = totalRows;\n\n // Ensure start is adjusted if we hit the end\n if (end === totalRows && start > 0) {\n start = Math.max(0, end - visibleRows - overscan * 2);\n }\n\n return {\n start,\n end,\n offsetY: start * rowHeight,\n totalHeight: totalRows * rowHeight,\n };\n}\n\n/**\n * Determine if virtualization should be bypassed for small datasets.\n * When there are very few items, the overhead of virtualization isn't worth it.\n *\n * @param totalRows - Total number of items\n * @param threshold - Bypass threshold (skip virtualization if totalRows <= threshold)\n * @returns True if virtualization should be bypassed\n */\nexport function shouldBypassVirtualization(totalRows: number, threshold: number): boolean {\n return totalRows <= threshold;\n}\n\n/**\n * Compute the row index from a Y pixel position.\n *\n * @param y - Y position in pixels (relative to content top)\n * @param rowHeight - Height of each row\n * @returns Row index at that position\n */\nexport function getRowIndexFromY(y: number, rowHeight: number): number {\n return Math.floor(y / rowHeight);\n}\n\n/**\n * Compute the Y offset for a given row index.\n *\n * @param rowIndex - Row index\n * @param rowHeight - Height of each row\n * @returns Y position in pixels\n */\nexport function getRowOffsetY(rowIndex: number, rowHeight: number): number {\n return rowIndex * rowHeight;\n}\n\n/**\n * Compute the range of rows that are fully or partially visible in the viewport.\n * This is the range without overscan - just what the user can actually see.\n *\n * @param scrollTop - Current scroll position\n * @param viewportHeight - Height of the viewport\n * @param rowHeight - Height of each row\n * @param totalRows - Total number of rows\n * @returns Object with first and last visible row indices\n */\nexport function getVisibleRowRange(\n scrollTop: number,\n viewportHeight: number,\n rowHeight: number,\n totalRows: number\n): { first: number; last: number } {\n const first = Math.floor(scrollTop / rowHeight);\n let last = Math.ceil((scrollTop + viewportHeight) / rowHeight) - 1;\n if (last >= totalRows) last = totalRows - 1;\n if (first > last) return { first: 0, last: 0 };\n return { first, last };\n}\n\n/**\n * Check if a row is currently rendered in the virtual window.\n *\n * @param rowIndex - Row index to check\n * @param windowStart - Start of the render window\n * @param windowEnd - End of the render window\n * @returns True if the row is rendered\n */\nexport function isRowRendered(rowIndex: number, windowStart: number, windowEnd: number): boolean {\n return rowIndex >= windowStart && rowIndex < windowEnd;\n}\n\n/**\n * Clamp a row index to valid bounds.\n *\n * @param rowIndex - Row index to clamp\n * @param totalRows - Total number of rows\n * @returns Clamped row index (0 to totalRows - 1)\n */\nexport function clampRowIndex(rowIndex: number, totalRows: number): number {\n if (totalRows === 0) return 0;\n if (rowIndex < 0) return 0;\n if (rowIndex >= totalRows) return totalRows - 1;\n return rowIndex;\n}\n\n/**\n * Compute the scroll position needed to bring a row into view.\n *\n * @param rowIndex - Row index to scroll to\n * @param rowHeight - Height of each row\n * @param viewportHeight - Height of the viewport\n * @param currentScrollTop - Current scroll position\n * @returns New scroll position, or null if row is already visible\n */\nexport function computeScrollToRow(\n rowIndex: number,\n rowHeight: number,\n viewportHeight: number,\n currentScrollTop: number\n): number | null {\n const rowTop = rowIndex * rowHeight;\n const rowBottom = rowTop + rowHeight;\n\n // Row is above viewport\n if (rowTop < currentScrollTop) {\n return rowTop;\n }\n\n // Row is below viewport\n if (rowBottom > currentScrollTop + viewportHeight) {\n return rowBottom - viewportHeight;\n }\n\n // Row is already visible\n return null;\n}\n","/**\n * Filter Model Core Logic\n *\n * Pure functions for filtering operations.\n */\n\nimport type { FilterModel } from './types';\n\n/**\n * Check if a single row matches a filter condition.\n *\n * @param row - The row data object\n * @param filter - The filter to apply\n * @param caseSensitive - Whether text comparisons are case sensitive\n * @returns True if the row matches the filter\n */\nexport function matchesFilter(row: Record<string, unknown>, filter: FilterModel, caseSensitive = false): boolean {\n const rawValue = row[filter.field];\n\n // Handle blank/notBlank first - these work on null/undefined/empty\n if (filter.operator === 'blank') {\n return rawValue == null || rawValue === '';\n }\n if (filter.operator === 'notBlank') {\n return rawValue != null && rawValue !== '';\n }\n\n // Null/undefined values don't match other filters\n if (rawValue == null) return false;\n\n // Prepare values for comparison\n const stringValue = String(rawValue);\n const compareValue = caseSensitive ? stringValue : stringValue.toLowerCase();\n const filterValue = caseSensitive ? String(filter.value) : String(filter.value).toLowerCase();\n\n switch (filter.operator) {\n // Text operators\n case 'contains':\n return compareValue.includes(filterValue);\n\n case 'notContains':\n return !compareValue.includes(filterValue);\n\n case 'equals':\n return compareValue === filterValue;\n\n case 'notEquals':\n return compareValue !== filterValue;\n\n case 'startsWith':\n return compareValue.startsWith(filterValue);\n\n case 'endsWith':\n return compareValue.endsWith(filterValue);\n\n // Number/Date operators (use raw numeric values)\n case 'lessThan':\n return Number(rawValue) < Number(filter.value);\n\n case 'lessThanOrEqual':\n return Number(rawValue) <= Number(filter.value);\n\n case 'greaterThan':\n return Number(rawValue) > Number(filter.value);\n\n case 'greaterThanOrEqual':\n return Number(rawValue) >= Number(filter.value);\n\n case 'between':\n return Number(rawValue) >= Number(filter.value) && Number(rawValue) <= Number(filter.valueTo);\n\n // Set operators\n case 'in':\n return Array.isArray(filter.value) && filter.value.includes(rawValue);\n\n case 'notIn':\n return Array.isArray(filter.value) && !filter.value.includes(rawValue);\n\n default:\n return true;\n }\n}\n\n/**\n * Filter rows based on multiple filter conditions (AND logic).\n * All filters must match for a row to be included.\n *\n * @param rows - The rows to filter\n * @param filters - Array of filters to apply\n * @param caseSensitive - Whether text comparisons are case sensitive\n * @returns Filtered rows\n */\nexport function filterRows<T extends Record<string, unknown>>(\n rows: T[],\n filters: FilterModel[],\n caseSensitive = false\n): T[] {\n if (!filters.length) return rows;\n return rows.filter((row) => filters.every((f) => matchesFilter(row, f, caseSensitive)));\n}\n\n/**\n * Compute a cache key for a set of filters.\n * Used for memoization of filter results.\n *\n * @param filters - Array of filters\n * @returns Stable string key for the filter set\n */\nexport function computeFilterCacheKey(filters: FilterModel[]): string {\n return JSON.stringify(\n filters.map((f) => ({\n field: f.field,\n operator: f.operator,\n value: f.value,\n valueTo: f.valueTo,\n }))\n );\n}\n\n/**\n * Extract unique values from a field across all rows.\n * Useful for populating \"set\" filter dropdowns.\n *\n * @param rows - The rows to extract values from\n * @param field - The field name\n * @returns Sorted array of unique non-null values\n */\nexport function getUniqueValues<T extends Record<string, unknown>>(rows: T[], field: string): unknown[] {\n const values = new Set<unknown>();\n for (const row of rows) {\n const value = row[field];\n if (value != null) {\n values.add(value);\n }\n }\n return [...values].sort((a, b) => {\n // Handle mixed types gracefully\n if (typeof a === 'number' && typeof b === 'number') {\n return a - b;\n }\n return String(a).localeCompare(String(b));\n });\n}\n","/**\n * Filtering Plugin (Class-based)\n *\n * Provides comprehensive filtering functionality for tbw-grid.\n * Supports text, number, date, set, and boolean filters with caching.\n * Includes UI with filter buttons in headers and dropdown filter panels.\n */\n\nimport { BaseGridPlugin, type GridElement } from '../../core/plugin/base-plugin';\nimport type { ColumnConfig, ColumnState } from '../../core/types';\nimport { computeVirtualWindow, shouldBypassVirtualization } from '../../core/internal/virtualization';\nimport { computeFilterCacheKey, filterRows, getUniqueValues } from './filter-model';\nimport type { FilterChangeDetail, FilterConfig, FilterModel, FilterPanelParams } from './types';\n\n/** Global styles for filter panel (rendered in document.body) */\nconst filterPanelStyles = `\n.tbw-filter-panel {\n position: fixed;\n background: var(--tbw-filter-panel-bg, var(--tbw-color-panel-bg, light-dark(#eeeeee, #222222)));\n color: var(--tbw-filter-panel-fg, var(--tbw-color-fg, light-dark(#222222, #eeeeee)));\n border: 1px solid var(--tbw-filter-panel-border, var(--tbw-color-border, light-dark(#d0d0d4, #454545)));\n border-radius: var(--tbw-filter-panel-radius, var(--tbw-border-radius, 4px));\n box-shadow: 0 4px 16px var(--tbw-filter-panel-shadow, var(--tbw-color-shadow, light-dark(rgba(0,0,0,0.1), rgba(0,0,0,0.3))));\n padding: 12px;\n z-index: 10000;\n min-width: 200px;\n max-width: 280px;\n max-height: 350px;\n display: flex;\n flex-direction: column;\n font-family: var(--tbw-font-family, system-ui, sans-serif);\n font-size: var(--tbw-font-size, 13px);\n}\n\n.tbw-filter-search {\n margin-bottom: 8px;\n}\n\n.tbw-filter-search-input {\n width: 100%;\n padding: 6px 10px;\n background: var(--tbw-filter-input-bg, var(--tbw-color-bg, transparent));\n color: inherit;\n border: 1px solid var(--tbw-filter-input-border, var(--tbw-color-border, light-dark(#d0d0d4, #454545)));\n border-radius: var(--tbw-filter-input-radius, 4px);\n font-size: inherit;\n box-sizing: border-box;\n}\n\n.tbw-filter-search-input:focus {\n outline: none;\n border-color: var(--tbw-filter-accent, var(--tbw-color-accent, #3b82f6));\n box-shadow: 0 0 0 2px rgba(from var(--tbw-filter-accent, var(--tbw-color-accent, #3b82f6)) r g b / 15%);\n}\n\n.tbw-filter-actions {\n display: flex;\n padding: 4px 2px;\n margin-bottom: 8px;\n border-bottom: 1px solid var(--tbw-filter-divider, var(--tbw-color-border, light-dark(#d0d0d4, #454545)));\n}\n\n.tbw-filter-action-btn {\n background: transparent;\n border: none;\n color: var(--tbw-filter-accent, var(--tbw-color-accent, #3b82f6));\n cursor: pointer;\n font-size: 12px;\n padding: 2px 0;\n}\n\n.tbw-filter-action-btn:hover {\n text-decoration: underline;\n}\n\n.tbw-filter-values {\n flex: 1;\n overflow-y: auto;\n margin-bottom: 8px;\n max-height: 180px;\n position: relative;\n}\n\n.tbw-filter-values-spacer {\n width: 1px;\n}\n\n.tbw-filter-values-content {\n position: absolute;\n top: 0;\n left: 0;\n right: 0;\n}\n\n.tbw-filter-value-item {\n display: flex;\n align-items: center;\n gap: 8px;\n padding: 4px 2px;\n cursor: pointer;\n border-radius: 3px;\n}\n\n.tbw-filter-value-item:hover {\n background: var(--tbw-filter-hover, var(--tbw-color-row-hover, light-dark(#f0f6ff, #1c1c1c)));\n}\n\n.tbw-filter-checkbox {\n margin: 0;\n cursor: pointer;\n accent-color: var(--tbw-filter-accent, var(--tbw-color-accent, #3b82f6));\n}\n\n.tbw-filter-no-match {\n color: var(--tbw-filter-muted, var(--tbw-color-fg-muted, light-dark(#555555, #aaaaaa)));\n padding: 8px 0;\n text-align: center;\n font-style: italic;\n}\n\n.tbw-filter-buttons {\n display: flex;\n gap: 8px;\n padding-top: 8px;\n border-top: 1px solid var(--tbw-filter-divider, var(--tbw-color-border, light-dark(#d0d0d4, #454545)));\n}\n\n.tbw-filter-apply-btn {\n flex: 1;\n padding: 6px 12px;\n background: var(--tbw-filter-accent, var(--tbw-color-accent, #3b82f6));\n color: var(--tbw-filter-accent-fg, var(--tbw-color-accent-fg, light-dark(#ffffff, #000000)));\n border: none;\n border-radius: 4px;\n cursor: pointer;\n font-size: 13px;\n}\n\n.tbw-filter-apply-btn:hover {\n filter: brightness(0.9);\n}\n\n.tbw-filter-clear-btn {\n flex: 1;\n padding: 6px 12px;\n background: transparent;\n color: var(--tbw-filter-muted, var(--tbw-color-fg-muted, light-dark(#555555, #aaaaaa)));\n border: 1px solid var(--tbw-filter-input-border, var(--tbw-color-border, light-dark(#d0d0d4, #454545)));\n border-radius: 4px;\n cursor: pointer;\n font-size: 13px;\n}\n\n.tbw-filter-clear-btn:hover {\n background: var(--tbw-filter-hover, var(--tbw-color-row-hover, light-dark(#f0f6ff, #1c1c1c)));\n}\n`;\n\n/**\n * Filtering Plugin for tbw-grid\n *\n * @example\n * ```ts\n * new FilteringPlugin({ enabled: true, debounceMs: 300 })\n * ```\n */\nexport class FilteringPlugin extends BaseGridPlugin<FilterConfig> {\n readonly name = 'filtering';\n override readonly version = '1.0.0';\n\n protected override get defaultConfig(): Partial<FilterConfig> {\n return {\n enabled: true,\n debounceMs: 300,\n caseSensitive: false,\n trimInput: true,\n useWorker: true,\n };\n }\n\n // ===== Internal State =====\n private filters: Map<string, FilterModel> = new Map();\n private cachedResult: unknown[] | null = null;\n private cacheKey: string | null = null;\n private openPanelField: string | null = null;\n private panelElement: HTMLElement | null = null;\n private searchText: Map<string, string> = new Map();\n private excludedValues: Map<string, Set<unknown>> = new Map();\n private documentClickHandler: ((e: MouseEvent) => void) | null = null;\n private globalStylesInjected = false;\n\n // Virtualization constants for filter value list\n private static readonly LIST_ITEM_HEIGHT = 28;\n private static readonly LIST_OVERSCAN = 3;\n private static readonly LIST_BYPASS_THRESHOLD = 50; // Don't virtualize if < 50 items\n\n // ===== Lifecycle =====\n\n override attach(grid: GridElement): void {\n super.attach(grid);\n this.injectGlobalStyles();\n }\n\n override detach(): void {\n this.filters.clear();\n this.cachedResult = null;\n this.cacheKey = null;\n this.openPanelField = null;\n if (this.panelElement) {\n this.panelElement.remove();\n this.panelElement = null;\n }\n this.searchText.clear();\n this.excludedValues.clear();\n this.removeDocumentClickHandler();\n }\n\n // ===== Hooks =====\n\n override processRows(rows: readonly unknown[]): unknown[] {\n const filterList = [...this.filters.values()];\n if (!filterList.length) return [...rows];\n\n // Check cache\n const newCacheKey = computeFilterCacheKey(filterList);\n if (this.cacheKey === newCacheKey && this.cachedResult) {\n return this.cachedResult;\n }\n\n // Filter rows synchronously (worker support can be added later)\n const result = filterRows([...rows] as Record<string, unknown>[], filterList, this.config.caseSensitive);\n\n // Update cache\n this.cachedResult = result;\n this.cacheKey = newCacheKey;\n\n return result;\n }\n\n override afterRender(): void {\n if (!this.config.enabled) return;\n\n const shadowRoot = this.shadowRoot;\n if (!shadowRoot) return;\n\n // Find all header cells (using part attribute, not class)\n const headerCells = shadowRoot.querySelectorAll('[part~=\"header-cell\"]');\n headerCells.forEach((cell) => {\n const colIndex = cell.getAttribute('data-col');\n if (colIndex === null) return;\n\n const col = this.columns[parseInt(colIndex, 10)] as ColumnConfig;\n if (!col || col.filterable === false) return;\n\n // Skip if button already exists\n if (cell.querySelector('.tbw-filter-btn')) return;\n\n const field = col.field;\n if (!field) return;\n\n // Create filter button\n const filterBtn = document.createElement('button');\n filterBtn.className = 'tbw-filter-btn';\n filterBtn.setAttribute('aria-label', `Filter ${col.header ?? field}`);\n filterBtn.innerHTML = `<svg viewBox=\"0 0 16 16\" width=\"12\" height=\"12\"><path fill=\"currentColor\" d=\"M6 10.5a.5.5 0 0 1 .5-.5h3a.5.5 0 0 1 0 1h-3a.5.5 0 0 1-.5-.5zm-2-3a.5.5 0 0 1 .5-.5h7a.5.5 0 0 1 0 1h-7a.5.5 0 0 1-.5-.5zm-2-3a.5.5 0 0 1 .5-.5h11a.5.5 0 0 1 0 1h-11a.5.5 0 0 1-.5-.5z\"/></svg>`;\n\n // Mark button as active if filter exists\n if (this.filters.has(field)) {\n filterBtn.classList.add('active');\n cell.classList.add('filtered');\n }\n\n filterBtn.addEventListener('click', (e) => {\n e.stopPropagation();\n this.toggleFilterPanel(field, col, filterBtn);\n });\n\n // Append to header cell\n cell.appendChild(filterBtn);\n });\n }\n\n // ===== Public API =====\n\n /**\n * Set a filter on a specific field.\n * Pass null to remove the filter.\n */\n setFilter(field: string, filter: Omit<FilterModel, 'field'> | null): void {\n if (filter === null) {\n this.filters.delete(field);\n } else {\n this.filters.set(field, { ...filter, field });\n }\n // Invalidate cache\n this.cachedResult = null;\n this.cacheKey = null;\n\n this.emit<FilterChangeDetail>('filter-change', {\n filters: [...this.filters.values()],\n filteredRowCount: 0, // Will be accurate after processRows\n });\n this.requestRender();\n }\n\n /**\n * Get the current filter for a field.\n */\n getFilter(field: string): FilterModel | undefined {\n return this.filters.get(field);\n }\n\n /**\n * Get all active filters.\n */\n getFilters(): FilterModel[] {\n return [...this.filters.values()];\n }\n\n /**\n * Alias for getFilters() to match functional API naming.\n */\n getFilterModel(): FilterModel[] {\n return this.getFilters();\n }\n\n /**\n * Set filters from an array (replaces all existing filters).\n */\n setFilterModel(filters: FilterModel[]): void {\n this.filters.clear();\n for (const filter of filters) {\n this.filters.set(filter.field, filter);\n }\n this.cachedResult = null;\n this.cacheKey = null;\n\n this.emit<FilterChangeDetail>('filter-change', {\n filters: [...this.filters.values()],\n filteredRowCount: 0,\n });\n this.requestRender();\n }\n\n /**\n * Clear all filters.\n */\n clearAllFilters(): void {\n this.filters.clear();\n this.excludedValues.clear();\n this.searchText.clear();\n this.cachedResult = null;\n this.cacheKey = null;\n\n this.emit<FilterChangeDetail>('filter-change', {\n filters: [],\n filteredRowCount: this.rows.length,\n });\n this.requestRender();\n }\n\n /**\n * Clear filter for a specific field.\n */\n clearFieldFilter(field: string): void {\n this.filters.delete(field);\n this.excludedValues.delete(field);\n this.searchText.delete(field);\n\n this.cachedResult = null;\n this.cacheKey = null;\n\n this.emit<FilterChangeDetail>('filter-change', {\n filters: [...this.filters.values()],\n filteredRowCount: 0,\n });\n this.requestRender();\n }\n\n /**\n * Check if a field has an active filter.\n */\n isFieldFiltered(field: string): boolean {\n return this.filters.has(field);\n }\n\n /**\n * Get the count of filtered rows (from cache).\n */\n getFilteredRowCount(): number {\n return this.cachedResult?.length ?? this.rows.length;\n }\n\n /**\n * Get all active filters (alias for getFilters).\n */\n getActiveFilters(): FilterModel[] {\n return this.getFilters();\n }\n\n /**\n * Get unique values for a field (for set filter dropdowns).\n * Uses sourceRows to include all values regardless of current filter.\n */\n getUniqueValues(field: string): unknown[] {\n return getUniqueValues(this.sourceRows as Record<string, unknown>[], field);\n }\n\n // ===== Private Methods =====\n\n /**\n * Inject global styles for filter panel (rendered in document.body)\n */\n private injectGlobalStyles(): void {\n if (this.globalStylesInjected) return;\n if (document.getElementById('tbw-filter-panel-styles')) {\n this.globalStylesInjected = true;\n return;\n }\n const style = document.createElement('style');\n style.id = 'tbw-filter-panel-styles';\n style.textContent = filterPanelStyles;\n document.head.appendChild(style);\n this.globalStylesInjected = true;\n }\n\n /**\n * Toggle the filter panel for a field\n */\n private toggleFilterPanel(field: string, column: ColumnConfig, buttonEl: HTMLElement): void {\n // Close if already open\n if (this.openPanelField === field) {\n this.closeFilterPanel();\n return;\n }\n\n // Close any existing panel\n this.closeFilterPanel();\n\n // Create panel\n const panel = document.createElement('div');\n panel.className = 'tbw-filter-panel';\n this.panelElement = panel;\n this.openPanelField = field;\n\n // Get unique values for this field (from source rows, not filtered)\n const uniqueValues = getUniqueValues(this.sourceRows as Record<string, unknown>[], field);\n\n // Get current excluded values or initialize empty\n let excludedSet = this.excludedValues.get(field);\n if (!excludedSet) {\n excludedSet = new Set();\n this.excludedValues.set(field, excludedSet);\n }\n\n // Get current search text\n const currentSearchText = this.searchText.get(field) ?? '';\n\n // Create panel params for custom renderer\n const params: FilterPanelParams = {\n field,\n column,\n uniqueValues,\n excludedValues: excludedSet,\n searchText: currentSearchText,\n applySetFilter: (excluded: unknown[]) => {\n this.applySetFilter(field, excluded);\n this.closeFilterPanel();\n },\n applyTextFilter: (operator, value, valueTo) => {\n this.applyTextFilter(field, operator, value, valueTo);\n this.closeFilterPanel();\n },\n clearFilter: () => {\n this.clearFieldFilter(field);\n this.closeFilterPanel();\n },\n closePanel: () => this.closeFilterPanel(),\n };\n\n // Use custom renderer or default\n // Custom renderer can return undefined to fall back to default panel for specific columns\n let usedCustomRenderer = false;\n if (this.config.filterPanelRenderer) {\n const result = this.config.filterPanelRenderer(panel, params);\n // If renderer added content to panel, it handled rendering\n usedCustomRenderer = panel.children.length > 0;\n }\n if (!usedCustomRenderer) {\n this.renderDefaultFilterPanel(panel, params, uniqueValues, excludedSet);\n }\n\n // Position and append to body\n document.body.appendChild(panel);\n this.positionPanel(panel, buttonEl);\n\n // Add global click handler to close on outside click\n const handler = (e: MouseEvent) => {\n if (!panel.contains(e.target as Node) && e.target !== buttonEl) {\n this.closeFilterPanel();\n }\n };\n this.documentClickHandler = handler;\n // Defer to next tick to avoid immediate close\n setTimeout(() => {\n document.addEventListener('click', handler);\n }, 0);\n }\n\n /**\n * Close the filter panel\n */\n private closeFilterPanel(): void {\n if (this.panelElement) {\n this.panelElement.remove();\n this.panelElement = null;\n }\n this.openPanelField = null;\n this.removeDocumentClickHandler();\n }\n\n /**\n * Remove the document click handler\n */\n private removeDocumentClickHandler(): void {\n if (this.documentClickHandler) {\n document.removeEventListener('click', this.documentClickHandler);\n this.documentClickHandler = null;\n }\n }\n\n /**\n * Position the panel below the button\n */\n private positionPanel(panel: HTMLElement, buttonEl: HTMLElement): void {\n const rect = buttonEl.getBoundingClientRect();\n panel.style.position = 'fixed';\n panel.style.top = `${rect.bottom + 4}px`;\n panel.style.left = `${rect.left}px`;\n\n // Adjust if overflows right edge\n requestAnimationFrame(() => {\n const panelRect = panel.getBoundingClientRect();\n if (panelRect.right > window.innerWidth - 8) {\n panel.style.left = `${window.innerWidth - panelRect.width - 8}px`;\n }\n // Adjust if overflows bottom\n if (panelRect.bottom > window.innerHeight - 8) {\n panel.style.top = `${rect.top - panelRect.height - 4}px`;\n }\n });\n }\n\n /**\n * Render the default filter panel content\n */\n private renderDefaultFilterPanel(\n panel: HTMLElement,\n params: FilterPanelParams,\n uniqueValues: unknown[],\n excludedValues: Set<unknown>\n ): void {\n const { field } = params;\n\n // Search input\n const searchContainer = document.createElement('div');\n searchContainer.className = 'tbw-filter-search';\n\n const searchInput = document.createElement('input');\n searchInput.type = 'text';\n searchInput.placeholder = 'Search...';\n searchInput.className = 'tbw-filter-search-input';\n searchInput.value = this.searchText.get(field) ?? '';\n searchContainer.appendChild(searchInput);\n panel.appendChild(searchContainer);\n\n // Select All tristate checkbox\n const actionsRow = document.createElement('div');\n actionsRow.className = 'tbw-filter-actions';\n\n const selectAllLabel = document.createElement('label');\n selectAllLabel.className = 'tbw-filter-value-item';\n selectAllLabel.style.padding = '0';\n selectAllLabel.style.margin = '0';\n\n const selectAllCheckbox = document.createElement('input');\n selectAllCheckbox.type = 'checkbox';\n selectAllCheckbox.className = 'tbw-filter-checkbox';\n\n const selectAllText = document.createElement('span');\n selectAllText.textContent = 'Select All';\n\n selectAllLabel.appendChild(selectAllCheckbox);\n selectAllLabel.appendChild(selectAllText);\n actionsRow.appendChild(selectAllLabel);\n\n // Update tristate checkbox based on checkState\n const updateSelectAllState = () => {\n const values = [...checkState.values()];\n const allChecked = values.every((v) => v);\n const noneChecked = values.every((v) => !v);\n\n selectAllCheckbox.checked = allChecked;\n selectAllCheckbox.indeterminate = !allChecked && !noneChecked;\n };\n\n // Toggle all on click\n selectAllCheckbox.addEventListener('change', () => {\n const newState = selectAllCheckbox.checked;\n for (const key of checkState.keys()) {\n checkState.set(key, newState);\n }\n updateSelectAllState();\n renderVisibleItems();\n });\n\n panel.appendChild(actionsRow);\n\n // Values container with virtualization support\n const valuesContainer = document.createElement('div');\n valuesContainer.className = 'tbw-filter-values';\n\n // Spacer for virtual height\n const spacer = document.createElement('div');\n spacer.className = 'tbw-filter-values-spacer';\n valuesContainer.appendChild(spacer);\n\n // Content container positioned absolutely\n const contentContainer = document.createElement('div');\n contentContainer.className = 'tbw-filter-values-content';\n valuesContainer.appendChild(contentContainer);\n\n // Track current check state for values (persists across virtualizations)\n const checkState = new Map<string, boolean>();\n uniqueValues.forEach((value) => {\n const key = value == null ? '__null__' : String(value);\n checkState.set(key, !excludedValues.has(value));\n });\n\n // Initialize select all state\n updateSelectAllState();\n\n // Filtered values cache\n let filteredValues: unknown[] = [];\n\n // Create a single checkbox item element\n const createItem = (value: unknown, index: number): HTMLElement => {\n const strValue = value == null ? '(Blank)' : String(value);\n const key = value == null ? '__null__' : String(value);\n\n const item = document.createElement('label');\n item.className = 'tbw-filter-value-item';\n item.style.position = 'absolute';\n item.style.top = `${index * FilteringPlugin.LIST_ITEM_HEIGHT}px`;\n item.style.left = '0';\n item.style.right = '0';\n item.style.height = `${FilteringPlugin.LIST_ITEM_HEIGHT}px`;\n item.style.boxSizing = 'border-box';\n\n const checkbox = document.createElement('input');\n checkbox.type = 'checkbox';\n checkbox.className = 'tbw-filter-checkbox';\n checkbox.checked = checkState.get(key) ?? true;\n checkbox.dataset.value = key;\n\n // Sync check state on change and update tristate checkbox\n checkbox.addEventListener('change', () => {\n checkState.set(key, checkbox.checked);\n updateSelectAllState();\n });\n\n const label = document.createElement('span');\n label.textContent = strValue;\n\n item.appendChild(checkbox);\n item.appendChild(label);\n return item;\n };\n\n // Render visible items using virtualization\n const renderVisibleItems = () => {\n const totalItems = filteredValues.length;\n const viewportHeight = valuesContainer.clientHeight;\n const scrollTop = valuesContainer.scrollTop;\n\n // Set total height for scrollbar\n spacer.style.height = `${totalItems * FilteringPlugin.LIST_ITEM_HEIGHT}px`;\n\n // Bypass virtualization for small lists\n if (shouldBypassVirtualization(totalItems, FilteringPlugin.LIST_BYPASS_THRESHOLD / 3)) {\n contentContainer.innerHTML = '';\n contentContainer.style.transform = 'translateY(0px)';\n filteredValues.forEach((value, idx) => {\n contentContainer.appendChild(createItem(value, idx));\n });\n return;\n }\n\n // Use computeVirtualWindow for real-scroll virtualization\n const window = computeVirtualWindow({\n totalRows: totalItems,\n viewportHeight,\n scrollTop,\n rowHeight: FilteringPlugin.LIST_ITEM_HEIGHT,\n overscan: FilteringPlugin.LIST_OVERSCAN,\n });\n\n // Position content container\n contentContainer.style.transform = `translateY(${window.offsetY}px)`;\n\n // Clear and render visible items\n contentContainer.innerHTML = '';\n for (let i = window.start; i < window.end; i++) {\n contentContainer.appendChild(createItem(filteredValues[i], i - window.start));\n }\n };\n\n // Filter and re-render values\n const renderValues = (filterText: string) => {\n const lowerFilter = filterText.toLowerCase();\n\n // Filter the unique values\n filteredValues = uniqueValues.filter((value) => {\n const strValue = value == null ? '(Blank)' : String(value);\n return !filterText || strValue.toLowerCase().includes(lowerFilter);\n });\n\n if (filteredValues.length === 0) {\n spacer.style.height = '0px';\n contentContainer.innerHTML = '';\n const noMatch = document.createElement('div');\n noMatch.className = 'tbw-filter-no-match';\n noMatch.textContent = 'No matching values';\n contentContainer.appendChild(noMatch);\n return;\n }\n\n renderVisibleItems();\n };\n\n // Scroll handler for virtualization\n valuesContainer.addEventListener(\n 'scroll',\n () => {\n if (filteredValues.length > 0) {\n renderVisibleItems();\n }\n },\n { passive: true }\n );\n\n renderValues(searchInput.value);\n panel.appendChild(valuesContainer);\n\n // Debounced search\n let debounceTimer: ReturnType<typeof setTimeout>;\n searchInput.addEventListener('input', () => {\n clearTimeout(debounceTimer);\n debounceTimer = setTimeout(() => {\n this.searchText.set(field, searchInput.value);\n renderValues(searchInput.value);\n }, this.config.debounceMs ?? 150);\n });\n\n // Apply/Clear buttons\n const buttonRow = document.createElement('div');\n buttonRow.className = 'tbw-filter-buttons';\n\n const applyBtn = document.createElement('button');\n applyBtn.className = 'tbw-filter-apply-btn';\n applyBtn.textContent = 'Apply';\n applyBtn.addEventListener('click', () => {\n // Read from checkState map (works with virtualization)\n const excluded: unknown[] = [];\n for (const [key, isChecked] of checkState) {\n if (!isChecked) {\n if (key === '__null__') {\n excluded.push(null);\n } else {\n // Try to match original value type\n const original = uniqueValues.find((v) => String(v) === key);\n excluded.push(original !== undefined ? original : key);\n }\n }\n }\n params.applySetFilter(excluded);\n });\n buttonRow.appendChild(applyBtn);\n\n const clearBtn = document.createElement('button');\n clearBtn.className = 'tbw-filter-clear-btn';\n clearBtn.textContent = 'Clear Filter';\n clearBtn.addEventListener('click', () => {\n params.clearFilter();\n });\n buttonRow.appendChild(clearBtn);\n\n panel.appendChild(buttonRow);\n }\n\n /**\n * Apply a set filter (exclude values)\n */\n private applySetFilter(field: string, excluded: unknown[]): void {\n // Store excluded values\n this.excludedValues.set(field, new Set(excluded));\n\n if (excluded.length === 0) {\n // No exclusions = no filter\n this.filters.delete(field);\n } else {\n // Create \"notIn\" filter\n this.filters.set(field, {\n field,\n type: 'set',\n operator: 'notIn',\n value: excluded,\n });\n }\n\n this.cachedResult = null;\n this.cacheKey = null;\n\n this.emit<FilterChangeDetail>('filter-change', {\n filters: [...this.filters.values()],\n filteredRowCount: 0,\n });\n this.requestRender();\n }\n\n /**\n * Apply a text filter\n */\n private applyTextFilter(field: string, operator: FilterModel['operator'], value: string, valueTo?: string): void {\n this.filters.set(field, {\n field,\n type: 'text',\n operator,\n value,\n valueTo,\n });\n\n this.cachedResult = null;\n this.cacheKey = null;\n\n this.emit<FilterChangeDetail>('filter-change', {\n filters: [...this.filters.values()],\n filteredRowCount: 0,\n });\n this.requestRender();\n }\n\n // ===== Column State Hooks =====\n\n /**\n * Return filter state for a column if it has an active filter.\n */\n override getColumnState(field: string): Partial<ColumnState> | undefined {\n const filterModel = this.filters.get(field);\n if (!filterModel) return undefined;\n\n return {\n filter: {\n type: filterModel.type,\n operator: filterModel.operator,\n value: filterModel.value,\n valueTo: filterModel.valueTo,\n },\n };\n }\n\n /**\n * Apply filter state from column state.\n */\n override applyColumnState(field: string, state: ColumnState): void {\n // Only process if the column has filter state\n if (!state.filter) {\n this.filters.delete(field);\n return;\n }\n\n // Reconstruct the FilterModel from the stored state\n const filterModel: FilterModel = {\n field,\n type: state.filter.type,\n operator: state.filter.operator as FilterModel['operator'],\n value: state.filter.value,\n valueTo: state.filter.valueTo,\n };\n\n this.filters.set(field, filterModel);\n // Invalidate cache so filter is reapplied\n this.cachedResult = null;\n this.cacheKey = null;\n }\n\n // ===== Styles =====\n\n override readonly styles = `\n .header-cell.filtered::before {\n content: '';\n position: absolute;\n top: 4px;\n right: 4px;\n width: 6px;\n height: 6px;\n background: var(--tbw-filter-accent, var(--tbw-color-accent, #3b82f6));\n border-radius: 50%;\n }\n .tbw-filter-btn {\n display: inline-flex;\n align-items: center;\n justify-content: center;\n background: transparent;\n border: none;\n cursor: pointer;\n padding: 2px;\n margin-left: 4px;\n opacity: 0.4;\n transition: opacity 0.15s;\n color: inherit;\n vertical-align: middle;\n }\n .tbw-filter-btn:hover,\n .tbw-filter-btn.active {\n opacity: 1;\n }\n .tbw-filter-btn.active {\n color: var(--tbw-filter-accent, var(--tbw-color-accent, #3b82f6));\n }\n `;\n}\n","/**\n * Column Groups Core Logic\n *\n * Pure functions for computing and managing column header groups.\n */\n\n/* eslint-disable @typescript-eslint/no-explicit-any */\n\nimport type { ColumnConfig } from '../../core/types';\nimport type { ColumnGroup, ColumnGroupInternal } from './types';\n\n/**\n * Compute column groups from column configuration.\n * Handles explicit groups (via column.group) and creates implicit groups for ungrouped columns.\n *\n * @param columns - Array of column configurations\n * @returns Array of column groups, or empty if no meaningful groups\n */\nexport function computeColumnGroups<T>(columns: ColumnConfig<T>[]): ColumnGroup<T>[] {\n if (!columns.length) return [];\n\n const explicitMap = new Map<string, ColumnGroupInternal<T>>();\n const groupsOrdered: ColumnGroupInternal<T>[] = [];\n\n // Helper to push unnamed implicit group for a run of ungrouped columns\n const pushImplicit = (startIdx: number, cols: ColumnConfig<T>[]) => {\n if (!cols.length) return;\n // Merge with previous implicit group if adjacent to reduce noise\n const prev = groupsOrdered[groupsOrdered.length - 1];\n if (prev && prev.implicit && prev.firstIndex + prev.columns.length === startIdx) {\n prev.columns.push(...cols);\n return;\n }\n groupsOrdered.push({\n id: '__implicit__' + startIdx,\n label: undefined,\n columns: cols,\n firstIndex: startIdx,\n implicit: true,\n });\n };\n\n let run: ColumnConfig<T>[] = [];\n let runStart = 0;\n\n columns.forEach((col, idx) => {\n const g: any = (col as any).group;\n if (!g) {\n if (run.length === 0) runStart = idx;\n run.push(col);\n return;\n }\n // Close any pending implicit run\n if (run.length) {\n pushImplicit(runStart, run.slice());\n run = [];\n }\n const id = typeof g === 'string' ? g : g.id;\n let group = explicitMap.get(id);\n if (!group) {\n group = {\n id,\n label: typeof g === 'string' ? undefined : g.label,\n columns: [],\n firstIndex: idx,\n };\n explicitMap.set(id, group);\n groupsOrdered.push(group);\n }\n group.columns.push(col);\n });\n\n // Trailing implicit run\n if (run.length) pushImplicit(runStart, run);\n\n // If we only have a single implicit group covering all columns, treat as no groups\n if (\n groupsOrdered.length === 1 &&\n groupsOrdered[0].implicit &&\n groupsOrdered[0].columns.length === columns.length\n ) {\n return [];\n }\n\n return groupsOrdered as ColumnGroup<T>[];\n}\n\n/**\n * Apply CSS classes to header cells based on their group membership.\n *\n * @param headerRowEl - The header row element\n * @param groups - The computed column groups\n * @param columns - The column configurations\n */\nexport function applyGroupedHeaderCellClasses(\n headerRowEl: HTMLElement | null,\n groups: ColumnGroup[],\n columns: ColumnConfig<any>[]\n): void {\n if (!groups.length || !headerRowEl) return;\n\n const fieldToGroup = new Map<string, string>();\n for (const g of groups) {\n for (const c of g.columns) {\n if ((c as any)?.field) {\n fieldToGroup.set((c as any).field, g.id);\n }\n }\n }\n\n const headerCells = Array.from(headerRowEl.querySelectorAll('.cell[data-field]')) as HTMLElement[];\n headerCells.forEach((cell) => {\n const f = cell.getAttribute('data-field') || '';\n const gid = fieldToGroup.get(f);\n if (gid) {\n cell.classList.add('grouped');\n if (!cell.getAttribute('data-group')) {\n cell.setAttribute('data-group', gid);\n }\n }\n });\n\n // Mark group end cells for styling\n for (const g of groups) {\n const last = g.columns[g.columns.length - 1];\n const cell = headerCells.find((c) => c.getAttribute('data-field') === (last as any).field);\n if (cell) cell.classList.add('group-end');\n }\n}\n\n/**\n * Build the group header row element.\n *\n * @param groups - The computed column groups\n * @param columns - The column configurations\n * @returns The group header row element, or null if no groups\n */\nexport function buildGroupHeaderRow(\n groups: ColumnGroup[],\n columns: ColumnConfig<any>[]\n): HTMLElement | null {\n if (groups.length === 0) return null;\n\n const groupRow = document.createElement('div');\n groupRow.className = 'header-group-row';\n groupRow.setAttribute('role', 'row');\n\n for (const g of groups) {\n const startIndex =\n g.firstIndex != null\n ? g.firstIndex\n : columns.findIndex((c) => (g.columns as any[]).includes(c));\n\n const isImplicit = String(g.id).startsWith('__implicit__');\n const label = isImplicit ? '' : g.label || g.id;\n\n const cell = document.createElement('div');\n cell.className = 'cell header-group-cell';\n if (isImplicit) cell.classList.add('implicit-group');\n cell.setAttribute('data-group', String(g.id));\n cell.style.gridColumn = `${startIndex + 1} / span ${g.columns.length}`;\n cell.textContent = label;\n groupRow.appendChild(cell);\n }\n\n return groupRow;\n}\n\n/**\n * Check if any columns have group configuration.\n *\n * @param columns - The column configurations\n * @returns True if at least one column has a group\n */\nexport function hasColumnGroups(columns: ColumnConfig<any>[]): boolean {\n return columns.some((col) => (col as any).group != null);\n}\n\n/**\n * Get group ID for a specific column.\n *\n * @param column - The column configuration\n * @returns The group ID, or undefined if not grouped\n */\nexport function getColumnGroupId(column: ColumnConfig<any>): string | undefined {\n const g = (column as any).group;\n if (!g) return undefined;\n return typeof g === 'string' ? g : g.id;\n}\n","/**\n * Column Groups Plugin (Class-based)\n *\n * Enables multi-level column header grouping.\n */\n\n/* eslint-disable @typescript-eslint/no-explicit-any */\n\nimport { BaseGridPlugin } from '../../core/plugin/base-plugin';\nimport type { ColumnConfig } from '../../core/types';\nimport {\n applyGroupedHeaderCellClasses,\n buildGroupHeaderRow,\n computeColumnGroups,\n hasColumnGroups,\n} from './grouping-columns';\nimport type { ColumnGroup, GroupingColumnsConfig } from './types';\n\n/**\n * Column Groups Plugin for tbw-grid\n *\n * @example\n * ```ts\n * new GroupingColumnsPlugin({\n * enabled: true,\n * showGroupBorders: true,\n * })\n * ```\n */\nexport class GroupingColumnsPlugin extends BaseGridPlugin<GroupingColumnsConfig> {\n readonly name = 'groupingColumns';\n override readonly version = '1.0.0';\n\n protected override get defaultConfig(): Partial<GroupingColumnsConfig> {\n return {\n enabled: true,\n showGroupBorders: true,\n };\n }\n\n // ===== Internal State =====\n private groups: ColumnGroup[] = [];\n private isActive = false;\n\n // ===== Lifecycle =====\n\n override detach(): void {\n this.groups = [];\n this.isActive = false;\n }\n\n // ===== Static Detection =====\n\n /**\n * Auto-detect column groups from column configuration.\n */\n static detect(rows: readonly any[], config: any): boolean {\n const columns = config?.columns;\n if (!Array.isArray(columns)) return false;\n return hasColumnGroups(columns);\n }\n\n // ===== Hooks =====\n\n override processColumns(columns: readonly ColumnConfig[]): ColumnConfig[] {\n if (!this.config.enabled) {\n this.isActive = false;\n this.groups = [];\n return [...columns];\n }\n\n // Compute groups from column definitions\n const groups = computeColumnGroups(columns as ColumnConfig[]);\n\n if (groups.length === 0) {\n this.isActive = false;\n this.groups = [];\n return [...columns];\n }\n\n this.isActive = true;\n this.groups = groups;\n\n // Return columns unchanged - the afterRender hook will add the group header\n return [...columns];\n }\n\n override afterRender(): void {\n if (!this.isActive || this.groups.length === 0) {\n // Remove any existing group header\n const header = this.shadowRoot?.querySelector('.header');\n const existingGroupRow = header?.querySelector('.header-group-row');\n if (existingGroupRow) existingGroupRow.remove();\n return;\n }\n\n const header = this.shadowRoot?.querySelector('.header');\n if (!header) return;\n\n // Remove existing group row if present\n const existingGroupRow = header.querySelector('.header-group-row');\n if (existingGroupRow) existingGroupRow.remove();\n\n // Build and insert group header row\n const groupRow = buildGroupHeaderRow(this.groups, this.columns as ColumnConfig[]);\n if (groupRow) {\n const headerRow = header.querySelector('.header-row');\n if (headerRow) {\n header.insertBefore(groupRow, headerRow);\n } else {\n header.appendChild(groupRow);\n }\n }\n\n // Apply classes to header cells\n const headerRow = header.querySelector('.header-row') as HTMLElement;\n if (headerRow) {\n applyGroupedHeaderCellClasses(headerRow, this.groups, this.columns as ColumnConfig[]);\n }\n }\n\n // ===== Public API =====\n\n /**\n * Check if column groups are active.\n * @returns Whether grouping is active\n */\n isGroupingActive(): boolean {\n return this.isActive;\n }\n\n /**\n * Get the computed column groups.\n * @returns Array of column groups\n */\n getGroups(): ColumnGroup[] {\n return this.groups;\n }\n\n /**\n * Get columns in a specific group.\n * @param groupId - The group ID to find\n * @returns Array of columns in the group\n */\n getGroupColumns(groupId: string): ColumnConfig[] {\n const group = this.groups.find((g) => g.id === groupId);\n return group ? group.columns : [];\n }\n\n /**\n * Refresh column groups (recompute from current columns).\n */\n refresh(): void {\n this.requestRender();\n }\n\n // ===== Styles =====\n\n override readonly styles = `\n .header-group-row {\n display: grid;\n grid-auto-flow: column;\n background: var(--tbw-grouping-columns-header-bg, var(--tbw-color-header-bg));\n border-bottom: 1px solid var(--tbw-grouping-columns-border, var(--tbw-color-border));\n }\n .header-group-cell {\n display: flex;\n align-items: center;\n justify-content: center;\n padding: 4px 8px;\n font-weight: 600;\n font-size: 0.9em;\n text-transform: uppercase;\n letter-spacing: 0.5px;\n border-right: 1px solid var(--tbw-grouping-columns-border, var(--tbw-color-border));\n }\n .header-group-cell:last-child {\n border-right: none;\n }\n .header-row .cell.grouped {\n border-top: none;\n }\n .header-row .cell.group-end {\n border-right: 2px solid var(--tbw-grouping-columns-separator, var(--tbw-color-border-strong));\n }\n `;\n}\n","/**\n * Row Grouping Core Logic\n *\n * Pure functions for building grouped row models and aggregations.\n */\n\n/* eslint-disable @typescript-eslint/no-explicit-any */\n\nimport type { RenderRow, RowGroupingConfig } from './types';\n\n// Re-export aggregator functions from core for backward compatibility\nexport {\n getAggregator,\n listAggregators,\n registerAggregator,\n runAggregator,\n} from '../../core/internal/aggregators';\n\ninterface GroupNode {\n key: string; // composite key\n value: any;\n depth: number;\n rows: any[];\n children: Map<string, GroupNode>;\n parent?: GroupNode;\n}\n\ninterface BuildGroupingArgs {\n rows: any[];\n config: RowGroupingConfig;\n expanded: Set<string>;\n}\n\n/**\n * Build a flattened grouping projection (collapsed by default).\n * Returns empty array when grouping disabled or all rows ungrouped.\n *\n * @param args - The grouping arguments\n * @returns Flattened array of render rows (groups + data rows)\n */\nexport function buildGroupedRowModel({ rows, config, expanded }: BuildGroupingArgs): RenderRow[] {\n const groupOn = config.groupOn;\n if (!config.enabled || typeof groupOn !== 'function') {\n return [];\n }\n\n const root: GroupNode = { key: '__root__', value: null, depth: -1, rows: [], children: new Map() };\n\n // Build tree structure\n rows.forEach((r) => {\n let path: any = groupOn(r);\n if (path == null || path === false) path = ['__ungrouped__'];\n else if (!Array.isArray(path)) path = [path];\n\n let parent = root;\n path.forEach((rawVal: any, depthIdx: number) => {\n const seg = rawVal == null ? '∅' : String(rawVal);\n const composite = parent.key === '__root__' ? seg : parent.key + '||' + seg;\n let node = parent.children.get(seg);\n if (!node) {\n node = { key: composite, value: rawVal, depth: depthIdx, rows: [], children: new Map(), parent };\n parent.children.set(seg, node);\n }\n parent = node;\n });\n parent.rows.push(r);\n });\n\n // All ungrouped? treat as no grouping\n if (root.children.size === 1 && root.children.has('__ungrouped__')) {\n const only = root.children.get('__ungrouped__')!;\n if (only.rows.length === rows.length) return [];\n }\n\n // Flatten tree to array\n const flat: RenderRow[] = [];\n const visit = (node: GroupNode) => {\n if (node === root) {\n node.children.forEach((c) => visit(c));\n return;\n }\n\n const isExpanded = expanded.has(node.key);\n flat.push({\n kind: 'group',\n key: node.key,\n value: node.value,\n depth: node.depth,\n rows: node.rows,\n expanded: isExpanded,\n });\n\n if (isExpanded) {\n if (node.children.size) {\n node.children.forEach((c) => visit(c));\n } else {\n node.rows.forEach((r) => flat.push({ kind: 'data', row: r, rowIndex: rows.indexOf(r) }));\n }\n }\n };\n visit(root);\n\n return flat;\n}\n\n/**\n * Toggle expansion state for a group key.\n *\n * @param expandedKeys - Current set of expanded keys\n * @param key - The group key to toggle\n * @returns New set with toggled state\n */\nexport function toggleGroupExpansion(expandedKeys: Set<string>, key: string): Set<string> {\n const newSet = new Set(expandedKeys);\n if (newSet.has(key)) {\n newSet.delete(key);\n } else {\n newSet.add(key);\n }\n return newSet;\n}\n\n/**\n * Expand all groups.\n *\n * @param rows - The flattened render rows\n * @returns Set of all group keys\n */\nexport function expandAllGroups(rows: RenderRow[]): Set<string> {\n const keys = new Set<string>();\n for (const row of rows) {\n if (row.kind === 'group') {\n keys.add(row.key);\n }\n }\n return keys;\n}\n\n/**\n * Collapse all groups.\n *\n * @returns Empty set\n */\nexport function collapseAllGroups(): Set<string> {\n return new Set();\n}\n\n/**\n * Get all group keys from a flattened model.\n *\n * @param rows - The flattened render rows\n * @returns Array of group keys\n */\nexport function getGroupKeys(rows: RenderRow[]): string[] {\n return rows.filter((r) => r.kind === 'group').map((r) => (r as any).key);\n}\n\n/**\n * Count total rows in a group (including nested groups).\n *\n * @param groupRow - The group row\n * @returns Total row count\n */\nexport function getGroupRowCount(groupRow: RenderRow): number {\n if (groupRow.kind !== 'group') return 0;\n return groupRow.rows.length;\n}\n","/**\n * Row Grouping Plugin (Class-based)\n *\n * Enables hierarchical row grouping with expand/collapse and aggregations.\n */\n\n/* eslint-disable @typescript-eslint/no-explicit-any */\n\nimport { BaseGridPlugin, CellClickEvent } from '../../core/plugin/base-plugin';\nimport {\n buildGroupedRowModel,\n collapseAllGroups,\n expandAllGroups,\n getGroupRowCount,\n runAggregator,\n toggleGroupExpansion,\n} from './grouping-rows';\nimport type { GroupingRowsConfig, GroupRowModelItem, GroupToggleDetail, RenderRow } from './types';\n\n/**\n * Group state information returned by getGroupState()\n */\nexport interface GroupState {\n /** Whether grouping is currently active */\n isActive: boolean;\n /** Number of expanded groups */\n expandedCount: number;\n /** Total number of groups */\n totalGroups: number;\n /** Array of expanded group keys */\n expandedKeys: string[];\n}\n\n/**\n * Row Grouping Plugin for tbw-grid\n *\n * @example\n * ```ts\n * new GroupingRowsPlugin({\n * enabled: true,\n * groupOn: (row) => row.category,\n * defaultExpanded: false,\n * showRowCount: true,\n * })\n * ```\n */\nexport class GroupingRowsPlugin extends BaseGridPlugin<GroupingRowsConfig> {\n readonly name = 'groupingRows';\n override readonly version = '1.0.0';\n\n protected override get defaultConfig(): Partial<GroupingRowsConfig> {\n return {\n enabled: true,\n defaultExpanded: false,\n showRowCount: true,\n indentWidth: 20,\n aggregators: {},\n };\n }\n\n // ===== Internal State =====\n private expandedKeys: Set<string> = new Set();\n private flattenedRows: RenderRow[] = [];\n private isActive = false;\n\n // ===== Lifecycle =====\n\n override detach(): void {\n this.expandedKeys.clear();\n this.flattenedRows = [];\n this.isActive = false;\n }\n\n // ===== Hooks =====\n\n /**\n * Auto-detect grouping configuration from grid config.\n * Called by plugin system to determine if plugin should activate.\n */\n static detect(rows: readonly any[], config: any): boolean {\n return typeof config?.groupOn === 'function' || typeof config?.enableRowGrouping === 'boolean';\n }\n\n override processRows(rows: readonly any[]): any[] {\n const config = this.config;\n\n // Check if grouping is configured\n if (!config.enabled || typeof config.groupOn !== 'function') {\n this.isActive = false;\n this.flattenedRows = [];\n return [...rows];\n }\n\n // Build grouped model\n const grouped = buildGroupedRowModel({\n rows: rows as any[],\n config: config,\n expanded: this.expandedKeys,\n });\n\n // If no grouping produced, return original rows\n if (grouped.length === 0) {\n this.isActive = false;\n this.flattenedRows = [];\n return [...rows];\n }\n\n this.isActive = true;\n this.flattenedRows = grouped;\n\n // Return flattened rows for rendering\n // The grid will need to handle group rows specially\n return grouped.map((item) => {\n if (item.kind === 'group') {\n return {\n __isGroupRow: true,\n __groupKey: item.key,\n __groupValue: item.value,\n __groupDepth: item.depth,\n __groupRows: item.rows,\n __groupExpanded: item.expanded,\n __groupRowCount: getGroupRowCount(item),\n };\n }\n return item.row;\n });\n }\n\n override onCellClick(event: CellClickEvent): boolean | void {\n const row = event.row;\n\n // Check if this is a group row toggle\n if (row?.__isGroupRow) {\n const target = event.originalEvent.target as HTMLElement;\n if (target?.closest('.group-toggle')) {\n this.toggle(row.__groupKey);\n return true; // Prevent default\n }\n }\n }\n\n /**\n * Render a row. Returns true if we handled the row (group row), false otherwise.\n */\n override renderRow(row: any, rowEl: HTMLElement, _rowIndex: number): boolean {\n // Only handle group rows\n if (!row?.__isGroupRow) {\n return false;\n }\n\n const config = this.config;\n\n // If a custom renderer is provided, use it\n if (config.groupRowRenderer) {\n const toggleExpand = () => {\n this.toggle(row.__groupKey);\n };\n\n const result = config.groupRowRenderer({\n key: row.__groupKey,\n value: row.__groupValue,\n depth: row.__groupDepth,\n rows: row.__groupRows,\n expanded: row.__groupExpanded,\n toggleExpand,\n });\n\n if (result) {\n rowEl.className = 'group-row';\n (rowEl as any).__isCustomRow = true; // Mark for proper class reset on recycle\n rowEl.setAttribute('data-group-depth', String(row.__groupDepth));\n if (typeof result === 'string') {\n rowEl.innerHTML = result;\n } else {\n rowEl.innerHTML = '';\n rowEl.appendChild(result);\n }\n return true;\n }\n }\n\n // Helper to toggle expansion\n const handleToggle = () => {\n this.toggle(row.__groupKey);\n };\n\n // Default group row rendering\n rowEl.className = 'group-row';\n (rowEl as any).__isCustomRow = true; // Mark for proper class reset on recycle\n rowEl.setAttribute('data-group-depth', String(row.__groupDepth));\n rowEl.setAttribute('role', 'row');\n rowEl.setAttribute('aria-expanded', String(row.__groupExpanded));\n rowEl.style.paddingLeft = `${(row.__groupDepth || 0) * (config.indentWidth ?? 20)}px`;\n rowEl.innerHTML = '';\n\n const isFullWidth = config.fullWidth !== false; // default true\n\n if (isFullWidth) {\n this.renderFullWidthGroupRow(row, rowEl, handleToggle);\n } else {\n this.renderPerColumnGroupRow(row, rowEl, handleToggle);\n }\n\n return true;\n }\n\n override afterRender(): void {\n // No additional DOM manipulation needed for grouping\n // The renderRow hook handles all group row rendering\n }\n\n // ===== Private Rendering Helpers =====\n\n private renderFullWidthGroupRow(row: any, rowEl: HTMLElement, handleToggle: () => void): void {\n const config = this.config;\n\n // Full-width mode: single spanning cell with toggle + label + count\n const cell = document.createElement('div');\n cell.className = 'cell group-full';\n cell.style.gridColumn = '1 / -1';\n cell.setAttribute('role', 'gridcell');\n\n // Toggle button with click handler\n const btn = document.createElement('button');\n btn.type = 'button';\n btn.className = 'group-toggle';\n btn.setAttribute('aria-label', row.__groupExpanded ? 'Collapse group' : 'Expand group');\n btn.textContent = row.__groupExpanded ? '▾' : '▸';\n btn.addEventListener('click', (e) => {\n e.stopPropagation();\n handleToggle();\n });\n cell.appendChild(btn);\n\n // Group label - use formatLabel if provided\n const label = document.createElement('span');\n label.className = 'group-label';\n const labelText = config.formatLabel\n ? config.formatLabel(row.__groupValue, row.__groupDepth || 0, row.__groupKey)\n : String(row.__groupValue);\n label.textContent = labelText;\n cell.appendChild(label);\n\n // Row count\n if (config.showRowCount !== false) {\n const count = document.createElement('span');\n count.className = 'group-count';\n count.textContent = `(${row.__groupRowCount ?? row.__groupRows?.length ?? 0})`;\n cell.appendChild(count);\n }\n\n rowEl.appendChild(cell);\n }\n\n private renderPerColumnGroupRow(row: any, rowEl: HTMLElement, handleToggle: () => void): void {\n const config = this.config;\n const aggregators = config.aggregators ?? {};\n const columns = this.columns;\n const groupRows = row.__groupRows ?? [];\n\n // Get grid template from the grid element\n const gridEl = this.grid as any;\n const bodyEl = this.shadowRoot?.querySelector('.body') as HTMLElement | null;\n const gridTemplate = bodyEl?.style.gridTemplateColumns || '';\n if (gridTemplate) {\n rowEl.style.display = 'grid';\n rowEl.style.gridTemplateColumns = gridTemplate;\n }\n\n columns.forEach((col, colIdx) => {\n const cell = document.createElement('div');\n cell.className = 'cell group-cell';\n cell.setAttribute('data-col', String(colIdx));\n cell.setAttribute('role', 'gridcell');\n\n if (colIdx === 0) {\n // First column: toggle button + label\n const btn = document.createElement('button');\n btn.type = 'button';\n btn.className = 'group-toggle';\n btn.textContent = row.__groupExpanded ? '▾' : '▸';\n btn.addEventListener('click', (e) => {\n e.stopPropagation();\n handleToggle();\n });\n cell.appendChild(btn);\n\n const label = document.createElement('span');\n const firstColAgg = aggregators[col.field];\n if (firstColAgg) {\n const aggResult = runAggregator(firstColAgg, groupRows, col.field, col);\n label.textContent = aggResult != null ? String(aggResult) : String(row.__groupValue);\n } else {\n const labelText = config.formatLabel\n ? config.formatLabel(row.__groupValue, row.__groupDepth || 0, row.__groupKey)\n : String(row.__groupValue);\n label.textContent = labelText;\n }\n cell.appendChild(label);\n\n if (config.showRowCount !== false) {\n const count = document.createElement('span');\n count.className = 'group-count';\n count.textContent = ` (${groupRows.length})`;\n cell.appendChild(count);\n }\n } else {\n // Other columns: run aggregator if defined\n const aggRef = aggregators[col.field];\n if (aggRef) {\n const result = runAggregator(aggRef, groupRows, col.field, col);\n cell.textContent = result != null ? String(result) : '';\n } else {\n cell.textContent = '';\n }\n }\n\n rowEl.appendChild(cell);\n });\n }\n\n // ===== Public API =====\n\n /**\n * Expand all groups.\n */\n expandAll(): void {\n this.expandedKeys = expandAllGroups(this.flattenedRows);\n this.requestRender();\n }\n\n /**\n * Collapse all groups.\n */\n collapseAll(): void {\n this.expandedKeys = collapseAllGroups();\n this.requestRender();\n }\n\n /**\n * Toggle expansion of a specific group.\n * @param key - The group key to toggle\n */\n toggle(key: string): void {\n this.expandedKeys = toggleGroupExpansion(this.expandedKeys, key);\n\n // Find the group to emit event details\n const group = this.flattenedRows.find((r) => r.kind === 'group' && r.key === key) as GroupRowModelItem | undefined;\n\n this.emit<GroupToggleDetail>('group-toggle', {\n key,\n expanded: this.expandedKeys.has(key),\n value: group?.value,\n depth: group?.depth ?? 0,\n });\n\n this.requestRender();\n }\n\n /**\n * Check if a specific group is expanded.\n * @param key - The group key to check\n * @returns Whether the group is expanded\n */\n isExpanded(key: string): boolean {\n return this.expandedKeys.has(key);\n }\n\n /**\n * Expand a specific group.\n * @param key - The group key to expand\n */\n expand(key: string): void {\n if (!this.expandedKeys.has(key)) {\n this.expandedKeys = new Set([...this.expandedKeys, key]);\n this.requestRender();\n }\n }\n\n /**\n * Collapse a specific group.\n * @param key - The group key to collapse\n */\n collapse(key: string): void {\n if (this.expandedKeys.has(key)) {\n const newKeys = new Set(this.expandedKeys);\n newKeys.delete(key);\n this.expandedKeys = newKeys;\n this.requestRender();\n }\n }\n\n /**\n * Get the current group state.\n * @returns Group state information\n */\n getGroupState(): GroupState {\n const groupRows = this.flattenedRows.filter((r) => r.kind === 'group');\n return {\n isActive: this.isActive,\n expandedCount: this.expandedKeys.size,\n totalGroups: groupRows.length,\n expandedKeys: [...this.expandedKeys],\n };\n }\n\n /**\n * Get the total count of visible rows (including group headers).\n * @returns Number of visible rows\n */\n getRowCount(): number {\n return this.flattenedRows.length;\n }\n\n /**\n * Refresh the grouped row model.\n * Call this after modifying groupOn or other config options.\n */\n refreshGroups(): void {\n this.requestRender();\n }\n\n /**\n * Get current expanded group keys.\n * @returns Array of expanded group keys\n */\n getExpandedGroups(): string[] {\n return [...this.expandedKeys];\n }\n\n /**\n * Get the flattened row model.\n * @returns Array of render rows (groups + data rows)\n */\n getFlattenedRows(): RenderRow[] {\n return this.flattenedRows;\n }\n\n /**\n * Check if grouping is currently active.\n * @returns Whether grouping is active\n */\n isGroupingActive(): boolean {\n return this.isActive;\n }\n\n /**\n * Set the groupOn function dynamically.\n * @param fn - The groupOn function or undefined to disable\n */\n setGroupOn(fn: ((row: any) => any[] | any | null | false) | undefined): void {\n (this.config as GroupingRowsConfig).groupOn = fn;\n this.requestRender();\n }\n\n // ===== Styles =====\n\n override readonly styles = `\n .group-row {\n background: var(--tbw-grouping-rows-bg, var(--tbw-color-panel-bg));\n font-weight: 500;\n }\n .group-row:hover {\n background: var(--tbw-grouping-rows-bg-hover, var(--tbw-color-row-hover));\n }\n .group-toggle {\n cursor: pointer;\n user-select: none;\n display: inline-flex;\n align-items: center;\n justify-content: center;\n width: 20px;\n height: 20px;\n margin-right: 4px;\n font-size: 10px;\n }\n .group-toggle:hover {\n background: var(--tbw-grouping-rows-toggle-hover, var(--tbw-color-row-hover));\n border-radius: 2px;\n }\n .group-label {\n display: inline-flex;\n align-items: center;\n gap: 8px;\n }\n .group-count {\n color: var(--tbw-grouping-rows-count-color, var(--tbw-color-fg-muted));\n font-size: 0.85em;\n font-weight: normal;\n }\n [data-group-depth=\"0\"] .group-label { padding-left: 0; }\n [data-group-depth=\"1\"] .group-label { padding-left: 20px; }\n [data-group-depth=\"2\"] .group-label { padding-left: 40px; }\n [data-group-depth=\"3\"] .group-label { padding-left: 60px; }\n [data-group-depth=\"4\"] .group-label { padding-left: 80px; }\n `;\n}\n","/**\n * Master/Detail Core Logic\n *\n * Pure functions for managing detail row expansion state.\n */\n\n/* eslint-disable @typescript-eslint/no-explicit-any */\n// Uses `any` for maximum flexibility with user-defined row types.\n\n/**\n * Toggle the expansion state of a detail row.\n * Returns a new Set with the updated state.\n */\nexport function toggleDetailRow(expandedRows: Set<object>, row: object): Set<object> {\n const newExpanded = new Set(expandedRows);\n if (newExpanded.has(row)) {\n newExpanded.delete(row);\n } else {\n newExpanded.add(row);\n }\n return newExpanded;\n}\n\n/**\n * Expand a detail row.\n * Returns a new Set with the row added.\n */\nexport function expandDetailRow(expandedRows: Set<object>, row: object): Set<object> {\n const newExpanded = new Set(expandedRows);\n newExpanded.add(row);\n return newExpanded;\n}\n\n/**\n * Collapse a detail row.\n * Returns a new Set with the row removed.\n */\nexport function collapseDetailRow(expandedRows: Set<object>, row: object): Set<object> {\n const newExpanded = new Set(expandedRows);\n newExpanded.delete(row);\n return newExpanded;\n}\n\n/**\n * Check if a detail row is expanded.\n */\nexport function isDetailExpanded(expandedRows: Set<object>, row: object): boolean {\n return expandedRows.has(row);\n}\n\n/**\n * Create a detail element for a given row.\n * The element spans all columns and contains the rendered content.\n */\nexport function createDetailElement(\n row: any,\n rowIndex: number,\n renderer: (row: any, rowIndex: number) => HTMLElement | string,\n columnCount: number\n): HTMLElement {\n const detailRow = document.createElement('div');\n detailRow.className = 'master-detail-row';\n detailRow.setAttribute('data-detail-for', String(rowIndex));\n detailRow.setAttribute('role', 'row');\n\n const detailCell = document.createElement('div');\n detailCell.className = 'master-detail-cell';\n detailCell.setAttribute('role', 'cell');\n detailCell.style.gridColumn = `1 / ${columnCount + 1}`;\n\n const content = renderer(row, rowIndex);\n if (typeof content === 'string') {\n detailCell.innerHTML = content;\n } else if (content instanceof HTMLElement) {\n detailCell.appendChild(content);\n }\n\n detailRow.appendChild(detailCell);\n return detailRow;\n}\n","/**\n * Master/Detail Plugin (Class-based)\n *\n * Enables expandable detail rows showing additional content for each row.\n */\n\n/* eslint-disable @typescript-eslint/no-explicit-any */\n\nimport { BaseGridPlugin, RowClickEvent } from '../../core/plugin/base-plugin';\nimport {\n collapseDetailRow,\n createDetailElement,\n expandDetailRow,\n isDetailExpanded,\n toggleDetailRow,\n} from './master-detail';\nimport type { DetailExpandDetail, MasterDetailConfig } from './types';\n\n/**\n * Master/Detail Plugin for tbw-grid\n *\n * @example\n * ```ts\n * new MasterDetailPlugin({\n * enabled: true,\n * detailRenderer: (row) => `<div>Details for ${row.name}</div>`,\n * expandOnRowClick: true,\n * })\n * ```\n */\nexport class MasterDetailPlugin extends BaseGridPlugin<MasterDetailConfig> {\n readonly name = 'masterDetail';\n override readonly version = '1.0.0';\n\n protected override get defaultConfig(): Partial<MasterDetailConfig> {\n return {\n enabled: true,\n detailHeight: 'auto',\n expandOnRowClick: false,\n collapseOnClickOutside: false,\n showExpandColumn: true,\n };\n }\n\n // ===== Internal State =====\n private expandedRows: Set<any> = new Set();\n private detailElements: Map<any, HTMLElement> = new Map();\n\n // ===== Lifecycle =====\n\n override detach(): void {\n this.expandedRows.clear();\n this.detailElements.clear();\n }\n\n // ===== Hooks =====\n\n override processColumns(\n columns: readonly import('../../core/types').ColumnConfig[]\n ): import('../../core/types').ColumnConfig[] {\n if (!this.config.detailRenderer) {\n return [...columns];\n }\n\n // Wrap first column's renderer to add expand/collapse toggle\n const cols = [...columns];\n if (cols.length > 0) {\n const firstCol = { ...cols[0] };\n const originalRenderer = firstCol.viewRenderer;\n\n firstCol.viewRenderer = (renderCtx) => {\n const { value, row } = renderCtx;\n const isExpanded = this.expandedRows.has(row);\n\n const container = document.createElement('span');\n container.className = 'master-detail-cell-wrapper';\n\n // Expand/collapse toggle icon\n const toggle = document.createElement('span');\n toggle.className = 'master-detail-toggle';\n toggle.textContent = isExpanded ? '▼' : '▶';\n toggle.setAttribute('aria-expanded', String(isExpanded));\n toggle.setAttribute('aria-label', isExpanded ? 'Collapse details' : 'Expand details');\n toggle.addEventListener('click', (e) => {\n e.stopPropagation();\n const rowIndex = this.rows.indexOf(row);\n this.expandedRows = toggleDetailRow(this.expandedRows, row);\n this.emit<DetailExpandDetail>('detail-expand', {\n rowIndex,\n row,\n expanded: this.expandedRows.has(row),\n });\n this.requestRender();\n });\n container.appendChild(toggle);\n\n // Cell content\n const content = document.createElement('span');\n if (originalRenderer) {\n const rendered = originalRenderer(renderCtx);\n if (rendered instanceof Node) {\n content.appendChild(rendered);\n } else {\n content.textContent = String(rendered ?? value ?? '');\n }\n } else {\n content.textContent = String(value ?? '');\n }\n container.appendChild(content);\n\n return container;\n };\n\n cols[0] = firstCol;\n }\n\n return cols;\n }\n\n override onRowClick(event: RowClickEvent): boolean | void {\n if (!this.config.expandOnRowClick || !this.config.detailRenderer) return;\n\n this.expandedRows = toggleDetailRow(this.expandedRows, event.row);\n\n this.emit<DetailExpandDetail>('detail-expand', {\n rowIndex: event.rowIndex,\n row: event.row,\n expanded: this.expandedRows.has(event.row),\n });\n\n this.requestRender();\n return false;\n }\n\n override afterRender(): void {\n if (!this.config.detailRenderer) return;\n\n const body = this.shadowRoot?.querySelector('.rows');\n if (!body) return;\n\n // Remove old detail rows\n body.querySelectorAll('.master-detail-row').forEach((el) => el.remove());\n this.detailElements.clear();\n\n // Insert detail rows as last child of expanded row elements\n const dataRows = body.querySelectorAll('.data-grid-row');\n const columnCount = this.columns.length;\n\n for (const rowEl of dataRows) {\n const firstCell = rowEl.querySelector('.cell[data-row]');\n const rowIndex = firstCell ? parseInt(firstCell.getAttribute('data-row') ?? '-1', 10) : -1;\n if (rowIndex < 0) continue;\n\n const row = this.rows[rowIndex];\n if (!row || !this.expandedRows.has(row)) continue;\n\n const detailEl = createDetailElement(row, rowIndex, this.config.detailRenderer, columnCount);\n\n if (typeof this.config.detailHeight === 'number') {\n detailEl.style.height = `${this.config.detailHeight}px`;\n }\n\n rowEl.appendChild(detailEl);\n this.detailElements.set(row, detailEl);\n }\n }\n\n // ===== Public API =====\n\n /**\n * Expand the detail row at the given index.\n * @param rowIndex - Index of the row to expand\n */\n expand(rowIndex: number): void {\n const row = this.rows[rowIndex];\n if (row) {\n this.expandedRows = expandDetailRow(this.expandedRows, row);\n this.requestRender();\n }\n }\n\n /**\n * Collapse the detail row at the given index.\n * @param rowIndex - Index of the row to collapse\n */\n collapse(rowIndex: number): void {\n const row = this.rows[rowIndex];\n if (row) {\n this.expandedRows = collapseDetailRow(this.expandedRows, row);\n this.requestRender();\n }\n }\n\n /**\n * Toggle the detail row at the given index.\n * @param rowIndex - Index of the row to toggle\n */\n toggle(rowIndex: number): void {\n const row = this.rows[rowIndex];\n if (row) {\n this.expandedRows = toggleDetailRow(this.expandedRows, row);\n this.requestRender();\n }\n }\n\n /**\n * Check if the detail row at the given index is expanded.\n * @param rowIndex - Index of the row to check\n * @returns Whether the detail row is expanded\n */\n isExpanded(rowIndex: number): boolean {\n const row = this.rows[rowIndex];\n return row ? isDetailExpanded(this.expandedRows, row) : false;\n }\n\n /**\n * Expand all detail rows.\n */\n expandAll(): void {\n for (const row of this.rows) {\n this.expandedRows.add(row);\n }\n this.requestRender();\n }\n\n /**\n * Collapse all detail rows.\n */\n collapseAll(): void {\n this.expandedRows.clear();\n this.requestRender();\n }\n\n /**\n * Get the indices of all expanded rows.\n * @returns Array of row indices that are expanded\n */\n getExpandedRows(): number[] {\n const indices: number[] = [];\n for (const row of this.expandedRows) {\n const idx = this.rows.indexOf(row);\n if (idx >= 0) indices.push(idx);\n }\n return indices;\n }\n\n /**\n * Get the detail element for a specific row.\n * @param rowIndex - Index of the row\n * @returns The detail HTMLElement or undefined\n */\n getDetailElement(rowIndex: number): HTMLElement | undefined {\n const row = this.rows[rowIndex];\n return row ? this.detailElements.get(row) : undefined;\n }\n\n // ===== Styles =====\n\n override readonly styles = `\n .master-detail-cell-wrapper {\n display: flex;\n align-items: center;\n gap: 4px;\n }\n .master-detail-toggle {\n cursor: pointer;\n font-size: 10px;\n opacity: 0.7;\n user-select: none;\n }\n .master-detail-toggle:hover {\n opacity: 1;\n }\n .master-detail-row {\n grid-column: 1 / -1;\n display: grid;\n background: var(--tbw-master-detail-bg, var(--tbw-color-row-alt));\n border-bottom: 1px solid var(--tbw-master-detail-border, var(--tbw-color-border));\n }\n .master-detail-cell {\n padding: 16px;\n overflow: auto;\n }\n `;\n}\n","/**\n * Multi-Sort Core Logic\n *\n * Pure functions for multi-column sorting operations.\n */\n\nimport type { ColumnConfig } from '../../core/types';\nimport type { SortModel } from './types';\n\n/**\n * Apply multiple sort columns to a row array.\n * Sorts are applied in order - first sort has highest priority.\n *\n * @param rows - Array of row objects to sort\n * @param sorts - Ordered array of sort configurations\n * @param columns - Column configurations (for custom comparators)\n * @returns New sorted array (does not mutate original)\n */\nexport function applySorts<TRow = unknown>(rows: TRow[], sorts: SortModel[], columns: ColumnConfig<TRow>[]): TRow[] {\n if (!sorts.length) return [...rows];\n\n return [...rows].sort((a, b) => {\n for (const sort of sorts) {\n const col = columns.find((c) => c.field === sort.field);\n const comparator = col?.sortComparator ?? defaultComparator;\n const aVal = (a as Record<string, unknown>)[sort.field];\n const bVal = (b as Record<string, unknown>)[sort.field];\n const result = comparator(aVal, bVal, a, b);\n if (result !== 0) {\n return sort.direction === 'asc' ? result : -result;\n }\n }\n return 0;\n });\n}\n\n/**\n * Default comparator for sorting values.\n * Handles nulls, numbers, dates, and strings.\n *\n * @param a - First value\n * @param b - Second value\n * @returns Comparison result (-1, 0, 1)\n */\nexport function defaultComparator(a: unknown, b: unknown): number {\n // Handle nulls/undefined - push to end\n if (a == null && b == null) return 0;\n if (a == null) return 1;\n if (b == null) return -1;\n\n // Type-aware comparison\n if (typeof a === 'number' && typeof b === 'number') {\n return a - b;\n }\n\n if (a instanceof Date && b instanceof Date) {\n return a.getTime() - b.getTime();\n }\n\n // Boolean comparison\n if (typeof a === 'boolean' && typeof b === 'boolean') {\n return a === b ? 0 : a ? -1 : 1;\n }\n\n // String comparison (fallback)\n return String(a).localeCompare(String(b));\n}\n\n/**\n * Toggle sort state for a field.\n * With shift key: adds/toggles in multi-sort list\n * Without shift key: replaces entire sort with single column\n *\n * @param current - Current sort model\n * @param field - Field to toggle\n * @param shiftKey - Whether shift key is held (multi-sort mode)\n * @param maxColumns - Maximum columns allowed in sort\n * @returns New sort model\n */\nexport function toggleSort(current: SortModel[], field: string, shiftKey: boolean, maxColumns: number): SortModel[] {\n const existing = current.find((s) => s.field === field);\n\n if (shiftKey) {\n // Multi-sort: add/toggle in list\n if (existing) {\n if (existing.direction === 'asc') {\n // Flip to descending\n return current.map((s) => (s.field === field ? { ...s, direction: 'desc' as const } : s));\n } else {\n // Remove from sort\n return current.filter((s) => s.field !== field);\n }\n } else if (current.length < maxColumns) {\n // Add new sort column\n return [...current, { field, direction: 'asc' as const }];\n }\n // Max columns reached, return unchanged\n return current;\n } else {\n // Single sort: replace all\n if (existing?.direction === 'asc') {\n return [{ field, direction: 'desc' }];\n } else if (existing?.direction === 'desc') {\n return [];\n }\n return [{ field, direction: 'asc' }];\n }\n}\n\n/**\n * Get the sort index (1-based) for a field in the sort model.\n * Returns undefined if the field is not in the sort model.\n *\n * @param sortModel - Current sort model\n * @param field - Field to check\n * @returns 1-based index or undefined\n */\nexport function getSortIndex(sortModel: SortModel[], field: string): number | undefined {\n const index = sortModel.findIndex((s) => s.field === field);\n return index >= 0 ? index + 1 : undefined;\n}\n\n/**\n * Get the sort direction for a field in the sort model.\n *\n * @param sortModel - Current sort model\n * @param field - Field to check\n * @returns Sort direction or undefined if not sorted\n */\nexport function getSortDirection(sortModel: SortModel[], field: string): 'asc' | 'desc' | undefined {\n return sortModel.find((s) => s.field === field)?.direction;\n}\n","/**\r\n * Multi-Sort Plugin (Class-based)\r\n *\r\n * Provides multi-column sorting capabilities for tbw-grid.\r\n * Supports shift+click for adding secondary sort columns.\r\n */\r\n\r\nimport { BaseGridPlugin, HeaderClickEvent } from '../../core/plugin/base-plugin';\r\nimport type { ColumnState } from '../../core/types';\r\nimport { applySorts, getSortDirection, getSortIndex, toggleSort } from './multi-sort';\r\nimport type { MultiSortConfig, SortModel } from './types';\r\n\r\n/**\r\n * Multi-Sort Plugin for tbw-grid\r\n *\r\n * @example\r\n * ```ts\r\n * new MultiSortPlugin({ maxSortColumns: 3, showSortIndex: true })\r\n * ```\r\n */\r\nexport class MultiSortPlugin extends BaseGridPlugin<MultiSortConfig> {\r\n readonly name = 'multiSort';\r\n override readonly version = '1.0.0';\r\n\r\n protected override get defaultConfig(): Partial<MultiSortConfig> {\r\n return {\r\n enabled: true,\r\n maxSortColumns: 3,\r\n showSortIndex: true,\r\n };\r\n }\r\n\r\n // ===== Internal State =====\r\n private sortModel: SortModel[] = [];\r\n\r\n // ===== Lifecycle =====\r\n\r\n override detach(): void {\r\n this.sortModel = [];\r\n }\r\n\r\n // ===== Hooks =====\r\n\r\n override processRows(rows: readonly unknown[]): unknown[] {\r\n if (this.sortModel.length === 0) {\r\n return [...rows];\r\n }\r\n return applySorts([...rows], this.sortModel, [...this.columns]);\r\n }\r\n\r\n override onHeaderClick(event: HeaderClickEvent): boolean {\r\n const column = this.columns.find((c) => c.field === event.field);\r\n if (!column?.sortable) return false;\r\n\r\n const shiftKey = event.originalEvent.shiftKey;\r\n const maxColumns = this.config.maxSortColumns ?? 3;\r\n\r\n this.sortModel = toggleSort(this.sortModel, event.field, shiftKey, maxColumns);\r\n\r\n this.emit('sort-change', { sortModel: [...this.sortModel] });\r\n this.requestRender();\r\n\r\n return true;\r\n }\r\n\r\n override afterRender(): void {\r\n const shadowRoot = this.shadowRoot;\r\n if (!shadowRoot) return;\r\n\r\n const showIndex = this.config.showSortIndex !== false;\r\n\r\n // Update all sortable header cells with sort indicators\r\n const headerCells = shadowRoot.querySelectorAll('.header-row .cell[data-field]');\r\n headerCells.forEach((cell) => {\r\n const field = cell.getAttribute('data-field');\r\n if (!field) return;\r\n\r\n const sortIndex = getSortIndex(this.sortModel, field);\r\n const sortDir = getSortDirection(this.sortModel, field);\r\n\r\n // Remove existing sort index badge (always clean up)\r\n const existingBadge = cell.querySelector('.sort-index');\r\n existingBadge?.remove();\r\n\r\n if (sortDir) {\r\n // Column is sorted - remove base indicator and add our own\r\n const existingIndicator = cell.querySelector('[part~=\"sort-indicator\"], .sort-indicator');\r\n existingIndicator?.remove();\r\n\r\n cell.setAttribute('data-sort', sortDir);\r\n\r\n // Add sort arrow indicator\r\n const indicator = document.createElement('span');\r\n indicator.className = 'sort-indicator';\r\n indicator.style.marginLeft = '4px';\r\n indicator.style.opacity = '0.8';\r\n indicator.textContent = sortDir === 'asc' ? '▲' : '▼';\r\n cell.appendChild(indicator);\r\n\r\n // Add sort index badge if multiple columns sorted and showSortIndex is enabled\r\n if (showIndex && this.sortModel.length > 1 && sortIndex !== undefined) {\r\n const badge = document.createElement('span');\r\n badge.className = 'sort-index';\r\n badge.textContent = String(sortIndex);\r\n cell.appendChild(badge);\r\n }\r\n } else {\r\n cell.removeAttribute('data-sort');\r\n // For unsorted columns, leave the base indicator (⇅) alone\r\n }\r\n });\r\n }\r\n\r\n // ===== Public API =====\r\n\r\n /**\r\n * Get the current sort model.\r\n * @returns Copy of the current sort model\r\n */\r\n getSortModel(): SortModel[] {\r\n return [...this.sortModel];\r\n }\r\n\r\n /**\r\n * Set the sort model programmatically.\r\n * @param model - New sort model to apply\r\n */\r\n setSortModel(model: SortModel[]): void {\r\n this.sortModel = [...model];\r\n this.emit('sort-change', { sortModel: [...model] });\r\n this.requestRender();\r\n }\r\n\r\n /**\r\n * Clear all sorting.\r\n */\r\n clearSort(): void {\r\n this.sortModel = [];\r\n this.emit('sort-change', { sortModel: [] });\r\n this.requestRender();\r\n }\r\n\r\n /**\r\n * Get the sort index (1-based) for a specific field.\r\n * @param field - Field to check\r\n * @returns 1-based index or undefined if not sorted\r\n */\r\n getSortIndex(field: string): number | undefined {\r\n return getSortIndex(this.sortModel, field);\r\n }\r\n\r\n /**\r\n * Get the sort direction for a specific field.\r\n * @param field - Field to check\r\n * @returns Sort direction or undefined if not sorted\r\n */\r\n getSortDirection(field: string): 'asc' | 'desc' | undefined {\r\n return getSortDirection(this.sortModel, field);\r\n }\r\n\r\n // ===== Column State Hooks =====\r\n\r\n /**\r\n * Return sort state for a column if it's in the sort model.\r\n */\r\n override getColumnState(field: string): Partial<ColumnState> | undefined {\r\n const index = this.sortModel.findIndex((s) => s.field === field);\r\n if (index === -1) return undefined;\r\n\r\n const sortEntry = this.sortModel[index];\r\n return {\r\n sort: {\r\n direction: sortEntry.direction,\r\n priority: index,\r\n },\r\n };\r\n }\r\n\r\n /**\r\n * Apply sort state from column state.\r\n * Rebuilds the sort model from all column states.\r\n */\r\n override applyColumnState(field: string, state: ColumnState): void {\r\n // Only process if the column has sort state\r\n if (!state.sort) {\r\n // Remove this field from sortModel if it exists\r\n this.sortModel = this.sortModel.filter((s) => s.field !== field);\r\n return;\r\n }\r\n\r\n // Find existing entry or add new one\r\n const existingIndex = this.sortModel.findIndex((s) => s.field === field);\r\n const newEntry: SortModel = {\r\n field,\r\n direction: state.sort.direction,\r\n };\r\n\r\n if (existingIndex !== -1) {\r\n // Update existing entry\r\n this.sortModel[existingIndex] = newEntry;\r\n } else {\r\n // Add at the correct priority position\r\n this.sortModel.splice(state.sort.priority, 0, newEntry);\r\n }\r\n\r\n // Re-sort the model by priority to ensure correct order\r\n // This is handled after all columns are processed, but we maintain order here\r\n }\r\n\r\n // ===== Styles =====\r\n\r\n override readonly styles = `\r\n .header-cell[data-sort=\"asc\"]::after {\r\n content: '↑';\r\n margin-left: 4px;\r\n opacity: 0.8;\r\n }\r\n .header-cell[data-sort=\"desc\"]::after {\r\n content: '↓';\r\n margin-left: 4px;\r\n opacity: 0.8;\r\n }\r\n .sort-index {\r\n font-size: 10px;\r\n background: var(--tbw-multi-sort-badge-bg, var(--tbw-color-panel-bg));\r\n color: var(--tbw-multi-sort-badge-color, var(--tbw-color-fg));\r\n border-radius: 50%;\r\n width: 14px;\r\n height: 14px;\r\n display: inline-flex;\r\n align-items: center;\r\n justify-content: center;\r\n margin-left: 2px;\r\n font-weight: 600;\r\n }\r\n `;\r\n}\r\n","/**\n * Sticky Columns Core Logic\n *\n * Pure functions for applying sticky (pinned) column positioning.\n */\n\n/* eslint-disable @typescript-eslint/no-explicit-any */\n\nimport type { StickyPosition } from './types';\n\n/**\n * Get columns that should be sticky on the left.\n *\n * @param columns - Array of column configurations\n * @returns Array of columns with sticky='left'\n */\nexport function getLeftStickyColumns(columns: any[]): any[] {\n return columns.filter((col) => col.sticky === 'left');\n}\n\n/**\n * Get columns that should be sticky on the right.\n *\n * @param columns - Array of column configurations\n * @returns Array of columns with sticky='right'\n */\nexport function getRightStickyColumns(columns: any[]): any[] {\n return columns.filter((col) => col.sticky === 'right');\n}\n\n/**\n * Check if any columns have sticky positioning.\n *\n * @param columns - Array of column configurations\n * @returns True if any column has sticky position\n */\nexport function hasStickyColumns(columns: any[]): boolean {\n return columns.some((col) => col.sticky === 'left' || col.sticky === 'right');\n}\n\n/**\n * Get the sticky position of a column.\n *\n * @param column - Column configuration\n * @returns The sticky position or null if not sticky\n */\nexport function getColumnStickyPosition(column: any): StickyPosition | null {\n if (column.sticky === 'left') return 'left';\n if (column.sticky === 'right') return 'right';\n return null;\n}\n\n/**\n * Calculate left offsets for sticky-left columns.\n * Returns a map of field -> offset in pixels.\n *\n * @param columns - Array of column configurations (in order)\n * @param getColumnWidth - Function to get column width by field\n * @returns Map of field to left offset\n */\nexport function calculateLeftStickyOffsets(\n columns: any[],\n getColumnWidth: (field: string) => number\n): Map<string, number> {\n const offsets = new Map<string, number>();\n let currentOffset = 0;\n\n for (const col of columns) {\n if (col.sticky === 'left') {\n offsets.set(col.field, currentOffset);\n currentOffset += getColumnWidth(col.field);\n }\n }\n\n return offsets;\n}\n\n/**\n * Calculate right offsets for sticky-right columns.\n * Processes columns in reverse order.\n *\n * @param columns - Array of column configurations (in order)\n * @param getColumnWidth - Function to get column width by field\n * @returns Map of field to right offset\n */\nexport function calculateRightStickyOffsets(\n columns: any[],\n getColumnWidth: (field: string) => number\n): Map<string, number> {\n const offsets = new Map<string, number>();\n let currentOffset = 0;\n\n // Process in reverse for right-sticky columns\n const reversed = [...columns].reverse();\n for (const col of reversed) {\n if (col.sticky === 'right') {\n offsets.set(col.field, currentOffset);\n currentOffset += getColumnWidth(col.field);\n }\n }\n\n return offsets;\n}\n\n/**\n * Apply sticky offsets to header and body cells.\n * This modifies the DOM elements in place.\n *\n * @param host - The grid host element\n * @param columns - Array of column configurations\n */\nexport function applyStickyOffsets(host: HTMLElement, columns: any[]): void {\n const shadowRoot = host.shadowRoot;\n if (!shadowRoot) return;\n\n const headerCells = Array.from(shadowRoot.querySelectorAll('.header-row .cell')) as HTMLElement[];\n if (!headerCells.length) return;\n\n // Build column index map for matching body cells (which use data-col, not data-field)\n const fieldToIndex = new Map<string, number>();\n columns.forEach((col, i) => {\n if (col.field) fieldToIndex.set(col.field, i);\n });\n\n // Apply left sticky\n let left = 0;\n for (const col of columns) {\n if (col.sticky === 'left') {\n const colIndex = fieldToIndex.get(col.field);\n const cell = headerCells.find((c) => c.getAttribute('data-field') === col.field);\n if (cell) {\n cell.classList.add('sticky-left');\n cell.style.left = left + 'px';\n // Body cells use data-col (column index), not data-field\n if (colIndex !== undefined) {\n shadowRoot.querySelectorAll(`.data-grid-row .cell[data-col=\"${colIndex}\"]`).forEach((el) => {\n el.classList.add('sticky-left');\n (el as HTMLElement).style.left = left + 'px';\n });\n }\n left += cell.offsetWidth;\n }\n }\n }\n\n // Apply right sticky (process in reverse)\n let right = 0;\n for (const col of [...columns].reverse()) {\n if (col.sticky === 'right') {\n const colIndex = fieldToIndex.get(col.field);\n const cell = headerCells.find((c) => c.getAttribute('data-field') === col.field);\n if (cell) {\n cell.classList.add('sticky-right');\n cell.style.right = right + 'px';\n // Body cells use data-col (column index), not data-field\n if (colIndex !== undefined) {\n shadowRoot.querySelectorAll(`.data-grid-row .cell[data-col=\"${colIndex}\"]`).forEach((el) => {\n el.classList.add('sticky-right');\n (el as HTMLElement).style.right = right + 'px';\n });\n }\n right += cell.offsetWidth;\n }\n }\n }\n}\n\n/**\n * Clear sticky positioning from all cells.\n *\n * @param host - The grid host element\n */\nexport function clearStickyOffsets(host: HTMLElement): void {\n const shadowRoot = host.shadowRoot;\n if (!shadowRoot) return;\n\n const cells = shadowRoot.querySelectorAll('.sticky-left, .sticky-right');\n cells.forEach((cell) => {\n cell.classList.remove('sticky-left', 'sticky-right');\n (cell as HTMLElement).style.left = '';\n (cell as HTMLElement).style.right = '';\n });\n}\n","/**\n * Pinned Columns Plugin (Class-based)\n *\n * Enables column pinning (sticky left/right positioning).\n */\n\nimport { BaseGridPlugin } from '../../core/plugin/base-plugin';\nimport type { ColumnConfig } from '../../core/types';\nimport {\n applyStickyOffsets,\n clearStickyOffsets,\n getLeftStickyColumns,\n getRightStickyColumns,\n hasStickyColumns,\n} from './pinned-columns';\nimport type { PinnedColumnsConfig } from './types';\n\n/**\n * Pinned Columns Plugin for tbw-grid\n *\n * @example\n * ```ts\n * new PinnedColumnsPlugin({ enabled: true })\n * ```\n */\nexport class PinnedColumnsPlugin extends BaseGridPlugin<PinnedColumnsConfig> {\n readonly name = 'pinnedColumns';\n override readonly version = '1.0.0';\n\n protected override get defaultConfig(): Partial<PinnedColumnsConfig> {\n return {\n enabled: true,\n };\n }\n\n // ===== Internal State =====\n private isApplied = false;\n private leftOffsets = new Map<string, number>();\n private rightOffsets = new Map<string, number>();\n\n // ===== Lifecycle =====\n\n override detach(): void {\n this.leftOffsets.clear();\n this.rightOffsets.clear();\n this.isApplied = false;\n }\n\n // ===== Detection =====\n\n /**\n * Auto-detect sticky columns from column configuration.\n */\n static detect(rows: readonly unknown[], config: { columns?: ColumnConfig[] }): boolean {\n const columns = config?.columns;\n if (!Array.isArray(columns)) return false;\n return hasStickyColumns(columns);\n }\n\n // ===== Hooks =====\n\n override processColumns(columns: readonly ColumnConfig[]): ColumnConfig[] {\n if (!this.config.enabled) {\n this.isApplied = false;\n return [...columns];\n }\n\n // Mark that we have sticky columns to apply\n this.isApplied = hasStickyColumns([...columns]);\n return [...columns];\n }\n\n override afterRender(): void {\n if (!this.config.enabled || !this.isApplied) {\n return;\n }\n\n const host = this.grid as unknown as HTMLElement;\n const columns = [...this.columns];\n\n if (!hasStickyColumns(columns)) {\n clearStickyOffsets(host);\n this.isApplied = false;\n return;\n }\n\n // Apply sticky offsets after a microtask to ensure DOM is ready\n queueMicrotask(() => {\n applyStickyOffsets(host, columns);\n });\n }\n\n // ===== Public API =====\n\n /**\n * Re-apply sticky offsets (e.g., after column resize).\n */\n refreshStickyOffsets(): void {\n const columns = [...this.columns];\n applyStickyOffsets(this.grid as unknown as HTMLElement, columns);\n }\n\n /**\n * Get columns pinned to the left.\n */\n getLeftPinnedColumns(): ColumnConfig[] {\n const columns = [...this.columns];\n return getLeftStickyColumns(columns);\n }\n\n /**\n * Get columns pinned to the right.\n */\n getRightPinnedColumns(): ColumnConfig[] {\n const columns = [...this.columns];\n return getRightStickyColumns(columns);\n }\n\n /**\n * Clear all sticky positioning.\n */\n clearStickyPositions(): void {\n clearStickyOffsets(this.grid as unknown as HTMLElement);\n }\n}\n","/**\n * Status Bar Rendering Logic\n *\n * Pure functions for creating and updating the status bar UI.\n * Includes both info bar and aggregation row rendering.\n */\n\nimport type { PinnedRowsPanel, PinnedRowsContext, PinnedRowsConfig, AggregationRowConfig } from './types';\nimport type { ColumnConfig } from '../../core/types';\nimport { getAggregator } from '../../core/internal/aggregators';\n\n/**\n * Creates the info bar DOM element with all configured panels.\n *\n * @param config - The status bar configuration\n * @param context - The current grid context for rendering\n * @returns The complete info bar element\n */\nexport function createInfoBarElement(config: PinnedRowsConfig, context: PinnedRowsContext): HTMLElement {\n const pinnedRows = document.createElement('div');\n pinnedRows.className = 'tbw-pinned-rows';\n pinnedRows.setAttribute('role', 'status');\n pinnedRows.setAttribute('aria-live', 'polite');\n\n const left = document.createElement('div');\n left.className = 'tbw-pinned-rows-left';\n\n const center = document.createElement('div');\n center.className = 'tbw-pinned-rows-center';\n\n const right = document.createElement('div');\n right.className = 'tbw-pinned-rows-right';\n\n // Default panels - row count\n if (config.showRowCount !== false) {\n const rowCount = document.createElement('span');\n rowCount.className = 'tbw-status-panel tbw-status-panel-row-count';\n rowCount.textContent = `Total: ${context.totalRows} rows`;\n left.appendChild(rowCount);\n }\n\n // Filtered count panel (only shows when filter is active)\n if (config.showFilteredCount && context.filteredRows !== context.totalRows) {\n const filteredCount = document.createElement('span');\n filteredCount.className = 'tbw-status-panel tbw-status-panel-filtered-count';\n filteredCount.textContent = `Filtered: ${context.filteredRows}`;\n left.appendChild(filteredCount);\n }\n\n // Selected count panel (only shows when rows are selected)\n if (config.showSelectedCount && context.selectedRows > 0) {\n const selectedCount = document.createElement('span');\n selectedCount.className = 'tbw-status-panel tbw-status-panel-selected-count';\n selectedCount.textContent = `Selected: ${context.selectedRows}`;\n right.appendChild(selectedCount);\n }\n\n // Render custom panels\n if (config.customPanels) {\n for (const panel of config.customPanels) {\n const panelEl = renderCustomPanel(panel, context);\n switch (panel.position) {\n case 'left':\n left.appendChild(panelEl);\n break;\n case 'center':\n center.appendChild(panelEl);\n break;\n case 'right':\n right.appendChild(panelEl);\n break;\n }\n }\n }\n\n pinnedRows.appendChild(left);\n pinnedRows.appendChild(center);\n pinnedRows.appendChild(right);\n\n return pinnedRows;\n}\n\n/**\n * Creates a container for aggregation rows at top or bottom.\n *\n * @param position - 'top' or 'bottom'\n * @returns The container element\n */\nexport function createAggregationContainer(position: 'top' | 'bottom'): HTMLElement {\n const container = document.createElement('div');\n container.className = `tbw-aggregation-rows tbw-aggregation-rows-${position}`;\n container.setAttribute('role', 'rowgroup');\n return container;\n}\n\n/**\n * Renders aggregation rows into a container.\n *\n * @param container - The container to render into\n * @param rows - Aggregation row configurations\n * @param columns - Current column configuration\n * @param dataRows - Current row data for aggregation calculations\n */\nexport function renderAggregationRows(\n container: HTMLElement,\n rows: AggregationRowConfig[],\n columns: ColumnConfig[],\n dataRows: unknown[]\n): void {\n container.innerHTML = '';\n\n for (const rowConfig of rows) {\n const rowEl = document.createElement('div');\n rowEl.className = 'tbw-aggregation-row';\n rowEl.setAttribute('role', 'row');\n if (rowConfig.id) {\n rowEl.setAttribute('data-aggregation-id', rowConfig.id);\n }\n\n if (rowConfig.fullWidth) {\n // Full-width mode: single cell spanning all columns\n const cell = document.createElement('div');\n cell.className = 'tbw-aggregation-cell tbw-aggregation-cell-full';\n cell.style.gridColumn = '1 / -1';\n cell.textContent = rowConfig.label || '';\n rowEl.appendChild(cell);\n } else {\n // Per-column mode: one cell per column with aggregated/static values\n for (const col of columns) {\n const cell = document.createElement('div');\n cell.className = 'tbw-aggregation-cell';\n cell.setAttribute('data-field', col.field);\n\n let value: unknown;\n\n // Check for aggregator first\n const aggRef = rowConfig.aggregators?.[col.field];\n if (aggRef) {\n const aggFn = getAggregator(aggRef);\n if (aggFn) {\n value = aggFn(dataRows, col.field, col);\n }\n } else if (rowConfig.cells && Object.prototype.hasOwnProperty.call(rowConfig.cells, col.field)) {\n // Static or computed cell value\n const staticVal = rowConfig.cells[col.field];\n if (typeof staticVal === 'function') {\n value = staticVal(dataRows, col.field, col);\n } else {\n value = staticVal;\n }\n }\n\n cell.textContent = value != null ? String(value) : '';\n rowEl.appendChild(cell);\n }\n }\n\n container.appendChild(rowEl);\n }\n}\n\n/**\n * Renders a custom panel element.\n *\n * @param panel - The panel definition\n * @param context - The current grid context\n * @returns The panel DOM element\n */\nfunction renderCustomPanel(panel: PinnedRowsPanel, context: PinnedRowsContext): HTMLElement {\n const panelEl = document.createElement('div');\n panelEl.className = 'tbw-status-panel tbw-status-panel-custom';\n panelEl.id = `status-panel-${panel.id}`;\n\n const content = panel.render(context);\n\n if (typeof content === 'string') {\n panelEl.innerHTML = content;\n } else {\n panelEl.appendChild(content);\n }\n\n return panelEl;\n}\n\n/**\n * Builds the status bar context from grid state and plugin states.\n *\n * @param rows - Current row data\n * @param columns - Current column configuration\n * @param grid - Grid element reference\n * @param selectionState - Optional selection plugin state\n * @param filterState - Optional filtering plugin state\n * @returns The status bar context\n */\nexport function buildContext(\n rows: unknown[],\n columns: unknown[],\n grid: HTMLElement,\n selectionState?: { selected: Set<number> } | null,\n filterState?: { cachedResult: unknown[] | null } | null\n): PinnedRowsContext {\n return {\n totalRows: rows.length,\n filteredRows: filterState?.cachedResult?.length ?? rows.length,\n selectedRows: selectionState?.selected?.size ?? 0,\n columns: columns as PinnedRowsContext['columns'],\n rows,\n grid,\n };\n}\n\n// Keep old name as alias for backwards compatibility\nexport const createPinnedRowsElement = createInfoBarElement;\n","/**\n * Pinned Rows Plugin (Class-based)\n *\n * Adds info bars and aggregation rows to the grid.\n * - Info bar: Shows row counts, selection info, and custom panels\n * - Aggregation rows: Footer/header rows with computed values (sum, avg, etc.)\n */\n\nimport { BaseGridPlugin } from '../../core/plugin/base-plugin';\nimport type { ColumnConfig } from '../../core/types';\nimport { buildContext, createAggregationContainer, createInfoBarElement, renderAggregationRows } from './pinned-rows';\nimport type { AggregationRowConfig, PinnedRowsConfig, PinnedRowsContext, PinnedRowsPanel } from './types';\n\n/**\n * Pinned Rows Plugin for tbw-grid\n *\n * @example\n * ```ts\n * new PinnedRowsPlugin({\n * enabled: true,\n * position: 'bottom',\n * showRowCount: true,\n * showSelectedCount: true,\n * aggregationRows: [\n * { id: 'totals', position: 'bottom', values: { amount: 'sum' } },\n * ],\n * })\n * ```\n */\nexport class PinnedRowsPlugin extends BaseGridPlugin<PinnedRowsConfig> {\n readonly name = 'pinnedRows';\n override readonly version = '1.0.0';\n\n protected override get defaultConfig(): Partial<PinnedRowsConfig> {\n return {\n enabled: true,\n position: 'bottom',\n showRowCount: true,\n showSelectedCount: true,\n showFilteredCount: true,\n };\n }\n\n // ===== Internal State =====\n private infoBarElement: HTMLElement | null = null;\n private topAggregationContainer: HTMLElement | null = null;\n private bottomAggregationContainer: HTMLElement | null = null;\n private footerWrapper: HTMLElement | null = null;\n\n // ===== Lifecycle =====\n\n override detach(): void {\n if (this.infoBarElement) {\n this.infoBarElement.remove();\n this.infoBarElement = null;\n }\n if (this.topAggregationContainer) {\n this.topAggregationContainer.remove();\n this.topAggregationContainer = null;\n }\n if (this.bottomAggregationContainer) {\n this.bottomAggregationContainer.remove();\n this.bottomAggregationContainer = null;\n }\n if (this.footerWrapper) {\n this.footerWrapper.remove();\n this.footerWrapper = null;\n }\n }\n\n // ===== Hooks =====\n\n override afterRender(): void {\n if (!this.config.enabled) {\n this.cleanup();\n return;\n }\n\n const shadowRoot = this.shadowRoot;\n if (!shadowRoot) return;\n\n // Use .tbw-scroll-area so footer is inside the horizontal scroll area,\n // otherwise fall back to .tbw-grid-content or root container\n const container =\n shadowRoot.querySelector('.tbw-scroll-area') ??\n shadowRoot.querySelector('.tbw-grid-content') ??\n shadowRoot.children[0];\n if (!container) return;\n\n // Build context with plugin states\n const selectionState = this.getSelectionState();\n const filterState = this.getFilterState();\n\n const context = buildContext(\n this.rows as unknown[],\n this.columns as unknown[],\n this.grid as unknown as HTMLElement,\n selectionState,\n filterState\n );\n\n // ===== Handle Aggregation Rows =====\n const aggregationRows = this.config.aggregationRows || [];\n const topRows = aggregationRows.filter((r) => r.position === 'top');\n const bottomRows = aggregationRows.filter((r) => r.position !== 'top');\n\n // Top aggregation rows\n if (topRows.length > 0) {\n if (!this.topAggregationContainer) {\n this.topAggregationContainer = createAggregationContainer('top');\n const header = shadowRoot.querySelector('.header');\n if (header && header.nextSibling) {\n container.insertBefore(this.topAggregationContainer, header.nextSibling);\n } else {\n container.appendChild(this.topAggregationContainer);\n }\n }\n renderAggregationRows(\n this.topAggregationContainer,\n topRows,\n this.visibleColumns as ColumnConfig[],\n this.rows as unknown[]\n );\n } else if (this.topAggregationContainer) {\n this.topAggregationContainer.remove();\n this.topAggregationContainer = null;\n }\n\n // Handle footer\n const hasInfoContent =\n this.config.showRowCount !== false ||\n (this.config.showSelectedCount && context.selectedRows > 0) ||\n (this.config.showFilteredCount && context.filteredRows !== context.totalRows) ||\n (this.config.customPanels && this.config.customPanels.length > 0);\n const hasBottomInfoBar = hasInfoContent && this.config.position !== 'top';\n const needsFooter = bottomRows.length > 0 || hasBottomInfoBar;\n\n // Handle top info bar\n if (hasInfoContent && this.config.position === 'top') {\n if (!this.infoBarElement) {\n this.infoBarElement = createInfoBarElement(this.config, context);\n container.insertBefore(this.infoBarElement, container.firstChild);\n } else {\n const newInfoBar = createInfoBarElement(this.config, context);\n this.infoBarElement.replaceWith(newInfoBar);\n this.infoBarElement = newInfoBar;\n }\n } else if (this.config.position === 'top' && this.infoBarElement) {\n this.infoBarElement.remove();\n this.infoBarElement = null;\n }\n\n // Create/manage footer wrapper\n if (needsFooter) {\n if (!this.footerWrapper) {\n this.footerWrapper = document.createElement('div');\n this.footerWrapper.className = 'tbw-footer';\n container.appendChild(this.footerWrapper);\n }\n\n this.footerWrapper.innerHTML = '';\n\n if (bottomRows.length > 0) {\n if (!this.bottomAggregationContainer) {\n this.bottomAggregationContainer = createAggregationContainer('bottom');\n }\n this.footerWrapper.appendChild(this.bottomAggregationContainer);\n renderAggregationRows(\n this.bottomAggregationContainer,\n bottomRows,\n this.visibleColumns as ColumnConfig[],\n this.rows as unknown[]\n );\n }\n\n if (hasBottomInfoBar) {\n this.infoBarElement = createInfoBarElement(this.config, context);\n this.footerWrapper.appendChild(this.infoBarElement);\n }\n } else {\n this.cleanupFooter();\n }\n }\n\n // ===== Private Methods =====\n\n private cleanup(): void {\n if (this.infoBarElement) {\n this.infoBarElement.remove();\n this.infoBarElement = null;\n }\n if (this.topAggregationContainer) {\n this.topAggregationContainer.remove();\n this.topAggregationContainer = null;\n }\n if (this.bottomAggregationContainer) {\n this.bottomAggregationContainer.remove();\n this.bottomAggregationContainer = null;\n }\n if (this.footerWrapper) {\n this.footerWrapper.remove();\n this.footerWrapper = null;\n }\n }\n\n private cleanupFooter(): void {\n if (this.footerWrapper) {\n this.footerWrapper.remove();\n this.footerWrapper = null;\n }\n if (this.bottomAggregationContainer) {\n this.bottomAggregationContainer.remove();\n this.bottomAggregationContainer = null;\n }\n if (this.infoBarElement && this.config.position !== 'top') {\n this.infoBarElement.remove();\n this.infoBarElement = null;\n }\n }\n\n private getSelectionState(): { selected: Set<number> } | null {\n // Try to get selection plugin state\n try {\n const grid = this.grid as any;\n return grid?.getPluginState?.('selection') ?? null;\n } catch {\n return null;\n }\n }\n\n private getFilterState(): { cachedResult: unknown[] | null } | null {\n try {\n const grid = this.grid as any;\n return grid?.getPluginState?.('filtering') ?? null;\n } catch {\n return null;\n }\n }\n\n // ===== Public API =====\n\n /**\n * Refresh the status bar to reflect current grid state.\n */\n refresh(): void {\n this.requestRender();\n }\n\n /**\n * Get the current status bar context.\n * @returns The context with row counts and other info\n */\n getContext(): PinnedRowsContext {\n const selectionState = this.getSelectionState();\n const filterState = this.getFilterState();\n\n return buildContext(\n this.rows as unknown[],\n this.columns as unknown[],\n this.grid as unknown as HTMLElement,\n selectionState,\n filterState\n );\n }\n\n /**\n * Add a custom panel to the info bar.\n * @param panel - The panel configuration to add\n */\n addPanel(panel: PinnedRowsPanel): void {\n if (!this.config.customPanels) {\n this.config.customPanels = [];\n }\n this.config.customPanels.push(panel);\n this.requestRender();\n }\n\n /**\n * Remove a custom panel by ID.\n * @param id - The panel ID to remove\n */\n removePanel(id: string): void {\n if (this.config.customPanels) {\n this.config.customPanels = this.config.customPanels.filter((p) => p.id !== id);\n this.requestRender();\n }\n }\n\n /**\n * Add an aggregation row.\n * @param row - The aggregation row configuration\n */\n addAggregationRow(row: AggregationRowConfig): void {\n if (!this.config.aggregationRows) {\n this.config.aggregationRows = [];\n }\n this.config.aggregationRows.push(row);\n this.requestRender();\n }\n\n /**\n * Remove an aggregation row by ID.\n * @param id - The aggregation row ID to remove\n */\n removeAggregationRow(id: string): void {\n if (this.config.aggregationRows) {\n this.config.aggregationRows = this.config.aggregationRows.filter((r) => r.id !== id);\n this.requestRender();\n }\n }\n\n // ===== Styles =====\n\n override readonly styles = `\n .tbw-footer {\n position: sticky;\n bottom: 0;\n z-index: var(--tbw-z-layer-pinned-rows, 20);\n background: var(--tbw-color-panel-bg);\n }\n\n .tbw-pinned-rows {\n display: flex;\n align-items: center;\n justify-content: space-between;\n padding: 8px 12px;\n background: var(--tbw-pinned-rows-bg, var(--tbw-color-panel-bg));\n border-top: 1px solid var(--tbw-pinned-rows-border, var(--tbw-color-border));\n font-size: 12px;\n color: var(--tbw-pinned-rows-color, var(--tbw-color-fg-muted));\n min-height: 32px;\n box-sizing: border-box;\n min-width: fit-content;\n }\n .tbw-pinned-rows-left,\n .tbw-pinned-rows-center,\n .tbw-pinned-rows-right {\n display: flex;\n align-items: center;\n gap: 16px;\n }\n .tbw-pinned-rows-left {\n justify-content: flex-start;\n }\n .tbw-pinned-rows-center {\n justify-content: center;\n flex: 1;\n }\n .tbw-pinned-rows-right {\n justify-content: flex-end;\n }\n .tbw-status-panel {\n white-space: nowrap;\n }\n\n .tbw-aggregation-rows {\n min-width: fit-content;\n background: var(--tbw-aggregation-bg, var(--tbw-color-header-bg));\n }\n .tbw-aggregation-rows-top {\n border-bottom: 1px solid var(--tbw-aggregation-border, var(--tbw-color-border));\n }\n .tbw-aggregation-rows-bottom {\n border-top: 1px solid var(--tbw-aggregation-border, var(--tbw-color-border));\n }\n .tbw-aggregation-row {\n display: grid;\n grid-template-columns: var(--tbw-column-template);\n font-weight: var(--tbw-aggregation-font-weight, 600);\n }\n .tbw-aggregation-cell {\n padding: var(--tbw-cell-padding, 2px 8px);\n min-height: var(--tbw-row-height, 28px);\n display: flex;\n align-items: center;\n border-right: 1px solid var(--tbw-color-border-cell);\n }\n .tbw-aggregation-cell:last-child {\n border-right: 0;\n }\n .tbw-aggregation-cell-full {\n grid-column: 1 / -1;\n border-right: 0;\n }\n `;\n}\n","import type { PivotConfig } from './types';\n\nexport function validatePivotConfig(config: PivotConfig): string[] {\n const errors: string[] = [];\n\n if (!config.rowGroupFields?.length && !config.columnGroupFields?.length) {\n errors.push('At least one row or column group field is required');\n }\n\n if (!config.valueFields?.length) {\n errors.push('At least one value field is required');\n }\n\n return errors;\n}\n\n/**\n * Get a value-based aggregator function for pivot operations.\n * This operates on pre-extracted numeric values (different from core row-based aggregators).\n */\nexport function getPivotAggregator(aggFunc: string): (values: number[]) => number {\n switch (aggFunc) {\n case 'sum':\n return (vals) => vals.reduce((a, b) => a + b, 0);\n case 'avg':\n return (vals) => (vals.length ? vals.reduce((a, b) => a + b, 0) / vals.length : 0);\n case 'count':\n return (vals) => vals.length;\n case 'min':\n return (vals) => (vals.length ? Math.min(...vals) : 0);\n case 'max':\n return (vals) => (vals.length ? Math.max(...vals) : 0);\n case 'first':\n return (vals) => vals[0] ?? 0;\n case 'last':\n return (vals) => vals[vals.length - 1] ?? 0;\n default:\n return (vals) => vals.reduce((a, b) => a + b, 0);\n }\n}\n\nexport function createValueKey(columnValues: string[], valueField: string): string {\n return [...columnValues, valueField].join('|');\n}\n","import type { PivotConfig, PivotResult, PivotRow, PivotValueField } from './types';\nimport { getPivotAggregator, createValueKey } from './pivot-model';\n\nexport type PivotDataRow = Record<string, unknown>;\n\nexport function buildPivot(rows: PivotDataRow[], config: PivotConfig): PivotResult {\n const rowGroupFields = config.rowGroupFields ?? [];\n const columnGroupFields = config.columnGroupFields ?? [];\n const valueFields = config.valueFields ?? [];\n\n // Get unique column combinations\n const columnKeys = getUniqueColumnKeys(rows, columnGroupFields);\n\n // Group rows by row group fields\n const groupedData = groupByFields(rows, rowGroupFields);\n\n // Build pivot rows\n const pivotRows = buildPivotRows(groupedData, columnGroupFields, columnKeys, valueFields, 0);\n\n // Calculate totals\n const totals = calculateTotals(pivotRows, columnKeys, valueFields);\n const grandTotal = Object.values(totals).reduce((a, b) => a + b, 0);\n\n return {\n rows: pivotRows,\n columnKeys,\n totals,\n grandTotal,\n };\n}\n\nexport function getUniqueColumnKeys(rows: PivotDataRow[], columnFields: string[]): string[] {\n if (columnFields.length === 0) return ['value'];\n\n const keys = new Set<string>();\n for (const row of rows) {\n const key = columnFields.map((f) => String(row[f] ?? '')).join('|');\n keys.add(key);\n }\n return [...keys].sort();\n}\n\nexport function groupByFields(rows: PivotDataRow[], fields: string[]): Map<string, PivotDataRow[]> {\n const groups = new Map<string, PivotDataRow[]>();\n\n for (const row of rows) {\n const key = fields.map((f) => String(row[f] ?? '')).join('|');\n if (!groups.has(key)) {\n groups.set(key, []);\n }\n const group = groups.get(key);\n if (group) group.push(row);\n }\n\n return groups;\n}\n\nexport function buildPivotRows(\n groupedData: Map<string, PivotDataRow[]>,\n columnFields: string[],\n columnKeys: string[],\n valueFields: PivotValueField[],\n depth: number\n): PivotRow[] {\n const result: PivotRow[] = [];\n\n for (const [rowKey, groupRows] of groupedData) {\n const values: Record<string, number | null> = {};\n let total = 0;\n\n for (const colKey of columnKeys) {\n for (const vf of valueFields) {\n const matchingRows =\n columnFields.length > 0\n ? groupRows.filter((r) => columnFields.map((f) => String(r[f] ?? '')).join('|') === colKey)\n : groupRows;\n\n const nums = matchingRows.map((r) => Number(r[vf.field]) || 0);\n const aggregator = getPivotAggregator(vf.aggFunc);\n const aggregatedResult = nums.length > 0 ? aggregator(nums) : null;\n\n const valueKey = createValueKey([colKey], vf.field);\n values[valueKey] = aggregatedResult;\n\n if (aggregatedResult !== null) total += aggregatedResult;\n }\n }\n\n result.push({\n rowKey,\n rowLabel: rowKey || '(blank)',\n depth,\n values,\n total,\n isGroup: false,\n });\n }\n\n return result;\n}\n\nexport function calculateTotals(\n pivotRows: PivotRow[],\n columnKeys: string[],\n valueFields: PivotValueField[]\n): Record<string, number> {\n const totals: Record<string, number> = {};\n\n for (const colKey of columnKeys) {\n for (const vf of valueFields) {\n const valueKey = createValueKey([colKey], vf.field);\n totals[valueKey] = pivotRows.reduce((sum, row) => {\n return sum + (row.values[valueKey] ?? 0);\n }, 0);\n }\n }\n\n return totals;\n}\n\nexport function flattenPivotRows(rows: PivotRow[]): PivotRow[] {\n const result: PivotRow[] = [];\n\n function flatten(row: PivotRow) {\n result.push(row);\n if (row.children) {\n for (const child of row.children) {\n flatten(child);\n }\n }\n }\n\n for (const row of rows) {\n flatten(row);\n }\n\n return result;\n}\n","/**\n * Pivot Plugin (Class-based)\n *\n * Provides pivot table functionality for tbw-grid.\n * Transforms flat data into grouped, aggregated pivot views.\n */\n\nimport { BaseGridPlugin } from '../../core/plugin/base-plugin';\nimport type { ColumnConfig } from '../../core/types';\nimport { buildPivot, flattenPivotRows, type PivotDataRow } from './pivot-engine';\nimport { createValueKey, validatePivotConfig } from './pivot-model';\nimport type { PivotConfig, PivotResult, PivotValueField } from './types';\n\n/**\n * Pivot Plugin for tbw-grid\n *\n * @example\n * ```ts\n * new PivotPlugin({\n * rowGroupFields: ['category'],\n * columnGroupFields: ['region'],\n * valueFields: [{ field: 'sales', aggFunc: 'sum' }]\n * })\n * ```\n */\nexport class PivotPlugin extends BaseGridPlugin<PivotConfig> {\n readonly name = 'pivot';\n override readonly version = '1.0.0';\n\n protected override get defaultConfig(): Partial<PivotConfig> {\n return {\n enabled: true,\n showTotals: true,\n showGrandTotal: true,\n };\n }\n\n // ===== Internal State =====\n private isActive = false;\n private pivotResult: PivotResult | null = null;\n private columnHeaders: string[] = [];\n private rowHeaders: string[] = [];\n\n // ===== Lifecycle =====\n\n override detach(): void {\n this.isActive = false;\n this.pivotResult = null;\n this.columnHeaders = [];\n this.rowHeaders = [];\n }\n\n // ===== Hooks =====\n\n override processRows(rows: readonly unknown[]): PivotDataRow[] {\n if (!this.config.enabled || !this.isActive) {\n return [...rows] as PivotDataRow[];\n }\n\n const errors = validatePivotConfig(this.config);\n if (errors.length > 0) {\n this.warn(`Config errors: ${errors.join(', ')}`);\n return [...rows] as PivotDataRow[];\n }\n\n // Build pivot\n this.pivotResult = buildPivot(rows as PivotDataRow[], this.config);\n\n // Return flattened pivot rows for rendering\n return flattenPivotRows(this.pivotResult.rows).map((pr) => ({\n __pivotRowKey: pr.rowKey,\n __pivotLabel: pr.rowLabel,\n __pivotDepth: pr.depth,\n __pivotIsGroup: pr.isGroup,\n __pivotTotal: pr.total,\n ...pr.values,\n }));\n }\n\n override processColumns(columns: readonly ColumnConfig[]): ColumnConfig[] {\n if (!this.config.enabled || !this.isActive || !this.pivotResult) {\n return [...columns];\n }\n\n const pivotColumns: ColumnConfig[] = [];\n\n // Row label column\n pivotColumns.push({\n field: '__pivotLabel',\n header: this.config.rowGroupFields?.join(' / ') ?? 'Group',\n width: 200,\n });\n\n // Value columns for each column key\n for (const colKey of this.pivotResult.columnKeys) {\n for (const vf of this.config.valueFields ?? []) {\n const valueKey = createValueKey([colKey], vf.field);\n pivotColumns.push({\n field: valueKey,\n header: `${colKey} - ${vf.header || vf.field} (${vf.aggFunc})`,\n width: 120,\n type: 'number',\n });\n }\n }\n\n // Totals column\n if (this.config.showTotals) {\n pivotColumns.push({\n field: '__pivotTotal',\n header: 'Total',\n width: 100,\n type: 'number',\n });\n }\n\n return pivotColumns;\n }\n\n // ===== Public API =====\n\n /**\n * Enable pivot mode.\n */\n enablePivot(): void {\n this.isActive = true;\n this.requestRender();\n }\n\n /**\n * Disable pivot mode and return to normal grid view.\n */\n disablePivot(): void {\n this.isActive = false;\n this.pivotResult = null;\n this.requestRender();\n }\n\n /**\n * Check if pivot mode is currently active.\n */\n isPivotActive(): boolean {\n return this.isActive;\n }\n\n /**\n * Get the current pivot result.\n */\n getPivotResult(): PivotResult | null {\n return this.pivotResult;\n }\n\n /**\n * Set the row group fields for pivoting.\n * @param fields - Array of field names to group rows by\n */\n setRowGroupFields(fields: string[]): void {\n this.config.rowGroupFields = fields;\n this.requestRender();\n }\n\n /**\n * Set the column group fields for pivoting.\n * @param fields - Array of field names to create columns from\n */\n setColumnGroupFields(fields: string[]): void {\n this.config.columnGroupFields = fields;\n this.requestRender();\n }\n\n /**\n * Set the value fields with aggregation functions.\n * @param fields - Array of value field configurations\n */\n setValueFields(fields: PivotValueField[]): void {\n this.config.valueFields = fields;\n this.requestRender();\n }\n\n /**\n * Refresh the pivot by clearing cached results.\n */\n refresh(): void {\n this.pivotResult = null;\n this.requestRender();\n }\n\n // ===== Styles =====\n\n override readonly styles = `\n [data-pivot-depth=\"1\"] { padding-left: 20px; }\n [data-pivot-depth=\"2\"] { padding-left: 40px; }\n [data-pivot-depth=\"3\"] { padding-left: 60px; }\n .pivot-group-row { font-weight: bold; background: var(--tbw-pivot-group-bg, var(--tbw-color-panel-bg)); }\n .pivot-total-row { font-weight: bold; border-top: 2px solid var(--tbw-pivot-border, var(--tbw-color-border-strong)); }\n `;\n}\n","/**\n * Column Reordering Core Logic\n *\n * Pure functions for column drag and reordering operations.\n */\n\nimport type { ColumnConfig } from '../../core/types';\n\n/**\n * Check if a column can be moved.\n * Respects lockPosition, suppressMovable, and sticky properties.\n * Sticky (pinned) columns cannot be reordered as they have fixed positions.\n *\n * @param column - The column configuration to check\n * @returns True if the column can be moved\n */\nexport function canMoveColumn<TRow = unknown>(column: ColumnConfig<TRow>): boolean {\n // Sticky columns cannot be reordered - they have fixed left/right positions\n // Check via meta since sticky is added by PinnedColumnsPlugin\n const meta = column.meta ?? {};\n const sticky = (meta as { sticky?: 'left' | 'right' }).sticky;\n if (sticky === 'left' || sticky === 'right') {\n return false;\n }\n // Check for lockPosition or suppressMovable properties in the column config\n return meta.lockPosition !== true && meta.suppressMovable !== true;\n}\n\n/**\n * Move a column from one position to another in the order array.\n *\n * @param columns - Array of field names in current order\n * @param fromIndex - The current index of the column to move\n * @param toIndex - The target index to move the column to\n * @returns New array with updated order\n */\nexport function moveColumn(columns: string[], fromIndex: number, toIndex: number): string[] {\n if (fromIndex === toIndex) return columns;\n if (fromIndex < 0 || fromIndex >= columns.length) return columns;\n if (toIndex < 0 || toIndex > columns.length) return columns;\n\n const result = [...columns];\n const [removed] = result.splice(fromIndex, 1);\n result.splice(toIndex, 0, removed);\n return result;\n}\n\n/**\n * Calculate the drop index based on the current drag position.\n *\n * @param dragX - The current X position of the drag\n * @param headerRect - The bounding rect of the header container\n * @param columnWidths - Array of column widths in order\n * @returns The index where the column should be dropped\n */\nexport function getDropIndex(dragX: number, headerRect: DOMRect, columnWidths: number[]): number {\n let x = headerRect.left;\n\n for (let i = 0; i < columnWidths.length; i++) {\n const mid = x + columnWidths[i] / 2;\n if (dragX < mid) return i;\n x += columnWidths[i];\n }\n\n return columnWidths.length;\n}\n\n/**\n * Reorder columns according to a specified order.\n * Columns not in the order array are appended at the end.\n *\n * @param columns - Array of column configurations\n * @param order - Array of field names specifying the desired order\n * @returns New array of columns in the specified order\n */\nexport function reorderColumns<TRow = unknown>(columns: ColumnConfig<TRow>[], order: string[]): ColumnConfig<TRow>[] {\n const columnMap = new Map<string, ColumnConfig<TRow>>(columns.map((c) => [c.field as string, c]));\n const reordered: ColumnConfig<TRow>[] = [];\n\n // Add columns in specified order\n for (const field of order) {\n const col = columnMap.get(field);\n if (col) {\n reordered.push(col);\n columnMap.delete(field);\n }\n }\n\n // Add any remaining columns not in order\n for (const col of columnMap.values()) {\n reordered.push(col);\n }\n\n return reordered;\n}\n","/**\r\n * Column Reordering Plugin (Class-based)\r\n *\r\n * Provides drag-and-drop column reordering functionality for tbw-grid.\r\n * Supports keyboard and mouse interactions with visual feedback.\r\n */\r\n\r\nimport { BaseGridPlugin } from '../../core/plugin/base-plugin';\r\nimport { canMoveColumn, moveColumn } from './column-drag';\r\nimport type { ColumnMoveDetail, ReorderConfig } from './types';\r\n\r\n/** Extended grid interface with column order methods */\r\ninterface GridWithColumnOrder {\r\n setColumnOrder(order: string[]): void;\r\n getColumnOrder(): string[];\r\n requestStateChange?: () => void;\r\n}\r\n\r\n/**\r\n * Column Reordering Plugin for tbw-grid\r\n *\r\n * @example\r\n * ```ts\r\n * new ReorderPlugin({\r\n * enabled: true,\r\n * animation: true,\r\n * animationDuration: 200,\r\n * })\r\n * ```\r\n */\r\nexport class ReorderPlugin extends BaseGridPlugin<ReorderConfig> {\r\n readonly name = 'reorder';\r\n override readonly version = '1.0.0';\r\n\r\n protected override get defaultConfig(): Partial<ReorderConfig> {\r\n return {\r\n enabled: true,\r\n animation: true,\r\n animationDuration: 200,\r\n };\r\n }\r\n\r\n // ===== Internal State =====\r\n private isDragging = false;\r\n private draggedField: string | null = null;\r\n private draggedIndex: number | null = null;\r\n private dropIndex: number | null = null;\r\n private boundReorderRequestHandler: ((e: Event) => void) | null = null;\r\n\r\n // ===== Lifecycle =====\r\n\r\n override attach(grid: import('../../core/plugin/base-plugin').GridElement): void {\r\n super.attach(grid);\r\n\r\n // Listen for reorder requests from other plugins (e.g., VisibilityPlugin)\r\n this.boundReorderRequestHandler = (e: Event) => {\r\n const detail = (e as CustomEvent).detail;\r\n if (detail?.field && typeof detail.toIndex === 'number') {\r\n this.moveColumn(detail.field, detail.toIndex);\r\n }\r\n };\r\n (grid as unknown as HTMLElement).addEventListener('column-reorder-request', this.boundReorderRequestHandler);\r\n }\r\n\r\n override detach(): void {\r\n // Remove event listener\r\n if (this.boundReorderRequestHandler && this.grid) {\r\n (this.grid as unknown as HTMLElement).removeEventListener(\r\n 'column-reorder-request',\r\n this.boundReorderRequestHandler\r\n );\r\n this.boundReorderRequestHandler = null;\r\n }\r\n\r\n this.isDragging = false;\r\n this.draggedField = null;\r\n this.draggedIndex = null;\r\n this.dropIndex = null;\r\n }\r\n\r\n // ===== Hooks =====\r\n // Note: No processColumns hook needed - we directly update the grid's column order\r\n\r\n override afterRender(): void {\r\n if (!this.config.enabled) return;\r\n\r\n const shadowRoot = this.shadowRoot;\r\n if (!shadowRoot) return;\r\n\r\n const headers = shadowRoot.querySelectorAll('.header-row > .cell');\r\n\r\n headers.forEach((header) => {\r\n const headerEl = header as HTMLElement;\r\n const field = headerEl.getAttribute('data-field');\r\n if (!field) return;\r\n\r\n const column = this.columns.find((c) => c.field === field);\r\n if (!column || !canMoveColumn(column)) {\r\n headerEl.draggable = false;\r\n return;\r\n }\r\n\r\n headerEl.draggable = true;\r\n\r\n // Remove existing listeners to prevent duplicates\r\n if (headerEl.getAttribute('data-dragstart-bound')) return;\r\n headerEl.setAttribute('data-dragstart-bound', 'true');\r\n\r\n headerEl.addEventListener('dragstart', (e: DragEvent) => {\r\n const currentOrder = this.getColumnOrder();\r\n const orderIndex = currentOrder.indexOf(field);\r\n this.isDragging = true;\r\n this.draggedField = field;\r\n this.draggedIndex = orderIndex;\r\n\r\n if (e.dataTransfer) {\r\n e.dataTransfer.effectAllowed = 'move';\r\n e.dataTransfer.setData('text/plain', field);\r\n }\r\n\r\n headerEl.classList.add('dragging');\r\n });\r\n\r\n headerEl.addEventListener('dragend', () => {\r\n this.isDragging = false;\r\n this.draggedField = null;\r\n this.draggedIndex = null;\r\n this.dropIndex = null;\r\n\r\n shadowRoot.querySelectorAll('.header-row > .cell').forEach((h) => {\r\n h.classList.remove('dragging', 'drop-target', 'drop-before', 'drop-after');\r\n });\r\n });\r\n\r\n headerEl.addEventListener('dragover', (e: DragEvent) => {\r\n e.preventDefault();\r\n if (!this.isDragging || this.draggedField === field) return;\r\n\r\n const rect = headerEl.getBoundingClientRect();\r\n const midX = rect.left + rect.width / 2;\r\n\r\n const currentOrder = this.getColumnOrder();\r\n const orderIndex = currentOrder.indexOf(field);\r\n this.dropIndex = e.clientX < midX ? orderIndex : orderIndex + 1;\r\n\r\n headerEl.classList.add('drop-target');\r\n headerEl.classList.toggle('drop-before', e.clientX < midX);\r\n headerEl.classList.toggle('drop-after', e.clientX >= midX);\r\n });\r\n\r\n headerEl.addEventListener('dragleave', () => {\r\n headerEl.classList.remove('drop-target', 'drop-before', 'drop-after');\r\n });\r\n\r\n headerEl.addEventListener('drop', (e: DragEvent) => {\r\n e.preventDefault();\r\n const draggedField = this.draggedField;\r\n const draggedIndex = this.draggedIndex;\r\n const dropIndex = this.dropIndex;\r\n\r\n if (!this.isDragging || draggedField === null || draggedIndex === null || dropIndex === null) {\r\n return;\r\n }\r\n\r\n const effectiveToIndex = dropIndex > draggedIndex ? dropIndex - 1 : dropIndex;\r\n const currentOrder = this.getColumnOrder();\r\n const newOrder = moveColumn(currentOrder, draggedIndex, effectiveToIndex);\r\n\r\n const detail: ColumnMoveDetail = {\r\n field: draggedField,\r\n fromIndex: draggedIndex,\r\n toIndex: effectiveToIndex,\r\n columnOrder: newOrder,\r\n };\r\n\r\n // Directly update the grid's column order\r\n (this.grid as unknown as GridWithColumnOrder).setColumnOrder(newOrder);\r\n\r\n this.emit('column-move', detail);\r\n // Trigger state change after reorder\r\n (this.grid as unknown as GridWithColumnOrder).requestStateChange?.();\r\n });\r\n });\r\n }\r\n\r\n // ===== Public API =====\r\n\r\n /**\r\n * Get the current column order from the grid.\r\n * @returns Array of field names in display order\r\n */\r\n getColumnOrder(): string[] {\r\n return (this.grid as unknown as GridWithColumnOrder).getColumnOrder();\r\n }\r\n\r\n /**\r\n * Move a column to a new position.\r\n * @param field - The field name of the column to move\r\n * @param toIndex - The target index\r\n */\r\n moveColumn(field: string, toIndex: number): void {\r\n const currentOrder = this.getColumnOrder();\r\n const fromIndex = currentOrder.indexOf(field);\r\n if (fromIndex === -1) return;\r\n\r\n const newOrder = moveColumn(currentOrder, fromIndex, toIndex);\r\n\r\n // Directly update the grid's column order\r\n (this.grid as unknown as GridWithColumnOrder).setColumnOrder(newOrder);\r\n\r\n this.emit<ColumnMoveDetail>('column-move', {\r\n field,\r\n fromIndex,\r\n toIndex,\r\n columnOrder: newOrder,\r\n });\r\n\r\n // Trigger state change after reorder\r\n (this.grid as unknown as GridWithColumnOrder).requestStateChange?.();\r\n }\r\n\r\n /**\r\n * Set a specific column order.\r\n * @param order - Array of field names in desired order\r\n */\r\n setColumnOrder(order: string[]): void {\r\n (this.grid as unknown as GridWithColumnOrder).setColumnOrder(order);\r\n // Trigger state change after reorder\r\n (this.grid as unknown as GridWithColumnOrder).requestStateChange?.();\r\n }\r\n\r\n /**\r\n * Reset column order to the original configuration order.\r\n */\r\n resetColumnOrder(): void {\r\n const originalOrder = this.columns.map((c) => c.field);\r\n (this.grid as unknown as GridWithColumnOrder).setColumnOrder(originalOrder);\r\n // Trigger state change after reset\r\n (this.grid as unknown as GridWithColumnOrder).requestStateChange?.();\r\n }\r\n\r\n // ===== Styles =====\r\n\r\n override readonly styles = `\r\n .header-row > .cell[draggable=\"true\"] {\r\n cursor: grab;\r\n position: relative;\r\n }\r\n .header-row > .cell.dragging {\r\n opacity: 0.5;\r\n cursor: grabbing;\r\n }\r\n .header-row > .cell.drop-before::before {\r\n content: '';\r\n position: absolute;\r\n left: 0;\r\n top: 0;\r\n bottom: 0;\r\n width: 2px;\r\n background: var(--tbw-reorder-indicator, var(--tbw-color-accent));\r\n z-index: 1;\r\n }\r\n .header-row > .cell.drop-after::after {\r\n content: '';\r\n position: absolute;\r\n right: 0;\r\n top: 0;\r\n bottom: 0;\r\n width: 2px;\r\n background: var(--tbw-reorder-indicator, var(--tbw-color-accent));\r\n z-index: 1;\r\n }\r\n `;\r\n}\r\n","import type { ServerSideDataSource, GetRowsParams, GetRowsResult } from './types';\n\nexport function getBlockNumber(rowIndex: number, blockSize: number): number {\n return Math.floor(rowIndex / blockSize);\n}\n\nexport function getBlockRange(blockNumber: number, blockSize: number): { start: number; end: number } {\n return {\n start: blockNumber * blockSize,\n end: (blockNumber + 1) * blockSize,\n };\n}\n\nexport function getRequiredBlocks(startRow: number, endRow: number, blockSize: number): number[] {\n const startBlock = getBlockNumber(startRow, blockSize);\n const endBlock = getBlockNumber(endRow - 1, blockSize);\n\n const blocks: number[] = [];\n for (let i = startBlock; i <= endBlock; i++) {\n blocks.push(i);\n }\n return blocks;\n}\n\nexport async function loadBlock(\n dataSource: ServerSideDataSource,\n blockNumber: number,\n blockSize: number,\n params: Partial<GetRowsParams>\n): Promise<GetRowsResult> {\n const range = getBlockRange(blockNumber, blockSize);\n\n return dataSource.getRows({\n startRow: range.start,\n endRow: range.end,\n sortModel: params.sortModel,\n filterModel: params.filterModel,\n });\n}\n\nexport function getRowFromCache(\n rowIndex: number,\n blockSize: number,\n loadedBlocks: Map<number, any[]>\n): any | undefined {\n const blockNumber = getBlockNumber(rowIndex, blockSize);\n const block = loadedBlocks.get(blockNumber);\n if (!block) return undefined;\n\n const indexInBlock = rowIndex % blockSize;\n return block[indexInBlock];\n}\n\nexport function isBlockLoaded(blockNumber: number, loadedBlocks: Map<number, any[]>): boolean {\n return loadedBlocks.has(blockNumber);\n}\n\nexport function isBlockLoading(blockNumber: number, loadingBlocks: Set<number>): boolean {\n return loadingBlocks.has(blockNumber);\n}\n","/**\n * Server-Side Data Plugin (Class-based)\n *\n * Provides server-side data loading with caching and lazy loading.\n */\n\nimport { BaseGridPlugin, ScrollEvent } from '../../core/plugin/base-plugin';\nimport { getBlockNumber, getRequiredBlocks, getRowFromCache, loadBlock } from './datasource';\nimport type { ServerSideConfig, ServerSideDataSource } from './types';\n\n/** Scroll debounce delay in ms */\nconst SCROLL_DEBOUNCE_MS = 100;\n\n/**\n * Server-Side Plugin for tbw-grid\n *\n * @example\n * ```ts\n * const plugin = new ServerSidePlugin({ cacheBlockSize: 100 });\n * plugin.setDataSource(myDataSource);\n * ```\n */\nexport class ServerSidePlugin extends BaseGridPlugin<ServerSideConfig> {\n readonly name = 'serverSide';\n override readonly version = '1.0.0';\n\n protected override get defaultConfig(): Partial<ServerSideConfig> {\n return {\n enabled: true,\n pageSize: 100,\n cacheBlockSize: 100,\n maxConcurrentRequests: 2,\n };\n }\n\n // ===== Internal State =====\n private dataSource: ServerSideDataSource | null = null;\n private totalRowCount = 0;\n private loadedBlocks = new Map<number, unknown[]>();\n private loadingBlocks = new Set<number>();\n private lastRequestId = 0;\n private scrollDebounceTimer?: ReturnType<typeof setTimeout>;\n\n // ===== Lifecycle =====\n\n override detach(): void {\n this.dataSource = null;\n this.totalRowCount = 0;\n this.loadedBlocks.clear();\n this.loadingBlocks.clear();\n this.lastRequestId = 0;\n if (this.scrollDebounceTimer) {\n clearTimeout(this.scrollDebounceTimer);\n this.scrollDebounceTimer = undefined;\n }\n }\n\n // ===== Private Methods =====\n\n /**\n * Check current viewport and load any missing blocks.\n */\n private loadRequiredBlocks(): void {\n if (!this.dataSource) return;\n\n // Get fresh viewport from grid's virtualization state\n const gridRef = this.grid as unknown as { virtualization: { start: number; end: number } };\n const blockSize = this.config.cacheBlockSize ?? 100;\n const viewport = { startRow: gridRef.virtualization.start, endRow: gridRef.virtualization.end };\n\n // Determine which blocks are needed for current viewport\n const requiredBlocks = getRequiredBlocks(viewport.startRow, viewport.endRow, blockSize);\n\n // Load missing blocks\n for (const blockNum of requiredBlocks) {\n if (this.loadedBlocks.has(blockNum) || this.loadingBlocks.has(blockNum)) {\n continue;\n }\n\n // Check concurrent request limit\n if (this.loadingBlocks.size >= (this.config.maxConcurrentRequests ?? 2)) {\n break;\n }\n\n this.loadingBlocks.add(blockNum);\n\n loadBlock(this.dataSource, blockNum, blockSize, {})\n .then((result) => {\n this.loadedBlocks.set(blockNum, result.rows);\n this.totalRowCount = result.totalRowCount;\n this.loadingBlocks.delete(blockNum);\n this.requestRender();\n // Re-check with fresh viewport: user may have scrolled further\n this.loadRequiredBlocks();\n })\n .catch(() => {\n this.loadingBlocks.delete(blockNum);\n });\n }\n }\n\n // ===== Hooks =====\n\n override processRows(rows: readonly unknown[]): unknown[] {\n if (!this.dataSource) return [...rows];\n\n // Create placeholder rows for total count\n const result: unknown[] = [];\n for (let i = 0; i < this.totalRowCount; i++) {\n const cached = getRowFromCache(i, this.config.cacheBlockSize ?? 100, this.loadedBlocks);\n result.push(cached ?? { __loading: true, __index: i });\n }\n\n return result;\n }\n\n override onScroll(event: ScrollEvent): void {\n if (!this.dataSource) return;\n\n // Immediate check for blocks\n this.loadRequiredBlocks();\n\n // Debounce: when scrolling stops, do a final check with fresh viewport\n if (this.scrollDebounceTimer) {\n clearTimeout(this.scrollDebounceTimer);\n }\n this.scrollDebounceTimer = setTimeout(() => {\n this.loadRequiredBlocks();\n }, SCROLL_DEBOUNCE_MS);\n }\n\n // ===== Public API =====\n\n /**\n * Set the data source for server-side loading.\n * @param dataSource - Data source implementing the getRows method\n */\n setDataSource(dataSource: ServerSideDataSource): void {\n this.dataSource = dataSource;\n this.loadedBlocks.clear();\n this.loadingBlocks.clear();\n\n // Load first block\n const blockSize = this.config.cacheBlockSize ?? 100;\n loadBlock(dataSource, 0, blockSize, {}).then((result) => {\n this.loadedBlocks.set(0, result.rows);\n this.totalRowCount = result.totalRowCount;\n this.requestRender();\n });\n }\n\n /**\n * Refresh all data from the server.\n */\n refresh(): void {\n if (!this.dataSource) return;\n this.loadedBlocks.clear();\n this.loadingBlocks.clear();\n this.requestRender();\n }\n\n /**\n * Clear all cached data without refreshing.\n */\n purgeCache(): void {\n this.loadedBlocks.clear();\n }\n\n /**\n * Get the total row count from the server.\n */\n getTotalRowCount(): number {\n return this.totalRowCount;\n }\n\n /**\n * Check if a specific row is loaded in the cache.\n * @param rowIndex - Row index to check\n */\n isRowLoaded(rowIndex: number): boolean {\n const blockSize = this.config.cacheBlockSize ?? 100;\n const blockNum = getBlockNumber(rowIndex, blockSize);\n return this.loadedBlocks.has(blockNum);\n }\n\n /**\n * Get the number of loaded cache blocks.\n */\n getLoadedBlockCount(): number {\n return this.loadedBlocks.size;\n }\n}\n","/**\n * Undo/Redo History Management\n *\n * Pure functions for managing the undo/redo stacks.\n * These functions are stateless and return new state objects.\n */\n\nimport type { EditAction, UndoRedoState } from './types';\n\n/**\n * Push a new action onto the undo stack.\n * Clears the redo stack since new actions invalidate redo history.\n *\n * @param state - Current undo/redo state\n * @param action - The action to add\n * @param maxSize - Maximum history size\n * @returns New state with the action added\n */\nexport function pushAction(state: UndoRedoState, action: EditAction, maxSize: number): UndoRedoState {\n const undoStack = [...state.undoStack, action];\n\n // Trim oldest actions if over max size\n while (undoStack.length > maxSize) {\n undoStack.shift();\n }\n\n return {\n undoStack,\n redoStack: [], // Clear redo on new action\n };\n}\n\n/**\n * Undo the most recent action.\n * Moves the action from undo stack to redo stack.\n *\n * @param state - Current undo/redo state\n * @returns New state and the action that was undone (or null if nothing to undo)\n */\nexport function undo(state: UndoRedoState): {\n newState: UndoRedoState;\n action: EditAction | null;\n} {\n if (state.undoStack.length === 0) {\n return { newState: state, action: null };\n }\n\n const undoStack = [...state.undoStack];\n const action = undoStack.pop();\n\n // This should never happen due to the length check above,\n // but TypeScript needs the explicit check\n if (!action) {\n return { newState: state, action: null };\n }\n\n return {\n newState: {\n undoStack,\n redoStack: [...state.redoStack, action],\n },\n action,\n };\n}\n\n/**\n * Redo the most recently undone action.\n * Moves the action from redo stack back to undo stack.\n *\n * @param state - Current undo/redo state\n * @returns New state and the action that was redone (or null if nothing to redo)\n */\nexport function redo(state: UndoRedoState): {\n newState: UndoRedoState;\n action: EditAction | null;\n} {\n if (state.redoStack.length === 0) {\n return { newState: state, action: null };\n }\n\n const redoStack = [...state.redoStack];\n const action = redoStack.pop();\n\n // This should never happen due to the length check above,\n // but TypeScript needs the explicit check\n if (!action) {\n return { newState: state, action: null };\n }\n\n return {\n newState: {\n undoStack: [...state.undoStack, action],\n redoStack,\n },\n action,\n };\n}\n\n/**\n * Check if there are any actions that can be undone.\n *\n * @param state - Current undo/redo state\n * @returns True if undo is available\n */\nexport function canUndo(state: UndoRedoState): boolean {\n return state.undoStack.length > 0;\n}\n\n/**\n * Check if there are any actions that can be redone.\n *\n * @param state - Current undo/redo state\n * @returns True if redo is available\n */\nexport function canRedo(state: UndoRedoState): boolean {\n return state.redoStack.length > 0;\n}\n\n/**\n * Clear all history, returning an empty state.\n *\n * @returns Fresh empty state\n */\nexport function clearHistory(): UndoRedoState {\n return { undoStack: [], redoStack: [] };\n}\n\n/**\n * Create a new edit action with the current timestamp.\n *\n * @param rowIndex - The row index where the edit occurred\n * @param field - The field (column key) that was edited\n * @param oldValue - The value before the edit\n * @param newValue - The value after the edit\n * @returns A new EditAction object\n */\nexport function createEditAction(rowIndex: number, field: string, oldValue: unknown, newValue: unknown): EditAction {\n return {\n type: 'cell-edit',\n rowIndex,\n field,\n oldValue,\n newValue,\n timestamp: Date.now(),\n };\n}\n","/**\n * Undo/Redo Plugin (Class-based)\n *\n * Provides undo/redo functionality for cell edits in tbw-grid.\n * Supports Ctrl+Z/Cmd+Z for undo and Ctrl+Y/Cmd+Y (or Ctrl+Shift+Z) for redo.\n */\n\nimport { BaseGridPlugin } from '../../core/plugin/base-plugin';\nimport { canRedo, canUndo, clearHistory, createEditAction, pushAction, redo, undo } from './history';\nimport type { EditAction, UndoRedoConfig, UndoRedoDetail } from './types';\n\n/**\n * Class-based Undo/Redo plugin for tbw-grid.\n *\n * Tracks cell edits and provides undo/redo functionality via keyboard shortcuts\n * or programmatic API.\n */\nexport class UndoRedoPlugin extends BaseGridPlugin<UndoRedoConfig> {\n readonly name = 'undoRedo';\n override readonly version = '1.0.0';\n\n protected override get defaultConfig(): Partial<UndoRedoConfig> {\n return {\n enabled: true,\n maxHistorySize: 100,\n };\n }\n\n // State as class properties\n private undoStack: EditAction[] = [];\n private redoStack: EditAction[] = [];\n\n /**\n * Clean up state when plugin is detached.\n */\n override detach(): void {\n this.undoStack = [];\n this.redoStack = [];\n }\n\n /**\n * Handle keyboard shortcuts for undo/redo.\n * - Ctrl+Z / Cmd+Z: Undo\n * - Ctrl+Y / Cmd+Y / Ctrl+Shift+Z / Cmd+Shift+Z: Redo\n */\n override onKeyDown(event: KeyboardEvent): boolean {\n if (!this.config.enabled) return false;\n\n const isUndo = (event.ctrlKey || event.metaKey) && event.key === 'z' && !event.shiftKey;\n const isRedo = (event.ctrlKey || event.metaKey) && (event.key === 'y' || (event.key === 'z' && event.shiftKey));\n\n if (isUndo) {\n const result = undo({ undoStack: this.undoStack, redoStack: this.redoStack });\n if (result.action) {\n // Apply undo - restore old value\n const rows = this.rows as Record<string, unknown>[];\n if (rows[result.action.rowIndex]) {\n rows[result.action.rowIndex][result.action.field] = result.action.oldValue;\n }\n\n // Update state from result\n this.undoStack = result.newState.undoStack;\n this.redoStack = result.newState.redoStack;\n\n this.emit<UndoRedoDetail>('undo', {\n action: result.action,\n type: 'undo',\n });\n\n this.requestRender();\n }\n return true;\n }\n\n if (isRedo) {\n const result = redo({ undoStack: this.undoStack, redoStack: this.redoStack });\n if (result.action) {\n // Apply redo - restore new value\n const rows = this.rows as Record<string, unknown>[];\n if (rows[result.action.rowIndex]) {\n rows[result.action.rowIndex][result.action.field] = result.action.newValue;\n }\n\n // Update state from result\n this.undoStack = result.newState.undoStack;\n this.redoStack = result.newState.redoStack;\n\n this.emit<UndoRedoDetail>('redo', {\n action: result.action,\n type: 'redo',\n });\n\n this.requestRender();\n }\n return true;\n }\n\n return false;\n }\n\n // ===== Public API Methods =====\n\n /**\n * Record a cell edit for undo/redo tracking.\n * Call this when a cell value changes.\n *\n * @param rowIndex - The row index where the edit occurred\n * @param field - The field (column key) that was edited\n * @param oldValue - The value before the edit\n * @param newValue - The value after the edit\n */\n recordEdit(rowIndex: number, field: string, oldValue: unknown, newValue: unknown): void {\n const action = createEditAction(rowIndex, field, oldValue, newValue);\n const newState = pushAction(\n { undoStack: this.undoStack, redoStack: this.redoStack },\n action,\n this.config.maxHistorySize ?? 100\n );\n this.undoStack = newState.undoStack;\n this.redoStack = newState.redoStack;\n }\n\n /**\n * Programmatically undo the last action.\n *\n * @returns The undone action, or null if nothing to undo\n */\n undo(): EditAction | null {\n const result = undo({ undoStack: this.undoStack, redoStack: this.redoStack });\n if (result.action) {\n const rows = this.rows as Record<string, unknown>[];\n if (rows[result.action.rowIndex]) {\n rows[result.action.rowIndex][result.action.field] = result.action.oldValue;\n }\n this.undoStack = result.newState.undoStack;\n this.redoStack = result.newState.redoStack;\n this.requestRender();\n }\n return result.action;\n }\n\n /**\n * Programmatically redo the last undone action.\n *\n * @returns The redone action, or null if nothing to redo\n */\n redo(): EditAction | null {\n const result = redo({ undoStack: this.undoStack, redoStack: this.redoStack });\n if (result.action) {\n const rows = this.rows as Record<string, unknown>[];\n if (rows[result.action.rowIndex]) {\n rows[result.action.rowIndex][result.action.field] = result.action.newValue;\n }\n this.undoStack = result.newState.undoStack;\n this.redoStack = result.newState.redoStack;\n this.requestRender();\n }\n return result.action;\n }\n\n /**\n * Check if there are any actions that can be undone.\n */\n canUndo(): boolean {\n return canUndo({ undoStack: this.undoStack, redoStack: this.redoStack });\n }\n\n /**\n * Check if there are any actions that can be redone.\n */\n canRedo(): boolean {\n return canRedo({ undoStack: this.undoStack, redoStack: this.redoStack });\n }\n\n /**\n * Clear all undo/redo history.\n */\n clearHistory(): void {\n const newState = clearHistory();\n this.undoStack = newState.undoStack;\n this.redoStack = newState.redoStack;\n }\n\n /**\n * Get a copy of the current undo stack.\n */\n getUndoStack(): EditAction[] {\n return [...this.undoStack];\n }\n\n /**\n * Get a copy of the current redo stack.\n */\n getRedoStack(): EditAction[] {\n return [...this.redoStack];\n }\n}\n","/**\r\n * Column Visibility Plugin (Class-based)\r\n *\r\n * Provides a UI for column visibility control via the shell's tool panel system.\r\n * Column visibility is a core grid feature - this plugin provides:\r\n * - A tool panel for column visibility management (registered with the shell)\r\n * - Backward-compatible API methods that delegate to grid.setColumnVisible(), etc.\r\n *\r\n * The grid emits 'column-visibility' events when columns are shown/hidden,\r\n * allowing consumers to save user preferences.\r\n *\r\n * When a reorder plugin is present, column rows become draggable for reordering.\r\n * Drag-drop emits 'column-reorder-request' events that the ReorderPlugin can listen for.\r\n */\r\n\r\nimport { BaseGridPlugin } from '../../core/plugin/base-plugin';\r\nimport type { ColumnConfig, ToolPanelDefinition } from '../../core/types';\r\nimport type { VisibilityConfig } from './types';\r\n\r\n/**\r\n * Detail for column-reorder-request events emitted when users drag-drop in the visibility panel.\r\n */\r\nexport interface ColumnReorderRequestDetail {\r\n /** The field name of the column to move */\r\n field: string;\r\n /** The source index (before move) */\r\n fromIndex: number;\r\n /** The target index (after move) */\r\n toIndex: number;\r\n}\r\n\r\n/**\r\n * Check if a column can be moved (respects lockPosition/suppressMovable).\r\n * Inlined to avoid importing from reorder plugin.\r\n */\r\nfunction canMoveColumn(column: ColumnConfig): boolean {\r\n const meta = column.meta ?? {};\r\n return meta.lockPosition !== true && meta.suppressMovable !== true;\r\n}\r\n\r\n/** Extended grid interface with visibility methods */\r\ninterface GridWithVisibility {\r\n shadowRoot: ShadowRoot | null;\r\n getAllColumns(): Array<{ field: string; header: string; visible: boolean; lockVisible?: boolean }>;\r\n setColumnVisible(field: string, visible: boolean): void;\r\n toggleColumnVisibility(field: string): void;\r\n showAllColumns(): void;\r\n isColumnVisible(field: string): boolean;\r\n requestRender(): void;\r\n openToolPanel(id: string): void;\r\n closeToolPanel(): void;\r\n toggleToolPanel(id: string): void;\r\n activeToolPanel: string | undefined;\r\n}\r\n\r\n/**\r\n * Column Visibility Plugin for tbw-grid\r\n *\r\n * @example\r\n * ```ts\r\n * new VisibilityPlugin({ enabled: true, allowHideAll: false })\r\n * ```\r\n */\r\nexport class VisibilityPlugin extends BaseGridPlugin<VisibilityConfig> {\r\n readonly name = 'visibility';\r\n override readonly version = '1.0.0';\r\n\r\n /** Tool panel ID for shell integration */\r\n static readonly PANEL_ID = 'columns';\r\n\r\n protected override get defaultConfig(): Partial<VisibilityConfig> {\r\n return {\r\n enabled: true,\r\n allowHideAll: false,\r\n };\r\n }\r\n\r\n // ===== Internal State =====\r\n private columnListElement: HTMLElement | null = null;\r\n\r\n // Drag state for reorder integration\r\n private isDragging = false;\r\n private draggedField: string | null = null;\r\n private draggedIndex: number | null = null;\r\n private dropIndex: number | null = null;\r\n\r\n // ===== Lifecycle =====\r\n\r\n override detach(): void {\r\n this.columnListElement = null;\r\n this.isDragging = false;\r\n this.draggedField = null;\r\n this.draggedIndex = null;\r\n this.dropIndex = null;\r\n }\r\n\r\n // ===== Shell Integration =====\r\n\r\n /**\r\n * Register the column visibility tool panel with the shell.\r\n */\r\n override getToolPanel(): ToolPanelDefinition | undefined {\r\n if (!this.config.enabled) return undefined;\r\n\r\n return {\r\n id: VisibilityPlugin.PANEL_ID,\r\n title: 'Columns',\r\n icon: '☰',\r\n tooltip: 'Column visibility',\r\n order: 100, // High order so it appears last\r\n render: (container) => this.renderPanelContent(container),\r\n };\r\n }\r\n\r\n // ===== Public API =====\r\n\r\n /**\r\n * Show the visibility sidebar panel.\r\n */\r\n show(): void {\r\n const grid = this.grid as unknown as GridWithVisibility;\r\n grid.openToolPanel(VisibilityPlugin.PANEL_ID);\r\n }\r\n\r\n /**\r\n * Hide the visibility sidebar panel.\r\n */\r\n hide(): void {\r\n const grid = this.grid as unknown as GridWithVisibility;\r\n grid.closeToolPanel();\r\n }\r\n\r\n /**\r\n * Toggle the visibility sidebar panel.\r\n */\r\n toggle(): void {\r\n const grid = this.grid as unknown as GridWithVisibility;\r\n grid.toggleToolPanel(VisibilityPlugin.PANEL_ID);\r\n }\r\n\r\n /**\r\n * Check if a specific column is visible.\r\n * Delegates to grid.isColumnVisible().\r\n * @param field - The field name to check\r\n * @returns True if the column is visible\r\n */\r\n isColumnVisible(field: string): boolean {\r\n const grid = this.grid as unknown as GridWithVisibility;\r\n return grid.isColumnVisible(field);\r\n }\r\n\r\n /**\r\n * Set visibility for a specific column.\r\n * Delegates to grid.setColumnVisible().\r\n * @param field - The field name of the column\r\n * @param visible - Whether the column should be visible\r\n */\r\n setColumnVisible(field: string, visible: boolean): void {\r\n const grid = this.grid as unknown as GridWithVisibility;\r\n grid.setColumnVisible(field, visible);\r\n }\r\n\r\n /**\r\n * Get list of all visible column fields.\r\n * @returns Array of visible field names\r\n */\r\n getVisibleColumns(): string[] {\r\n const grid = this.grid as unknown as GridWithVisibility;\r\n return grid\r\n .getAllColumns()\r\n .filter((c) => c.visible)\r\n .map((c) => c.field);\r\n }\r\n\r\n /**\r\n * Get list of all hidden column fields.\r\n * @returns Array of hidden field names\r\n */\r\n getHiddenColumns(): string[] {\r\n const grid = this.grid as unknown as GridWithVisibility;\r\n return grid\r\n .getAllColumns()\r\n .filter((c) => !c.visible)\r\n .map((c) => c.field);\r\n }\r\n\r\n /**\r\n * Show all columns.\r\n * Delegates to grid.showAllColumns().\r\n */\r\n showAll(): void {\r\n const grid = this.grid as unknown as GridWithVisibility;\r\n grid.showAllColumns();\r\n }\r\n\r\n /**\r\n * Toggle visibility for a specific column.\r\n * Delegates to grid.toggleColumnVisibility().\r\n * @param field - The field name of the column\r\n */\r\n toggleColumn(field: string): void {\r\n const grid = this.grid as unknown as GridWithVisibility;\r\n grid.toggleColumnVisibility(field);\r\n }\r\n\r\n /**\r\n * Show a specific column.\r\n * Delegates to grid.setColumnVisible().\r\n * @param field - The field name of the column to show\r\n */\r\n showColumn(field: string): void {\r\n const grid = this.grid as unknown as GridWithVisibility;\r\n grid.setColumnVisible(field, true);\r\n }\r\n\r\n /**\r\n * Hide a specific column.\r\n * Delegates to grid.setColumnVisible().\r\n * @param field - The field name of the column to hide\r\n */\r\n hideColumn(field: string): void {\r\n const grid = this.grid as unknown as GridWithVisibility;\r\n grid.setColumnVisible(field, false);\r\n }\r\n\r\n /**\r\n * Get all columns with their visibility status.\r\n * Useful for building visibility UI.\r\n * @returns Array of column info with visibility status\r\n */\r\n getAllColumns(): Array<{ field: string; header: string; visible: boolean; lockVisible?: boolean }> {\r\n const grid = this.grid as unknown as GridWithVisibility;\r\n return grid.getAllColumns();\r\n }\r\n\r\n /**\r\n * Check if the sidebar panel is currently open.\r\n * @returns True if the panel is open\r\n */\r\n isPanelVisible(): boolean {\r\n const grid = this.grid as unknown as GridWithVisibility;\r\n return grid.activeToolPanel === VisibilityPlugin.PANEL_ID;\r\n }\r\n\r\n // ===== Private Methods =====\r\n\r\n /**\r\n * Render the panel content into the shell's tool panel container.\r\n * Returns a cleanup function.\r\n */\r\n private renderPanelContent(container: HTMLElement): (() => void) | void {\r\n const grid = this.grid as unknown as GridWithVisibility;\r\n\r\n // Create content wrapper\r\n const wrapper = document.createElement('div');\r\n wrapper.className = 'tbw-visibility-content';\r\n\r\n // Column list container\r\n const columnList = document.createElement('div');\r\n columnList.className = 'tbw-visibility-list';\r\n wrapper.appendChild(columnList);\r\n\r\n // Show all button\r\n const showAllBtn = document.createElement('button');\r\n showAllBtn.className = 'tbw-visibility-show-all';\r\n showAllBtn.textContent = 'Show All';\r\n showAllBtn.addEventListener('click', () => {\r\n grid.showAllColumns();\r\n this.rebuildToggles(columnList);\r\n });\r\n wrapper.appendChild(showAllBtn);\r\n\r\n // Store reference\r\n this.columnListElement = columnList;\r\n\r\n // Build initial toggles\r\n this.rebuildToggles(columnList);\r\n\r\n // Append to container\r\n container.appendChild(wrapper);\r\n\r\n // Return cleanup function\r\n return () => {\r\n this.columnListElement = null;\r\n wrapper.remove();\r\n };\r\n }\r\n\r\n /**\r\n * Check if a reorder plugin is present (by name to avoid static import).\r\n */\r\n private hasReorderPlugin(): boolean {\r\n const plugin = this.grid?.getPluginByName?.('reorder');\r\n // Duck-type check - just verify the plugin exists and has a moveColumn method\r\n return !!(plugin && typeof (plugin as { moveColumn?: unknown }).moveColumn === 'function');\r\n }\r\n\r\n /**\r\n * Build the column toggle checkboxes.\r\n * When a reorder plugin is present, adds drag handles for reordering.\r\n */\r\n private rebuildToggles(columnList: HTMLElement): void {\r\n const grid = this.grid as unknown as GridWithVisibility;\r\n const reorderEnabled = this.hasReorderPlugin();\r\n\r\n columnList.innerHTML = '';\r\n\r\n // getAllColumns() now returns columns in their effective display order\r\n const allColumns = grid.getAllColumns();\r\n\r\n for (let i = 0; i < allColumns.length; i++) {\r\n const col = allColumns[i];\r\n const label = col.header || col.field;\r\n\r\n const row = document.createElement('div');\r\n row.className = col.lockVisible ? 'tbw-visibility-row locked' : 'tbw-visibility-row';\r\n row.setAttribute('data-field', col.field);\r\n row.setAttribute('data-index', String(i));\r\n\r\n // Add drag handle if reorder is enabled\r\n if (reorderEnabled && canMoveColumn(col as unknown as ColumnConfig)) {\r\n row.draggable = true;\r\n row.classList.add('reorderable');\r\n\r\n this.setupDragListeners(row, col.field, i, columnList);\r\n }\r\n\r\n const labelWrapper = document.createElement('label');\r\n labelWrapper.className = 'tbw-visibility-label';\r\n\r\n const checkbox = document.createElement('input');\r\n checkbox.type = 'checkbox';\r\n checkbox.checked = col.visible;\r\n checkbox.disabled = col.lockVisible ?? false;\r\n checkbox.addEventListener('change', () => {\r\n grid.toggleColumnVisibility(col.field);\r\n // Refresh after toggle (grid may re-render)\r\n setTimeout(() => this.rebuildToggles(columnList), 0);\r\n });\r\n\r\n const text = document.createElement('span');\r\n text.textContent = label;\r\n\r\n labelWrapper.appendChild(checkbox);\r\n labelWrapper.appendChild(text);\r\n\r\n // Add drag handle icon if reorderable\r\n if (reorderEnabled && canMoveColumn(col as unknown as ColumnConfig)) {\r\n const handle = document.createElement('span');\r\n handle.className = 'tbw-visibility-handle';\r\n handle.textContent = '⋮⋮';\r\n handle.title = 'Drag to reorder';\r\n row.appendChild(handle);\r\n }\r\n\r\n row.appendChild(labelWrapper);\r\n columnList.appendChild(row);\r\n }\r\n }\r\n\r\n /**\r\n * Set up drag-and-drop event listeners for a row.\r\n * On drop, emits a 'column-reorder-request' event for other plugins to handle.\r\n */\r\n private setupDragListeners(row: HTMLElement, field: string, index: number, columnList: HTMLElement): void {\r\n row.addEventListener('dragstart', (e: DragEvent) => {\r\n this.isDragging = true;\r\n this.draggedField = field;\r\n this.draggedIndex = index;\r\n\r\n if (e.dataTransfer) {\r\n e.dataTransfer.effectAllowed = 'move';\r\n e.dataTransfer.setData('text/plain', field);\r\n }\r\n\r\n row.classList.add('dragging');\r\n });\r\n\r\n row.addEventListener('dragend', () => {\r\n this.isDragging = false;\r\n this.draggedField = null;\r\n this.draggedIndex = null;\r\n this.dropIndex = null;\r\n\r\n columnList.querySelectorAll('.tbw-visibility-row').forEach((r) => {\r\n r.classList.remove('dragging', 'drop-target', 'drop-before', 'drop-after');\r\n });\r\n });\r\n\r\n row.addEventListener('dragover', (e: DragEvent) => {\r\n e.preventDefault();\r\n if (!this.isDragging || this.draggedField === field) return;\r\n\r\n const rect = row.getBoundingClientRect();\r\n const midY = rect.top + rect.height / 2;\r\n\r\n this.dropIndex = e.clientY < midY ? index : index + 1;\r\n\r\n // Clear other row highlights\r\n columnList.querySelectorAll('.tbw-visibility-row').forEach((r) => {\r\n if (r !== row) r.classList.remove('drop-target', 'drop-before', 'drop-after');\r\n });\r\n\r\n row.classList.add('drop-target');\r\n row.classList.toggle('drop-before', e.clientY < midY);\r\n row.classList.toggle('drop-after', e.clientY >= midY);\r\n });\r\n\r\n row.addEventListener('dragleave', () => {\r\n row.classList.remove('drop-target', 'drop-before', 'drop-after');\r\n });\r\n\r\n row.addEventListener('drop', (e: DragEvent) => {\r\n e.preventDefault();\r\n const draggedField = this.draggedField;\r\n const draggedIndex = this.draggedIndex;\r\n const dropIndex = this.dropIndex;\r\n\r\n if (!this.isDragging || draggedField === null || draggedIndex === null || dropIndex === null) {\r\n return;\r\n }\r\n\r\n // Calculate the effective target index\r\n const effectiveToIndex = dropIndex > draggedIndex ? dropIndex - 1 : dropIndex;\r\n\r\n if (effectiveToIndex !== draggedIndex) {\r\n // Emit a request event - other plugins (like ReorderPlugin) can listen and handle\r\n const detail: ColumnReorderRequestDetail = {\r\n field: draggedField,\r\n fromIndex: draggedIndex,\r\n toIndex: effectiveToIndex,\r\n };\r\n this.emit<ColumnReorderRequestDetail>('column-reorder-request', detail);\r\n\r\n // Rebuild the panel after reorder (deferred to allow re-render)\r\n setTimeout(() => {\r\n this.rebuildToggles(columnList);\r\n }, 0);\r\n }\r\n });\r\n }\r\n\r\n // ===== Styles =====\r\n\r\n override readonly styles = `\r\n .tbw-visibility-content {\r\n display: flex;\r\n flex-direction: column;\r\n height: 100%;\r\n }\r\n\r\n .tbw-visibility-list {\r\n flex: 1;\r\n overflow-y: auto;\r\n padding: 8px;\r\n }\r\n\r\n .tbw-visibility-row {\r\n display: flex;\r\n align-items: center;\r\n gap: 8px;\r\n padding: 6px 4px;\r\n cursor: pointer;\r\n font-size: 13px;\r\n border-radius: var(--tbw-border-radius, 4px);\r\n position: relative;\r\n }\r\n .tbw-visibility-row:hover {\r\n background: var(--tbw-visibility-hover, var(--tbw-color-row-hover, #f3f4f6));\r\n }\r\n .tbw-visibility-row input[type=\"checkbox\"] {\r\n cursor: pointer;\r\n }\r\n .tbw-visibility-row.locked span {\r\n color: var(--tbw-color-fg-muted, #888);\r\n }\r\n\r\n /* Drag handle */\r\n .tbw-visibility-handle {\r\n cursor: grab;\r\n color: var(--tbw-color-fg-muted, #888);\r\n font-size: 10px;\r\n letter-spacing: -2px;\r\n user-select: none;\r\n flex-shrink: 0;\r\n }\r\n .tbw-visibility-row.reorderable:hover .tbw-visibility-handle {\r\n color: var(--tbw-color-fg, #1f2937);\r\n }\r\n\r\n /* Label wrapper for checkbox and text */\r\n .tbw-visibility-label {\r\n display: flex;\r\n align-items: center;\r\n gap: 8px;\r\n flex: 1;\r\n cursor: pointer;\r\n }\r\n\r\n /* Drag states */\r\n .tbw-visibility-row.dragging {\r\n opacity: 0.5;\r\n cursor: grabbing;\r\n }\r\n .tbw-visibility-row.drop-before::before {\r\n content: '';\r\n position: absolute;\r\n left: 0;\r\n right: 0;\r\n top: 0;\r\n height: 2px;\r\n background: var(--tbw-reorder-indicator, var(--tbw-color-accent, #3b82f6));\r\n }\r\n .tbw-visibility-row.drop-after::after {\r\n content: '';\r\n position: absolute;\r\n left: 0;\r\n right: 0;\r\n bottom: 0;\r\n height: 2px;\r\n background: var(--tbw-reorder-indicator, var(--tbw-color-accent, #3b82f6));\r\n }\r\n\r\n .tbw-visibility-show-all {\r\n margin: 8px;\r\n padding: 8px 12px;\r\n border: 1px solid var(--tbw-visibility-border, var(--tbw-color-border, #e5e7eb));\r\n border-radius: var(--tbw-border-radius, 4px);\r\n background: var(--tbw-visibility-btn-bg, var(--tbw-color-header-bg, #f9fafb));\r\n color: var(--tbw-color-fg, #1f2937);\r\n cursor: pointer;\r\n font-size: 13px;\r\n }\r\n .tbw-visibility-show-all:hover {\r\n background: var(--tbw-visibility-hover, var(--tbw-color-row-hover, #f3f4f6));\r\n }\r\n `;\r\n}\r\n"],"names":["formatCellValue","value","field","row","config","str","delimiter","newline","buildClipboardText","params","rows","columns","selectedIndices","visibleColumns","c","lines","headerCells","header","sortedIndices","a","b","idx","cells","col","copyToClipboard","text","textarea","success","parseClipboardText","normalizedText","currentRow","currentCell","inQuotes","i","char","readFromClipboard","ClipboardPlugin","BaseGridPlugin","event","isCopy","isPaste","#handleCopy","#handlePaste","target","selectionPlugin","#getSelectionPlugin","selectedRows","hasRowSelection","ranges","hasRangeSelection","hasCellSelection","rowCount","columnCount","range","result","#buildRangeText","cell","#buildCellText","#buildSingleCellText","parsed","grid","plugin","rowIndex","colIndex","rowData","column","formattedValue","startRow","startCol","endRow","endCol","minRow","maxRow","minCol","maxCol","rangeColumns","r","rowIndexStr","indices","DEFAULT_COLUMN_WIDTH","parseColumnWidth","width","numeric","getColumnWidths","computeColumnOffsets","offsets","offset","computeTotalWidth","sum","getVisibleColumnRange","scrollLeft","viewportWidth","columnOffsets","columnWidths","overscan","binarySearchFirstVisible","rightEdge","low","high","mid","shouldVirtualize","threshold","autoEnable","ColumnVirtualizationPlugin","isVirtualized","viewport","shadowRoot","leftPadding","headerRow","bodyRows","rowsContainer","columnIndex","gridEl","buildMenuItems","items","item","isItemDisabled","createMenuElement","onAction","menu","separator","menuItem","disabled","icon","label","shortcut","arrow","subMenuItems","subMenu","e","positionMenu","x","y","menuRect","viewportHeight","left","top","globalClickHandler","globalKeydownHandler","globalStyleSheet","contextMenuStyles","defaultItems","ContextMenuPlugin","container","fullParams","formatCsvValue","quote","buildCsv","options","bom","processed","downloadBlob","blob","fileName","url","link","downloadCsv","content","escapeXml","buildExcelXml","xml","type","displayValue","downloadExcel","finalName","ExportPlugin","format","colSet","selectionState","jsonData","obj","computeVirtualWindow","totalRows","scrollTop","rowHeight","visibleRows","start","end","shouldBypassVirtualization","matchesFilter","filter","caseSensitive","rawValue","stringValue","compareValue","filterValue","filterRows","filters","f","computeFilterCacheKey","getUniqueValues","values","filterPanelStyles","FilteringPlugin","filterList","newCacheKey","filterBtn","style","buttonEl","panel","uniqueValues","excludedSet","currentSearchText","excluded","operator","valueTo","usedCustomRenderer","handler","rect","panelRect","excludedValues","searchContainer","searchInput","actionsRow","selectAllLabel","selectAllCheckbox","selectAllText","updateSelectAllState","checkState","allChecked","v","noneChecked","newState","key","renderVisibleItems","valuesContainer","spacer","contentContainer","filteredValues","createItem","index","strValue","checkbox","totalItems","window","renderValues","filterText","lowerFilter","noMatch","debounceTimer","buttonRow","applyBtn","isChecked","original","clearBtn","filterModel","state","computeColumnGroups","explicitMap","groupsOrdered","pushImplicit","startIdx","cols","prev","run","runStart","g","id","group","applyGroupedHeaderCellClasses","headerRowEl","groups","fieldToGroup","gid","last","buildGroupHeaderRow","groupRow","startIndex","isImplicit","hasColumnGroups","GroupingColumnsPlugin","existingGroupRow","groupId","buildGroupedRowModel","expanded","groupOn","root","path","parent","rawVal","depthIdx","seg","composite","node","flat","visit","isExpanded","toggleGroupExpansion","expandedKeys","newSet","expandAllGroups","keys","collapseAllGroups","getGroupRowCount","GroupingRowsPlugin","grouped","rowEl","_rowIndex","toggleExpand","handleToggle","btn","labelText","count","aggregators","groupRows","gridTemplate","colIdx","firstColAgg","aggResult","runAggregator","aggRef","newKeys","fn","toggleDetailRow","expandedRows","newExpanded","expandDetailRow","collapseDetailRow","isDetailExpanded","createDetailElement","renderer","detailRow","detailCell","MasterDetailPlugin","firstCol","originalRenderer","renderCtx","toggle","rendered","body","el","dataRows","firstCell","detailEl","applySorts","sorts","sort","comparator","defaultComparator","aVal","bVal","toggleSort","current","shiftKey","maxColumns","existing","s","getSortIndex","sortModel","getSortDirection","MultiSortPlugin","showIndex","sortIndex","sortDir","indicator","badge","model","existingIndex","newEntry","getLeftStickyColumns","getRightStickyColumns","hasStickyColumns","applyStickyOffsets","host","fieldToIndex","right","clearStickyOffsets","PinnedColumnsPlugin","createInfoBarElement","context","pinnedRows","center","filteredCount","selectedCount","panelEl","renderCustomPanel","createAggregationContainer","position","renderAggregationRows","rowConfig","aggFn","getAggregator","staticVal","buildContext","filterState","PinnedRowsPlugin","aggregationRows","topRows","bottomRows","hasInfoContent","hasBottomInfoBar","needsFooter","newInfoBar","p","validatePivotConfig","errors","getPivotAggregator","aggFunc","vals","createValueKey","columnValues","valueField","buildPivot","rowGroupFields","columnGroupFields","valueFields","columnKeys","getUniqueColumnKeys","groupedData","groupByFields","pivotRows","buildPivotRows","totals","calculateTotals","grandTotal","columnFields","fields","depth","rowKey","total","colKey","vf","nums","aggregator","aggregatedResult","valueKey","flattenPivotRows","flatten","child","PivotPlugin","pr","pivotColumns","canMoveColumn","meta","sticky","moveColumn","fromIndex","toIndex","removed","ReorderPlugin","detail","headerEl","orderIndex","h","midX","draggedField","draggedIndex","dropIndex","effectiveToIndex","currentOrder","newOrder","order","originalOrder","getBlockNumber","blockSize","getBlockRange","blockNumber","getRequiredBlocks","startBlock","endBlock","blocks","loadBlock","dataSource","getRowFromCache","loadedBlocks","block","indexInBlock","SCROLL_DEBOUNCE_MS","ServerSidePlugin","gridRef","requiredBlocks","blockNum","cached","pushAction","action","maxSize","undoStack","undo","redo","redoStack","canUndo","canRedo","clearHistory","createEditAction","oldValue","newValue","UndoRedoPlugin","isUndo","isRedo","VisibilityPlugin","visible","wrapper","columnList","showAllBtn","reorderEnabled","allColumns","labelWrapper","handle","midY"],"mappings":"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"}
|