@toolbox-web/grid 0.2.4 → 0.2.6
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 +61 -23
- package/all.js +841 -809
- package/all.js.map +1 -1
- package/index.d.ts +17 -5
- package/index.js +316 -247
- package/index.js.map +1 -1
- package/lib/plugins/clipboard/index.js +1 -1
- package/lib/plugins/clipboard/index.js.map +1 -1
- package/lib/plugins/column-virtualization/index.js +1 -1
- package/lib/plugins/column-virtualization/index.js.map +1 -1
- package/lib/plugins/context-menu/index.js +1 -1
- package/lib/plugins/context-menu/index.js.map +1 -1
- package/lib/plugins/export/index.js +1 -1
- package/lib/plugins/export/index.js.map +1 -1
- package/lib/plugins/filtering/index.js +1 -1
- package/lib/plugins/filtering/index.js.map +1 -1
- package/lib/plugins/grouping-columns/index.js +46 -45
- package/lib/plugins/grouping-columns/index.js.map +1 -1
- package/lib/plugins/grouping-rows/index.js +1 -1
- package/lib/plugins/grouping-rows/index.js.map +1 -1
- package/lib/plugins/master-detail/index.js +1 -1
- package/lib/plugins/master-detail/index.js.map +1 -1
- package/lib/plugins/multi-sort/index.js +1 -1
- package/lib/plugins/multi-sort/index.js.map +1 -1
- package/lib/plugins/pinned-columns/index.js +1 -1
- package/lib/plugins/pinned-columns/index.js.map +1 -1
- package/lib/plugins/pinned-rows/index.js +55 -47
- package/lib/plugins/pinned-rows/index.js.map +1 -1
- package/lib/plugins/pivot/index.js +243 -241
- package/lib/plugins/pivot/index.js.map +1 -1
- package/lib/plugins/reorder/index.js +87 -67
- package/lib/plugins/reorder/index.js.map +1 -1
- package/lib/plugins/selection/index.js +28 -27
- package/lib/plugins/selection/index.js.map +1 -1
- package/lib/plugins/server-side/index.js +2 -2
- package/lib/plugins/server-side/index.js.map +1 -1
- package/lib/plugins/tree/index.js +70 -70
- package/lib/plugins/tree/index.js.map +1 -1
- package/lib/plugins/undo-redo/index.js +1 -1
- package/lib/plugins/undo-redo/index.js.map +1 -1
- package/lib/plugins/visibility/index.js +1 -1
- package/lib/plugins/visibility/index.js.map +1 -1
- package/package.json +1 -1
- package/themes/dg-theme-bootstrap.css +0 -2
- package/themes/dg-theme-contrast.css +0 -1
- package/themes/dg-theme-large.css +0 -1
- package/themes/dg-theme-material.css +0 -2
- package/themes/dg-theme-standard.css +0 -1
- package/themes/dg-theme-vibrant.css +0 -1
- package/umd/grid.all.umd.js +13 -13
- package/umd/grid.all.umd.js.map +1 -1
- package/umd/grid.umd.js +7 -7
- package/umd/grid.umd.js.map +1 -1
- package/umd/plugins/grouping-columns.umd.js +1 -1
- package/umd/plugins/grouping-columns.umd.js.map +1 -1
- package/umd/plugins/pinned-rows.umd.js +1 -1
- package/umd/plugins/pinned-rows.umd.js.map +1 -1
- package/umd/plugins/pivot.umd.js +1 -1
- package/umd/plugins/pivot.umd.js.map +1 -1
- package/umd/plugins/reorder.umd.js +1 -1
- package/umd/plugins/reorder.umd.js.map +1 -1
- package/umd/plugins/selection.umd.js +1 -1
- package/umd/plugins/selection.umd.js.map +1 -1
- package/umd/plugins/server-side.umd.js +1 -1
- package/umd/plugins/server-side.umd.js.map +1 -1
- package/umd/plugins/tree.umd.js +1 -1
- package/umd/plugins/tree.umd.js.map +1 -1
package/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.js","sources":["../../../libs/grid/src/lib/core/internal/column-state.ts","../../../libs/grid/src/lib/core/types.ts","../../../libs/grid/src/lib/core/internal/inference.ts","../../../libs/grid/src/lib/core/internal/sanitize.ts","../../../libs/grid/src/lib/core/internal/columns.ts","../../../libs/grid/src/lib/core/internal/editors.ts","../../../libs/grid/src/lib/core/internal/keyboard.ts","../../../libs/grid/src/lib/core/internal/rows.ts","../../../libs/grid/src/lib/core/internal/editing.ts","../../../libs/grid/src/lib/core/internal/sorting.ts","../../../libs/grid/src/lib/core/internal/header.ts","../../../libs/grid/src/lib/core/internal/resize.ts","../../../libs/grid/src/lib/core/internal/shell.ts","../../../libs/grid/src/lib/core/plugin/plugin-manager.ts","../../../libs/grid/src/lib/core/grid.ts","../../../libs/grid/src/lib/core/plugin/base-plugin.ts","../../../libs/grid/src/lib/core/constants.ts","../../../libs/grid/src/public.ts","../../../libs/grid/src/lib/core/internal/aggregators.ts"],"sourcesContent":["/**\n * Column State Module\n *\n * Handles collection and application of column state for persistence.\n * State includes user-driven changes: order, width, visibility, and sort.\n * Plugins can contribute additional state via getColumnState/applyColumnState hooks.\n */\n\nimport type { BaseGridPlugin } from '../plugin';\nimport type {\n ColumnConfig,\n ColumnInternal,\n ColumnSortState,\n ColumnState,\n GridColumnState,\n InternalGrid,\n} from '../types';\n\n/** Debounce timeout for state change events */\nconst STATE_CHANGE_DEBOUNCE_MS = 100;\n\n/**\n * Get sort state for a column from the grid's sortState.\n */\nfunction getSortState(grid: InternalGrid): Map<string, ColumnSortState> {\n const sortMap = new Map<string, ColumnSortState>();\n\n // Core sort state (single column)\n if (grid._sortState) {\n sortMap.set(grid._sortState.field, {\n direction: grid._sortState.direction === 1 ? 'asc' : 'desc',\n priority: 0,\n });\n }\n\n return sortMap;\n}\n\n/**\n * Collect column state from the grid and all plugins.\n * Returns a complete GridColumnState object ready for serialization.\n */\nexport function collectColumnState<T>(grid: InternalGrid<T>, plugins: BaseGridPlugin[]): GridColumnState {\n const columns = grid._columns;\n const sortStates = getSortState(grid);\n\n return {\n columns: columns.map((col, index) => {\n // 1. Core state\n const state: ColumnState = {\n field: col.field,\n order: index,\n visible: true, // If it's in _columns, it's visible (hidden columns are filtered out)\n };\n\n // Include width if set (either from config or resize)\n const internalCol = col as ColumnInternal<T>;\n if (internalCol.__renderedWidth !== undefined) {\n state.width = internalCol.__renderedWidth;\n } else if (col.width !== undefined) {\n state.width = typeof col.width === 'string' ? parseFloat(col.width) : col.width;\n }\n\n // Include sort state if present\n const sortState = sortStates.get(col.field);\n if (sortState) {\n state.sort = sortState;\n }\n\n // 2. Collect from each plugin\n for (const plugin of plugins) {\n if (plugin.getColumnState) {\n const pluginState = plugin.getColumnState(col.field);\n if (pluginState) {\n Object.assign(state, pluginState);\n }\n }\n }\n\n return state;\n }),\n };\n}\n\n/**\n * Apply column state to the grid and all plugins.\n * Modifies the grid's internal state and triggers plugin state restoration.\n *\n * @param grid - The grid instance\n * @param state - The state to apply\n * @param allColumns - All available columns (including hidden ones)\n * @param plugins - Plugins that may have applyColumnState hooks\n */\nexport function applyColumnState<T>(\n grid: InternalGrid<T>,\n state: GridColumnState,\n allColumns: ColumnConfig<T>[],\n plugins: BaseGridPlugin[],\n): void {\n if (!state.columns || state.columns.length === 0) return;\n\n const stateMap = new Map(state.columns.map((s) => [s.field, s]));\n\n // 1. Apply width and visibility to columns\n const updatedColumns = allColumns.map((col) => {\n const s = stateMap.get(col.field);\n if (!s) return col;\n\n const updated: ColumnInternal<T> = { ...col };\n\n // Apply width\n if (s.width !== undefined) {\n updated.width = s.width;\n updated.__renderedWidth = s.width;\n }\n\n // Apply visibility (hidden is inverse of visible)\n if (s.visible !== undefined) {\n updated.hidden = !s.visible;\n }\n\n return updated;\n });\n\n // 2. Reorder columns based on state\n updatedColumns.sort((a, b) => {\n const orderA = stateMap.get(a.field)?.order ?? Infinity;\n const orderB = stateMap.get(b.field)?.order ?? Infinity;\n return orderA - orderB;\n });\n\n // 3. Update grid's internal columns\n grid._columns = updatedColumns as ColumnInternal<T>[];\n\n // 4. Apply sort state (core single-column sort)\n // Find the column with highest sort priority\n const sortedByPriority = state.columns\n .filter((s) => s.sort !== undefined)\n .sort((a, b) => (a.sort?.priority ?? 0) - (b.sort?.priority ?? 0));\n\n if (sortedByPriority.length > 0) {\n const primarySort = sortedByPriority[0];\n if (primarySort.sort) {\n grid._sortState = {\n field: primarySort.field,\n direction: primarySort.sort.direction === 'asc' ? 1 : -1,\n };\n }\n } else {\n grid._sortState = null;\n }\n\n // 5. Let each plugin apply its state\n for (const plugin of plugins) {\n if (plugin.applyColumnState) {\n for (const colState of state.columns) {\n plugin.applyColumnState(colState.field, colState);\n }\n }\n }\n}\n\n/**\n * Create a state change handler with debouncing.\n * Returns a function that, when called, will eventually emit the state change event.\n */\nexport function createStateChangeHandler<T>(\n grid: InternalGrid<T>,\n getPlugins: () => BaseGridPlugin[],\n emit: (detail: GridColumnState) => void,\n): () => void {\n let timeoutId: ReturnType<typeof setTimeout> | null = null;\n\n return () => {\n // Clear any pending timeout\n if (timeoutId !== null) {\n clearTimeout(timeoutId);\n }\n\n // Schedule the emit\n timeoutId = setTimeout(() => {\n timeoutId = null;\n const state = collectColumnState(grid, getPlugins());\n emit(state);\n }, STATE_CHANGE_DEBOUNCE_MS);\n };\n}\n\n/**\n * Compare two column states to check if they are equal.\n * Useful for preventing duplicate state change events.\n */\nexport function areColumnStatesEqual(a: GridColumnState, b: GridColumnState): boolean {\n if (a.columns.length !== b.columns.length) return false;\n\n for (let i = 0; i < a.columns.length; i++) {\n const colA = a.columns[i];\n const colB = b.columns[i];\n\n if (colA.field !== colB.field) return false;\n if (colA.order !== colB.order) return false;\n if (colA.visible !== colB.visible) return false;\n if (colA.width !== colB.width) return false;\n\n // Compare sort state\n const sortA = colA.sort;\n const sortB = colB.sort;\n if ((sortA === undefined) !== (sortB === undefined)) return false;\n if (sortA && sortB) {\n if (sortA.direction !== sortB.direction) return false;\n if (sortA.priority !== sortB.priority) return false;\n }\n }\n\n return true;\n}\n","import type { PluginQuery } from './plugin/base-plugin';\n\n/**\n * The compiled webcomponent interface for DataGrid\n */\nexport interface DataGridElement extends PublicGrid, HTMLElement {}\n\n/**\n * Public API interface for DataGrid component.\n *\n * **Property Getters vs Setters:**\n *\n * Property getters return the EFFECTIVE (resolved) value after merging all config sources.\n * This is the \"current situation\" - what consumers and plugins need to know.\n *\n * Property setters accept input values which are merged into the effective config.\n * Multiple sources can contribute (gridConfig, columns prop, light DOM, individual props).\n *\n * For example:\n * - `grid.fitMode` returns the resolved fitMode (e.g., 'stretch' even if you set undefined)\n * - `grid.columns` returns the effective columns after merging\n * - `grid.gridConfig` returns the full effective config\n */\nexport interface PublicGrid<T = any> {\n /**\n * Full config object. Setter merges with other inputs per precedence rules.\n * Getter returns the effective (resolved) config.\n */\n gridConfig?: GridConfig<T>;\n /**\n * Column definitions.\n * Getter returns effective columns (after merging config, light DOM, inference).\n */\n columns?: ColumnConfig<T>[];\n /** Current row data (after plugin processing like grouping, filtering). */\n rows?: T[];\n /** Resolves once the component has finished initial work (layout, inference). */\n ready?: () => Promise<void>;\n /** Force a layout / measurement pass (e.g. after container resize). */\n forceLayout?: () => Promise<void>;\n /** Return effective resolved config (after inference & precedence). */\n getConfig?: () => Promise<Readonly<GridConfig<T>>>;\n /** Toggle expansion state of a group row by its generated key. */\n toggleGroup?: (key: string) => Promise<void>;\n}\n\n/**\n * Internal-only augmented interface for DataGrid component\n */\nexport interface InternalGrid<T = any> extends PublicGrid<T>, GridConfig<T> {\n shadowRoot: ShadowRoot | null;\n _rows: T[];\n _columns: ColumnInternal<T>[];\n /** Visible columns only (excludes hidden). Use for rendering. */\n _visibleColumns: ColumnInternal<T>[];\n _headerRowEl: HTMLElement;\n _bodyEl: HTMLElement;\n _rowPool: HTMLElement[];\n _resizeController: ResizeController;\n _sortState: { field: string; direction: 1 | -1 } | null;\n __originalOrder: T[];\n __rowRenderEpoch: number;\n __didInitialAutoSize?: boolean;\n __lightDomColumnsCache?: ColumnInternal[];\n __originalColumnNodes?: HTMLElement[];\n _gridTemplate: string;\n _virtualization: VirtualState;\n _focusRow: number;\n _focusCol: number;\n _activeEditRows: number;\n _rowEditSnapshots: Map<number, T>;\n _changedRowIndices: Set<number>;\n changedRows?: T[];\n changedRowIndices?: number[];\n effectiveConfig?: GridConfig<T>;\n findHeaderRow?: () => HTMLElement;\n refreshVirtualWindow: (full: boolean) => void;\n updateTemplate?: () => void;\n findRenderedRowElement?: (rowIndex: number) => HTMLElement | null;\n beginBulkEdit?: (rowIndex: number) => void;\n commitActiveRowEdit?: () => void;\n /** Dispatch cell click to plugin system, returns true if handled */\n _dispatchCellClick?: (event: MouseEvent, rowIndex: number, colIndex: number, cellEl: HTMLElement) => boolean;\n /** Dispatch header click to plugin system, returns true if handled */\n _dispatchHeaderClick?: (event: MouseEvent, colIndex: number, headerEl: HTMLElement) => boolean;\n /** Dispatch keydown to plugin system, returns true if handled */\n _dispatchKeyDown?: (event: KeyboardEvent) => boolean;\n /** Get horizontal scroll boundary offsets from plugins (e.g., pinned columns) */\n _getHorizontalScrollOffsets?: (\n rowEl?: HTMLElement,\n focusedCell?: HTMLElement,\n ) => { left: number; right: number; skipScroll?: boolean };\n /** Query all plugins with a generic query and collect responses */\n queryPlugins?: <T>(query: PluginQuery) => T[];\n /** Request emission of column-state-change event (debounced) */\n requestStateChange?: () => void;\n}\n\nexport type PrimitiveColumnType = 'number' | 'string' | 'date' | 'boolean' | 'select' | 'typeahead';\n\n/**\n * Base contract for a column. Public; kept intentionally lean so host apps can extend via intersection types.\n * Prefer adding optional properties here only when broadly useful to most grids.\n */\nexport interface BaseColumnConfig<TRow = any, TValue = any> {\n /** Unique field key referencing property in row objects */\n field: keyof TRow & string;\n /** Visible header label; defaults to capitalized field */\n header?: string;\n /** Column data type; inferred if omitted */\n type?: PrimitiveColumnType;\n /** Column width in pixels; fixed size (no flexibility) */\n width?: string | number;\n /** Minimum column width in pixels (stretch mode only); when set, column uses minmax(minWidth, 1fr) */\n minWidth?: number;\n /** Whether column can be sorted */\n sortable?: boolean;\n /** Whether column can be resized by user */\n resizable?: boolean;\n /** Optional custom comparator for sorting (a,b) -> number */\n sortComparator?: (a: TValue, b: TValue, rowA: TRow, rowB: TRow) => number;\n /** Whether the field is editable (enables editors) */\n editable?: boolean;\n /** Optional custom editor factory or element tag name */\n editor?: ColumnEditorSpec<TRow, TValue>;\n /** For select/typeahead types - available options */\n options?: Array<{ label: string; value: unknown }> | (() => Array<{ label: string; value: unknown }>);\n /** For select/typeahead - allow multi select */\n multi?: boolean;\n /** Optional formatter */\n format?: (value: TValue, row: TRow) => string;\n /** Arbitrary extra metadata */\n meta?: Record<string, unknown>;\n}\n\n/**\n * Full column configuration including optional custom view/renderer & grouping metadata.\n */\nexport interface ColumnConfig<TRow = any> extends BaseColumnConfig<TRow, any> {\n /** Optional custom view renderer used instead of default text rendering */\n viewRenderer?: ColumnViewRenderer<TRow, any>;\n /** External view spec (lets host app mount any framework component) */\n externalView?: {\n component: unknown;\n props?: Record<string, unknown>;\n mount?: (options: {\n placeholder: HTMLElement;\n context: CellRenderContext<TRow, unknown>;\n spec: unknown;\n }) => void | { dispose?: () => void };\n };\n /** Whether the column is initially hidden */\n hidden?: boolean;\n /** Prevent this column from being hidden by the visibility plugin */\n lockVisible?: boolean;\n}\n\nexport type ColumnConfigMap<TRow = any> = ColumnConfig<TRow>[];\n\n/** External editor spec: tag name, factory function, or external mount spec */\nexport type ColumnEditorSpec<TRow = unknown, TValue = unknown> =\n | string // custom element tag name\n | ((context: ColumnEditorContext<TRow, TValue>) => HTMLElement | string)\n | {\n /** Arbitrary component reference (class, function, token) */\n component: unknown;\n /** Optional static props passed to mount */\n props?: Record<string, unknown>;\n /** Optional custom mount function; if provided we call it directly instead of emitting an event */\n mount?: (options: {\n placeholder: HTMLElement;\n context: ColumnEditorContext<TRow, TValue>;\n spec: unknown;\n }) => void | { dispose?: () => void };\n };\n\n/**\n * Context object provided to editor factories allowing mutation (commit/cancel) of a cell value.\n */\nexport interface ColumnEditorContext<TRow = any, TValue = any> {\n /** Underlying full row object for the active edit. */\n row: TRow;\n /** Current cell value (mutable only via commit). */\n value: TValue;\n /** Field name being edited. */\n field: keyof TRow & string;\n /** Column configuration reference. */\n column: ColumnConfig<TRow>;\n /** Accept the edit; triggers change tracking + rerender. */\n commit: (newValue: TValue) => void;\n /** Abort edit without persisting changes. */\n cancel: () => void;\n}\n\n/**\n * Context passed to custom view renderers (pure display – no commit helpers).\n */\nexport interface CellRenderContext<TRow = any, TValue = any> {\n /** Row object for the cell being rendered. */\n row: TRow;\n /** Value at field. */\n value: TValue;\n /** Field key. */\n field: keyof TRow & string;\n /** Column configuration reference. */\n column: ColumnConfig<TRow>;\n}\n\nexport type ColumnViewRenderer<TRow = unknown, TValue = unknown> = (\n ctx: CellRenderContext<TRow, TValue>,\n) => Node | string | void;\n\n// #region Internal-only augmented types (not re-exported publicly)\nexport interface ColumnInternal<T = any> extends ColumnConfig<T> {\n __autoSized?: boolean;\n __userResized?: boolean;\n __renderedWidth?: number;\n __viewTemplate?: HTMLElement;\n __editorTemplate?: HTMLElement;\n __headerTemplate?: HTMLElement;\n __compiledView?: (ctx: CellContext<T>) => string;\n __compiledEditor?: (ctx: EditorExecContext<T>) => string;\n}\n\n/**\n * Runtime cell context used internally for compiled template execution.\n */\nexport interface CellContext<T = any> {\n row: T;\n value: unknown;\n field: string;\n column: ColumnInternal<T>;\n}\n\n/**\n * Internal editor execution context extending the generic cell context with commit helpers.\n */\nexport interface EditorExecContext<T = any> extends CellContext<T> {\n commit: (newValue: unknown) => void;\n cancel: () => void;\n}\n\n/** Controller managing drag-based column resize lifecycle. */\nexport interface ResizeController {\n start: (e: MouseEvent, colIndex: number, cell: HTMLElement) => void;\n dispose: () => void;\n /** True while a resize drag is in progress (used to suppress header click/sort). */\n isResizing: boolean;\n}\n\n/** Virtual window bookkeeping; modified in-place as scroll position changes. */\nexport interface VirtualState {\n enabled: boolean;\n rowHeight: number;\n /** Threshold for bypassing virtualization (renders all rows if totalRows <= bypassThreshold) */\n bypassThreshold: number;\n start: number;\n end: number;\n /** Faux scrollbar element that provides scroll events (AG Grid pattern) */\n container: HTMLElement | null;\n /** Rows viewport element for measuring visible area height */\n viewportEl: HTMLElement | null;\n /** Spacer element inside faux scrollbar for setting virtual height */\n totalHeightEl: HTMLElement | null;\n}\n// #endregion\n\n// #region Grouping & Footer Public Types\n/**\n * Group row rendering customization options.\n * Used within grouping-rows plugin config for presentation of group rows.\n */\nexport interface RowGroupRenderConfig {\n /** If true, group rows span all columns (single full-width cell). Default false. */\n fullWidth?: boolean;\n /** Optional label formatter override. Receives raw group value + depth. */\n formatLabel?: (value: unknown, depth: number, key: string) => string;\n /** Optional aggregate overrides per field for group summary cells (only when not fullWidth). */\n aggregators?: Record<string, AggregatorRef>;\n /** Additional CSS class applied to each group row root element. */\n class?: string;\n}\n\nexport type AggregatorRef = string | ((rows: unknown[], field: string, column?: unknown) => unknown);\n\n/** Result of automatic column inference from sample rows. */\nexport interface InferredColumnResult<TRow = unknown> {\n columns: ColumnConfigMap<TRow>;\n typeMap: Record<string, PrimitiveColumnType>;\n}\n\nexport const FitModeEnum = {\n STRETCH: 'stretch',\n FIXED: 'fixed',\n} as const;\nexport type FitMode = (typeof FitModeEnum)[keyof typeof FitModeEnum]; // evaluates to 'stretch' | 'fixed'\n// #endregion\n\n// #region Plugin Interface\n/**\n * Minimal plugin interface for type-checking.\n * This interface is defined here to avoid circular imports with BaseGridPlugin.\n * All plugins must satisfy this shape (BaseGridPlugin implements it).\n */\nexport interface GridPlugin {\n /** Unique plugin identifier */\n readonly name: string;\n /** Plugin version */\n readonly version: string;\n /** CSS styles to inject into grid's shadow DOM */\n readonly styles?: string;\n}\n// #endregion\n\n// #region Grid Config\n/**\n * Grid configuration object - the **single source of truth** for grid behavior.\n *\n * Users can configure the grid via multiple input methods, all of which converge\n * into an effective `GridConfig` internally:\n *\n * **Configuration Input Methods:**\n * - `gridConfig` property - direct assignment of this object\n * - `columns` property - shorthand for `gridConfig.columns`\n * - `fitMode` property - shorthand for `gridConfig.fitMode`\n * - `editOn` property - shorthand for `gridConfig.editOn`\n * - Light DOM `<tbw-grid-column>` - declarative columns (merged into `columns`)\n * - Light DOM `<tbw-grid-header>` - declarative shell header (merged into `shell.header`)\n *\n * **Precedence (when same property set multiple ways):**\n * Individual props (`fitMode`, `editOn`) > `columns` prop > Light DOM > `gridConfig`\n *\n * @example\n * ```ts\n * // Via gridConfig (recommended for complex setups)\n * grid.gridConfig = {\n * columns: [{ field: 'name' }, { field: 'age' }],\n * fitMode: 'stretch',\n * plugins: [new SelectionPlugin()],\n * shell: { header: { title: 'My Grid' } }\n * };\n *\n * // Via individual props (convenience for simple cases)\n * grid.columns = [{ field: 'name' }, { field: 'age' }];\n * grid.fitMode = 'stretch';\n * ```\n */\nexport interface GridConfig<TRow = any> {\n /** Column definitions. Can also be set via `columns` prop or `<tbw-grid-column>` light DOM. */\n columns?: ColumnConfigMap<TRow>;\n /** Sizing mode for columns. Can also be set via `fitMode` prop. */\n fitMode?: FitMode;\n /** Edit activation mode ('click' | 'dblclick'). Can also be set via `editOn` prop. */\n editOn?: string;\n /**\n * Row height in pixels for virtualization calculations.\n * The virtualization system assumes uniform row heights for performance.\n *\n * If not specified, the grid measures the first rendered row's height,\n * which respects the CSS variable `--tbw-row-height` set by themes.\n *\n * Set this explicitly when:\n * - Row content may wrap to multiple lines (also set `--tbw-cell-white-space: normal`)\n * - Using custom row templates with variable content\n * - You want to override theme-defined row height\n *\n * @default Auto-measured from first row (respects --tbw-row-height CSS variable)\n *\n * @example\n * ```ts\n * // Fixed height for rows that may wrap to 2 lines\n * gridConfig = { rowHeight: 56 };\n * ```\n */\n rowHeight?: number;\n /**\n * Array of plugin instances.\n * Each plugin is instantiated with its configuration and attached to this grid.\n *\n * @example\n * ```ts\n * plugins: [\n * new SelectionPlugin({ mode: 'range' }),\n * new MultiSortPlugin(),\n * new FilteringPlugin({ debounceMs: 150 }),\n * ]\n * ```\n */\n plugins?: GridPlugin[];\n\n /**\n * Saved column state to restore on initialization.\n * Includes order, width, visibility, sort, and plugin-contributed state.\n */\n columnState?: GridColumnState;\n\n /**\n * Shell configuration for header bar and tool panels.\n * When configured, adds an optional wrapper with title, toolbar, and collapsible side panels.\n */\n shell?: ShellConfig;\n\n /**\n * Grid-wide icon configuration.\n * Provides consistent icons across all plugins (tree, grouping, sorting, etc.).\n * Plugins will use these by default but can override with their own config.\n */\n icons?: GridIcons;\n}\n// #endregion\n\n// #region Grid Icons\n\n/** Icon value - can be a string (text/HTML) or HTMLElement */\nexport type IconValue = string | HTMLElement;\n\n/**\n * Grid-wide icon configuration.\n * All icons are optional - sensible defaults are used when not specified.\n */\nexport interface GridIcons {\n /** Expand icon for collapsed items (trees, groups, details). Default: '▶' */\n expand?: IconValue;\n /** Collapse icon for expanded items (trees, groups, details). Default: '▼' */\n collapse?: IconValue;\n /** Sort ascending indicator. Default: '▲' */\n sortAsc?: IconValue;\n /** Sort descending indicator. Default: '▼' */\n sortDesc?: IconValue;\n /** Sort neutral/unsorted indicator. Default: '⇅' */\n sortNone?: IconValue;\n /** Submenu arrow for context menus. Default: '▶' */\n submenuArrow?: IconValue;\n /** Drag handle icon for reordering. Default: '⋮⋮' */\n dragHandle?: IconValue;\n /** Tool panel toggle icon in toolbar. Default: '☰' */\n toolPanel?: IconValue;\n}\n\n/** Default icons used when not overridden */\nexport const DEFAULT_GRID_ICONS: Required<GridIcons> = {\n expand: '▶',\n collapse: '▼',\n sortAsc: '▲',\n sortDesc: '▼',\n sortNone: '⇅',\n submenuArrow: '▶',\n dragHandle: '⋮⋮',\n toolPanel: '☰',\n};\n// #endregion\n\n// #region Shell Configuration\n\n/**\n * Shell configuration for the grid's optional header bar and tool panels.\n */\nexport interface ShellConfig {\n /** Shell header bar configuration */\n header?: ShellHeaderConfig;\n /** Tool panel configuration */\n toolPanel?: ToolPanelConfig;\n}\n\n/**\n * Shell header bar configuration\n */\nexport interface ShellHeaderConfig {\n /** Grid title displayed on the left (optional) */\n title?: string;\n /** Custom toolbar buttons (rendered before tool panel toggles) */\n toolbarButtons?: ToolbarButtonConfig[];\n}\n\n/**\n * Tool panel configuration\n */\nexport interface ToolPanelConfig {\n /** Panel position: 'left' | 'right' (default: 'right') */\n position?: 'left' | 'right';\n /** Default panel width in pixels (default: 280) */\n width?: number;\n /** Panel ID to open by default on load */\n defaultOpen?: string;\n /** Whether to persist open/closed state (requires Column State Events) */\n persistState?: boolean;\n}\n\n/**\n * Toolbar button defined via config (programmatic approach).\n * Supports three modes:\n * - Simple: provide `icon` + `action` for grid to create button\n * - Element: provide `element` for user-created DOM\n * - Render: provide `render` function for complex widgets\n */\nexport interface ToolbarButtonConfig {\n /** Unique button ID */\n id: string;\n /** Tooltip / aria-label (required for accessibility) */\n label: string;\n /** Order priority (lower = first, default: 100) */\n order?: number;\n /** Whether button is disabled (only applies to grid-rendered buttons) */\n disabled?: boolean;\n\n // ===== Option A: Simple - Grid renders the button =====\n /** Button content: SVG string, emoji, or text. Grid creates <button> with this. */\n icon?: string;\n /** Click handler (required when using icon) */\n action?: () => void;\n\n // ===== Option B: Custom DOM - User provides element or render function =====\n /**\n * User-provided element. Grid wraps it but doesn't modify it.\n * User is responsible for event handlers.\n */\n element?: HTMLElement;\n /**\n * Render function called once. Receives container, user appends their DOM.\n * User is responsible for event handlers.\n * Return a cleanup function (optional).\n */\n render?: (container: HTMLElement) => void | (() => void);\n}\n\n/**\n * Toolbar button info returned by getToolbarButtons().\n */\nexport interface ToolbarButtonInfo {\n id: string;\n label: string;\n disabled: boolean;\n /** Source of this button: 'config' | 'light-dom' | 'panel-toggle' */\n source: 'config' | 'light-dom' | 'panel-toggle';\n /** For panel toggles, the associated panel ID */\n panelId?: string;\n}\n\n/**\n * Tool panel definition registered by plugins or consumers.\n */\nexport interface ToolPanelDefinition {\n /** Unique panel ID */\n id: string;\n /** Panel title shown in accordion header */\n title: string;\n /** Icon for accordion section header (optional, emoji or SVG) */\n icon?: string;\n /** Tooltip for accordion section header */\n tooltip?: string;\n /** Panel content factory - called when panel section opens */\n render: (container: HTMLElement) => void | (() => void);\n /** Called when panel closes (for cleanup) */\n onClose?: () => void;\n /** Panel order priority (lower = first, default: 100) */\n order?: number;\n}\n\n/**\n * Header content definition for plugins contributing to shell header center section.\n */\nexport interface HeaderContentDefinition {\n /** Unique content ID */\n id: string;\n /** Content factory - called once when shell header renders */\n render: (container: HTMLElement) => void | (() => void);\n /** Called when content is removed (for cleanup) */\n onDestroy?: () => void;\n /** Order priority (lower = first, default: 100) */\n order?: number;\n}\n// #endregion\n\n// #region Column State (Persistence)\n\n/**\n * State for a single column. Captures user-driven changes at runtime.\n * Plugins can extend this interface via module augmentation to add their own state.\n *\n * @example\n * ```ts\n * // In filtering plugin\n * declare module '@toolbox-web/grid' {\n * interface ColumnState {\n * filter?: FilterValue;\n * }\n * }\n * ```\n */\nexport interface ColumnState {\n /** Column field identifier */\n field: string;\n /** Position index after reordering (0-based) */\n order: number;\n /** Width in pixels (undefined = use default) */\n width?: number;\n /** Visibility state */\n visible: boolean;\n /** Sort state (undefined = not sorted) */\n sort?: ColumnSortState;\n}\n\n/**\n * Sort state for a column\n */\nexport interface ColumnSortState {\n /** Sort direction */\n direction: 'asc' | 'desc';\n /** Priority for multi-sort (0 = primary, 1 = secondary, etc.) */\n priority: number;\n}\n\n/**\n * Complete grid column state for persistence.\n * Contains state for all columns, including plugin-contributed properties.\n */\nexport interface GridColumnState {\n columns: ColumnState[];\n}\n// #endregion\n\n// #region Public Event Detail Interfaces\nexport interface CellCommitDetail<TRow = unknown> {\n /** The mutated row after commit. */\n row: TRow;\n /** Field name whose value changed. */\n field: string;\n /** New value stored. */\n value: unknown;\n /** Index of the row in current data set. */\n rowIndex: number;\n /** All rows that have at least one committed change (snapshot list). */\n changedRows: TRow[];\n /** Indices parallel to changedRows. */\n changedRowIndices: number[];\n /** True if this row just entered the changed set. */\n firstTimeForRow: boolean;\n}\n\n/** Detail payload for a committed row edit (may or may not include changes). */\nexport interface RowCommitDetail<TRow = unknown> {\n /** Row index that lost edit focus. */\n rowIndex: number;\n /** Row object reference. */\n row: TRow;\n /** Whether any cell changes were actually committed in this row during the session. */\n changed: boolean;\n /** Current changed row collection. */\n changedRows: TRow[];\n /** Indices of changed rows. */\n changedRowIndices: number[];\n}\n\n/** Emitted when the changed rows tracking set is cleared programmatically. */\nexport interface ChangedRowsResetDetail<TRow = unknown> {\n /** New (empty) changed rows array after reset. */\n rows: TRow[];\n /** Parallel indices (likely empty). */\n indices: number[];\n}\n\n/** Detail for a sort change (direction 0 indicates cleared sort). */\nexport interface SortChangeDetail {\n /** Sorted field key. */\n field: string;\n /** Direction: 1 ascending, -1 descending, 0 cleared. */\n direction: 1 | -1 | 0;\n}\n\n/** Column resize event detail containing final pixel width. */\nexport interface ColumnResizeDetail {\n /** Resized column field key. */\n field: string;\n /** New width in pixels. */\n width: number;\n}\n\n/** Fired when keyboard navigation or programmatic focus changes active cell. */\nexport interface ActivateCellDetail {\n /** Zero-based row index now focused. */\n row: number;\n /** Zero-based column index now focused. */\n col: number;\n}\n\nexport interface ExternalMountViewDetail<TRow = unknown> {\n placeholder: HTMLElement;\n spec: unknown;\n context: { row: TRow; value: unknown; field: string; column: unknown };\n}\n\nexport interface ExternalMountEditorDetail<TRow = unknown> {\n placeholder: HTMLElement;\n spec: unknown;\n context: {\n row: TRow;\n value: unknown;\n field: string;\n column: unknown;\n commit: (v: unknown) => void;\n cancel: () => void;\n };\n}\n\nexport interface DataGridEventMap<TRow = unknown> {\n 'cell-commit': CellCommitDetail<TRow>;\n 'row-commit': RowCommitDetail<TRow>;\n 'changed-rows-reset': ChangedRowsResetDetail<TRow>;\n 'mount-external-view': ExternalMountViewDetail<TRow>;\n 'mount-external-editor': ExternalMountEditorDetail<TRow>;\n 'sort-change': SortChangeDetail;\n 'column-resize': ColumnResizeDetail;\n 'activate-cell': ActivateCellDetail;\n 'column-state-change': GridColumnState;\n}\n\nexport type DataGridEventDetail<K extends keyof DataGridEventMap<unknown>, TRow = unknown> = DataGridEventMap<TRow>[K];\nexport type DataGridCustomEvent<K extends keyof DataGridEventMap<unknown>, TRow = unknown> = CustomEvent<\n DataGridEventMap<TRow>[K]\n>;\n\n// Internal code now reuses the public ColumnEditorContext; provide alias for backward compatibility\nexport type EditorContext<T = unknown> = ColumnEditorContext<T, unknown>;\n\nexport interface EvalContext {\n value: unknown;\n row: Record<string, unknown> | null;\n}\n// #endregion\n","import type { ColumnConfigMap, InferredColumnResult, PrimitiveColumnType } from '../types';\n/**\n * Best-effort primitive type inference for a cell value used during automatic column generation.\n */\nfunction inferType(value: any): PrimitiveColumnType {\n if (value == null) return 'string';\n if (typeof value === 'number') return 'number';\n if (typeof value === 'boolean') return 'boolean';\n if (value instanceof Date) return 'date';\n if (typeof value === 'string' && /\\d{4}-\\d{2}-\\d{2}/.test(value) && !isNaN(Date.parse(value))) return 'date';\n return 'string';\n}\n/**\n * Derive column definitions from provided configuration or by inspecting the first row of data.\n * Returns both the resolved column array and a field->type map.\n */\nexport function inferColumns<TRow extends Record<string, unknown>>(\n rows: TRow[],\n provided?: ColumnConfigMap<TRow>\n): InferredColumnResult<TRow> {\n if (provided && provided.length) {\n const typeMap: Record<string, PrimitiveColumnType> = {};\n provided.forEach((col) => {\n if (col.type) typeMap[col.field] = col.type;\n });\n return { columns: provided, typeMap };\n }\n const sample = rows[0] || ({} as TRow);\n const columns: ColumnConfigMap<TRow> = Object.keys(sample).map((k) => {\n const v = (sample as any)[k];\n const type = inferType(v);\n return { field: k as keyof TRow & string, header: k.charAt(0).toUpperCase() + k.slice(1), type };\n });\n const typeMap: Record<string, PrimitiveColumnType> = {};\n columns.forEach((c) => {\n typeMap[c.field] = c.type || 'string';\n });\n return { columns, typeMap };\n}\nexport { inferType };\n","// Centralized template expression evaluation & sanitization utilities.\n// Responsible for safely interpolating {{ }} expressions while blocking\n// access to dangerous globals / reflective capabilities.\nimport type { EvalContext } from '../types';\n\nconst EXPR_RE = /{{\\s*([^}]+)\\s*}}/g;\nconst EMPTY_SENTINEL = '__DG_EMPTY__';\nconst SAFE_EXPR = /^[\\w$. '?+\\-*/%:()!<>=,&|]+$/;\nconst FORBIDDEN =\n /__(proto|defineGetter|defineSetter)|constructor|window|globalThis|global|process|Function|import|eval|Reflect|Proxy|Error|arguments|document|location|cookie|localStorage|sessionStorage|indexedDB|fetch|XMLHttpRequest|WebSocket|Worker|SharedWorker|ServiceWorker|opener|parent|top|frames|self|this\\b/;\n\n// #region HTML Sanitization\n\n/**\n * Tags that are considered dangerous and will be completely removed.\n * These can execute scripts, load external resources, or manipulate the page.\n */\nconst DANGEROUS_TAGS = new Set([\n 'script',\n 'iframe',\n 'object',\n 'embed',\n 'form',\n 'input',\n 'button',\n 'textarea',\n 'select',\n 'link',\n 'meta',\n 'base',\n 'style',\n 'template',\n 'slot',\n 'portal',\n 'frame',\n 'frameset',\n 'applet',\n 'noscript',\n 'noembed',\n 'plaintext',\n 'xmp',\n 'listing',\n]);\n\n/**\n * Attributes that are considered dangerous - event handlers and data loading.\n */\nconst DANGEROUS_ATTR_PATTERN = /^on\\w+$/i;\n\n/**\n * Attributes that can contain URLs which might be javascript: or data: URIs.\n */\nconst URL_ATTRS = new Set(['href', 'src', 'action', 'formaction', 'data', 'srcdoc', 'xlink:href', 'poster', 'srcset']);\n\n/**\n * Protocol patterns that are dangerous in URLs.\n */\nconst DANGEROUS_URL_PROTOCOL = /^\\s*(javascript|vbscript|data|blob):/i;\n\n/**\n * Sanitize an HTML string by removing dangerous tags and attributes.\n * This is a defense-in-depth measure for content rendered via innerHTML.\n *\n * @param html - Raw HTML string to sanitize\n * @returns Sanitized HTML string safe for innerHTML\n */\nexport function sanitizeHTML(html: string): string {\n if (!html || typeof html !== 'string') return '';\n\n // Fast path: if no HTML tags at all, return as-is (already safe)\n if (html.indexOf('<') === -1) return html;\n\n const template = document.createElement('template');\n template.innerHTML = html;\n\n sanitizeNode(template.content);\n\n return template.innerHTML;\n}\n\n/**\n * Recursively sanitize a DOM node tree.\n */\nfunction sanitizeNode(root: DocumentFragment | Element): void {\n const toRemove: Element[] = [];\n\n // Use querySelectorAll to find all elements, then filter\n const elements = root.querySelectorAll('*');\n\n for (const el of elements) {\n const tagName = el.tagName.toLowerCase();\n\n // Check if tag is dangerous\n if (DANGEROUS_TAGS.has(tagName)) {\n toRemove.push(el);\n continue;\n }\n\n // SVG elements need special handling - they can contain script-like behavior\n if (tagName === 'svg' || el.namespaceURI === 'http://www.w3.org/2000/svg') {\n // Remove entire SVG if it has any suspicious attributes\n const hasDangerousContent = Array.from(el.attributes).some(\n (attr) => DANGEROUS_ATTR_PATTERN.test(attr.name) || attr.name === 'href' || attr.name === 'xlink:href',\n );\n if (hasDangerousContent) {\n toRemove.push(el);\n continue;\n }\n }\n\n // Check and remove dangerous attributes\n const attrsToRemove: string[] = [];\n for (const attr of el.attributes) {\n const attrName = attr.name.toLowerCase();\n\n // Event handlers (onclick, onerror, onload, etc.)\n if (DANGEROUS_ATTR_PATTERN.test(attrName)) {\n attrsToRemove.push(attr.name);\n continue;\n }\n\n // URL attributes with dangerous protocols\n if (URL_ATTRS.has(attrName) && DANGEROUS_URL_PROTOCOL.test(attr.value)) {\n attrsToRemove.push(attr.name);\n continue;\n }\n\n // style attribute can contain expressions (IE) or url() with javascript:\n if (attrName === 'style' && /expression\\s*\\(|javascript:|behavior\\s*:/i.test(attr.value)) {\n attrsToRemove.push(attr.name);\n continue;\n }\n }\n\n attrsToRemove.forEach((name) => el.removeAttribute(name));\n }\n\n // Remove dangerous elements (do this after iteration to avoid modifying during traversal)\n toRemove.forEach((el) => el.remove());\n}\n\n// #endregion\n\nexport function evalTemplateString(raw: string, ctx: EvalContext): string {\n if (!raw || raw.indexOf('{{') === -1) return raw; // fast path (no expressions)\n const parts: { expr: string; result: string }[] = [];\n const evaluated = raw.replace(EXPR_RE, (_m, expr) => {\n const res = evalSingle(expr, ctx);\n parts.push({ expr: expr.trim(), result: res });\n return res;\n });\n const finalStr = postProcess(evaluated);\n // If every part evaluated to EMPTY_SENTINEL we treat this as intentionally blank.\n // If any expression was blocked due to forbidden token (EMPTY_SENTINEL) we *still* only output ''\n // but do not escalate to BLOCKED_SENTINEL unless the original contained explicit forbidden tokens.\n const allEmpty = parts.length && parts.every((p) => p.result === '' || p.result === EMPTY_SENTINEL);\n const hadForbidden = /Reflect\\.|\\bProxy\\b|ownKeys\\(/.test(raw);\n if (hadForbidden || allEmpty) return '';\n return finalStr;\n}\n\nfunction evalSingle(expr: string, ctx: EvalContext): string {\n expr = (expr || '').trim();\n if (!expr) return EMPTY_SENTINEL;\n if (/\\b(Reflect|Proxy|ownKeys)\\b/.test(expr)) return EMPTY_SENTINEL;\n if (expr === 'value') return ctx.value == null ? EMPTY_SENTINEL : String(ctx.value);\n if (expr.startsWith('row.') && !/[()?]/.test(expr) && !expr.includes(':')) {\n const key = expr.slice(4);\n const v = ctx.row ? ctx.row[key] : undefined;\n return v == null ? EMPTY_SENTINEL : String(v);\n }\n if (expr.length > 80) return EMPTY_SENTINEL;\n if (!SAFE_EXPR.test(expr) || FORBIDDEN.test(expr)) return EMPTY_SENTINEL;\n const dotChain = expr.match(/\\./g);\n if (dotChain && dotChain.length > 1) return EMPTY_SENTINEL;\n try {\n \n const fn = new Function('value', 'row', `return (${expr});`);\n const out = fn(ctx.value, ctx.row);\n const str = out == null ? '' : String(out);\n if (/Reflect|Proxy|ownKeys/.test(str)) return EMPTY_SENTINEL;\n return str || EMPTY_SENTINEL;\n } catch {\n return EMPTY_SENTINEL;\n }\n}\n\nfunction postProcess(s: string): string {\n if (!s) return s;\n return s\n .replace(new RegExp(EMPTY_SENTINEL, 'g'), '')\n .replace(/Reflect\\.[^<>{}\\s]+/g, '')\n .replace(/\\bProxy\\b/g, '')\n .replace(/ownKeys\\([^)]*\\)/g, '');\n}\n\nexport function finalCellScrub(cell: HTMLElement): void {\n if (/Reflect|Proxy|ownKeys/.test(cell.textContent || '')) {\n Array.from(cell.childNodes).forEach((n) => {\n if (n.nodeType === Node.TEXT_NODE && /Reflect|Proxy|ownKeys/.test(n.textContent || '')) n.textContent = '';\n });\n if (/Reflect|Proxy|ownKeys/.test(cell.textContent || '')) {\n // If remaining content still includes forbidden tokens inside element nodes, clear children entirely.\n const still = /Reflect|Proxy|ownKeys/.test(cell.textContent || '');\n if (still) {\n while (cell.firstChild) cell.removeChild(cell.firstChild);\n }\n cell.textContent = (cell.textContent || '').replace(/Reflect|Proxy|ownKeys/g, '');\n }\n if ((cell.textContent || '').trim().length === 0) cell.textContent = '';\n }\n}\n\nexport function compileTemplate(raw: string) {\n const forceBlank = /Reflect\\.|\\bProxy\\b|ownKeys\\(/.test(raw);\n const fn = (ctx: EvalContext) => {\n if (forceBlank) return '';\n const out = evalTemplateString(raw, ctx);\n return out;\n };\n (fn as any).__blocked = forceBlank;\n return fn;\n}\n","import type { ColumnConfig, ColumnInternal, InternalGrid } from '../types';\nimport { FitModeEnum } from '../types';\nimport { inferColumns } from './inference';\nimport { compileTemplate } from './sanitize';\n\n/**\n * Parse `<tbw-grid-column>` elements from the host light DOM into column config objects,\n * capturing template elements for later cloning / compilation.\n */\nexport function parseLightDomColumns(host: HTMLElement): ColumnInternal[] {\n const domColumns = Array.from(host.querySelectorAll('tbw-grid-column')) as HTMLElement[];\n return domColumns\n .map((el) => {\n const field = el.getAttribute('field') || '';\n if (!field) return null;\n const rawType = el.getAttribute('type') || undefined;\n const allowedTypes = new Set(['number', 'string', 'date', 'boolean', 'select', 'typeahead']);\n const type = rawType && allowedTypes.has(rawType) ? (rawType as any) : undefined;\n const header = el.getAttribute('header') || undefined;\n const sortable = el.hasAttribute('sortable');\n const editable = el.hasAttribute('editable');\n const config: ColumnInternal = { field, type, header, sortable, editable };\n if (el.hasAttribute('resizable')) (config as any).resizable = true;\n if (el.hasAttribute('sizable')) (config as any).resizable = true; // legacy attribute support\n // Parse options attribute for select/typeahead: \"value1:Label1,value2:Label2\" or \"value1,value2\"\n const optionsAttr = el.getAttribute('options');\n if (optionsAttr) {\n (config as any).options = optionsAttr.split(',').map((item) => {\n const [value, label] = item.includes(':') ? item.split(':') : [item.trim(), item.trim()];\n return { value: value.trim(), label: label?.trim() || value.trim() };\n });\n }\n const viewTpl = el.querySelector('tbw-grid-column-view');\n const editorTpl = el.querySelector('tbw-grid-column-editor');\n const headerTpl = el.querySelector('tbw-grid-column-header');\n if (viewTpl) config.__viewTemplate = viewTpl as HTMLElement;\n if (editorTpl) config.__editorTemplate = editorTpl as HTMLElement;\n if (headerTpl) config.__headerTemplate = headerTpl as HTMLElement;\n return config;\n })\n .filter((c): c is ColumnInternal => !!c);\n}\n\n/**\n * Merge programmatic columns with light DOM columns by field name, allowing DOM-provided\n * attributes / templates to supplement (not overwrite) programmatic definitions.\n * Any DOM columns without a programmatic counterpart are appended.\n */\nexport function mergeColumns(\n programmatic: ColumnConfig[] | undefined,\n dom: ColumnConfig[] | undefined,\n): ColumnInternal[] {\n if ((!programmatic || !programmatic.length) && (!dom || !dom.length)) return [];\n if (!programmatic || !programmatic.length) return (dom || []) as ColumnInternal[];\n if (!dom || !dom.length) return programmatic as ColumnInternal[];\n const domMap: Record<string, ColumnInternal> = {};\n (dom as ColumnInternal[]).forEach((c) => (domMap[c.field] = c));\n const merged: ColumnInternal[] = (programmatic as ColumnInternal[]).map((c) => {\n const d = domMap[c.field];\n if (!d) return c;\n const m: ColumnInternal = { ...c };\n if (d.header && !m.header) m.header = d.header;\n if (d.type && !m.type) m.type = d.type;\n m.sortable = c.sortable || d.sortable;\n if ((c as any).resizable === true || (d as any).resizable === true) (m as any).resizable = true;\n m.editable = c.editable || d.editable;\n if ((d as any).__viewTemplate) (m as any).__viewTemplate = (d as any).__viewTemplate;\n if ((d as any).__editorTemplate) (m as any).__editorTemplate = (d as any).__editorTemplate;\n if ((d as any).__headerTemplate) (m as any).__headerTemplate = (d as any).__headerTemplate;\n delete domMap[c.field];\n return m;\n });\n Object.keys(domMap).forEach((field) => merged.push(domMap[field]));\n return merged;\n}\n\n/**\n * Safely add a token to an element's `part` attribute (supporting the CSS ::part API)\n * without duplicating values. Falls back to string manipulation if `el.part` API isn't present.\n */\nexport function addPart(el: HTMLElement, token: string): void {\n try {\n (el as any).part?.add?.(token);\n } catch {\n /* empty */\n }\n const existing = el.getAttribute('part');\n if (!existing) el.setAttribute('part', token);\n else if (!existing.split(/\\s+/).includes(token)) el.setAttribute('part', existing + ' ' + token);\n}\n\n/**\n * Resolve the effective column list for the grid by combining:\n * 1. Programmatic columns (`grid._columns`)\n * 2. Light DOM `<tbw-grid-column>` definitions (cached)\n * 3. Inferred columns (if none provided)\n * Also compiles inline template expressions into fast functions.\n * Columns with `hidden: true` in config are added to hidden tracking.\n */\nexport function getColumnConfiguration(grid: InternalGrid): void {\n if (!grid.__lightDomColumnsCache) {\n grid.__originalColumnNodes = Array.from(\n (grid as unknown as HTMLElement).querySelectorAll('tbw-grid-column'),\n ) as HTMLElement[];\n grid.__lightDomColumnsCache = grid.__originalColumnNodes.length\n ? parseLightDomColumns(grid as unknown as HTMLElement)\n : [];\n }\n const lightDomColumns = grid.__lightDomColumnsCache;\n const merged = mergeColumns(grid._columns, lightDomColumns);\n merged.forEach((c: ColumnInternal) => {\n if (c.__viewTemplate && !c.__compiledView) {\n c.__compiledView = compileTemplate((c.__viewTemplate as HTMLElement).innerHTML);\n }\n if (c.__editorTemplate && !c.__compiledEditor) {\n c.__compiledEditor = compileTemplate((c.__editorTemplate as HTMLElement).innerHTML);\n }\n });\n const { columns } = inferColumns(grid._rows, merged as any);\n grid._columns = columns as ColumnInternal[];\n}\n\n/**\n * Measure rendered header + visible cell content to assign initial pixel widths\n * to columns when in `content` fit mode. Runs only once unless fit mode changes.\n */\nexport function autoSizeColumns(grid: InternalGrid): void {\n const mode = (grid as any).effectiveConfig?.fitMode || grid.fitMode || FitModeEnum.STRETCH;\n // Run for both stretch (to derive baseline pixel widths before fr distribution) and fixed.\n if (mode !== FitModeEnum.STRETCH && mode !== FitModeEnum.FIXED) return;\n if (grid.__didInitialAutoSize) return;\n if (!(grid as unknown as HTMLElement).isConnected) return;\n const headerCells = (grid._headerRowEl?.children || []) as any;\n if (!headerCells.length) return;\n let changed = false;\n grid._visibleColumns.forEach((col: ColumnInternal, i: number) => {\n if (col.width) return;\n const headerCell = headerCells[i] as HTMLElement | undefined;\n let max = headerCell ? headerCell.scrollWidth : 0;\n for (const rowEl of grid._rowPool) {\n const cell = rowEl.children[i] as HTMLElement | undefined;\n if (cell) {\n const w = cell.scrollWidth;\n if (w > max) max = w;\n }\n }\n if (max > 0) {\n col.width = max + 2;\n (col as ColumnInternal).__autoSized = true;\n changed = true;\n }\n });\n if (changed) updateTemplate(grid);\n grid.__didInitialAutoSize = true;\n}\n\n/**\n * Compute and apply the CSS grid template string that drives column layout.\n * Uses `fr` units for flexible (non user-resized) columns in stretch mode, otherwise\n * explicit pixel widths or auto sizing.\n */\nexport function updateTemplate(grid: InternalGrid): void {\n // Modes:\n // - 'stretch': columns with explicit width use that width; columns without width are flexible\n // Uses minmax(minWidth, maxWidth) when both min/max specified (bounded flex)\n // Uses minmax(minWidth, 1fr) when only min specified (grows unbounded)\n // Uses minmax(defaultMin, maxWidth) when only max specified (capped growth)\n // - 'fixed': columns with explicit width use that width; columns without width use max-content\n const mode = (grid as any).effectiveConfig?.fitMode || grid.fitMode || FitModeEnum.STRETCH;\n\n if (mode === FitModeEnum.STRETCH) {\n grid._gridTemplate = grid._visibleColumns\n .map((c: ColumnInternal) => {\n if (c.width) return `${c.width}px`;\n // Flexible column: pure 1fr unless minWidth specified\n const min = (c as any).minWidth;\n return min != null ? `minmax(${min}px, 1fr)` : '1fr';\n })\n .join(' ')\n .trim();\n } else {\n // fixed mode: explicit pixel widths or max-content for content-based sizing\n grid._gridTemplate = grid._visibleColumns\n .map((c: ColumnInternal) => (c.width ? `${c.width}px` : 'max-content'))\n .join(' ');\n }\n ((grid as unknown as HTMLElement).style as any).setProperty('--tbw-column-template', grid._gridTemplate);\n}\n","/**\n * Default Editors Module\n *\n * Provides built-in editor factories for different column types.\n */\n\nimport type { ColumnConfig, EditorContext } from '../types';\n\n/**\n * Returns a default editor factory function for the given column type.\n * Each editor handles focus, commit on blur/Enter, and cancel on Escape.\n */\nexport function defaultEditorFor(column: ColumnConfig<any>): (ctx: EditorContext) => HTMLElement | string {\n switch (column.type) {\n case 'number':\n return (ctx: EditorContext) => {\n const input = document.createElement('input');\n input.type = 'number';\n input.value = ctx.value != null ? String(ctx.value) : '';\n input.addEventListener('blur', () => ctx.commit(input.value === '' ? null : Number(input.value)));\n input.addEventListener('keydown', (e) => {\n if (e.key === 'Enter') ctx.commit(input.value === '' ? null : Number(input.value));\n if (e.key === 'Escape') ctx.cancel();\n });\n input.focus();\n return input;\n };\n case 'boolean':\n return (ctx: EditorContext) => {\n const input = document.createElement('input');\n input.type = 'checkbox';\n input.checked = !!ctx.value;\n input.addEventListener('change', () => ctx.commit(input.checked));\n input.focus();\n return input;\n };\n case 'date':\n return (ctx: EditorContext) => {\n const input = document.createElement('input');\n input.type = 'date';\n if (ctx.value instanceof Date) input.valueAsDate = ctx.value;\n input.addEventListener('change', () => ctx.commit(input.valueAsDate));\n input.addEventListener('keydown', (e) => {\n if (e.key === 'Escape') ctx.cancel();\n });\n input.focus();\n return input;\n };\n case 'select':\n case 'typeahead':\n return (ctx: EditorContext) => {\n const select = document.createElement('select');\n if ((ctx.column as any).multi) select.multiple = true;\n const options =\n typeof (ctx.column as any).options === 'function'\n ? (ctx.column as any).options()\n : (ctx.column as any).options || [];\n options.forEach((opt: any) => {\n const o = document.createElement('option');\n o.value = String(opt.value);\n o.textContent = opt.label;\n if ((ctx.column as any).multi && Array.isArray(ctx.value) && ctx.value.includes(opt.value)) o.selected = true;\n else if (!(ctx.column as any).multi && ctx.value === opt.value) o.selected = true;\n select.appendChild(o);\n });\n const commitValue = () => {\n if ((ctx.column as any).multi) {\n const values: any[] = [];\n Array.from(select.selectedOptions).forEach((o) => {\n values.push(o.value);\n });\n ctx.commit(values);\n } else {\n ctx.commit(select.value);\n }\n };\n select.addEventListener('change', commitValue);\n select.addEventListener('blur', commitValue);\n select.addEventListener('keydown', (e) => {\n if (e.key === 'Escape') ctx.cancel();\n });\n select.focus();\n return select;\n };\n default:\n return (ctx: EditorContext) => {\n const input = document.createElement('input');\n input.type = 'text';\n input.value = ctx.value != null ? String(ctx.value) : '';\n input.addEventListener('blur', () => ctx.commit(input.value));\n input.addEventListener('keydown', (e) => {\n if (e.key === 'Enter') ctx.commit(input.value);\n if (e.key === 'Escape') ctx.cancel();\n });\n input.focus();\n return input;\n };\n }\n}\n","/**\n * Central keyboard handler attached to the host element. Manages navigation, paging,\n * and edit lifecycle triggers while respecting active form field interactions.\n */\nimport type { InternalGrid } from '../types';\n\nexport function handleGridKeyDown(grid: InternalGrid, e: KeyboardEvent): void {\n // Dispatch to plugin system first - if any plugin handles it, stop here\n if (grid._dispatchKeyDown?.(e)) {\n return;\n }\n\n const maxRow = grid._rows.length - 1;\n const maxCol = grid._visibleColumns.length - 1;\n const editing = grid._activeEditRows !== undefined && grid._activeEditRows !== -1;\n const col = grid._visibleColumns[grid._focusCol];\n const colType = col?.type;\n const path = (e as any).composedPath ? (e as any).composedPath() : [];\n const target = (path && path.length ? path[0] : (e.target as any)) as HTMLElement | null;\n const isFormField = (el: HTMLElement | null) => {\n if (!el) return false;\n const tag = el.tagName;\n if (tag === 'INPUT' || tag === 'SELECT' || tag === 'TEXTAREA') return true;\n if (el.isContentEditable) return true;\n return false;\n };\n if (isFormField(target) && (e.key === 'Home' || e.key === 'End')) return;\n if (isFormField(target) && (e.key === 'ArrowUp' || e.key === 'ArrowDown')) {\n if ((target as HTMLInputElement).tagName === 'INPUT' && (target as HTMLInputElement).type === 'number') return;\n }\n // Let arrow left/right navigate within text inputs instead of moving cells\n if (isFormField(target) && (e.key === 'ArrowLeft' || e.key === 'ArrowRight')) return;\n // Let Enter/Escape be handled by the input's own handlers first\n if (isFormField(target) && (e.key === 'Enter' || e.key === 'Escape')) return;\n if (editing && (colType === 'select' || colType === 'typeahead') && (e.key === 'ArrowDown' || e.key === 'ArrowUp'))\n return;\n switch (e.key) {\n case 'Tab': {\n e.preventDefault();\n const forward = !e.shiftKey;\n if (forward) {\n if (grid._focusCol < maxCol) grid._focusCol += 1;\n else {\n if (typeof grid.commitActiveRowEdit === 'function') grid.commitActiveRowEdit();\n if (grid._focusRow < maxRow) {\n grid._focusRow += 1;\n grid._focusCol = 0;\n }\n }\n } else {\n if (grid._focusCol > 0) grid._focusCol -= 1;\n else if (grid._focusRow > 0) {\n if (typeof grid.commitActiveRowEdit === 'function' && grid._activeEditRows === grid._focusRow)\n grid.commitActiveRowEdit();\n grid._focusRow -= 1;\n grid._focusCol = maxCol;\n }\n }\n ensureCellVisible(grid);\n return;\n }\n case 'ArrowDown':\n if (editing && typeof grid.commitActiveRowEdit === 'function') grid.commitActiveRowEdit();\n grid._focusRow = Math.min(maxRow, grid._focusRow + 1);\n e.preventDefault();\n break;\n case 'ArrowUp':\n if (editing && typeof grid.commitActiveRowEdit === 'function') grid.commitActiveRowEdit();\n grid._focusRow = Math.max(0, grid._focusRow - 1);\n e.preventDefault();\n break;\n case 'ArrowRight':\n grid._focusCol = Math.min(maxCol, grid._focusCol + 1);\n e.preventDefault();\n break;\n case 'ArrowLeft':\n grid._focusCol = Math.max(0, grid._focusCol - 1);\n e.preventDefault();\n break;\n case 'Home':\n if (e.ctrlKey || e.metaKey) {\n // CTRL+Home: navigate to first row, first cell\n if (editing && typeof grid.commitActiveRowEdit === 'function') grid.commitActiveRowEdit();\n grid._focusRow = 0;\n grid._focusCol = 0;\n } else {\n // Home: navigate to first cell in current row\n grid._focusCol = 0;\n }\n e.preventDefault();\n ensureCellVisible(grid, { forceScrollLeft: true });\n return;\n case 'End':\n if (e.ctrlKey || e.metaKey) {\n // CTRL+End: navigate to last row, last cell\n if (editing && typeof grid.commitActiveRowEdit === 'function') grid.commitActiveRowEdit();\n grid._focusRow = maxRow;\n grid._focusCol = maxCol;\n } else {\n // End: navigate to last cell in current row\n grid._focusCol = maxCol;\n }\n e.preventDefault();\n ensureCellVisible(grid, { forceScrollRight: true });\n return;\n case 'PageDown':\n grid._focusRow = Math.min(maxRow, grid._focusRow + 20);\n e.preventDefault();\n break;\n case 'PageUp':\n grid._focusRow = Math.max(0, grid._focusRow - 20);\n e.preventDefault();\n break;\n case 'Enter':\n if (typeof grid.beginBulkEdit === 'function') grid.beginBulkEdit(grid._focusRow);\n else\n (grid as unknown as HTMLElement).dispatchEvent(\n new CustomEvent('activate-cell', { detail: { row: grid._focusRow, col: grid._focusCol } }),\n );\n return ensureCellVisible(grid);\n default:\n return;\n }\n ensureCellVisible(grid);\n}\n\n/**\n * Options for ensureCellVisible to control scroll behavior.\n */\ninterface EnsureCellVisibleOptions {\n /** Force scroll to the leftmost position (for Home key) */\n forceScrollLeft?: boolean;\n /** Force scroll to the rightmost position (for End key) */\n forceScrollRight?: boolean;\n}\n\n/**\n * Scroll the viewport (virtualized or static) so the focused cell's row is visible\n * and apply visual focus styling / tabindex management.\n */\nexport function ensureCellVisible(grid: InternalGrid, options?: EnsureCellVisibleOptions): void {\n if (grid._virtualization?.enabled) {\n const { rowHeight, container, viewportEl } = grid._virtualization;\n // container is the faux scrollbar element that handles actual scrolling\n // viewportEl is the visible area element that has the correct height\n const scrollEl = container as HTMLElement | undefined;\n const visibleHeight = viewportEl?.clientHeight ?? scrollEl?.clientHeight ?? 0;\n if (scrollEl && visibleHeight > 0) {\n const y = grid._focusRow * rowHeight;\n if (y < scrollEl.scrollTop) {\n scrollEl.scrollTop = y;\n } else if (y + rowHeight > scrollEl.scrollTop + visibleHeight) {\n scrollEl.scrollTop = y - visibleHeight + rowHeight;\n }\n }\n }\n // Skip refreshVirtualWindow when in edit mode to avoid wiping editors\n const isEditing = grid._activeEditRows !== undefined && grid._activeEditRows !== -1;\n if (!isEditing) {\n grid.refreshVirtualWindow(false);\n }\n Array.from(grid._bodyEl.querySelectorAll('.cell-focus')).forEach((el: any) => el.classList.remove('cell-focus'));\n // Clear previous aria-selected markers\n Array.from(grid._bodyEl.querySelectorAll('[aria-selected=\"true\"]')).forEach((el: any) => {\n el.setAttribute('aria-selected', 'false');\n });\n const rowIndex = grid._focusRow;\n const vStart = (grid._virtualization as any).start ?? 0;\n const vEnd = (grid._virtualization as any).end ?? grid._rows.length;\n if (rowIndex >= vStart && rowIndex < vEnd) {\n const rowEl = grid._bodyEl.querySelectorAll('.data-grid-row')[rowIndex - vStart] as HTMLElement | null;\n const cell = rowEl?.children[grid._focusCol] as HTMLElement | undefined;\n if (cell) {\n cell.classList.add('cell-focus');\n cell.setAttribute('aria-selected', 'true');\n\n // Horizontal scroll: ensure focused cell is visible in the horizontal scroll area\n // The .tbw-scroll-area element handles horizontal scrolling\n const scrollArea = grid.shadowRoot?.querySelector('.tbw-scroll-area') as HTMLElement | null;\n if (scrollArea && cell) {\n // Handle forced scroll for Home/End keys - always scroll to edge\n if (options?.forceScrollLeft) {\n scrollArea.scrollLeft = 0;\n } else if (options?.forceScrollRight) {\n scrollArea.scrollLeft = scrollArea.scrollWidth - scrollArea.clientWidth;\n } else {\n // Get scroll boundary offsets from plugins (e.g., pinned columns)\n // This allows plugins to report how much of the scroll area they obscure\n // and whether the focused cell should skip scrolling (e.g., pinned cells are always visible)\n const offsets = grid._getHorizontalScrollOffsets?.(rowEl ?? undefined, cell) ?? { left: 0, right: 0 };\n\n if (!offsets.skipScroll) {\n // Get cell position relative to the scroll area\n const cellRect = cell.getBoundingClientRect();\n const scrollAreaRect = scrollArea.getBoundingClientRect();\n // Calculate the cell's position relative to scroll area's visible region\n const cellLeft = cellRect.left - scrollAreaRect.left + scrollArea.scrollLeft;\n const cellRight = cellLeft + cellRect.width;\n // Adjust visible boundaries to account for plugin-reported offsets\n const visibleLeft = scrollArea.scrollLeft + offsets.left;\n const visibleRight = scrollArea.scrollLeft + scrollArea.clientWidth - offsets.right;\n // Scroll horizontally if needed\n if (cellLeft < visibleLeft) {\n scrollArea.scrollLeft = cellLeft - offsets.left;\n } else if (cellRight > visibleRight) {\n scrollArea.scrollLeft = cellRight - scrollArea.clientWidth + offsets.right;\n }\n }\n }\n }\n\n if (grid._activeEditRows !== undefined && grid._activeEditRows !== -1 && cell.classList.contains('editing')) {\n const focusTarget = cell.querySelector(\n 'input,select,textarea,[contenteditable=\"true\"],[contenteditable=\"\"],[tabindex]:not([tabindex=\"-1\"])',\n ) as HTMLElement | null;\n if (focusTarget && document.activeElement !== focusTarget) {\n try {\n focusTarget.focus();\n } catch {\n /* empty */\n }\n }\n } else if (!cell.contains(document.activeElement)) {\n if (!cell.hasAttribute('tabindex')) cell.setAttribute('tabindex', '-1');\n try {\n (cell as HTMLElement).focus({ preventScroll: true } as any);\n } catch {\n /* empty */\n }\n }\n }\n }\n}\n","import type { ColumnConfig, InternalGrid } from '../types';\nimport { addPart } from './columns';\nimport { commitCellValue, inlineEnterEdit, startRowEdit } from './editing';\nimport { ensureCellVisible } from './keyboard';\nimport { evalTemplateString, finalCellScrub, sanitizeHTML } from './sanitize';\n\n/** Callback type for plugin row rendering hook */\nexport type RenderRowHook = (row: any, rowEl: HTMLElement, rowIndex: number) => boolean;\n\n/**\n * Cell display value cache key on grid instance.\n * Structure: Map<rowIndex, Map<colIndex, displayString>>\n * This cache is invalidated when rows or columns change (epoch bump).\n */\nconst CELL_CACHE_KEY = '__cellDisplayCache';\nconst CELL_CACHE_EPOCH_KEY = '__cellCacheEpoch';\n\n/**\n * Get the cached display value for a cell, computing it if not cached.\n * This is the hot path during scroll - must be as fast as possible.\n */\nfunction getCellDisplayValue(\n grid: InternalGrid,\n rowIndex: number,\n colIndex: number,\n rowData: any,\n col: ColumnConfig<any>,\n epoch: number | undefined,\n): string {\n // Fast path: check cache first\n let cache = (grid as any)[CELL_CACHE_KEY] as Map<number, string[]> | undefined;\n const cacheEpoch = (grid as any)[CELL_CACHE_EPOCH_KEY];\n\n // Invalidate cache if epoch changed\n if (cache && cacheEpoch !== epoch) {\n cache = undefined;\n (grid as any)[CELL_CACHE_KEY] = undefined;\n }\n\n if (!cache) {\n cache = new Map();\n (grid as any)[CELL_CACHE_KEY] = cache;\n (grid as any)[CELL_CACHE_EPOCH_KEY] = epoch;\n }\n\n let rowCache = cache.get(rowIndex);\n if (rowCache && rowCache[colIndex] !== undefined) {\n return rowCache[colIndex];\n }\n\n // Compute the display value\n const displayValue = computeCellDisplayValue(rowData, col);\n\n // Cache it\n if (!rowCache) {\n rowCache = [];\n cache.set(rowIndex, rowCache);\n }\n rowCache[colIndex] = displayValue;\n\n return displayValue;\n}\n\n/**\n * Compute the display string for a cell value.\n * Handles formatting, date conversion, boolean display, etc.\n */\nfunction computeCellDisplayValue(rowData: any, col: ColumnConfig<any>): string {\n let value = rowData[col.field];\n\n // Apply format function if present\n const format = (col as any).format;\n if (format) {\n try {\n value = format(value, rowData);\n } catch {\n // Keep original value on format error\n }\n }\n\n // Type-specific conversion\n if (col.type === 'date') {\n if (value == null || value === '') return '';\n if (value instanceof Date) {\n return isNaN(value.getTime()) ? '' : value.toLocaleDateString();\n }\n if (typeof value === 'number' || typeof value === 'string') {\n const d = new Date(value);\n return isNaN(d.getTime()) ? '' : d.toLocaleDateString();\n }\n return '';\n }\n\n if (col.type === 'boolean') {\n return value ? '\\u{1F5F9}' : '\\u2610';\n }\n\n return value == null ? '' : String(value);\n}\n\n/**\n * Pre-compute display values for a range of rows.\n * Call this after rows change to warm the cache for visible + overscan rows.\n */\nexport function precomputeCellCache(\n grid: InternalGrid,\n startRow: number,\n endRow: number,\n epoch: number | undefined,\n): void {\n const columns = grid._visibleColumns;\n const rows = grid._rows;\n\n for (let r = startRow; r < endRow && r < rows.length; r++) {\n const rowData = rows[r];\n if (!rowData) continue;\n for (let c = 0; c < columns.length; c++) {\n // This will compute and cache\n getCellDisplayValue(grid, r, c, rowData, columns[c], epoch);\n }\n }\n}\n\n/**\n * Invalidate the cell cache (call when rows or columns change).\n */\nexport function invalidateCellCache(grid: InternalGrid): void {\n (grid as any)[CELL_CACHE_KEY] = undefined;\n (grid as any)[CELL_CACHE_EPOCH_KEY] = undefined;\n (grid as any).__hasSpecialColumns = undefined; // Reset fast-path check\n}\n\n/**\n * Render / patch the visible window of rows [start, end) using a recyclable DOM pool.\n * Newly required row elements are created and appended; excess are detached.\n * Uses an epoch counter to force full row rebuilds when structural changes (like columns) occur.\n * @param renderRowHook - Optional callback that plugins can use to render custom rows (e.g., group rows).\n * If it returns true, default rendering is skipped for that row.\n */\nexport function renderVisibleRows(\n grid: InternalGrid,\n start: number,\n end: number,\n epoch?: number,\n renderRowHook?: RenderRowHook,\n): void {\n const needed = Math.max(0, end - start);\n const bodyEl = grid._bodyEl;\n const columns = grid._visibleColumns;\n const colLen = columns.length;\n\n // Cache header row count once (check for group header row existence)\n let headerRowCount = (grid as any).__cachedHeaderRowCount;\n if (headerRowCount === undefined) {\n headerRowCount = grid.shadowRoot?.querySelector('.header-group-row') ? 2 : 1;\n (grid as any).__cachedHeaderRowCount = headerRowCount;\n }\n\n // Pool management: grow pool if needed\n while (grid._rowPool.length < needed) {\n const rowEl = document.createElement('div');\n rowEl.className = 'data-grid-row';\n rowEl.setAttribute('role', 'row');\n rowEl.addEventListener('click', (e) => handleRowClick(grid, e, rowEl, false));\n rowEl.addEventListener('dblclick', (e) => handleRowClick(grid, e, rowEl, true));\n grid._rowPool.push(rowEl);\n }\n\n // Remove excess pool elements from DOM and shrink pool\n if (grid._rowPool.length > needed) {\n for (let i = needed; i < grid._rowPool.length; i++) {\n const el = grid._rowPool[i];\n if (el.parentNode === bodyEl) el.remove();\n }\n grid._rowPool.length = needed;\n }\n\n // Check if any plugin has a renderRow hook (cache this)\n const hasRenderRowPlugins = renderRowHook && (grid as any).__hasRenderRowPlugins !== false;\n\n for (let i = 0; i < needed; i++) {\n const rowIndex = start + i;\n const rowData = grid._rows[rowIndex];\n const rowEl = grid._rowPool[i];\n\n // Always set aria-rowindex (1-based, accounting for header rows)\n rowEl.setAttribute('aria-rowindex', String(rowIndex + headerRowCount + 1));\n\n // Let plugins handle custom row rendering (e.g., group rows)\n if (hasRenderRowPlugins && renderRowHook!(rowData, rowEl, rowIndex)) {\n (rowEl as any).__epoch = epoch;\n (rowEl as any).__rowDataRef = rowData;\n if (rowEl.parentNode !== bodyEl) bodyEl.appendChild(rowEl);\n continue;\n }\n\n const rowEpoch = (rowEl as any).__epoch;\n const prevRef = (rowEl as any).__rowDataRef;\n const cellCount = rowEl.children.length;\n\n // Check if we need a full rebuild vs fast update\n const epochMatch = rowEpoch === epoch;\n const structureValid = epochMatch && cellCount === colLen;\n const dataRefChanged = prevRef !== rowData;\n\n // Need external view rebuild check when structure is valid but data changed\n let needsExternalRebuild = false;\n if (structureValid && dataRefChanged) {\n for (let c = 0; c < colLen; c++) {\n const col = columns[c];\n if ((col as any).externalView) {\n const cellCheck = rowEl.querySelector(`.cell[data-col=\"${c}\"] [data-external-view]`);\n if (!cellCheck) {\n needsExternalRebuild = true;\n break;\n }\n }\n }\n }\n\n if (!structureValid || needsExternalRebuild) {\n // Full rebuild needed - epoch changed, cell count mismatch, or external view missing\n const hasEditingCell = rowEl.querySelector('.cell.editing');\n const isActivelyEditedRow = grid._activeEditRows === rowIndex;\n\n // If DOM element has editors but this is NOT the actively edited row, clear them\n // (This happens when virtualization recycles the DOM element for a different row)\n if (hasEditingCell && !isActivelyEditedRow) {\n // Force full rebuild to clear stale editors\n if ((rowEl as any).__isCustomRow) {\n rowEl.className = 'data-grid-row';\n rowEl.setAttribute('role', 'row');\n (rowEl as any).__isCustomRow = false;\n }\n renderInlineRow(grid, rowEl, rowData, rowIndex);\n (rowEl as any).__epoch = epoch;\n (rowEl as any).__rowDataRef = rowData;\n } else if (hasEditingCell && isActivelyEditedRow) {\n // Row is in editing mode AND this is the correct row - preserve editors\n fastPatchRow(grid, rowEl, rowData, rowIndex);\n (rowEl as any).__rowDataRef = rowData;\n } else {\n if ((rowEl as any).__isCustomRow) {\n rowEl.className = 'data-grid-row';\n rowEl.setAttribute('role', 'row');\n (rowEl as any).__isCustomRow = false;\n }\n renderInlineRow(grid, rowEl, rowData, rowIndex);\n (rowEl as any).__epoch = epoch;\n (rowEl as any).__rowDataRef = rowData;\n\n // If this is the actively edited row but DOM doesn't have editors, create them\n if (isActivelyEditedRow) {\n const children = rowEl.children;\n for (let c = 0; c < children.length; c++) {\n const col = grid._visibleColumns[c];\n if (col && (col as any).editable) {\n inlineEnterEdit(grid, rowData, rowIndex, col, children[c] as HTMLElement);\n }\n }\n }\n }\n } else if (dataRefChanged) {\n // Same structure, different row data - fast update\n const hasEditingCell = rowEl.querySelector('.cell.editing');\n const isActivelyEditedRow = grid._activeEditRows === rowIndex;\n\n // If DOM element has editors but this is NOT the actively edited row, clear them\n if (hasEditingCell && !isActivelyEditedRow) {\n renderInlineRow(grid, rowEl, rowData, rowIndex);\n (rowEl as any).__epoch = epoch;\n (rowEl as any).__rowDataRef = rowData;\n } else {\n fastPatchRow(grid, rowEl, rowData, rowIndex);\n (rowEl as any).__rowDataRef = rowData;\n\n // If this is the actively edited row but DOM doesn't have editors, create them\n if (isActivelyEditedRow && !hasEditingCell) {\n const children = rowEl.children;\n for (let c = 0; c < children.length; c++) {\n const col = grid._visibleColumns[c];\n if (col && (col as any).editable) {\n inlineEnterEdit(grid, rowData, rowIndex, col, children[c] as HTMLElement);\n }\n }\n }\n }\n } else {\n // Same row data reference - just patch if any values changed\n const hasEditingCell = rowEl.querySelector('.cell.editing');\n const isActivelyEditedRow = grid._activeEditRows === rowIndex;\n\n // If DOM element has editors but this is NOT the actively edited row, clear them\n if (hasEditingCell && !isActivelyEditedRow) {\n renderInlineRow(grid, rowEl, rowData, rowIndex);\n (rowEl as any).__epoch = epoch;\n (rowEl as any).__rowDataRef = rowData;\n } else {\n fastPatchRow(grid, rowEl, rowData, rowIndex);\n\n // If this is the actively edited row but DOM doesn't have editors, create them\n if (isActivelyEditedRow && !hasEditingCell) {\n const children = rowEl.children;\n for (let c = 0; c < children.length; c++) {\n const col = grid._visibleColumns[c];\n if (col && (col as any).editable) {\n inlineEnterEdit(grid, rowData, rowIndex, col, children[c] as HTMLElement);\n }\n }\n }\n }\n }\n\n // Changed class toggle\n const isChanged = grid._changedRowIndices.has(rowIndex);\n const hasChangedClass = rowEl.classList.contains('changed');\n if (isChanged !== hasChangedClass) {\n rowEl.classList.toggle('changed', isChanged);\n }\n\n if (rowEl.parentNode !== bodyEl) bodyEl.appendChild(rowEl);\n }\n}\n\n/**\n * Fast patch path for an already-rendered row: updates plain text cells whose data changed\n * while skipping cells with external views, templates, or active editors.\n *\n * Optimized for scroll performance - avoids querySelectorAll in favor of children access.\n */\nfunction fastPatchRow(grid: InternalGrid, rowEl: HTMLElement, rowData: any, rowIndex: number): void {\n const children = rowEl.children;\n const columns = grid._visibleColumns;\n const colsLen = columns.length;\n const childLen = children.length;\n const minLen = colsLen < childLen ? colsLen : childLen;\n const focusRow = grid._focusRow;\n const focusCol = grid._focusCol;\n\n // Ultra-fast path: if no special columns (templates, formatters, etc.), use direct assignment\n // Check is cached on grid to avoid repeated iteration\n let hasSpecialCols = (grid as any).__hasSpecialColumns;\n if (hasSpecialCols === undefined) {\n hasSpecialCols = false;\n for (let i = 0; i < colsLen; i++) {\n const col = columns[i] as any;\n if (\n col.__viewTemplate ||\n col.__compiledView ||\n col.viewRenderer ||\n col.externalView ||\n col.format ||\n col.type === 'date' ||\n col.type === 'boolean'\n ) {\n hasSpecialCols = true;\n break;\n }\n }\n (grid as any).__hasSpecialColumns = hasSpecialCols;\n }\n\n const rowIndexStr = String(rowIndex);\n\n // Ultra-fast path for plain text grids - just set textContent directly\n if (!hasSpecialCols) {\n for (let i = 0; i < minLen; i++) {\n const cell = children[i] as HTMLElement;\n const value = rowData[columns[i].field];\n cell.textContent = value == null ? '' : String(value);\n // Update data-row for click handling\n if (cell.getAttribute('data-row') !== rowIndexStr) {\n cell.setAttribute('data-row', rowIndexStr);\n }\n // Update focus state - must be data-driven, not DOM-element-driven\n const shouldHaveFocus = focusRow === rowIndex && focusCol === i;\n const hasFocus = cell.classList.contains('cell-focus');\n if (shouldHaveFocus !== hasFocus) {\n cell.classList.toggle('cell-focus', shouldHaveFocus);\n // aria-selected only valid for gridcell, not checkbox (but ultra-fast path has no special cols)\n cell.setAttribute('aria-selected', String(shouldHaveFocus));\n }\n }\n return;\n }\n\n // Check if any external view placeholder is missing - if so, do full rebuild\n for (let i = 0; i < minLen; i++) {\n const col = columns[i] as any;\n if (col.externalView) {\n const cell = children[i] as HTMLElement;\n if (!cell.querySelector('[data-external-view]')) {\n renderInlineRow(grid, rowEl, rowData, rowIndex);\n return;\n }\n }\n }\n\n // Standard path for grids with special columns\n for (let i = 0; i < minLen; i++) {\n const col = columns[i] as any;\n const cell = children[i] as HTMLElement;\n\n // Update data-row for click handling\n if (cell.getAttribute('data-row') !== rowIndexStr) {\n cell.setAttribute('data-row', rowIndexStr);\n }\n\n // Update focus state - must be data-driven, not DOM-element-driven\n const shouldHaveFocus = focusRow === rowIndex && focusCol === i;\n const hasFocus = cell.classList.contains('cell-focus');\n if (shouldHaveFocus !== hasFocus) {\n cell.classList.toggle('cell-focus', shouldHaveFocus);\n cell.setAttribute('aria-selected', String(shouldHaveFocus));\n }\n\n // Skip cells in edit mode\n if (cell.classList.contains('editing')) continue;\n\n // Handle viewRenderer - must re-invoke to get updated content\n if (col.viewRenderer) {\n const value = rowData[col.field];\n const produced = col.viewRenderer({ row: rowData, value, field: col.field, column: col });\n if (typeof produced === 'string') {\n cell.innerHTML = sanitizeHTML(produced);\n } else if (produced) {\n cell.innerHTML = '';\n cell.appendChild(produced);\n } else {\n cell.textContent = value == null ? '' : String(value);\n }\n continue;\n }\n\n // Skip templated / external cells (these need full rebuild to remount)\n if (col.__viewTemplate || col.__compiledView || col.externalView) {\n continue;\n }\n\n // Compute and set display value\n const value = rowData[col.field];\n let displayStr: string;\n\n if (col.format) {\n try {\n const formatted = col.format(value, rowData);\n displayStr = formatted == null ? '' : String(formatted);\n } catch {\n displayStr = value == null ? '' : String(value);\n }\n } else if (col.type === 'date') {\n if (value == null || value === '') {\n displayStr = '';\n } else if (value instanceof Date) {\n displayStr = isNaN(value.getTime()) ? '' : value.toLocaleDateString();\n } else {\n const d = new Date(value);\n displayStr = isNaN(d.getTime()) ? '' : d.toLocaleDateString();\n }\n cell.textContent = displayStr;\n } else if (col.type === 'boolean') {\n const isTrue = !!value;\n // Boolean cells have inner span with checkbox role for ARIA compliance\n cell.innerHTML = `<span role=\"checkbox\" aria-checked=\"${isTrue}\" aria-label=\"${isTrue}\">${isTrue ? '🗹' : '☐'}</span>`;\n } else {\n displayStr = value == null ? '' : String(value);\n cell.textContent = displayStr;\n }\n }\n}\n\n/**\n * Full reconstruction of a row's set of cells including templated, external view, and formatted content.\n * Attaches event handlers for editing and accessibility per cell.\n */\nexport function renderInlineRow(grid: InternalGrid, rowEl: HTMLElement, rowData: any, rowIndex: number): void {\n rowEl.innerHTML = '';\n\n // Pre-cache values used in the loop\n const columns = grid._visibleColumns;\n const colsLen = columns.length;\n const focusRow = grid._focusRow;\n const focusCol = grid._focusCol;\n const editMode = (grid as any).effectiveConfig?.editOn || grid.editOn;\n const gridEl = grid as unknown as HTMLElement;\n\n // Use DocumentFragment for batch DOM insertion\n const fragment = document.createDocumentFragment();\n\n for (let colIndex = 0; colIndex < colsLen; colIndex++) {\n const col: ColumnConfig<any> = columns[colIndex];\n const cell = document.createElement('div');\n cell.className = 'cell';\n addPart(cell, 'cell');\n\n // All cells get role=gridcell (required by role=row)\n cell.setAttribute('role', 'gridcell');\n // aria-colindex is 1-based\n cell.setAttribute('aria-colindex', String(colIndex + 1));\n cell.setAttribute('data-col', String(colIndex));\n cell.setAttribute('data-row', String(rowIndex));\n const isCheckbox = col.type === 'boolean';\n if (col.type) cell.setAttribute('data-type', col.type as any);\n\n let value = (rowData as any)[col.field];\n const format = (col as any).format;\n if (format) {\n try {\n value = format(value, rowData);\n } catch {\n /* empty */\n }\n }\n\n const compiled = (col as any).__compiledView as ((ctx: any) => string) | undefined;\n const tplHolder = (col as any).__viewTemplate as HTMLElement | undefined;\n const viewRenderer = (col as any).viewRenderer;\n const externalView = (col as any).externalView;\n\n // Track if we used a template that needs sanitization\n let needsSanitization = false;\n\n if (viewRenderer) {\n const produced = viewRenderer({ row: rowData, value, field: col.field, column: col });\n if (typeof produced === 'string') {\n // Sanitize HTML from viewRenderer to prevent XSS from user-controlled data\n cell.innerHTML = sanitizeHTML(produced);\n needsSanitization = true;\n } else if (produced) cell.appendChild(produced);\n else cell.textContent = value == null ? '' : String(value);\n } else if (externalView) {\n const spec = externalView;\n const placeholder = document.createElement('div');\n placeholder.setAttribute('data-external-view', '');\n placeholder.setAttribute('data-field', col.field);\n cell.appendChild(placeholder);\n const context = { row: rowData, value, field: col.field, column: col };\n if (spec.mount) {\n try {\n spec.mount({ placeholder, context, spec });\n } catch {\n /* empty */\n }\n } else {\n queueMicrotask(() => {\n try {\n gridEl.dispatchEvent(\n new CustomEvent('mount-external-view', {\n bubbles: true,\n composed: true,\n detail: { placeholder, spec, context },\n }),\n );\n } catch {\n /* empty */\n }\n });\n }\n placeholder.setAttribute('data-mounted', '');\n } else if (compiled) {\n const output = compiled({ row: rowData, value, field: col.field, column: col });\n const blocked = (compiled as any).__blocked;\n // Sanitize compiled template output to prevent XSS\n cell.innerHTML = blocked ? '' : sanitizeHTML(output);\n needsSanitization = true;\n if (blocked) {\n // Forcefully clear any residual whitespace text nodes for deterministic emptiness\n cell.textContent = '';\n cell.setAttribute('data-blocked-template', '');\n }\n } else if (tplHolder) {\n const rawTpl = tplHolder.innerHTML;\n if (/Reflect\\.|\\bProxy\\b|ownKeys\\(/.test(rawTpl)) {\n cell.textContent = '';\n cell.setAttribute('data-blocked-template', '');\n } else {\n // Sanitize inline template output to prevent XSS\n cell.innerHTML = sanitizeHTML(evalTemplateString(rawTpl, { row: rowData, value }));\n needsSanitization = true;\n }\n } else {\n // Plain value rendering - compute display directly (matches Stencil performance)\n if (col.type === 'date') {\n if (value == null || value === '') {\n cell.textContent = '';\n } else {\n let d: Date | null = null;\n if (value instanceof Date) d = value;\n else if (typeof value === 'number' || typeof value === 'string') {\n const tentative = new Date(value);\n if (!isNaN(tentative.getTime())) d = tentative;\n }\n cell.textContent = d ? d.toLocaleDateString() : '';\n }\n } else if (col.type === 'boolean') {\n const isTrue = !!value;\n // Wrap checkbox in span to satisfy ARIA: gridcell can contain checkbox\n cell.innerHTML = `<span role=\"checkbox\" aria-checked=\"${isTrue}\" aria-label=\"${isTrue}\">${isTrue ? '🗹' : '☐'}</span>`;\n } else {\n cell.textContent = value == null ? '' : String(value);\n }\n }\n\n // Only run expensive sanitization when we used innerHTML with user content\n if (needsSanitization) {\n finalCellScrub(cell);\n // Defensive: if forbidden tokens leaked via async or framework hydration, scrub again.\n const textContent = cell.textContent || '';\n if (/Proxy|Reflect\\.ownKeys/.test(textContent)) {\n cell.textContent = textContent.replace(/Proxy|Reflect\\.ownKeys/g, '').trim();\n if (/Proxy|Reflect\\.ownKeys/.test(cell.textContent || '')) cell.textContent = '';\n }\n }\n\n if (cell.hasAttribute('data-blocked-template')) {\n // If anything at all remains (e.g., 'function () { [native code] }'), blank it completely.\n if ((cell.textContent || '').trim().length) cell.textContent = '';\n }\n if ((col as any).editable) {\n cell.tabIndex = 0;\n cell.addEventListener('mousedown', () => {\n // Skip if cell is already in editing mode - avoid refreshVirtualWindow wiping editors\n if (cell.classList.contains('editing')) return;\n // Read row/col index from data attributes to handle virtualization row reuse\n const currentRowIndex = Number(cell.getAttribute('data-row'));\n const currentColIndex = Number(cell.getAttribute('data-col'));\n if (isNaN(currentRowIndex) || isNaN(currentColIndex)) return;\n grid._focusRow = currentRowIndex;\n grid._focusCol = currentColIndex;\n ensureCellVisible(grid);\n });\n if (editMode === 'click') {\n cell.addEventListener('click', (e) => {\n if (cell.classList.contains('editing')) return;\n e.stopPropagation();\n // Read row/col index from data attributes to handle virtualization row reuse\n const currentRowIndex = Number(cell.getAttribute('data-row'));\n const currentColIndex = Number(cell.getAttribute('data-col'));\n if (isNaN(currentRowIndex) || isNaN(currentColIndex)) return;\n const currentRowData = grid._rows[currentRowIndex];\n const currentCol = grid._visibleColumns[currentColIndex];\n if (!currentRowData || !currentCol) return;\n grid._focusRow = currentRowIndex;\n grid._focusCol = currentColIndex;\n inlineEnterEdit(grid, currentRowData, currentRowIndex, currentCol, cell);\n });\n } else {\n cell.addEventListener('dblclick', (e) => {\n e.stopPropagation();\n // Read row index from data attribute to handle virtualization row reuse\n const currentRowIndex = Number(cell.getAttribute('data-row'));\n if (isNaN(currentRowIndex)) return;\n const currentRowData = grid._rows[currentRowIndex];\n if (!currentRowData) return;\n startRowEdit(grid, currentRowIndex, currentRowData);\n const rowElCurrent = grid.findRenderedRowElement?.(currentRowIndex);\n if (rowElCurrent) {\n const children = rowElCurrent.children;\n for (let i = 0; i < children.length; i++) {\n const col2 = grid._visibleColumns[i];\n if (col2 && (col2 as any).editable)\n inlineEnterEdit(grid, currentRowData, currentRowIndex, col2, children[i] as HTMLElement);\n }\n }\n });\n }\n cell.addEventListener('keydown', (e) => {\n // Read row/col index from data attributes to handle virtualization row reuse\n const currentRowIndex = Number(cell.getAttribute('data-row'));\n const currentColIndex = Number(cell.getAttribute('data-col'));\n if (isNaN(currentRowIndex) || isNaN(currentColIndex)) return;\n const currentRowData = grid._rows[currentRowIndex];\n const currentCol = grid._visibleColumns[currentColIndex];\n if (!currentRowData || !currentCol) return;\n if (\n (currentCol.type === 'select' || currentCol.type === 'typeahead') &&\n !cell.classList.contains('editing') &&\n e.key === 'Enter'\n ) {\n e.preventDefault();\n if (grid._activeEditRows !== currentRowIndex) startRowEdit(grid, currentRowIndex, currentRowData);\n inlineEnterEdit(grid, currentRowData, currentRowIndex, currentCol, cell);\n setTimeout(() => {\n const selectEl = cell.querySelector('select') as HTMLSelectElement | null;\n try {\n (selectEl as any)?.showPicker?.();\n } catch {\n /* empty */\n }\n selectEl?.focus();\n }, 0);\n return;\n }\n if (currentCol.type === 'boolean' && e.key === ' ' && !cell.classList.contains('editing')) {\n e.preventDefault();\n if (grid._activeEditRows !== currentRowIndex) startRowEdit(grid, currentRowIndex, currentRowData);\n const newVal = !currentRowData[currentCol.field];\n commitCellValue(grid, currentRowIndex, currentCol, newVal, currentRowData);\n cell.innerHTML = `<span role=\"checkbox\" aria-checked=\"${newVal}\" aria-label=\"${newVal}\">${newVal ? '🗹' : '☐'}</span>`;\n return;\n }\n if (e.key === 'Enter' && !cell.classList.contains('editing')) {\n e.preventDefault();\n e.stopPropagation(); // Prevent grid-level handler from also processing Enter\n grid._focusRow = currentRowIndex;\n grid._focusCol = currentColIndex;\n if (typeof grid.beginBulkEdit === 'function') grid.beginBulkEdit(currentRowIndex);\n else inlineEnterEdit(grid, currentRowData, currentRowIndex, currentCol, cell);\n return;\n }\n if (e.key === 'F2' && !cell.classList.contains('editing')) {\n e.preventDefault();\n inlineEnterEdit(grid, currentRowData, currentRowIndex, currentCol, cell);\n return;\n }\n });\n } else if (col.type === 'boolean') {\n // Non-editable boolean cells should NOT toggle on space key\n // They are read-only, only set tabindex for focus navigation\n if (!cell.hasAttribute('tabindex')) cell.tabIndex = 0;\n }\n\n // Initialize focus state (must match fastPatchRow for consistent behavior)\n if (focusRow === rowIndex && focusCol === colIndex) {\n cell.classList.add('cell-focus');\n cell.setAttribute('aria-selected', 'true');\n } else {\n cell.setAttribute('aria-selected', 'false');\n }\n\n fragment.appendChild(cell);\n }\n\n // Single DOM operation to append all cells\n rowEl.appendChild(fragment);\n}\n\n/**\n * Handle click / double click interaction to focus cells and optionally start row editing\n * according to the grid's configured edit activation mode.\n */\nexport function handleRowClick(grid: InternalGrid, e: MouseEvent, rowEl: HTMLElement, isDbl: boolean): void {\n if ((e.target as HTMLElement)?.closest('.resize-handle')) return;\n const firstCell = rowEl.querySelector('.cell[data-row]') as HTMLElement | null;\n if (!firstCell) return;\n const rowIndex = Number(firstCell.getAttribute('data-row'));\n if (isNaN(rowIndex)) return;\n const rowData = grid._rows[rowIndex];\n if (!rowData) return;\n const cellEl = (e.target as HTMLElement)?.closest('.cell[data-col]') as HTMLElement | null;\n if (cellEl) {\n // Skip focus/ensureCellVisible if cell is already editing - avoid wiping editors\n if (cellEl.classList.contains('editing')) return;\n const colIndex = Number(cellEl.getAttribute('data-col'));\n if (!isNaN(colIndex)) {\n // Dispatch to plugin system first - if handled, stop propagation\n if (grid._dispatchCellClick?.(e, rowIndex, colIndex, cellEl)) {\n return;\n }\n grid._focusRow = rowIndex;\n grid._focusCol = colIndex;\n ensureCellVisible(grid);\n }\n }\n if (rowEl.querySelector('.cell.editing')) {\n const active = rowEl.querySelectorAll('.cell.editing');\n if (!isDbl) return;\n active.forEach((n: any) => n.classList.remove('editing'));\n }\n const mode: 'click' | 'doubleClick' = ((grid as any).effectiveConfig?.editOn || grid.editOn || 'doubleClick') as any;\n if (mode === 'click' || (mode === 'doubleClick' && isDbl)) startRowEdit(grid, rowIndex, rowData);\n else return;\n Array.from(rowEl.children).forEach((c: any, i: number) => {\n const col = grid._visibleColumns[i];\n if (col && (col as any).editable) inlineEnterEdit(grid, rowData, rowIndex, col, c as HTMLElement);\n });\n if (cellEl) {\n queueMicrotask(() => {\n const targetCell = rowEl.querySelector(`.cell[data-col=\"${grid._focusCol}\"]`);\n if (targetCell?.classList.contains('editing')) {\n const editor = (targetCell as HTMLElement).querySelector(\n 'input,select,textarea,[contenteditable=\"true\"],[contenteditable=\"\"],[tabindex]:not([tabindex=\"-1\"])',\n ) as HTMLElement | null;\n try {\n editor?.focus();\n } catch {\n /* empty */\n }\n }\n });\n }\n}\n","/**\n * Editing Lifecycle Module\n *\n * Handles row/cell editing state, commit/cancel operations, and value persistence.\n */\n\nimport type { ColumnConfig, InternalGrid } from '../types';\nimport { defaultEditorFor } from './editors';\nimport { invalidateCellCache, renderInlineRow } from './rows';\n\n/**\n * Returns true if the given property key is safe to use on a plain object without risking\n * prototype pollution via special names like \"__proto__\", \"constructor\", or \"prototype\".\n */\nfunction isSafePropertyKey(key: any): boolean {\n if (key === '__proto__' || key === 'constructor' || key === 'prototype') return false;\n return true;\n}\n\n/**\n * Snapshot original row data and mark the row as actively being edited.\n */\nexport function startRowEdit(grid: InternalGrid, rowIndex: number, rowData: any): void {\n if (grid._activeEditRows !== rowIndex) {\n grid._rowEditSnapshots.set(rowIndex, { ...rowData });\n grid._activeEditRows = rowIndex;\n }\n}\n\n/**\n * Finish editing for a row. If `revert` is true restore original snapshot and clear change marks.\n * Otherwise emit a row-commit event describing change status.\n */\nexport function exitRowEdit(grid: InternalGrid, rowIndex: number, revert: boolean): void {\n if (grid._activeEditRows !== rowIndex) return;\n const snapshot = grid._rowEditSnapshots.get(rowIndex);\n const current = grid._rows[rowIndex];\n\n // Before re-rendering, collect and commit values from any active editors\n // This ensures values are persisted even if blur hasn't fired yet\n const rowEl = grid.findRenderedRowElement?.(rowIndex);\n if (!revert && rowEl && current) {\n const editingCells = rowEl.querySelectorAll('.cell.editing');\n editingCells.forEach((cell) => {\n const colIndex = Number((cell as HTMLElement).getAttribute('data-col'));\n if (isNaN(colIndex)) return;\n const col = grid._visibleColumns[colIndex];\n if (!col) return;\n const input = cell.querySelector('input,textarea,select') as\n | HTMLInputElement\n | HTMLTextAreaElement\n | HTMLSelectElement\n | null;\n if (input) {\n let val: unknown;\n if (input instanceof HTMLInputElement && input.type === 'checkbox') {\n val = input.checked;\n } else {\n val = input.value;\n // Convert to number for number columns\n if (col.type === 'number' && val !== '') {\n val = Number(val);\n }\n }\n // Only commit if value actually changed\n if (current[col.field] !== val) {\n commitCellValue(grid, rowIndex, col, val, current);\n }\n }\n });\n }\n\n if (revert && snapshot && current) {\n Object.keys(snapshot).forEach((k) => (current[k] = snapshot[k]));\n grid._changedRowIndices.delete(rowIndex);\n // Invalidate cell cache so reverted values display correctly\n invalidateCellCache(grid);\n } else if (!revert) {\n const changed = grid._changedRowIndices.has(rowIndex);\n (grid as unknown as HTMLElement).dispatchEvent(\n new CustomEvent('row-commit', {\n detail: {\n rowIndex,\n row: current,\n changed,\n changedRows: grid.changedRows,\n changedRowIndices: grid.changedRowIndices,\n },\n }),\n );\n }\n grid._rowEditSnapshots.delete(rowIndex);\n grid._activeEditRows = -1;\n if (rowEl) {\n renderInlineRow(grid, rowEl, grid._rows[rowIndex], rowIndex);\n if (grid._changedRowIndices.has(rowIndex)) rowEl.classList.add('changed');\n else rowEl.classList.remove('changed');\n }\n // Restore focus to the cell after exiting edit mode (for both commit and revert)\n queueMicrotask(() => {\n try {\n const rowIdx = grid._focusRow;\n const colIdx = grid._focusCol;\n const rowEl2 = grid.findRenderedRowElement?.(rowIdx);\n if (rowEl2) {\n // Clear all cell-focus markers\n Array.from(grid._bodyEl.querySelectorAll('.cell-focus')).forEach((el: any) =>\n el.classList.remove('cell-focus'),\n );\n // Find and focus the cell\n const cell = rowEl2.querySelector(`.cell[data-row=\"${rowIdx}\"][data-col=\"${colIdx}\"]`) as HTMLElement | null;\n if (cell) {\n cell.classList.add('cell-focus');\n cell.setAttribute('aria-selected', 'true');\n if (!cell.hasAttribute('tabindex')) cell.setAttribute('tabindex', '-1');\n cell.focus({ preventScroll: true });\n }\n }\n } catch {\n /* empty */\n }\n });\n}\n\n/**\n * Commit a single cell value change, updating the row object, marking the row as changed (first-time flag),\n * and emitting a `cell-commit` event with row + field metadata.\n */\nexport function commitCellValue(\n grid: InternalGrid,\n rowIndex: number,\n column: ColumnConfig<any>,\n newValue: any,\n rowData: any,\n): void {\n const field = column.field;\n if (!isSafePropertyKey(field)) return;\n const oldValue = rowData[field];\n if (oldValue === newValue) return;\n rowData[field] = newValue;\n const firstTime = !grid._changedRowIndices.has(rowIndex);\n grid._changedRowIndices.add(rowIndex);\n const rowEl = grid.findRenderedRowElement?.(rowIndex);\n if (rowEl) rowEl.classList.add('changed');\n (grid as unknown as HTMLElement).dispatchEvent(\n new CustomEvent('cell-commit', {\n detail: {\n row: rowData,\n field,\n value: newValue,\n rowIndex,\n changedRows: grid.changedRows,\n changedRowIndices: grid.changedRowIndices,\n firstTimeForRow: firstTime,\n },\n }),\n );\n}\n\n/**\n * Replace a cell's content with an editor resolved from column configuration (custom editor, template, external\n * mount spec or default editor by type). Manages commit / cancel lifecycle and value restoration.\n */\nexport function inlineEnterEdit(\n grid: InternalGrid,\n rowData: any,\n rowIndex: number,\n column: ColumnConfig<any>,\n cell: HTMLElement,\n): void {\n if (!column.editable) return;\n if (grid._activeEditRows !== rowIndex) startRowEdit(grid, rowIndex, rowData);\n if (cell.classList.contains('editing')) return;\n const originalValue = isSafePropertyKey(column.field) ? rowData[column.field] : undefined;\n cell.classList.add('editing');\n let editFinalized = false; // Flag to prevent blur from committing after explicit Enter/Escape\n const commit = (newValue: any) => {\n // Skip if edit was already finalized by Enter/Escape, or if we've exited edit mode\n // (handles bulk edit case where one cell's exit removes all editors)\n if (editFinalized || grid._activeEditRows === -1) return;\n commitCellValue(grid, rowIndex, column, newValue, rowData);\n };\n const cancel = () => {\n editFinalized = true; // Mark as finalized to prevent blur from re-committing\n rowData[column.field] = isSafePropertyKey(column.field) ? originalValue : undefined;\n const inputLike = cell.querySelector('input,textarea,select') as any;\n if (inputLike) {\n const hasHTMLInput = typeof HTMLInputElement !== 'undefined';\n if (hasHTMLInput && inputLike instanceof HTMLInputElement && inputLike.type === 'checkbox')\n inputLike.checked = !!originalValue;\n else if ('value' in inputLike) inputLike.value = originalValue ?? '';\n }\n };\n const editorHost = document.createElement('div');\n editorHost.style.display = 'contents';\n cell.innerHTML = '';\n cell.appendChild(editorHost);\n\n // Common keydown handler for all editor types to handle Enter/Escape with proper exit\n // This catches events that bubble up from child elements (default editors, custom editors)\n editorHost.addEventListener('keydown', (e: KeyboardEvent) => {\n if (e.key === 'Enter') {\n e.stopPropagation();\n e.preventDefault();\n editFinalized = true; // Prevent blur from committing again\n // Value should already be committed by the editor's own handler\n // Just need to exit edit mode\n exitRowEdit(grid, rowIndex, false);\n }\n if (e.key === 'Escape') {\n e.stopPropagation();\n e.preventDefault();\n cancel(); // cancel() sets editFinalized = true\n exitRowEdit(grid, rowIndex, true);\n }\n });\n\n const tplHolder = (column as any).__editorTemplate as HTMLElement | undefined;\n const editorSpec = (column as any).editor || (tplHolder ? 'template' : defaultEditorFor(column));\n const value = originalValue;\n if (editorSpec === 'template' && tplHolder) {\n const clone = tplHolder.cloneNode(true) as HTMLElement;\n const compiledEditor = (column as any).__compiledEditor as ((ctx: any) => string) | undefined;\n if (compiledEditor)\n clone.innerHTML = compiledEditor({ row: rowData, value: originalValue, field: column.field, column });\n else\n clone.querySelectorAll<HTMLElement>('*').forEach((node) => {\n if (node.childNodes.length === 1 && node.firstChild?.nodeType === Node.TEXT_NODE) {\n node.textContent =\n node.textContent\n ?.replace(/{{\\s*value\\s*}}/g, originalValue == null ? '' : String(originalValue))\n .replace(/{{\\s*row\\.([a-zA-Z0-9_]+)\\s*}}/g, (_m, g) => {\n const v = (rowData as any)[g];\n return v == null ? '' : String(v);\n }) || '';\n }\n });\n const input = clone.querySelector('input,textarea,select') as HTMLInputElement | HTMLSelectElement | null;\n if (input) {\n const hasHTMLInput = typeof HTMLInputElement !== 'undefined';\n if (hasHTMLInput && input instanceof HTMLInputElement && input.type === 'checkbox')\n input.checked = !!originalValue;\n else if ('value' in input) (input as any).value = originalValue ?? '';\n input.addEventListener('blur', () => {\n // commit() will check editFinalized flag and skip if already handled\n const val =\n hasHTMLInput && input instanceof HTMLInputElement && input.type === 'checkbox'\n ? input.checked\n : (input as any).value;\n commit(val);\n });\n input.addEventListener('keydown', (e: any) => {\n if (e.key === 'Enter') {\n e.stopPropagation();\n e.preventDefault();\n editFinalized = true; // Prevent blur from committing again\n const val =\n hasHTMLInput && input instanceof HTMLInputElement && input.type === 'checkbox'\n ? input.checked\n : (input as any).value;\n commit(val);\n exitRowEdit(grid, rowIndex, false);\n }\n if (e.key === 'Escape') {\n e.stopPropagation();\n e.preventDefault();\n cancel(); // cancel() sets editFinalized = true\n exitRowEdit(grid, rowIndex, true);\n }\n });\n if (hasHTMLInput && input instanceof HTMLInputElement && input.type === 'checkbox') {\n input.addEventListener('change', () => {\n const val = input.checked;\n commit(val);\n });\n }\n setTimeout(() => input.focus(), 0);\n }\n editorHost.appendChild(clone);\n } else if (typeof editorSpec === 'string') {\n const el = document.createElement(editorSpec);\n (el as any).value = value;\n el.addEventListener('change', () => commit((el as any).value));\n editorHost.appendChild(el);\n } else if (typeof editorSpec === 'function') {\n const produced = editorSpec({ row: rowData, value, field: column.field, column, commit, cancel });\n if (typeof produced === 'string') editorHost.innerHTML = produced;\n else editorHost.appendChild(produced);\n } else if (editorSpec && typeof editorSpec === 'object') {\n const placeholder = document.createElement('div');\n placeholder.setAttribute('data-external-editor', '');\n placeholder.setAttribute('data-field', column.field);\n editorHost.appendChild(placeholder);\n const context = { row: rowData, value, field: column.field, column, commit, cancel };\n if (editorSpec.mount) {\n try {\n editorSpec.mount({ placeholder, context, spec: editorSpec });\n } catch {\n /* empty */\n }\n } else {\n (grid as unknown as HTMLElement).dispatchEvent(\n new CustomEvent('mount-external-editor', { detail: { placeholder, spec: editorSpec, context } }),\n );\n }\n }\n}\n","/**\n * Sorting Module\n *\n * Handles column sorting state transitions and row ordering.\n */\n\nimport type { ColumnConfig, InternalGrid } from '../types';\nimport { renderHeader } from './header';\n\n/**\n * Cycle sort state for a column: none -> ascending -> descending -> none.\n * Restores original row order when clearing sort.\n */\nexport function toggleSort(grid: InternalGrid, col: ColumnConfig<any>): void {\n if (!grid._sortState || grid._sortState.field !== col.field) {\n if (!grid._sortState) grid.__originalOrder = grid._rows.slice();\n applySort(grid, col, 1);\n } else if (grid._sortState.direction === 1) {\n applySort(grid, col, -1);\n } else {\n grid._sortState = null;\n // Force full row rebuild after clearing sort so templated cells reflect original order\n grid.__rowRenderEpoch++;\n // Invalidate existing pooled row epochs so virtualization triggers a full inline rebuild\n grid._rowPool.forEach((r) => ((r as any).__epoch = -1));\n grid._rows = grid.__originalOrder.slice();\n renderHeader(grid);\n // After re-render ensure cleared column shows aria-sort=\"none\" baseline.\n const headers = grid._headerRowEl?.querySelectorAll('[role=\"columnheader\"].sortable');\n headers?.forEach((h: any) => {\n if (!h.getAttribute('aria-sort')) h.setAttribute('aria-sort', 'none');\n else if (h.getAttribute('aria-sort') === 'ascending' || h.getAttribute('aria-sort') === 'descending') {\n // The active column was re-rendered already, but normalize any missing ones.\n if (!grid._sortState) h.setAttribute('aria-sort', 'none');\n }\n });\n grid.refreshVirtualWindow(true);\n (grid as unknown as HTMLElement).dispatchEvent(\n new CustomEvent('sort-change', { detail: { field: col.field, direction: 0 } }),\n );\n // Trigger state change after sort is cleared\n grid.requestStateChange?.();\n }\n}\n\n/**\n * Apply a concrete sort direction to rows using either the column's custom comparator\n * or a default comparator aware of null/undefined ordering.\n */\nexport function applySort(grid: InternalGrid, col: ColumnConfig<any>, dir: 1 | -1): void {\n grid._sortState = { field: col.field, direction: dir };\n const comparator =\n (col as any).sortComparator ||\n ((a: any, b: any) => (a == null && b == null ? 0 : a == null ? -1 : b == null ? 1 : a > b ? 1 : a < b ? -1 : 0));\n grid._rows.sort((rA: any, rB: any) => comparator(rA[col.field], rB[col.field], rA, rB) * dir);\n // Bump epoch so renderVisibleRows triggers full inline rebuild (ensures templated / compiled view cells update)\n grid.__rowRenderEpoch++;\n // Invalidate pooled rows to guarantee rebuild even if epoch comparison logic changes\n grid._rowPool.forEach((r) => ((r as any).__epoch = -1));\n renderHeader(grid);\n grid.refreshVirtualWindow(true);\n (grid as unknown as HTMLElement).dispatchEvent(\n new CustomEvent('sort-change', { detail: { field: col.field, direction: dir } }),\n );\n // Trigger state change after sort applied\n grid.requestStateChange?.();\n}\n","/**\n * Header Rendering Module\n *\n * Handles rendering of the grid header row with sorting and resize affordances.\n */\n\nimport type { ColumnConfig, IconValue, InternalGrid } from '../types';\nimport { DEFAULT_GRID_ICONS } from '../types';\nimport { addPart } from './columns';\nimport { toggleSort } from './sorting';\n\n/**\n * Set an icon value on an element. Handles both string and HTMLElement icons.\n */\nfunction setIcon(element: HTMLElement, icon: IconValue): void {\n if (typeof icon === 'string') {\n element.textContent = icon;\n } else if (icon instanceof HTMLElement) {\n element.innerHTML = '';\n element.appendChild(icon.cloneNode(true));\n }\n}\n\n/**\n * Rebuild the header row DOM based on current column configuration, attaching\n * sorting and resize affordances where enabled.\n */\nexport function renderHeader(grid: InternalGrid): void {\n grid._headerRowEl = (grid.findHeaderRow! as any)();\n const headerRow = grid._headerRowEl as HTMLElement;\n headerRow.innerHTML = '';\n\n grid._visibleColumns.forEach((col: ColumnConfig<any>, i: number) => {\n const cell = document.createElement('div');\n cell.className = 'cell';\n addPart(cell, 'header-cell');\n cell.setAttribute('role', 'columnheader');\n\n // aria-colindex is 1-based\n cell.setAttribute('aria-colindex', String(i + 1));\n cell.setAttribute('data-field', col.field);\n cell.setAttribute('data-col', String(i)); // Add data-col for consistency with body cells\n\n // Column grouping styling is handled by the grouping-columns plugin via afterRender\n const maybeTpl = (col as any).__headerTemplate as HTMLElement | undefined;\n if (maybeTpl) Array.from(maybeTpl.childNodes).forEach((n) => cell.appendChild(n.cloneNode(true)));\n else {\n const label = (col as any).header || col.field;\n const span = document.createElement('span');\n span.textContent = label;\n cell.appendChild(span);\n }\n if (col.sortable) {\n cell.classList.add('sortable');\n cell.tabIndex = 0;\n const icon = document.createElement('span');\n addPart(icon as any, 'sort-indicator');\n icon.style.opacity = '0.6';\n const active = grid._sortState?.field === col.field ? grid._sortState.direction : 0;\n // Use grid-level icons (fall back to defaults)\n const icons = { ...DEFAULT_GRID_ICONS, ...grid.icons };\n const iconValue = active === 1 ? icons.sortAsc : active === -1 ? icons.sortDesc : icons.sortNone;\n setIcon(icon, iconValue);\n cell.appendChild(icon);\n // Always set a baseline aria-sort for sortable headers for assistive tech clarity.\n cell.setAttribute('aria-sort', active === 0 ? 'none' : active === 1 ? 'ascending' : 'descending');\n cell.addEventListener('click', (e) => {\n // Ignore clicks that are the result of a resize drag ending\n if (grid._resizeController?.isResizing) return;\n // Let plugins handle the click first (e.g., multi-sort)\n if (grid._dispatchHeaderClick?.(e, i, cell)) return;\n toggleSort(grid, col);\n });\n cell.addEventListener('keydown', (e) => {\n if (e.key === 'Enter' || e.key === ' ') {\n e.preventDefault();\n // Let plugins handle the keydown first\n if (grid._dispatchHeaderClick?.(e as unknown as MouseEvent, i, cell)) return;\n toggleSort(grid, col);\n }\n });\n }\n if (col.resizable) {\n // Set position: relative for the resize handle positioning context\n // Note: If a plugin applies position: sticky (e.g., PinnedColumnsPlugin), it will override this\n cell.style.position = 'relative';\n const handle = document.createElement('div');\n handle.className = 'resize-handle';\n handle.setAttribute('aria-hidden', 'true');\n handle.addEventListener('mousedown', (e: MouseEvent) => {\n e.stopPropagation();\n e.preventDefault();\n grid._resizeController.start(e, i, cell);\n });\n cell.appendChild(handle);\n }\n headerRow.appendChild(cell);\n });\n\n // Ensure every sortable header has a baseline aria-sort if not already set during construction.\n headerRow.querySelectorAll('.cell.sortable').forEach((el) => {\n if (!el.getAttribute('aria-sort')) el.setAttribute('aria-sort', 'none');\n });\n\n // Set ARIA role only if header has children (role=\"row\" requires columnheader children)\n // When grid is cleared with 0 columns, the header row should not have role=\"row\"\n if (headerRow.children.length > 0) {\n headerRow.setAttribute('role', 'row');\n headerRow.setAttribute('aria-rowindex', '1');\n } else {\n headerRow.removeAttribute('role');\n headerRow.removeAttribute('aria-rowindex');\n }\n}\n","/** Controller interface for column resize interactions (local minimal typing). */\nimport type { InternalGrid } from '../types';\n\ninterface ResizeController {\n start: (e: MouseEvent, colIndex: number, cell: HTMLElement) => void;\n dispose: () => void;\n /** True while a resize drag is in progress (used to suppress header click/sort). */\n isResizing: boolean;\n}\n\nexport function createResizeController(grid: InternalGrid): ResizeController {\n let resizeState: { startX: number; colIndex: number; startWidth: number } | null = null;\n let pendingRaf: number | null = null;\n let prevCursor: string | null = null;\n let prevUserSelect: string | null = null;\n const onMove = (e: MouseEvent) => {\n if (!resizeState) return;\n const delta = e.clientX - resizeState.startX;\n const width = Math.max(40, resizeState.startWidth + delta);\n const col = grid._visibleColumns[resizeState.colIndex];\n col.width = width;\n col.__userResized = true;\n col.__renderedWidth = width;\n if (pendingRaf == null) {\n pendingRaf = requestAnimationFrame(() => {\n pendingRaf = null;\n grid.updateTemplate?.();\n });\n }\n (grid as unknown as HTMLElement).dispatchEvent(\n new CustomEvent('column-resize', { detail: { field: col.field, width } }),\n );\n };\n let justFinishedResize = false;\n const onUp = () => {\n const hadResize = resizeState !== null;\n // Set flag to suppress click events that fire immediately after mouseup\n if (hadResize) {\n justFinishedResize = true;\n requestAnimationFrame(() => {\n justFinishedResize = false;\n });\n }\n window.removeEventListener('mousemove', onMove);\n window.removeEventListener('mouseup', onUp);\n if (prevCursor !== null) {\n document.documentElement.style.cursor = prevCursor;\n prevCursor = null;\n }\n if (prevUserSelect !== null) {\n document.body.style.userSelect = prevUserSelect;\n prevUserSelect = null;\n }\n resizeState = null;\n // Trigger state change after resize completes\n if (hadResize && grid.requestStateChange) {\n grid.requestStateChange();\n }\n };\n return {\n get isResizing() {\n return resizeState !== null || justFinishedResize;\n },\n start(e, colIndex, cell) {\n e.preventDefault();\n const rect = cell.getBoundingClientRect();\n resizeState = { startX: e.clientX, colIndex, startWidth: rect.width };\n window.addEventListener('mousemove', onMove);\n window.addEventListener('mouseup', onUp);\n if (prevCursor === null) prevCursor = document.documentElement.style.cursor;\n document.documentElement.style.cursor = 'e-resize';\n if (prevUserSelect === null) prevUserSelect = document.body.style.userSelect;\n document.body.style.userSelect = 'none';\n },\n dispose() {\n onUp();\n },\n };\n}\n","/**\n * Shell infrastructure for grid header bar and tool panels.\n *\n * The shell is an optional wrapper layer that provides:\n * - Header bar with title, plugin content, and toolbar buttons\n * - Tool panels that plugins can register content into\n * - Light DOM parsing for framework-friendly configuration\n */\n\nimport type {\n HeaderContentDefinition,\n IconValue,\n ShellConfig,\n ToolbarButtonConfig,\n ToolbarButtonInfo,\n ToolPanelDefinition,\n} from '../types';\nimport { DEFAULT_GRID_ICONS } from '../types';\n\n/**\n * Convert an IconValue to a string for rendering in HTML.\n */\nfunction iconToString(icon: IconValue | undefined): string {\n if (!icon) return '';\n if (typeof icon === 'string') return icon;\n // For HTMLElement, get the outerHTML\n return icon.outerHTML;\n}\n\n/**\n * State for managing shell UI.\n */\nexport interface ShellState {\n /** Registered tool panels (from plugins + consumer API) */\n toolPanels: Map<string, ToolPanelDefinition>;\n /** Registered header content (from plugins + consumer API) */\n headerContents: Map<string, HeaderContentDefinition>;\n /** Custom toolbar buttons registered via API */\n toolbarButtons: Map<string, ToolbarButtonConfig>;\n /** Light DOM toolbar buttons */\n lightDomButtons: HTMLElement[];\n /** Light DOM header content elements */\n lightDomHeaderContent: HTMLElement[];\n /** Whether the tool panel sidebar is open */\n isPanelOpen: boolean;\n /** Which accordion sections are expanded (by panel ID) */\n expandedSections: Set<string>;\n /** Cleanup functions for header content render returns */\n headerContentCleanups: Map<string, () => void>;\n /** Cleanup functions for each panel section's render return */\n panelCleanups: Map<string, () => void>;\n /** Cleanup functions for toolbar button render returns */\n toolbarButtonCleanups: Map<string, () => void>;\n /** @deprecated Use isPanelOpen instead. Kept for backward compatibility. */\n activePanel: string | null;\n /** @deprecated Use panelCleanups instead. Kept for backward compatibility. */\n activePanelCleanup: (() => void) | null;\n}\n\n/**\n * Create initial shell state.\n */\nexport function createShellState(): ShellState {\n return {\n toolPanels: new Map(),\n headerContents: new Map(),\n toolbarButtons: new Map(),\n lightDomButtons: [],\n lightDomHeaderContent: [],\n isPanelOpen: false,\n expandedSections: new Set(),\n headerContentCleanups: new Map(),\n panelCleanups: new Map(),\n toolbarButtonCleanups: new Map(),\n // Deprecated - kept for backward compatibility\n activePanel: null,\n activePanelCleanup: null,\n };\n}\n\n/**\n * Determine if shell header should be rendered.\n */\nexport function shouldRenderShellHeader(config: ShellConfig | undefined, state: ShellState): boolean {\n // Check if title is configured\n if (config?.header?.title) return true;\n\n // Check if config has toolbar buttons\n if (config?.header?.toolbarButtons?.length) return true;\n\n // Check if any tool panels are registered (need toolbar buttons for them)\n if (state.toolPanels.size > 0) return true;\n\n // Check if any header content is registered\n if (state.headerContents.size > 0) return true;\n\n // Check if any API toolbar buttons registered\n if (state.toolbarButtons.size > 0) return true;\n\n // Check if light DOM has header elements\n if (state.lightDomButtons.length > 0 || state.lightDomHeaderContent.length > 0) return true;\n\n return false;\n}\n\n/**\n * Render the shell header HTML.\n * @param toolPanelIcon - Icon for the tool panel toggle (from grid icon config)\n */\nexport function renderShellHeader(\n config: ShellConfig | undefined,\n state: ShellState,\n toolPanelIcon: IconValue = '☰',\n): string {\n const title = config?.header?.title ?? '';\n const hasTitle = !!title;\n const iconStr = iconToString(toolPanelIcon);\n\n // Collect all toolbar buttons in order\n // 1. Config buttons (sorted by order)\n // 2. API-registered buttons (sorted by order)\n // 3. Light DOM buttons via slot\n // 4. Single panel toggle button (if any panels registered)\n\n const configButtons = config?.header?.toolbarButtons ?? [];\n const hasConfigButtons = configButtons.length > 0;\n const hasApiButtons = state.toolbarButtons.size > 0;\n const hasLightDomButtons = state.lightDomButtons.length > 0;\n const hasPanels = state.toolPanels.size > 0;\n const hasCustomButtons = hasConfigButtons || hasApiButtons || hasLightDomButtons;\n const showSeparator = hasCustomButtons && hasPanels;\n\n // Sort config buttons by order\n const sortedConfigButtons = [...configButtons].sort((a, b) => (a.order ?? 100) - (b.order ?? 100));\n\n // Sort API buttons by order\n const sortedApiButtons = [...state.toolbarButtons.values()].sort((a, b) => (a.order ?? 100) - (b.order ?? 100));\n\n // Build toolbar HTML\n let toolbarHtml = '';\n\n // Config buttons with icon/action (grid renders these)\n for (const btn of sortedConfigButtons) {\n if (btn.icon && btn.action) {\n toolbarHtml += `<button class=\"tbw-toolbar-btn\" data-btn=\"${btn.id}\" title=\"${btn.label}\" aria-label=\"${\n btn.label\n }\"${btn.disabled ? ' disabled' : ''}>${btn.icon}</button>`;\n }\n }\n\n // API buttons with icon/action\n for (const btn of sortedApiButtons) {\n if (btn.icon && btn.action) {\n toolbarHtml += `<button class=\"tbw-toolbar-btn\" data-btn=\"${btn.id}\" title=\"${btn.label}\" aria-label=\"${\n btn.label\n }\"${btn.disabled ? ' disabled' : ''}>${btn.icon}</button>`;\n }\n }\n\n // Placeholders for config/API buttons with element or render function\n for (const btn of sortedConfigButtons) {\n if (btn.element || btn.render) {\n toolbarHtml += `<div class=\"tbw-toolbar-btn-slot\" data-btn-slot=\"${btn.id}\"></div>`;\n }\n }\n for (const btn of sortedApiButtons) {\n if (btn.element || btn.render) {\n toolbarHtml += `<div class=\"tbw-toolbar-btn-slot\" data-btn-slot=\"${btn.id}\"></div>`;\n }\n }\n\n // Light DOM slot\n if (hasLightDomButtons) {\n toolbarHtml += '<slot name=\"toolbar\"></slot>';\n }\n\n // Separator\n if (showSeparator) {\n toolbarHtml += '<div class=\"tbw-toolbar-separator\"></div>';\n }\n\n // Single panel toggle button (opens accordion-style sidebar with all panels)\n if (hasPanels) {\n const isOpen = state.isPanelOpen;\n toolbarHtml += `<button class=\"tbw-toolbar-btn${isOpen ? ' active' : ''}\" data-panel-toggle title=\"Settings\" aria-label=\"Toggle settings panel\" aria-pressed=\"${isOpen}\" aria-controls=\"tbw-tool-panel\">${iconStr}</button>`;\n }\n\n return `\n <div class=\"tbw-shell-header\" part=\"shell-header\" role=\"presentation\">\n ${hasTitle ? `<div class=\"tbw-shell-title\">${title}</div>` : ''}\n <div class=\"tbw-shell-content\" part=\"shell-content\" role=\"presentation\">\n <slot name=\"header-content\"></slot>\n </div>\n <div class=\"tbw-shell-toolbar\" part=\"shell-toolbar\" role=\"presentation\">\n ${toolbarHtml}\n </div>\n </div>\n `;\n}\n\n/**\n * Render the shell body wrapper HTML (contains grid content + accordion-style tool panel).\n * @param icons - Optional icons for expand/collapse chevrons (from grid config)\n */\nexport function renderShellBody(\n config: ShellConfig | undefined,\n state: ShellState,\n gridContentHtml: string,\n icons?: { expand?: IconValue; collapse?: IconValue },\n): string {\n const position = config?.toolPanel?.position ?? 'right';\n const hasPanel = state.toolPanels.size > 0;\n const isOpen = state.isPanelOpen;\n const expandIcon = iconToString(icons?.expand ?? DEFAULT_GRID_ICONS.expand);\n const collapseIcon = iconToString(icons?.collapse ?? DEFAULT_GRID_ICONS.collapse);\n\n // Sort panels by order for accordion sections\n const sortedPanels = [...state.toolPanels.values()].sort((a, b) => (a.order ?? 100) - (b.order ?? 100));\n const isSinglePanel = sortedPanels.length === 1;\n\n // Build accordion sections HTML\n let accordionHtml = '';\n for (const panel of sortedPanels) {\n const isExpanded = state.expandedSections.has(panel.id);\n const iconHtml = panel.icon ? `<span class=\"tbw-accordion-icon\">${panel.icon}</span>` : '';\n // Hide chevron for single panel (no toggling needed)\n const chevronHtml = isSinglePanel\n ? ''\n : `<span class=\"tbw-accordion-chevron\">${isExpanded ? collapseIcon : expandIcon}</span>`;\n // Disable accordion toggle for single panel\n const sectionClasses = `tbw-accordion-section${isExpanded ? ' expanded' : ''}${isSinglePanel ? ' single' : ''}`;\n accordionHtml += `\n <div class=\"${sectionClasses}\" data-section=\"${panel.id}\">\n <button class=\"tbw-accordion-header\" aria-expanded=\"${isExpanded}\" aria-controls=\"tbw-section-${panel.id}\"${isSinglePanel ? ' aria-disabled=\"true\"' : ''}>\n ${iconHtml}\n <span class=\"tbw-accordion-title\">${panel.title}</span>\n ${chevronHtml}\n </button>\n <div class=\"tbw-accordion-content\" id=\"tbw-section-${panel.id}\" role=\"presentation\"></div>\n </div>\n `;\n }\n\n // Resize handle position depends on panel position\n const resizeHandlePosition = position === 'left' ? 'right' : 'left';\n\n const panelHtml = hasPanel\n ? `\n <aside class=\"tbw-tool-panel${isOpen ? ' open' : ''}\" part=\"tool-panel\" data-position=\"${position}\" role=\"presentation\" id=\"tbw-tool-panel\">\n <div class=\"tbw-tool-panel-resize\" data-resize-handle data-handle-position=\"${resizeHandlePosition}\" aria-hidden=\"true\"></div>\n <div class=\"tbw-tool-panel-content\" role=\"presentation\">\n <div class=\"tbw-accordion\">\n ${accordionHtml}\n </div>\n </div>\n </aside>\n `\n : '';\n\n // For left position, panel comes before content in DOM order\n if (position === 'left') {\n return `\n <div class=\"tbw-shell-body\">\n ${panelHtml}\n <div class=\"tbw-grid-content\">\n ${gridContentHtml}\n </div>\n </div>\n `;\n }\n\n return `\n <div class=\"tbw-shell-body\">\n <div class=\"tbw-grid-content\">\n ${gridContentHtml}\n </div>\n ${panelHtml}\n </div>\n `;\n}\n\n/**\n * Parse light DOM shell elements (tbw-grid-header, etc.).\n */\nexport function parseLightDomShell(host: HTMLElement, state: ShellState): void {\n const headerEl = host.querySelector('tbw-grid-header');\n if (!headerEl) return;\n\n // Hide the light DOM container\n (headerEl as HTMLElement).style.display = 'none';\n\n // Parse header content elements\n const headerContents = headerEl.querySelectorAll('tbw-grid-header-content');\n state.lightDomHeaderContent = Array.from(headerContents) as HTMLElement[];\n\n // Assign slot names for slotting into shadow DOM\n state.lightDomHeaderContent.forEach((el) => {\n el.setAttribute('slot', 'header-content');\n });\n\n // Parse toolbar button elements\n const toolButtons = headerEl.querySelectorAll('tbw-grid-tool-button');\n state.lightDomButtons = Array.from(toolButtons) as HTMLElement[];\n\n // Sort by order attribute and assign slots\n state.lightDomButtons.sort((a, b) => {\n const orderA = parseInt(a.getAttribute('order') ?? '100', 10);\n const orderB = parseInt(b.getAttribute('order') ?? '100', 10);\n return orderA - orderB;\n });\n\n state.lightDomButtons.forEach((el) => {\n el.setAttribute('slot', 'toolbar');\n });\n}\n\n/**\n * Set up event listeners for shell toolbar buttons and accordion.\n */\nexport function setupShellEventListeners(\n shadowRoot: ShadowRoot,\n config: ShellConfig | undefined,\n state: ShellState,\n callbacks: {\n onPanelToggle: () => void;\n onSectionToggle: (sectionId: string) => void;\n onToolbarButtonClick: (buttonId: string) => void;\n },\n): void {\n const toolbar = shadowRoot.querySelector('.tbw-shell-toolbar');\n if (toolbar) {\n toolbar.addEventListener('click', (e) => {\n const target = e.target as HTMLElement;\n\n // Handle single panel toggle button\n const panelToggle = target.closest('[data-panel-toggle]') as HTMLElement | null;\n if (panelToggle) {\n callbacks.onPanelToggle();\n return;\n }\n\n // Handle custom toolbar buttons\n const customBtn = target.closest('[data-btn]') as HTMLElement | null;\n if (customBtn) {\n const btnId = customBtn.getAttribute('data-btn');\n if (btnId) {\n callbacks.onToolbarButtonClick(btnId);\n }\n }\n });\n }\n\n // Accordion header clicks\n const accordion = shadowRoot.querySelector('.tbw-accordion');\n if (accordion) {\n accordion.addEventListener('click', (e) => {\n const target = e.target as HTMLElement;\n const header = target.closest('.tbw-accordion-header') as HTMLElement | null;\n if (header) {\n const section = header.closest('[data-section]') as HTMLElement | null;\n const sectionId = section?.getAttribute('data-section');\n if (sectionId) {\n callbacks.onSectionToggle(sectionId);\n }\n }\n });\n }\n}\n\n/**\n * Set up resize handle for tool panel.\n * Returns a cleanup function to remove event listeners.\n */\nexport function setupToolPanelResize(\n shadowRoot: ShadowRoot,\n config: ShellConfig | undefined,\n onResize: (width: number) => void,\n): () => void {\n const panel = shadowRoot.querySelector('.tbw-tool-panel') as HTMLElement | null;\n const handle = shadowRoot.querySelector('[data-resize-handle]') as HTMLElement | null;\n const shellBody = shadowRoot.querySelector('.tbw-shell-body') as HTMLElement | null;\n if (!panel || !handle || !shellBody) {\n // eslint-disable-next-line @typescript-eslint/no-empty-function\n return () => {};\n }\n\n const position = config?.toolPanel?.position ?? 'right';\n const minWidth = 200;\n\n let startX = 0;\n let startWidth = 0;\n let maxWidth = 0;\n let isResizing = false;\n\n const onMouseMove = (e: MouseEvent) => {\n if (!isResizing) return;\n e.preventDefault();\n\n // For right-positioned panel: dragging left (negative clientX change) should expand\n // For left-positioned panel: dragging right (positive clientX change) should expand\n const delta = position === 'left' ? e.clientX - startX : startX - e.clientX;\n const newWidth = Math.min(maxWidth, Math.max(minWidth, startWidth + delta));\n\n panel.style.width = `${newWidth}px`;\n };\n\n const onMouseUp = () => {\n if (!isResizing) return;\n isResizing = false;\n handle.classList.remove('resizing');\n panel.style.transition = ''; // Re-enable transition\n document.body.style.cursor = '';\n document.body.style.userSelect = '';\n\n // Get final width and notify\n const finalWidth = panel.getBoundingClientRect().width;\n onResize(finalWidth);\n\n document.removeEventListener('mousemove', onMouseMove);\n document.removeEventListener('mouseup', onMouseUp);\n };\n\n const onMouseDown = (e: MouseEvent) => {\n e.preventDefault();\n isResizing = true;\n startX = e.clientX;\n startWidth = panel.getBoundingClientRect().width;\n // Calculate max width dynamically based on grid container width\n maxWidth = shellBody.getBoundingClientRect().width - 20; // Leave 20px margin\n handle.classList.add('resizing');\n panel.style.transition = 'none'; // Disable transition for smooth resize\n document.body.style.cursor = 'col-resize';\n document.body.style.userSelect = 'none';\n\n document.addEventListener('mousemove', onMouseMove);\n document.addEventListener('mouseup', onMouseUp);\n };\n\n handle.addEventListener('mousedown', onMouseDown);\n\n // Return cleanup function\n return () => {\n handle.removeEventListener('mousedown', onMouseDown);\n document.removeEventListener('mousemove', onMouseMove);\n document.removeEventListener('mouseup', onMouseUp);\n };\n}\n\n/**\n * Render custom button elements/render functions into toolbar slots.\n */\nexport function renderCustomToolbarButtons(\n shadowRoot: ShadowRoot,\n config: ShellConfig | undefined,\n state: ShellState,\n): void {\n const allButtons = [...(config?.header?.toolbarButtons ?? []), ...state.toolbarButtons.values()];\n\n for (const btn of allButtons) {\n const slot = shadowRoot.querySelector(`[data-btn-slot=\"${btn.id}\"]`);\n if (!slot) continue;\n\n // Clean up previous render if any\n const existingCleanup = state.toolbarButtonCleanups.get(btn.id);\n if (existingCleanup) {\n existingCleanup();\n state.toolbarButtonCleanups.delete(btn.id);\n }\n\n if (btn.element) {\n slot.appendChild(btn.element);\n } else if (btn.render) {\n const cleanup = btn.render(slot as HTMLElement);\n if (cleanup) {\n state.toolbarButtonCleanups.set(btn.id, cleanup);\n }\n }\n }\n}\n\n/**\n * Render header content from plugins into the shell content area.\n */\nexport function renderHeaderContent(shadowRoot: ShadowRoot, state: ShellState): void {\n const contentArea = shadowRoot.querySelector('.tbw-shell-content');\n if (!contentArea) return;\n\n // Sort by order\n const sortedContents = [...state.headerContents.values()].sort((a, b) => (a.order ?? 100) - (b.order ?? 100));\n\n // Create containers for each content piece (before the slot)\n const slot = contentArea.querySelector('slot[name=\"header-content\"]');\n\n for (const content of sortedContents) {\n // Clean up previous render if any\n const existingCleanup = state.headerContentCleanups.get(content.id);\n if (existingCleanup) {\n existingCleanup();\n state.headerContentCleanups.delete(content.id);\n }\n\n // Check if container already exists\n let container = contentArea.querySelector(`[data-header-content=\"${content.id}\"]`) as HTMLElement | null;\n if (!container) {\n container = document.createElement('div');\n container.setAttribute('data-header-content', content.id);\n // Insert before the slot\n if (slot) {\n contentArea.insertBefore(container, slot);\n } else {\n contentArea.appendChild(container);\n }\n }\n\n const cleanup = content.render(container);\n if (cleanup) {\n state.headerContentCleanups.set(content.id, cleanup);\n }\n }\n}\n\n/**\n * Render content for expanded accordion sections.\n * @param icons - Optional icons for expand/collapse chevrons (from grid config)\n */\nexport function renderPanelContent(\n shadowRoot: ShadowRoot,\n state: ShellState,\n icons?: { expand?: IconValue; collapse?: IconValue },\n): void {\n if (!state.isPanelOpen) return;\n\n const expandIcon = iconToString(icons?.expand ?? DEFAULT_GRID_ICONS.expand);\n const collapseIcon = iconToString(icons?.collapse ?? DEFAULT_GRID_ICONS.collapse);\n\n for (const [panelId, panel] of state.toolPanels) {\n const isExpanded = state.expandedSections.has(panelId);\n const section = shadowRoot.querySelector(`[data-section=\"${panelId}\"]`);\n const contentArea = section?.querySelector('.tbw-accordion-content') as HTMLElement | null;\n\n if (!section || !contentArea) continue;\n\n // Update expanded state\n section.classList.toggle('expanded', isExpanded);\n const header = section.querySelector('.tbw-accordion-header');\n if (header) {\n header.setAttribute('aria-expanded', String(isExpanded));\n }\n const chevron = section.querySelector('.tbw-accordion-chevron');\n if (chevron) {\n chevron.innerHTML = isExpanded ? collapseIcon : expandIcon;\n }\n\n if (isExpanded) {\n // Check if content is already rendered\n if (contentArea.children.length === 0) {\n // Render panel content\n const cleanup = panel.render(contentArea);\n if (cleanup) {\n state.panelCleanups.set(panelId, cleanup);\n }\n }\n } else {\n // Clean up and clear content when collapsed\n const cleanup = state.panelCleanups.get(panelId);\n if (cleanup) {\n cleanup();\n state.panelCleanups.delete(panelId);\n }\n contentArea.innerHTML = '';\n }\n }\n}\n\n/**\n * Update toolbar button active states.\n */\nexport function updateToolbarActiveStates(shadowRoot: ShadowRoot, state: ShellState): void {\n // Update single panel toggle button\n const panelToggle = shadowRoot.querySelector('[data-panel-toggle]');\n if (panelToggle) {\n panelToggle.classList.toggle('active', state.isPanelOpen);\n panelToggle.setAttribute('aria-pressed', String(state.isPanelOpen));\n }\n}\n\n/**\n * Update tool panel open/close state.\n */\nexport function updatePanelState(shadowRoot: ShadowRoot, state: ShellState): void {\n const panel = shadowRoot.querySelector('.tbw-tool-panel') as HTMLElement | null;\n if (!panel) return;\n\n panel.classList.toggle('open', state.isPanelOpen);\n\n // Clear inline width when closing (resize sets inline style that overrides CSS)\n if (!state.isPanelOpen) {\n panel.style.width = '';\n }\n}\n\n/**\n * Get all toolbar button info.\n */\nexport function getToolbarButtonsInfo(config: ShellConfig | undefined, state: ShellState): ToolbarButtonInfo[] {\n const result: ToolbarButtonInfo[] = [];\n\n // Config buttons\n for (const btn of config?.header?.toolbarButtons ?? []) {\n result.push({\n id: btn.id,\n label: btn.label,\n disabled: btn.disabled ?? false,\n source: 'config',\n });\n }\n\n // API buttons\n for (const btn of state.toolbarButtons.values()) {\n result.push({\n id: btn.id,\n label: btn.label,\n disabled: btn.disabled ?? false,\n source: 'config',\n });\n }\n\n // Light DOM buttons (limited info since user provides DOM)\n for (let i = 0; i < state.lightDomButtons.length; i++) {\n const el = state.lightDomButtons[i];\n const btn = el.querySelector('button');\n result.push({\n id: `light-dom-${i}`,\n label: btn?.getAttribute('title') ?? btn?.getAttribute('aria-label') ?? '',\n disabled: btn?.disabled ?? false,\n source: 'light-dom',\n });\n }\n\n // Panel toggles\n for (const panel of state.toolPanels.values()) {\n result.push({\n id: `panel-toggle-${panel.id}`,\n label: panel.tooltip ?? panel.title,\n disabled: false,\n source: 'panel-toggle',\n panelId: panel.id,\n });\n }\n\n return result;\n}\n\n/**\n * Cleanup all shell state when grid disconnects.\n */\nexport function cleanupShellState(state: ShellState): void {\n // Clean up header content\n for (const cleanup of state.headerContentCleanups.values()) {\n cleanup();\n }\n state.headerContentCleanups.clear();\n\n // Clean up active panel\n if (state.activePanelCleanup) {\n state.activePanelCleanup();\n state.activePanelCleanup = null;\n }\n\n // Clean up toolbar buttons\n for (const cleanup of state.toolbarButtonCleanups.values()) {\n cleanup();\n }\n state.toolbarButtonCleanups.clear();\n\n // Invoke panel onClose if open\n if (state.activePanel) {\n const panel = state.toolPanels.get(state.activePanel);\n panel?.onClose?.();\n }\n\n // Clear registrations\n state.toolPanels.clear();\n state.headerContents.clear();\n state.toolbarButtons.clear();\n state.lightDomButtons = [];\n state.lightDomHeaderContent = [];\n state.activePanel = null;\n}\n\n// ============================================================================\n// ShellController - Encapsulates tool panel orchestration logic\n// ============================================================================\n\n/**\n * Callbacks for ShellController to communicate with the grid.\n * This interface decouples the controller from grid internals.\n */\nexport interface ShellControllerCallbacks {\n /** Get the shadow root for DOM queries */\n getShadow: () => ShadowRoot;\n /** Get the current shell config */\n getShellConfig: () => ShellConfig | undefined;\n /** Get accordion expand/collapse icons */\n getAccordionIcons: () => { expand: IconValue; collapse: IconValue };\n /** Emit an event from the grid */\n emit: (eventName: string, detail: unknown) => void;\n /** Refresh the shell header (re-parse light DOM and re-render) */\n refreshShellHeader: () => void;\n}\n\n/**\n * Controller interface for managing shell/tool panel behavior.\n */\nexport interface ShellController {\n /** Whether the shell has been initialized */\n readonly isInitialized: boolean;\n /** Set the initialized state */\n setInitialized(value: boolean): void;\n /** Whether the tool panel is currently open */\n readonly isPanelOpen: boolean;\n /** Get the currently active panel ID (deprecated) */\n readonly activePanel: string | null;\n /** Get IDs of expanded accordion sections */\n readonly expandedSections: string[];\n /** Open the tool panel */\n openToolPanel(): void;\n /** Close the tool panel */\n closeToolPanel(): void;\n /** Toggle the tool panel */\n toggleToolPanel(): void;\n /** Toggle an accordion section */\n toggleToolPanelSection(sectionId: string): void;\n /** Get registered tool panels */\n getToolPanels(): ToolPanelDefinition[];\n /** Register a tool panel */\n registerToolPanel(panel: ToolPanelDefinition): void;\n /** Unregister a tool panel */\n unregisterToolPanel(panelId: string): void;\n /** Get registered header contents */\n getHeaderContents(): HeaderContentDefinition[];\n /** Register header content */\n registerHeaderContent(content: HeaderContentDefinition): void;\n /** Unregister header content */\n unregisterHeaderContent(contentId: string): void;\n /** Get all toolbar buttons info */\n getToolbarButtons(): ToolbarButtonInfo[];\n /** Register a toolbar button */\n registerToolbarButton(button: ToolbarButtonConfig): void;\n /** Unregister a toolbar button */\n unregisterToolbarButton(buttonId: string): void;\n /** Enable/disable a toolbar button */\n setToolbarButtonDisabled(buttonId: string, disabled: boolean): void;\n}\n\n/**\n * Create a ShellController instance.\n * The controller encapsulates all tool panel orchestration logic.\n */\nexport function createShellController(state: ShellState, callbacks: ShellControllerCallbacks): ShellController {\n let initialized = false;\n\n const controller: ShellController = {\n get isInitialized() {\n return initialized;\n },\n setInitialized(value: boolean) {\n initialized = value;\n },\n\n get isPanelOpen() {\n return state.isPanelOpen;\n },\n\n get activePanel() {\n // For backward compatibility, return first expanded section if panel is open\n if (state.isPanelOpen && state.expandedSections.size > 0) {\n return [...state.expandedSections][0];\n }\n return null;\n },\n\n get expandedSections() {\n return [...state.expandedSections];\n },\n\n openToolPanel() {\n if (state.isPanelOpen) return;\n if (state.toolPanels.size === 0) {\n console.warn('[tbw-grid] No tool panels registered');\n return;\n }\n\n state.isPanelOpen = true;\n\n // Auto-expand first section if none expanded\n if (state.expandedSections.size === 0 && state.toolPanels.size > 0) {\n const sortedPanels = [...state.toolPanels.values()].sort((a, b) => (a.order ?? 100) - (b.order ?? 100));\n const firstPanel = sortedPanels[0];\n if (firstPanel) {\n state.expandedSections.add(firstPanel.id);\n }\n }\n\n // Update UI\n const shadow = callbacks.getShadow();\n updateToolbarActiveStates(shadow, state);\n updatePanelState(shadow, state);\n\n // Render accordion sections\n renderPanelContent(shadow, state, callbacks.getAccordionIcons());\n\n // Emit event\n callbacks.emit('tool-panel-open', { sections: controller.expandedSections });\n },\n\n closeToolPanel() {\n if (!state.isPanelOpen) return;\n\n // Clean up all panel content\n for (const cleanup of state.panelCleanups.values()) {\n cleanup();\n }\n state.panelCleanups.clear();\n\n // Legacy cleanup\n if (state.activePanelCleanup) {\n state.activePanelCleanup();\n state.activePanelCleanup = null;\n }\n\n // Call onClose for all panels\n for (const panel of state.toolPanels.values()) {\n panel.onClose?.();\n }\n\n state.isPanelOpen = false;\n\n // Update UI\n const shadow = callbacks.getShadow();\n updateToolbarActiveStates(shadow, state);\n updatePanelState(shadow, state);\n\n // Emit event\n callbacks.emit('tool-panel-close', {});\n },\n\n toggleToolPanel() {\n if (state.isPanelOpen) {\n controller.closeToolPanel();\n } else {\n controller.openToolPanel();\n }\n },\n\n toggleToolPanelSection(sectionId: string) {\n const panel = state.toolPanels.get(sectionId);\n if (!panel) {\n console.warn(`[tbw-grid] Tool panel section \"${sectionId}\" not found`);\n return;\n }\n\n // Don't allow toggling when there's only one panel (it should stay expanded)\n if (state.toolPanels.size === 1) {\n return;\n }\n\n const shadow = callbacks.getShadow();\n const isExpanded = state.expandedSections.has(sectionId);\n\n if (isExpanded) {\n // Collapsing current section\n const cleanup = state.panelCleanups.get(sectionId);\n if (cleanup) {\n cleanup();\n state.panelCleanups.delete(sectionId);\n }\n panel.onClose?.();\n state.expandedSections.delete(sectionId);\n updateAccordionSectionState(shadow, sectionId, false);\n } else {\n // Expanding - first collapse all others (exclusive accordion)\n for (const [otherId, otherPanel] of state.toolPanels) {\n if (otherId !== sectionId && state.expandedSections.has(otherId)) {\n const cleanup = state.panelCleanups.get(otherId);\n if (cleanup) {\n cleanup();\n state.panelCleanups.delete(otherId);\n }\n otherPanel.onClose?.();\n state.expandedSections.delete(otherId);\n updateAccordionSectionState(shadow, otherId, false);\n // Clear content of collapsed section\n const contentEl = shadow.querySelector(`[data-section=\"${otherId}\"] .tbw-accordion-content`);\n if (contentEl) contentEl.innerHTML = '';\n }\n }\n // Now expand the target section\n state.expandedSections.add(sectionId);\n updateAccordionSectionState(shadow, sectionId, true);\n renderAccordionSectionContent(shadow, state, sectionId);\n }\n\n // Emit event\n callbacks.emit('tool-panel-section-toggle', { id: sectionId, expanded: !isExpanded });\n },\n\n getToolPanels() {\n return [...state.toolPanels.values()];\n },\n\n registerToolPanel(panel: ToolPanelDefinition) {\n if (state.toolPanels.has(panel.id)) {\n console.warn(`[tbw-grid] Tool panel \"${panel.id}\" already registered`);\n return;\n }\n state.toolPanels.set(panel.id, panel);\n\n if (initialized) {\n callbacks.refreshShellHeader();\n }\n },\n\n unregisterToolPanel(panelId: string) {\n // Close panel if open and this section is expanded\n if (state.expandedSections.has(panelId)) {\n const cleanup = state.panelCleanups.get(panelId);\n if (cleanup) {\n cleanup();\n state.panelCleanups.delete(panelId);\n }\n state.expandedSections.delete(panelId);\n }\n\n state.toolPanels.delete(panelId);\n\n if (initialized) {\n callbacks.refreshShellHeader();\n }\n },\n\n getHeaderContents() {\n return [...state.headerContents.values()];\n },\n\n registerHeaderContent(content: HeaderContentDefinition) {\n if (state.headerContents.has(content.id)) {\n console.warn(`[tbw-grid] Header content \"${content.id}\" already registered`);\n return;\n }\n state.headerContents.set(content.id, content);\n\n if (initialized) {\n renderHeaderContent(callbacks.getShadow(), state);\n }\n },\n\n unregisterHeaderContent(contentId: string) {\n // Clean up\n const cleanup = state.headerContentCleanups.get(contentId);\n if (cleanup) {\n cleanup();\n state.headerContentCleanups.delete(contentId);\n }\n\n // Call onDestroy\n const content = state.headerContents.get(contentId);\n content?.onDestroy?.();\n\n state.headerContents.delete(contentId);\n\n // Remove DOM element\n const el = callbacks.getShadow().querySelector(`[data-header-content=\"${contentId}\"]`);\n el?.remove();\n },\n\n getToolbarButtons() {\n return getToolbarButtonsInfo(callbacks.getShellConfig(), state);\n },\n\n registerToolbarButton(button: ToolbarButtonConfig) {\n if (state.toolbarButtons.has(button.id)) {\n console.warn(`[tbw-grid] Toolbar button \"${button.id}\" already registered`);\n return;\n }\n state.toolbarButtons.set(button.id, button);\n\n if (initialized) {\n callbacks.refreshShellHeader();\n }\n },\n\n unregisterToolbarButton(buttonId: string) {\n // Clean up\n const cleanup = state.toolbarButtonCleanups.get(buttonId);\n if (cleanup) {\n cleanup();\n state.toolbarButtonCleanups.delete(buttonId);\n }\n\n state.toolbarButtons.delete(buttonId);\n\n if (initialized) {\n callbacks.refreshShellHeader();\n }\n },\n\n setToolbarButtonDisabled(buttonId: string, disabled: boolean) {\n // Check API-registered buttons\n const apiBtn = state.toolbarButtons.get(buttonId);\n if (apiBtn) {\n apiBtn.disabled = disabled;\n }\n\n // Update DOM\n const btn = callbacks.getShadow().querySelector(`[data-btn=\"${buttonId}\"]`) as HTMLButtonElement | null;\n if (btn) {\n btn.disabled = disabled;\n }\n },\n };\n\n return controller;\n}\n\n/**\n * Update accordion section visual state.\n */\nfunction updateAccordionSectionState(shadow: ShadowRoot, sectionId: string, expanded: boolean): void {\n const section = shadow.querySelector(`[data-section=\"${sectionId}\"]`);\n if (section) {\n section.classList.toggle('expanded', expanded);\n }\n}\n\n/**\n * Render content for a single accordion section.\n */\nfunction renderAccordionSectionContent(shadow: ShadowRoot, state: ShellState, sectionId: string): void {\n const panel = state.toolPanels.get(sectionId);\n if (!panel?.render) return;\n\n const contentEl = shadow.querySelector(`[data-section=\"${sectionId}\"] .tbw-accordion-content`);\n if (!contentEl) return;\n\n const cleanup = panel.render(contentEl as HTMLElement);\n if (cleanup) {\n state.panelCleanups.set(sectionId, cleanup);\n }\n}\n","/**\n * Plugin Manager\n *\n * Manages plugin instances for a single grid.\n * Each grid has its own PluginManager with its own set of plugin instances.\n */\n\nimport type { ColumnConfig } from '../types';\nimport type {\n BaseGridPlugin,\n CellClickEvent,\n CellEditor,\n CellMouseEvent,\n CellRenderer,\n HeaderClickEvent,\n HeaderRenderer,\n PluginQuery,\n RowClickEvent,\n ScrollEvent,\n} from './base-plugin';\n\n/**\n * Manages plugins for a single grid instance.\n */\nexport class PluginManager {\n /** Plugin instances in order of attachment */\n private plugins: BaseGridPlugin[] = [];\n\n /** Map from plugin class to instance for fast lookup */\n private pluginMap: Map<new (...args: unknown[]) => BaseGridPlugin, BaseGridPlugin> = new Map();\n\n /** Cell renderers registered by plugins */\n private cellRenderers: Map<string, CellRenderer> = new Map();\n\n /** Header renderers registered by plugins */\n private headerRenderers: Map<string, HeaderRenderer> = new Map();\n\n /** Cell editors registered by plugins */\n private cellEditors: Map<string, CellEditor> = new Map();\n\n constructor(private grid: any) {}\n\n /**\n * Attach all plugins from the config.\n */\n attachAll(plugins: BaseGridPlugin[]): void {\n for (const plugin of plugins) {\n this.attach(plugin);\n }\n }\n\n /**\n * Attach a plugin to this grid.\n */\n attach(plugin: BaseGridPlugin): void {\n // Store by constructor for type-safe lookup\n this.pluginMap.set(plugin.constructor as new (...args: unknown[]) => BaseGridPlugin, plugin);\n this.plugins.push(plugin);\n\n // Register renderers/editors\n if (plugin.cellRenderers) {\n for (const [type, renderer] of Object.entries(plugin.cellRenderers)) {\n this.cellRenderers.set(type, renderer);\n }\n }\n if (plugin.headerRenderers) {\n for (const [type, renderer] of Object.entries(plugin.headerRenderers)) {\n this.headerRenderers.set(type, renderer);\n }\n }\n if (plugin.cellEditors) {\n for (const [type, editor] of Object.entries(plugin.cellEditors)) {\n this.cellEditors.set(type, editor);\n }\n }\n\n // Call attach lifecycle method\n plugin.attach(this.grid);\n }\n\n /**\n * Detach all plugins and clean up.\n */\n detachAll(): void {\n // Detach in reverse order\n for (let i = this.plugins.length - 1; i >= 0; i--) {\n this.plugins[i].detach();\n }\n this.plugins = [];\n this.pluginMap.clear();\n this.cellRenderers.clear();\n this.headerRenderers.clear();\n this.cellEditors.clear();\n }\n\n /**\n * Get a plugin instance by its class.\n */\n getPlugin<T extends BaseGridPlugin>(PluginClass: new (...args: any[]) => T): T | undefined {\n return this.pluginMap.get(PluginClass) as T | undefined;\n }\n\n /**\n * Get a plugin instance by its name.\n */\n getPluginByName(name: string): BaseGridPlugin | undefined {\n return this.plugins.find((p) => p.name === name);\n }\n\n /**\n * Check if a plugin is attached.\n */\n hasPlugin<T extends BaseGridPlugin>(PluginClass: new (...args: any[]) => T): boolean {\n return this.pluginMap.has(PluginClass);\n }\n\n /**\n * Get all attached plugins.\n */\n getAll(): readonly BaseGridPlugin[] {\n return this.plugins;\n }\n\n /**\n * Get a cell renderer by type name.\n */\n getCellRenderer(type: string): CellRenderer | undefined {\n return this.cellRenderers.get(type);\n }\n\n /**\n * Get a header renderer by type name.\n */\n getHeaderRenderer(type: string): HeaderRenderer | undefined {\n return this.headerRenderers.get(type);\n }\n\n /**\n * Get a cell editor by type name.\n */\n getCellEditor(type: string): CellEditor | undefined {\n return this.cellEditors.get(type);\n }\n\n /**\n * Get all CSS styles from all plugins.\n */\n getAllStyles(): string {\n return this.plugins\n .filter((p) => p.styles)\n .map((p) => p.styles)\n .join('\\n');\n }\n\n // #region Hook execution methods\n\n /**\n * Execute processRows hook on all plugins.\n */\n processRows(rows: readonly any[]): any[] {\n let result = [...rows];\n for (const plugin of this.plugins) {\n if (plugin.processRows) {\n result = plugin.processRows(result);\n }\n }\n return result;\n }\n\n /**\n * Execute processColumns hook on all plugins.\n */\n processColumns(columns: readonly ColumnConfig[]): ColumnConfig[] {\n let result = [...columns];\n for (const plugin of this.plugins) {\n if (plugin.processColumns) {\n result = plugin.processColumns(result);\n }\n }\n return result;\n }\n\n /**\n * Execute beforeRender hook on all plugins.\n */\n beforeRender(): void {\n for (const plugin of this.plugins) {\n plugin.beforeRender?.();\n }\n }\n\n /**\n * Execute afterRender hook on all plugins.\n */\n afterRender(): void {\n for (const plugin of this.plugins) {\n plugin.afterRender?.();\n }\n }\n\n /**\n * Execute onScrollRender hook on all plugins.\n * Called after scroll-triggered row rendering for lightweight visual state updates.\n */\n onScrollRender(): void {\n for (const plugin of this.plugins) {\n plugin.onScrollRender?.();\n }\n }\n\n /**\n * Get total extra height contributed by plugins (e.g., expanded detail rows).\n * Used to adjust scrollbar height calculations.\n */\n getExtraHeight(): number {\n let total = 0;\n for (const plugin of this.plugins) {\n if (typeof plugin.getExtraHeight === 'function') {\n total += plugin.getExtraHeight();\n }\n }\n return total;\n }\n\n /**\n * Get extra height from plugins that appears before a given row index.\n * Used by virtualization to correctly position the scroll window.\n */\n getExtraHeightBefore(beforeRowIndex: number): number {\n let total = 0;\n for (const plugin of this.plugins) {\n if (typeof plugin.getExtraHeightBefore === 'function') {\n total += plugin.getExtraHeightBefore(beforeRowIndex);\n }\n }\n return total;\n }\n\n /**\n * Adjust the virtualization start index based on plugin needs.\n * Returns the minimum start index from all plugins.\n */\n adjustVirtualStart(start: number, scrollTop: number, rowHeight: number): number {\n let adjustedStart = start;\n for (const plugin of this.plugins) {\n if (typeof plugin.adjustVirtualStart === 'function') {\n const pluginStart = plugin.adjustVirtualStart(start, scrollTop, rowHeight);\n if (pluginStart < adjustedStart) {\n adjustedStart = pluginStart;\n }\n }\n }\n return adjustedStart;\n }\n\n /**\n * Execute renderRow hook on all plugins.\n * Returns true if any plugin handled the row.\n */\n renderRow(row: any, rowEl: HTMLElement, rowIndex: number): boolean {\n for (const plugin of this.plugins) {\n if (plugin.renderRow?.(row, rowEl, rowIndex)) {\n return true;\n }\n }\n return false;\n }\n\n /**\n * Query all plugins with a generic query and collect responses.\n * This enables inter-plugin communication without the core knowing plugin-specific concepts.\n *\n * Common query types are defined in PLUGIN_QUERIES, but plugins can define their own.\n *\n * @param query - The query object containing type and context\n * @returns Array of non-undefined responses from plugins\n */\n queryPlugins<T>(query: PluginQuery): T[] {\n const responses: T[] = [];\n for (const plugin of this.plugins) {\n const response = plugin.onPluginQuery?.(query);\n if (response !== undefined) {\n responses.push(response as T);\n }\n }\n return responses;\n }\n\n /**\n * Execute onKeyDown hook on all plugins.\n * Returns true if any plugin handled the event.\n */\n onKeyDown(event: KeyboardEvent): boolean {\n for (const plugin of this.plugins) {\n if (plugin.onKeyDown?.(event)) {\n return true;\n }\n }\n return false;\n }\n\n /**\n * Execute onCellClick hook on all plugins.\n * Returns true if any plugin handled the event.\n */\n onCellClick(event: CellClickEvent): boolean {\n for (const plugin of this.plugins) {\n if (plugin.onCellClick?.(event)) {\n return true;\n }\n }\n return false;\n }\n\n /**\n * Execute onRowClick hook on all plugins.\n * Returns true if any plugin handled the event.\n */\n onRowClick(event: RowClickEvent): boolean {\n for (const plugin of this.plugins) {\n if (plugin.onRowClick?.(event)) {\n return true;\n }\n }\n return false;\n }\n\n /**\n * Execute onHeaderClick hook on all plugins.\n * Returns true if any plugin handled the event.\n */\n onHeaderClick(event: HeaderClickEvent): boolean {\n for (const plugin of this.plugins) {\n if (plugin.onHeaderClick?.(event)) {\n return true;\n }\n }\n return false;\n }\n\n /**\n * Execute onScroll hook on all plugins.\n */\n onScroll(event: ScrollEvent): void {\n for (const plugin of this.plugins) {\n plugin.onScroll?.(event);\n }\n }\n\n /**\n * Execute onCellMouseDown hook on all plugins.\n * Returns true if any plugin handled the event.\n */\n onCellMouseDown(event: CellMouseEvent): boolean {\n for (const plugin of this.plugins) {\n if (plugin.onCellMouseDown?.(event)) {\n return true;\n }\n }\n return false;\n }\n\n /**\n * Execute onCellMouseMove hook on all plugins.\n * Returns true if any plugin handled the event.\n */\n onCellMouseMove(event: CellMouseEvent): boolean {\n for (const plugin of this.plugins) {\n if (plugin.onCellMouseMove?.(event)) {\n return true;\n }\n }\n return false;\n }\n\n /**\n * Execute onCellMouseUp hook on all plugins.\n * Returns true if any plugin handled the event.\n */\n onCellMouseUp(event: CellMouseEvent): boolean {\n for (const plugin of this.plugins) {\n if (plugin.onCellMouseUp?.(event)) {\n return true;\n }\n }\n return false;\n }\n\n // #endregion\n\n // #region Scroll Boundary Hooks\n\n /**\n * Collect horizontal scroll boundary offsets from all plugins.\n * Combines offsets from all plugins that report them.\n *\n * @param rowEl - The row element (optional, for calculating widths from rendered cells)\n * @param focusedCell - The currently focused cell element (optional, to determine if scrolling should be skipped)\n * @returns Combined left and right pixel offsets, plus skipScroll if any plugin requests it\n */\n getHorizontalScrollOffsets(\n rowEl?: HTMLElement,\n focusedCell?: HTMLElement,\n ): { left: number; right: number; skipScroll?: boolean } {\n let left = 0;\n let right = 0;\n let skipScroll = false;\n for (const plugin of this.plugins) {\n const offsets = plugin.getHorizontalScrollOffsets?.(rowEl, focusedCell);\n if (offsets) {\n left += offsets.left;\n right += offsets.right;\n if (offsets.skipScroll) {\n skipScroll = true;\n }\n }\n }\n return { left, right, skipScroll };\n }\n // #endregion\n\n // #region Shell Integration Hooks\n\n /**\n * Collect tool panels from all plugins.\n * Returns panels sorted by order (ascending).\n */\n getToolPanels(): {\n plugin: BaseGridPlugin;\n panel: NonNullable<ReturnType<NonNullable<BaseGridPlugin['getToolPanel']>>>;\n }[] {\n const panels: {\n plugin: BaseGridPlugin;\n panel: NonNullable<ReturnType<NonNullable<BaseGridPlugin['getToolPanel']>>>;\n }[] = [];\n for (const plugin of this.plugins) {\n const panel = plugin.getToolPanel?.();\n if (panel) {\n panels.push({ plugin, panel });\n }\n }\n // Sort by order (ascending), default to 0\n return panels.sort((a, b) => (a.panel.order ?? 0) - (b.panel.order ?? 0));\n }\n\n /**\n * Collect header contents from all plugins.\n * Returns contents sorted by order (ascending).\n */\n getHeaderContents(): {\n plugin: BaseGridPlugin;\n content: NonNullable<ReturnType<NonNullable<BaseGridPlugin['getHeaderContent']>>>;\n }[] {\n const contents: {\n plugin: BaseGridPlugin;\n content: NonNullable<ReturnType<NonNullable<BaseGridPlugin['getHeaderContent']>>>;\n }[] = [];\n for (const plugin of this.plugins) {\n const content = plugin.getHeaderContent?.();\n if (content) {\n contents.push({ plugin, content });\n }\n }\n // Sort by order (ascending), default to 0\n return contents.sort((a, b) => (a.content.order ?? 0) - (b.content.order ?? 0));\n }\n // #endregion\n}\n","import styles from './grid.css?inline';\nimport { applyColumnState, collectColumnState, createStateChangeHandler } from './internal/column-state';\nimport { autoSizeColumns, getColumnConfiguration, updateTemplate } from './internal/columns';\nimport { exitRowEdit, inlineEnterEdit, startRowEdit } from './internal/editing';\nimport { renderHeader } from './internal/header';\nimport { inferColumns } from './internal/inference';\nimport { ensureCellVisible, handleGridKeyDown } from './internal/keyboard';\nimport { createResizeController } from './internal/resize';\nimport { invalidateCellCache, renderVisibleRows } from './internal/rows';\nimport {\n cleanupShellState,\n createShellController,\n createShellState,\n parseLightDomShell,\n renderCustomToolbarButtons,\n renderHeaderContent,\n renderShellBody,\n renderShellHeader,\n setupShellEventListeners,\n setupToolPanelResize,\n shouldRenderShellHeader,\n type ShellController,\n type ShellState,\n} from './internal/shell';\nimport type { CellMouseEvent, ScrollEvent } from './plugin';\nimport type { BaseGridPlugin, CellClickEvent, HeaderClickEvent, PluginQuery } from './plugin/base-plugin';\nimport { PluginManager } from './plugin/plugin-manager';\nimport type {\n ActivateCellDetail,\n CellCommitDetail,\n ColumnConfig,\n ColumnConfigMap,\n ColumnInternal,\n ColumnResizeDetail,\n FitMode,\n GridColumnState,\n GridConfig,\n HeaderContentDefinition,\n InternalGrid,\n ResizeController,\n RowCommitDetail,\n SortChangeDetail,\n ToolbarButtonConfig,\n ToolbarButtonInfo,\n ToolPanelDefinition,\n VirtualState,\n} from './types';\nimport { DEFAULT_GRID_ICONS } from './types';\n\n/**\n * High-performance data grid web component.\n * During migration, uses tbw-grid tag to avoid conflicts with existing datagrid.\n * Will be renamed back to data-grid when migration is complete.\n *\n * ## Configuration Architecture\n *\n * The grid follows a **single source of truth** pattern where all configuration\n * converges into `#effectiveConfig`. Users can set configuration via multiple inputs:\n *\n * **Input Sources (precedence low → high):**\n * 1. `gridConfig` property - base configuration object\n * 2. Light DOM elements:\n * - `<tbw-grid-column>` → `effectiveConfig.columns`\n * - `<tbw-grid-header title=\"...\">` → `effectiveConfig.shell.header.title`\n * - `<tbw-grid-header-content>` → `effectiveConfig.shell.header.content`\n * 3. `columns` property → merged into `effectiveConfig.columns`\n * 4. `fitMode` property → merged into `effectiveConfig.fitMode`\n * 5. `editOn` property → merged into `effectiveConfig.editOn`\n * 6. Column inference from first row (if no columns defined)\n *\n * **Derived State:**\n * - `_columns` - processed columns from `effectiveConfig.columns` after plugin hooks\n * - `_rows` - processed rows after plugin hooks (grouping, filtering, etc.)\n *\n * The `#mergeEffectiveConfig()` method is the single place where all inputs converge.\n * All rendering and logic should read from `effectiveConfig` or derived state.\n *\n * @element tbw-grid\n *\n * @csspart container - The main grid container\n * @csspart header - The header row container\n * @csspart body - The body/rows container\n *\n * @fires cell-commit - Fired when a cell value is committed\n * @fires row-commit - Fired when a bulk row edit session commits\n * @fires changed-rows-reset - Fired after resetChangedRows() unless silent\n * @fires mount-external-view - Fired to request mounting of an external view renderer\n * @fires mount-external-editor - Fired to request mounting of an external editor renderer\n * @fires sort-change - Fired when sort state changes for a column\n * @fires column-resize - Fired after a column resize drag completes\n * @fires activate-cell - Fired when a cell activation intent occurs\n * @fires group-toggle - Fired when a group row is toggled\n *\n * @cssprop --tbw-color-bg - Background color\n * @cssprop --tbw-color-fg - Foreground/text color\n */\n// Injected by Vite at build time from package.json\ndeclare const __GRID_VERSION__: string;\n\nexport class DataGridElement<T = any> extends HTMLElement implements InternalGrid<T> {\n // TODO: Rename to 'data-grid' when migration is complete\n static readonly tagName = 'tbw-grid';\n static readonly version = typeof __GRID_VERSION__ !== 'undefined' ? __GRID_VERSION__ : 'dev';\n\n // ---------------- Observed Attributes ----------------\n static get observedAttributes(): string[] {\n return ['rows', 'columns', 'grid-config', 'fit-mode', 'edit-on'];\n }\n\n readonly #shadow: ShadowRoot;\n #initialized = false;\n\n // ---------------- Ready Promise ----------------\n #readyPromise: Promise<void>;\n #readyResolve?: () => void;\n\n // #region Input Properties\n // These backing fields store raw user input. They are merged into\n // #effectiveConfig by #mergeEffectiveConfig(). Never read directly\n // for rendering logic - always use effectiveConfig or derived state.\n #rows: T[] = [];\n #columns?: ColumnConfig<T>[] | ColumnConfigMap<T>;\n #gridConfig?: GridConfig<T>;\n #fitMode?: FitMode;\n #editOn?: string;\n // #endregion\n\n // #region Single Source of Truth\n // All input sources converge here. This is the canonical config\n // that all rendering and logic should read from.\n #effectiveConfig: GridConfig<T> = {};\n #connected = false;\n #scrollRaf = 0;\n #pendingScrollTop: number | null = null;\n #hasScrollPlugins = false; // Cached flag for plugin scroll handlers\n #renderRowHook?: (row: any, rowEl: HTMLElement, rowIndex: number) => boolean; // Cached hook to avoid closures\n #isDragging = false;\n #touchStartY: number | null = null;\n #touchStartX: number | null = null;\n #touchScrollTop: number | null = null;\n #touchScrollLeft: number | null = null;\n #eventAbortController?: AbortController;\n #resizeObserver?: ResizeObserver;\n\n // ---------------- Plugin System ----------------\n #pluginManager!: PluginManager;\n\n // ---------------- Column State ----------------\n #stateChangeHandler?: () => void;\n #initialColumnState?: GridColumnState;\n\n // ---------------- Shell State ----------------\n #shellState: ShellState = createShellState();\n #shellController!: ShellController;\n #resizeCleanup?: () => void;\n // #endregion\n\n // #region Derived State\n // _rows: result of applying plugin processRows hooks\n _rows: T[] = [];\n\n // _baseColumns: columns before plugin transformation (analogous to #rows for row processing)\n // This is the source of truth for processColumns - plugins transform these\n #baseColumns: ColumnInternal<T>[] = [];\n\n // _columns is a getter/setter that operates on effectiveConfig.columns\n // This ensures effectiveConfig.columns is the single source of truth for columns\n // _columns always contains ALL columns (including hidden)\n get _columns(): ColumnInternal<T>[] {\n return (this.#effectiveConfig.columns ?? []) as ColumnInternal<T>[];\n }\n set _columns(value: ColumnInternal<T>[]) {\n this.#effectiveConfig.columns = value as ColumnConfig<T>[];\n }\n\n // visibleColumns returns only visible columns for rendering\n // This is what header/row rendering should use\n get _visibleColumns(): ColumnInternal<T>[] {\n return this._columns.filter((c) => !c.hidden);\n }\n // #endregion\n\n // #region Runtime State (Plugin-accessible)\n // DOM references\n _headerRowEl!: HTMLElement;\n _bodyEl!: HTMLElement;\n _rowPool: HTMLElement[] = [];\n _resizeController!: ResizeController;\n\n // Virtualization & scroll state\n _virtualization: VirtualState = {\n enabled: true,\n rowHeight: 28,\n bypassThreshold: 24,\n start: 0,\n end: 0,\n container: null,\n viewportEl: null,\n totalHeightEl: null,\n };\n\n // Focus & navigation\n _focusRow = 0;\n _focusCol = 0;\n\n // Sort state\n _sortState: { field: string; direction: 1 | -1 } | null = null;\n\n // Edit state\n _activeEditRows = -1;\n _rowEditSnapshots = new Map<number, T>();\n _changedRowIndices = new Set<number>();\n\n // Layout\n _gridTemplate = '';\n // #endregion\n\n // #region Implementation Details (Internal only)\n __rowRenderEpoch = 0;\n __didInitialAutoSize = false;\n __lightDomColumnsCache?: ColumnInternal[];\n __originalColumnNodes?: HTMLElement[];\n __originalOrder: T[] = [];\n // #endregion\n\n // ---------------- Public API Props (getters/setters) ----------------\n // Getters return the EFFECTIVE value (after merging), not the raw input.\n // This is what consumers and plugins need - the current resolved state.\n // Setters update input properties which trigger re-merge into effectiveConfig.\n\n get rows(): T[] {\n return this._rows;\n }\n set rows(value: T[]) {\n const oldValue = this.#rows;\n this.#rows = value;\n if (oldValue !== value) {\n this.#onRowsChanged();\n }\n }\n\n /**\n * Get the original unfiltered/unprocessed rows.\n * Use this when you need access to all source data regardless of active filters.\n */\n get sourceRows(): T[] {\n return this.#rows;\n }\n\n get columns(): ColumnConfig<T>[] {\n return [...this._columns] as ColumnConfig<T>[];\n }\n set columns(value: ColumnConfig<T>[] | ColumnConfigMap<T> | undefined) {\n const oldValue = this.#columns;\n this.#columns = value;\n if (oldValue !== value) {\n this.#onColsChanged();\n }\n }\n\n get gridConfig(): GridConfig<T> {\n return this.#effectiveConfig;\n }\n set gridConfig(value: GridConfig<T> | undefined) {\n const oldValue = this.#gridConfig;\n this.#gridConfig = value;\n if (oldValue !== value) {\n this.#onGridConfigChanged();\n }\n }\n\n get fitMode(): FitMode {\n return this.#effectiveConfig.fitMode ?? 'stretch';\n }\n set fitMode(value: FitMode | undefined) {\n const oldValue = this.#fitMode;\n this.#fitMode = value;\n if (oldValue !== value) {\n this.#onFitChanged();\n }\n }\n\n get editOn(): string | undefined {\n return this.#effectiveConfig.editOn;\n }\n set editOn(value: string | undefined) {\n const oldValue = this.#editOn;\n this.#editOn = value;\n if (oldValue !== value) {\n this.#onEditModeChanged();\n }\n }\n\n /**\n * Effective config accessor for internal modules and plugins.\n * Returns the merged config (single source of truth) before plugin processing.\n * Use this when you need the raw merged config (e.g., for column definitions including hidden).\n * @internal Plugin API\n */\n get effectiveConfig(): GridConfig<T> {\n return this.#effectiveConfig;\n }\n\n /**\n * Get the disconnect signal for event listener cleanup.\n * This signal is aborted when the grid disconnects from the DOM.\n * Plugins and internal code can use this for automatic listener cleanup.\n * @internal Plugin API\n * @example\n * element.addEventListener('click', handler, { signal: this.grid.disconnectSignal });\n */\n get disconnectSignal(): AbortSignal {\n // Ensure AbortController exists (created in connectedCallback before plugins attach)\n if (!this.#eventAbortController) {\n this.#eventAbortController = new AbortController();\n }\n return this.#eventAbortController.signal;\n }\n\n constructor() {\n super();\n this.#shadow = this.attachShadow({ mode: 'open' });\n this.#injectStyles();\n this.#readyPromise = new Promise((res) => (this.#readyResolve = res));\n\n // Initialize shell controller with callbacks\n this.#shellController = createShellController(this.#shellState, {\n getShadow: () => this.#shadow,\n getShellConfig: () => this.#effectiveConfig?.shell,\n getAccordionIcons: () => ({\n expand: this.#effectiveConfig?.icons?.expand ?? DEFAULT_GRID_ICONS.expand,\n collapse: this.#effectiveConfig?.icons?.collapse ?? DEFAULT_GRID_ICONS.collapse,\n }),\n emit: (eventName, detail) => this.#emit(eventName, detail),\n refreshShellHeader: () => this.refreshShellHeader(),\n });\n }\n\n #injectStyles(): void {\n const sheet = new CSSStyleSheet();\n sheet.replaceSync(styles);\n this.#shadow.adoptedStyleSheets = [sheet];\n }\n\n // ---------------- Plugin System ----------------\n\n /**\n * Get a plugin instance by its class.\n * Used by plugins for inter-plugin communication.\n * @internal Plugin API\n */\n getPlugin<P extends BaseGridPlugin>(PluginClass: new (...args: any[]) => P): P | undefined {\n return this.#pluginManager?.getPlugin(PluginClass);\n }\n\n /**\n * Get a plugin instance by its name.\n * Used for loose coupling between plugins (avoids static imports).\n * @internal Plugin API\n */\n getPluginByName(name: string): BaseGridPlugin | undefined {\n return this.#pluginManager?.getPluginByName(name);\n }\n\n /**\n * Request a full re-render of the grid.\n * Called by plugins when they need the grid to update.\n * Note: This does NOT reset plugin state - just re-processes rows/columns and renders.\n * @internal Plugin API\n */\n requestRender(): void {\n this.#rebuildRowModel();\n this.#processColumns();\n renderHeader(this);\n updateTemplate(this);\n this.refreshVirtualWindow(true);\n }\n\n /**\n * Request a lightweight style update without rebuilding DOM.\n * Called by plugins when they only need to update CSS classes/styles.\n * This runs all plugin afterRender hooks without rebuilding row/column DOM.\n * @internal Plugin API\n */\n requestAfterRender(): void {\n this.#pluginManager?.afterRender();\n }\n\n /**\n * Initialize plugin system with instances from config.\n * Plugins are class instances passed in gridConfig.plugins[].\n */\n #initializePlugins(): void {\n // Create plugin manager for this grid\n this.#pluginManager = new PluginManager(this);\n\n // Get plugin instances from config - ensure it's an array\n const pluginsConfig = this.#effectiveConfig?.plugins;\n const plugins = Array.isArray(pluginsConfig) ? (pluginsConfig as BaseGridPlugin[]) : [];\n\n // Attach all plugins\n this.#pluginManager.attachAll(plugins);\n }\n\n /**\n * Inject all plugin styles into the shadow DOM.\n * Must be called after #render() since innerHTML wipes existing content.\n */\n #injectAllPluginStyles(): void {\n const allStyles = this.#pluginManager?.getAllStyles() ?? '';\n if (allStyles) {\n const styleEl = document.createElement('style');\n styleEl.setAttribute('data-plugin', 'all');\n styleEl.textContent = allStyles;\n this.#shadow.appendChild(styleEl);\n }\n }\n\n /**\n * Update plugins when grid config changes.\n * With class-based plugins, we need to detach old and attach new.\n */\n #updatePluginConfigs(): void {\n // With class-based plugins, config changes require re-initialization\n // The new plugins are in the new config - detach old, attach new\n if (this.#pluginManager) {\n this.#pluginManager.detachAll();\n }\n this.#initializePlugins();\n this.#injectAllPluginStyles();\n // Update cached scroll plugin flag\n this.#hasScrollPlugins = this.#pluginManager?.getAll().some((p) => p.onScroll) ?? false;\n }\n\n /**\n * Clean up plugin states when grid disconnects.\n */\n #destroyPlugins(): void {\n this.#pluginManager?.detachAll();\n }\n\n /**\n * Collect tool panels and header content from all plugins.\n * Called after plugins are attached but before render.\n */\n #collectPluginShellContributions(): void {\n if (!this.#pluginManager) return;\n\n // Collect tool panels from plugins\n const pluginPanels = this.#pluginManager.getToolPanels();\n for (const { panel } of pluginPanels) {\n // Skip if already registered (light DOM or API takes precedence)\n if (!this.#shellState.toolPanels.has(panel.id)) {\n this.#shellState.toolPanels.set(panel.id, panel);\n }\n }\n\n // Collect header contents from plugins\n const pluginContents = this.#pluginManager.getHeaderContents();\n for (const { content } of pluginContents) {\n // Skip if already registered (light DOM or API takes precedence)\n if (!this.#shellState.headerContents.has(content.id)) {\n this.#shellState.headerContents.set(content.id, content);\n }\n }\n }\n\n // ---------------- Lifecycle ----------------\n connectedCallback(): void {\n if (!this.hasAttribute('tabindex')) (this as any).tabIndex = 0;\n if (!this.hasAttribute('version')) this.setAttribute('version', DataGridElement.version);\n this._rows = Array.isArray(this.#rows) ? [...this.#rows] : [];\n\n // Create AbortController for all event listeners (grid internal + plugins)\n // This must happen BEFORE plugins attach so they can use disconnectSignal\n // Abort any previous controller first (in case of re-connect)\n this.#eventAbortController?.abort();\n this.#eventAbortController = new AbortController();\n\n // Merge all config sources into effectiveConfig (including columns)\n this.#mergeEffectiveConfig();\n\n // Initialize plugin system (now plugins can access disconnectSignal)\n this.#initializePlugins();\n\n // Collect tool panels and header content from plugins (must be before render)\n this.#collectPluginShellContributions();\n\n if (!this.#initialized) {\n this.#render();\n this.#injectAllPluginStyles(); // Inject plugin styles after render\n this.#initialized = true;\n }\n this.#afterConnect();\n }\n\n disconnectedCallback(): void {\n // Clean up plugin states\n this.#destroyPlugins();\n\n // Clean up shell state\n cleanupShellState(this.#shellState);\n this.#shellController.setInitialized(false);\n\n // Clean up tool panel resize handler\n this.#resizeCleanup?.();\n this.#resizeCleanup = undefined;\n\n // Abort all event listeners (internal + document-level)\n // This cleans up all listeners added with { signal } option\n if (this.#eventAbortController) {\n this.#eventAbortController.abort();\n this.#eventAbortController = undefined;\n }\n\n if (this._resizeController) {\n this._resizeController.dispose();\n }\n if (this.#resizeObserver) {\n this.#resizeObserver.disconnect();\n this.#resizeObserver = undefined;\n }\n this.#connected = false;\n }\n\n /**\n * Handle HTML attribute changes.\n * Only processes attribute values when SET (non-null).\n * Removing an attribute does NOT clear JS-set properties.\n */\n attributeChangedCallback(name: string, oldValue: string | null, newValue: string | null): void {\n if (oldValue === newValue || !newValue || newValue === 'null' || newValue === 'undefined') return;\n\n // Map kebab-case attributes to camelCase properties\n const propMap: Record<string, keyof this> = {\n rows: 'rows',\n columns: 'columns',\n 'grid-config': 'gridConfig',\n 'fit-mode': 'fitMode',\n 'edit-on': 'editOn',\n };\n\n const prop = propMap[name];\n if (!prop) return;\n\n // JSON attributes need parsing\n if (name === 'rows' || name === 'columns' || name === 'grid-config') {\n try {\n (this as any)[prop] = JSON.parse(newValue);\n } catch {\n console.warn(`[tbw-grid] Invalid JSON for '${name}' attribute:`, newValue);\n }\n } else {\n // String attributes (fit-mode, edit-on)\n (this as any)[prop] = newValue;\n }\n }\n\n #afterConnect(): void {\n // Shell changes the DOM structure - need to find elements appropriately\n const gridContent = this.#shadow.querySelector('.tbw-grid-content');\n const gridRoot = gridContent ?? this.#shadow.querySelector('.tbw-grid-root');\n\n this._headerRowEl = gridRoot?.querySelector('.header-row') as HTMLElement;\n // Faux scrollbar pattern:\n // - .faux-vscroll-spacer sets virtual height\n // - .rows-viewport provides visible height for virtualization calculations\n this._virtualization.totalHeightEl = gridRoot?.querySelector('.faux-vscroll-spacer') as HTMLElement;\n this._virtualization.viewportEl = gridRoot?.querySelector('.rows-viewport') as HTMLElement;\n this._bodyEl = gridRoot?.querySelector('.rows') as HTMLElement;\n\n // Initialize shell header content and custom buttons if shell is active\n if (this.#shellController.isInitialized) {\n // Render plugin header content\n renderHeaderContent(this.#shadow, this.#shellState);\n // Render custom toolbar buttons (element/render modes)\n renderCustomToolbarButtons(this.#shadow, this.#effectiveConfig?.shell, this.#shellState);\n // Open default section if configured\n const defaultOpen = this.#effectiveConfig?.shell?.toolPanel?.defaultOpen;\n if (defaultOpen && this.#shellState.toolPanels.has(defaultOpen)) {\n this.openToolPanel();\n this.#shellState.expandedSections.add(defaultOpen);\n }\n }\n\n // Mark for tests that afterConnect ran\n this.setAttribute('data-upgraded', '');\n this.#connected = true;\n\n // Get the signal for event listener cleanup (AbortController created in connectedCallback)\n const signal = this.disconnectSignal;\n\n // Run setup\n this.#setup();\n\n // Element-level keydown handler (uses signal for automatic cleanup)\n this.addEventListener('keydown', (e) => handleGridKeyDown(this as any, e), { signal });\n\n // Document-level listeners (also use signal for automatic cleanup)\n // Escape key to cancel row editing\n document.addEventListener(\n 'keydown',\n (e: KeyboardEvent) => {\n if (e.key === 'Escape' && this._activeEditRows !== -1) {\n exitRowEdit(this, this._activeEditRows, true);\n }\n },\n { capture: true, signal },\n );\n\n // Click outside to commit row editing\n document.addEventListener(\n 'mousedown',\n (e: MouseEvent) => {\n if (this._activeEditRows === -1) return;\n const rowEl = this.findRenderedRowElement(this._activeEditRows);\n if (!rowEl) return;\n const path = (e.composedPath && e.composedPath()) || [];\n if (path.includes(rowEl)) return;\n exitRowEdit(this, this._activeEditRows, false);\n },\n { signal },\n );\n\n // Faux scrollbar pattern: scroll events come from the fake scrollbar element\n // Content area doesn't scroll - rows are positioned via transforms\n // This prevents blank viewport: old content stays until transforms are updated\n // Reuse gridRoot from earlier in this function\n const fauxScrollbar = gridRoot?.querySelector('.faux-vscroll') as HTMLElement;\n const rowsEl = gridRoot?.querySelector('.rows') as HTMLElement;\n\n // Store reference for scroll position reading in refreshVirtualWindow\n this._virtualization.container = fauxScrollbar ?? this;\n\n // Cache whether any plugin has scroll handlers (checked once during setup)\n this.#hasScrollPlugins = this.#pluginManager?.getAll().some((p) => p.onScroll) ?? false;\n\n if (fauxScrollbar && rowsEl) {\n fauxScrollbar.addEventListener(\n 'scroll',\n () => {\n // Fast exit if no scroll processing needed\n if (!this._virtualization.enabled && !this.#hasScrollPlugins) return;\n\n const currentScrollTop = fauxScrollbar.scrollTop;\n const rowHeight = this._virtualization.rowHeight;\n\n // Smooth scroll: apply offset immediately for fluid motion\n // Calculate even-aligned start to preserve zebra stripe parity\n // DOM nth-child(even) will always match data row parity\n const rawStart = Math.floor(currentScrollTop / rowHeight);\n const evenAlignedStart = rawStart - (rawStart % 2);\n const subPixelOffset = -(currentScrollTop - evenAlignedStart * rowHeight);\n rowsEl.style.transform = `translateY(${subPixelOffset}px)`;\n\n // Batch content update with requestAnimationFrame\n // Old content stays visible with smooth offset until new content renders\n this.#pendingScrollTop = currentScrollTop;\n if (!this.#scrollRaf) {\n this.#scrollRaf = requestAnimationFrame(() => {\n this.#scrollRaf = 0;\n if (this.#pendingScrollTop !== null) {\n this.#onScrollBatched(this.#pendingScrollTop);\n this.#pendingScrollTop = null;\n }\n });\n }\n },\n { passive: true, signal },\n );\n\n // Forward wheel events from content area to faux scrollbar\n // Without this, mouse wheel over content wouldn't scroll\n // Listen on .tbw-grid-content to capture wheel events from entire grid area\n // Note: gridRoot may already BE .tbw-grid-content when shell is active, so search from shadow root\n const gridContentEl = this.#shadow.querySelector('.tbw-grid-content') as HTMLElement;\n const scrollArea = this.#shadow.querySelector('.tbw-scroll-area') as HTMLElement;\n if (gridContentEl) {\n gridContentEl.addEventListener(\n 'wheel',\n (e: WheelEvent) => {\n // Prevent default to stop any residual scroll behavior\n e.preventDefault();\n\n // SHIFT+wheel = horizontal scroll\n // Also handle trackpad horizontal scroll (deltaX)\n if (e.shiftKey || Math.abs(e.deltaX) > Math.abs(e.deltaY)) {\n // Horizontal scroll - apply to scroll area\n if (scrollArea) {\n scrollArea.scrollLeft += e.shiftKey ? e.deltaY : e.deltaX;\n }\n } else {\n // Vertical scroll - apply to faux scrollbar\n fauxScrollbar.scrollTop += e.deltaY;\n }\n },\n { passive: false, signal },\n );\n\n // Touch scrolling support for mobile devices\n // Supports both vertical (via faux scrollbar) and horizontal (via scroll area) scrolling\n gridContentEl.addEventListener(\n 'touchstart',\n (e: TouchEvent) => {\n if (e.touches.length === 1) {\n this.#touchStartY = e.touches[0].clientY;\n this.#touchStartX = e.touches[0].clientX;\n this.#touchScrollTop = fauxScrollbar.scrollTop;\n this.#touchScrollLeft = scrollArea?.scrollLeft ?? 0;\n }\n },\n { passive: true, signal },\n );\n\n gridContentEl.addEventListener(\n 'touchmove',\n (e: TouchEvent) => {\n if (\n e.touches.length === 1 &&\n this.#touchStartY !== null &&\n this.#touchStartX !== null &&\n this.#touchScrollTop !== null &&\n this.#touchScrollLeft !== null\n ) {\n const deltaY = this.#touchStartY - e.touches[0].clientY;\n const deltaX = this.#touchStartX - e.touches[0].clientX;\n\n // Apply both vertical and horizontal scroll\n fauxScrollbar.scrollTop = this.#touchScrollTop + deltaY;\n if (scrollArea) {\n scrollArea.scrollLeft = this.#touchScrollLeft + deltaX;\n }\n\n // Prevent page scroll when scrolling within grid\n e.preventDefault();\n }\n },\n { passive: false, signal },\n );\n\n gridContentEl.addEventListener(\n 'touchend',\n () => {\n this.#touchStartY = null;\n this.#touchStartX = null;\n this.#touchScrollTop = null;\n this.#touchScrollLeft = null;\n },\n { passive: true, signal },\n );\n }\n }\n\n this._resizeController = createResizeController(this as any);\n\n // Central mouse event handling for plugins (uses signal for automatic cleanup)\n this.#shadow.addEventListener('mousedown', (e) => this.#handleMouseDown(e as MouseEvent), { signal });\n\n // Track global mousemove/mouseup for drag operations (uses signal for automatic cleanup)\n document.addEventListener('mousemove', (e: MouseEvent) => this.#handleMouseMove(e), { signal });\n document.addEventListener('mouseup', (e: MouseEvent) => this.#handleMouseUp(e), { signal });\n\n if (this._virtualization.enabled) {\n requestAnimationFrame(() => this.refreshVirtualWindow(true));\n }\n\n // Determine row height for virtualization:\n // 1. User-configured rowHeight in gridConfig takes precedence\n // 2. Otherwise, measure actual row height from DOM (respects CSS variable --tbw-row-height)\n const userRowHeight = this.#effectiveConfig.rowHeight;\n if (userRowHeight && userRowHeight > 0) {\n this._virtualization.rowHeight = userRowHeight;\n } else {\n // Measure after first render to pick up CSS-defined row height\n requestAnimationFrame(() => {\n const firstRow = this._bodyEl?.querySelector('.data-grid-row');\n if (firstRow) {\n const measuredHeight = (firstRow as HTMLElement).getBoundingClientRect().height;\n if (measuredHeight > 0) {\n this._virtualization.rowHeight = measuredHeight;\n this.refreshVirtualWindow(true);\n }\n }\n });\n }\n\n // Resize observer to refresh virtualization and maintain focus when viewport size changes\n if (this._virtualization.viewportEl) {\n this.#resizeObserver = new ResizeObserver(() => {\n // Debounce with RAF to avoid excessive recalculations\n if (!this.#scrollRaf) {\n this.#scrollRaf = requestAnimationFrame(() => {\n this.#scrollRaf = 0;\n this.refreshVirtualWindow(true);\n\n // Ensure focused cell remains visible after resize\n // (viewport size may have changed, pushing the focused cell out of view)\n ensureCellVisible(this as any);\n });\n }\n });\n this.#resizeObserver.observe(this._virtualization.viewportEl);\n }\n\n // Initialize ARIA selection state\n queueMicrotask(() => this.#updateAriaSelection());\n\n requestAnimationFrame(() => requestAnimationFrame(() => this.#readyResolve?.()));\n }\n\n // ---------------- Event Emitters ----------------\n #emit<D>(eventName: string, detail: D): void {\n this.dispatchEvent(new CustomEvent(eventName, { detail, bubbles: true, composed: true }));\n }\n\n _emitCellCommit(detail: CellCommitDetail<T>): void {\n this.#emit('cell-commit', detail);\n }\n\n _emitRowCommit(detail: RowCommitDetail<T>): void {\n this.#emit('row-commit', detail);\n }\n\n _emitSortChange(detail: SortChangeDetail): void {\n this.#emit('sort-change', detail);\n }\n\n _emitColumnResize(detail: ColumnResizeDetail): void {\n this.#emit('column-resize', detail);\n }\n\n _emitActivateCell(detail: ActivateCellDetail): void {\n this.#emit('activate-cell', detail);\n }\n\n /** Update ARIA selection attributes on rendered rows/cells */\n #updateAriaSelection(): void {\n // Mark active row and cell with aria-selected\n const rows = this._bodyEl?.querySelectorAll('.data-grid-row');\n rows?.forEach((row, rowIdx) => {\n const isActiveRow = rowIdx === this._focusRow;\n row.setAttribute('aria-selected', String(isActiveRow));\n row.querySelectorAll('.cell').forEach((cell, colIdx) => {\n (cell as HTMLElement).setAttribute('aria-selected', String(isActiveRow && colIdx === this._focusCol));\n });\n });\n }\n\n // ---------------- Watch Handlers ----------------\n #onFitChanged(): void {\n if (!this.#connected) return;\n this.#mergeEffectiveConfig();\n const mode = this.#effectiveConfig.fitMode;\n if (mode === 'fixed') {\n this.__didInitialAutoSize = false;\n autoSizeColumns(this);\n } else {\n this._columns.forEach((c: any) => {\n if (!c.__userResized && c.__autoSized) delete c.width;\n });\n updateTemplate(this);\n }\n }\n\n #onEditModeChanged(): void {\n if (!this.#connected) return;\n this.#mergeEffectiveConfig();\n this._rowPool.length = 0;\n if (this._bodyEl) this._bodyEl.innerHTML = '';\n this.__rowRenderEpoch++;\n this.refreshVirtualWindow(true);\n }\n\n #onRowsChanged(): void {\n this._rows = Array.isArray(this.#rows) ? [...this.#rows] : [];\n this.#rebuildRowModel();\n // If no explicit columns provided, trigger full setup so inference runs\n if (!this.#columns || (Array.isArray(this.#columns) && this.#columns.length === 0)) {\n this.#setup();\n } else {\n this.refreshVirtualWindow(true);\n }\n }\n\n #onColsChanged(): void {\n // Invalidate caches that depend on column configuration\n invalidateCellCache(this);\n\n // Re-merge config and setup - _columns will be set through effectiveConfig\n if (this.#connected) {\n this.#mergeEffectiveConfig();\n this.#setup();\n }\n }\n\n #onGridConfigChanged(): void {\n if (!this.#connected) return;\n this.#mergeEffectiveConfig();\n this.#updatePluginConfigs(); // Sync plugin configs with new grid config\n this.#rebuildRowModel();\n this.#processColumns(); // Process columns after rows for tree plugin\n renderHeader(this);\n updateTemplate(this);\n this.refreshVirtualWindow(true);\n }\n\n #processColumns(): void {\n // Let plugins process visible columns (column grouping, etc.)\n // Start from base columns (before any plugin transformation) - like #rebuildRowModel uses #rows\n if (this.#pluginManager) {\n // Use base columns as source of truth, falling back to current _columns if not set\n const sourceColumns = this.#baseColumns.length > 0 ? this.#baseColumns : this._columns;\n const visibleCols = sourceColumns.filter((c) => !c.hidden);\n const hiddenCols = sourceColumns.filter((c) => c.hidden);\n const processedColumns = this.#pluginManager.processColumns([...visibleCols] as any[]);\n\n // If plugins modified visible columns, update them\n if (processedColumns !== visibleCols) {\n // Build a map of processed columns by field for quick lookup\n const processedMap = new Map(processedColumns.map((c: any, i: number) => [c.field, { col: c, order: i }]));\n\n // Check if this is a complete column replacement (e.g., pivot mode)\n // If no processed columns match original columns, use processed columns directly\n const hasMatchingFields = visibleCols.some((c) => processedMap.has(c.field));\n\n if (!hasMatchingFields && processedColumns.length > 0) {\n // Complete replacement: use processed columns directly (pivot mode)\n // Preserve hidden columns at the end\n this._columns = [...processedColumns, ...hiddenCols] as ColumnInternal<T>[];\n } else {\n // Plugins returned original fields (possibly modified) - merge back\n // Use source columns as base, not current _columns\n const updatedColumns = sourceColumns.map((c) => {\n if (c.hidden) return c; // Keep hidden columns unchanged\n const processed = processedMap.get(c.field);\n return processed ? processed.col : c;\n });\n\n this._columns = updatedColumns as ColumnInternal<T>[];\n }\n } else {\n // Plugins returned columns unchanged, but we may need to restore from base\n this._columns = [...sourceColumns] as ColumnInternal<T>[];\n }\n }\n }\n\n /** Recompute row model via plugin hooks (grouping, tree, filtering, etc.). */\n #rebuildRowModel(): void {\n // Invalidate cell display value cache - rows are changing\n invalidateCellCache(this);\n\n // Start fresh from original rows (plugins will transform them)\n const originalRows = Array.isArray(this.#rows) ? [...this.#rows] : [];\n\n // Let plugins process rows (row grouping, tree, filtering, etc.)\n // Plugins can transform the rows array, adding markers like __isGroupRow\n // The renderRow hook will handle rendering specialized row types\n const processedRows = this.#pluginManager?.processRows(originalRows) ?? originalRows;\n\n // Store processed rows for rendering\n // Note: processedRows may contain group markers that plugins handle via renderRow hook\n this._rows = processedRows as T[];\n }\n\n /**\n * Build the canonical effective configuration by merging all input sources.\n *\n * This is the **single source of truth** for the grid's configuration.\n * All inputs (gridConfig, light DOM, individual props) converge here.\n *\n * **Precedence (lowest → highest):**\n * 1. `gridConfig` property - base config object\n * 2. Light DOM `<tbw-grid-column>` elements - declarative columns\n * 3. `columns` property - programmatic columns override\n * 4. Inferred columns - auto-detected from row data\n * 5. Individual props (`fitMode`, `editOn`) - convenience overrides\n *\n * After this method runs:\n * - `#effectiveConfig` contains the merged result\n * - `_columns` is NOT set here (done by #getColumnConfiguration + #processColumns)\n * - Plugins receive config via their attach() method\n */\n #mergeEffectiveConfig(): void {\n const base: GridConfig<T> = this.#gridConfig ? { ...this.#gridConfig } : {};\n let columns: ColumnConfig<T>[] = Array.isArray(base.columns) ? [...base.columns] : [];\n\n // Light DOM cached parse (if already parsed by columns pipeline); non-invasive merge (fill gaps only)\n const domCols: ColumnConfig<T>[] = ((this as any).__lightDomColumnsCache || []).map((c: ColumnConfig<T>) => ({\n ...c,\n }));\n if (domCols.length) {\n const map: Record<string, ColumnConfig<T>> = {};\n columns.forEach((c) => (map[(c as any).field] = c));\n domCols.forEach((c: any) => {\n const exist = map[c.field];\n if (!exist) {\n columns.push(c);\n map[c.field] = c;\n } else {\n if (c.header && !exist.header) exist.header = c.header;\n if (c.type && !exist.type) exist.type = c.type;\n exist.sortable = exist.sortable || c.sortable;\n if (c.resizable) exist.resizable = true;\n if (c.editable) exist.editable = true;\n }\n });\n }\n\n // Columns prop highest structural precedence\n if (this.#columns && (this.#columns as ColumnConfig<T>[]).length) {\n columns = [...(this.#columns as ColumnConfig<T>[])];\n }\n\n // Inference if still empty\n if ((!columns || columns.length === 0) && this._rows.length) {\n const result = inferColumns(this._rows as Record<string, unknown>[]);\n columns = result.columns as ColumnConfig<T>[];\n }\n\n if (columns.length) {\n // Apply per-column defaults (sortable/resizable default true unless explicitly false)\n columns.forEach((c) => {\n if (c.sortable === undefined) c.sortable = true;\n if (c.resizable === undefined) c.resizable = true;\n });\n // Preserve processed columns (with __compiledView etc.) if already set by #getColumnConfiguration\n // Only set base.columns if effectiveConfig.columns is empty or doesn't have compiled templates\n const existingCols = this.#effectiveConfig.columns as ColumnInternal<T>[] | undefined;\n const alreadyProcessed = existingCols?.some((c) => c.__compiledView || c.__compiledEditor);\n if (alreadyProcessed) {\n // Keep existing processed columns\n base.columns = existingCols as ColumnConfig<T>[];\n } else {\n base.columns = columns;\n }\n } else {\n // No new columns computed, but preserve existing if processed\n const existingCols = this.#effectiveConfig.columns as ColumnInternal<T>[] | undefined;\n if (existingCols?.some((c) => c.__compiledView || c.__compiledEditor)) {\n base.columns = existingCols as ColumnConfig<T>[];\n }\n }\n\n // Individual prop overrides (behavioral)\n if (this.#fitMode) base.fitMode = this.#fitMode;\n if (!base.fitMode) base.fitMode = 'stretch';\n if (this.#editOn) base.editOn = this.#editOn;\n\n // Apply rowHeight from config if specified\n if (base.rowHeight && base.rowHeight > 0) {\n this._virtualization.rowHeight = base.rowHeight;\n }\n\n // Store columnState from gridConfig if not already set\n if (base.columnState && !this.#initialColumnState) {\n this.#initialColumnState = base.columnState;\n }\n\n this.#effectiveConfig = base;\n // Note: _columns is a getter/setter for effectiveConfig.columns\n // #getColumnConfiguration() populates it, and we preserve those processed columns above\n // Plugins (like ReorderPlugin) modify effectiveConfig.columns via the _columns setter\n\n // If fixed mode and width not specified: assign default 80px\n if (base.fitMode === 'fixed') {\n this._columns.forEach((c) => {\n if (c.width == null) (c as ColumnConfig<T>).width = 80;\n });\n }\n }\n\n // ---------------- Delegate Wrappers ----------------\n #renderVisibleRows(start: number, end: number, epoch = this.__rowRenderEpoch): void {\n // Use cached hook to avoid creating closures on every render (hot path optimization)\n if (!this.#renderRowHook) {\n this.#renderRowHook = (row: any, rowEl: HTMLElement, rowIndex: number): boolean => {\n return this.#pluginManager?.renderRow(row, rowEl, rowIndex) ?? false;\n };\n }\n renderVisibleRows(this as any, start, end, epoch, this.#renderRowHook);\n }\n\n // ---------------- Core Helpers ----------------\n #setup(): void {\n if (!this.isConnected) return;\n if (!this._headerRowEl || !this._bodyEl) {\n return;\n }\n\n // Seed effectiveConfig.columns from config sources before getColumnConfiguration\n // This ensures columns from gridConfig/columns prop are available for merging with light DOM\n // Preserve hidden state from existing columns (visibility is runtime state)\n const configCols = (this.#gridConfig?.columns || this.#columns || []) as ColumnConfig<T>[];\n if (configCols.length) {\n // Preserve hidden state from existing effectiveConfig.columns\n const existingHiddenMap = new Map(this._columns.filter((c) => c.hidden).map((c) => [c.field, true]));\n const seeded = configCols.map((c) => ({\n ...c,\n hidden: existingHiddenMap.get(c.field) ?? c.hidden,\n }));\n this._columns = seeded as ColumnInternal<T>[];\n }\n\n getColumnConfiguration(this);\n this.#mergeEffectiveConfig();\n this.#updatePluginConfigs(); // Sync plugin configs (including auto-detection) before processing\n\n // Store base columns before plugin transformation (like #rows for row processing)\n this.#baseColumns = [...this._columns];\n\n this.#rebuildRowModel(); // Runs processRows hooks (must run before processColumns for tree plugin)\n this.#processColumns(); // Runs processColumns hooks\n\n // Apply initial column state (from gridConfig.columnState or columnState setter)\n if (this.#initialColumnState) {\n const state = this.#initialColumnState;\n this.#initialColumnState = undefined; // Clear to avoid re-applying\n this.#applyColumnStateInternal(state);\n }\n\n renderHeader(this);\n updateTemplate(this);\n this.refreshVirtualWindow(true);\n\n const mode = this.#effectiveConfig.fitMode;\n if (mode === 'fixed' && !this.__didInitialAutoSize) {\n requestAnimationFrame(() => autoSizeColumns(this));\n }\n\n // Ensure legacy inline grid styles are cleared from container\n if (this._bodyEl) {\n this._bodyEl.style.display = '';\n this._bodyEl.style.gridTemplateColumns = '';\n }\n\n // Run plugin afterRender hooks (column groups, sticky, etc.)\n queueMicrotask(() => this.#pluginManager?.afterRender());\n }\n\n /** Internal method to apply column state without triggering setup loop */\n #applyColumnStateInternal(state: GridColumnState): void {\n // Get all columns from effectiveConfig (single source of truth)\n const allCols = (this.#effectiveConfig.columns ?? []) as ColumnInternal<T>[];\n\n const plugins = (this.#pluginManager?.getAll() ?? []) as BaseGridPlugin[];\n applyColumnState(this, state, allCols, plugins);\n\n // Update hidden property on columns based on state\n for (const colState of state.columns) {\n const col = allCols.find((c) => c.field === colState.field);\n if (col) {\n col.hidden = !colState.visible;\n }\n }\n }\n\n #onScrollBatched(scrollTop: number): void {\n // Faux scrollbar pattern: content never scrolls, just update transforms\n // Old content stays visible until new transforms are applied\n this.refreshVirtualWindow(false);\n\n // Let plugins reapply visual state to recycled DOM elements\n this.#pluginManager?.onScrollRender();\n\n // Dispatch to plugins (using cached flag)\n if (this.#hasScrollPlugins) {\n const fauxScrollbar = this._virtualization.container;\n const scrollEvent: ScrollEvent = {\n scrollTop,\n scrollLeft: fauxScrollbar?.scrollLeft ?? 0,\n scrollHeight: fauxScrollbar?.scrollHeight ?? 0,\n scrollWidth: fauxScrollbar?.scrollWidth ?? 0,\n clientHeight: fauxScrollbar?.clientHeight ?? 0,\n clientWidth: fauxScrollbar?.clientWidth ?? 0,\n originalEvent: new Event('scroll'),\n };\n this.#pluginManager?.onScroll(scrollEvent);\n }\n }\n\n /**\n * Find the header row element in the shadow DOM.\n * Used by plugins that need to access header cells for styling or measurement.\n * @internal Plugin API\n */\n findHeaderRow(): HTMLElement {\n return this.#shadow.querySelector('.header-row') as HTMLElement;\n }\n\n /**\n * Find a rendered row element by its data row index.\n * Returns null if the row is not currently rendered (virtualized out of view).\n * Used by plugins that need to access specific row elements for styling or measurement.\n * @internal Plugin API\n * @param rowIndex - The data row index (not the DOM position)\n */\n findRenderedRowElement(rowIndex: number): HTMLElement | null {\n return (\n (Array.from(this._bodyEl.querySelectorAll('.data-grid-row')) as HTMLElement[]).find((r) => {\n const cell = r.querySelector('.cell[data-row]');\n return cell && Number(cell.getAttribute('data-row')) === rowIndex;\n }) || null\n );\n }\n\n /**\n * Dispatch a cell click event to the plugin system.\n * Returns true if any plugin handled the event.\n */\n _dispatchCellClick(event: MouseEvent, rowIndex: number, colIndex: number, cellEl: HTMLElement): boolean {\n const row = this._rows[rowIndex];\n const col = this._columns[colIndex];\n if (!row || !col) return false;\n\n const cellClickEvent: CellClickEvent = {\n row,\n rowIndex,\n colIndex,\n field: col.field,\n value: (row as any)[col.field],\n cellEl,\n originalEvent: event,\n };\n\n return this.#pluginManager?.onCellClick(cellClickEvent) ?? false;\n }\n\n /**\n * Dispatch a header click event to the plugin system.\n * Returns true if any plugin handled the event.\n */\n _dispatchHeaderClick(event: MouseEvent, colIndex: number, headerEl: HTMLElement): boolean {\n const col = this._columns[colIndex];\n if (!col) return false;\n\n const headerClickEvent: HeaderClickEvent = {\n colIndex,\n field: col.field,\n column: col,\n headerEl,\n originalEvent: event,\n };\n\n return this.#pluginManager?.onHeaderClick(headerClickEvent) ?? false;\n }\n\n /**\n * Dispatch a keyboard event to the plugin system.\n * Returns true if any plugin handled the event.\n */\n _dispatchKeyDown(event: KeyboardEvent): boolean {\n return this.#pluginManager?.onKeyDown(event) ?? false;\n }\n\n /**\n * Get horizontal scroll boundary offsets from plugins.\n * Used by keyboard navigation to ensure focused cells are fully visible\n * when plugins like pinned columns obscure part of the scroll area.\n */\n _getHorizontalScrollOffsets(\n rowEl?: HTMLElement,\n focusedCell?: HTMLElement,\n ): { left: number; right: number; skipScroll?: boolean } {\n return this.#pluginManager?.getHorizontalScrollOffsets(rowEl, focusedCell) ?? { left: 0, right: 0 };\n }\n\n /**\n * Query all plugins with a generic query and collect responses.\n * This enables inter-plugin communication without the core knowing plugin-specific concepts.\n * @internal Plugin API\n *\n * @example\n * // Check if any plugin vetoes moving a column\n * const responses = grid.queryPlugins<boolean>({ type: PLUGIN_QUERIES.CAN_MOVE_COLUMN, context: column });\n * const canMove = !responses.includes(false);\n */\n queryPlugins<T>(query: PluginQuery): T[] {\n return this.#pluginManager?.queryPlugins<T>(query) ?? [];\n }\n\n /**\n * Build a CellMouseEvent from a native MouseEvent.\n * Extracts cell/row information from the event target.\n */\n #buildCellMouseEvent(e: MouseEvent, type: 'mousedown' | 'mousemove' | 'mouseup'): CellMouseEvent {\n // For document-level events (mousemove/mouseup during drag), e.target won't be inside shadow DOM.\n // Use composedPath to find elements inside shadow roots, or fall back to elementFromPoint.\n let target: Element | null = null;\n\n // composedPath gives us the full path including shadow DOM elements\n const path = e.composedPath?.() as Element[] | undefined;\n if (path && path.length > 0) {\n target = path[0];\n } else {\n target = e.target as Element;\n }\n\n // If target is still not inside our shadow root (e.g., for document-level events),\n // use elementFromPoint to find the actual element under the mouse\n if (target && !this.#shadow.contains(target)) {\n const elAtPoint = this.#shadow.elementFromPoint(e.clientX, e.clientY);\n if (elAtPoint) {\n target = elAtPoint;\n }\n }\n\n // Cells have data-col and data-row attributes\n const cellEl = target?.closest?.('[data-col]') as HTMLElement | null;\n const rowEl = target?.closest?.('.data-grid-row') as HTMLElement | null;\n const headerEl = target?.closest?.('.header-row') as HTMLElement | null;\n\n let rowIndex: number | undefined;\n let colIndex: number | undefined;\n let row: T | undefined;\n let field: string | undefined;\n let value: unknown;\n let column: any;\n\n if (cellEl) {\n // Get indices from cell attributes\n rowIndex = parseInt(cellEl.getAttribute('data-row') ?? '-1', 10);\n colIndex = parseInt(cellEl.getAttribute('data-col') ?? '-1', 10);\n if (rowIndex >= 0 && colIndex >= 0) {\n row = this._rows[rowIndex];\n column = this._columns[colIndex];\n field = column?.field;\n value = row && field ? (row as any)[field] : undefined;\n }\n }\n\n return {\n type,\n row,\n rowIndex: rowIndex !== undefined && rowIndex >= 0 ? rowIndex : undefined,\n colIndex: colIndex !== undefined && colIndex >= 0 ? colIndex : undefined,\n field,\n value,\n column,\n originalEvent: e,\n cellElement: cellEl ?? undefined,\n rowElement: rowEl ?? undefined,\n isHeader: !!headerEl,\n cell:\n rowIndex !== undefined && colIndex !== undefined && rowIndex >= 0 && colIndex >= 0\n ? { row: rowIndex, col: colIndex }\n : undefined,\n };\n }\n\n /**\n * Handle mousedown events and dispatch to plugin system.\n */\n #handleMouseDown(e: MouseEvent): void {\n const event = this.#buildCellMouseEvent(e, 'mousedown');\n const handled = this.#pluginManager?.onCellMouseDown(event) ?? false;\n\n // If any plugin handled mousedown, start tracking for drag\n if (handled) {\n this.#isDragging = true;\n }\n }\n\n /**\n * Handle mousemove events (only when dragging).\n */\n #handleMouseMove(e: MouseEvent): void {\n if (!this.#isDragging) return;\n\n const event = this.#buildCellMouseEvent(e, 'mousemove');\n this.#pluginManager?.onCellMouseMove(event);\n }\n\n /**\n * Handle mouseup events.\n */\n #handleMouseUp(e: MouseEvent): void {\n if (!this.#isDragging) return;\n\n const event = this.#buildCellMouseEvent(e, 'mouseup');\n this.#pluginManager?.onCellMouseUp(event);\n this.#isDragging = false;\n }\n\n // API consumed by internal utils (rows.ts)\n get changedRows(): T[] {\n return Array.from(this._changedRowIndices).map((i) => this._rows[i]);\n }\n\n get changedRowIndices(): number[] {\n return Array.from(this._changedRowIndices);\n }\n\n async resetChangedRows(silent?: boolean): Promise<void> {\n this._changedRowIndices.clear();\n if (!silent) {\n this.#emit('changed-rows-reset', { rows: this.changedRows, indices: this.changedRowIndices });\n }\n this._rowPool.forEach((r) => r.classList.remove('changed'));\n }\n\n async beginBulkEdit(rowIndex: number): Promise<void> {\n // Check if any columns are editable - if not, skip edit mode entirely\n const hasEditableColumn = this._columns.some((col) => (col as ColumnInternal<T>).editable);\n if (!hasEditableColumn) return;\n\n const rowData = this._rows[rowIndex];\n startRowEdit(this, rowIndex, rowData);\n\n // Enter edit mode on all editable cells in the row (same as click/dblclick)\n const rowEl = this.findRenderedRowElement?.(rowIndex);\n if (rowEl) {\n Array.from(rowEl.children).forEach((cell, i) => {\n // Use visibleColumns to match the cell index - _columns may include hidden columns\n const col = this._visibleColumns[i] as ColumnInternal<T> | undefined;\n if (col?.editable) {\n const cellEl = cell as HTMLElement;\n if (!cellEl.classList.contains('editing')) {\n inlineEnterEdit(this as unknown as InternalGrid, rowData, rowIndex, col, cellEl);\n }\n }\n });\n\n // Focus the editor in the focused cell\n queueMicrotask(() => {\n const targetCell = rowEl.querySelector(`.cell[data-col=\"${this._focusCol}\"]`);\n if (targetCell?.classList.contains('editing')) {\n const editor = (targetCell as HTMLElement).querySelector(\n 'input,select,textarea,[contenteditable=\"true\"],[contenteditable=\"\"],[tabindex]:not([tabindex=\"-1\"])',\n ) as HTMLElement | null;\n try {\n editor?.focus();\n } catch {\n /* empty */\n }\n }\n });\n }\n }\n\n async commitActiveRowEdit(): Promise<void> {\n if (this._activeEditRows !== -1) {\n exitRowEdit(this, this._activeEditRows, false);\n }\n }\n\n async ready(): Promise<void> {\n return this.#readyPromise;\n }\n\n async forceLayout(): Promise<void> {\n this.#setup();\n await new Promise((r) => requestAnimationFrame(() => requestAnimationFrame(r)));\n }\n\n /** Public method: returns a frozen snapshot of the merged effective configuration */\n async getConfig(): Promise<Readonly<GridConfig<T>>> {\n return Object.freeze({ ...(this.#effectiveConfig || {}) });\n }\n\n // ---------------- Column Visibility API ----------------\n\n /**\n * Set the visibility of a column.\n * @param field - The field name of the column\n * @param visible - Whether the column should be visible\n * @returns True if visibility was changed, false if column not found or locked\n */\n setColumnVisible(field: string, visible: boolean): boolean {\n // Find the column in effectiveConfig.columns (includes hidden columns)\n const allCols = this.#effectiveConfig.columns as ColumnInternal<T>[] | undefined;\n const col = allCols?.find((c) => c.field === field);\n\n // If column not found, cannot change visibility\n if (!col) return false;\n\n // Check lockVisible - cannot hide locked columns\n if (!visible && col.lockVisible) return false;\n\n // Check if at least one column would remain visible\n if (!visible) {\n const currentVisible = (allCols ?? []).filter((c) => !c.hidden && c.field !== field).length;\n if (currentVisible === 0) return false;\n }\n\n const wasHidden = !!col.hidden;\n const willBeHidden = !visible;\n\n // Only refresh if visibility actually changed\n if (wasHidden !== willBeHidden) {\n // Update the hidden property on the column in effectiveConfig\n col.hidden = willBeHidden;\n\n // Emit event for consumer preference saving\n this.#emit('column-visibility', {\n field,\n visible,\n visibleColumns: (allCols ?? []).filter((c) => !c.hidden).map((c) => c.field),\n });\n\n // Clear row pool to force complete rebuild with new column count\n this._rowPool.length = 0;\n if (this._bodyEl) this._bodyEl.innerHTML = '';\n this.__rowRenderEpoch++;\n\n // Re-setup to rebuild columns with updated visibility\n this.#setup();\n\n // Trigger state change after visibility change\n this.requestStateChange();\n return true;\n }\n return false;\n }\n\n /**\n * Toggle the visibility of a column.\n * @param field - The field name of the column\n * @returns True if visibility was toggled, false if column not found or locked\n */\n toggleColumnVisibility(field: string): boolean {\n const allCols = this.#effectiveConfig.columns as ColumnInternal<T>[] | undefined;\n const col = allCols?.find((c) => c.field === field);\n const isCurrentlyHidden = !!col?.hidden;\n return this.setColumnVisible(field, isCurrentlyHidden);\n }\n\n /**\n * Check if a column is currently visible.\n * @param field - The field name of the column\n * @returns True if visible, false if hidden or not found\n */\n isColumnVisible(field: string): boolean {\n const allCols = this.#effectiveConfig.columns as ColumnInternal<T>[] | undefined;\n const col = allCols?.find((c) => c.field === field);\n return col ? !col.hidden : false;\n }\n\n /**\n * Show all columns.\n */\n showAllColumns(): void {\n const allCols = this.#effectiveConfig.columns as ColumnInternal<T>[] | undefined;\n const hasHidden = allCols?.some((c) => c.hidden);\n if (!hasHidden) return;\n\n // Clear hidden flag on all columns\n allCols?.forEach((c) => {\n c.hidden = false;\n });\n\n this.#emit('column-visibility', {\n visibleColumns: (allCols ?? []).map((c) => c.field),\n });\n\n // Clear row pool to force complete rebuild with new column count\n this._rowPool.length = 0;\n if (this._bodyEl) this._bodyEl.innerHTML = '';\n this.__rowRenderEpoch++;\n\n this.#setup();\n\n // Trigger state change after visibility change\n this.requestStateChange();\n }\n\n /**\n * Get list of all column fields (including hidden).\n * Returns columns reflecting current display order (after reordering).\n * Hidden columns are interleaved at their original relative positions.\n * @returns Array of all field names with their visibility status\n */\n getAllColumns(): Array<{ field: string; header: string; visible: boolean; lockVisible?: boolean }> {\n // effectiveConfig.columns is the single source of truth\n const allCols = (this.#effectiveConfig.columns ?? []) as ColumnInternal<T>[];\n\n // Return all columns with their current visibility state\n return allCols.map((c) => ({\n field: c.field,\n header: c.header || c.field,\n visible: !c.hidden,\n lockVisible: c.lockVisible,\n }));\n }\n\n /**\n * Reorder columns according to the specified field order.\n * This directly updates _columns in place without going through processColumns.\n * @param order - Array of field names in the desired order\n */\n setColumnOrder(order: string[]): void {\n if (!order.length) return;\n\n const columnMap = new Map<string, ColumnInternal<T>>(this._columns.map((c) => [c.field as string, c]));\n const reordered: ColumnInternal<T>[] = [];\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 this._columns = reordered;\n\n // Re-render with new order\n renderHeader(this);\n updateTemplate(this);\n this.refreshVirtualWindow(true);\n }\n\n /**\n * Get the current column order as an array of field names.\n * @returns Array of field names in display order\n */\n getColumnOrder(): string[] {\n return this._columns.map((c) => c.field);\n }\n\n // ---------------- Column State API ----------------\n\n /**\n * Get the current column state, including order, width, visibility, sort, and plugin state.\n * Returns a serializable object suitable for localStorage or database storage.\n */\n getColumnState(): GridColumnState {\n const plugins = this.#pluginManager?.getAll() ?? [];\n return collectColumnState(this, plugins as BaseGridPlugin[]);\n }\n\n /**\n * Set the column state, restoring order, width, visibility, sort, and plugin state.\n * Use this to restore previously saved column state.\n */\n set columnState(state: GridColumnState | undefined) {\n if (!state) return;\n\n // Store for use after initialization if called before ready\n this.#initialColumnState = state;\n\n // If already initialized, apply immediately\n if (this.#initialized) {\n this.#applyColumnState(state);\n }\n }\n\n /**\n * Get the current column state.\n */\n get columnState(): GridColumnState | undefined {\n return this.getColumnState();\n }\n\n /**\n * Apply column state internally.\n */\n #applyColumnState(state: GridColumnState): void {\n // Clear hidden flags before applying state\n const allCols = (this.#effectiveConfig.columns ?? []) as ColumnInternal<T>[];\n allCols.forEach((c) => {\n c.hidden = false;\n });\n\n this.#applyColumnStateInternal(state);\n\n // Re-setup to apply changes\n this.#setup();\n }\n\n /**\n * Request a state change event to be emitted.\n * Called internally after resize, reorder, visibility, or sort changes.\n * Plugins should call this after changing their state.\n * The event is debounced to avoid excessive events during drag operations.\n * @internal Plugin API\n */\n requestStateChange(): void {\n if (!this.#stateChangeHandler) {\n this.#stateChangeHandler = createStateChangeHandler(\n this,\n () => (this.#pluginManager?.getAll() ?? []) as BaseGridPlugin[],\n (state) => this.#emit('column-state-change', state),\n );\n }\n this.#stateChangeHandler();\n }\n\n /**\n * Reset column state to initial configuration.\n * Clears all user modifications (order, width, visibility, sort).\n */\n resetColumnState(): void {\n // Clear initial state\n this.#initialColumnState = undefined;\n\n // Clear hidden flag on all columns\n const allCols = (this.#effectiveConfig.columns ?? []) as ColumnInternal<T>[];\n allCols.forEach((c) => {\n c.hidden = false;\n });\n\n // Reset sort state\n this._sortState = null;\n this.__originalOrder = [];\n\n // Re-initialize columns from config\n this.#mergeEffectiveConfig();\n this.#setup();\n\n // Notify plugins to reset their state\n const plugins = (this.#pluginManager?.getAll() ?? []) as BaseGridPlugin[];\n for (const plugin of plugins) {\n if (plugin.applyColumnState) {\n // Pass empty state to indicate reset\n for (const col of this._columns) {\n plugin.applyColumnState(col.field, {\n field: col.field,\n order: 0,\n visible: true,\n });\n }\n }\n }\n\n // Emit state change\n this.requestStateChange();\n }\n\n // ---------------- Shell / Tool Panel API ----------------\n // These methods delegate to ShellController for implementation.\n // The controller encapsulates all tool panel logic while grid.ts\n // exposes the public API surface.\n\n /** Check if the tool panel is currently open. */\n get isToolPanelOpen(): boolean {\n return this.#shellController.isPanelOpen;\n }\n\n /**\n * Get the currently active tool panel ID, or null if none is open.\n * @deprecated Use isToolPanelOpen and expandedToolPanelSections instead.\n */\n get activeToolPanel(): string | null {\n return this.#shellController.activePanel;\n }\n\n /** Get the IDs of expanded accordion sections. */\n get expandedToolPanelSections(): string[] {\n return this.#shellController.expandedSections;\n }\n\n /** Open the tool panel (accordion view with all registered panels). */\n openToolPanel(): void {\n this.#shellController.openToolPanel();\n }\n\n /** Close the tool panel. */\n closeToolPanel(): void {\n this.#shellController.closeToolPanel();\n }\n\n /** Toggle the tool panel open/closed. */\n toggleToolPanel(): void {\n this.#shellController.toggleToolPanel();\n }\n\n /** Toggle an accordion section expanded/collapsed. */\n toggleToolPanelSection(sectionId: string): void {\n this.#shellController.toggleToolPanelSection(sectionId);\n }\n\n /** Get registered tool panel definitions. */\n getToolPanels(): ToolPanelDefinition[] {\n return this.#shellController.getToolPanels();\n }\n\n /** Register a custom tool panel (without creating a plugin). */\n registerToolPanel(panel: ToolPanelDefinition): void {\n this.#shellController.registerToolPanel(panel);\n }\n\n /** Unregister a custom tool panel. */\n unregisterToolPanel(panelId: string): void {\n this.#shellController.unregisterToolPanel(panelId);\n }\n\n /** Get registered header content definitions. */\n getHeaderContents(): HeaderContentDefinition[] {\n return this.#shellController.getHeaderContents();\n }\n\n /** Register custom header content (without creating a plugin). */\n registerHeaderContent(content: HeaderContentDefinition): void {\n this.#shellController.registerHeaderContent(content);\n }\n\n /** Unregister custom header content. */\n unregisterHeaderContent(contentId: string): void {\n this.#shellController.unregisterHeaderContent(contentId);\n }\n\n /** Get all registered toolbar buttons. */\n getToolbarButtons(): ToolbarButtonInfo[] {\n return this.#shellController.getToolbarButtons();\n }\n\n /** Register a custom toolbar button programmatically. */\n registerToolbarButton(button: ToolbarButtonConfig): void {\n this.#shellController.registerToolbarButton(button);\n }\n\n /** Unregister a custom toolbar button. */\n unregisterToolbarButton(buttonId: string): void {\n this.#shellController.unregisterToolbarButton(buttonId);\n }\n\n /** Enable/disable a toolbar button by ID. */\n setToolbarButtonDisabled(buttonId: string, disabled: boolean): void {\n this.#shellController.setToolbarButtonDisabled(buttonId, disabled);\n }\n\n /**\n * Re-parse light DOM shell elements and refresh shell header.\n * Call this after dynamically modifying <tbw-grid-header> children.\n */\n refreshShellHeader(): void {\n // Re-parse light DOM\n parseLightDomShell(this, this.#shellState);\n\n // Re-render the entire grid (shell structure may change)\n this.#render();\n this.#afterConnect();\n }\n\n // ---------------- Virtual Window ----------------\n /**\n * Core virtualization routine. Chooses between bypass (small datasets), grouped window rendering,\n * or standard row window rendering.\n * @internal Plugin API\n */\n refreshVirtualWindow(force = false): void {\n if (!this._bodyEl) return;\n\n const totalRows = this._rows.length;\n\n if (!this._virtualization.enabled) {\n this.#renderVisibleRows(0, totalRows);\n this.#pluginManager?.afterRender();\n return;\n }\n\n if (this._rows.length <= this._virtualization.bypassThreshold) {\n this._virtualization.start = 0;\n this._virtualization.end = totalRows;\n this._bodyEl.style.transform = 'translateY(0px)';\n this.#renderVisibleRows(0, totalRows, this.__rowRenderEpoch);\n if (this._virtualization.totalHeightEl) {\n // Account for horizontal scrollbar height even in bypass mode\n const scrollAreaEl = this.#shadow.querySelector('.tbw-scroll-area') as HTMLElement;\n const hScrollbarHeight = scrollAreaEl ? scrollAreaEl.offsetHeight - scrollAreaEl.clientHeight : 0;\n this._virtualization.totalHeightEl.style.height = `${totalRows * this._virtualization.rowHeight + hScrollbarHeight}px`;\n }\n // Set ARIA counts on inner grid element (not host, which may contain shell chrome)\n const innerGrid = this.#shadow.querySelector('.rows-body');\n innerGrid?.setAttribute('aria-rowcount', String(totalRows));\n innerGrid?.setAttribute('aria-colcount', String(this._visibleColumns.length));\n this.#pluginManager?.afterRender();\n return;\n }\n\n // --- Normal virtualization path with faux scrollbar pattern ---\n // Faux scrollbar provides scrollTop, viewport provides visible height\n const fauxScrollbar = this._virtualization.container ?? this;\n const viewportEl = this._virtualization.viewportEl ?? fauxScrollbar;\n const viewportHeight = viewportEl.clientHeight;\n const rowHeight = this._virtualization.rowHeight;\n const scrollTop = fauxScrollbar.scrollTop;\n\n // When plugins add extra height (e.g., expanded details), the scroll position\n // includes that extra height. We need to find the actual row at scrollTop\n // by iteratively accounting for cumulative extra heights.\n // This prevents jumping when scrolling past expanded content.\n let start = Math.floor(scrollTop / rowHeight);\n\n // Iteratively refine: the initial guess may be too high because scrollTop\n // includes extra heights from expanded rows before it. Adjust downward.\n let iterations = 0;\n const maxIterations = 10; // Prevent infinite loop\n while (iterations < maxIterations) {\n const extraHeightBefore = this.#pluginManager?.getExtraHeightBefore?.(start) ?? 0;\n const adjustedStart = Math.floor((scrollTop - extraHeightBefore) / rowHeight);\n if (adjustedStart >= start || adjustedStart < 0) break;\n start = adjustedStart;\n iterations++;\n }\n\n // Faux scrollbar pattern: calculate effective position for this start\n // With translateY(0), the first rendered row appears at viewport top\n // Round down to even number so DOM nth-child(even) always matches data row parity\n // This prevents zebra stripe flickering during scroll since rows shift in pairs\n start = start - (start % 2);\n if (start < 0) start = 0;\n\n // Allow plugins to extend the start index backwards\n // (e.g., to keep expanded detail rows visible as they scroll out)\n const pluginAdjustedStart = this.#pluginManager?.adjustVirtualStart(start, scrollTop, rowHeight);\n if (pluginAdjustedStart !== undefined && pluginAdjustedStart < start) {\n start = pluginAdjustedStart;\n // Re-apply even alignment after plugin adjustment\n start = start - (start % 2);\n if (start < 0) start = 0;\n }\n\n // Faux pattern buffer: render 2 extra rows below for smooth edge transition\n // This is smaller than traditional overscan since sub-pixel offset handles smoothness\n // +1 extra to account for the even-alignment above potentially showing 1 more row at top\n const visibleCount = Math.ceil(viewportHeight / rowHeight) + 3;\n let end = start + visibleCount;\n if (end > totalRows) end = totalRows;\n\n this._virtualization.start = start;\n this._virtualization.end = end;\n\n // Height spacer for scrollbar\n // Add 1 extra row height to account for even-alignment: when we round down\n // from odd to even start, we need extra scroll range to reveal the last row\n // Also add footer height: faux-vscroll is outside .tbw-scroll-area so it doesn't\n // shrink when footer is present - we need extra spacer to scroll past the footer\n const footerEl = this.#shadow.querySelector('.tbw-footer') as HTMLElement;\n const footerHeight = footerEl?.offsetHeight ?? 0;\n // Add extra height from plugins (e.g., expanded master-detail rows)\n // This ensures the scrollbar range accounts for all content including expanded details\n const pluginExtraHeight = this.#pluginManager?.getExtraHeight() ?? 0;\n // Add horizontal scrollbar height: when horizontal scrollbar is visible in .tbw-scroll-area,\n // it takes space at the bottom that the faux vertical scrollbar doesn't account for.\n // Detect by comparing offsetHeight (includes scrollbar) vs clientHeight (excludes scrollbar).\n const scrollAreaEl = this.#shadow.querySelector('.tbw-scroll-area') as HTMLElement;\n const hScrollbarHeight = scrollAreaEl ? scrollAreaEl.offsetHeight - scrollAreaEl.clientHeight : 0;\n if (this._virtualization.totalHeightEl) {\n this._virtualization.totalHeightEl.style.height = `${\n totalRows * rowHeight + rowHeight + footerHeight + pluginExtraHeight + hScrollbarHeight\n }px`;\n }\n\n // Smooth scroll: apply offset for fluid motion\n // Since start is even-aligned, offset is distance from that aligned position\n // This creates smooth sliding while preserving zebra stripe parity\n // Account for extra heights (expanded details) before the start row\n const extraHeightBeforeStart = this.#pluginManager?.getExtraHeightBefore?.(start) ?? 0;\n const subPixelOffset = -(scrollTop - start * rowHeight - extraHeightBeforeStart);\n this._bodyEl.style.transform = `translateY(${subPixelOffset}px)`;\n\n this.#renderVisibleRows(start, end, force ? ++this.__rowRenderEpoch : this.__rowRenderEpoch);\n\n // Set ARIA counts on inner grid element (not host, which may contain shell chrome)\n const innerGrid = this.#shadow.querySelector('.rows-body');\n innerGrid?.setAttribute('aria-rowcount', String(totalRows));\n innerGrid?.setAttribute('aria-colcount', String(this._visibleColumns.length));\n\n // Only run plugin afterRender hooks on force refresh (structural changes)\n // Skip on scroll-triggered renders for maximum performance\n if (force) {\n this.#pluginManager?.afterRender();\n }\n }\n\n // ---------------- Render ----------------\n #render(): void {\n // Parse light DOM shell elements before rendering\n parseLightDomShell(this, this.#shellState);\n\n // Get shell config\n const shellConfig = this.#effectiveConfig?.shell;\n\n // Determine if shell should be rendered\n const hasShell = shouldRenderShellHeader(shellConfig, this.#shellState);\n\n // Core grid content HTML\n // Uses faux scrollbar pattern (like AG Grid) for smooth virtualized scrolling:\n // - .tbw-grid-content: outer container (row layout: scroll-area + faux-vscroll)\n // - .tbw-scroll-area: horizontal scroll container (overflow-x: auto) - footer appends here\n // - .rows-body-wrapper: header + rows in column layout\n // - .faux-vscroll: vertical scrollbar at inline-end, sticky during horizontal scroll\n // - .rows-viewport: visible rows area (no scroll, overflow hidden)\n // - Scroll events come from faux scrollbar, content positioned via transforms\n // This prevents blank viewport during fast scroll - old content stays until new renders\n const gridContentHtml = `\n <div class=\"tbw-scroll-area\">\n <div class=\"rows-body-wrapper\">\n <div class=\"rows-body\" role=\"grid\">\n <div class=\"header\">\n <div class=\"header-row\" part=\"header-row\"></div>\n </div>\n <div class=\"rows-container\">\n <div class=\"rows-viewport\">\n <div class=\"rows\"></div>\n </div>\n </div>\n </div>\n </div>\n </div>\n <div class=\"faux-vscroll\">\n <div class=\"faux-vscroll-spacer\"></div>\n </div>\n `;\n\n if (hasShell) {\n // Build shell DOM structure\n const toolPanelIcon = this.#effectiveConfig?.icons?.toolPanel ?? DEFAULT_GRID_ICONS.toolPanel;\n const accordionIcons = {\n expand: this.#effectiveConfig?.icons?.expand ?? DEFAULT_GRID_ICONS.expand,\n collapse: this.#effectiveConfig?.icons?.collapse ?? DEFAULT_GRID_ICONS.collapse,\n };\n const shellHeaderHtml = renderShellHeader(shellConfig, this.#shellState, toolPanelIcon);\n const shellBodyHtml = renderShellBody(shellConfig, this.#shellState, gridContentHtml, accordionIcons);\n\n this.#shadow.innerHTML = `\n <div class=\"tbw-grid-root has-shell\">\n ${shellHeaderHtml}\n ${shellBodyHtml}\n </div>\n `;\n\n // Set up shell event listeners\n this.#setupShellListeners();\n\n // Mark shell as initialized\n this.#shellController.setInitialized(true);\n } else {\n // Build minimal DOM structure (no shell)\n // Wrap in .tbw-grid-content for consistent horizontal scroll behavior\n this.#shadow.innerHTML = `\n <div class=\"tbw-grid-root\">\n <div class=\"tbw-grid-content\">\n ${gridContentHtml}\n </div>\n </div>\n `;\n }\n }\n\n /**\n * Set up shell event listeners after render.\n */\n #setupShellListeners(): void {\n setupShellEventListeners(this.#shadow, this.#effectiveConfig?.shell, this.#shellState, {\n onPanelToggle: () => this.toggleToolPanel(),\n onSectionToggle: (sectionId: string) => this.toggleToolPanelSection(sectionId),\n onToolbarButtonClick: (buttonId) => this.#handleToolbarButtonClick(buttonId),\n });\n\n // Set up tool panel resize\n this.#resizeCleanup?.();\n this.#resizeCleanup = setupToolPanelResize(this.#shadow, this.#effectiveConfig?.shell, (width: number) => {\n // Update the CSS variable to persist the new width\n this.style.setProperty('--tbw-tool-panel-width', `${width}px`);\n });\n }\n\n /**\n * Handle toolbar button click (for config buttons with action).\n */\n #handleToolbarButtonClick(buttonId: string): void {\n // Check config buttons\n const configButtons = this.#effectiveConfig?.shell?.header?.toolbarButtons ?? [];\n const configBtn = configButtons.find((b) => b.id === buttonId);\n if (configBtn?.action) {\n configBtn.action();\n return;\n }\n\n // Check API-registered buttons\n const apiBtn = this.#shellState.toolbarButtons.get(buttonId);\n if (apiBtn?.action) {\n apiBtn.action();\n }\n }\n}\n\n// Self-registering custom element\nif (!customElements.get(DataGridElement.tagName)) {\n customElements.define(DataGridElement.tagName, DataGridElement);\n}\n\n// Type augmentation for querySelector/createElement\ndeclare global {\n interface HTMLElementTagNameMap {\n 'tbw-grid': DataGridElement;\n }\n}\n","/**\n * Base Grid Plugin Class\n *\n * All plugins extend this abstract class.\n * Plugins are instantiated per-grid and manage their own state.\n */\n\nimport type {\n ColumnConfig,\n ColumnState,\n GridPlugin,\n HeaderContentDefinition,\n IconValue,\n ToolPanelDefinition,\n} from '../types';\nimport { DEFAULT_GRID_ICONS } from '../types';\n\n// Forward declare to avoid circular imports\nexport interface GridElement {\n shadowRoot: ShadowRoot | null;\n rows: any[];\n columns: ColumnConfig[];\n gridConfig: any;\n /** Current focused row index */\n focusRow: number;\n /** Current focused column index */\n focusCol: number;\n /** AbortSignal that is aborted when the grid disconnects from the DOM */\n disconnectSignal: AbortSignal;\n requestRender(): void;\n requestAfterRender(): void;\n forceLayout(): Promise<void>;\n getPlugin<T extends BaseGridPlugin>(PluginClass: new (...args: any[]) => T): T | undefined;\n getPluginByName(name: string): BaseGridPlugin | undefined;\n dispatchEvent(event: Event): boolean;\n}\n\n/**\n * Keyboard modifier flags\n */\nexport interface KeyboardModifiers {\n ctrl?: boolean;\n shift?: boolean;\n alt?: boolean;\n meta?: boolean;\n}\n\n/**\n * Cell coordinates\n */\nexport interface CellCoords {\n row: number;\n col: number;\n}\n\n/**\n * Cell click event\n */\nexport interface CellClickEvent {\n rowIndex: number;\n colIndex: number;\n field: string;\n value: any;\n row: any;\n cellEl: HTMLElement;\n originalEvent: MouseEvent;\n}\n\n/**\n * Row click event\n */\nexport interface RowClickEvent {\n rowIndex: number;\n row: any;\n rowEl: HTMLElement;\n originalEvent: MouseEvent;\n}\n\n/**\n * Header click event\n */\nexport interface HeaderClickEvent {\n colIndex: number;\n field: string;\n column: ColumnConfig;\n headerEl: HTMLElement;\n originalEvent: MouseEvent;\n}\n\n/**\n * Scroll event\n */\nexport interface ScrollEvent {\n scrollTop: number;\n scrollLeft: number;\n scrollHeight: number;\n scrollWidth: number;\n clientHeight: number;\n clientWidth: number;\n originalEvent?: Event;\n}\n\n/**\n * Cell mouse event (for drag operations, selection, etc.)\n */\nexport interface CellMouseEvent {\n /** Event type: mousedown, mousemove, or mouseup */\n type: 'mousedown' | 'mousemove' | 'mouseup';\n /** Row index, undefined if not over a data cell */\n rowIndex?: number;\n /** Column index, undefined if not over a cell */\n colIndex?: number;\n /** Field name, undefined if not over a cell */\n field?: string;\n /** Cell value, undefined if not over a data cell */\n value?: unknown;\n /** Row data object, undefined if not over a data row */\n row?: unknown;\n /** Column configuration, undefined if not over a column */\n column?: ColumnConfig;\n /** The cell element, undefined if not over a cell */\n cellElement?: HTMLElement;\n /** The row element, undefined if not over a row */\n rowElement?: HTMLElement;\n /** Whether the event is over a header cell */\n isHeader: boolean;\n /** Cell coordinates if over a valid data cell */\n cell?: CellCoords;\n /** The original mouse event */\n originalEvent: MouseEvent;\n}\n\n/**\n * Context menu parameters\n */\nexport interface ContextMenuParams {\n x: number;\n y: number;\n rowIndex?: number;\n colIndex?: number;\n field?: string;\n value?: any;\n row?: any;\n column?: ColumnConfig;\n isHeader?: boolean;\n}\n\n/**\n * Context menu item (used by context-menu plugin query)\n */\nexport interface ContextMenuItem {\n id: string;\n label: string;\n icon?: string;\n disabled?: boolean;\n separator?: boolean;\n children?: ContextMenuItem[];\n action?: (params: ContextMenuParams) => void;\n}\n\n/**\n * Generic plugin query for inter-plugin communication.\n * Plugins can define their own query types as string constants\n * and respond to queries from other plugins.\n */\nexport interface PluginQuery<T = unknown> {\n /** Query type identifier (e.g., 'canMoveColumn', 'getContextMenuItems') */\n type: string;\n /** Query-specific context/parameters */\n context: T;\n}\n\n/**\n * Well-known plugin query types.\n * Plugins can define additional query types beyond these.\n */\nexport const PLUGIN_QUERIES = {\n /** Ask if a column can be moved. Context: ColumnConfig. Response: boolean | undefined */\n CAN_MOVE_COLUMN: 'canMoveColumn',\n /** Get context menu items. Context: ContextMenuParams. Response: ContextMenuItem[] */\n GET_CONTEXT_MENU_ITEMS: 'getContextMenuItems',\n} as const;\n\n/**\n * Cell render context for plugin cell renderers.\n * Provides full context including position and editing state.\n *\n * Note: This differs from the core `CellRenderContext` in types.ts which is\n * simpler and used for column view renderers. This version provides additional\n * context needed by plugins that register custom cell renderers.\n */\nexport interface PluginCellRenderContext {\n /** The cell value */\n value: any;\n /** The field/column key */\n field: string;\n /** The row data object */\n row: any;\n /** Row index in the data array */\n rowIndex: number;\n /** Column index */\n colIndex: number;\n /** Column configuration */\n column: ColumnConfig;\n /** Whether the cell is currently in edit mode */\n isEditing: boolean;\n}\n\n/**\n * Header render context for plugin header renderers.\n */\nexport interface PluginHeaderRenderContext {\n /** Column configuration */\n column: ColumnConfig;\n /** Column index */\n colIndex: number;\n}\n\n/**\n * Cell renderer function type for plugins.\n */\nexport type CellRenderer = (ctx: PluginCellRenderContext) => string | HTMLElement;\n\n/**\n * Header renderer function type for plugins.\n */\nexport type HeaderRenderer = (ctx: PluginHeaderRenderContext) => string | HTMLElement;\n\n/**\n * Cell editor interface for plugins.\n */\nexport interface CellEditor {\n create(ctx: PluginCellRenderContext, commitFn: (value: any) => void, cancelFn: () => void): HTMLElement;\n getValue?(element: HTMLElement): any;\n focus?(element: HTMLElement): void;\n}\n\n/**\n * Abstract base class for all grid plugins.\n *\n * @template TConfig - Configuration type for the plugin\n */\nexport abstract class BaseGridPlugin<TConfig = unknown> implements GridPlugin {\n /** Unique plugin identifier (derived from class name by default) */\n abstract readonly name: string;\n\n /** Plugin version - override in subclass if needed */\n readonly version: string = '1.0.0';\n\n /** CSS styles to inject into the grid's shadow DOM */\n readonly styles?: string;\n\n /** Custom cell renderers keyed by type name */\n readonly cellRenderers?: Record<string, CellRenderer>;\n\n /** Custom header renderers keyed by type name */\n readonly headerRenderers?: Record<string, HeaderRenderer>;\n\n /** Custom cell editors keyed by type name */\n readonly cellEditors?: Record<string, CellEditor>;\n\n /** The grid instance this plugin is attached to */\n protected grid!: GridElement;\n\n /** Plugin configuration - merged with defaults in attach() */\n protected config!: TConfig;\n\n /** User-provided configuration from constructor */\n private readonly userConfig: Partial<TConfig>;\n\n /**\n * Default configuration - subclasses should override this getter.\n * Note: This must be a getter (not property initializer) for proper inheritance\n * since property initializers run after parent constructor.\n */\n protected get defaultConfig(): Partial<TConfig> {\n return {};\n }\n\n constructor(config: Partial<TConfig> = {}) {\n this.userConfig = config;\n }\n\n /**\n * Called when the plugin is attached to a grid.\n * Override to set up event listeners, initialize state, etc.\n */\n attach(grid: GridElement): void {\n this.grid = grid;\n // Merge config here (after subclass construction is complete)\n this.config = { ...this.defaultConfig, ...this.userConfig } as TConfig;\n }\n\n /**\n * Called when the plugin is detached from a grid.\n * Override to clean up event listeners, timers, etc.\n */\n detach(): void {\n // Override in subclass\n }\n\n /**\n * Get another plugin instance from the same grid.\n * Use for inter-plugin communication.\n */\n protected getPlugin<T extends BaseGridPlugin>(PluginClass: new (...args: any[]) => T): T | undefined {\n return this.grid?.getPlugin(PluginClass);\n }\n\n /**\n * Emit a custom event from the grid.\n */\n protected emit<T>(eventName: string, detail: T): void {\n this.grid?.dispatchEvent?.(new CustomEvent(eventName, { detail, bubbles: true }));\n }\n\n /**\n * Request a re-render of the grid.\n */\n protected requestRender(): void {\n this.grid?.requestRender?.();\n }\n\n /**\n * Request a lightweight style update without rebuilding DOM.\n * Use this instead of requestRender() when only CSS classes need updating.\n */\n protected requestAfterRender(): void {\n this.grid?.requestAfterRender?.();\n }\n\n /**\n * Get the current rows from the grid.\n */\n protected get rows(): any[] {\n return this.grid?.rows ?? [];\n }\n\n /**\n * Get the original unfiltered/unprocessed rows from the grid.\n * Use this when you need all source data regardless of active filters.\n */\n protected get sourceRows(): any[] {\n return (this.grid as any)?.sourceRows ?? [];\n }\n\n /**\n * Get the current columns from the grid.\n */\n protected get columns(): ColumnConfig[] {\n return this.grid?.columns ?? [];\n }\n\n /**\n * Get only visible columns from the grid (excludes hidden).\n * Use this for rendering that needs to match the grid template.\n */\n protected get visibleColumns(): ColumnConfig[] {\n return (this.grid as any)?.visibleColumns ?? [];\n }\n\n /**\n * Get the shadow root of the grid.\n */\n protected get shadowRoot(): ShadowRoot | null {\n return this.grid?.shadowRoot ?? null;\n }\n\n /**\n * Get the disconnect signal for event listener cleanup.\n * This signal is aborted when the grid disconnects from the DOM.\n * Use this when adding event listeners that should be cleaned up automatically.\n *\n * Best for:\n * - Document/window-level listeners added in attach()\n * - Listeners on the grid element itself\n * - Any listener that should persist across renders\n *\n * Not needed for:\n * - Listeners on elements created in afterRender() (removed with element)\n *\n * @example\n * element.addEventListener('click', handler, { signal: this.disconnectSignal });\n * document.addEventListener('keydown', handler, { signal: this.disconnectSignal });\n */\n protected get disconnectSignal(): AbortSignal {\n return this.grid?.disconnectSignal;\n }\n\n /**\n * Get the grid-level icons configuration.\n * Returns merged icons (user config + defaults).\n */\n protected get gridIcons(): typeof DEFAULT_GRID_ICONS {\n const userIcons = this.grid?.gridConfig?.icons ?? {};\n return { ...DEFAULT_GRID_ICONS, ...userIcons };\n }\n\n /**\n * Resolve an icon value to string or HTMLElement.\n * Checks plugin config first, then grid-level icons, then defaults.\n *\n * @param iconKey - The icon key in GridIcons (e.g., 'expand', 'collapse')\n * @param pluginOverride - Optional plugin-level override\n * @returns The resolved icon value\n */\n protected resolveIcon(iconKey: keyof typeof DEFAULT_GRID_ICONS, pluginOverride?: IconValue): IconValue {\n // Plugin override takes precedence\n if (pluginOverride !== undefined) {\n return pluginOverride;\n }\n // Then grid-level config\n return this.gridIcons[iconKey];\n }\n\n /**\n * Set an icon value on an element.\n * Handles both string (text/HTML) and HTMLElement values.\n *\n * @param element - The element to set the icon on\n * @param icon - The icon value (string or HTMLElement)\n */\n protected setIcon(element: HTMLElement, icon: IconValue): void {\n if (typeof icon === 'string') {\n element.innerHTML = icon;\n } else if (icon instanceof HTMLElement) {\n element.innerHTML = '';\n element.appendChild(icon.cloneNode(true));\n }\n }\n\n /**\n * Log a warning message.\n */\n protected warn(message: string): void {\n console.warn(`[tbw-grid:${this.name}] ${message}`);\n }\n\n // #region Lifecycle Hooks\n\n /**\n * Transform rows before rendering.\n * Called during each render cycle before rows are rendered to the DOM.\n * Use this to filter, sort, or add computed properties to rows.\n *\n * @param rows - The current rows array (readonly to encourage returning a new array)\n * @returns The modified rows array to render\n *\n * @example\n * ```ts\n * processRows(rows: readonly any[]): any[] {\n * // Filter out hidden rows\n * return rows.filter(row => !row._hidden);\n * }\n * ```\n *\n * @example\n * ```ts\n * processRows(rows: readonly any[]): any[] {\n * // Add computed properties\n * return rows.map(row => ({\n * ...row,\n * _fullName: `${row.firstName} ${row.lastName}`\n * }));\n * }\n * ```\n */\n processRows?(rows: readonly any[]): any[];\n\n /**\n * Transform columns before rendering.\n * Called during each render cycle before column headers and cells are rendered.\n * Use this to add, remove, or modify column definitions.\n *\n * @param columns - The current columns array (readonly to encourage returning a new array)\n * @returns The modified columns array to render\n *\n * @example\n * ```ts\n * processColumns(columns: readonly ColumnConfig[]): ColumnConfig[] {\n * // Add a selection checkbox column\n * return [\n * { field: '_select', header: '', width: 40 },\n * ...columns\n * ];\n * }\n * ```\n */\n processColumns?(columns: readonly ColumnConfig[]): ColumnConfig[];\n\n /**\n * Called before each render cycle begins.\n * Use this to prepare state or cache values needed during rendering.\n *\n * @example\n * ```ts\n * beforeRender(): void {\n * this.visibleRowCount = this.calculateVisibleRows();\n * }\n * ```\n */\n beforeRender?(): void;\n\n /**\n * Called after each render cycle completes.\n * Use this for DOM manipulation, adding event listeners to rendered elements,\n * or applying visual effects like selection highlights.\n *\n * @example\n * ```ts\n * afterRender(): void {\n * // Apply selection styling to rendered rows\n * const rows = this.shadowRoot?.querySelectorAll('.data-row');\n * rows?.forEach((row, i) => {\n * row.classList.toggle('selected', this.selectedRows.has(i));\n * });\n * }\n * ```\n */\n afterRender?(): void;\n\n /**\n * Called after scroll-triggered row rendering completes.\n * This is a lightweight hook for applying visual state to recycled DOM elements.\n * Use this instead of afterRender when you need to reapply styling during scroll.\n *\n * Performance note: This is called frequently during scroll. Keep implementation fast.\n *\n * @example\n * ```ts\n * onScrollRender(): void {\n * // Reapply selection state to visible cells\n * this.applySelectionToVisibleCells();\n * }\n * ```\n */\n onScrollRender?(): void;\n\n /**\n * Return extra height contributed by this plugin (e.g., expanded detail rows).\n * Used to adjust scrollbar height calculations for virtualization.\n *\n * @returns Total extra height in pixels\n *\n * @example\n * ```ts\n * getExtraHeight(): number {\n * return this.expandedRows.size * this.detailHeight;\n * }\n * ```\n */\n getExtraHeight?(): number;\n\n /**\n * Return extra height that appears before a given row index.\n * Used by virtualization to correctly calculate scroll positions when\n * there's variable height content (like expanded detail rows) above the viewport.\n *\n * @param beforeRowIndex - The row index to calculate extra height before\n * @returns Extra height in pixels that appears before this row\n *\n * @example\n * ```ts\n * getExtraHeightBefore(beforeRowIndex: number): number {\n * let height = 0;\n * for (const expandedRowIndex of this.expandedRowIndices) {\n * if (expandedRowIndex < beforeRowIndex) {\n * height += this.getDetailHeight(expandedRowIndex);\n * }\n * }\n * return height;\n * }\n * ```\n */\n getExtraHeightBefore?(beforeRowIndex: number): number;\n\n /**\n * Adjust the virtualization start index to render additional rows before the visible range.\n * Use this when expanded content (like detail rows) needs its parent row to remain rendered\n * even when the parent row itself has scrolled above the viewport.\n *\n * @param start - The calculated start row index\n * @param scrollTop - The current scroll position\n * @param rowHeight - The height of a single row\n * @returns The adjusted start index (lower than or equal to original start)\n *\n * @example\n * ```ts\n * adjustVirtualStart(start: number, scrollTop: number, rowHeight: number): number {\n * // If row 5 is expanded and scrolled partially, keep it rendered\n * for (const expandedRowIndex of this.expandedRowIndices) {\n * const expandedRowTop = expandedRowIndex * rowHeight;\n * const expandedRowBottom = expandedRowTop + rowHeight + this.detailHeight;\n * if (expandedRowBottom > scrollTop && expandedRowIndex < start) {\n * return expandedRowIndex;\n * }\n * }\n * return start;\n * }\n * ```\n */\n adjustVirtualStart?(start: number, scrollTop: number, rowHeight: number): number;\n\n /**\n * Render a custom row, bypassing the default row rendering.\n * Use this for special row types like group headers, detail rows, or footers.\n *\n * @param row - The row data object\n * @param rowEl - The row DOM element to render into\n * @param rowIndex - The index of the row in the data array\n * @returns `true` if the plugin handled rendering (prevents default), `false`/`void` for default rendering\n *\n * @example\n * ```ts\n * renderRow(row: any, rowEl: HTMLElement, rowIndex: number): boolean | void {\n * if (row._isGroupHeader) {\n * rowEl.innerHTML = `<div class=\"group-header\">${row._groupLabel}</div>`;\n * return true; // Handled - skip default rendering\n * }\n * // Return void to let default rendering proceed\n * }\n * ```\n */\n renderRow?(row: any, rowEl: HTMLElement, rowIndex: number): boolean | void;\n\n // #endregion\n\n // #region Inter-Plugin Communication\n\n /**\n * Handle queries from other plugins.\n * This is the generic mechanism for inter-plugin communication.\n * Plugins can respond to well-known query types or define their own.\n *\n * @param query - The query object with type and context\n * @returns Query-specific response, or undefined if not handling this query\n *\n * @example\n * ```ts\n * onPluginQuery(query: PluginQuery): unknown {\n * switch (query.type) {\n * case PLUGIN_QUERIES.CAN_MOVE_COLUMN:\n * // Prevent moving pinned columns\n * const column = query.context as ColumnConfig;\n * if (column.sticky === 'left' || column.sticky === 'right') {\n * return false;\n * }\n * break;\n * case PLUGIN_QUERIES.GET_CONTEXT_MENU_ITEMS:\n * const params = query.context as ContextMenuParams;\n * return [{ id: 'my-action', label: 'My Action', action: () => {} }];\n * }\n * }\n * ```\n */\n onPluginQuery?(query: PluginQuery): unknown;\n\n // #endregion\n\n // #region Interaction Hooks\n\n /**\n * Handle keyboard events on the grid.\n * Called when a key is pressed while the grid or a cell has focus.\n *\n * @param event - The native KeyboardEvent\n * @returns `true` to prevent default behavior and stop propagation, `false`/`void` to allow default\n *\n * @example\n * ```ts\n * onKeyDown(event: KeyboardEvent): boolean | void {\n * // Handle Ctrl+A for select all\n * if (event.ctrlKey && event.key === 'a') {\n * this.selectAllRows();\n * return true; // Prevent default browser select-all\n * }\n * }\n * ```\n */\n onKeyDown?(event: KeyboardEvent): boolean | void;\n\n /**\n * Handle cell click events.\n * Called when a data cell is clicked (not headers).\n *\n * @param event - Cell click event with row/column context\n * @returns `true` to prevent default behavior and stop propagation, `false`/`void` to allow default\n *\n * @example\n * ```ts\n * onCellClick(event: CellClickEvent): boolean | void {\n * if (event.field === '_select') {\n * this.toggleRowSelection(event.rowIndex);\n * return true; // Handled\n * }\n * }\n * ```\n */\n onCellClick?(event: CellClickEvent): boolean | void;\n\n /**\n * Handle row click events.\n * Called when any part of a data row is clicked.\n * Note: This is called in addition to onCellClick, not instead of.\n *\n * @param event - Row click event with row context\n * @returns `true` to prevent default behavior and stop propagation, `false`/`void` to allow default\n *\n * @example\n * ```ts\n * onRowClick(event: RowClickEvent): boolean | void {\n * if (this.config.mode === 'row') {\n * this.selectRow(event.rowIndex, event.originalEvent);\n * return true;\n * }\n * }\n * ```\n */\n onRowClick?(event: RowClickEvent): boolean | void;\n\n /**\n * Handle header click events.\n * Called when a column header is clicked. Commonly used for sorting.\n *\n * @param event - Header click event with column context\n * @returns `true` to prevent default behavior and stop propagation, `false`/`void` to allow default\n *\n * @example\n * ```ts\n * onHeaderClick(event: HeaderClickEvent): boolean | void {\n * if (event.column.sortable !== false) {\n * this.toggleSort(event.field);\n * return true;\n * }\n * }\n * ```\n */\n onHeaderClick?(event: HeaderClickEvent): boolean | void;\n\n /**\n * Handle scroll events on the grid viewport.\n * Called during scrolling. Note: This may be called frequently; debounce if needed.\n *\n * @param event - Scroll event with scroll position and viewport dimensions\n *\n * @example\n * ```ts\n * onScroll(event: ScrollEvent): void {\n * // Update sticky column positions\n * this.updateStickyPositions(event.scrollLeft);\n * }\n * ```\n */\n onScroll?(event: ScrollEvent): void;\n\n /**\n * Handle cell mousedown events.\n * Used for initiating drag operations like range selection or column resize.\n *\n * @param event - Mouse event with cell context\n * @returns `true` to indicate drag started (prevents text selection), `false`/`void` otherwise\n *\n * @example\n * ```ts\n * onCellMouseDown(event: CellMouseEvent): boolean | void {\n * if (event.rowIndex !== undefined && this.config.mode === 'range') {\n * this.startDragSelection(event.rowIndex, event.colIndex);\n * return true; // Prevent text selection\n * }\n * }\n * ```\n */\n onCellMouseDown?(event: CellMouseEvent): boolean | void;\n\n /**\n * Handle cell mousemove events during drag operations.\n * Only called when a drag is in progress (after mousedown returned true).\n *\n * @param event - Mouse event with current cell context\n * @returns `true` to continue handling the drag, `false`/`void` otherwise\n *\n * @example\n * ```ts\n * onCellMouseMove(event: CellMouseEvent): boolean | void {\n * if (this.isDragging && event.rowIndex !== undefined) {\n * this.extendSelection(event.rowIndex, event.colIndex);\n * return true;\n * }\n * }\n * ```\n */\n onCellMouseMove?(event: CellMouseEvent): boolean | void;\n\n /**\n * Handle cell mouseup events to end drag operations.\n *\n * @param event - Mouse event with final cell context\n * @returns `true` if drag was finalized, `false`/`void` otherwise\n *\n * @example\n * ```ts\n * onCellMouseUp(event: CellMouseEvent): boolean | void {\n * if (this.isDragging) {\n * this.finalizeDragSelection();\n * this.isDragging = false;\n * return true;\n * }\n * }\n * ```\n */\n onCellMouseUp?(event: CellMouseEvent): boolean | void;\n\n // Note: Context menu items are now provided via onPluginQuery with PLUGIN_QUERIES.GET_CONTEXT_MENU_ITEMS\n // This keeps the core decoupled from the context-menu plugin specifics.\n\n // #endregion\n\n // #region Column State Hooks\n\n /**\n * Contribute plugin-specific state for a column.\n * Called by the grid when collecting column state for serialization.\n * Plugins can add their own properties to the column state.\n *\n * @param field - The field name of the column\n * @returns Partial column state with plugin-specific properties, or undefined if no state to contribute\n *\n * @example\n * ```ts\n * getColumnState(field: string): Partial<ColumnState> | undefined {\n * const filterModel = this.filterModels.get(field);\n * if (filterModel) {\n * // Uses module augmentation to add filter property to ColumnState\n * return { filter: filterModel } as Partial<ColumnState>;\n * }\n * return undefined;\n * }\n * ```\n */\n getColumnState?(field: string): Partial<ColumnState> | undefined;\n\n /**\n * Apply plugin-specific state to a column.\n * Called by the grid when restoring column state from serialized data.\n * Plugins should restore their internal state based on the provided state.\n *\n * @param field - The field name of the column\n * @param state - The column state to apply (may contain plugin-specific properties)\n *\n * @example\n * ```ts\n * applyColumnState(field: string, state: ColumnState): void {\n * // Check for filter property added via module augmentation\n * const filter = (state as any).filter;\n * if (filter) {\n * this.filterModels.set(field, filter);\n * this.applyFilter();\n * }\n * }\n * ```\n */\n applyColumnState?(field: string, state: ColumnState): void;\n\n // #endregion\n\n // #region Scroll Boundary Hooks\n\n /**\n * Report horizontal scroll boundary offsets for this plugin.\n * Plugins that obscure part of the scroll area (e.g., pinned/sticky columns)\n * should return how much space they occupy on each side.\n * The keyboard navigation uses this to ensure focused cells are fully visible.\n *\n * @param rowEl - The row element (optional, for calculating widths from rendered cells)\n * @param focusedCell - The currently focused cell element (optional, to determine if scrolling should be skipped)\n * @returns Object with left/right pixel offsets and optional skipScroll flag, or undefined if plugin has no offsets\n *\n * @example\n * ```ts\n * getHorizontalScrollOffsets(rowEl?: HTMLElement, focusedCell?: HTMLElement): { left: number; right: number; skipScroll?: boolean } | undefined {\n * // Calculate total width of left-pinned columns\n * const leftCells = rowEl?.querySelectorAll('.sticky-left') ?? [];\n * let left = 0;\n * leftCells.forEach(el => { left += (el as HTMLElement).offsetWidth; });\n * // Skip scroll if focused cell is pinned (always visible)\n * const skipScroll = focusedCell?.classList.contains('sticky-left');\n * return { left, right: 0, skipScroll };\n * }\n * ```\n */\n getHorizontalScrollOffsets?(\n rowEl?: HTMLElement,\n focusedCell?: HTMLElement,\n ): { left: number; right: number; skipScroll?: boolean } | undefined;\n\n // #endregion\n\n // #region Shell Integration Hooks\n\n /**\n * Register a tool panel for this plugin.\n * Return undefined if plugin has no tool panel.\n * The shell will create a toolbar toggle button and render the panel content\n * when the user opens the panel.\n *\n * @returns Tool panel definition, or undefined if plugin has no panel\n *\n * @example\n * ```ts\n * getToolPanel(): ToolPanelDefinition | undefined {\n * return {\n * id: 'columns',\n * title: 'Columns',\n * icon: '☰',\n * tooltip: 'Show/hide columns',\n * order: 10,\n * render: (container) => {\n * this.renderColumnList(container);\n * return () => this.cleanup();\n * },\n * };\n * }\n * ```\n */\n getToolPanel?(): ToolPanelDefinition | undefined;\n\n /**\n * Register content for the shell header center section.\n * Return undefined if plugin has no header content.\n * Examples: search input, selection summary, status indicators.\n *\n * @returns Header content definition, or undefined if plugin has no header content\n *\n * @example\n * ```ts\n * getHeaderContent(): HeaderContentDefinition | undefined {\n * return {\n * id: 'quick-filter',\n * order: 10,\n * render: (container) => {\n * const input = document.createElement('input');\n * input.type = 'text';\n * input.placeholder = 'Search...';\n * input.addEventListener('input', this.handleInput);\n * container.appendChild(input);\n * return () => input.removeEventListener('input', this.handleInput);\n * },\n * };\n * }\n * ```\n */\n getHeaderContent?(): HeaderContentDefinition | undefined;\n\n // #endregion\n}\n","/**\n * Grid DOM Constants\n *\n * Centralized constants for CSS classes, data attributes, and selectors\n * used throughout the grid. Use these instead of magic strings.\n *\n * Note: Some constants here are used by plugins but defined in core because:\n * 1. The core CSS needs to style these elements (e.g., sticky positioning)\n * 2. Multiple plugins may share the same class names\n *\n * Plugins can define their own additional constants and export them.\n * See each plugin's index.ts for plugin-specific exports.\n */\n\n// #region CSS Classes\n\n/**\n * CSS class names used in the grid's shadow DOM.\n * Use these when adding/removing classes or querying elements.\n *\n * Classes are organized by:\n * - Core: Used by the grid core for structure and basic functionality\n * - Shared: Used by multiple features/plugins, styled by core CSS\n */\nexport const GridClasses = {\n // ─── Core Structure ───────────────────────────────────────────────\n ROOT: 'tbw-grid-root',\n HEADER: 'header',\n HEADER_ROW: 'header-row',\n HEADER_CELL: 'header-cell',\n\n // Body structure\n ROWS_VIEWPORT: 'rows-viewport',\n ROWS_SPACER: 'rows-spacer',\n ROWS_CONTAINER: 'rows',\n\n // Row elements\n DATA_ROW: 'data-row',\n GROUP_ROW: 'group-row',\n\n // Cell elements\n DATA_CELL: 'data-cell',\n\n // ─── Core States ──────────────────────────────────────────────────\n SELECTED: 'selected',\n FOCUSED: 'focused',\n EDITING: 'editing',\n EXPANDED: 'expanded',\n COLLAPSED: 'collapsed',\n DRAGGING: 'dragging',\n RESIZING: 'resizing',\n\n // Sorting (core feature)\n SORTABLE: 'sortable',\n SORTED_ASC: 'sorted-asc',\n SORTED_DESC: 'sorted-desc',\n\n // Visibility\n HIDDEN: 'hidden',\n\n // ─── Shared Classes (used by plugins, styled by core CSS) ────────\n // These are defined here because core CSS provides the base styling.\n // Plugins apply these classes; core CSS defines how they look.\n\n // Sticky positioning (PinnedColumnsPlugin applies, core CSS styles)\n STICKY_LEFT: 'sticky-left',\n STICKY_RIGHT: 'sticky-right',\n\n // Pinned rows (PinnedRowsPlugin applies, core CSS styles)\n PINNED_TOP: 'pinned-top',\n PINNED_BOTTOM: 'pinned-bottom',\n\n // Tree structure (TreePlugin applies, core CSS styles)\n TREE_TOGGLE: 'tree-toggle',\n TREE_INDENT: 'tree-indent',\n\n // Grouping (GroupingRowsPlugin applies, core CSS styles)\n GROUP_TOGGLE: 'group-toggle',\n GROUP_LABEL: 'group-label',\n GROUP_COUNT: 'group-count',\n\n // Selection (SelectionPlugin applies, core CSS styles)\n RANGE_SELECTION: 'range-selection',\n SELECTION_OVERLAY: 'selection-overlay',\n} as const;\n\n// #endregion\n\n// #region Data Attributes\n\n/**\n * Data attribute names used on grid elements.\n * Use these when getting/setting data attributes.\n */\nexport const GridDataAttrs = {\n // ─── Core Attributes ──────────────────────────────────────────────\n ROW_INDEX: 'data-row-index',\n COL_INDEX: 'data-col-index',\n FIELD: 'data-field',\n\n // ─── Shared Attributes (used by plugins) ──────────────────────────\n GROUP_KEY: 'data-group-key', // GroupingRowsPlugin\n TREE_LEVEL: 'data-tree-level', // TreePlugin\n STICKY: 'data-sticky', // PinnedColumnsPlugin\n} as const;\n\n// #endregion\n\n// #region Selectors\n\n/**\n * Common CSS selectors for querying grid elements.\n * Built from the class constants for consistency.\n */\nexport const GridSelectors = {\n ROOT: `.${GridClasses.ROOT}`,\n HEADER: `.${GridClasses.HEADER}`,\n HEADER_ROW: `.${GridClasses.HEADER_ROW}`,\n HEADER_CELL: `.${GridClasses.HEADER_CELL}`,\n ROWS_VIEWPORT: `.${GridClasses.ROWS_VIEWPORT}`,\n ROWS_CONTAINER: `.${GridClasses.ROWS_CONTAINER}`,\n DATA_ROW: `.${GridClasses.DATA_ROW}`,\n DATA_CELL: `.${GridClasses.DATA_CELL}`,\n GROUP_ROW: `.${GridClasses.GROUP_ROW}`,\n\n // By data attribute\n ROW_BY_INDEX: (index: number) => `.${GridClasses.DATA_ROW}[${GridDataAttrs.ROW_INDEX}=\"${index}\"]`,\n CELL_BY_FIELD: (field: string) => `.${GridClasses.DATA_CELL}[${GridDataAttrs.FIELD}=\"${field}\"]`,\n CELL_AT: (row: number, col: number) =>\n `.${GridClasses.DATA_ROW}[${GridDataAttrs.ROW_INDEX}=\"${row}\"] .${GridClasses.DATA_CELL}[${GridDataAttrs.COL_INDEX}=\"${col}\"]`,\n\n // State selectors\n SELECTED_ROWS: `.${GridClasses.DATA_ROW}.${GridClasses.SELECTED}`,\n EDITING_CELL: `.${GridClasses.DATA_CELL}.${GridClasses.EDITING}`,\n} as const;\n\n// #endregion\n\n// #region CSS Custom Properties\n\n/**\n * CSS custom property names for theming.\n * Use these when programmatically setting styles.\n */\nexport const GridCSSVars = {\n // Colors\n COLOR_BG: '--tbw-color-bg',\n COLOR_FG: '--tbw-color-fg',\n COLOR_FG_MUTED: '--tbw-color-fg-muted',\n COLOR_BORDER: '--tbw-color-border',\n COLOR_ACCENT: '--tbw-color-accent',\n COLOR_HEADER_BG: '--tbw-color-header-bg',\n COLOR_HEADER_FG: '--tbw-color-header-fg',\n COLOR_SELECTION: '--tbw-color-selection',\n COLOR_ROW_HOVER: '--tbw-color-row-hover',\n COLOR_ROW_ALT: '--tbw-color-row-alt',\n\n // Sizing\n ROW_HEIGHT: '--tbw-row-height',\n HEADER_HEIGHT: '--tbw-header-height',\n CELL_PADDING: '--tbw-cell-padding',\n\n // Typography\n FONT_FAMILY: '--tbw-font-family',\n FONT_SIZE: '--tbw-font-size',\n\n // Borders\n BORDER_RADIUS: '--tbw-border-radius',\n FOCUS_OUTLINE: '--tbw-focus-outline',\n} as const;\n\n// #endregion\n\n// Type helpers\nexport type GridClassName = (typeof GridClasses)[keyof typeof GridClasses];\nexport type GridDataAttr = (typeof GridDataAttrs)[keyof typeof GridDataAttrs];\nexport type GridCSSVar = (typeof GridCSSVars)[keyof typeof GridCSSVars];\n","// #region Public API surface - only export what consumers need\nexport { DataGridElement, DataGridElement as GridElement } from './lib/core/grid';\n\n// Event name constants for DataGrid (public API)\nexport const DGEvents = {\n CELL_COMMIT: 'cell-commit',\n ROW_COMMIT: 'row-commit',\n CHANGED_ROWS_RESET: 'changed-rows-reset',\n MOUNT_EXTERNAL_VIEW: 'mount-external-view',\n MOUNT_EXTERNAL_EDITOR: 'mount-external-editor',\n SORT_CHANGE: 'sort-change',\n COLUMN_RESIZE: 'column-resize',\n ACTIVATE_CELL: 'activate-cell',\n GROUP_TOGGLE: 'group-toggle',\n COLUMN_STATE_CHANGE: 'column-state-change',\n} as const;\n\nexport type DGEventName = (typeof DGEvents)[keyof typeof DGEvents];\n\n// Plugin event constants (mirrors DGEvents pattern)\nexport const PluginEvents = {\n // Selection plugin\n SELECTION_CHANGE: 'selection-change',\n // Tree plugin\n TREE_EXPAND: 'tree-expand',\n // Filtering plugin\n FILTER_CHANGE: 'filter-change',\n // Sorting plugin\n SORT_MODEL_CHANGE: 'sort-model-change',\n // Export plugin\n EXPORT_START: 'export-start',\n EXPORT_COMPLETE: 'export-complete',\n // Clipboard plugin\n CLIPBOARD_COPY: 'clipboard-copy',\n CLIPBOARD_PASTE: 'clipboard-paste',\n // Context menu plugin\n CONTEXT_MENU_OPEN: 'context-menu-open',\n CONTEXT_MENU_CLOSE: 'context-menu-close',\n // Undo/Redo plugin\n HISTORY_CHANGE: 'history-change',\n // Server-side plugin\n SERVER_LOADING: 'server-loading',\n SERVER_ERROR: 'server-error',\n // Visibility plugin\n COLUMN_VISIBILITY_CHANGE: 'column-visibility-change',\n // Reorder plugin\n COLUMN_REORDER: 'column-reorder',\n // Master-detail plugin\n DETAIL_EXPAND: 'detail-expand',\n // Grouping rows plugin\n GROUP_EXPAND: 'group-expand',\n} as const;\n\nexport type PluginEventName = (typeof PluginEvents)[keyof typeof PluginEvents];\n\n// Public type exports\nexport type {\n ActivateCellDetail,\n AggregatorRef,\n BaseColumnConfig,\n // Event detail types\n CellCommitDetail,\n CellRenderContext,\n ChangedRowsResetDetail,\n ColumnConfig,\n ColumnConfigMap,\n ColumnEditorContext,\n // Column features\n ColumnEditorSpec,\n ColumnResizeDetail,\n // Column state types\n ColumnSortState,\n ColumnState,\n ColumnViewRenderer,\n DataGridCustomEvent,\n DataGridElement as DataGridElementInterface,\n DataGridEventMap,\n ExternalMountEditorDetail,\n ExternalMountViewDetail,\n FitMode,\n GridColumnState,\n // Core configuration types\n GridConfig,\n // Icons\n GridIcons,\n // Plugin interface (minimal shape for type-checking)\n GridPlugin,\n // Shell types\n HeaderContentDefinition,\n IconValue,\n // Inference types\n InferredColumnResult,\n PrimitiveColumnType,\n // Public interface\n PublicGrid,\n RowCommitDetail,\n // Grouping & Footer types\n RowGroupRenderConfig,\n ShellConfig,\n ShellHeaderConfig,\n SortChangeDetail,\n ToolPanelConfig,\n ToolPanelDefinition,\n ToolbarButtonConfig,\n} from './lib/core/types';\n\n// Re-export FitModeEnum for runtime usage\nexport { DEFAULT_GRID_ICONS, FitModeEnum } from './lib/core/types';\n// #endregion\n\n// #region Plugin Types\n// Only export types that consumers need to use plugins\n// Plugin classes are available via @toolbox-web/grid/plugins/<name> or from 'all.ts'\n\n// Selection plugin\nexport type { CellRange, SelectionChangeDetail, SelectionConfig, SelectionMode } from './lib/plugins/selection/types';\n\n// Tree plugin\nexport type { TreeConfig, TreeExpandDetail } from './lib/plugins/tree/types';\n\n// Filtering plugin\nexport type { FilterConfig, FilterModel, FilterOperator, FilterType } from './lib/plugins/filtering/types';\n\n// Multi-sort plugin\nexport type { MultiSortConfig, SortModel } from './lib/plugins/multi-sort/types';\n\n// Export plugin\nexport type { ExportFormat, ExportParams } from './lib/plugins/export/types';\n\n// Pinned rows plugin\nexport type { PinnedRowsContext, PinnedRowsPanel } from './lib/plugins/pinned-rows/types';\n\n// Pivot plugin\nexport type { PivotConfig, PivotResult, PivotValueField } from './lib/plugins/pivot/types';\n\n// Server-side plugin\nexport type { GetRowsParams, GetRowsResult, ServerSideDataSource } from './lib/plugins/server-side/types';\n\n// Undo/Redo plugin\nexport type { EditAction } from './lib/plugins/undo-redo/types';\n\n// Grouping rows plugin\nexport type { GroupingRowsConfig } from './lib/plugins/grouping-rows/types';\n\n// Plugin base class - for creating custom plugins\nexport { BaseGridPlugin, PLUGIN_QUERIES } from './lib/core/plugin';\nexport type { PluginQuery } from './lib/core/plugin';\n\n// DOM constants - for querying grid elements and styling\nexport { GridCSSVars, GridClasses, GridDataAttrs, GridSelectors } from './lib/core/constants';\nexport type { GridCSSVar, GridClassName, GridDataAttr } from './lib/core/constants';\n// #endregion\n","/**\n * Aggregators Core Registry\n *\n * Provides a central registry for aggregator functions.\n * Built-in aggregators are provided by default.\n * Plugins can register additional aggregators.\n *\n * The registry is exposed as a singleton object that can be accessed:\n * - By ES module imports: import { aggregatorRegistry } from '@toolbox-web/grid'\n * - By UMD/CDN: TbwGrid.aggregatorRegistry\n * - By plugins via context: ctx.aggregatorRegistry\n */\n\n/* eslint-disable @typescript-eslint/no-explicit-any */\n\nexport type AggregatorFn = (rows: any[], field: string, column?: any) => any;\nexport type AggregatorRef = string | AggregatorFn;\n\n/** Built-in aggregator functions */\nconst builtInAggregators: Record<string, AggregatorFn> = {\n sum: (rows, field) => rows.reduce((acc, row) => acc + (Number(row[field]) || 0), 0),\n avg: (rows, field) => {\n const sum = rows.reduce((acc, row) => acc + (Number(row[field]) || 0), 0);\n return rows.length ? sum / rows.length : 0;\n },\n count: (rows) => rows.length,\n min: (rows, field) => Math.min(...rows.map((r) => Number(r[field]) || Infinity)),\n max: (rows, field) => Math.max(...rows.map((r) => Number(r[field]) || -Infinity)),\n first: (rows, field) => rows[0]?.[field],\n last: (rows, field) => rows[rows.length - 1]?.[field],\n};\n\n/** Custom aggregator registry (for plugins to add to) */\nconst customAggregators: Map<string, AggregatorFn> = new Map();\n\n/**\n * The aggregator registry singleton.\n * Plugins should access this through context or the global namespace.\n */\nexport const aggregatorRegistry = {\n /**\n * Register a custom aggregator function.\n */\n register(name: string, fn: AggregatorFn): void {\n customAggregators.set(name, fn);\n },\n\n /**\n * Unregister a custom aggregator function.\n */\n unregister(name: string): void {\n customAggregators.delete(name);\n },\n\n /**\n * Get an aggregator function by reference.\n */\n get(ref: AggregatorRef | undefined): AggregatorFn | undefined {\n if (ref === undefined) return undefined;\n if (typeof ref === 'function') return ref;\n // Check custom first, then built-in\n return customAggregators.get(ref) ?? builtInAggregators[ref];\n },\n\n /**\n * Run an aggregator on a set of rows.\n */\n run(ref: AggregatorRef | undefined, rows: any[], field: string, column?: any): any {\n const fn = this.get(ref);\n return fn ? fn(rows, field, column) : undefined;\n },\n\n /**\n * Check if an aggregator exists.\n */\n has(name: string): boolean {\n return customAggregators.has(name) || name in builtInAggregators;\n },\n\n /**\n * List all available aggregator names.\n */\n list(): string[] {\n return [...Object.keys(builtInAggregators), ...customAggregators.keys()];\n },\n};\n\n// #region Value-based Aggregators\n// Used by plugins like Pivot that work with pre-extracted numeric values\n\nexport type ValueAggregatorFn = (values: number[]) => number;\n\n/**\n * Built-in value-based aggregators.\n * These operate on arrays of numbers (unlike row-based aggregators).\n */\nconst builtInValueAggregators: Record<string, ValueAggregatorFn> = {\n sum: (vals) => vals.reduce((a, b) => a + b, 0),\n avg: (vals) => (vals.length ? vals.reduce((a, b) => a + b, 0) / vals.length : 0),\n count: (vals) => vals.length,\n min: (vals) => (vals.length ? Math.min(...vals) : 0),\n max: (vals) => (vals.length ? Math.max(...vals) : 0),\n first: (vals) => vals[0] ?? 0,\n last: (vals) => vals[vals.length - 1] ?? 0,\n};\n\n/**\n * Get a value-based aggregator function.\n * Used by Pivot plugin and other features that aggregate pre-extracted values.\n *\n * @param aggFunc - Aggregation function name ('sum', 'avg', 'count', 'min', 'max', 'first', 'last')\n * @returns Aggregator function that takes number[] and returns number\n */\nexport function getValueAggregator(aggFunc: string): ValueAggregatorFn {\n return builtInValueAggregators[aggFunc] ?? builtInValueAggregators.sum;\n}\n\n/**\n * Run a value-based aggregator on a set of values.\n *\n * @param aggFunc - Aggregation function name\n * @param values - Array of numbers to aggregate\n * @returns Aggregated result\n */\nexport function runValueAggregator(aggFunc: string, values: number[]): number {\n return getValueAggregator(aggFunc)(values);\n}\n// #endregion\n\n// Legacy function exports for backward compatibility\nexport const registerAggregator = aggregatorRegistry.register.bind(aggregatorRegistry);\nexport const unregisterAggregator = aggregatorRegistry.unregister.bind(aggregatorRegistry);\nexport const getAggregator = aggregatorRegistry.get.bind(aggregatorRegistry);\nexport const runAggregator = aggregatorRegistry.run.bind(aggregatorRegistry);\nexport const listAggregators = aggregatorRegistry.list.bind(aggregatorRegistry);\n"],"names":["getSortState","grid","sortMap","collectColumnState","plugins","columns","sortStates","col","index","state","internalCol","sortState","plugin","pluginState","applyColumnState","allColumns","stateMap","s","updatedColumns","updated","a","b","orderA","orderB","sortedByPriority","primarySort","colState","createStateChangeHandler","getPlugins","emit","timeoutId","FitModeEnum","DEFAULT_GRID_ICONS","inferType","value","inferColumns","rows","provided","typeMap","sample","k","v","type","c","EXPR_RE","EMPTY_SENTINEL","SAFE_EXPR","FORBIDDEN","DANGEROUS_TAGS","DANGEROUS_ATTR_PATTERN","URL_ATTRS","DANGEROUS_URL_PROTOCOL","sanitizeHTML","html","template","sanitizeNode","root","toRemove","elements","el","tagName","attr","attrsToRemove","attrName","name","evalTemplateString","raw","ctx","parts","evaluated","_m","expr","res","evalSingle","finalStr","postProcess","allEmpty","p","key","dotChain","out","str","finalCellScrub","cell","n","compileTemplate","forceBlank","fn","parseLightDomColumns","host","field","rawType","header","sortable","editable","config","optionsAttr","item","label","viewTpl","editorTpl","headerTpl","mergeColumns","programmatic","dom","domMap","merged","d","m","addPart","token","existing","getColumnConfiguration","lightDomColumns","autoSizeColumns","mode","headerCells","changed","i","headerCell","max","rowEl","w","updateTemplate","min","defaultEditorFor","column","input","e","select","opt","o","commitValue","values","handleGridKeyDown","maxRow","maxCol","editing","colType","path","target","isFormField","tag","ensureCellVisible","options","rowHeight","container","viewportEl","scrollEl","visibleHeight","y","rowIndex","vStart","vEnd","scrollArea","offsets","cellRect","scrollAreaRect","cellLeft","cellRight","visibleLeft","visibleRight","focusTarget","CELL_CACHE_KEY","CELL_CACHE_EPOCH_KEY","invalidateCellCache","renderVisibleRows","start","end","epoch","renderRowHook","needed","bodyEl","colLen","headerRowCount","handleRowClick","hasRenderRowPlugins","rowData","rowEpoch","prevRef","cellCount","structureValid","dataRefChanged","needsExternalRebuild","hasEditingCell","isActivelyEditedRow","renderInlineRow","fastPatchRow","children","inlineEnterEdit","isChanged","hasChangedClass","colsLen","childLen","minLen","focusRow","focusCol","hasSpecialCols","rowIndexStr","shouldHaveFocus","hasFocus","produced","displayStr","formatted","isTrue","editMode","gridEl","fragment","colIndex","format","compiled","tplHolder","viewRenderer","externalView","needsSanitization","spec","placeholder","context","output","blocked","rawTpl","tentative","textContent","currentRowIndex","currentColIndex","currentRowData","currentCol","startRowEdit","rowElCurrent","col2","selectEl","newVal","commitCellValue","isDbl","firstCell","cellEl","active","targetCell","editor","isSafePropertyKey","exitRowEdit","revert","snapshot","current","val","rowIdx","colIdx","rowEl2","newValue","firstTime","originalValue","editFinalized","commit","cancel","inputLike","editorHost","editorSpec","clone","compiledEditor","node","g","hasHTMLInput","toggleSort","applySort","r","renderHeader","h","dir","comparator","rA","rB","setIcon","element","icon","headerRow","maybeTpl","span","icons","iconValue","handle","createResizeController","resizeState","pendingRaf","prevCursor","prevUserSelect","onMove","delta","width","justFinishedResize","onUp","hadResize","rect","iconToString","createShellState","shouldRenderShellHeader","renderShellHeader","toolPanelIcon","title","hasTitle","iconStr","configButtons","hasConfigButtons","hasApiButtons","hasLightDomButtons","hasPanels","showSeparator","sortedConfigButtons","sortedApiButtons","toolbarHtml","btn","isOpen","renderShellBody","gridContentHtml","position","hasPanel","expandIcon","collapseIcon","sortedPanels","isSinglePanel","accordionHtml","panel","isExpanded","iconHtml","chevronHtml","panelHtml","parseLightDomShell","headerEl","headerContents","toolButtons","setupShellEventListeners","shadowRoot","callbacks","toolbar","customBtn","btnId","accordion","sectionId","setupToolPanelResize","onResize","shellBody","minWidth","startX","startWidth","maxWidth","isResizing","onMouseMove","newWidth","onMouseUp","finalWidth","onMouseDown","renderCustomToolbarButtons","allButtons","slot","existingCleanup","cleanup","renderHeaderContent","contentArea","sortedContents","content","renderPanelContent","panelId","section","chevron","updateToolbarActiveStates","panelToggle","updatePanelState","getToolbarButtonsInfo","result","cleanupShellState","createShellController","initialized","controller","firstPanel","shadow","updateAccordionSectionState","otherId","otherPanel","contentEl","renderAccordionSectionContent","contentId","button","buttonId","disabled","apiBtn","expanded","PluginManager","renderer","PluginClass","total","beforeRowIndex","scrollTop","adjustedStart","pluginStart","row","query","responses","response","event","focusedCell","left","right","skipScroll","panels","contents","DataGridElement","#shadow","#initialized","#readyPromise","#readyResolve","#rows","#columns","#gridConfig","#fitMode","#editOn","#effectiveConfig","#connected","#scrollRaf","#pendingScrollTop","#hasScrollPlugins","#renderRowHook","#isDragging","#touchStartY","#touchStartX","#touchScrollTop","#touchScrollLeft","#eventAbortController","#resizeObserver","#pluginManager","#stateChangeHandler","#initialColumnState","#shellState","#shellController","#resizeCleanup","#baseColumns","oldValue","#onRowsChanged","#onColsChanged","#onGridConfigChanged","#onFitChanged","#onEditModeChanged","#injectStyles","eventName","detail","#emit","sheet","styles","#rebuildRowModel","#processColumns","#initializePlugins","pluginsConfig","#injectAllPluginStyles","allStyles","styleEl","#updatePluginConfigs","#destroyPlugins","#collectPluginShellContributions","pluginPanels","pluginContents","#mergeEffectiveConfig","#render","#afterConnect","prop","gridRoot","defaultOpen","signal","#setup","fauxScrollbar","rowsEl","currentScrollTop","rawStart","evenAlignedStart","subPixelOffset","#onScrollBatched","gridContentEl","deltaY","deltaX","#handleMouseDown","#handleMouseMove","#handleMouseUp","userRowHeight","firstRow","measuredHeight","#updateAriaSelection","isActiveRow","sourceColumns","visibleCols","hiddenCols","processedColumns","processedMap","processed","originalRows","processedRows","base","domCols","map","exist","existingCols","#renderVisibleRows","configCols","existingHiddenMap","seeded","#applyColumnStateInternal","allCols","scrollEvent","cellClickEvent","headerClickEvent","#buildCellMouseEvent","elAtPoint","silent","visible","wasHidden","willBeHidden","isCurrentlyHidden","order","columnMap","reordered","#applyColumnState","force","totalRows","scrollAreaEl","hScrollbarHeight","innerGrid","viewportHeight","iterations","maxIterations","extraHeightBefore","pluginAdjustedStart","visibleCount","footerHeight","pluginExtraHeight","extraHeightBeforeStart","shellConfig","hasShell","accordionIcons","shellHeaderHtml","shellBodyHtml","#setupShellListeners","#handleToolbarButtonClick","configBtn","PLUGIN_QUERIES","BaseGridPlugin","userIcons","iconKey","pluginOverride","message","GridClasses","GridDataAttrs","GridSelectors","GridCSSVars","DGEvents","PluginEvents","builtInAggregators","acc","sum","customAggregators","aggregatorRegistry","ref","builtInValueAggregators","vals","getValueAggregator","aggFunc","runValueAggregator","registerAggregator","unregisterAggregator","getAggregator","runAggregator","listAggregators"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"index.js","sources":["../../../libs/grid/src/lib/core/internal/column-state.ts","../../../libs/grid/src/lib/core/types.ts","../../../libs/grid/src/lib/core/internal/inference.ts","../../../libs/grid/src/lib/core/internal/sanitize.ts","../../../libs/grid/src/lib/core/internal/columns.ts","../../../libs/grid/src/lib/core/internal/editors.ts","../../../libs/grid/src/lib/core/internal/keyboard.ts","../../../libs/grid/src/lib/core/internal/rows.ts","../../../libs/grid/src/lib/core/internal/editing.ts","../../../libs/grid/src/lib/core/internal/sorting.ts","../../../libs/grid/src/lib/core/internal/header.ts","../../../libs/grid/src/lib/core/internal/resize.ts","../../../libs/grid/src/lib/core/internal/shell.ts","../../../libs/grid/src/lib/core/plugin/plugin-manager.ts","../../../libs/grid/src/lib/core/grid.ts","../../../libs/grid/src/lib/core/plugin/base-plugin.ts","../../../libs/grid/src/lib/core/constants.ts","../../../libs/grid/src/public.ts","../../../libs/grid/src/lib/core/internal/aggregators.ts"],"sourcesContent":["/**\n * Column State Module\n *\n * Handles collection and application of column state for persistence.\n * State includes user-driven changes: order, width, visibility, and sort.\n * Plugins can contribute additional state via getColumnState/applyColumnState hooks.\n */\n\nimport type { BaseGridPlugin } from '../plugin';\nimport type {\n ColumnConfig,\n ColumnInternal,\n ColumnSortState,\n ColumnState,\n GridColumnState,\n InternalGrid,\n} from '../types';\n\n/** Debounce timeout for state change events */\nconst STATE_CHANGE_DEBOUNCE_MS = 100;\n\n/**\n * Get sort state for a column from the grid's sortState.\n */\nfunction getSortState(grid: InternalGrid): Map<string, ColumnSortState> {\n const sortMap = new Map<string, ColumnSortState>();\n\n // Core sort state (single column)\n if (grid._sortState) {\n sortMap.set(grid._sortState.field, {\n direction: grid._sortState.direction === 1 ? 'asc' : 'desc',\n priority: 0,\n });\n }\n\n return sortMap;\n}\n\n/**\n * Collect column state from the grid and all plugins.\n * Returns a complete GridColumnState object ready for serialization.\n */\nexport function collectColumnState<T>(grid: InternalGrid<T>, plugins: BaseGridPlugin[]): GridColumnState {\n const columns = grid._columns;\n const sortStates = getSortState(grid);\n\n return {\n columns: columns.map((col, index) => {\n // 1. Core state\n const state: ColumnState = {\n field: col.field,\n order: index,\n visible: true, // If it's in _columns, it's visible (hidden columns are filtered out)\n };\n\n // Include width if set (either from config or resize)\n const internalCol = col as ColumnInternal<T>;\n if (internalCol.__renderedWidth !== undefined) {\n state.width = internalCol.__renderedWidth;\n } else if (col.width !== undefined) {\n state.width = typeof col.width === 'string' ? parseFloat(col.width) : col.width;\n }\n\n // Include sort state if present\n const sortState = sortStates.get(col.field);\n if (sortState) {\n state.sort = sortState;\n }\n\n // 2. Collect from each plugin\n for (const plugin of plugins) {\n if (plugin.getColumnState) {\n const pluginState = plugin.getColumnState(col.field);\n if (pluginState) {\n Object.assign(state, pluginState);\n }\n }\n }\n\n return state;\n }),\n };\n}\n\n/**\n * Apply column state to the grid and all plugins.\n * Modifies the grid's internal state and triggers plugin state restoration.\n *\n * @param grid - The grid instance\n * @param state - The state to apply\n * @param allColumns - All available columns (including hidden ones)\n * @param plugins - Plugins that may have applyColumnState hooks\n */\nexport function applyColumnState<T>(\n grid: InternalGrid<T>,\n state: GridColumnState,\n allColumns: ColumnConfig<T>[],\n plugins: BaseGridPlugin[],\n): void {\n if (!state.columns || state.columns.length === 0) return;\n\n const stateMap = new Map(state.columns.map((s) => [s.field, s]));\n\n // 1. Apply width and visibility to columns\n const updatedColumns = allColumns.map((col) => {\n const s = stateMap.get(col.field);\n if (!s) return col;\n\n const updated: ColumnInternal<T> = { ...col };\n\n // Apply width\n if (s.width !== undefined) {\n updated.width = s.width;\n updated.__renderedWidth = s.width;\n }\n\n // Apply visibility (hidden is inverse of visible)\n if (s.visible !== undefined) {\n updated.hidden = !s.visible;\n }\n\n return updated;\n });\n\n // 2. Reorder columns based on state\n updatedColumns.sort((a, b) => {\n const orderA = stateMap.get(a.field)?.order ?? Infinity;\n const orderB = stateMap.get(b.field)?.order ?? Infinity;\n return orderA - orderB;\n });\n\n // 3. Update grid's internal columns\n grid._columns = updatedColumns as ColumnInternal<T>[];\n\n // 4. Apply sort state (core single-column sort)\n // Find the column with highest sort priority\n const sortedByPriority = state.columns\n .filter((s) => s.sort !== undefined)\n .sort((a, b) => (a.sort?.priority ?? 0) - (b.sort?.priority ?? 0));\n\n if (sortedByPriority.length > 0) {\n const primarySort = sortedByPriority[0];\n if (primarySort.sort) {\n grid._sortState = {\n field: primarySort.field,\n direction: primarySort.sort.direction === 'asc' ? 1 : -1,\n };\n }\n } else {\n grid._sortState = null;\n }\n\n // 5. Let each plugin apply its state\n for (const plugin of plugins) {\n if (plugin.applyColumnState) {\n for (const colState of state.columns) {\n plugin.applyColumnState(colState.field, colState);\n }\n }\n }\n}\n\n/**\n * Create a state change handler with debouncing.\n * Returns a function that, when called, will eventually emit the state change event.\n */\nexport function createStateChangeHandler<T>(\n grid: InternalGrid<T>,\n getPlugins: () => BaseGridPlugin[],\n emit: (detail: GridColumnState) => void,\n): () => void {\n let timeoutId: ReturnType<typeof setTimeout> | null = null;\n\n return () => {\n // Clear any pending timeout\n if (timeoutId !== null) {\n clearTimeout(timeoutId);\n }\n\n // Schedule the emit\n timeoutId = setTimeout(() => {\n timeoutId = null;\n const state = collectColumnState(grid, getPlugins());\n emit(state);\n }, STATE_CHANGE_DEBOUNCE_MS);\n };\n}\n\n/**\n * Compare two column states to check if they are equal.\n * Useful for preventing duplicate state change events.\n */\nexport function areColumnStatesEqual(a: GridColumnState, b: GridColumnState): boolean {\n if (a.columns.length !== b.columns.length) return false;\n\n for (let i = 0; i < a.columns.length; i++) {\n const colA = a.columns[i];\n const colB = b.columns[i];\n\n if (colA.field !== colB.field) return false;\n if (colA.order !== colB.order) return false;\n if (colA.visible !== colB.visible) return false;\n if (colA.width !== colB.width) return false;\n\n // Compare sort state\n const sortA = colA.sort;\n const sortB = colB.sort;\n if ((sortA === undefined) !== (sortB === undefined)) return false;\n if (sortA && sortB) {\n if (sortA.direction !== sortB.direction) return false;\n if (sortA.priority !== sortB.priority) return false;\n }\n }\n\n return true;\n}\n","import type { PluginQuery } from './plugin/base-plugin';\n\n/**\n * The compiled webcomponent interface for DataGrid\n */\nexport interface DataGridElement extends PublicGrid, HTMLElement {}\n\n/**\n * Public API interface for DataGrid component.\n *\n * **Property Getters vs Setters:**\n *\n * Property getters return the EFFECTIVE (resolved) value after merging all config sources.\n * This is the \"current situation\" - what consumers and plugins need to know.\n *\n * Property setters accept input values which are merged into the effective config.\n * Multiple sources can contribute (gridConfig, columns prop, light DOM, individual props).\n *\n * For example:\n * - `grid.fitMode` returns the resolved fitMode (e.g., 'stretch' even if you set undefined)\n * - `grid.columns` returns the effective columns after merging\n * - `grid.gridConfig` returns the full effective config\n */\nexport interface PublicGrid<T = any> {\n /**\n * Full config object. Setter merges with other inputs per precedence rules.\n * Getter returns the effective (resolved) config.\n */\n gridConfig?: GridConfig<T>;\n /**\n * Column definitions.\n * Getter returns effective columns (after merging config, light DOM, inference).\n */\n columns?: ColumnConfig<T>[];\n /** Current row data (after plugin processing like grouping, filtering). */\n rows?: T[];\n /** Resolves once the component has finished initial work (layout, inference). */\n ready?: () => Promise<void>;\n /** Force a layout / measurement pass (e.g. after container resize). */\n forceLayout?: () => Promise<void>;\n /** Return effective resolved config (after inference & precedence). */\n getConfig?: () => Promise<Readonly<GridConfig<T>>>;\n /** Toggle expansion state of a group row by its generated key. */\n toggleGroup?: (key: string) => Promise<void>;\n}\n\n/**\n * Internal-only augmented interface for DataGrid component\n */\nexport interface InternalGrid<T = any> extends PublicGrid<T>, GridConfig<T> {\n shadowRoot: ShadowRoot | null;\n _rows: T[];\n _columns: ColumnInternal<T>[];\n /** Visible columns only (excludes hidden). Use for rendering. */\n _visibleColumns: ColumnInternal<T>[];\n _headerRowEl: HTMLElement;\n _bodyEl: HTMLElement;\n _rowPool: HTMLElement[];\n _resizeController: ResizeController;\n _sortState: { field: string; direction: 1 | -1 } | null;\n __originalOrder: T[];\n __rowRenderEpoch: number;\n __didInitialAutoSize?: boolean;\n __lightDomColumnsCache?: ColumnInternal[];\n __originalColumnNodes?: HTMLElement[];\n _gridTemplate: string;\n _virtualization: VirtualState;\n _focusRow: number;\n _focusCol: number;\n _activeEditRows: number;\n _rowEditSnapshots: Map<number, T>;\n _changedRowIndices: Set<number>;\n changedRows?: T[];\n changedRowIndices?: number[];\n effectiveConfig?: GridConfig<T>;\n findHeaderRow?: () => HTMLElement;\n refreshVirtualWindow: (full: boolean) => void;\n updateTemplate?: () => void;\n findRenderedRowElement?: (rowIndex: number) => HTMLElement | null;\n beginBulkEdit?: (rowIndex: number) => void;\n commitActiveRowEdit?: () => void;\n /** Dispatch cell click to plugin system, returns true if handled */\n _dispatchCellClick?: (event: MouseEvent, rowIndex: number, colIndex: number, cellEl: HTMLElement) => boolean;\n /** Dispatch row click to plugin system, returns true if handled */\n _dispatchRowClick?: (event: MouseEvent, rowIndex: number, row: any, rowEl: HTMLElement) => boolean;\n /** Dispatch header click to plugin system, returns true if handled */\n _dispatchHeaderClick?: (event: MouseEvent, colIndex: number, headerEl: HTMLElement) => boolean;\n /** Dispatch keydown to plugin system, returns true if handled */\n _dispatchKeyDown?: (event: KeyboardEvent) => boolean;\n /** Get horizontal scroll boundary offsets from plugins (e.g., pinned columns) */\n _getHorizontalScrollOffsets?: (\n rowEl?: HTMLElement,\n focusedCell?: HTMLElement,\n ) => { left: number; right: number; skipScroll?: boolean };\n /** Query all plugins with a generic query and collect responses */\n queryPlugins?: <T>(query: PluginQuery) => T[];\n /** Request emission of column-state-change event (debounced) */\n requestStateChange?: () => void;\n}\n\nexport type PrimitiveColumnType = 'number' | 'string' | 'date' | 'boolean' | 'select' | 'typeahead';\n\n/**\n * Base contract for a column. Public; kept intentionally lean so host apps can extend via intersection types.\n * Prefer adding optional properties here only when broadly useful to most grids.\n */\nexport interface BaseColumnConfig<TRow = any, TValue = any> {\n /** Unique field key referencing property in row objects */\n field: keyof TRow & string;\n /** Visible header label; defaults to capitalized field */\n header?: string;\n /** Column data type; inferred if omitted */\n type?: PrimitiveColumnType;\n /** Column width in pixels; fixed size (no flexibility) */\n width?: string | number;\n /** Minimum column width in pixels (stretch mode only); when set, column uses minmax(minWidth, 1fr) */\n minWidth?: number;\n /** Whether column can be sorted */\n sortable?: boolean;\n /** Whether column can be resized by user */\n resizable?: boolean;\n /** Optional custom comparator for sorting (a,b) -> number */\n sortComparator?: (a: TValue, b: TValue, rowA: TRow, rowB: TRow) => number;\n /** Whether the field is editable (enables editors) */\n editable?: boolean;\n /** Optional custom editor factory or element tag name */\n editor?: ColumnEditorSpec<TRow, TValue>;\n /** For select/typeahead types - available options */\n options?: Array<{ label: string; value: unknown }> | (() => Array<{ label: string; value: unknown }>);\n /** For select/typeahead - allow multi select */\n multi?: boolean;\n /** Optional formatter */\n format?: (value: TValue, row: TRow) => string;\n /** Arbitrary extra metadata */\n meta?: Record<string, unknown>;\n}\n\n/**\n * Full column configuration including optional custom view/renderer & grouping metadata.\n */\nexport interface ColumnConfig<TRow = any> extends BaseColumnConfig<TRow, any> {\n /** Optional custom view renderer used instead of default text rendering */\n viewRenderer?: ColumnViewRenderer<TRow, any>;\n /** External view spec (lets host app mount any framework component) */\n externalView?: {\n component: unknown;\n props?: Record<string, unknown>;\n mount?: (options: {\n placeholder: HTMLElement;\n context: CellRenderContext<TRow, unknown>;\n spec: unknown;\n }) => void | { dispose?: () => void };\n };\n /** Whether the column is initially hidden */\n hidden?: boolean;\n /** Prevent this column from being hidden by the visibility plugin */\n lockVisible?: boolean;\n}\n\nexport type ColumnConfigMap<TRow = any> = ColumnConfig<TRow>[];\n\n/** External editor spec: tag name, factory function, or external mount spec */\nexport type ColumnEditorSpec<TRow = unknown, TValue = unknown> =\n | string // custom element tag name\n | ((context: ColumnEditorContext<TRow, TValue>) => HTMLElement | string)\n | {\n /** Arbitrary component reference (class, function, token) */\n component: unknown;\n /** Optional static props passed to mount */\n props?: Record<string, unknown>;\n /** Optional custom mount function; if provided we call it directly instead of emitting an event */\n mount?: (options: {\n placeholder: HTMLElement;\n context: ColumnEditorContext<TRow, TValue>;\n spec: unknown;\n }) => void | { dispose?: () => void };\n };\n\n/**\n * Context object provided to editor factories allowing mutation (commit/cancel) of a cell value.\n */\nexport interface ColumnEditorContext<TRow = any, TValue = any> {\n /** Underlying full row object for the active edit. */\n row: TRow;\n /** Current cell value (mutable only via commit). */\n value: TValue;\n /** Field name being edited. */\n field: keyof TRow & string;\n /** Column configuration reference. */\n column: ColumnConfig<TRow>;\n /** Accept the edit; triggers change tracking + rerender. */\n commit: (newValue: TValue) => void;\n /** Abort edit without persisting changes. */\n cancel: () => void;\n}\n\n/**\n * Context passed to custom view renderers (pure display – no commit helpers).\n */\nexport interface CellRenderContext<TRow = any, TValue = any> {\n /** Row object for the cell being rendered. */\n row: TRow;\n /** Value at field. */\n value: TValue;\n /** Field key. */\n field: keyof TRow & string;\n /** Column configuration reference. */\n column: ColumnConfig<TRow>;\n}\n\nexport type ColumnViewRenderer<TRow = unknown, TValue = unknown> = (\n ctx: CellRenderContext<TRow, TValue>,\n) => Node | string | void;\n\n// #region Internal-only augmented types (not re-exported publicly)\nexport interface ColumnInternal<T = any> extends ColumnConfig<T> {\n __autoSized?: boolean;\n __userResized?: boolean;\n __renderedWidth?: number;\n /** Original configured width (for reset on double-click) */\n __originalWidth?: number;\n __viewTemplate?: HTMLElement;\n __editorTemplate?: HTMLElement;\n __headerTemplate?: HTMLElement;\n __compiledView?: (ctx: CellContext<T>) => string;\n __compiledEditor?: (ctx: EditorExecContext<T>) => string;\n}\n\n/**\n * Runtime cell context used internally for compiled template execution.\n */\nexport interface CellContext<T = any> {\n row: T;\n value: unknown;\n field: string;\n column: ColumnInternal<T>;\n}\n\n/**\n * Internal editor execution context extending the generic cell context with commit helpers.\n */\nexport interface EditorExecContext<T = any> extends CellContext<T> {\n commit: (newValue: unknown) => void;\n cancel: () => void;\n}\n\n/** Controller managing drag-based column resize lifecycle. */\nexport interface ResizeController {\n start: (e: MouseEvent, colIndex: number, cell: HTMLElement) => void;\n /** Reset a column to its configured width (or auto-size if none configured). */\n resetColumn: (colIndex: number) => void;\n dispose: () => void;\n /** True while a resize drag is in progress (used to suppress header click/sort). */\n isResizing: boolean;\n}\n\n/** Virtual window bookkeeping; modified in-place as scroll position changes. */\nexport interface VirtualState {\n enabled: boolean;\n rowHeight: number;\n /** Threshold for bypassing virtualization (renders all rows if totalRows <= bypassThreshold) */\n bypassThreshold: number;\n start: number;\n end: number;\n /** Faux scrollbar element that provides scroll events (AG Grid pattern) */\n container: HTMLElement | null;\n /** Rows viewport element for measuring visible area height */\n viewportEl: HTMLElement | null;\n /** Spacer element inside faux scrollbar for setting virtual height */\n totalHeightEl: HTMLElement | null;\n}\n// #endregion\n\n// #region Grouping & Footer Public Types\n/**\n * Group row rendering customization options.\n * Used within grouping-rows plugin config for presentation of group rows.\n */\nexport interface RowGroupRenderConfig {\n /** If true, group rows span all columns (single full-width cell). Default false. */\n fullWidth?: boolean;\n /** Optional label formatter override. Receives raw group value + depth. */\n formatLabel?: (value: unknown, depth: number, key: string) => string;\n /** Optional aggregate overrides per field for group summary cells (only when not fullWidth). */\n aggregators?: Record<string, AggregatorRef>;\n /** Additional CSS class applied to each group row root element. */\n class?: string;\n}\n\nexport type AggregatorRef = string | ((rows: unknown[], field: string, column?: unknown) => unknown);\n\n/** Result of automatic column inference from sample rows. */\nexport interface InferredColumnResult<TRow = unknown> {\n columns: ColumnConfigMap<TRow>;\n typeMap: Record<string, PrimitiveColumnType>;\n}\n\nexport const FitModeEnum = {\n STRETCH: 'stretch',\n FIXED: 'fixed',\n} as const;\nexport type FitMode = (typeof FitModeEnum)[keyof typeof FitModeEnum]; // evaluates to 'stretch' | 'fixed'\n// #endregion\n\n// #region Plugin Interface\n/**\n * Minimal plugin interface for type-checking.\n * This interface is defined here to avoid circular imports with BaseGridPlugin.\n * All plugins must satisfy this shape (BaseGridPlugin implements it).\n */\nexport interface GridPlugin {\n /** Unique plugin identifier */\n readonly name: string;\n /** Plugin version */\n readonly version: string;\n /** CSS styles to inject into grid's shadow DOM */\n readonly styles?: string;\n}\n// #endregion\n\n// #region Grid Config\n/**\n * Grid configuration object - the **single source of truth** for grid behavior.\n *\n * Users can configure the grid via multiple input methods, all of which converge\n * into an effective `GridConfig` internally:\n *\n * **Configuration Input Methods:**\n * - `gridConfig` property - direct assignment of this object\n * - `columns` property - shorthand for `gridConfig.columns`\n * - `fitMode` property - shorthand for `gridConfig.fitMode`\n * - `editOn` property - shorthand for `gridConfig.editOn`\n * - Light DOM `<tbw-grid-column>` - declarative columns (merged into `columns`)\n * - Light DOM `<tbw-grid-header>` - declarative shell header (merged into `shell.header`)\n *\n * **Precedence (when same property set multiple ways):**\n * Individual props (`fitMode`, `editOn`) > `columns` prop > Light DOM > `gridConfig`\n *\n * @example\n * ```ts\n * // Via gridConfig (recommended for complex setups)\n * grid.gridConfig = {\n * columns: [{ field: 'name' }, { field: 'age' }],\n * fitMode: 'stretch',\n * plugins: [new SelectionPlugin()],\n * shell: { header: { title: 'My Grid' } }\n * };\n *\n * // Via individual props (convenience for simple cases)\n * grid.columns = [{ field: 'name' }, { field: 'age' }];\n * grid.fitMode = 'stretch';\n * ```\n */\nexport interface GridConfig<TRow = any> {\n /** Column definitions. Can also be set via `columns` prop or `<tbw-grid-column>` light DOM. */\n columns?: ColumnConfigMap<TRow>;\n /** Sizing mode for columns. Can also be set via `fitMode` prop. */\n fitMode?: FitMode;\n /** Edit activation mode ('click' | 'dblclick'). Can also be set via `editOn` prop. */\n editOn?: string;\n /**\n * Row height in pixels for virtualization calculations.\n * The virtualization system assumes uniform row heights for performance.\n *\n * If not specified, the grid measures the first rendered row's height,\n * which respects the CSS variable `--tbw-row-height` set by themes.\n *\n * Set this explicitly when:\n * - Row content may wrap to multiple lines (also set `--tbw-cell-white-space: normal`)\n * - Using custom row templates with variable content\n * - You want to override theme-defined row height\n *\n * @default Auto-measured from first row (respects --tbw-row-height CSS variable)\n *\n * @example\n * ```ts\n * // Fixed height for rows that may wrap to 2 lines\n * gridConfig = { rowHeight: 56 };\n * ```\n */\n rowHeight?: number;\n /**\n * Array of plugin instances.\n * Each plugin is instantiated with its configuration and attached to this grid.\n *\n * @example\n * ```ts\n * plugins: [\n * new SelectionPlugin({ mode: 'range' }),\n * new MultiSortPlugin(),\n * new FilteringPlugin({ debounceMs: 150 }),\n * ]\n * ```\n */\n plugins?: GridPlugin[];\n\n /**\n * Saved column state to restore on initialization.\n * Includes order, width, visibility, sort, and plugin-contributed state.\n */\n columnState?: GridColumnState;\n\n /**\n * Shell configuration for header bar and tool panels.\n * When configured, adds an optional wrapper with title, toolbar, and collapsible side panels.\n */\n shell?: ShellConfig;\n\n /**\n * Grid-wide icon configuration.\n * Provides consistent icons across all plugins (tree, grouping, sorting, etc.).\n * Plugins will use these by default but can override with their own config.\n */\n icons?: GridIcons;\n}\n// #endregion\n\n// #region Grid Icons\n\n/** Icon value - can be a string (text/HTML) or HTMLElement */\nexport type IconValue = string | HTMLElement;\n\n/**\n * Grid-wide icon configuration.\n * All icons are optional - sensible defaults are used when not specified.\n */\nexport interface GridIcons {\n /** Expand icon for collapsed items (trees, groups, details). Default: '▶' */\n expand?: IconValue;\n /** Collapse icon for expanded items (trees, groups, details). Default: '▼' */\n collapse?: IconValue;\n /** Sort ascending indicator. Default: '▲' */\n sortAsc?: IconValue;\n /** Sort descending indicator. Default: '▼' */\n sortDesc?: IconValue;\n /** Sort neutral/unsorted indicator. Default: '⇅' */\n sortNone?: IconValue;\n /** Submenu arrow for context menus. Default: '▶' */\n submenuArrow?: IconValue;\n /** Drag handle icon for reordering. Default: '⋮⋮' */\n dragHandle?: IconValue;\n /** Tool panel toggle icon in toolbar. Default: '☰' */\n toolPanel?: IconValue;\n}\n\n/** Default icons used when not overridden */\nexport const DEFAULT_GRID_ICONS: Required<GridIcons> = {\n expand: '▶',\n collapse: '▼',\n sortAsc: '▲',\n sortDesc: '▼',\n sortNone: '⇅',\n submenuArrow: '▶',\n dragHandle: '⋮⋮',\n toolPanel: '☰',\n};\n// #endregion\n\n// #region Shell Configuration\n\n/**\n * Shell configuration for the grid's optional header bar and tool panels.\n */\nexport interface ShellConfig {\n /** Shell header bar configuration */\n header?: ShellHeaderConfig;\n /** Tool panel configuration */\n toolPanel?: ToolPanelConfig;\n}\n\n/**\n * Shell header bar configuration\n */\nexport interface ShellHeaderConfig {\n /** Grid title displayed on the left (optional) */\n title?: string;\n /** Custom toolbar buttons (rendered before tool panel toggles) */\n toolbarButtons?: ToolbarButtonConfig[];\n}\n\n/**\n * Tool panel configuration\n */\nexport interface ToolPanelConfig {\n /** Panel position: 'left' | 'right' (default: 'right') */\n position?: 'left' | 'right';\n /** Default panel width in pixels (default: 280) */\n width?: number;\n /** Panel ID to open by default on load */\n defaultOpen?: string;\n /** Whether to persist open/closed state (requires Column State Events) */\n persistState?: boolean;\n}\n\n/**\n * Toolbar button defined via config (programmatic approach).\n * Supports three modes:\n * - Simple: provide `icon` + `action` for grid to create button\n * - Element: provide `element` for user-created DOM\n * - Render: provide `render` function for complex widgets\n */\nexport interface ToolbarButtonConfig {\n /** Unique button ID */\n id: string;\n /** Tooltip / aria-label (required for accessibility) */\n label: string;\n /** Order priority (lower = first, default: 100) */\n order?: number;\n /** Whether button is disabled (only applies to grid-rendered buttons) */\n disabled?: boolean;\n\n // ===== Option A: Simple - Grid renders the button =====\n /** Button content: SVG string, emoji, or text. Grid creates <button> with this. */\n icon?: string;\n /** Click handler (required when using icon) */\n action?: () => void;\n\n // ===== Option B: Custom DOM - User provides element or render function =====\n /**\n * User-provided element. Grid wraps it but doesn't modify it.\n * User is responsible for event handlers.\n */\n element?: HTMLElement;\n /**\n * Render function called once. Receives container, user appends their DOM.\n * User is responsible for event handlers.\n * Return a cleanup function (optional).\n */\n render?: (container: HTMLElement) => void | (() => void);\n}\n\n/**\n * Toolbar button info returned by getToolbarButtons().\n */\nexport interface ToolbarButtonInfo {\n id: string;\n label: string;\n disabled: boolean;\n /** Source of this button: 'config' | 'light-dom' | 'panel-toggle' */\n source: 'config' | 'light-dom' | 'panel-toggle';\n /** For panel toggles, the associated panel ID */\n panelId?: string;\n}\n\n/**\n * Tool panel definition registered by plugins or consumers.\n */\nexport interface ToolPanelDefinition {\n /** Unique panel ID */\n id: string;\n /** Panel title shown in accordion header */\n title: string;\n /** Icon for accordion section header (optional, emoji or SVG) */\n icon?: string;\n /** Tooltip for accordion section header */\n tooltip?: string;\n /** Panel content factory - called when panel section opens */\n render: (container: HTMLElement) => void | (() => void);\n /** Called when panel closes (for cleanup) */\n onClose?: () => void;\n /** Panel order priority (lower = first, default: 100) */\n order?: number;\n}\n\n/**\n * Header content definition for plugins contributing to shell header center section.\n */\nexport interface HeaderContentDefinition {\n /** Unique content ID */\n id: string;\n /** Content factory - called once when shell header renders */\n render: (container: HTMLElement) => void | (() => void);\n /** Called when content is removed (for cleanup) */\n onDestroy?: () => void;\n /** Order priority (lower = first, default: 100) */\n order?: number;\n}\n// #endregion\n\n// #region Column State (Persistence)\n\n/**\n * State for a single column. Captures user-driven changes at runtime.\n * Plugins can extend this interface via module augmentation to add their own state.\n *\n * @example\n * ```ts\n * // In filtering plugin\n * declare module '@toolbox-web/grid' {\n * interface ColumnState {\n * filter?: FilterValue;\n * }\n * }\n * ```\n */\nexport interface ColumnState {\n /** Column field identifier */\n field: string;\n /** Position index after reordering (0-based) */\n order: number;\n /** Width in pixels (undefined = use default) */\n width?: number;\n /** Visibility state */\n visible: boolean;\n /** Sort state (undefined = not sorted) */\n sort?: ColumnSortState;\n}\n\n/**\n * Sort state for a column\n */\nexport interface ColumnSortState {\n /** Sort direction */\n direction: 'asc' | 'desc';\n /** Priority for multi-sort (0 = primary, 1 = secondary, etc.) */\n priority: number;\n}\n\n/**\n * Complete grid column state for persistence.\n * Contains state for all columns, including plugin-contributed properties.\n */\nexport interface GridColumnState {\n columns: ColumnState[];\n}\n// #endregion\n\n// #region Public Event Detail Interfaces\nexport interface CellCommitDetail<TRow = unknown> {\n /** The mutated row after commit. */\n row: TRow;\n /** Field name whose value changed. */\n field: string;\n /** New value stored. */\n value: unknown;\n /** Index of the row in current data set. */\n rowIndex: number;\n /** All rows that have at least one committed change (snapshot list). */\n changedRows: TRow[];\n /** Indices parallel to changedRows. */\n changedRowIndices: number[];\n /** True if this row just entered the changed set. */\n firstTimeForRow: boolean;\n}\n\n/** Detail payload for a committed row edit (may or may not include changes). */\nexport interface RowCommitDetail<TRow = unknown> {\n /** Row index that lost edit focus. */\n rowIndex: number;\n /** Row object reference. */\n row: TRow;\n /** Whether any cell changes were actually committed in this row during the session. */\n changed: boolean;\n /** Current changed row collection. */\n changedRows: TRow[];\n /** Indices of changed rows. */\n changedRowIndices: number[];\n}\n\n/** Emitted when the changed rows tracking set is cleared programmatically. */\nexport interface ChangedRowsResetDetail<TRow = unknown> {\n /** New (empty) changed rows array after reset. */\n rows: TRow[];\n /** Parallel indices (likely empty). */\n indices: number[];\n}\n\n/** Detail for a sort change (direction 0 indicates cleared sort). */\nexport interface SortChangeDetail {\n /** Sorted field key. */\n field: string;\n /** Direction: 1 ascending, -1 descending, 0 cleared. */\n direction: 1 | -1 | 0;\n}\n\n/** Column resize event detail containing final pixel width. */\nexport interface ColumnResizeDetail {\n /** Resized column field key. */\n field: string;\n /** New width in pixels. */\n width: number;\n}\n\n/** Fired when keyboard navigation or programmatic focus changes active cell. */\nexport interface ActivateCellDetail {\n /** Zero-based row index now focused. */\n row: number;\n /** Zero-based column index now focused. */\n col: number;\n}\n\nexport interface ExternalMountViewDetail<TRow = unknown> {\n placeholder: HTMLElement;\n spec: unknown;\n context: { row: TRow; value: unknown; field: string; column: unknown };\n}\n\nexport interface ExternalMountEditorDetail<TRow = unknown> {\n placeholder: HTMLElement;\n spec: unknown;\n context: {\n row: TRow;\n value: unknown;\n field: string;\n column: unknown;\n commit: (v: unknown) => void;\n cancel: () => void;\n };\n}\n\nexport interface DataGridEventMap<TRow = unknown> {\n 'cell-commit': CellCommitDetail<TRow>;\n 'row-commit': RowCommitDetail<TRow>;\n 'changed-rows-reset': ChangedRowsResetDetail<TRow>;\n 'mount-external-view': ExternalMountViewDetail<TRow>;\n 'mount-external-editor': ExternalMountEditorDetail<TRow>;\n 'sort-change': SortChangeDetail;\n 'column-resize': ColumnResizeDetail;\n 'activate-cell': ActivateCellDetail;\n 'column-state-change': GridColumnState;\n}\n\nexport type DataGridEventDetail<K extends keyof DataGridEventMap<unknown>, TRow = unknown> = DataGridEventMap<TRow>[K];\nexport type DataGridCustomEvent<K extends keyof DataGridEventMap<unknown>, TRow = unknown> = CustomEvent<\n DataGridEventMap<TRow>[K]\n>;\n\n// Internal code now reuses the public ColumnEditorContext; provide alias for backward compatibility\nexport type EditorContext<T = unknown> = ColumnEditorContext<T, unknown>;\n\nexport interface EvalContext {\n value: unknown;\n row: Record<string, unknown> | null;\n}\n// #endregion\n","import type { ColumnConfigMap, InferredColumnResult, PrimitiveColumnType } from '../types';\n/**\n * Best-effort primitive type inference for a cell value used during automatic column generation.\n */\nfunction inferType(value: any): PrimitiveColumnType {\n if (value == null) return 'string';\n if (typeof value === 'number') return 'number';\n if (typeof value === 'boolean') return 'boolean';\n if (value instanceof Date) return 'date';\n if (typeof value === 'string' && /\\d{4}-\\d{2}-\\d{2}/.test(value) && !isNaN(Date.parse(value))) return 'date';\n return 'string';\n}\n/**\n * Derive column definitions from provided configuration or by inspecting the first row of data.\n * Returns both the resolved column array and a field->type map.\n */\nexport function inferColumns<TRow extends Record<string, unknown>>(\n rows: TRow[],\n provided?: ColumnConfigMap<TRow>\n): InferredColumnResult<TRow> {\n if (provided && provided.length) {\n const typeMap: Record<string, PrimitiveColumnType> = {};\n provided.forEach((col) => {\n if (col.type) typeMap[col.field] = col.type;\n });\n return { columns: provided, typeMap };\n }\n const sample = rows[0] || ({} as TRow);\n const columns: ColumnConfigMap<TRow> = Object.keys(sample).map((k) => {\n const v = (sample as any)[k];\n const type = inferType(v);\n return { field: k as keyof TRow & string, header: k.charAt(0).toUpperCase() + k.slice(1), type };\n });\n const typeMap: Record<string, PrimitiveColumnType> = {};\n columns.forEach((c) => {\n typeMap[c.field] = c.type || 'string';\n });\n return { columns, typeMap };\n}\nexport { inferType };\n","// Centralized template expression evaluation & sanitization utilities.\n// Responsible for safely interpolating {{ }} expressions while blocking\n// access to dangerous globals / reflective capabilities.\nimport type { EvalContext } from '../types';\n\nconst EXPR_RE = /{{\\s*([^}]+)\\s*}}/g;\nconst EMPTY_SENTINEL = '__DG_EMPTY__';\nconst SAFE_EXPR = /^[\\w$. '?+\\-*/%:()!<>=,&|]+$/;\nconst FORBIDDEN =\n /__(proto|defineGetter|defineSetter)|constructor|window|globalThis|global|process|Function|import|eval|Reflect|Proxy|Error|arguments|document|location|cookie|localStorage|sessionStorage|indexedDB|fetch|XMLHttpRequest|WebSocket|Worker|SharedWorker|ServiceWorker|opener|parent|top|frames|self|this\\b/;\n\n// #region HTML Sanitization\n\n/**\n * Tags that are considered dangerous and will be completely removed.\n * These can execute scripts, load external resources, or manipulate the page.\n */\nconst DANGEROUS_TAGS = new Set([\n 'script',\n 'iframe',\n 'object',\n 'embed',\n 'form',\n 'input',\n 'button',\n 'textarea',\n 'select',\n 'link',\n 'meta',\n 'base',\n 'style',\n 'template',\n 'slot',\n 'portal',\n 'frame',\n 'frameset',\n 'applet',\n 'noscript',\n 'noembed',\n 'plaintext',\n 'xmp',\n 'listing',\n]);\n\n/**\n * Attributes that are considered dangerous - event handlers and data loading.\n */\nconst DANGEROUS_ATTR_PATTERN = /^on\\w+$/i;\n\n/**\n * Attributes that can contain URLs which might be javascript: or data: URIs.\n */\nconst URL_ATTRS = new Set(['href', 'src', 'action', 'formaction', 'data', 'srcdoc', 'xlink:href', 'poster', 'srcset']);\n\n/**\n * Protocol patterns that are dangerous in URLs.\n */\nconst DANGEROUS_URL_PROTOCOL = /^\\s*(javascript|vbscript|data|blob):/i;\n\n/**\n * Sanitize an HTML string by removing dangerous tags and attributes.\n * This is a defense-in-depth measure for content rendered via innerHTML.\n *\n * @param html - Raw HTML string to sanitize\n * @returns Sanitized HTML string safe for innerHTML\n */\nexport function sanitizeHTML(html: string): string {\n if (!html || typeof html !== 'string') return '';\n\n // Fast path: if no HTML tags at all, return as-is (already safe)\n if (html.indexOf('<') === -1) return html;\n\n const template = document.createElement('template');\n template.innerHTML = html;\n\n sanitizeNode(template.content);\n\n return template.innerHTML;\n}\n\n/**\n * Recursively sanitize a DOM node tree.\n */\nfunction sanitizeNode(root: DocumentFragment | Element): void {\n const toRemove: Element[] = [];\n\n // Use querySelectorAll to find all elements, then filter\n const elements = root.querySelectorAll('*');\n\n for (const el of elements) {\n const tagName = el.tagName.toLowerCase();\n\n // Check if tag is dangerous\n if (DANGEROUS_TAGS.has(tagName)) {\n toRemove.push(el);\n continue;\n }\n\n // SVG elements need special handling - they can contain script-like behavior\n if (tagName === 'svg' || el.namespaceURI === 'http://www.w3.org/2000/svg') {\n // Remove entire SVG if it has any suspicious attributes\n const hasDangerousContent = Array.from(el.attributes).some(\n (attr) => DANGEROUS_ATTR_PATTERN.test(attr.name) || attr.name === 'href' || attr.name === 'xlink:href',\n );\n if (hasDangerousContent) {\n toRemove.push(el);\n continue;\n }\n }\n\n // Check and remove dangerous attributes\n const attrsToRemove: string[] = [];\n for (const attr of el.attributes) {\n const attrName = attr.name.toLowerCase();\n\n // Event handlers (onclick, onerror, onload, etc.)\n if (DANGEROUS_ATTR_PATTERN.test(attrName)) {\n attrsToRemove.push(attr.name);\n continue;\n }\n\n // URL attributes with dangerous protocols\n if (URL_ATTRS.has(attrName) && DANGEROUS_URL_PROTOCOL.test(attr.value)) {\n attrsToRemove.push(attr.name);\n continue;\n }\n\n // style attribute can contain expressions (IE) or url() with javascript:\n if (attrName === 'style' && /expression\\s*\\(|javascript:|behavior\\s*:/i.test(attr.value)) {\n attrsToRemove.push(attr.name);\n continue;\n }\n }\n\n attrsToRemove.forEach((name) => el.removeAttribute(name));\n }\n\n // Remove dangerous elements (do this after iteration to avoid modifying during traversal)\n toRemove.forEach((el) => el.remove());\n}\n\n// #endregion\n\nexport function evalTemplateString(raw: string, ctx: EvalContext): string {\n if (!raw || raw.indexOf('{{') === -1) return raw; // fast path (no expressions)\n const parts: { expr: string; result: string }[] = [];\n const evaluated = raw.replace(EXPR_RE, (_m, expr) => {\n const res = evalSingle(expr, ctx);\n parts.push({ expr: expr.trim(), result: res });\n return res;\n });\n const finalStr = postProcess(evaluated);\n // If every part evaluated to EMPTY_SENTINEL we treat this as intentionally blank.\n // If any expression was blocked due to forbidden token (EMPTY_SENTINEL) we *still* only output ''\n // but do not escalate to BLOCKED_SENTINEL unless the original contained explicit forbidden tokens.\n const allEmpty = parts.length && parts.every((p) => p.result === '' || p.result === EMPTY_SENTINEL);\n const hadForbidden = /Reflect\\.|\\bProxy\\b|ownKeys\\(/.test(raw);\n if (hadForbidden || allEmpty) return '';\n return finalStr;\n}\n\nfunction evalSingle(expr: string, ctx: EvalContext): string {\n expr = (expr || '').trim();\n if (!expr) return EMPTY_SENTINEL;\n if (/\\b(Reflect|Proxy|ownKeys)\\b/.test(expr)) return EMPTY_SENTINEL;\n if (expr === 'value') return ctx.value == null ? EMPTY_SENTINEL : String(ctx.value);\n if (expr.startsWith('row.') && !/[()?]/.test(expr) && !expr.includes(':')) {\n const key = expr.slice(4);\n const v = ctx.row ? ctx.row[key] : undefined;\n return v == null ? EMPTY_SENTINEL : String(v);\n }\n if (expr.length > 80) return EMPTY_SENTINEL;\n if (!SAFE_EXPR.test(expr) || FORBIDDEN.test(expr)) return EMPTY_SENTINEL;\n const dotChain = expr.match(/\\./g);\n if (dotChain && dotChain.length > 1) return EMPTY_SENTINEL;\n try {\n \n const fn = new Function('value', 'row', `return (${expr});`);\n const out = fn(ctx.value, ctx.row);\n const str = out == null ? '' : String(out);\n if (/Reflect|Proxy|ownKeys/.test(str)) return EMPTY_SENTINEL;\n return str || EMPTY_SENTINEL;\n } catch {\n return EMPTY_SENTINEL;\n }\n}\n\nfunction postProcess(s: string): string {\n if (!s) return s;\n return s\n .replace(new RegExp(EMPTY_SENTINEL, 'g'), '')\n .replace(/Reflect\\.[^<>{}\\s]+/g, '')\n .replace(/\\bProxy\\b/g, '')\n .replace(/ownKeys\\([^)]*\\)/g, '');\n}\n\nexport function finalCellScrub(cell: HTMLElement): void {\n if (/Reflect|Proxy|ownKeys/.test(cell.textContent || '')) {\n Array.from(cell.childNodes).forEach((n) => {\n if (n.nodeType === Node.TEXT_NODE && /Reflect|Proxy|ownKeys/.test(n.textContent || '')) n.textContent = '';\n });\n if (/Reflect|Proxy|ownKeys/.test(cell.textContent || '')) {\n // If remaining content still includes forbidden tokens inside element nodes, clear children entirely.\n const still = /Reflect|Proxy|ownKeys/.test(cell.textContent || '');\n if (still) {\n while (cell.firstChild) cell.removeChild(cell.firstChild);\n }\n cell.textContent = (cell.textContent || '').replace(/Reflect|Proxy|ownKeys/g, '');\n }\n if ((cell.textContent || '').trim().length === 0) cell.textContent = '';\n }\n}\n\nexport function compileTemplate(raw: string) {\n const forceBlank = /Reflect\\.|\\bProxy\\b|ownKeys\\(/.test(raw);\n const fn = (ctx: EvalContext) => {\n if (forceBlank) return '';\n const out = evalTemplateString(raw, ctx);\n return out;\n };\n (fn as any).__blocked = forceBlank;\n return fn;\n}\n","import type { ColumnConfig, ColumnInternal, InternalGrid } from '../types';\nimport { FitModeEnum } from '../types';\nimport { inferColumns } from './inference';\nimport { compileTemplate } from './sanitize';\n\n/**\n * Parse `<tbw-grid-column>` elements from the host light DOM into column config objects,\n * capturing template elements for later cloning / compilation.\n */\nexport function parseLightDomColumns(host: HTMLElement): ColumnInternal[] {\n const domColumns = Array.from(host.querySelectorAll('tbw-grid-column')) as HTMLElement[];\n return domColumns\n .map((el) => {\n const field = el.getAttribute('field') || '';\n if (!field) return null;\n const rawType = el.getAttribute('type') || undefined;\n const allowedTypes = new Set(['number', 'string', 'date', 'boolean', 'select', 'typeahead']);\n const type = rawType && allowedTypes.has(rawType) ? (rawType as any) : undefined;\n const header = el.getAttribute('header') || undefined;\n const sortable = el.hasAttribute('sortable');\n const editable = el.hasAttribute('editable');\n const config: ColumnInternal = { field, type, header, sortable, editable };\n if (el.hasAttribute('resizable')) (config as any).resizable = true;\n if (el.hasAttribute('sizable')) (config as any).resizable = true; // legacy attribute support\n // Parse options attribute for select/typeahead: \"value1:Label1,value2:Label2\" or \"value1,value2\"\n const optionsAttr = el.getAttribute('options');\n if (optionsAttr) {\n (config as any).options = optionsAttr.split(',').map((item) => {\n const [value, label] = item.includes(':') ? item.split(':') : [item.trim(), item.trim()];\n return { value: value.trim(), label: label?.trim() || value.trim() };\n });\n }\n const viewTpl = el.querySelector('tbw-grid-column-view');\n const editorTpl = el.querySelector('tbw-grid-column-editor');\n const headerTpl = el.querySelector('tbw-grid-column-header');\n if (viewTpl) config.__viewTemplate = viewTpl as HTMLElement;\n if (editorTpl) config.__editorTemplate = editorTpl as HTMLElement;\n if (headerTpl) config.__headerTemplate = headerTpl as HTMLElement;\n return config;\n })\n .filter((c): c is ColumnInternal => !!c);\n}\n\n/**\n * Merge programmatic columns with light DOM columns by field name, allowing DOM-provided\n * attributes / templates to supplement (not overwrite) programmatic definitions.\n * Any DOM columns without a programmatic counterpart are appended.\n */\nexport function mergeColumns(\n programmatic: ColumnConfig[] | undefined,\n dom: ColumnConfig[] | undefined,\n): ColumnInternal[] {\n if ((!programmatic || !programmatic.length) && (!dom || !dom.length)) return [];\n if (!programmatic || !programmatic.length) return (dom || []) as ColumnInternal[];\n if (!dom || !dom.length) return programmatic as ColumnInternal[];\n const domMap: Record<string, ColumnInternal> = {};\n (dom as ColumnInternal[]).forEach((c) => (domMap[c.field] = c));\n const merged: ColumnInternal[] = (programmatic as ColumnInternal[]).map((c) => {\n const d = domMap[c.field];\n if (!d) return c;\n const m: ColumnInternal = { ...c };\n if (d.header && !m.header) m.header = d.header;\n if (d.type && !m.type) m.type = d.type;\n m.sortable = c.sortable || d.sortable;\n if ((c as any).resizable === true || (d as any).resizable === true) (m as any).resizable = true;\n m.editable = c.editable || d.editable;\n if ((d as any).__viewTemplate) (m as any).__viewTemplate = (d as any).__viewTemplate;\n if ((d as any).__editorTemplate) (m as any).__editorTemplate = (d as any).__editorTemplate;\n if ((d as any).__headerTemplate) (m as any).__headerTemplate = (d as any).__headerTemplate;\n delete domMap[c.field];\n return m;\n });\n Object.keys(domMap).forEach((field) => merged.push(domMap[field]));\n return merged;\n}\n\n/**\n * Safely add a token to an element's `part` attribute (supporting the CSS ::part API)\n * without duplicating values. Falls back to string manipulation if `el.part` API isn't present.\n */\nexport function addPart(el: HTMLElement, token: string): void {\n try {\n (el as any).part?.add?.(token);\n } catch {\n /* empty */\n }\n const existing = el.getAttribute('part');\n if (!existing) el.setAttribute('part', token);\n else if (!existing.split(/\\s+/).includes(token)) el.setAttribute('part', existing + ' ' + token);\n}\n\n/**\n * Resolve the effective column list for the grid by combining:\n * 1. Programmatic columns (`grid._columns`)\n * 2. Light DOM `<tbw-grid-column>` definitions (cached)\n * 3. Inferred columns (if none provided)\n * Also compiles inline template expressions into fast functions.\n * Columns with `hidden: true` in config are added to hidden tracking.\n */\nexport function getColumnConfiguration(grid: InternalGrid): void {\n if (!grid.__lightDomColumnsCache) {\n grid.__originalColumnNodes = Array.from(\n (grid as unknown as HTMLElement).querySelectorAll('tbw-grid-column'),\n ) as HTMLElement[];\n grid.__lightDomColumnsCache = grid.__originalColumnNodes.length\n ? parseLightDomColumns(grid as unknown as HTMLElement)\n : [];\n }\n const lightDomColumns = grid.__lightDomColumnsCache;\n const merged = mergeColumns(grid._columns, lightDomColumns);\n merged.forEach((c: ColumnInternal) => {\n if (c.__viewTemplate && !c.__compiledView) {\n c.__compiledView = compileTemplate((c.__viewTemplate as HTMLElement).innerHTML);\n }\n if (c.__editorTemplate && !c.__compiledEditor) {\n c.__compiledEditor = compileTemplate((c.__editorTemplate as HTMLElement).innerHTML);\n }\n });\n const { columns } = inferColumns(grid._rows, merged as any);\n grid._columns = columns as ColumnInternal[];\n}\n\n/**\n * Measure rendered header + visible cell content to assign initial pixel widths\n * to columns when in `content` fit mode. Runs only once unless fit mode changes.\n */\nexport function autoSizeColumns(grid: InternalGrid): void {\n const mode = (grid as any).effectiveConfig?.fitMode || grid.fitMode || FitModeEnum.STRETCH;\n // Run for both stretch (to derive baseline pixel widths before fr distribution) and fixed.\n if (mode !== FitModeEnum.STRETCH && mode !== FitModeEnum.FIXED) return;\n if (grid.__didInitialAutoSize) return;\n if (!(grid as unknown as HTMLElement).isConnected) return;\n const headerCells = (grid._headerRowEl?.children || []) as any;\n if (!headerCells.length) return;\n let changed = false;\n grid._visibleColumns.forEach((col: ColumnInternal, i: number) => {\n if (col.width) return;\n const headerCell = headerCells[i] as HTMLElement | undefined;\n let max = headerCell ? headerCell.scrollWidth : 0;\n for (const rowEl of grid._rowPool) {\n const cell = rowEl.children[i] as HTMLElement | undefined;\n if (cell) {\n const w = cell.scrollWidth;\n if (w > max) max = w;\n }\n }\n if (max > 0) {\n col.width = max + 2;\n (col as ColumnInternal).__autoSized = true;\n changed = true;\n }\n });\n if (changed) updateTemplate(grid);\n grid.__didInitialAutoSize = true;\n}\n\n/**\n * Compute and apply the CSS grid template string that drives column layout.\n * Uses `fr` units for flexible (non user-resized) columns in stretch mode, otherwise\n * explicit pixel widths or auto sizing.\n */\nexport function updateTemplate(grid: InternalGrid): void {\n // Modes:\n // - 'stretch': columns with explicit width use that width; columns without width are flexible\n // Uses minmax(minWidth, maxWidth) when both min/max specified (bounded flex)\n // Uses minmax(minWidth, 1fr) when only min specified (grows unbounded)\n // Uses minmax(defaultMin, maxWidth) when only max specified (capped growth)\n // - 'fixed': columns with explicit width use that width; columns without width use max-content\n const mode = (grid as any).effectiveConfig?.fitMode || grid.fitMode || FitModeEnum.STRETCH;\n\n if (mode === FitModeEnum.STRETCH) {\n grid._gridTemplate = grid._visibleColumns\n .map((c: ColumnInternal) => {\n if (c.width) return `${c.width}px`;\n // Flexible column: pure 1fr unless minWidth specified\n const min = (c as any).minWidth;\n return min != null ? `minmax(${min}px, 1fr)` : '1fr';\n })\n .join(' ')\n .trim();\n } else {\n // fixed mode: explicit pixel widths or max-content for content-based sizing\n grid._gridTemplate = grid._visibleColumns\n .map((c: ColumnInternal) => (c.width ? `${c.width}px` : 'max-content'))\n .join(' ');\n }\n ((grid as unknown as HTMLElement).style as any).setProperty('--tbw-column-template', grid._gridTemplate);\n}\n","/**\n * Default Editors Module\n *\n * Provides built-in editor factories for different column types.\n */\n\nimport type { ColumnConfig, EditorContext } from '../types';\n\n/**\n * Returns a default editor factory function for the given column type.\n * Each editor handles focus, commit on blur/Enter, and cancel on Escape.\n */\nexport function defaultEditorFor(column: ColumnConfig<any>): (ctx: EditorContext) => HTMLElement | string {\n switch (column.type) {\n case 'number':\n return (ctx: EditorContext) => {\n const input = document.createElement('input');\n input.type = 'number';\n input.value = ctx.value != null ? String(ctx.value) : '';\n input.addEventListener('blur', () => ctx.commit(input.value === '' ? null : Number(input.value)));\n input.addEventListener('keydown', (e) => {\n if (e.key === 'Enter') ctx.commit(input.value === '' ? null : Number(input.value));\n if (e.key === 'Escape') ctx.cancel();\n });\n input.focus();\n return input;\n };\n case 'boolean':\n return (ctx: EditorContext) => {\n const input = document.createElement('input');\n input.type = 'checkbox';\n input.checked = !!ctx.value;\n input.addEventListener('change', () => ctx.commit(input.checked));\n input.focus();\n return input;\n };\n case 'date':\n return (ctx: EditorContext) => {\n const input = document.createElement('input');\n input.type = 'date';\n if (ctx.value instanceof Date) input.valueAsDate = ctx.value;\n input.addEventListener('change', () => ctx.commit(input.valueAsDate));\n input.addEventListener('keydown', (e) => {\n if (e.key === 'Escape') ctx.cancel();\n });\n input.focus();\n return input;\n };\n case 'select':\n case 'typeahead':\n return (ctx: EditorContext) => {\n const select = document.createElement('select');\n if ((ctx.column as any).multi) select.multiple = true;\n const options =\n typeof (ctx.column as any).options === 'function'\n ? (ctx.column as any).options()\n : (ctx.column as any).options || [];\n options.forEach((opt: any) => {\n const o = document.createElement('option');\n o.value = String(opt.value);\n o.textContent = opt.label;\n if ((ctx.column as any).multi && Array.isArray(ctx.value) && ctx.value.includes(opt.value)) o.selected = true;\n else if (!(ctx.column as any).multi && ctx.value === opt.value) o.selected = true;\n select.appendChild(o);\n });\n const commitValue = () => {\n if ((ctx.column as any).multi) {\n const values: any[] = [];\n Array.from(select.selectedOptions).forEach((o) => {\n values.push(o.value);\n });\n ctx.commit(values);\n } else {\n ctx.commit(select.value);\n }\n };\n select.addEventListener('change', commitValue);\n select.addEventListener('blur', commitValue);\n select.addEventListener('keydown', (e) => {\n if (e.key === 'Escape') ctx.cancel();\n });\n select.focus();\n return select;\n };\n default:\n return (ctx: EditorContext) => {\n const input = document.createElement('input');\n input.type = 'text';\n input.value = ctx.value != null ? String(ctx.value) : '';\n input.addEventListener('blur', () => ctx.commit(input.value));\n input.addEventListener('keydown', (e) => {\n if (e.key === 'Enter') ctx.commit(input.value);\n if (e.key === 'Escape') ctx.cancel();\n });\n input.focus();\n return input;\n };\n }\n}\n","/**\n * Central keyboard handler attached to the host element. Manages navigation, paging,\n * and edit lifecycle triggers while respecting active form field interactions.\n */\nimport type { InternalGrid } from '../types';\n\nexport function handleGridKeyDown(grid: InternalGrid, e: KeyboardEvent): void {\n // Dispatch to plugin system first - if any plugin handles it, stop here\n if (grid._dispatchKeyDown?.(e)) {\n return;\n }\n\n const maxRow = grid._rows.length - 1;\n const maxCol = grid._visibleColumns.length - 1;\n const editing = grid._activeEditRows !== undefined && grid._activeEditRows !== -1;\n const col = grid._visibleColumns[grid._focusCol];\n const colType = col?.type;\n const path = (e as any).composedPath ? (e as any).composedPath() : [];\n const target = (path && path.length ? path[0] : (e.target as any)) as HTMLElement | null;\n const isFormField = (el: HTMLElement | null) => {\n if (!el) return false;\n const tag = el.tagName;\n if (tag === 'INPUT' || tag === 'SELECT' || tag === 'TEXTAREA') return true;\n if (el.isContentEditable) return true;\n return false;\n };\n if (isFormField(target) && (e.key === 'Home' || e.key === 'End')) return;\n if (isFormField(target) && (e.key === 'ArrowUp' || e.key === 'ArrowDown')) {\n if ((target as HTMLInputElement).tagName === 'INPUT' && (target as HTMLInputElement).type === 'number') return;\n }\n // Let arrow left/right navigate within text inputs instead of moving cells\n if (isFormField(target) && (e.key === 'ArrowLeft' || e.key === 'ArrowRight')) return;\n // Let Enter/Escape be handled by the input's own handlers first\n if (isFormField(target) && (e.key === 'Enter' || e.key === 'Escape')) return;\n if (editing && (colType === 'select' || colType === 'typeahead') && (e.key === 'ArrowDown' || e.key === 'ArrowUp'))\n return;\n switch (e.key) {\n case 'Tab': {\n e.preventDefault();\n const forward = !e.shiftKey;\n if (forward) {\n if (grid._focusCol < maxCol) grid._focusCol += 1;\n else {\n if (typeof grid.commitActiveRowEdit === 'function') grid.commitActiveRowEdit();\n if (grid._focusRow < maxRow) {\n grid._focusRow += 1;\n grid._focusCol = 0;\n }\n }\n } else {\n if (grid._focusCol > 0) grid._focusCol -= 1;\n else if (grid._focusRow > 0) {\n if (typeof grid.commitActiveRowEdit === 'function' && grid._activeEditRows === grid._focusRow)\n grid.commitActiveRowEdit();\n grid._focusRow -= 1;\n grid._focusCol = maxCol;\n }\n }\n ensureCellVisible(grid);\n return;\n }\n case 'ArrowDown':\n if (editing && typeof grid.commitActiveRowEdit === 'function') grid.commitActiveRowEdit();\n grid._focusRow = Math.min(maxRow, grid._focusRow + 1);\n e.preventDefault();\n break;\n case 'ArrowUp':\n if (editing && typeof grid.commitActiveRowEdit === 'function') grid.commitActiveRowEdit();\n grid._focusRow = Math.max(0, grid._focusRow - 1);\n e.preventDefault();\n break;\n case 'ArrowRight':\n grid._focusCol = Math.min(maxCol, grid._focusCol + 1);\n e.preventDefault();\n break;\n case 'ArrowLeft':\n grid._focusCol = Math.max(0, grid._focusCol - 1);\n e.preventDefault();\n break;\n case 'Home':\n if (e.ctrlKey || e.metaKey) {\n // CTRL+Home: navigate to first row, first cell\n if (editing && typeof grid.commitActiveRowEdit === 'function') grid.commitActiveRowEdit();\n grid._focusRow = 0;\n grid._focusCol = 0;\n } else {\n // Home: navigate to first cell in current row\n grid._focusCol = 0;\n }\n e.preventDefault();\n ensureCellVisible(grid, { forceScrollLeft: true });\n return;\n case 'End':\n if (e.ctrlKey || e.metaKey) {\n // CTRL+End: navigate to last row, last cell\n if (editing && typeof grid.commitActiveRowEdit === 'function') grid.commitActiveRowEdit();\n grid._focusRow = maxRow;\n grid._focusCol = maxCol;\n } else {\n // End: navigate to last cell in current row\n grid._focusCol = maxCol;\n }\n e.preventDefault();\n ensureCellVisible(grid, { forceScrollRight: true });\n return;\n case 'PageDown':\n grid._focusRow = Math.min(maxRow, grid._focusRow + 20);\n e.preventDefault();\n break;\n case 'PageUp':\n grid._focusRow = Math.max(0, grid._focusRow - 20);\n e.preventDefault();\n break;\n case 'Enter':\n if (typeof grid.beginBulkEdit === 'function') grid.beginBulkEdit(grid._focusRow);\n else\n (grid as unknown as HTMLElement).dispatchEvent(\n new CustomEvent('activate-cell', { detail: { row: grid._focusRow, col: grid._focusCol } }),\n );\n return ensureCellVisible(grid);\n default:\n return;\n }\n ensureCellVisible(grid);\n}\n\n/**\n * Options for ensureCellVisible to control scroll behavior.\n */\ninterface EnsureCellVisibleOptions {\n /** Force scroll to the leftmost position (for Home key) */\n forceScrollLeft?: boolean;\n /** Force scroll to the rightmost position (for End key) */\n forceScrollRight?: boolean;\n}\n\n/**\n * Scroll the viewport (virtualized or static) so the focused cell's row is visible\n * and apply visual focus styling / tabindex management.\n */\nexport function ensureCellVisible(grid: InternalGrid, options?: EnsureCellVisibleOptions): void {\n if (grid._virtualization?.enabled) {\n const { rowHeight, container, viewportEl } = grid._virtualization;\n // container is the faux scrollbar element that handles actual scrolling\n // viewportEl is the visible area element that has the correct height\n const scrollEl = container as HTMLElement | undefined;\n const visibleHeight = viewportEl?.clientHeight ?? scrollEl?.clientHeight ?? 0;\n if (scrollEl && visibleHeight > 0) {\n const y = grid._focusRow * rowHeight;\n if (y < scrollEl.scrollTop) {\n scrollEl.scrollTop = y;\n } else if (y + rowHeight > scrollEl.scrollTop + visibleHeight) {\n scrollEl.scrollTop = y - visibleHeight + rowHeight;\n }\n }\n }\n // Skip refreshVirtualWindow when in edit mode to avoid wiping editors\n const isEditing = grid._activeEditRows !== undefined && grid._activeEditRows !== -1;\n if (!isEditing) {\n grid.refreshVirtualWindow(false);\n }\n Array.from(grid._bodyEl.querySelectorAll('.cell-focus')).forEach((el: any) => el.classList.remove('cell-focus'));\n // Clear previous aria-selected markers\n Array.from(grid._bodyEl.querySelectorAll('[aria-selected=\"true\"]')).forEach((el: any) => {\n el.setAttribute('aria-selected', 'false');\n });\n const rowIndex = grid._focusRow;\n const vStart = (grid._virtualization as any).start ?? 0;\n const vEnd = (grid._virtualization as any).end ?? grid._rows.length;\n if (rowIndex >= vStart && rowIndex < vEnd) {\n const rowEl = grid._bodyEl.querySelectorAll('.data-grid-row')[rowIndex - vStart] as HTMLElement | null;\n const cell = rowEl?.children[grid._focusCol] as HTMLElement | undefined;\n if (cell) {\n cell.classList.add('cell-focus');\n cell.setAttribute('aria-selected', 'true');\n\n // Horizontal scroll: ensure focused cell is visible in the horizontal scroll area\n // The .tbw-scroll-area element handles horizontal scrolling\n const scrollArea = grid.shadowRoot?.querySelector('.tbw-scroll-area') as HTMLElement | null;\n if (scrollArea && cell) {\n // Handle forced scroll for Home/End keys - always scroll to edge\n if (options?.forceScrollLeft) {\n scrollArea.scrollLeft = 0;\n } else if (options?.forceScrollRight) {\n scrollArea.scrollLeft = scrollArea.scrollWidth - scrollArea.clientWidth;\n } else {\n // Get scroll boundary offsets from plugins (e.g., pinned columns)\n // This allows plugins to report how much of the scroll area they obscure\n // and whether the focused cell should skip scrolling (e.g., pinned cells are always visible)\n const offsets = grid._getHorizontalScrollOffsets?.(rowEl ?? undefined, cell) ?? { left: 0, right: 0 };\n\n if (!offsets.skipScroll) {\n // Get cell position relative to the scroll area\n const cellRect = cell.getBoundingClientRect();\n const scrollAreaRect = scrollArea.getBoundingClientRect();\n // Calculate the cell's position relative to scroll area's visible region\n const cellLeft = cellRect.left - scrollAreaRect.left + scrollArea.scrollLeft;\n const cellRight = cellLeft + cellRect.width;\n // Adjust visible boundaries to account for plugin-reported offsets\n const visibleLeft = scrollArea.scrollLeft + offsets.left;\n const visibleRight = scrollArea.scrollLeft + scrollArea.clientWidth - offsets.right;\n // Scroll horizontally if needed\n if (cellLeft < visibleLeft) {\n scrollArea.scrollLeft = cellLeft - offsets.left;\n } else if (cellRight > visibleRight) {\n scrollArea.scrollLeft = cellRight - scrollArea.clientWidth + offsets.right;\n }\n }\n }\n }\n\n if (grid._activeEditRows !== undefined && grid._activeEditRows !== -1 && cell.classList.contains('editing')) {\n const focusTarget = cell.querySelector(\n 'input,select,textarea,[contenteditable=\"true\"],[contenteditable=\"\"],[tabindex]:not([tabindex=\"-1\"])',\n ) as HTMLElement | null;\n if (focusTarget && document.activeElement !== focusTarget) {\n try {\n focusTarget.focus();\n } catch {\n /* empty */\n }\n }\n } else if (!cell.contains(document.activeElement)) {\n if (!cell.hasAttribute('tabindex')) cell.setAttribute('tabindex', '-1');\n try {\n (cell as HTMLElement).focus({ preventScroll: true } as any);\n } catch {\n /* empty */\n }\n }\n }\n }\n}\n","import type { ColumnConfig, InternalGrid } from '../types';\nimport { addPart } from './columns';\nimport { commitCellValue, inlineEnterEdit, startRowEdit } from './editing';\nimport { ensureCellVisible } from './keyboard';\nimport { evalTemplateString, finalCellScrub, sanitizeHTML } from './sanitize';\n\n/** Callback type for plugin row rendering hook */\nexport type RenderRowHook = (row: any, rowEl: HTMLElement, rowIndex: number) => boolean;\n\n/**\n * Cell display value cache key on grid instance.\n * Structure: Map<rowIndex, Map<colIndex, displayString>>\n * This cache is invalidated when rows or columns change (epoch bump).\n */\nconst CELL_CACHE_KEY = '__cellDisplayCache';\nconst CELL_CACHE_EPOCH_KEY = '__cellCacheEpoch';\n\n/**\n * Get the cached display value for a cell, computing it if not cached.\n * This is the hot path during scroll - must be as fast as possible.\n */\nfunction getCellDisplayValue(\n grid: InternalGrid,\n rowIndex: number,\n colIndex: number,\n rowData: any,\n col: ColumnConfig<any>,\n epoch: number | undefined,\n): string {\n // Fast path: check cache first\n let cache = (grid as any)[CELL_CACHE_KEY] as Map<number, string[]> | undefined;\n const cacheEpoch = (grid as any)[CELL_CACHE_EPOCH_KEY];\n\n // Invalidate cache if epoch changed\n if (cache && cacheEpoch !== epoch) {\n cache = undefined;\n (grid as any)[CELL_CACHE_KEY] = undefined;\n }\n\n if (!cache) {\n cache = new Map();\n (grid as any)[CELL_CACHE_KEY] = cache;\n (grid as any)[CELL_CACHE_EPOCH_KEY] = epoch;\n }\n\n let rowCache = cache.get(rowIndex);\n if (rowCache && rowCache[colIndex] !== undefined) {\n return rowCache[colIndex];\n }\n\n // Compute the display value\n const displayValue = computeCellDisplayValue(rowData, col);\n\n // Cache it\n if (!rowCache) {\n rowCache = [];\n cache.set(rowIndex, rowCache);\n }\n rowCache[colIndex] = displayValue;\n\n return displayValue;\n}\n\n/**\n * Compute the display string for a cell value.\n * Handles formatting, date conversion, boolean display, etc.\n */\nfunction computeCellDisplayValue(rowData: any, col: ColumnConfig<any>): string {\n let value = rowData[col.field];\n\n // Apply format function if present\n const format = (col as any).format;\n if (format) {\n try {\n value = format(value, rowData);\n } catch {\n // Keep original value on format error\n }\n }\n\n // Type-specific conversion\n if (col.type === 'date') {\n if (value == null || value === '') return '';\n if (value instanceof Date) {\n return isNaN(value.getTime()) ? '' : value.toLocaleDateString();\n }\n if (typeof value === 'number' || typeof value === 'string') {\n const d = new Date(value);\n return isNaN(d.getTime()) ? '' : d.toLocaleDateString();\n }\n return '';\n }\n\n if (col.type === 'boolean') {\n return value ? '\\u{1F5F9}' : '\\u2610';\n }\n\n return value == null ? '' : String(value);\n}\n\n/**\n * Pre-compute display values for a range of rows.\n * Call this after rows change to warm the cache for visible + overscan rows.\n */\nexport function precomputeCellCache(\n grid: InternalGrid,\n startRow: number,\n endRow: number,\n epoch: number | undefined,\n): void {\n const columns = grid._visibleColumns;\n const rows = grid._rows;\n\n for (let r = startRow; r < endRow && r < rows.length; r++) {\n const rowData = rows[r];\n if (!rowData) continue;\n for (let c = 0; c < columns.length; c++) {\n // This will compute and cache\n getCellDisplayValue(grid, r, c, rowData, columns[c], epoch);\n }\n }\n}\n\n/**\n * Invalidate the cell cache (call when rows or columns change).\n */\nexport function invalidateCellCache(grid: InternalGrid): void {\n (grid as any)[CELL_CACHE_KEY] = undefined;\n (grid as any)[CELL_CACHE_EPOCH_KEY] = undefined;\n (grid as any).__hasSpecialColumns = undefined; // Reset fast-path check\n}\n\n/**\n * Render / patch the visible window of rows [start, end) using a recyclable DOM pool.\n * Newly required row elements are created and appended; excess are detached.\n * Uses an epoch counter to force full row rebuilds when structural changes (like columns) occur.\n * @param renderRowHook - Optional callback that plugins can use to render custom rows (e.g., group rows).\n * If it returns true, default rendering is skipped for that row.\n */\nexport function renderVisibleRows(\n grid: InternalGrid,\n start: number,\n end: number,\n epoch?: number,\n renderRowHook?: RenderRowHook,\n): void {\n const needed = Math.max(0, end - start);\n const bodyEl = grid._bodyEl;\n const columns = grid._visibleColumns;\n const colLen = columns.length;\n\n // Cache header row count once (check for group header row existence)\n let headerRowCount = (grid as any).__cachedHeaderRowCount;\n if (headerRowCount === undefined) {\n headerRowCount = grid.shadowRoot?.querySelector('.header-group-row') ? 2 : 1;\n (grid as any).__cachedHeaderRowCount = headerRowCount;\n }\n\n // Pool management: grow pool if needed\n while (grid._rowPool.length < needed) {\n const rowEl = document.createElement('div');\n rowEl.className = 'data-grid-row';\n rowEl.setAttribute('role', 'row');\n rowEl.addEventListener('click', (e) => handleRowClick(grid, e, rowEl, false));\n rowEl.addEventListener('dblclick', (e) => handleRowClick(grid, e, rowEl, true));\n grid._rowPool.push(rowEl);\n }\n\n // Remove excess pool elements from DOM and shrink pool\n if (grid._rowPool.length > needed) {\n for (let i = needed; i < grid._rowPool.length; i++) {\n const el = grid._rowPool[i];\n if (el.parentNode === bodyEl) el.remove();\n }\n grid._rowPool.length = needed;\n }\n\n // Check if any plugin has a renderRow hook (cache this)\n const hasRenderRowPlugins = renderRowHook && (grid as any).__hasRenderRowPlugins !== false;\n\n for (let i = 0; i < needed; i++) {\n const rowIndex = start + i;\n const rowData = grid._rows[rowIndex];\n const rowEl = grid._rowPool[i];\n\n // Always set aria-rowindex (1-based, accounting for header rows)\n rowEl.setAttribute('aria-rowindex', String(rowIndex + headerRowCount + 1));\n\n // Let plugins handle custom row rendering (e.g., group rows)\n if (hasRenderRowPlugins && renderRowHook!(rowData, rowEl, rowIndex)) {\n (rowEl as any).__epoch = epoch;\n (rowEl as any).__rowDataRef = rowData;\n if (rowEl.parentNode !== bodyEl) bodyEl.appendChild(rowEl);\n continue;\n }\n\n const rowEpoch = (rowEl as any).__epoch;\n const prevRef = (rowEl as any).__rowDataRef;\n const cellCount = rowEl.children.length;\n\n // Check if we need a full rebuild vs fast update\n const epochMatch = rowEpoch === epoch;\n const structureValid = epochMatch && cellCount === colLen;\n const dataRefChanged = prevRef !== rowData;\n\n // Need external view rebuild check when structure is valid but data changed\n let needsExternalRebuild = false;\n if (structureValid && dataRefChanged) {\n for (let c = 0; c < colLen; c++) {\n const col = columns[c];\n if ((col as any).externalView) {\n const cellCheck = rowEl.querySelector(`.cell[data-col=\"${c}\"] [data-external-view]`);\n if (!cellCheck) {\n needsExternalRebuild = true;\n break;\n }\n }\n }\n }\n\n if (!structureValid || needsExternalRebuild) {\n // Full rebuild needed - epoch changed, cell count mismatch, or external view missing\n const hasEditingCell = rowEl.querySelector('.cell.editing');\n const isActivelyEditedRow = grid._activeEditRows === rowIndex;\n\n // If DOM element has editors but this is NOT the actively edited row, clear them\n // (This happens when virtualization recycles the DOM element for a different row)\n if (hasEditingCell && !isActivelyEditedRow) {\n // Force full rebuild to clear stale editors\n if ((rowEl as any).__isCustomRow) {\n rowEl.className = 'data-grid-row';\n rowEl.setAttribute('role', 'row');\n (rowEl as any).__isCustomRow = false;\n }\n renderInlineRow(grid, rowEl, rowData, rowIndex);\n (rowEl as any).__epoch = epoch;\n (rowEl as any).__rowDataRef = rowData;\n } else if (hasEditingCell && isActivelyEditedRow) {\n // Row is in editing mode AND this is the correct row - preserve editors\n fastPatchRow(grid, rowEl, rowData, rowIndex);\n (rowEl as any).__rowDataRef = rowData;\n } else {\n if ((rowEl as any).__isCustomRow) {\n rowEl.className = 'data-grid-row';\n rowEl.setAttribute('role', 'row');\n (rowEl as any).__isCustomRow = false;\n }\n renderInlineRow(grid, rowEl, rowData, rowIndex);\n (rowEl as any).__epoch = epoch;\n (rowEl as any).__rowDataRef = rowData;\n\n // If this is the actively edited row but DOM doesn't have editors, create them\n if (isActivelyEditedRow) {\n const children = rowEl.children;\n for (let c = 0; c < children.length; c++) {\n const col = grid._visibleColumns[c];\n if (col && (col as any).editable) {\n inlineEnterEdit(grid, rowData, rowIndex, col, children[c] as HTMLElement);\n }\n }\n }\n }\n } else if (dataRefChanged) {\n // Same structure, different row data - fast update\n const hasEditingCell = rowEl.querySelector('.cell.editing');\n const isActivelyEditedRow = grid._activeEditRows === rowIndex;\n\n // If DOM element has editors but this is NOT the actively edited row, clear them\n if (hasEditingCell && !isActivelyEditedRow) {\n renderInlineRow(grid, rowEl, rowData, rowIndex);\n (rowEl as any).__epoch = epoch;\n (rowEl as any).__rowDataRef = rowData;\n } else {\n fastPatchRow(grid, rowEl, rowData, rowIndex);\n (rowEl as any).__rowDataRef = rowData;\n\n // If this is the actively edited row but DOM doesn't have editors, create them\n if (isActivelyEditedRow && !hasEditingCell) {\n const children = rowEl.children;\n for (let c = 0; c < children.length; c++) {\n const col = grid._visibleColumns[c];\n if (col && (col as any).editable) {\n inlineEnterEdit(grid, rowData, rowIndex, col, children[c] as HTMLElement);\n }\n }\n }\n }\n } else {\n // Same row data reference - just patch if any values changed\n const hasEditingCell = rowEl.querySelector('.cell.editing');\n const isActivelyEditedRow = grid._activeEditRows === rowIndex;\n\n // If DOM element has editors but this is NOT the actively edited row, clear them\n if (hasEditingCell && !isActivelyEditedRow) {\n renderInlineRow(grid, rowEl, rowData, rowIndex);\n (rowEl as any).__epoch = epoch;\n (rowEl as any).__rowDataRef = rowData;\n } else {\n fastPatchRow(grid, rowEl, rowData, rowIndex);\n\n // If this is the actively edited row but DOM doesn't have editors, create them\n if (isActivelyEditedRow && !hasEditingCell) {\n const children = rowEl.children;\n for (let c = 0; c < children.length; c++) {\n const col = grid._visibleColumns[c];\n if (col && (col as any).editable) {\n inlineEnterEdit(grid, rowData, rowIndex, col, children[c] as HTMLElement);\n }\n }\n }\n }\n }\n\n // Changed class toggle\n const isChanged = grid._changedRowIndices.has(rowIndex);\n const hasChangedClass = rowEl.classList.contains('changed');\n if (isChanged !== hasChangedClass) {\n rowEl.classList.toggle('changed', isChanged);\n }\n\n if (rowEl.parentNode !== bodyEl) bodyEl.appendChild(rowEl);\n }\n}\n\n/**\n * Fast patch path for an already-rendered row: updates plain text cells whose data changed\n * while skipping cells with external views, templates, or active editors.\n *\n * Optimized for scroll performance - avoids querySelectorAll in favor of children access.\n */\nfunction fastPatchRow(grid: InternalGrid, rowEl: HTMLElement, rowData: any, rowIndex: number): void {\n const children = rowEl.children;\n const columns = grid._visibleColumns;\n const colsLen = columns.length;\n const childLen = children.length;\n const minLen = colsLen < childLen ? colsLen : childLen;\n const focusRow = grid._focusRow;\n const focusCol = grid._focusCol;\n\n // Ultra-fast path: if no special columns (templates, formatters, etc.), use direct assignment\n // Check is cached on grid to avoid repeated iteration\n let hasSpecialCols = (grid as any).__hasSpecialColumns;\n if (hasSpecialCols === undefined) {\n hasSpecialCols = false;\n for (let i = 0; i < colsLen; i++) {\n const col = columns[i] as any;\n if (\n col.__viewTemplate ||\n col.__compiledView ||\n col.viewRenderer ||\n col.externalView ||\n col.format ||\n col.type === 'date' ||\n col.type === 'boolean'\n ) {\n hasSpecialCols = true;\n break;\n }\n }\n (grid as any).__hasSpecialColumns = hasSpecialCols;\n }\n\n const rowIndexStr = String(rowIndex);\n\n // Ultra-fast path for plain text grids - just set textContent directly\n if (!hasSpecialCols) {\n for (let i = 0; i < minLen; i++) {\n const cell = children[i] as HTMLElement;\n const value = rowData[columns[i].field];\n cell.textContent = value == null ? '' : String(value);\n // Update data-row for click handling\n if (cell.getAttribute('data-row') !== rowIndexStr) {\n cell.setAttribute('data-row', rowIndexStr);\n }\n // Update focus state - must be data-driven, not DOM-element-driven\n const shouldHaveFocus = focusRow === rowIndex && focusCol === i;\n const hasFocus = cell.classList.contains('cell-focus');\n if (shouldHaveFocus !== hasFocus) {\n cell.classList.toggle('cell-focus', shouldHaveFocus);\n // aria-selected only valid for gridcell, not checkbox (but ultra-fast path has no special cols)\n cell.setAttribute('aria-selected', String(shouldHaveFocus));\n }\n }\n return;\n }\n\n // Check if any external view placeholder is missing - if so, do full rebuild\n for (let i = 0; i < minLen; i++) {\n const col = columns[i] as any;\n if (col.externalView) {\n const cell = children[i] as HTMLElement;\n if (!cell.querySelector('[data-external-view]')) {\n renderInlineRow(grid, rowEl, rowData, rowIndex);\n return;\n }\n }\n }\n\n // Standard path for grids with special columns\n for (let i = 0; i < minLen; i++) {\n const col = columns[i] as any;\n const cell = children[i] as HTMLElement;\n\n // Update data-row for click handling\n if (cell.getAttribute('data-row') !== rowIndexStr) {\n cell.setAttribute('data-row', rowIndexStr);\n }\n\n // Update focus state - must be data-driven, not DOM-element-driven\n const shouldHaveFocus = focusRow === rowIndex && focusCol === i;\n const hasFocus = cell.classList.contains('cell-focus');\n if (shouldHaveFocus !== hasFocus) {\n cell.classList.toggle('cell-focus', shouldHaveFocus);\n cell.setAttribute('aria-selected', String(shouldHaveFocus));\n }\n\n // Skip cells in edit mode\n if (cell.classList.contains('editing')) continue;\n\n // Handle viewRenderer - must re-invoke to get updated content\n if (col.viewRenderer) {\n const value = rowData[col.field];\n const produced = col.viewRenderer({ row: rowData, value, field: col.field, column: col });\n if (typeof produced === 'string') {\n cell.innerHTML = sanitizeHTML(produced);\n } else if (produced) {\n cell.innerHTML = '';\n cell.appendChild(produced);\n } else {\n cell.textContent = value == null ? '' : String(value);\n }\n continue;\n }\n\n // Skip templated / external cells (these need full rebuild to remount)\n if (col.__viewTemplate || col.__compiledView || col.externalView) {\n continue;\n }\n\n // Compute and set display value\n const value = rowData[col.field];\n let displayStr: string;\n\n if (col.format) {\n try {\n const formatted = col.format(value, rowData);\n displayStr = formatted == null ? '' : String(formatted);\n } catch {\n displayStr = value == null ? '' : String(value);\n }\n } else if (col.type === 'date') {\n if (value == null || value === '') {\n displayStr = '';\n } else if (value instanceof Date) {\n displayStr = isNaN(value.getTime()) ? '' : value.toLocaleDateString();\n } else {\n const d = new Date(value);\n displayStr = isNaN(d.getTime()) ? '' : d.toLocaleDateString();\n }\n cell.textContent = displayStr;\n } else if (col.type === 'boolean') {\n const isTrue = !!value;\n // Boolean cells have inner span with checkbox role for ARIA compliance\n cell.innerHTML = `<span role=\"checkbox\" aria-checked=\"${isTrue}\" aria-label=\"${isTrue}\">${isTrue ? '🗹' : '☐'}</span>`;\n } else {\n displayStr = value == null ? '' : String(value);\n cell.textContent = displayStr;\n }\n }\n}\n\n/**\n * Full reconstruction of a row's set of cells including templated, external view, and formatted content.\n * Attaches event handlers for editing and accessibility per cell.\n */\nexport function renderInlineRow(grid: InternalGrid, rowEl: HTMLElement, rowData: any, rowIndex: number): void {\n rowEl.innerHTML = '';\n\n // Pre-cache values used in the loop\n const columns = grid._visibleColumns;\n const colsLen = columns.length;\n const focusRow = grid._focusRow;\n const focusCol = grid._focusCol;\n const editMode = (grid as any).effectiveConfig?.editOn || grid.editOn;\n const gridEl = grid as unknown as HTMLElement;\n\n // Use DocumentFragment for batch DOM insertion\n const fragment = document.createDocumentFragment();\n\n for (let colIndex = 0; colIndex < colsLen; colIndex++) {\n const col: ColumnConfig<any> = columns[colIndex];\n const cell = document.createElement('div');\n cell.className = 'cell';\n addPart(cell, 'cell');\n\n // All cells get role=gridcell (required by role=row)\n cell.setAttribute('role', 'gridcell');\n // aria-colindex is 1-based\n cell.setAttribute('aria-colindex', String(colIndex + 1));\n cell.setAttribute('data-col', String(colIndex));\n cell.setAttribute('data-row', String(rowIndex));\n cell.setAttribute('data-field', col.field); // Field name for column identification\n const isCheckbox = col.type === 'boolean';\n if (col.type) cell.setAttribute('data-type', col.type as any);\n\n let value = (rowData as any)[col.field];\n const format = (col as any).format;\n if (format) {\n try {\n value = format(value, rowData);\n } catch {\n /* empty */\n }\n }\n\n const compiled = (col as any).__compiledView as ((ctx: any) => string) | undefined;\n const tplHolder = (col as any).__viewTemplate as HTMLElement | undefined;\n const viewRenderer = (col as any).viewRenderer;\n const externalView = (col as any).externalView;\n\n // Track if we used a template that needs sanitization\n let needsSanitization = false;\n\n if (viewRenderer) {\n const produced = viewRenderer({ row: rowData, value, field: col.field, column: col });\n if (typeof produced === 'string') {\n // Sanitize HTML from viewRenderer to prevent XSS from user-controlled data\n cell.innerHTML = sanitizeHTML(produced);\n needsSanitization = true;\n } else if (produced) cell.appendChild(produced);\n else cell.textContent = value == null ? '' : String(value);\n } else if (externalView) {\n const spec = externalView;\n const placeholder = document.createElement('div');\n placeholder.setAttribute('data-external-view', '');\n placeholder.setAttribute('data-field', col.field);\n cell.appendChild(placeholder);\n const context = { row: rowData, value, field: col.field, column: col };\n if (spec.mount) {\n try {\n spec.mount({ placeholder, context, spec });\n } catch {\n /* empty */\n }\n } else {\n queueMicrotask(() => {\n try {\n gridEl.dispatchEvent(\n new CustomEvent('mount-external-view', {\n bubbles: true,\n composed: true,\n detail: { placeholder, spec, context },\n }),\n );\n } catch {\n /* empty */\n }\n });\n }\n placeholder.setAttribute('data-mounted', '');\n } else if (compiled) {\n const output = compiled({ row: rowData, value, field: col.field, column: col });\n const blocked = (compiled as any).__blocked;\n // Sanitize compiled template output to prevent XSS\n cell.innerHTML = blocked ? '' : sanitizeHTML(output);\n needsSanitization = true;\n if (blocked) {\n // Forcefully clear any residual whitespace text nodes for deterministic emptiness\n cell.textContent = '';\n cell.setAttribute('data-blocked-template', '');\n }\n } else if (tplHolder) {\n const rawTpl = tplHolder.innerHTML;\n if (/Reflect\\.|\\bProxy\\b|ownKeys\\(/.test(rawTpl)) {\n cell.textContent = '';\n cell.setAttribute('data-blocked-template', '');\n } else {\n // Sanitize inline template output to prevent XSS\n cell.innerHTML = sanitizeHTML(evalTemplateString(rawTpl, { row: rowData, value }));\n needsSanitization = true;\n }\n } else {\n // Plain value rendering - compute display directly (matches Stencil performance)\n if (col.type === 'date') {\n if (value == null || value === '') {\n cell.textContent = '';\n } else {\n let d: Date | null = null;\n if (value instanceof Date) d = value;\n else if (typeof value === 'number' || typeof value === 'string') {\n const tentative = new Date(value);\n if (!isNaN(tentative.getTime())) d = tentative;\n }\n cell.textContent = d ? d.toLocaleDateString() : '';\n }\n } else if (col.type === 'boolean') {\n const isTrue = !!value;\n // Wrap checkbox in span to satisfy ARIA: gridcell can contain checkbox\n cell.innerHTML = `<span role=\"checkbox\" aria-checked=\"${isTrue}\" aria-label=\"${isTrue}\">${isTrue ? '🗹' : '☐'}</span>`;\n } else {\n cell.textContent = value == null ? '' : String(value);\n }\n }\n\n // Only run expensive sanitization when we used innerHTML with user content\n if (needsSanitization) {\n finalCellScrub(cell);\n // Defensive: if forbidden tokens leaked via async or framework hydration, scrub again.\n const textContent = cell.textContent || '';\n if (/Proxy|Reflect\\.ownKeys/.test(textContent)) {\n cell.textContent = textContent.replace(/Proxy|Reflect\\.ownKeys/g, '').trim();\n if (/Proxy|Reflect\\.ownKeys/.test(cell.textContent || '')) cell.textContent = '';\n }\n }\n\n if (cell.hasAttribute('data-blocked-template')) {\n // If anything at all remains (e.g., 'function () { [native code] }'), blank it completely.\n if ((cell.textContent || '').trim().length) cell.textContent = '';\n }\n if ((col as any).editable) {\n cell.tabIndex = 0;\n cell.addEventListener('mousedown', () => {\n // Skip if cell is already in editing mode - avoid refreshVirtualWindow wiping editors\n if (cell.classList.contains('editing')) return;\n // Read row/col index from data attributes to handle virtualization row reuse\n const currentRowIndex = Number(cell.getAttribute('data-row'));\n const currentColIndex = Number(cell.getAttribute('data-col'));\n if (isNaN(currentRowIndex) || isNaN(currentColIndex)) return;\n grid._focusRow = currentRowIndex;\n grid._focusCol = currentColIndex;\n ensureCellVisible(grid);\n });\n if (editMode === 'click') {\n cell.addEventListener('click', (e) => {\n if (cell.classList.contains('editing')) return;\n e.stopPropagation();\n // Read row/col index from data attributes to handle virtualization row reuse\n const currentRowIndex = Number(cell.getAttribute('data-row'));\n const currentColIndex = Number(cell.getAttribute('data-col'));\n if (isNaN(currentRowIndex) || isNaN(currentColIndex)) return;\n const currentRowData = grid._rows[currentRowIndex];\n const currentCol = grid._visibleColumns[currentColIndex];\n if (!currentRowData || !currentCol) return;\n grid._focusRow = currentRowIndex;\n grid._focusCol = currentColIndex;\n inlineEnterEdit(grid, currentRowData, currentRowIndex, currentCol, cell);\n });\n } else {\n cell.addEventListener('dblclick', (e) => {\n e.stopPropagation();\n // Read row index from data attribute to handle virtualization row reuse\n const currentRowIndex = Number(cell.getAttribute('data-row'));\n if (isNaN(currentRowIndex)) return;\n const currentRowData = grid._rows[currentRowIndex];\n if (!currentRowData) return;\n startRowEdit(grid, currentRowIndex, currentRowData);\n const rowElCurrent = grid.findRenderedRowElement?.(currentRowIndex);\n if (rowElCurrent) {\n const children = rowElCurrent.children;\n for (let i = 0; i < children.length; i++) {\n const col2 = grid._visibleColumns[i];\n if (col2 && (col2 as any).editable)\n inlineEnterEdit(grid, currentRowData, currentRowIndex, col2, children[i] as HTMLElement);\n }\n }\n });\n }\n cell.addEventListener('keydown', (e) => {\n // Read row/col index from data attributes to handle virtualization row reuse\n const currentRowIndex = Number(cell.getAttribute('data-row'));\n const currentColIndex = Number(cell.getAttribute('data-col'));\n if (isNaN(currentRowIndex) || isNaN(currentColIndex)) return;\n const currentRowData = grid._rows[currentRowIndex];\n const currentCol = grid._visibleColumns[currentColIndex];\n if (!currentRowData || !currentCol) return;\n if (\n (currentCol.type === 'select' || currentCol.type === 'typeahead') &&\n !cell.classList.contains('editing') &&\n e.key === 'Enter'\n ) {\n e.preventDefault();\n if (grid._activeEditRows !== currentRowIndex) startRowEdit(grid, currentRowIndex, currentRowData);\n inlineEnterEdit(grid, currentRowData, currentRowIndex, currentCol, cell);\n setTimeout(() => {\n const selectEl = cell.querySelector('select') as HTMLSelectElement | null;\n try {\n (selectEl as any)?.showPicker?.();\n } catch {\n /* empty */\n }\n selectEl?.focus();\n }, 0);\n return;\n }\n if (currentCol.type === 'boolean' && e.key === ' ' && !cell.classList.contains('editing')) {\n e.preventDefault();\n if (grid._activeEditRows !== currentRowIndex) startRowEdit(grid, currentRowIndex, currentRowData);\n const newVal = !currentRowData[currentCol.field];\n commitCellValue(grid, currentRowIndex, currentCol, newVal, currentRowData);\n cell.innerHTML = `<span role=\"checkbox\" aria-checked=\"${newVal}\" aria-label=\"${newVal}\">${newVal ? '🗹' : '☐'}</span>`;\n return;\n }\n if (e.key === 'Enter' && !cell.classList.contains('editing')) {\n e.preventDefault();\n e.stopPropagation(); // Prevent grid-level handler from also processing Enter\n grid._focusRow = currentRowIndex;\n grid._focusCol = currentColIndex;\n if (typeof grid.beginBulkEdit === 'function') grid.beginBulkEdit(currentRowIndex);\n else inlineEnterEdit(grid, currentRowData, currentRowIndex, currentCol, cell);\n return;\n }\n if (e.key === 'F2' && !cell.classList.contains('editing')) {\n e.preventDefault();\n inlineEnterEdit(grid, currentRowData, currentRowIndex, currentCol, cell);\n return;\n }\n });\n } else if (col.type === 'boolean') {\n // Non-editable boolean cells should NOT toggle on space key\n // They are read-only, only set tabindex for focus navigation\n if (!cell.hasAttribute('tabindex')) cell.tabIndex = 0;\n }\n\n // Initialize focus state (must match fastPatchRow for consistent behavior)\n if (focusRow === rowIndex && focusCol === colIndex) {\n cell.classList.add('cell-focus');\n cell.setAttribute('aria-selected', 'true');\n } else {\n cell.setAttribute('aria-selected', 'false');\n }\n\n fragment.appendChild(cell);\n }\n\n // Single DOM operation to append all cells\n rowEl.appendChild(fragment);\n}\n\n/**\n * Handle click / double click interaction to focus cells and optionally start row editing\n * according to the grid's configured edit activation mode.\n */\nexport function handleRowClick(grid: InternalGrid, e: MouseEvent, rowEl: HTMLElement, isDbl: boolean): void {\n if ((e.target as HTMLElement)?.closest('.resize-handle')) return;\n const firstCell = rowEl.querySelector('.cell[data-row]') as HTMLElement | null;\n if (!firstCell) return;\n const rowIndex = Number(firstCell.getAttribute('data-row'));\n if (isNaN(rowIndex)) return;\n const rowData = grid._rows[rowIndex];\n if (!rowData) return;\n\n // Dispatch row click to plugin system first (e.g., for master-detail expansion)\n if (grid._dispatchRowClick?.(e, rowIndex, rowData, rowEl)) {\n return;\n }\n\n const cellEl = (e.target as HTMLElement)?.closest('.cell[data-col]') as HTMLElement | null;\n if (cellEl) {\n // Skip focus/ensureCellVisible if cell is already editing - avoid wiping editors\n if (cellEl.classList.contains('editing')) return;\n const colIndex = Number(cellEl.getAttribute('data-col'));\n if (!isNaN(colIndex)) {\n // Dispatch to plugin system first - if handled, stop propagation\n if (grid._dispatchCellClick?.(e, rowIndex, colIndex, cellEl)) {\n return;\n }\n grid._focusRow = rowIndex;\n grid._focusCol = colIndex;\n ensureCellVisible(grid);\n }\n }\n if (rowEl.querySelector('.cell.editing')) {\n const active = rowEl.querySelectorAll('.cell.editing');\n if (!isDbl) return;\n active.forEach((n: any) => n.classList.remove('editing'));\n }\n const mode: 'click' | 'doubleClick' = ((grid as any).effectiveConfig?.editOn || grid.editOn || 'doubleClick') as any;\n if (mode === 'click' || (mode === 'doubleClick' && isDbl)) startRowEdit(grid, rowIndex, rowData);\n else return;\n Array.from(rowEl.children).forEach((c: any, i: number) => {\n const col = grid._visibleColumns[i];\n if (col && (col as any).editable) inlineEnterEdit(grid, rowData, rowIndex, col, c as HTMLElement);\n });\n if (cellEl) {\n queueMicrotask(() => {\n const targetCell = rowEl.querySelector(`.cell[data-col=\"${grid._focusCol}\"]`);\n if (targetCell?.classList.contains('editing')) {\n const editor = (targetCell as HTMLElement).querySelector(\n 'input,select,textarea,[contenteditable=\"true\"],[contenteditable=\"\"],[tabindex]:not([tabindex=\"-1\"])',\n ) as HTMLElement | null;\n try {\n editor?.focus();\n } catch {\n /* empty */\n }\n }\n });\n }\n}\n","/**\n * Editing Lifecycle Module\n *\n * Handles row/cell editing state, commit/cancel operations, and value persistence.\n */\n\nimport type { ColumnConfig, InternalGrid } from '../types';\nimport { defaultEditorFor } from './editors';\nimport { invalidateCellCache, renderInlineRow } from './rows';\n\n/**\n * Returns true if the given property key is safe to use on a plain object without risking\n * prototype pollution via special names like \"__proto__\", \"constructor\", or \"prototype\".\n */\nfunction isSafePropertyKey(key: any): boolean {\n if (key === '__proto__' || key === 'constructor' || key === 'prototype') return false;\n return true;\n}\n\n/**\n * Snapshot original row data and mark the row as actively being edited.\n */\nexport function startRowEdit(grid: InternalGrid, rowIndex: number, rowData: any): void {\n if (grid._activeEditRows !== rowIndex) {\n grid._rowEditSnapshots.set(rowIndex, { ...rowData });\n grid._activeEditRows = rowIndex;\n }\n}\n\n/**\n * Finish editing for a row. If `revert` is true restore original snapshot and clear change marks.\n * Otherwise emit a row-commit event describing change status.\n */\nexport function exitRowEdit(grid: InternalGrid, rowIndex: number, revert: boolean): void {\n if (grid._activeEditRows !== rowIndex) return;\n const snapshot = grid._rowEditSnapshots.get(rowIndex);\n const current = grid._rows[rowIndex];\n\n // Before re-rendering, collect and commit values from any active editors\n // This ensures values are persisted even if blur hasn't fired yet\n const rowEl = grid.findRenderedRowElement?.(rowIndex);\n if (!revert && rowEl && current) {\n const editingCells = rowEl.querySelectorAll('.cell.editing');\n editingCells.forEach((cell) => {\n const colIndex = Number((cell as HTMLElement).getAttribute('data-col'));\n if (isNaN(colIndex)) return;\n const col = grid._visibleColumns[colIndex];\n if (!col) return;\n const input = cell.querySelector('input,textarea,select') as\n | HTMLInputElement\n | HTMLTextAreaElement\n | HTMLSelectElement\n | null;\n if (input) {\n let val: unknown;\n if (input instanceof HTMLInputElement && input.type === 'checkbox') {\n val = input.checked;\n } else {\n val = input.value;\n // Convert to number for number columns\n if (col.type === 'number' && val !== '') {\n val = Number(val);\n }\n }\n // Only commit if value actually changed\n if (current[col.field] !== val) {\n commitCellValue(grid, rowIndex, col, val, current);\n }\n }\n });\n }\n\n if (revert && snapshot && current) {\n Object.keys(snapshot).forEach((k) => (current[k] = snapshot[k]));\n grid._changedRowIndices.delete(rowIndex);\n // Invalidate cell cache so reverted values display correctly\n invalidateCellCache(grid);\n } else if (!revert) {\n const changed = grid._changedRowIndices.has(rowIndex);\n (grid as unknown as HTMLElement).dispatchEvent(\n new CustomEvent('row-commit', {\n detail: {\n rowIndex,\n row: current,\n changed,\n changedRows: grid.changedRows,\n changedRowIndices: grid.changedRowIndices,\n },\n }),\n );\n }\n grid._rowEditSnapshots.delete(rowIndex);\n grid._activeEditRows = -1;\n if (rowEl) {\n renderInlineRow(grid, rowEl, grid._rows[rowIndex], rowIndex);\n if (grid._changedRowIndices.has(rowIndex)) rowEl.classList.add('changed');\n else rowEl.classList.remove('changed');\n }\n // Restore focus to the cell after exiting edit mode (for both commit and revert)\n queueMicrotask(() => {\n try {\n const rowIdx = grid._focusRow;\n const colIdx = grid._focusCol;\n const rowEl2 = grid.findRenderedRowElement?.(rowIdx);\n if (rowEl2) {\n // Clear all cell-focus markers\n Array.from(grid._bodyEl.querySelectorAll('.cell-focus')).forEach((el: any) =>\n el.classList.remove('cell-focus'),\n );\n // Find and focus the cell\n const cell = rowEl2.querySelector(`.cell[data-row=\"${rowIdx}\"][data-col=\"${colIdx}\"]`) as HTMLElement | null;\n if (cell) {\n cell.classList.add('cell-focus');\n cell.setAttribute('aria-selected', 'true');\n if (!cell.hasAttribute('tabindex')) cell.setAttribute('tabindex', '-1');\n cell.focus({ preventScroll: true });\n }\n }\n } catch {\n /* empty */\n }\n });\n}\n\n/**\n * Commit a single cell value change, updating the row object, marking the row as changed (first-time flag),\n * and emitting a `cell-commit` event with row + field metadata.\n */\nexport function commitCellValue(\n grid: InternalGrid,\n rowIndex: number,\n column: ColumnConfig<any>,\n newValue: any,\n rowData: any,\n): void {\n const field = column.field;\n if (!isSafePropertyKey(field)) return;\n const oldValue = rowData[field];\n if (oldValue === newValue) return;\n rowData[field] = newValue;\n const firstTime = !grid._changedRowIndices.has(rowIndex);\n grid._changedRowIndices.add(rowIndex);\n const rowEl = grid.findRenderedRowElement?.(rowIndex);\n if (rowEl) rowEl.classList.add('changed');\n (grid as unknown as HTMLElement).dispatchEvent(\n new CustomEvent('cell-commit', {\n detail: {\n row: rowData,\n field,\n value: newValue,\n rowIndex,\n changedRows: grid.changedRows,\n changedRowIndices: grid.changedRowIndices,\n firstTimeForRow: firstTime,\n },\n }),\n );\n}\n\n/**\n * Replace a cell's content with an editor resolved from column configuration (custom editor, template, external\n * mount spec or default editor by type). Manages commit / cancel lifecycle and value restoration.\n */\nexport function inlineEnterEdit(\n grid: InternalGrid,\n rowData: any,\n rowIndex: number,\n column: ColumnConfig<any>,\n cell: HTMLElement,\n): void {\n if (!column.editable) return;\n if (grid._activeEditRows !== rowIndex) startRowEdit(grid, rowIndex, rowData);\n if (cell.classList.contains('editing')) return;\n const originalValue = isSafePropertyKey(column.field) ? rowData[column.field] : undefined;\n cell.classList.add('editing');\n let editFinalized = false; // Flag to prevent blur from committing after explicit Enter/Escape\n const commit = (newValue: any) => {\n // Skip if edit was already finalized by Enter/Escape, or if we've exited edit mode\n // (handles bulk edit case where one cell's exit removes all editors)\n if (editFinalized || grid._activeEditRows === -1) return;\n commitCellValue(grid, rowIndex, column, newValue, rowData);\n };\n const cancel = () => {\n editFinalized = true; // Mark as finalized to prevent blur from re-committing\n rowData[column.field] = isSafePropertyKey(column.field) ? originalValue : undefined;\n const inputLike = cell.querySelector('input,textarea,select') as any;\n if (inputLike) {\n const hasHTMLInput = typeof HTMLInputElement !== 'undefined';\n if (hasHTMLInput && inputLike instanceof HTMLInputElement && inputLike.type === 'checkbox')\n inputLike.checked = !!originalValue;\n else if ('value' in inputLike) inputLike.value = originalValue ?? '';\n }\n };\n const editorHost = document.createElement('div');\n editorHost.style.display = 'contents';\n cell.innerHTML = '';\n cell.appendChild(editorHost);\n\n // Common keydown handler for all editor types to handle Enter/Escape with proper exit\n // This catches events that bubble up from child elements (default editors, custom editors)\n editorHost.addEventListener('keydown', (e: KeyboardEvent) => {\n if (e.key === 'Enter') {\n e.stopPropagation();\n e.preventDefault();\n editFinalized = true; // Prevent blur from committing again\n // Value should already be committed by the editor's own handler\n // Just need to exit edit mode\n exitRowEdit(grid, rowIndex, false);\n }\n if (e.key === 'Escape') {\n e.stopPropagation();\n e.preventDefault();\n cancel(); // cancel() sets editFinalized = true\n exitRowEdit(grid, rowIndex, true);\n }\n });\n\n const tplHolder = (column as any).__editorTemplate as HTMLElement | undefined;\n const editorSpec = (column as any).editor || (tplHolder ? 'template' : defaultEditorFor(column));\n const value = originalValue;\n if (editorSpec === 'template' && tplHolder) {\n const clone = tplHolder.cloneNode(true) as HTMLElement;\n const compiledEditor = (column as any).__compiledEditor as ((ctx: any) => string) | undefined;\n if (compiledEditor)\n clone.innerHTML = compiledEditor({ row: rowData, value: originalValue, field: column.field, column });\n else\n clone.querySelectorAll<HTMLElement>('*').forEach((node) => {\n if (node.childNodes.length === 1 && node.firstChild?.nodeType === Node.TEXT_NODE) {\n node.textContent =\n node.textContent\n ?.replace(/{{\\s*value\\s*}}/g, originalValue == null ? '' : String(originalValue))\n .replace(/{{\\s*row\\.([a-zA-Z0-9_]+)\\s*}}/g, (_m, g) => {\n const v = (rowData as any)[g];\n return v == null ? '' : String(v);\n }) || '';\n }\n });\n const input = clone.querySelector('input,textarea,select') as HTMLInputElement | HTMLSelectElement | null;\n if (input) {\n const hasHTMLInput = typeof HTMLInputElement !== 'undefined';\n if (hasHTMLInput && input instanceof HTMLInputElement && input.type === 'checkbox')\n input.checked = !!originalValue;\n else if ('value' in input) (input as any).value = originalValue ?? '';\n input.addEventListener('blur', () => {\n // commit() will check editFinalized flag and skip if already handled\n const val =\n hasHTMLInput && input instanceof HTMLInputElement && input.type === 'checkbox'\n ? input.checked\n : (input as any).value;\n commit(val);\n });\n input.addEventListener('keydown', (e: any) => {\n if (e.key === 'Enter') {\n e.stopPropagation();\n e.preventDefault();\n editFinalized = true; // Prevent blur from committing again\n const val =\n hasHTMLInput && input instanceof HTMLInputElement && input.type === 'checkbox'\n ? input.checked\n : (input as any).value;\n commit(val);\n exitRowEdit(grid, rowIndex, false);\n }\n if (e.key === 'Escape') {\n e.stopPropagation();\n e.preventDefault();\n cancel(); // cancel() sets editFinalized = true\n exitRowEdit(grid, rowIndex, true);\n }\n });\n if (hasHTMLInput && input instanceof HTMLInputElement && input.type === 'checkbox') {\n input.addEventListener('change', () => {\n const val = input.checked;\n commit(val);\n });\n }\n setTimeout(() => input.focus(), 0);\n }\n editorHost.appendChild(clone);\n } else if (typeof editorSpec === 'string') {\n const el = document.createElement(editorSpec);\n (el as any).value = value;\n el.addEventListener('change', () => commit((el as any).value));\n editorHost.appendChild(el);\n } else if (typeof editorSpec === 'function') {\n const produced = editorSpec({ row: rowData, value, field: column.field, column, commit, cancel });\n if (typeof produced === 'string') editorHost.innerHTML = produced;\n else editorHost.appendChild(produced);\n } else if (editorSpec && typeof editorSpec === 'object') {\n const placeholder = document.createElement('div');\n placeholder.setAttribute('data-external-editor', '');\n placeholder.setAttribute('data-field', column.field);\n editorHost.appendChild(placeholder);\n const context = { row: rowData, value, field: column.field, column, commit, cancel };\n if (editorSpec.mount) {\n try {\n editorSpec.mount({ placeholder, context, spec: editorSpec });\n } catch {\n /* empty */\n }\n } else {\n (grid as unknown as HTMLElement).dispatchEvent(\n new CustomEvent('mount-external-editor', { detail: { placeholder, spec: editorSpec, context } }),\n );\n }\n }\n}\n","/**\n * Sorting Module\n *\n * Handles column sorting state transitions and row ordering.\n */\n\nimport type { ColumnConfig, InternalGrid } from '../types';\nimport { renderHeader } from './header';\n\n/**\n * Cycle sort state for a column: none -> ascending -> descending -> none.\n * Restores original row order when clearing sort.\n */\nexport function toggleSort(grid: InternalGrid, col: ColumnConfig<any>): void {\n if (!grid._sortState || grid._sortState.field !== col.field) {\n if (!grid._sortState) grid.__originalOrder = grid._rows.slice();\n applySort(grid, col, 1);\n } else if (grid._sortState.direction === 1) {\n applySort(grid, col, -1);\n } else {\n grid._sortState = null;\n // Force full row rebuild after clearing sort so templated cells reflect original order\n grid.__rowRenderEpoch++;\n // Invalidate existing pooled row epochs so virtualization triggers a full inline rebuild\n grid._rowPool.forEach((r) => ((r as any).__epoch = -1));\n grid._rows = grid.__originalOrder.slice();\n renderHeader(grid);\n // After re-render ensure cleared column shows aria-sort=\"none\" baseline.\n const headers = grid._headerRowEl?.querySelectorAll('[role=\"columnheader\"].sortable');\n headers?.forEach((h: any) => {\n if (!h.getAttribute('aria-sort')) h.setAttribute('aria-sort', 'none');\n else if (h.getAttribute('aria-sort') === 'ascending' || h.getAttribute('aria-sort') === 'descending') {\n // The active column was re-rendered already, but normalize any missing ones.\n if (!grid._sortState) h.setAttribute('aria-sort', 'none');\n }\n });\n grid.refreshVirtualWindow(true);\n (grid as unknown as HTMLElement).dispatchEvent(\n new CustomEvent('sort-change', { detail: { field: col.field, direction: 0 } }),\n );\n // Trigger state change after sort is cleared\n grid.requestStateChange?.();\n }\n}\n\n/**\n * Apply a concrete sort direction to rows using either the column's custom comparator\n * or a default comparator aware of null/undefined ordering.\n */\nexport function applySort(grid: InternalGrid, col: ColumnConfig<any>, dir: 1 | -1): void {\n grid._sortState = { field: col.field, direction: dir };\n const comparator =\n (col as any).sortComparator ||\n ((a: any, b: any) => (a == null && b == null ? 0 : a == null ? -1 : b == null ? 1 : a > b ? 1 : a < b ? -1 : 0));\n grid._rows.sort((rA: any, rB: any) => comparator(rA[col.field], rB[col.field], rA, rB) * dir);\n // Bump epoch so renderVisibleRows triggers full inline rebuild (ensures templated / compiled view cells update)\n grid.__rowRenderEpoch++;\n // Invalidate pooled rows to guarantee rebuild even if epoch comparison logic changes\n grid._rowPool.forEach((r) => ((r as any).__epoch = -1));\n renderHeader(grid);\n grid.refreshVirtualWindow(true);\n (grid as unknown as HTMLElement).dispatchEvent(\n new CustomEvent('sort-change', { detail: { field: col.field, direction: dir } }),\n );\n // Trigger state change after sort applied\n grid.requestStateChange?.();\n}\n","/**\n * Header Rendering Module\n *\n * Handles rendering of the grid header row with sorting and resize affordances.\n */\n\nimport type { ColumnConfig, IconValue, InternalGrid } from '../types';\nimport { DEFAULT_GRID_ICONS } from '../types';\nimport { addPart } from './columns';\nimport { toggleSort } from './sorting';\n\n/**\n * Set an icon value on an element. Handles both string and HTMLElement icons.\n */\nfunction setIcon(element: HTMLElement, icon: IconValue): void {\n if (typeof icon === 'string') {\n element.textContent = icon;\n } else if (icon instanceof HTMLElement) {\n element.innerHTML = '';\n element.appendChild(icon.cloneNode(true));\n }\n}\n\n/**\n * Rebuild the header row DOM based on current column configuration, attaching\n * sorting and resize affordances where enabled.\n */\nexport function renderHeader(grid: InternalGrid): void {\n grid._headerRowEl = (grid.findHeaderRow! as any)();\n const headerRow = grid._headerRowEl as HTMLElement;\n headerRow.innerHTML = '';\n\n grid._visibleColumns.forEach((col: ColumnConfig<any>, i: number) => {\n const cell = document.createElement('div');\n cell.className = 'cell';\n addPart(cell, 'header-cell');\n cell.setAttribute('role', 'columnheader');\n\n // aria-colindex is 1-based\n cell.setAttribute('aria-colindex', String(i + 1));\n cell.setAttribute('data-field', col.field);\n cell.setAttribute('data-col', String(i)); // Add data-col for consistency with body cells\n\n // Column grouping styling is handled by the grouping-columns plugin via afterRender\n const maybeTpl = (col as any).__headerTemplate as HTMLElement | undefined;\n if (maybeTpl) Array.from(maybeTpl.childNodes).forEach((n) => cell.appendChild(n.cloneNode(true)));\n else {\n const label = (col as any).header || col.field;\n const span = document.createElement('span');\n span.textContent = label;\n cell.appendChild(span);\n }\n if (col.sortable) {\n cell.classList.add('sortable');\n cell.tabIndex = 0;\n const icon = document.createElement('span');\n addPart(icon as any, 'sort-indicator');\n icon.style.opacity = '0.6';\n const active = grid._sortState?.field === col.field ? grid._sortState.direction : 0;\n // Use grid-level icons (fall back to defaults)\n const icons = { ...DEFAULT_GRID_ICONS, ...grid.icons };\n const iconValue = active === 1 ? icons.sortAsc : active === -1 ? icons.sortDesc : icons.sortNone;\n setIcon(icon, iconValue);\n cell.appendChild(icon);\n // Always set a baseline aria-sort for sortable headers for assistive tech clarity.\n cell.setAttribute('aria-sort', active === 0 ? 'none' : active === 1 ? 'ascending' : 'descending');\n cell.addEventListener('click', (e) => {\n // Ignore clicks that are the result of a resize drag ending\n if (grid._resizeController?.isResizing) return;\n // Let plugins handle the click first (e.g., multi-sort)\n if (grid._dispatchHeaderClick?.(e, i, cell)) return;\n toggleSort(grid, col);\n });\n cell.addEventListener('keydown', (e) => {\n if (e.key === 'Enter' || e.key === ' ') {\n e.preventDefault();\n // Let plugins handle the keydown first\n if (grid._dispatchHeaderClick?.(e as unknown as MouseEvent, i, cell)) return;\n toggleSort(grid, col);\n }\n });\n }\n if (col.resizable) {\n // Set position: relative for the resize handle positioning context\n // Note: If a plugin applies position: sticky (e.g., PinnedColumnsPlugin), it will override this\n cell.style.position = 'relative';\n const handle = document.createElement('div');\n handle.className = 'resize-handle';\n handle.setAttribute('aria-hidden', 'true');\n handle.addEventListener('mousedown', (e: MouseEvent) => {\n e.stopPropagation();\n e.preventDefault();\n grid._resizeController.start(e, i, cell);\n });\n // Double-click to reset column width to default\n handle.addEventListener('dblclick', (e: MouseEvent) => {\n e.stopPropagation();\n e.preventDefault();\n grid._resizeController.resetColumn(i);\n });\n cell.appendChild(handle);\n }\n headerRow.appendChild(cell);\n });\n\n // Ensure every sortable header has a baseline aria-sort if not already set during construction.\n headerRow.querySelectorAll('.cell.sortable').forEach((el) => {\n if (!el.getAttribute('aria-sort')) el.setAttribute('aria-sort', 'none');\n });\n\n // Set ARIA role only if header has children (role=\"row\" requires columnheader children)\n // When grid is cleared with 0 columns, the header row should not have role=\"row\"\n if (headerRow.children.length > 0) {\n headerRow.setAttribute('role', 'row');\n headerRow.setAttribute('aria-rowindex', '1');\n } else {\n headerRow.removeAttribute('role');\n headerRow.removeAttribute('aria-rowindex');\n }\n}\n","import type { InternalGrid, ResizeController } from '../types';\n\nexport function createResizeController(grid: InternalGrid): ResizeController {\n let resizeState: { startX: number; colIndex: number; startWidth: number } | null = null;\n let pendingRaf: number | null = null;\n let prevCursor: string | null = null;\n let prevUserSelect: string | null = null;\n const onMove = (e: MouseEvent) => {\n if (!resizeState) return;\n const delta = e.clientX - resizeState.startX;\n const width = Math.max(40, resizeState.startWidth + delta);\n const col = grid._visibleColumns[resizeState.colIndex];\n col.width = width;\n col.__userResized = true;\n col.__renderedWidth = width;\n if (pendingRaf == null) {\n pendingRaf = requestAnimationFrame(() => {\n pendingRaf = null;\n grid.updateTemplate?.();\n });\n }\n (grid as unknown as HTMLElement).dispatchEvent(\n new CustomEvent('column-resize', { detail: { field: col.field, width } }),\n );\n };\n let justFinishedResize = false;\n const onUp = () => {\n const hadResize = resizeState !== null;\n // Set flag to suppress click events that fire immediately after mouseup\n if (hadResize) {\n justFinishedResize = true;\n requestAnimationFrame(() => {\n justFinishedResize = false;\n });\n }\n window.removeEventListener('mousemove', onMove);\n window.removeEventListener('mouseup', onUp);\n if (prevCursor !== null) {\n document.documentElement.style.cursor = prevCursor;\n prevCursor = null;\n }\n if (prevUserSelect !== null) {\n document.body.style.userSelect = prevUserSelect;\n prevUserSelect = null;\n }\n resizeState = null;\n // Trigger state change after resize completes\n if (hadResize && grid.requestStateChange) {\n grid.requestStateChange();\n }\n };\n return {\n get isResizing() {\n return resizeState !== null || justFinishedResize;\n },\n start(e, colIndex, cell) {\n e.preventDefault();\n const rect = cell.getBoundingClientRect();\n resizeState = { startX: e.clientX, colIndex, startWidth: rect.width };\n window.addEventListener('mousemove', onMove);\n window.addEventListener('mouseup', onUp);\n if (prevCursor === null) prevCursor = document.documentElement.style.cursor;\n document.documentElement.style.cursor = 'e-resize';\n if (prevUserSelect === null) prevUserSelect = document.body.style.userSelect;\n document.body.style.userSelect = 'none';\n },\n resetColumn(colIndex) {\n const col = grid._visibleColumns[colIndex];\n if (!col) return;\n\n // Reset to original configured width (or undefined for auto-sizing)\n col.__userResized = false;\n col.__renderedWidth = undefined;\n col.width = col.__originalWidth;\n\n grid.updateTemplate?.();\n grid.requestStateChange?.();\n (grid as unknown as HTMLElement).dispatchEvent(\n new CustomEvent('column-resize-reset', { detail: { field: col.field, width: col.width } }),\n );\n },\n dispose() {\n onUp();\n },\n };\n}\n","/**\n * Shell infrastructure for grid header bar and tool panels.\n *\n * The shell is an optional wrapper layer that provides:\n * - Header bar with title, plugin content, and toolbar buttons\n * - Tool panels that plugins can register content into\n * - Light DOM parsing for framework-friendly configuration\n */\n\nimport type {\n HeaderContentDefinition,\n IconValue,\n ShellConfig,\n ToolbarButtonConfig,\n ToolbarButtonInfo,\n ToolPanelDefinition,\n} from '../types';\nimport { DEFAULT_GRID_ICONS } from '../types';\n\n/**\n * Convert an IconValue to a string for rendering in HTML.\n */\nfunction iconToString(icon: IconValue | undefined): string {\n if (!icon) return '';\n if (typeof icon === 'string') return icon;\n // For HTMLElement, get the outerHTML\n return icon.outerHTML;\n}\n\n/**\n * State for managing shell UI.\n */\nexport interface ShellState {\n /** Registered tool panels (from plugins + consumer API) */\n toolPanels: Map<string, ToolPanelDefinition>;\n /** Registered header content (from plugins + consumer API) */\n headerContents: Map<string, HeaderContentDefinition>;\n /** Custom toolbar buttons registered via API */\n toolbarButtons: Map<string, ToolbarButtonConfig>;\n /** Light DOM toolbar buttons */\n lightDomButtons: HTMLElement[];\n /** Light DOM header content elements */\n lightDomHeaderContent: HTMLElement[];\n /** Whether the tool panel sidebar is open */\n isPanelOpen: boolean;\n /** Which accordion sections are expanded (by panel ID) */\n expandedSections: Set<string>;\n /** Cleanup functions for header content render returns */\n headerContentCleanups: Map<string, () => void>;\n /** Cleanup functions for each panel section's render return */\n panelCleanups: Map<string, () => void>;\n /** Cleanup functions for toolbar button render returns */\n toolbarButtonCleanups: Map<string, () => void>;\n /** @deprecated Use isPanelOpen instead. Kept for backward compatibility. */\n activePanel: string | null;\n /** @deprecated Use panelCleanups instead. Kept for backward compatibility. */\n activePanelCleanup: (() => void) | null;\n}\n\n/**\n * Create initial shell state.\n */\nexport function createShellState(): ShellState {\n return {\n toolPanels: new Map(),\n headerContents: new Map(),\n toolbarButtons: new Map(),\n lightDomButtons: [],\n lightDomHeaderContent: [],\n isPanelOpen: false,\n expandedSections: new Set(),\n headerContentCleanups: new Map(),\n panelCleanups: new Map(),\n toolbarButtonCleanups: new Map(),\n // Deprecated - kept for backward compatibility\n activePanel: null,\n activePanelCleanup: null,\n };\n}\n\n/**\n * Determine if shell header should be rendered.\n */\nexport function shouldRenderShellHeader(config: ShellConfig | undefined, state: ShellState): boolean {\n // Check if title is configured\n if (config?.header?.title) return true;\n\n // Check if config has toolbar buttons\n if (config?.header?.toolbarButtons?.length) return true;\n\n // Check if any tool panels are registered (need toolbar buttons for them)\n if (state.toolPanels.size > 0) return true;\n\n // Check if any header content is registered\n if (state.headerContents.size > 0) return true;\n\n // Check if any API toolbar buttons registered\n if (state.toolbarButtons.size > 0) return true;\n\n // Check if light DOM has header elements\n if (state.lightDomButtons.length > 0 || state.lightDomHeaderContent.length > 0) return true;\n\n return false;\n}\n\n/**\n * Render the shell header HTML.\n * @param toolPanelIcon - Icon for the tool panel toggle (from grid icon config)\n */\nexport function renderShellHeader(\n config: ShellConfig | undefined,\n state: ShellState,\n toolPanelIcon: IconValue = '☰',\n): string {\n const title = config?.header?.title ?? '';\n const hasTitle = !!title;\n const iconStr = iconToString(toolPanelIcon);\n\n // Collect all toolbar buttons in order\n // 1. Config buttons (sorted by order)\n // 2. API-registered buttons (sorted by order)\n // 3. Light DOM buttons via slot\n // 4. Single panel toggle button (if any panels registered)\n\n const configButtons = config?.header?.toolbarButtons ?? [];\n const hasConfigButtons = configButtons.length > 0;\n const hasApiButtons = state.toolbarButtons.size > 0;\n const hasLightDomButtons = state.lightDomButtons.length > 0;\n const hasPanels = state.toolPanels.size > 0;\n const hasCustomButtons = hasConfigButtons || hasApiButtons || hasLightDomButtons;\n const showSeparator = hasCustomButtons && hasPanels;\n\n // Sort config buttons by order\n const sortedConfigButtons = [...configButtons].sort((a, b) => (a.order ?? 100) - (b.order ?? 100));\n\n // Sort API buttons by order\n const sortedApiButtons = [...state.toolbarButtons.values()].sort((a, b) => (a.order ?? 100) - (b.order ?? 100));\n\n // Build toolbar HTML\n let toolbarHtml = '';\n\n // Config buttons with icon/action (grid renders these)\n for (const btn of sortedConfigButtons) {\n if (btn.icon && btn.action) {\n toolbarHtml += `<button class=\"tbw-toolbar-btn\" data-btn=\"${btn.id}\" title=\"${btn.label}\" aria-label=\"${\n btn.label\n }\"${btn.disabled ? ' disabled' : ''}>${btn.icon}</button>`;\n }\n }\n\n // API buttons with icon/action\n for (const btn of sortedApiButtons) {\n if (btn.icon && btn.action) {\n toolbarHtml += `<button class=\"tbw-toolbar-btn\" data-btn=\"${btn.id}\" title=\"${btn.label}\" aria-label=\"${\n btn.label\n }\"${btn.disabled ? ' disabled' : ''}>${btn.icon}</button>`;\n }\n }\n\n // Placeholders for config/API buttons with element or render function\n for (const btn of sortedConfigButtons) {\n if (btn.element || btn.render) {\n toolbarHtml += `<div class=\"tbw-toolbar-btn-slot\" data-btn-slot=\"${btn.id}\"></div>`;\n }\n }\n for (const btn of sortedApiButtons) {\n if (btn.element || btn.render) {\n toolbarHtml += `<div class=\"tbw-toolbar-btn-slot\" data-btn-slot=\"${btn.id}\"></div>`;\n }\n }\n\n // Light DOM slot\n if (hasLightDomButtons) {\n toolbarHtml += '<slot name=\"toolbar\"></slot>';\n }\n\n // Separator\n if (showSeparator) {\n toolbarHtml += '<div class=\"tbw-toolbar-separator\"></div>';\n }\n\n // Single panel toggle button (opens accordion-style sidebar with all panels)\n if (hasPanels) {\n const isOpen = state.isPanelOpen;\n toolbarHtml += `<button class=\"tbw-toolbar-btn${isOpen ? ' active' : ''}\" data-panel-toggle title=\"Settings\" aria-label=\"Toggle settings panel\" aria-pressed=\"${isOpen}\" aria-controls=\"tbw-tool-panel\">${iconStr}</button>`;\n }\n\n return `\n <div class=\"tbw-shell-header\" part=\"shell-header\" role=\"presentation\">\n ${hasTitle ? `<div class=\"tbw-shell-title\">${title}</div>` : ''}\n <div class=\"tbw-shell-content\" part=\"shell-content\" role=\"presentation\">\n <slot name=\"header-content\"></slot>\n </div>\n <div class=\"tbw-shell-toolbar\" part=\"shell-toolbar\" role=\"presentation\">\n ${toolbarHtml}\n </div>\n </div>\n `;\n}\n\n/**\n * Render the shell body wrapper HTML (contains grid content + accordion-style tool panel).\n * @param icons - Optional icons for expand/collapse chevrons (from grid config)\n */\nexport function renderShellBody(\n config: ShellConfig | undefined,\n state: ShellState,\n gridContentHtml: string,\n icons?: { expand?: IconValue; collapse?: IconValue },\n): string {\n const position = config?.toolPanel?.position ?? 'right';\n const hasPanel = state.toolPanels.size > 0;\n const isOpen = state.isPanelOpen;\n const expandIcon = iconToString(icons?.expand ?? DEFAULT_GRID_ICONS.expand);\n const collapseIcon = iconToString(icons?.collapse ?? DEFAULT_GRID_ICONS.collapse);\n\n // Sort panels by order for accordion sections\n const sortedPanels = [...state.toolPanels.values()].sort((a, b) => (a.order ?? 100) - (b.order ?? 100));\n const isSinglePanel = sortedPanels.length === 1;\n\n // Build accordion sections HTML\n let accordionHtml = '';\n for (const panel of sortedPanels) {\n const isExpanded = state.expandedSections.has(panel.id);\n const iconHtml = panel.icon ? `<span class=\"tbw-accordion-icon\">${panel.icon}</span>` : '';\n // Hide chevron for single panel (no toggling needed)\n const chevronHtml = isSinglePanel\n ? ''\n : `<span class=\"tbw-accordion-chevron\">${isExpanded ? collapseIcon : expandIcon}</span>`;\n // Disable accordion toggle for single panel\n const sectionClasses = `tbw-accordion-section${isExpanded ? ' expanded' : ''}${isSinglePanel ? ' single' : ''}`;\n accordionHtml += `\n <div class=\"${sectionClasses}\" data-section=\"${panel.id}\">\n <button class=\"tbw-accordion-header\" aria-expanded=\"${isExpanded}\" aria-controls=\"tbw-section-${panel.id}\"${isSinglePanel ? ' aria-disabled=\"true\"' : ''}>\n ${iconHtml}\n <span class=\"tbw-accordion-title\">${panel.title}</span>\n ${chevronHtml}\n </button>\n <div class=\"tbw-accordion-content\" id=\"tbw-section-${panel.id}\" role=\"presentation\"></div>\n </div>\n `;\n }\n\n // Resize handle position depends on panel position\n const resizeHandlePosition = position === 'left' ? 'right' : 'left';\n\n const panelHtml = hasPanel\n ? `\n <aside class=\"tbw-tool-panel${isOpen ? ' open' : ''}\" part=\"tool-panel\" data-position=\"${position}\" role=\"presentation\" id=\"tbw-tool-panel\">\n <div class=\"tbw-tool-panel-resize\" data-resize-handle data-handle-position=\"${resizeHandlePosition}\" aria-hidden=\"true\"></div>\n <div class=\"tbw-tool-panel-content\" role=\"presentation\">\n <div class=\"tbw-accordion\">\n ${accordionHtml}\n </div>\n </div>\n </aside>\n `\n : '';\n\n // For left position, panel comes before content in DOM order\n if (position === 'left') {\n return `\n <div class=\"tbw-shell-body\">\n ${panelHtml}\n <div class=\"tbw-grid-content\">\n ${gridContentHtml}\n </div>\n </div>\n `;\n }\n\n return `\n <div class=\"tbw-shell-body\">\n <div class=\"tbw-grid-content\">\n ${gridContentHtml}\n </div>\n ${panelHtml}\n </div>\n `;\n}\n\n/**\n * Parse light DOM shell elements (tbw-grid-header, etc.).\n */\nexport function parseLightDomShell(host: HTMLElement, state: ShellState): void {\n const headerEl = host.querySelector('tbw-grid-header');\n if (!headerEl) return;\n\n // Hide the light DOM container\n (headerEl as HTMLElement).style.display = 'none';\n\n // Parse header content elements\n const headerContents = headerEl.querySelectorAll('tbw-grid-header-content');\n state.lightDomHeaderContent = Array.from(headerContents) as HTMLElement[];\n\n // Assign slot names for slotting into shadow DOM\n state.lightDomHeaderContent.forEach((el) => {\n el.setAttribute('slot', 'header-content');\n });\n\n // Parse toolbar button elements\n const toolButtons = headerEl.querySelectorAll('tbw-grid-tool-button');\n state.lightDomButtons = Array.from(toolButtons) as HTMLElement[];\n\n // Sort by order attribute and assign slots\n state.lightDomButtons.sort((a, b) => {\n const orderA = parseInt(a.getAttribute('order') ?? '100', 10);\n const orderB = parseInt(b.getAttribute('order') ?? '100', 10);\n return orderA - orderB;\n });\n\n state.lightDomButtons.forEach((el) => {\n el.setAttribute('slot', 'toolbar');\n });\n}\n\n/**\n * Set up event listeners for shell toolbar buttons and accordion.\n */\nexport function setupShellEventListeners(\n shadowRoot: ShadowRoot,\n config: ShellConfig | undefined,\n state: ShellState,\n callbacks: {\n onPanelToggle: () => void;\n onSectionToggle: (sectionId: string) => void;\n onToolbarButtonClick: (buttonId: string) => void;\n },\n): void {\n const toolbar = shadowRoot.querySelector('.tbw-shell-toolbar');\n if (toolbar) {\n toolbar.addEventListener('click', (e) => {\n const target = e.target as HTMLElement;\n\n // Handle single panel toggle button\n const panelToggle = target.closest('[data-panel-toggle]') as HTMLElement | null;\n if (panelToggle) {\n callbacks.onPanelToggle();\n return;\n }\n\n // Handle custom toolbar buttons\n const customBtn = target.closest('[data-btn]') as HTMLElement | null;\n if (customBtn) {\n const btnId = customBtn.getAttribute('data-btn');\n if (btnId) {\n callbacks.onToolbarButtonClick(btnId);\n }\n }\n });\n }\n\n // Accordion header clicks\n const accordion = shadowRoot.querySelector('.tbw-accordion');\n if (accordion) {\n accordion.addEventListener('click', (e) => {\n const target = e.target as HTMLElement;\n const header = target.closest('.tbw-accordion-header') as HTMLElement | null;\n if (header) {\n const section = header.closest('[data-section]') as HTMLElement | null;\n const sectionId = section?.getAttribute('data-section');\n if (sectionId) {\n callbacks.onSectionToggle(sectionId);\n }\n }\n });\n }\n}\n\n/**\n * Set up resize handle for tool panel.\n * Returns a cleanup function to remove event listeners.\n */\nexport function setupToolPanelResize(\n shadowRoot: ShadowRoot,\n config: ShellConfig | undefined,\n onResize: (width: number) => void,\n): () => void {\n const panel = shadowRoot.querySelector('.tbw-tool-panel') as HTMLElement | null;\n const handle = shadowRoot.querySelector('[data-resize-handle]') as HTMLElement | null;\n const shellBody = shadowRoot.querySelector('.tbw-shell-body') as HTMLElement | null;\n if (!panel || !handle || !shellBody) {\n // eslint-disable-next-line @typescript-eslint/no-empty-function\n return () => {};\n }\n\n const position = config?.toolPanel?.position ?? 'right';\n const minWidth = 200;\n\n let startX = 0;\n let startWidth = 0;\n let maxWidth = 0;\n let isResizing = false;\n\n const onMouseMove = (e: MouseEvent) => {\n if (!isResizing) return;\n e.preventDefault();\n\n // For right-positioned panel: dragging left (negative clientX change) should expand\n // For left-positioned panel: dragging right (positive clientX change) should expand\n const delta = position === 'left' ? e.clientX - startX : startX - e.clientX;\n const newWidth = Math.min(maxWidth, Math.max(minWidth, startWidth + delta));\n\n panel.style.width = `${newWidth}px`;\n };\n\n const onMouseUp = () => {\n if (!isResizing) return;\n isResizing = false;\n handle.classList.remove('resizing');\n panel.style.transition = ''; // Re-enable transition\n document.body.style.cursor = '';\n document.body.style.userSelect = '';\n\n // Get final width and notify\n const finalWidth = panel.getBoundingClientRect().width;\n onResize(finalWidth);\n\n document.removeEventListener('mousemove', onMouseMove);\n document.removeEventListener('mouseup', onMouseUp);\n };\n\n const onMouseDown = (e: MouseEvent) => {\n e.preventDefault();\n isResizing = true;\n startX = e.clientX;\n startWidth = panel.getBoundingClientRect().width;\n // Calculate max width dynamically based on grid container width\n maxWidth = shellBody.getBoundingClientRect().width - 20; // Leave 20px margin\n handle.classList.add('resizing');\n panel.style.transition = 'none'; // Disable transition for smooth resize\n document.body.style.cursor = 'col-resize';\n document.body.style.userSelect = 'none';\n\n document.addEventListener('mousemove', onMouseMove);\n document.addEventListener('mouseup', onMouseUp);\n };\n\n handle.addEventListener('mousedown', onMouseDown);\n\n // Return cleanup function\n return () => {\n handle.removeEventListener('mousedown', onMouseDown);\n document.removeEventListener('mousemove', onMouseMove);\n document.removeEventListener('mouseup', onMouseUp);\n };\n}\n\n/**\n * Render custom button elements/render functions into toolbar slots.\n */\nexport function renderCustomToolbarButtons(\n shadowRoot: ShadowRoot,\n config: ShellConfig | undefined,\n state: ShellState,\n): void {\n const allButtons = [...(config?.header?.toolbarButtons ?? []), ...state.toolbarButtons.values()];\n\n for (const btn of allButtons) {\n const slot = shadowRoot.querySelector(`[data-btn-slot=\"${btn.id}\"]`);\n if (!slot) continue;\n\n // Clean up previous render if any\n const existingCleanup = state.toolbarButtonCleanups.get(btn.id);\n if (existingCleanup) {\n existingCleanup();\n state.toolbarButtonCleanups.delete(btn.id);\n }\n\n if (btn.element) {\n slot.appendChild(btn.element);\n } else if (btn.render) {\n const cleanup = btn.render(slot as HTMLElement);\n if (cleanup) {\n state.toolbarButtonCleanups.set(btn.id, cleanup);\n }\n }\n }\n}\n\n/**\n * Render header content from plugins into the shell content area.\n */\nexport function renderHeaderContent(shadowRoot: ShadowRoot, state: ShellState): void {\n const contentArea = shadowRoot.querySelector('.tbw-shell-content');\n if (!contentArea) return;\n\n // Sort by order\n const sortedContents = [...state.headerContents.values()].sort((a, b) => (a.order ?? 100) - (b.order ?? 100));\n\n // Create containers for each content piece (before the slot)\n const slot = contentArea.querySelector('slot[name=\"header-content\"]');\n\n for (const content of sortedContents) {\n // Clean up previous render if any\n const existingCleanup = state.headerContentCleanups.get(content.id);\n if (existingCleanup) {\n existingCleanup();\n state.headerContentCleanups.delete(content.id);\n }\n\n // Check if container already exists\n let container = contentArea.querySelector(`[data-header-content=\"${content.id}\"]`) as HTMLElement | null;\n if (!container) {\n container = document.createElement('div');\n container.setAttribute('data-header-content', content.id);\n // Insert before the slot\n if (slot) {\n contentArea.insertBefore(container, slot);\n } else {\n contentArea.appendChild(container);\n }\n }\n\n const cleanup = content.render(container);\n if (cleanup) {\n state.headerContentCleanups.set(content.id, cleanup);\n }\n }\n}\n\n/**\n * Render content for expanded accordion sections.\n * @param icons - Optional icons for expand/collapse chevrons (from grid config)\n */\nexport function renderPanelContent(\n shadowRoot: ShadowRoot,\n state: ShellState,\n icons?: { expand?: IconValue; collapse?: IconValue },\n): void {\n if (!state.isPanelOpen) return;\n\n const expandIcon = iconToString(icons?.expand ?? DEFAULT_GRID_ICONS.expand);\n const collapseIcon = iconToString(icons?.collapse ?? DEFAULT_GRID_ICONS.collapse);\n\n for (const [panelId, panel] of state.toolPanels) {\n const isExpanded = state.expandedSections.has(panelId);\n const section = shadowRoot.querySelector(`[data-section=\"${panelId}\"]`);\n const contentArea = section?.querySelector('.tbw-accordion-content') as HTMLElement | null;\n\n if (!section || !contentArea) continue;\n\n // Update expanded state\n section.classList.toggle('expanded', isExpanded);\n const header = section.querySelector('.tbw-accordion-header');\n if (header) {\n header.setAttribute('aria-expanded', String(isExpanded));\n }\n const chevron = section.querySelector('.tbw-accordion-chevron');\n if (chevron) {\n chevron.innerHTML = isExpanded ? collapseIcon : expandIcon;\n }\n\n if (isExpanded) {\n // Check if content is already rendered\n if (contentArea.children.length === 0) {\n // Render panel content\n const cleanup = panel.render(contentArea);\n if (cleanup) {\n state.panelCleanups.set(panelId, cleanup);\n }\n }\n } else {\n // Clean up and clear content when collapsed\n const cleanup = state.panelCleanups.get(panelId);\n if (cleanup) {\n cleanup();\n state.panelCleanups.delete(panelId);\n }\n contentArea.innerHTML = '';\n }\n }\n}\n\n/**\n * Update toolbar button active states.\n */\nexport function updateToolbarActiveStates(shadowRoot: ShadowRoot, state: ShellState): void {\n // Update single panel toggle button\n const panelToggle = shadowRoot.querySelector('[data-panel-toggle]');\n if (panelToggle) {\n panelToggle.classList.toggle('active', state.isPanelOpen);\n panelToggle.setAttribute('aria-pressed', String(state.isPanelOpen));\n }\n}\n\n/**\n * Update tool panel open/close state.\n */\nexport function updatePanelState(shadowRoot: ShadowRoot, state: ShellState): void {\n const panel = shadowRoot.querySelector('.tbw-tool-panel') as HTMLElement | null;\n if (!panel) return;\n\n panel.classList.toggle('open', state.isPanelOpen);\n\n // Clear inline width when closing (resize sets inline style that overrides CSS)\n if (!state.isPanelOpen) {\n panel.style.width = '';\n }\n}\n\n/**\n * Get all toolbar button info.\n */\nexport function getToolbarButtonsInfo(config: ShellConfig | undefined, state: ShellState): ToolbarButtonInfo[] {\n const result: ToolbarButtonInfo[] = [];\n\n // Config buttons\n for (const btn of config?.header?.toolbarButtons ?? []) {\n result.push({\n id: btn.id,\n label: btn.label,\n disabled: btn.disabled ?? false,\n source: 'config',\n });\n }\n\n // API buttons\n for (const btn of state.toolbarButtons.values()) {\n result.push({\n id: btn.id,\n label: btn.label,\n disabled: btn.disabled ?? false,\n source: 'config',\n });\n }\n\n // Light DOM buttons (limited info since user provides DOM)\n for (let i = 0; i < state.lightDomButtons.length; i++) {\n const el = state.lightDomButtons[i];\n const btn = el.querySelector('button');\n result.push({\n id: `light-dom-${i}`,\n label: btn?.getAttribute('title') ?? btn?.getAttribute('aria-label') ?? '',\n disabled: btn?.disabled ?? false,\n source: 'light-dom',\n });\n }\n\n // Panel toggles\n for (const panel of state.toolPanels.values()) {\n result.push({\n id: `panel-toggle-${panel.id}`,\n label: panel.tooltip ?? panel.title,\n disabled: false,\n source: 'panel-toggle',\n panelId: panel.id,\n });\n }\n\n return result;\n}\n\n/**\n * Cleanup all shell state when grid disconnects.\n */\nexport function cleanupShellState(state: ShellState): void {\n // Clean up header content\n for (const cleanup of state.headerContentCleanups.values()) {\n cleanup();\n }\n state.headerContentCleanups.clear();\n\n // Clean up active panel\n if (state.activePanelCleanup) {\n state.activePanelCleanup();\n state.activePanelCleanup = null;\n }\n\n // Clean up toolbar buttons\n for (const cleanup of state.toolbarButtonCleanups.values()) {\n cleanup();\n }\n state.toolbarButtonCleanups.clear();\n\n // Invoke panel onClose if open\n if (state.activePanel) {\n const panel = state.toolPanels.get(state.activePanel);\n panel?.onClose?.();\n }\n\n // Clear registrations\n state.toolPanels.clear();\n state.headerContents.clear();\n state.toolbarButtons.clear();\n state.lightDomButtons = [];\n state.lightDomHeaderContent = [];\n state.activePanel = null;\n}\n\n// ============================================================================\n// ShellController - Encapsulates tool panel orchestration logic\n// ============================================================================\n\n/**\n * Callbacks for ShellController to communicate with the grid.\n * This interface decouples the controller from grid internals.\n */\nexport interface ShellControllerCallbacks {\n /** Get the shadow root for DOM queries */\n getShadow: () => ShadowRoot;\n /** Get the current shell config */\n getShellConfig: () => ShellConfig | undefined;\n /** Get accordion expand/collapse icons */\n getAccordionIcons: () => { expand: IconValue; collapse: IconValue };\n /** Emit an event from the grid */\n emit: (eventName: string, detail: unknown) => void;\n /** Refresh the shell header (re-parse light DOM and re-render) */\n refreshShellHeader: () => void;\n}\n\n/**\n * Controller interface for managing shell/tool panel behavior.\n */\nexport interface ShellController {\n /** Whether the shell has been initialized */\n readonly isInitialized: boolean;\n /** Set the initialized state */\n setInitialized(value: boolean): void;\n /** Whether the tool panel is currently open */\n readonly isPanelOpen: boolean;\n /** Get the currently active panel ID (deprecated) */\n readonly activePanel: string | null;\n /** Get IDs of expanded accordion sections */\n readonly expandedSections: string[];\n /** Open the tool panel */\n openToolPanel(): void;\n /** Close the tool panel */\n closeToolPanel(): void;\n /** Toggle the tool panel */\n toggleToolPanel(): void;\n /** Toggle an accordion section */\n toggleToolPanelSection(sectionId: string): void;\n /** Get registered tool panels */\n getToolPanels(): ToolPanelDefinition[];\n /** Register a tool panel */\n registerToolPanel(panel: ToolPanelDefinition): void;\n /** Unregister a tool panel */\n unregisterToolPanel(panelId: string): void;\n /** Get registered header contents */\n getHeaderContents(): HeaderContentDefinition[];\n /** Register header content */\n registerHeaderContent(content: HeaderContentDefinition): void;\n /** Unregister header content */\n unregisterHeaderContent(contentId: string): void;\n /** Get all toolbar buttons info */\n getToolbarButtons(): ToolbarButtonInfo[];\n /** Register a toolbar button */\n registerToolbarButton(button: ToolbarButtonConfig): void;\n /** Unregister a toolbar button */\n unregisterToolbarButton(buttonId: string): void;\n /** Enable/disable a toolbar button */\n setToolbarButtonDisabled(buttonId: string, disabled: boolean): void;\n}\n\n/**\n * Create a ShellController instance.\n * The controller encapsulates all tool panel orchestration logic.\n */\nexport function createShellController(state: ShellState, callbacks: ShellControllerCallbacks): ShellController {\n let initialized = false;\n\n const controller: ShellController = {\n get isInitialized() {\n return initialized;\n },\n setInitialized(value: boolean) {\n initialized = value;\n },\n\n get isPanelOpen() {\n return state.isPanelOpen;\n },\n\n get activePanel() {\n // For backward compatibility, return first expanded section if panel is open\n if (state.isPanelOpen && state.expandedSections.size > 0) {\n return [...state.expandedSections][0];\n }\n return null;\n },\n\n get expandedSections() {\n return [...state.expandedSections];\n },\n\n openToolPanel() {\n if (state.isPanelOpen) return;\n if (state.toolPanels.size === 0) {\n console.warn('[tbw-grid] No tool panels registered');\n return;\n }\n\n state.isPanelOpen = true;\n\n // Auto-expand first section if none expanded\n if (state.expandedSections.size === 0 && state.toolPanels.size > 0) {\n const sortedPanels = [...state.toolPanels.values()].sort((a, b) => (a.order ?? 100) - (b.order ?? 100));\n const firstPanel = sortedPanels[0];\n if (firstPanel) {\n state.expandedSections.add(firstPanel.id);\n }\n }\n\n // Update UI\n const shadow = callbacks.getShadow();\n updateToolbarActiveStates(shadow, state);\n updatePanelState(shadow, state);\n\n // Render accordion sections\n renderPanelContent(shadow, state, callbacks.getAccordionIcons());\n\n // Emit event\n callbacks.emit('tool-panel-open', { sections: controller.expandedSections });\n },\n\n closeToolPanel() {\n if (!state.isPanelOpen) return;\n\n // Clean up all panel content\n for (const cleanup of state.panelCleanups.values()) {\n cleanup();\n }\n state.panelCleanups.clear();\n\n // Legacy cleanup\n if (state.activePanelCleanup) {\n state.activePanelCleanup();\n state.activePanelCleanup = null;\n }\n\n // Call onClose for all panels\n for (const panel of state.toolPanels.values()) {\n panel.onClose?.();\n }\n\n state.isPanelOpen = false;\n\n // Update UI\n const shadow = callbacks.getShadow();\n updateToolbarActiveStates(shadow, state);\n updatePanelState(shadow, state);\n\n // Emit event\n callbacks.emit('tool-panel-close', {});\n },\n\n toggleToolPanel() {\n if (state.isPanelOpen) {\n controller.closeToolPanel();\n } else {\n controller.openToolPanel();\n }\n },\n\n toggleToolPanelSection(sectionId: string) {\n const panel = state.toolPanels.get(sectionId);\n if (!panel) {\n console.warn(`[tbw-grid] Tool panel section \"${sectionId}\" not found`);\n return;\n }\n\n // Don't allow toggling when there's only one panel (it should stay expanded)\n if (state.toolPanels.size === 1) {\n return;\n }\n\n const shadow = callbacks.getShadow();\n const isExpanded = state.expandedSections.has(sectionId);\n\n if (isExpanded) {\n // Collapsing current section\n const cleanup = state.panelCleanups.get(sectionId);\n if (cleanup) {\n cleanup();\n state.panelCleanups.delete(sectionId);\n }\n panel.onClose?.();\n state.expandedSections.delete(sectionId);\n updateAccordionSectionState(shadow, sectionId, false);\n } else {\n // Expanding - first collapse all others (exclusive accordion)\n for (const [otherId, otherPanel] of state.toolPanels) {\n if (otherId !== sectionId && state.expandedSections.has(otherId)) {\n const cleanup = state.panelCleanups.get(otherId);\n if (cleanup) {\n cleanup();\n state.panelCleanups.delete(otherId);\n }\n otherPanel.onClose?.();\n state.expandedSections.delete(otherId);\n updateAccordionSectionState(shadow, otherId, false);\n // Clear content of collapsed section\n const contentEl = shadow.querySelector(`[data-section=\"${otherId}\"] .tbw-accordion-content`);\n if (contentEl) contentEl.innerHTML = '';\n }\n }\n // Now expand the target section\n state.expandedSections.add(sectionId);\n updateAccordionSectionState(shadow, sectionId, true);\n renderAccordionSectionContent(shadow, state, sectionId);\n }\n\n // Emit event\n callbacks.emit('tool-panel-section-toggle', { id: sectionId, expanded: !isExpanded });\n },\n\n getToolPanels() {\n return [...state.toolPanels.values()];\n },\n\n registerToolPanel(panel: ToolPanelDefinition) {\n if (state.toolPanels.has(panel.id)) {\n console.warn(`[tbw-grid] Tool panel \"${panel.id}\" already registered`);\n return;\n }\n state.toolPanels.set(panel.id, panel);\n\n if (initialized) {\n callbacks.refreshShellHeader();\n }\n },\n\n unregisterToolPanel(panelId: string) {\n // Close panel if open and this section is expanded\n if (state.expandedSections.has(panelId)) {\n const cleanup = state.panelCleanups.get(panelId);\n if (cleanup) {\n cleanup();\n state.panelCleanups.delete(panelId);\n }\n state.expandedSections.delete(panelId);\n }\n\n state.toolPanels.delete(panelId);\n\n if (initialized) {\n callbacks.refreshShellHeader();\n }\n },\n\n getHeaderContents() {\n return [...state.headerContents.values()];\n },\n\n registerHeaderContent(content: HeaderContentDefinition) {\n if (state.headerContents.has(content.id)) {\n console.warn(`[tbw-grid] Header content \"${content.id}\" already registered`);\n return;\n }\n state.headerContents.set(content.id, content);\n\n if (initialized) {\n renderHeaderContent(callbacks.getShadow(), state);\n }\n },\n\n unregisterHeaderContent(contentId: string) {\n // Clean up\n const cleanup = state.headerContentCleanups.get(contentId);\n if (cleanup) {\n cleanup();\n state.headerContentCleanups.delete(contentId);\n }\n\n // Call onDestroy\n const content = state.headerContents.get(contentId);\n content?.onDestroy?.();\n\n state.headerContents.delete(contentId);\n\n // Remove DOM element\n const el = callbacks.getShadow().querySelector(`[data-header-content=\"${contentId}\"]`);\n el?.remove();\n },\n\n getToolbarButtons() {\n return getToolbarButtonsInfo(callbacks.getShellConfig(), state);\n },\n\n registerToolbarButton(button: ToolbarButtonConfig) {\n if (state.toolbarButtons.has(button.id)) {\n console.warn(`[tbw-grid] Toolbar button \"${button.id}\" already registered`);\n return;\n }\n state.toolbarButtons.set(button.id, button);\n\n if (initialized) {\n callbacks.refreshShellHeader();\n }\n },\n\n unregisterToolbarButton(buttonId: string) {\n // Clean up\n const cleanup = state.toolbarButtonCleanups.get(buttonId);\n if (cleanup) {\n cleanup();\n state.toolbarButtonCleanups.delete(buttonId);\n }\n\n state.toolbarButtons.delete(buttonId);\n\n if (initialized) {\n callbacks.refreshShellHeader();\n }\n },\n\n setToolbarButtonDisabled(buttonId: string, disabled: boolean) {\n // Check API-registered buttons\n const apiBtn = state.toolbarButtons.get(buttonId);\n if (apiBtn) {\n apiBtn.disabled = disabled;\n }\n\n // Update DOM\n const btn = callbacks.getShadow().querySelector(`[data-btn=\"${buttonId}\"]`) as HTMLButtonElement | null;\n if (btn) {\n btn.disabled = disabled;\n }\n },\n };\n\n return controller;\n}\n\n/**\n * Update accordion section visual state.\n */\nfunction updateAccordionSectionState(shadow: ShadowRoot, sectionId: string, expanded: boolean): void {\n const section = shadow.querySelector(`[data-section=\"${sectionId}\"]`);\n if (section) {\n section.classList.toggle('expanded', expanded);\n }\n}\n\n/**\n * Render content for a single accordion section.\n */\nfunction renderAccordionSectionContent(shadow: ShadowRoot, state: ShellState, sectionId: string): void {\n const panel = state.toolPanels.get(sectionId);\n if (!panel?.render) return;\n\n const contentEl = shadow.querySelector(`[data-section=\"${sectionId}\"] .tbw-accordion-content`);\n if (!contentEl) return;\n\n const cleanup = panel.render(contentEl as HTMLElement);\n if (cleanup) {\n state.panelCleanups.set(sectionId, cleanup);\n }\n}\n","/**\n * Plugin Manager\n *\n * Manages plugin instances for a single grid.\n * Each grid has its own PluginManager with its own set of plugin instances.\n */\n\nimport type { ColumnConfig } from '../types';\nimport type {\n BaseGridPlugin,\n CellClickEvent,\n CellEditor,\n CellMouseEvent,\n CellRenderer,\n HeaderClickEvent,\n HeaderRenderer,\n PluginQuery,\n RowClickEvent,\n ScrollEvent,\n} from './base-plugin';\n\n/**\n * Manages plugins for a single grid instance.\n */\nexport class PluginManager {\n /** Plugin instances in order of attachment */\n private plugins: BaseGridPlugin[] = [];\n\n /** Map from plugin class to instance for fast lookup */\n private pluginMap: Map<new (...args: unknown[]) => BaseGridPlugin, BaseGridPlugin> = new Map();\n\n /** Cell renderers registered by plugins */\n private cellRenderers: Map<string, CellRenderer> = new Map();\n\n /** Header renderers registered by plugins */\n private headerRenderers: Map<string, HeaderRenderer> = new Map();\n\n /** Cell editors registered by plugins */\n private cellEditors: Map<string, CellEditor> = new Map();\n\n constructor(private grid: any) {}\n\n /**\n * Attach all plugins from the config.\n */\n attachAll(plugins: BaseGridPlugin[]): void {\n for (const plugin of plugins) {\n this.attach(plugin);\n }\n }\n\n /**\n * Attach a plugin to this grid.\n */\n attach(plugin: BaseGridPlugin): void {\n // Store by constructor for type-safe lookup\n this.pluginMap.set(plugin.constructor as new (...args: unknown[]) => BaseGridPlugin, plugin);\n this.plugins.push(plugin);\n\n // Register renderers/editors\n if (plugin.cellRenderers) {\n for (const [type, renderer] of Object.entries(plugin.cellRenderers)) {\n this.cellRenderers.set(type, renderer);\n }\n }\n if (plugin.headerRenderers) {\n for (const [type, renderer] of Object.entries(plugin.headerRenderers)) {\n this.headerRenderers.set(type, renderer);\n }\n }\n if (plugin.cellEditors) {\n for (const [type, editor] of Object.entries(plugin.cellEditors)) {\n this.cellEditors.set(type, editor);\n }\n }\n\n // Call attach lifecycle method\n plugin.attach(this.grid);\n }\n\n /**\n * Detach all plugins and clean up.\n */\n detachAll(): void {\n // Detach in reverse order\n for (let i = this.plugins.length - 1; i >= 0; i--) {\n this.plugins[i].detach();\n }\n this.plugins = [];\n this.pluginMap.clear();\n this.cellRenderers.clear();\n this.headerRenderers.clear();\n this.cellEditors.clear();\n }\n\n /**\n * Get a plugin instance by its class.\n */\n getPlugin<T extends BaseGridPlugin>(PluginClass: new (...args: any[]) => T): T | undefined {\n return this.pluginMap.get(PluginClass) as T | undefined;\n }\n\n /**\n * Get a plugin instance by its name.\n */\n getPluginByName(name: string): BaseGridPlugin | undefined {\n return this.plugins.find((p) => p.name === name);\n }\n\n /**\n * Check if a plugin is attached.\n */\n hasPlugin<T extends BaseGridPlugin>(PluginClass: new (...args: any[]) => T): boolean {\n return this.pluginMap.has(PluginClass);\n }\n\n /**\n * Get all attached plugins.\n */\n getAll(): readonly BaseGridPlugin[] {\n return this.plugins;\n }\n\n /**\n * Get a cell renderer by type name.\n */\n getCellRenderer(type: string): CellRenderer | undefined {\n return this.cellRenderers.get(type);\n }\n\n /**\n * Get a header renderer by type name.\n */\n getHeaderRenderer(type: string): HeaderRenderer | undefined {\n return this.headerRenderers.get(type);\n }\n\n /**\n * Get a cell editor by type name.\n */\n getCellEditor(type: string): CellEditor | undefined {\n return this.cellEditors.get(type);\n }\n\n /**\n * Get all CSS styles from all plugins.\n */\n getAllStyles(): string {\n return this.plugins\n .filter((p) => p.styles)\n .map((p) => p.styles)\n .join('\\n');\n }\n\n // #region Hook execution methods\n\n /**\n * Execute processRows hook on all plugins.\n */\n processRows(rows: readonly any[]): any[] {\n let result = [...rows];\n for (const plugin of this.plugins) {\n if (plugin.processRows) {\n result = plugin.processRows(result);\n }\n }\n return result;\n }\n\n /**\n * Execute processColumns hook on all plugins.\n */\n processColumns(columns: readonly ColumnConfig[]): ColumnConfig[] {\n let result = [...columns];\n for (const plugin of this.plugins) {\n if (plugin.processColumns) {\n result = plugin.processColumns(result);\n }\n }\n return result;\n }\n\n /**\n * Execute beforeRender hook on all plugins.\n */\n beforeRender(): void {\n for (const plugin of this.plugins) {\n plugin.beforeRender?.();\n }\n }\n\n /**\n * Execute afterRender hook on all plugins.\n */\n afterRender(): void {\n for (const plugin of this.plugins) {\n plugin.afterRender?.();\n }\n }\n\n /**\n * Execute onScrollRender hook on all plugins.\n * Called after scroll-triggered row rendering for lightweight visual state updates.\n */\n onScrollRender(): void {\n for (const plugin of this.plugins) {\n plugin.onScrollRender?.();\n }\n }\n\n /**\n * Get total extra height contributed by plugins (e.g., expanded detail rows).\n * Used to adjust scrollbar height calculations.\n */\n getExtraHeight(): number {\n let total = 0;\n for (const plugin of this.plugins) {\n if (typeof plugin.getExtraHeight === 'function') {\n total += plugin.getExtraHeight();\n }\n }\n return total;\n }\n\n /**\n * Get extra height from plugins that appears before a given row index.\n * Used by virtualization to correctly position the scroll window.\n */\n getExtraHeightBefore(beforeRowIndex: number): number {\n let total = 0;\n for (const plugin of this.plugins) {\n if (typeof plugin.getExtraHeightBefore === 'function') {\n total += plugin.getExtraHeightBefore(beforeRowIndex);\n }\n }\n return total;\n }\n\n /**\n * Adjust the virtualization start index based on plugin needs.\n * Returns the minimum start index from all plugins.\n */\n adjustVirtualStart(start: number, scrollTop: number, rowHeight: number): number {\n let adjustedStart = start;\n for (const plugin of this.plugins) {\n if (typeof plugin.adjustVirtualStart === 'function') {\n const pluginStart = plugin.adjustVirtualStart(start, scrollTop, rowHeight);\n if (pluginStart < adjustedStart) {\n adjustedStart = pluginStart;\n }\n }\n }\n return adjustedStart;\n }\n\n /**\n * Execute renderRow hook on all plugins.\n * Returns true if any plugin handled the row.\n */\n renderRow(row: any, rowEl: HTMLElement, rowIndex: number): boolean {\n for (const plugin of this.plugins) {\n if (plugin.renderRow?.(row, rowEl, rowIndex)) {\n return true;\n }\n }\n return false;\n }\n\n /**\n * Query all plugins with a generic query and collect responses.\n * This enables inter-plugin communication without the core knowing plugin-specific concepts.\n *\n * Common query types are defined in PLUGIN_QUERIES, but plugins can define their own.\n *\n * @param query - The query object containing type and context\n * @returns Array of non-undefined responses from plugins\n */\n queryPlugins<T>(query: PluginQuery): T[] {\n const responses: T[] = [];\n for (const plugin of this.plugins) {\n const response = plugin.onPluginQuery?.(query);\n if (response !== undefined) {\n responses.push(response as T);\n }\n }\n return responses;\n }\n\n /**\n * Execute onKeyDown hook on all plugins.\n * Returns true if any plugin handled the event.\n */\n onKeyDown(event: KeyboardEvent): boolean {\n for (const plugin of this.plugins) {\n if (plugin.onKeyDown?.(event)) {\n return true;\n }\n }\n return false;\n }\n\n /**\n * Execute onCellClick hook on all plugins.\n * Returns true if any plugin handled the event.\n */\n onCellClick(event: CellClickEvent): boolean {\n for (const plugin of this.plugins) {\n if (plugin.onCellClick?.(event)) {\n return true;\n }\n }\n return false;\n }\n\n /**\n * Execute onRowClick hook on all plugins.\n * Returns true if any plugin handled the event.\n */\n onRowClick(event: RowClickEvent): boolean {\n for (const plugin of this.plugins) {\n if (plugin.onRowClick?.(event)) {\n return true;\n }\n }\n return false;\n }\n\n /**\n * Execute onHeaderClick hook on all plugins.\n * Returns true if any plugin handled the event.\n */\n onHeaderClick(event: HeaderClickEvent): boolean {\n for (const plugin of this.plugins) {\n if (plugin.onHeaderClick?.(event)) {\n return true;\n }\n }\n return false;\n }\n\n /**\n * Execute onScroll hook on all plugins.\n */\n onScroll(event: ScrollEvent): void {\n for (const plugin of this.plugins) {\n plugin.onScroll?.(event);\n }\n }\n\n /**\n * Execute onCellMouseDown hook on all plugins.\n * Returns true if any plugin handled the event.\n */\n onCellMouseDown(event: CellMouseEvent): boolean {\n for (const plugin of this.plugins) {\n if (plugin.onCellMouseDown?.(event)) {\n return true;\n }\n }\n return false;\n }\n\n /**\n * Execute onCellMouseMove hook on all plugins.\n * Returns true if any plugin handled the event.\n */\n onCellMouseMove(event: CellMouseEvent): boolean {\n for (const plugin of this.plugins) {\n if (plugin.onCellMouseMove?.(event)) {\n return true;\n }\n }\n return false;\n }\n\n /**\n * Execute onCellMouseUp hook on all plugins.\n * Returns true if any plugin handled the event.\n */\n onCellMouseUp(event: CellMouseEvent): boolean {\n for (const plugin of this.plugins) {\n if (plugin.onCellMouseUp?.(event)) {\n return true;\n }\n }\n return false;\n }\n\n // #endregion\n\n // #region Scroll Boundary Hooks\n\n /**\n * Collect horizontal scroll boundary offsets from all plugins.\n * Combines offsets from all plugins that report them.\n *\n * @param rowEl - The row element (optional, for calculating widths from rendered cells)\n * @param focusedCell - The currently focused cell element (optional, to determine if scrolling should be skipped)\n * @returns Combined left and right pixel offsets, plus skipScroll if any plugin requests it\n */\n getHorizontalScrollOffsets(\n rowEl?: HTMLElement,\n focusedCell?: HTMLElement,\n ): { left: number; right: number; skipScroll?: boolean } {\n let left = 0;\n let right = 0;\n let skipScroll = false;\n for (const plugin of this.plugins) {\n const offsets = plugin.getHorizontalScrollOffsets?.(rowEl, focusedCell);\n if (offsets) {\n left += offsets.left;\n right += offsets.right;\n if (offsets.skipScroll) {\n skipScroll = true;\n }\n }\n }\n return { left, right, skipScroll };\n }\n // #endregion\n\n // #region Shell Integration Hooks\n\n /**\n * Collect tool panels from all plugins.\n * Returns panels sorted by order (ascending).\n */\n getToolPanels(): {\n plugin: BaseGridPlugin;\n panel: NonNullable<ReturnType<NonNullable<BaseGridPlugin['getToolPanel']>>>;\n }[] {\n const panels: {\n plugin: BaseGridPlugin;\n panel: NonNullable<ReturnType<NonNullable<BaseGridPlugin['getToolPanel']>>>;\n }[] = [];\n for (const plugin of this.plugins) {\n const panel = plugin.getToolPanel?.();\n if (panel) {\n panels.push({ plugin, panel });\n }\n }\n // Sort by order (ascending), default to 0\n return panels.sort((a, b) => (a.panel.order ?? 0) - (b.panel.order ?? 0));\n }\n\n /**\n * Collect header contents from all plugins.\n * Returns contents sorted by order (ascending).\n */\n getHeaderContents(): {\n plugin: BaseGridPlugin;\n content: NonNullable<ReturnType<NonNullable<BaseGridPlugin['getHeaderContent']>>>;\n }[] {\n const contents: {\n plugin: BaseGridPlugin;\n content: NonNullable<ReturnType<NonNullable<BaseGridPlugin['getHeaderContent']>>>;\n }[] = [];\n for (const plugin of this.plugins) {\n const content = plugin.getHeaderContent?.();\n if (content) {\n contents.push({ plugin, content });\n }\n }\n // Sort by order (ascending), default to 0\n return contents.sort((a, b) => (a.content.order ?? 0) - (b.content.order ?? 0));\n }\n // #endregion\n}\n","import styles from './grid.css?inline';\nimport { applyColumnState, collectColumnState, createStateChangeHandler } from './internal/column-state';\nimport { autoSizeColumns, getColumnConfiguration, updateTemplate } from './internal/columns';\nimport { exitRowEdit, inlineEnterEdit, startRowEdit } from './internal/editing';\nimport { renderHeader } from './internal/header';\nimport { inferColumns } from './internal/inference';\nimport { ensureCellVisible, handleGridKeyDown } from './internal/keyboard';\nimport { createResizeController } from './internal/resize';\nimport { invalidateCellCache, renderVisibleRows } from './internal/rows';\nimport {\n cleanupShellState,\n createShellController,\n createShellState,\n parseLightDomShell,\n renderCustomToolbarButtons,\n renderHeaderContent,\n renderShellBody,\n renderShellHeader,\n setupShellEventListeners,\n setupToolPanelResize,\n shouldRenderShellHeader,\n type ShellController,\n type ShellState,\n} from './internal/shell';\nimport type { CellMouseEvent, ScrollEvent } from './plugin';\nimport type {\n BaseGridPlugin,\n CellClickEvent,\n HeaderClickEvent,\n PluginQuery,\n RowClickEvent,\n} from './plugin/base-plugin';\nimport { PluginManager } from './plugin/plugin-manager';\nimport type {\n ActivateCellDetail,\n CellCommitDetail,\n ColumnConfig,\n ColumnConfigMap,\n ColumnInternal,\n ColumnResizeDetail,\n FitMode,\n GridColumnState,\n GridConfig,\n HeaderContentDefinition,\n InternalGrid,\n ResizeController,\n RowCommitDetail,\n SortChangeDetail,\n ToolbarButtonConfig,\n ToolbarButtonInfo,\n ToolPanelDefinition,\n VirtualState,\n} from './types';\nimport { DEFAULT_GRID_ICONS } from './types';\n\n/**\n * High-performance data grid web component.\n * During migration, uses tbw-grid tag to avoid conflicts with existing datagrid.\n * Will be renamed back to data-grid when migration is complete.\n *\n * ## Configuration Architecture\n *\n * The grid follows a **single source of truth** pattern where all configuration\n * converges into `#effectiveConfig`. Users can set configuration via multiple inputs:\n *\n * **Input Sources (precedence low → high):**\n * 1. `gridConfig` property - base configuration object\n * 2. Light DOM elements:\n * - `<tbw-grid-column>` → `effectiveConfig.columns`\n * - `<tbw-grid-header title=\"...\">` → `effectiveConfig.shell.header.title`\n * - `<tbw-grid-header-content>` → `effectiveConfig.shell.header.content`\n * 3. `columns` property → merged into `effectiveConfig.columns`\n * 4. `fitMode` property → merged into `effectiveConfig.fitMode`\n * 5. `editOn` property → merged into `effectiveConfig.editOn`\n * 6. Column inference from first row (if no columns defined)\n *\n * **Derived State:**\n * - `_columns` - processed columns from `effectiveConfig.columns` after plugin hooks\n * - `_rows` - processed rows after plugin hooks (grouping, filtering, etc.)\n *\n * The `#mergeEffectiveConfig()` method is the single place where all inputs converge.\n * All rendering and logic should read from `effectiveConfig` or derived state.\n *\n * @element tbw-grid\n *\n * @csspart container - The main grid container\n * @csspart header - The header row container\n * @csspart body - The body/rows container\n *\n * @fires cell-commit - Fired when a cell value is committed\n * @fires row-commit - Fired when a bulk row edit session commits\n * @fires changed-rows-reset - Fired after resetChangedRows() unless silent\n * @fires mount-external-view - Fired to request mounting of an external view renderer\n * @fires mount-external-editor - Fired to request mounting of an external editor renderer\n * @fires sort-change - Fired when sort state changes for a column\n * @fires column-resize - Fired after a column resize drag completes\n * @fires activate-cell - Fired when a cell activation intent occurs\n * @fires group-toggle - Fired when a group row is toggled\n *\n * @cssprop --tbw-color-bg - Background color\n * @cssprop --tbw-color-fg - Foreground/text color\n */\n// Injected by Vite at build time from package.json\ndeclare const __GRID_VERSION__: string;\n\nexport class DataGridElement<T = any> extends HTMLElement implements InternalGrid<T> {\n // TODO: Rename to 'data-grid' when migration is complete\n static readonly tagName = 'tbw-grid';\n static readonly version = typeof __GRID_VERSION__ !== 'undefined' ? __GRID_VERSION__ : 'dev';\n\n // ---------------- Observed Attributes ----------------\n static get observedAttributes(): string[] {\n return ['rows', 'columns', 'grid-config', 'fit-mode', 'edit-on'];\n }\n\n readonly #shadow: ShadowRoot;\n #initialized = false;\n\n // ---------------- Ready Promise ----------------\n #readyPromise: Promise<void>;\n #readyResolve?: () => void;\n\n // #region Input Properties\n // These backing fields store raw user input. They are merged into\n // #effectiveConfig by #mergeEffectiveConfig(). Never read directly\n // for rendering logic - always use effectiveConfig or derived state.\n #rows: T[] = [];\n #columns?: ColumnConfig<T>[] | ColumnConfigMap<T>;\n #gridConfig?: GridConfig<T>;\n #fitMode?: FitMode;\n #editOn?: string;\n // #endregion\n\n // #region Single Source of Truth\n // All input sources converge here. This is the canonical config\n // that all rendering and logic should read from.\n #effectiveConfig: GridConfig<T> = {};\n #connected = false;\n #scrollRaf = 0;\n #pendingScrollTop: number | null = null;\n #hasScrollPlugins = false; // Cached flag for plugin scroll handlers\n #renderRowHook?: (row: any, rowEl: HTMLElement, rowIndex: number) => boolean; // Cached hook to avoid closures\n #isDragging = false;\n #touchStartY: number | null = null;\n #touchStartX: number | null = null;\n #touchScrollTop: number | null = null;\n #touchScrollLeft: number | null = null;\n #touchLastY: number | null = null;\n #touchLastX: number | null = null;\n #touchLastTime: number | null = null;\n #touchVelocityY = 0;\n #touchVelocityX = 0;\n #momentumRaf = 0;\n #eventAbortController?: AbortController;\n #resizeObserver?: ResizeObserver;\n\n // ---------------- Plugin System ----------------\n #pluginManager!: PluginManager;\n\n // ---------------- Column State ----------------\n #stateChangeHandler?: () => void;\n #initialColumnState?: GridColumnState;\n\n // ---------------- Shell State ----------------\n #shellState: ShellState = createShellState();\n #shellController!: ShellController;\n #resizeCleanup?: () => void;\n // #endregion\n\n // #region Derived State\n // _rows: result of applying plugin processRows hooks\n _rows: T[] = [];\n\n // _baseColumns: columns before plugin transformation (analogous to #rows for row processing)\n // This is the source of truth for processColumns - plugins transform these\n #baseColumns: ColumnInternal<T>[] = [];\n\n // _columns is a getter/setter that operates on effectiveConfig.columns\n // This ensures effectiveConfig.columns is the single source of truth for columns\n // _columns always contains ALL columns (including hidden)\n get _columns(): ColumnInternal<T>[] {\n return (this.#effectiveConfig.columns ?? []) as ColumnInternal<T>[];\n }\n set _columns(value: ColumnInternal<T>[]) {\n this.#effectiveConfig.columns = value as ColumnConfig<T>[];\n }\n\n // visibleColumns returns only visible columns for rendering\n // This is what header/row rendering should use\n get _visibleColumns(): ColumnInternal<T>[] {\n return this._columns.filter((c) => !c.hidden);\n }\n // #endregion\n\n // #region Runtime State (Plugin-accessible)\n // DOM references\n _headerRowEl!: HTMLElement;\n _bodyEl!: HTMLElement;\n _rowPool: HTMLElement[] = [];\n _resizeController!: ResizeController;\n\n // Virtualization & scroll state\n _virtualization: VirtualState = {\n enabled: true,\n rowHeight: 28,\n bypassThreshold: 24,\n start: 0,\n end: 0,\n container: null,\n viewportEl: null,\n totalHeightEl: null,\n };\n\n // Focus & navigation\n _focusRow = 0;\n _focusCol = 0;\n\n // Sort state\n _sortState: { field: string; direction: 1 | -1 } | null = null;\n\n // Edit state\n _activeEditRows = -1;\n _rowEditSnapshots = new Map<number, T>();\n _changedRowIndices = new Set<number>();\n\n // Layout\n _gridTemplate = '';\n // #endregion\n\n // #region Implementation Details (Internal only)\n __rowRenderEpoch = 0;\n __didInitialAutoSize = false;\n __lightDomColumnsCache?: ColumnInternal[];\n __originalColumnNodes?: HTMLElement[];\n __originalOrder: T[] = [];\n // #endregion\n\n // ---------------- Public API Props (getters/setters) ----------------\n // Getters return the EFFECTIVE value (after merging), not the raw input.\n // This is what consumers and plugins need - the current resolved state.\n // Setters update input properties which trigger re-merge into effectiveConfig.\n\n get rows(): T[] {\n return this._rows;\n }\n set rows(value: T[]) {\n const oldValue = this.#rows;\n this.#rows = value;\n if (oldValue !== value) {\n this.#onRowsChanged();\n }\n }\n\n /**\n * Get the original unfiltered/unprocessed rows.\n * Use this when you need access to all source data regardless of active filters.\n */\n get sourceRows(): T[] {\n return this.#rows;\n }\n\n get columns(): ColumnConfig<T>[] {\n return [...this._columns] as ColumnConfig<T>[];\n }\n set columns(value: ColumnConfig<T>[] | ColumnConfigMap<T> | undefined) {\n const oldValue = this.#columns;\n this.#columns = value;\n if (oldValue !== value) {\n this.#onColsChanged();\n }\n }\n\n get gridConfig(): GridConfig<T> {\n return this.#effectiveConfig;\n }\n set gridConfig(value: GridConfig<T> | undefined) {\n const oldValue = this.#gridConfig;\n this.#gridConfig = value;\n if (oldValue !== value) {\n this.#onGridConfigChanged();\n }\n }\n\n get fitMode(): FitMode {\n return this.#effectiveConfig.fitMode ?? 'stretch';\n }\n set fitMode(value: FitMode | undefined) {\n const oldValue = this.#fitMode;\n this.#fitMode = value;\n if (oldValue !== value) {\n this.#onFitChanged();\n }\n }\n\n get editOn(): string | undefined {\n return this.#effectiveConfig.editOn;\n }\n set editOn(value: string | undefined) {\n const oldValue = this.#editOn;\n this.#editOn = value;\n if (oldValue !== value) {\n this.#onEditModeChanged();\n }\n }\n\n /**\n * Effective config accessor for internal modules and plugins.\n * Returns the merged config (single source of truth) before plugin processing.\n * Use this when you need the raw merged config (e.g., for column definitions including hidden).\n * @internal Plugin API\n */\n get effectiveConfig(): GridConfig<T> {\n return this.#effectiveConfig;\n }\n\n /**\n * Get the disconnect signal for event listener cleanup.\n * This signal is aborted when the grid disconnects from the DOM.\n * Plugins and internal code can use this for automatic listener cleanup.\n * @internal Plugin API\n * @example\n * element.addEventListener('click', handler, { signal: this.grid.disconnectSignal });\n */\n get disconnectSignal(): AbortSignal {\n // Ensure AbortController exists (created in connectedCallback before plugins attach)\n if (!this.#eventAbortController) {\n this.#eventAbortController = new AbortController();\n }\n return this.#eventAbortController.signal;\n }\n\n constructor() {\n super();\n this.#shadow = this.attachShadow({ mode: 'open' });\n this.#injectStyles();\n this.#readyPromise = new Promise((res) => (this.#readyResolve = res));\n\n // Initialize shell controller with callbacks\n this.#shellController = createShellController(this.#shellState, {\n getShadow: () => this.#shadow,\n getShellConfig: () => this.#effectiveConfig?.shell,\n getAccordionIcons: () => ({\n expand: this.#effectiveConfig?.icons?.expand ?? DEFAULT_GRID_ICONS.expand,\n collapse: this.#effectiveConfig?.icons?.collapse ?? DEFAULT_GRID_ICONS.collapse,\n }),\n emit: (eventName, detail) => this.#emit(eventName, detail),\n refreshShellHeader: () => this.refreshShellHeader(),\n });\n }\n\n #injectStyles(): void {\n const sheet = new CSSStyleSheet();\n sheet.replaceSync(styles);\n this.#shadow.adoptedStyleSheets = [sheet];\n }\n\n // ---------------- Plugin System ----------------\n\n /**\n * Get a plugin instance by its class.\n * Used by plugins for inter-plugin communication.\n * @internal Plugin API\n */\n getPlugin<P extends BaseGridPlugin>(PluginClass: new (...args: any[]) => P): P | undefined {\n return this.#pluginManager?.getPlugin(PluginClass);\n }\n\n /**\n * Get a plugin instance by its name.\n * Used for loose coupling between plugins (avoids static imports).\n * @internal Plugin API\n */\n getPluginByName(name: string): BaseGridPlugin | undefined {\n return this.#pluginManager?.getPluginByName(name);\n }\n\n /**\n * Request a full re-render of the grid.\n * Called by plugins when they need the grid to update.\n * Note: This does NOT reset plugin state - just re-processes rows/columns and renders.\n * @internal Plugin API\n */\n requestRender(): void {\n this.#rebuildRowModel();\n this.#processColumns();\n renderHeader(this);\n updateTemplate(this);\n this.refreshVirtualWindow(true);\n }\n\n /**\n * Update the grid's column template CSS.\n * Called by resize controller during column resize operations.\n * @internal\n */\n updateTemplate(): void {\n updateTemplate(this);\n }\n\n /**\n * Request a lightweight style update without rebuilding DOM.\n * Called by plugins when they only need to update CSS classes/styles.\n * This runs all plugin afterRender hooks without rebuilding row/column DOM.\n * @internal Plugin API\n */\n requestAfterRender(): void {\n this.#pluginManager?.afterRender();\n }\n\n /**\n * Initialize plugin system with instances from config.\n * Plugins are class instances passed in gridConfig.plugins[].\n */\n #initializePlugins(): void {\n // Create plugin manager for this grid\n this.#pluginManager = new PluginManager(this);\n\n // Get plugin instances from config - ensure it's an array\n const pluginsConfig = this.#effectiveConfig?.plugins;\n const plugins = Array.isArray(pluginsConfig) ? (pluginsConfig as BaseGridPlugin[]) : [];\n\n // Attach all plugins\n this.#pluginManager.attachAll(plugins);\n }\n\n /**\n * Inject all plugin styles into the shadow DOM.\n * Must be called after #render() since innerHTML wipes existing content.\n */\n #injectAllPluginStyles(): void {\n const allStyles = this.#pluginManager?.getAllStyles() ?? '';\n if (allStyles) {\n const styleEl = document.createElement('style');\n styleEl.setAttribute('data-plugin', 'all');\n styleEl.textContent = allStyles;\n this.#shadow.appendChild(styleEl);\n }\n }\n\n /**\n * Update plugins when grid config changes.\n * With class-based plugins, we need to detach old and attach new.\n */\n #updatePluginConfigs(): void {\n // With class-based plugins, config changes require re-initialization\n // The new plugins are in the new config - detach old, attach new\n if (this.#pluginManager) {\n this.#pluginManager.detachAll();\n }\n this.#initializePlugins();\n this.#injectAllPluginStyles();\n // Update cached scroll plugin flag\n this.#hasScrollPlugins = this.#pluginManager?.getAll().some((p) => p.onScroll) ?? false;\n }\n\n /**\n * Clean up plugin states when grid disconnects.\n */\n #destroyPlugins(): void {\n this.#pluginManager?.detachAll();\n }\n\n /**\n * Collect tool panels and header content from all plugins.\n * Called after plugins are attached but before render.\n */\n #collectPluginShellContributions(): void {\n if (!this.#pluginManager) return;\n\n // Collect tool panels from plugins\n const pluginPanels = this.#pluginManager.getToolPanels();\n for (const { panel } of pluginPanels) {\n // Skip if already registered (light DOM or API takes precedence)\n if (!this.#shellState.toolPanels.has(panel.id)) {\n this.#shellState.toolPanels.set(panel.id, panel);\n }\n }\n\n // Collect header contents from plugins\n const pluginContents = this.#pluginManager.getHeaderContents();\n for (const { content } of pluginContents) {\n // Skip if already registered (light DOM or API takes precedence)\n if (!this.#shellState.headerContents.has(content.id)) {\n this.#shellState.headerContents.set(content.id, content);\n }\n }\n }\n\n // ---------------- Lifecycle ----------------\n connectedCallback(): void {\n if (!this.hasAttribute('tabindex')) (this as any).tabIndex = 0;\n if (!this.hasAttribute('version')) this.setAttribute('version', DataGridElement.version);\n this._rows = Array.isArray(this.#rows) ? [...this.#rows] : [];\n\n // Create AbortController for all event listeners (grid internal + plugins)\n // This must happen BEFORE plugins attach so they can use disconnectSignal\n // Abort any previous controller first (in case of re-connect)\n this.#eventAbortController?.abort();\n this.#eventAbortController = new AbortController();\n\n // Merge all config sources into effectiveConfig (including columns)\n this.#mergeEffectiveConfig();\n\n // Initialize plugin system (now plugins can access disconnectSignal)\n this.#initializePlugins();\n\n // Collect tool panels and header content from plugins (must be before render)\n this.#collectPluginShellContributions();\n\n if (!this.#initialized) {\n this.#render();\n this.#injectAllPluginStyles(); // Inject plugin styles after render\n this.#initialized = true;\n }\n this.#afterConnect();\n }\n\n disconnectedCallback(): void {\n // Clean up plugin states\n this.#destroyPlugins();\n\n // Clean up shell state\n cleanupShellState(this.#shellState);\n this.#shellController.setInitialized(false);\n\n // Clean up tool panel resize handler\n this.#resizeCleanup?.();\n this.#resizeCleanup = undefined;\n\n // Abort all event listeners (internal + document-level)\n // This cleans up all listeners added with { signal } option\n if (this.#eventAbortController) {\n this.#eventAbortController.abort();\n this.#eventAbortController = undefined;\n }\n\n if (this._resizeController) {\n this._resizeController.dispose();\n }\n if (this.#resizeObserver) {\n this.#resizeObserver.disconnect();\n this.#resizeObserver = undefined;\n }\n this.#connected = false;\n }\n\n /**\n * Handle HTML attribute changes.\n * Only processes attribute values when SET (non-null).\n * Removing an attribute does NOT clear JS-set properties.\n */\n attributeChangedCallback(name: string, oldValue: string | null, newValue: string | null): void {\n if (oldValue === newValue || !newValue || newValue === 'null' || newValue === 'undefined') return;\n\n // Map kebab-case attributes to camelCase properties\n const propMap: Record<string, keyof this> = {\n rows: 'rows',\n columns: 'columns',\n 'grid-config': 'gridConfig',\n 'fit-mode': 'fitMode',\n 'edit-on': 'editOn',\n };\n\n const prop = propMap[name];\n if (!prop) return;\n\n // JSON attributes need parsing\n if (name === 'rows' || name === 'columns' || name === 'grid-config') {\n try {\n (this as any)[prop] = JSON.parse(newValue);\n } catch {\n console.warn(`[tbw-grid] Invalid JSON for '${name}' attribute:`, newValue);\n }\n } else {\n // String attributes (fit-mode, edit-on)\n (this as any)[prop] = newValue;\n }\n }\n\n #afterConnect(): void {\n // Shell changes the DOM structure - need to find elements appropriately\n const gridContent = this.#shadow.querySelector('.tbw-grid-content');\n const gridRoot = gridContent ?? this.#shadow.querySelector('.tbw-grid-root');\n\n this._headerRowEl = gridRoot?.querySelector('.header-row') as HTMLElement;\n // Faux scrollbar pattern:\n // - .faux-vscroll-spacer sets virtual height\n // - .rows-viewport provides visible height for virtualization calculations\n this._virtualization.totalHeightEl = gridRoot?.querySelector('.faux-vscroll-spacer') as HTMLElement;\n this._virtualization.viewportEl = gridRoot?.querySelector('.rows-viewport') as HTMLElement;\n this._bodyEl = gridRoot?.querySelector('.rows') as HTMLElement;\n\n // Initialize shell header content and custom buttons if shell is active\n if (this.#shellController.isInitialized) {\n // Render plugin header content\n renderHeaderContent(this.#shadow, this.#shellState);\n // Render custom toolbar buttons (element/render modes)\n renderCustomToolbarButtons(this.#shadow, this.#effectiveConfig?.shell, this.#shellState);\n // Open default section if configured\n const defaultOpen = this.#effectiveConfig?.shell?.toolPanel?.defaultOpen;\n if (defaultOpen && this.#shellState.toolPanels.has(defaultOpen)) {\n this.openToolPanel();\n this.#shellState.expandedSections.add(defaultOpen);\n }\n }\n\n // Mark for tests that afterConnect ran\n this.setAttribute('data-upgraded', '');\n this.#connected = true;\n\n // Get the signal for event listener cleanup (AbortController created in connectedCallback)\n const signal = this.disconnectSignal;\n\n // Create resize controller BEFORE setup - renderHeader() needs it for resize handle mousedown events\n this._resizeController = createResizeController(this as any);\n\n // Run setup\n this.#setup();\n\n // Element-level keydown handler (uses signal for automatic cleanup)\n this.addEventListener('keydown', (e) => handleGridKeyDown(this as any, e), { signal });\n\n // Document-level listeners (also use signal for automatic cleanup)\n // Escape key to cancel row editing\n document.addEventListener(\n 'keydown',\n (e: KeyboardEvent) => {\n if (e.key === 'Escape' && this._activeEditRows !== -1) {\n exitRowEdit(this, this._activeEditRows, true);\n }\n },\n { capture: true, signal },\n );\n\n // Click outside to commit row editing\n document.addEventListener(\n 'mousedown',\n (e: MouseEvent) => {\n if (this._activeEditRows === -1) return;\n const rowEl = this.findRenderedRowElement(this._activeEditRows);\n if (!rowEl) return;\n const path = (e.composedPath && e.composedPath()) || [];\n if (path.includes(rowEl)) return;\n exitRowEdit(this, this._activeEditRows, false);\n },\n { signal },\n );\n\n // Faux scrollbar pattern: scroll events come from the fake scrollbar element\n // Content area doesn't scroll - rows are positioned via transforms\n // This prevents blank viewport: old content stays until transforms are updated\n // Reuse gridRoot from earlier in this function\n const fauxScrollbar = gridRoot?.querySelector('.faux-vscroll') as HTMLElement;\n const rowsEl = gridRoot?.querySelector('.rows') as HTMLElement;\n\n // Store reference for scroll position reading in refreshVirtualWindow\n this._virtualization.container = fauxScrollbar ?? this;\n\n // Cache whether any plugin has scroll handlers (checked once during setup)\n this.#hasScrollPlugins = this.#pluginManager?.getAll().some((p) => p.onScroll) ?? false;\n\n if (fauxScrollbar && rowsEl) {\n fauxScrollbar.addEventListener(\n 'scroll',\n () => {\n // Fast exit if no scroll processing needed\n if (!this._virtualization.enabled && !this.#hasScrollPlugins) return;\n\n const currentScrollTop = fauxScrollbar.scrollTop;\n const rowHeight = this._virtualization.rowHeight;\n\n // Smooth scroll: apply offset immediately for fluid motion\n // Calculate even-aligned start to preserve zebra stripe parity\n // DOM nth-child(even) will always match data row parity\n const rawStart = Math.floor(currentScrollTop / rowHeight);\n const evenAlignedStart = rawStart - (rawStart % 2);\n const subPixelOffset = -(currentScrollTop - evenAlignedStart * rowHeight);\n rowsEl.style.transform = `translateY(${subPixelOffset}px)`;\n\n // Batch content update with requestAnimationFrame\n // Old content stays visible with smooth offset until new content renders\n this.#pendingScrollTop = currentScrollTop;\n if (!this.#scrollRaf) {\n this.#scrollRaf = requestAnimationFrame(() => {\n this.#scrollRaf = 0;\n if (this.#pendingScrollTop !== null) {\n this.#onScrollBatched(this.#pendingScrollTop);\n this.#pendingScrollTop = null;\n }\n });\n }\n },\n { passive: true, signal },\n );\n\n // Forward wheel events from content area to faux scrollbar\n // Without this, mouse wheel over content wouldn't scroll\n // Listen on .tbw-grid-content to capture wheel events from entire grid area\n // Note: gridRoot may already BE .tbw-grid-content when shell is active, so search from shadow root\n const gridContentEl = this.#shadow.querySelector('.tbw-grid-content') as HTMLElement;\n const scrollArea = this.#shadow.querySelector('.tbw-scroll-area') as HTMLElement;\n if (gridContentEl) {\n gridContentEl.addEventListener(\n 'wheel',\n (e: WheelEvent) => {\n // SHIFT+wheel or trackpad deltaX = horizontal scroll\n const isHorizontal = e.shiftKey || Math.abs(e.deltaX) > Math.abs(e.deltaY);\n\n if (isHorizontal && scrollArea) {\n const delta = e.shiftKey ? e.deltaY : e.deltaX;\n const { scrollLeft, scrollWidth, clientWidth } = scrollArea;\n const canScroll = (delta > 0 && scrollLeft < scrollWidth - clientWidth) || (delta < 0 && scrollLeft > 0);\n if (canScroll) {\n e.preventDefault();\n scrollArea.scrollLeft += delta;\n }\n } else if (!isHorizontal) {\n const { scrollTop, scrollHeight, clientHeight } = fauxScrollbar;\n const canScroll =\n (e.deltaY > 0 && scrollTop < scrollHeight - clientHeight) || (e.deltaY < 0 && scrollTop > 0);\n if (canScroll) {\n e.preventDefault();\n fauxScrollbar.scrollTop += e.deltaY;\n }\n }\n // If can't scroll, event bubbles to scroll the page\n },\n { passive: false, signal },\n );\n\n // Touch scrolling support for mobile devices\n // Supports both vertical (via faux scrollbar) and horizontal (via scroll area) scrolling\n // Includes momentum scrolling for natural \"flick\" behavior\n gridContentEl.addEventListener(\n 'touchstart',\n (e: TouchEvent) => {\n if (e.touches.length === 1) {\n // Cancel any ongoing momentum animation\n if (this.#momentumRaf) {\n cancelAnimationFrame(this.#momentumRaf);\n this.#momentumRaf = 0;\n }\n\n this.#touchStartY = e.touches[0].clientY;\n this.#touchStartX = e.touches[0].clientX;\n this.#touchLastY = e.touches[0].clientY;\n this.#touchLastX = e.touches[0].clientX;\n this.#touchLastTime = performance.now();\n this.#touchScrollTop = fauxScrollbar.scrollTop;\n this.#touchScrollLeft = scrollArea?.scrollLeft ?? 0;\n this.#touchVelocityY = 0;\n this.#touchVelocityX = 0;\n }\n },\n { passive: true, signal },\n );\n\n gridContentEl.addEventListener(\n 'touchmove',\n (e: TouchEvent) => {\n if (\n e.touches.length === 1 &&\n this.#touchStartY !== null &&\n this.#touchStartX !== null &&\n this.#touchScrollTop !== null &&\n this.#touchScrollLeft !== null\n ) {\n const currentY = e.touches[0].clientY;\n const currentX = e.touches[0].clientX;\n const now = performance.now();\n\n const deltaY = this.#touchStartY - currentY;\n const deltaX = this.#touchStartX - currentX;\n\n // Calculate velocity for momentum scrolling\n if (this.#touchLastTime !== null && this.#touchLastY !== null && this.#touchLastX !== null) {\n const dt = now - this.#touchLastTime;\n if (dt > 0) {\n // Velocity in pixels per millisecond\n this.#touchVelocityY = (this.#touchLastY - currentY) / dt;\n this.#touchVelocityX = (this.#touchLastX - currentX) / dt;\n }\n }\n this.#touchLastY = currentY;\n this.#touchLastX = currentX;\n this.#touchLastTime = now;\n\n // Check if grid can scroll in the requested directions\n const { scrollTop, scrollHeight, clientHeight } = fauxScrollbar;\n const maxScrollY = scrollHeight - clientHeight;\n const canScrollVertically = (deltaY > 0 && scrollTop < maxScrollY) || (deltaY < 0 && scrollTop > 0);\n\n let canScrollHorizontally = false;\n if (scrollArea) {\n const { scrollLeft, scrollWidth, clientWidth } = scrollArea;\n const maxScrollX = scrollWidth - clientWidth;\n canScrollHorizontally = (deltaX > 0 && scrollLeft < maxScrollX) || (deltaX < 0 && scrollLeft > 0);\n }\n\n // Apply scroll if grid can scroll in that direction\n if (canScrollVertically) {\n fauxScrollbar.scrollTop = this.#touchScrollTop + deltaY;\n }\n if (canScrollHorizontally && scrollArea) {\n scrollArea.scrollLeft = this.#touchScrollLeft + deltaX;\n }\n\n // Only prevent page scroll when we actually scrolled the grid\n if (canScrollVertically || canScrollHorizontally) {\n e.preventDefault();\n }\n }\n },\n { passive: false, signal },\n );\n\n gridContentEl.addEventListener(\n 'touchend',\n () => {\n // Start momentum scrolling if there's significant velocity\n const minVelocity = 0.1; // pixels per ms threshold\n if (Math.abs(this.#touchVelocityY) > minVelocity || Math.abs(this.#touchVelocityX) > minVelocity) {\n this.#startMomentumScroll(fauxScrollbar, scrollArea);\n }\n\n this.#touchStartY = null;\n this.#touchStartX = null;\n this.#touchScrollTop = null;\n this.#touchScrollLeft = null;\n this.#touchLastY = null;\n this.#touchLastX = null;\n this.#touchLastTime = null;\n },\n { passive: true, signal },\n );\n }\n }\n\n // Central mouse event handling for plugins (uses signal for automatic cleanup)\n this.#shadow.addEventListener('mousedown', (e) => this.#handleMouseDown(e as MouseEvent), { signal });\n\n // Track global mousemove/mouseup for drag operations (uses signal for automatic cleanup)\n document.addEventListener('mousemove', (e: MouseEvent) => this.#handleMouseMove(e), { signal });\n document.addEventListener('mouseup', (e: MouseEvent) => this.#handleMouseUp(e), { signal });\n\n if (this._virtualization.enabled) {\n requestAnimationFrame(() => this.refreshVirtualWindow(true));\n }\n\n // Determine row height for virtualization:\n // 1. User-configured rowHeight in gridConfig takes precedence\n // 2. Otherwise, measure actual row height from DOM (respects CSS variable --tbw-row-height)\n const userRowHeight = this.#effectiveConfig.rowHeight;\n if (userRowHeight && userRowHeight > 0) {\n this._virtualization.rowHeight = userRowHeight;\n } else {\n // Measure after first render to pick up CSS-defined row height\n requestAnimationFrame(() => {\n const firstRow = this._bodyEl?.querySelector('.data-grid-row');\n if (firstRow) {\n const measuredHeight = (firstRow as HTMLElement).getBoundingClientRect().height;\n if (measuredHeight > 0) {\n this._virtualization.rowHeight = measuredHeight;\n this.refreshVirtualWindow(true);\n }\n }\n });\n }\n\n // Resize observer to refresh virtualization and maintain focus when viewport size changes\n if (this._virtualization.viewportEl) {\n this.#resizeObserver = new ResizeObserver(() => {\n // Debounce with RAF to avoid excessive recalculations\n if (!this.#scrollRaf) {\n this.#scrollRaf = requestAnimationFrame(() => {\n this.#scrollRaf = 0;\n this.refreshVirtualWindow(true);\n\n // Ensure focused cell remains visible after resize\n // (viewport size may have changed, pushing the focused cell out of view)\n ensureCellVisible(this as any);\n });\n }\n });\n this.#resizeObserver.observe(this._virtualization.viewportEl);\n }\n\n // Initialize ARIA selection state\n queueMicrotask(() => this.#updateAriaSelection());\n\n requestAnimationFrame(() => requestAnimationFrame(() => this.#readyResolve?.()));\n }\n\n // ---------------- Event Emitters ----------------\n #emit<D>(eventName: string, detail: D): void {\n this.dispatchEvent(new CustomEvent(eventName, { detail, bubbles: true, composed: true }));\n }\n\n _emitCellCommit(detail: CellCommitDetail<T>): void {\n this.#emit('cell-commit', detail);\n }\n\n _emitRowCommit(detail: RowCommitDetail<T>): void {\n this.#emit('row-commit', detail);\n }\n\n _emitSortChange(detail: SortChangeDetail): void {\n this.#emit('sort-change', detail);\n }\n\n _emitColumnResize(detail: ColumnResizeDetail): void {\n this.#emit('column-resize', detail);\n }\n\n _emitActivateCell(detail: ActivateCellDetail): void {\n this.#emit('activate-cell', detail);\n }\n\n /** Update ARIA selection attributes on rendered rows/cells */\n #updateAriaSelection(): void {\n // Mark active row and cell with aria-selected\n const rows = this._bodyEl?.querySelectorAll('.data-grid-row');\n rows?.forEach((row, rowIdx) => {\n const isActiveRow = rowIdx === this._focusRow;\n row.setAttribute('aria-selected', String(isActiveRow));\n row.querySelectorAll('.cell').forEach((cell, colIdx) => {\n (cell as HTMLElement).setAttribute('aria-selected', String(isActiveRow && colIdx === this._focusCol));\n });\n });\n }\n\n // ---------------- Watch Handlers ----------------\n #onFitChanged(): void {\n if (!this.#connected) return;\n this.#mergeEffectiveConfig();\n const mode = this.#effectiveConfig.fitMode;\n if (mode === 'fixed') {\n this.__didInitialAutoSize = false;\n autoSizeColumns(this);\n } else {\n this._columns.forEach((c: any) => {\n if (!c.__userResized && c.__autoSized) delete c.width;\n });\n updateTemplate(this);\n }\n }\n\n #onEditModeChanged(): void {\n if (!this.#connected) return;\n this.#mergeEffectiveConfig();\n this._rowPool.length = 0;\n if (this._bodyEl) this._bodyEl.innerHTML = '';\n this.__rowRenderEpoch++;\n this.refreshVirtualWindow(true);\n }\n\n #onRowsChanged(): void {\n this._rows = Array.isArray(this.#rows) ? [...this.#rows] : [];\n this.#rebuildRowModel();\n // If no explicit columns provided, trigger full setup so inference runs\n if (!this.#columns || (Array.isArray(this.#columns) && this.#columns.length === 0)) {\n this.#setup();\n } else {\n this.refreshVirtualWindow(true);\n }\n }\n\n #onColsChanged(): void {\n // Invalidate caches that depend on column configuration\n invalidateCellCache(this);\n\n // Re-merge config and setup - _columns will be set through effectiveConfig\n if (this.#connected) {\n this.#mergeEffectiveConfig();\n this.#setup();\n }\n }\n\n #onGridConfigChanged(): void {\n if (!this.#connected) return;\n this.#mergeEffectiveConfig();\n this.#updatePluginConfigs(); // Sync plugin configs with new grid config\n this.#rebuildRowModel();\n this.#processColumns(); // Process columns after rows for tree plugin\n renderHeader(this);\n updateTemplate(this);\n this.refreshVirtualWindow(true);\n }\n\n #processColumns(): void {\n // Let plugins process visible columns (column grouping, etc.)\n // Start from base columns (before any plugin transformation) - like #rebuildRowModel uses #rows\n if (this.#pluginManager) {\n // Use base columns as source of truth, falling back to current _columns if not set\n const sourceColumns = this.#baseColumns.length > 0 ? this.#baseColumns : this._columns;\n const visibleCols = sourceColumns.filter((c) => !c.hidden);\n const hiddenCols = sourceColumns.filter((c) => c.hidden);\n const processedColumns = this.#pluginManager.processColumns([...visibleCols] as any[]);\n\n // If plugins modified visible columns, update them\n if (processedColumns !== visibleCols) {\n // Build a map of processed columns by field for quick lookup\n const processedMap = new Map(processedColumns.map((c: any, i: number) => [c.field, { col: c, order: i }]));\n\n // Check if this is a complete column replacement (e.g., pivot mode)\n // If no processed columns match original columns, use processed columns directly\n const hasMatchingFields = visibleCols.some((c) => processedMap.has(c.field));\n\n if (!hasMatchingFields && processedColumns.length > 0) {\n // Complete replacement: use processed columns directly (pivot mode)\n // Preserve hidden columns at the end\n this._columns = [...processedColumns, ...hiddenCols] as ColumnInternal<T>[];\n } else {\n // Plugins returned original fields (possibly modified) - merge back\n // Use source columns as base, not current _columns\n const updatedColumns = sourceColumns.map((c) => {\n if (c.hidden) return c; // Keep hidden columns unchanged\n const processed = processedMap.get(c.field);\n return processed ? processed.col : c;\n });\n\n this._columns = updatedColumns as ColumnInternal<T>[];\n }\n } else {\n // Plugins returned columns unchanged, but we may need to restore from base\n this._columns = [...sourceColumns] as ColumnInternal<T>[];\n }\n }\n }\n\n /** Recompute row model via plugin hooks (grouping, tree, filtering, etc.). */\n #rebuildRowModel(): void {\n // Invalidate cell display value cache - rows are changing\n invalidateCellCache(this);\n\n // Start fresh from original rows (plugins will transform them)\n const originalRows = Array.isArray(this.#rows) ? [...this.#rows] : [];\n\n // Let plugins process rows (row grouping, tree, filtering, etc.)\n // Plugins can transform the rows array, adding markers like __isGroupRow\n // The renderRow hook will handle rendering specialized row types\n const processedRows = this.#pluginManager?.processRows(originalRows) ?? originalRows;\n\n // Store processed rows for rendering\n // Note: processedRows may contain group markers that plugins handle via renderRow hook\n this._rows = processedRows as T[];\n }\n\n /**\n * Build the canonical effective configuration by merging all input sources.\n *\n * This is the **single source of truth** for the grid's configuration.\n * All inputs (gridConfig, light DOM, individual props) converge here.\n *\n * **Precedence (lowest → highest):**\n * 1. `gridConfig` property - base config object\n * 2. Light DOM `<tbw-grid-column>` elements - declarative columns\n * 3. `columns` property - programmatic columns override\n * 4. Inferred columns - auto-detected from row data\n * 5. Individual props (`fitMode`, `editOn`) - convenience overrides\n *\n * After this method runs:\n * - `#effectiveConfig` contains the merged result\n * - `_columns` is NOT set here (done by #getColumnConfiguration + #processColumns)\n * - Plugins receive config via their attach() method\n */\n #mergeEffectiveConfig(): void {\n const base: GridConfig<T> = this.#gridConfig ? { ...this.#gridConfig } : {};\n let columns: ColumnConfig<T>[] = Array.isArray(base.columns) ? [...base.columns] : [];\n\n // Light DOM cached parse (if already parsed by columns pipeline); non-invasive merge (fill gaps only)\n const domCols: ColumnConfig<T>[] = ((this as any).__lightDomColumnsCache || []).map((c: ColumnConfig<T>) => ({\n ...c,\n }));\n if (domCols.length) {\n const map: Record<string, ColumnConfig<T>> = {};\n columns.forEach((c) => (map[(c as any).field] = c));\n domCols.forEach((c: any) => {\n const exist = map[c.field];\n if (!exist) {\n columns.push(c);\n map[c.field] = c;\n } else {\n if (c.header && !exist.header) exist.header = c.header;\n if (c.type && !exist.type) exist.type = c.type;\n exist.sortable = exist.sortable || c.sortable;\n if (c.resizable) exist.resizable = true;\n if (c.editable) exist.editable = true;\n }\n });\n }\n\n // Columns prop highest structural precedence\n if (this.#columns && (this.#columns as ColumnConfig<T>[]).length) {\n columns = [...(this.#columns as ColumnConfig<T>[])];\n }\n\n // Inference if still empty\n if ((!columns || columns.length === 0) && this._rows.length) {\n const result = inferColumns(this._rows as Record<string, unknown>[]);\n columns = result.columns as ColumnConfig<T>[];\n }\n\n if (columns.length) {\n // Apply per-column defaults (sortable/resizable default true unless explicitly false)\n columns.forEach((c) => {\n if (c.sortable === undefined) c.sortable = true;\n if (c.resizable === undefined) c.resizable = true;\n // Store original configured width for reset on double-click (only numeric widths)\n const internal = c as ColumnInternal<T>;\n if (internal.__originalWidth === undefined && typeof c.width === 'number') {\n internal.__originalWidth = c.width;\n }\n });\n // Preserve processed columns (with __compiledView etc.) if already set by #getColumnConfiguration\n // Only set base.columns if effectiveConfig.columns is empty or doesn't have compiled templates\n const existingCols = this.#effectiveConfig.columns as ColumnInternal<T>[] | undefined;\n const alreadyProcessed = existingCols?.some((c) => c.__compiledView || c.__compiledEditor);\n if (alreadyProcessed) {\n // Keep existing processed columns\n base.columns = existingCols as ColumnConfig<T>[];\n } else {\n base.columns = columns;\n }\n } else {\n // No new columns computed, but preserve existing if processed\n const existingCols = this.#effectiveConfig.columns as ColumnInternal<T>[] | undefined;\n if (existingCols?.some((c) => c.__compiledView || c.__compiledEditor)) {\n base.columns = existingCols as ColumnConfig<T>[];\n }\n }\n\n // Individual prop overrides (behavioral)\n if (this.#fitMode) base.fitMode = this.#fitMode;\n if (!base.fitMode) base.fitMode = 'stretch';\n if (this.#editOn) base.editOn = this.#editOn;\n\n // Apply rowHeight from config if specified\n if (base.rowHeight && base.rowHeight > 0) {\n this._virtualization.rowHeight = base.rowHeight;\n }\n\n // Store columnState from gridConfig if not already set\n if (base.columnState && !this.#initialColumnState) {\n this.#initialColumnState = base.columnState;\n }\n\n this.#effectiveConfig = base;\n // Note: _columns is a getter/setter for effectiveConfig.columns\n // #getColumnConfiguration() populates it, and we preserve those processed columns above\n // Plugins (like ReorderPlugin) modify effectiveConfig.columns via the _columns setter\n\n // If fixed mode and width not specified: assign default 80px\n if (base.fitMode === 'fixed') {\n this._columns.forEach((c) => {\n if (c.width == null) (c as ColumnConfig<T>).width = 80;\n });\n }\n }\n\n // ---------------- Delegate Wrappers ----------------\n #renderVisibleRows(start: number, end: number, epoch = this.__rowRenderEpoch): void {\n // Use cached hook to avoid creating closures on every render (hot path optimization)\n if (!this.#renderRowHook) {\n this.#renderRowHook = (row: any, rowEl: HTMLElement, rowIndex: number): boolean => {\n return this.#pluginManager?.renderRow(row, rowEl, rowIndex) ?? false;\n };\n }\n renderVisibleRows(this as any, start, end, epoch, this.#renderRowHook);\n }\n\n // ---------------- Core Helpers ----------------\n #setup(): void {\n if (!this.isConnected) return;\n if (!this._headerRowEl || !this._bodyEl) {\n return;\n }\n\n // Seed effectiveConfig.columns from config sources before getColumnConfiguration\n // This ensures columns from gridConfig/columns prop are available for merging with light DOM\n // Preserve hidden state from existing columns (visibility is runtime state)\n const configCols = (this.#gridConfig?.columns || this.#columns || []) as ColumnConfig<T>[];\n if (configCols.length) {\n // Preserve hidden state from existing effectiveConfig.columns\n const existingHiddenMap = new Map(this._columns.filter((c) => c.hidden).map((c) => [c.field, true]));\n const seeded = configCols.map((c) => ({\n ...c,\n hidden: existingHiddenMap.get(c.field) ?? c.hidden,\n }));\n this._columns = seeded as ColumnInternal<T>[];\n }\n\n getColumnConfiguration(this);\n this.#mergeEffectiveConfig();\n this.#updatePluginConfigs(); // Sync plugin configs (including auto-detection) before processing\n\n // Store base columns before plugin transformation (like #rows for row processing)\n this.#baseColumns = [...this._columns];\n\n this.#rebuildRowModel(); // Runs processRows hooks (must run before processColumns for tree plugin)\n this.#processColumns(); // Runs processColumns hooks\n\n // Apply initial column state (from gridConfig.columnState or columnState setter)\n if (this.#initialColumnState) {\n const state = this.#initialColumnState;\n this.#initialColumnState = undefined; // Clear to avoid re-applying\n this.#applyColumnStateInternal(state);\n }\n\n renderHeader(this);\n updateTemplate(this);\n this.refreshVirtualWindow(true);\n\n const mode = this.#effectiveConfig.fitMode;\n if (mode === 'fixed' && !this.__didInitialAutoSize) {\n requestAnimationFrame(() => autoSizeColumns(this));\n }\n\n // Ensure legacy inline grid styles are cleared from container\n if (this._bodyEl) {\n this._bodyEl.style.display = '';\n this._bodyEl.style.gridTemplateColumns = '';\n }\n\n // Run plugin afterRender hooks (column groups, sticky, etc.)\n queueMicrotask(() => this.#pluginManager?.afterRender());\n }\n\n /** Internal method to apply column state without triggering setup loop */\n #applyColumnStateInternal(state: GridColumnState): void {\n // Get all columns from effectiveConfig (single source of truth)\n const allCols = (this.#effectiveConfig.columns ?? []) as ColumnInternal<T>[];\n\n const plugins = (this.#pluginManager?.getAll() ?? []) as BaseGridPlugin[];\n applyColumnState(this, state, allCols, plugins);\n\n // Update hidden property on columns based on state\n for (const colState of state.columns) {\n const col = allCols.find((c) => c.field === colState.field);\n if (col) {\n col.hidden = !colState.visible;\n }\n }\n }\n\n #onScrollBatched(scrollTop: number): void {\n // Faux scrollbar pattern: content never scrolls, just update transforms\n // Old content stays visible until new transforms are applied\n this.refreshVirtualWindow(false);\n\n // Let plugins reapply visual state to recycled DOM elements\n this.#pluginManager?.onScrollRender();\n\n // Dispatch to plugins (using cached flag)\n if (this.#hasScrollPlugins) {\n const fauxScrollbar = this._virtualization.container;\n const scrollEvent: ScrollEvent = {\n scrollTop,\n scrollLeft: fauxScrollbar?.scrollLeft ?? 0,\n scrollHeight: fauxScrollbar?.scrollHeight ?? 0,\n scrollWidth: fauxScrollbar?.scrollWidth ?? 0,\n clientHeight: fauxScrollbar?.clientHeight ?? 0,\n clientWidth: fauxScrollbar?.clientWidth ?? 0,\n originalEvent: new Event('scroll'),\n };\n this.#pluginManager?.onScroll(scrollEvent);\n }\n }\n\n /**\n * Find the header row element in the shadow DOM.\n * Used by plugins that need to access header cells for styling or measurement.\n * @internal Plugin API\n */\n findHeaderRow(): HTMLElement {\n return this.#shadow.querySelector('.header-row') as HTMLElement;\n }\n\n /**\n * Find a rendered row element by its data row index.\n * Returns null if the row is not currently rendered (virtualized out of view).\n * Used by plugins that need to access specific row elements for styling or measurement.\n * @internal Plugin API\n * @param rowIndex - The data row index (not the DOM position)\n */\n findRenderedRowElement(rowIndex: number): HTMLElement | null {\n return (\n (Array.from(this._bodyEl.querySelectorAll('.data-grid-row')) as HTMLElement[]).find((r) => {\n const cell = r.querySelector('.cell[data-row]');\n return cell && Number(cell.getAttribute('data-row')) === rowIndex;\n }) || null\n );\n }\n\n /**\n * Dispatch a cell click event to the plugin system.\n * Returns true if any plugin handled the event.\n */\n _dispatchCellClick(event: MouseEvent, rowIndex: number, colIndex: number, cellEl: HTMLElement): boolean {\n const row = this._rows[rowIndex];\n const col = this._columns[colIndex];\n if (!row || !col) return false;\n\n const cellClickEvent: CellClickEvent = {\n row,\n rowIndex,\n colIndex,\n field: col.field,\n value: (row as any)[col.field],\n cellEl,\n originalEvent: event,\n };\n\n return this.#pluginManager?.onCellClick(cellClickEvent) ?? false;\n }\n\n /**\n * Dispatch a row click event to the plugin system.\n * Returns true if any plugin handled the event.\n */\n _dispatchRowClick(event: MouseEvent, rowIndex: number, row: any, rowEl: HTMLElement): boolean {\n if (!row) return false;\n\n const rowClickEvent: RowClickEvent = {\n rowIndex,\n row,\n rowEl,\n originalEvent: event,\n };\n\n return this.#pluginManager?.onRowClick(rowClickEvent) ?? false;\n }\n\n /**\n * Dispatch a header click event to the plugin system.\n * Returns true if any plugin handled the event.\n */\n _dispatchHeaderClick(event: MouseEvent, colIndex: number, headerEl: HTMLElement): boolean {\n const col = this._columns[colIndex];\n if (!col) return false;\n\n const headerClickEvent: HeaderClickEvent = {\n colIndex,\n field: col.field,\n column: col,\n headerEl,\n originalEvent: event,\n };\n\n return this.#pluginManager?.onHeaderClick(headerClickEvent) ?? false;\n }\n\n /**\n * Dispatch a keyboard event to the plugin system.\n * Returns true if any plugin handled the event.\n */\n _dispatchKeyDown(event: KeyboardEvent): boolean {\n return this.#pluginManager?.onKeyDown(event) ?? false;\n }\n\n /**\n * Get horizontal scroll boundary offsets from plugins.\n * Used by keyboard navigation to ensure focused cells are fully visible\n * when plugins like pinned columns obscure part of the scroll area.\n */\n _getHorizontalScrollOffsets(\n rowEl?: HTMLElement,\n focusedCell?: HTMLElement,\n ): { left: number; right: number; skipScroll?: boolean } {\n return this.#pluginManager?.getHorizontalScrollOffsets(rowEl, focusedCell) ?? { left: 0, right: 0 };\n }\n\n /**\n * Query all plugins with a generic query and collect responses.\n * This enables inter-plugin communication without the core knowing plugin-specific concepts.\n * @internal Plugin API\n *\n * @example\n * // Check if any plugin vetoes moving a column\n * const responses = grid.queryPlugins<boolean>({ type: PLUGIN_QUERIES.CAN_MOVE_COLUMN, context: column });\n * const canMove = !responses.includes(false);\n */\n queryPlugins<T>(query: PluginQuery): T[] {\n return this.#pluginManager?.queryPlugins<T>(query) ?? [];\n }\n\n /**\n * Build a CellMouseEvent from a native MouseEvent.\n * Extracts cell/row information from the event target.\n */\n #buildCellMouseEvent(e: MouseEvent, type: 'mousedown' | 'mousemove' | 'mouseup'): CellMouseEvent {\n // For document-level events (mousemove/mouseup during drag), e.target won't be inside shadow DOM.\n // Use composedPath to find elements inside shadow roots, or fall back to elementFromPoint.\n let target: Element | null = null;\n\n // composedPath gives us the full path including shadow DOM elements\n const path = e.composedPath?.() as Element[] | undefined;\n if (path && path.length > 0) {\n target = path[0];\n } else {\n target = e.target as Element;\n }\n\n // If target is still not inside our shadow root (e.g., for document-level events),\n // use elementFromPoint to find the actual element under the mouse\n if (target && !this.#shadow.contains(target)) {\n const elAtPoint = this.#shadow.elementFromPoint(e.clientX, e.clientY);\n if (elAtPoint) {\n target = elAtPoint;\n }\n }\n\n // Cells have data-col and data-row attributes\n const cellEl = target?.closest?.('[data-col]') as HTMLElement | null;\n const rowEl = target?.closest?.('.data-grid-row') as HTMLElement | null;\n const headerEl = target?.closest?.('.header-row') as HTMLElement | null;\n\n let rowIndex: number | undefined;\n let colIndex: number | undefined;\n let row: T | undefined;\n let field: string | undefined;\n let value: unknown;\n let column: any;\n\n if (cellEl) {\n // Get indices from cell attributes\n rowIndex = parseInt(cellEl.getAttribute('data-row') ?? '-1', 10);\n colIndex = parseInt(cellEl.getAttribute('data-col') ?? '-1', 10);\n if (rowIndex >= 0 && colIndex >= 0) {\n row = this._rows[rowIndex];\n column = this._columns[colIndex];\n field = column?.field;\n value = row && field ? (row as any)[field] : undefined;\n }\n }\n\n return {\n type,\n row,\n rowIndex: rowIndex !== undefined && rowIndex >= 0 ? rowIndex : undefined,\n colIndex: colIndex !== undefined && colIndex >= 0 ? colIndex : undefined,\n field,\n value,\n column,\n originalEvent: e,\n cellElement: cellEl ?? undefined,\n rowElement: rowEl ?? undefined,\n isHeader: !!headerEl,\n cell:\n rowIndex !== undefined && colIndex !== undefined && rowIndex >= 0 && colIndex >= 0\n ? { row: rowIndex, col: colIndex }\n : undefined,\n };\n }\n\n /**\n * Apply momentum scrolling animation after touch release.\n * Decelerates smoothly until velocity drops below threshold.\n */\n #startMomentumScroll(fauxScrollbar: HTMLElement, scrollArea: HTMLElement | null): void {\n const friction = 0.95; // Deceleration factor per frame\n const minVelocity = 0.01; // Stop threshold in px/ms\n\n const animate = () => {\n // Apply friction\n this.#touchVelocityY *= friction;\n this.#touchVelocityX *= friction;\n\n // Convert velocity (px/ms) to per-frame scroll amount (~16ms per frame)\n const scrollY = this.#touchVelocityY * 16;\n const scrollX = this.#touchVelocityX * 16;\n\n // Apply scroll if above threshold\n if (Math.abs(this.#touchVelocityY) > minVelocity) {\n fauxScrollbar.scrollTop += scrollY;\n }\n if (Math.abs(this.#touchVelocityX) > minVelocity && scrollArea) {\n scrollArea.scrollLeft += scrollX;\n }\n\n // Continue animation if still moving\n if (Math.abs(this.#touchVelocityY) > minVelocity || Math.abs(this.#touchVelocityX) > minVelocity) {\n this.#momentumRaf = requestAnimationFrame(animate);\n } else {\n this.#momentumRaf = 0;\n }\n };\n\n this.#momentumRaf = requestAnimationFrame(animate);\n }\n\n /**\n * Handle mousedown events and dispatch to plugin system.\n */\n #handleMouseDown(e: MouseEvent): void {\n const event = this.#buildCellMouseEvent(e, 'mousedown');\n const handled = this.#pluginManager?.onCellMouseDown(event) ?? false;\n\n // If any plugin handled mousedown, start tracking for drag\n if (handled) {\n this.#isDragging = true;\n }\n }\n\n /**\n * Handle mousemove events (only when dragging).\n */\n #handleMouseMove(e: MouseEvent): void {\n if (!this.#isDragging) return;\n\n const event = this.#buildCellMouseEvent(e, 'mousemove');\n this.#pluginManager?.onCellMouseMove(event);\n }\n\n /**\n * Handle mouseup events.\n */\n #handleMouseUp(e: MouseEvent): void {\n if (!this.#isDragging) return;\n\n const event = this.#buildCellMouseEvent(e, 'mouseup');\n this.#pluginManager?.onCellMouseUp(event);\n this.#isDragging = false;\n }\n\n // API consumed by internal utils (rows.ts)\n get changedRows(): T[] {\n return Array.from(this._changedRowIndices).map((i) => this._rows[i]);\n }\n\n get changedRowIndices(): number[] {\n return Array.from(this._changedRowIndices);\n }\n\n async resetChangedRows(silent?: boolean): Promise<void> {\n this._changedRowIndices.clear();\n if (!silent) {\n this.#emit('changed-rows-reset', { rows: this.changedRows, indices: this.changedRowIndices });\n }\n this._rowPool.forEach((r) => r.classList.remove('changed'));\n }\n\n async beginBulkEdit(rowIndex: number): Promise<void> {\n // Check if any columns are editable - if not, skip edit mode entirely\n const hasEditableColumn = this._columns.some((col) => (col as ColumnInternal<T>).editable);\n if (!hasEditableColumn) return;\n\n const rowData = this._rows[rowIndex];\n startRowEdit(this, rowIndex, rowData);\n\n // Enter edit mode on all editable cells in the row (same as click/dblclick)\n const rowEl = this.findRenderedRowElement?.(rowIndex);\n if (rowEl) {\n Array.from(rowEl.children).forEach((cell, i) => {\n // Use visibleColumns to match the cell index - _columns may include hidden columns\n const col = this._visibleColumns[i] as ColumnInternal<T> | undefined;\n if (col?.editable) {\n const cellEl = cell as HTMLElement;\n if (!cellEl.classList.contains('editing')) {\n inlineEnterEdit(this as unknown as InternalGrid, rowData, rowIndex, col, cellEl);\n }\n }\n });\n\n // Focus the editor in the focused cell\n queueMicrotask(() => {\n const targetCell = rowEl.querySelector(`.cell[data-col=\"${this._focusCol}\"]`);\n if (targetCell?.classList.contains('editing')) {\n const editor = (targetCell as HTMLElement).querySelector(\n 'input,select,textarea,[contenteditable=\"true\"],[contenteditable=\"\"],[tabindex]:not([tabindex=\"-1\"])',\n ) as HTMLElement | null;\n try {\n editor?.focus();\n } catch {\n /* empty */\n }\n }\n });\n }\n }\n\n async commitActiveRowEdit(): Promise<void> {\n if (this._activeEditRows !== -1) {\n exitRowEdit(this, this._activeEditRows, false);\n }\n }\n\n async ready(): Promise<void> {\n return this.#readyPromise;\n }\n\n async forceLayout(): Promise<void> {\n this.#setup();\n await new Promise((r) => requestAnimationFrame(() => requestAnimationFrame(r)));\n }\n\n /** Public method: returns a frozen snapshot of the merged effective configuration */\n async getConfig(): Promise<Readonly<GridConfig<T>>> {\n return Object.freeze({ ...(this.#effectiveConfig || {}) });\n }\n\n // ---------------- Column Visibility API ----------------\n\n /**\n * Set the visibility of a column.\n * @param field - The field name of the column\n * @param visible - Whether the column should be visible\n * @returns True if visibility was changed, false if column not found or locked\n */\n setColumnVisible(field: string, visible: boolean): boolean {\n // Find the column in effectiveConfig.columns (includes hidden columns)\n const allCols = this.#effectiveConfig.columns as ColumnInternal<T>[] | undefined;\n const col = allCols?.find((c) => c.field === field);\n\n // If column not found, cannot change visibility\n if (!col) return false;\n\n // Check lockVisible - cannot hide locked columns\n if (!visible && col.lockVisible) return false;\n\n // Check if at least one column would remain visible\n if (!visible) {\n const currentVisible = (allCols ?? []).filter((c) => !c.hidden && c.field !== field).length;\n if (currentVisible === 0) return false;\n }\n\n const wasHidden = !!col.hidden;\n const willBeHidden = !visible;\n\n // Only refresh if visibility actually changed\n if (wasHidden !== willBeHidden) {\n // Update the hidden property on the column in effectiveConfig\n col.hidden = willBeHidden;\n\n // Emit event for consumer preference saving\n this.#emit('column-visibility', {\n field,\n visible,\n visibleColumns: (allCols ?? []).filter((c) => !c.hidden).map((c) => c.field),\n });\n\n // Clear row pool to force complete rebuild with new column count\n this._rowPool.length = 0;\n if (this._bodyEl) this._bodyEl.innerHTML = '';\n this.__rowRenderEpoch++;\n\n // Re-setup to rebuild columns with updated visibility\n this.#setup();\n\n // Trigger state change after visibility change\n this.requestStateChange();\n return true;\n }\n return false;\n }\n\n /**\n * Toggle the visibility of a column.\n * @param field - The field name of the column\n * @returns True if visibility was toggled, false if column not found or locked\n */\n toggleColumnVisibility(field: string): boolean {\n const allCols = this.#effectiveConfig.columns as ColumnInternal<T>[] | undefined;\n const col = allCols?.find((c) => c.field === field);\n const isCurrentlyHidden = !!col?.hidden;\n return this.setColumnVisible(field, isCurrentlyHidden);\n }\n\n /**\n * Check if a column is currently visible.\n * @param field - The field name of the column\n * @returns True if visible, false if hidden or not found\n */\n isColumnVisible(field: string): boolean {\n const allCols = this.#effectiveConfig.columns as ColumnInternal<T>[] | undefined;\n const col = allCols?.find((c) => c.field === field);\n return col ? !col.hidden : false;\n }\n\n /**\n * Show all columns.\n */\n showAllColumns(): void {\n const allCols = this.#effectiveConfig.columns as ColumnInternal<T>[] | undefined;\n const hasHidden = allCols?.some((c) => c.hidden);\n if (!hasHidden) return;\n\n // Clear hidden flag on all columns\n allCols?.forEach((c) => {\n c.hidden = false;\n });\n\n this.#emit('column-visibility', {\n visibleColumns: (allCols ?? []).map((c) => c.field),\n });\n\n // Clear row pool to force complete rebuild with new column count\n this._rowPool.length = 0;\n if (this._bodyEl) this._bodyEl.innerHTML = '';\n this.__rowRenderEpoch++;\n\n this.#setup();\n\n // Trigger state change after visibility change\n this.requestStateChange();\n }\n\n /**\n * Get list of all column fields (including hidden).\n * Returns columns reflecting current display order (after reordering).\n * Hidden columns are interleaved at their original relative positions.\n * @returns Array of all field names with their visibility status\n */\n getAllColumns(): Array<{ field: string; header: string; visible: boolean; lockVisible?: boolean }> {\n // effectiveConfig.columns is the single source of truth\n const allCols = (this.#effectiveConfig.columns ?? []) as ColumnInternal<T>[];\n\n // Return all columns with their current visibility state\n return allCols.map((c) => ({\n field: c.field,\n header: c.header || c.field,\n visible: !c.hidden,\n lockVisible: c.lockVisible,\n }));\n }\n\n /**\n * Reorder columns according to the specified field order.\n * This directly updates _columns in place without going through processColumns.\n * @param order - Array of field names in the desired order\n */\n setColumnOrder(order: string[]): void {\n if (!order.length) return;\n\n const columnMap = new Map<string, ColumnInternal<T>>(this._columns.map((c) => [c.field as string, c]));\n const reordered: ColumnInternal<T>[] = [];\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 this._columns = reordered;\n\n // Re-render with new order\n renderHeader(this);\n updateTemplate(this);\n this.refreshVirtualWindow(true);\n }\n\n /**\n * Get the current column order as an array of field names.\n * @returns Array of field names in display order\n */\n getColumnOrder(): string[] {\n return this._columns.map((c) => c.field);\n }\n\n // ---------------- Column State API ----------------\n\n /**\n * Get the current column state, including order, width, visibility, sort, and plugin state.\n * Returns a serializable object suitable for localStorage or database storage.\n */\n getColumnState(): GridColumnState {\n const plugins = this.#pluginManager?.getAll() ?? [];\n return collectColumnState(this, plugins as BaseGridPlugin[]);\n }\n\n /**\n * Set the column state, restoring order, width, visibility, sort, and plugin state.\n * Use this to restore previously saved column state.\n */\n set columnState(state: GridColumnState | undefined) {\n if (!state) return;\n\n // Store for use after initialization if called before ready\n this.#initialColumnState = state;\n\n // If already initialized, apply immediately\n if (this.#initialized) {\n this.#applyColumnState(state);\n }\n }\n\n /**\n * Get the current column state.\n */\n get columnState(): GridColumnState | undefined {\n return this.getColumnState();\n }\n\n /**\n * Apply column state internally.\n */\n #applyColumnState(state: GridColumnState): void {\n // Clear hidden flags before applying state\n const allCols = (this.#effectiveConfig.columns ?? []) as ColumnInternal<T>[];\n allCols.forEach((c) => {\n c.hidden = false;\n });\n\n this.#applyColumnStateInternal(state);\n\n // Re-setup to apply changes\n this.#setup();\n }\n\n /**\n * Request a state change event to be emitted.\n * Called internally after resize, reorder, visibility, or sort changes.\n * Plugins should call this after changing their state.\n * The event is debounced to avoid excessive events during drag operations.\n * @internal Plugin API\n */\n requestStateChange(): void {\n if (!this.#stateChangeHandler) {\n this.#stateChangeHandler = createStateChangeHandler(\n this,\n () => (this.#pluginManager?.getAll() ?? []) as BaseGridPlugin[],\n (state) => this.#emit('column-state-change', state),\n );\n }\n this.#stateChangeHandler();\n }\n\n /**\n * Reset column state to initial configuration.\n * Clears all user modifications (order, width, visibility, sort).\n */\n resetColumnState(): void {\n // Clear initial state\n this.#initialColumnState = undefined;\n\n // Clear hidden flag on all columns\n const allCols = (this.#effectiveConfig.columns ?? []) as ColumnInternal<T>[];\n allCols.forEach((c) => {\n c.hidden = false;\n });\n\n // Reset sort state\n this._sortState = null;\n this.__originalOrder = [];\n\n // Re-initialize columns from config\n this.#mergeEffectiveConfig();\n this.#setup();\n\n // Notify plugins to reset their state\n const plugins = (this.#pluginManager?.getAll() ?? []) as BaseGridPlugin[];\n for (const plugin of plugins) {\n if (plugin.applyColumnState) {\n // Pass empty state to indicate reset\n for (const col of this._columns) {\n plugin.applyColumnState(col.field, {\n field: col.field,\n order: 0,\n visible: true,\n });\n }\n }\n }\n\n // Emit state change\n this.requestStateChange();\n }\n\n // ---------------- Shell / Tool Panel API ----------------\n // These methods delegate to ShellController for implementation.\n // The controller encapsulates all tool panel logic while grid.ts\n // exposes the public API surface.\n\n /** Check if the tool panel is currently open. */\n get isToolPanelOpen(): boolean {\n return this.#shellController.isPanelOpen;\n }\n\n /**\n * Get the currently active tool panel ID, or null if none is open.\n * @deprecated Use isToolPanelOpen and expandedToolPanelSections instead.\n */\n get activeToolPanel(): string | null {\n return this.#shellController.activePanel;\n }\n\n /** Get the IDs of expanded accordion sections. */\n get expandedToolPanelSections(): string[] {\n return this.#shellController.expandedSections;\n }\n\n /** Open the tool panel (accordion view with all registered panels). */\n openToolPanel(): void {\n this.#shellController.openToolPanel();\n }\n\n /** Close the tool panel. */\n closeToolPanel(): void {\n this.#shellController.closeToolPanel();\n }\n\n /** Toggle the tool panel open/closed. */\n toggleToolPanel(): void {\n this.#shellController.toggleToolPanel();\n }\n\n /** Toggle an accordion section expanded/collapsed. */\n toggleToolPanelSection(sectionId: string): void {\n this.#shellController.toggleToolPanelSection(sectionId);\n }\n\n /** Get registered tool panel definitions. */\n getToolPanels(): ToolPanelDefinition[] {\n return this.#shellController.getToolPanels();\n }\n\n /** Register a custom tool panel (without creating a plugin). */\n registerToolPanel(panel: ToolPanelDefinition): void {\n this.#shellController.registerToolPanel(panel);\n }\n\n /** Unregister a custom tool panel. */\n unregisterToolPanel(panelId: string): void {\n this.#shellController.unregisterToolPanel(panelId);\n }\n\n /** Get registered header content definitions. */\n getHeaderContents(): HeaderContentDefinition[] {\n return this.#shellController.getHeaderContents();\n }\n\n /** Register custom header content (without creating a plugin). */\n registerHeaderContent(content: HeaderContentDefinition): void {\n this.#shellController.registerHeaderContent(content);\n }\n\n /** Unregister custom header content. */\n unregisterHeaderContent(contentId: string): void {\n this.#shellController.unregisterHeaderContent(contentId);\n }\n\n /** Get all registered toolbar buttons. */\n getToolbarButtons(): ToolbarButtonInfo[] {\n return this.#shellController.getToolbarButtons();\n }\n\n /** Register a custom toolbar button programmatically. */\n registerToolbarButton(button: ToolbarButtonConfig): void {\n this.#shellController.registerToolbarButton(button);\n }\n\n /** Unregister a custom toolbar button. */\n unregisterToolbarButton(buttonId: string): void {\n this.#shellController.unregisterToolbarButton(buttonId);\n }\n\n /** Enable/disable a toolbar button by ID. */\n setToolbarButtonDisabled(buttonId: string, disabled: boolean): void {\n this.#shellController.setToolbarButtonDisabled(buttonId, disabled);\n }\n\n /**\n * Re-parse light DOM shell elements and refresh shell header.\n * Call this after dynamically modifying <tbw-grid-header> children.\n */\n refreshShellHeader(): void {\n // Re-parse light DOM\n parseLightDomShell(this, this.#shellState);\n\n // Re-render the entire grid (shell structure may change)\n this.#render();\n this.#afterConnect();\n }\n\n // ---------------- Virtual Window ----------------\n /**\n * Core virtualization routine. Chooses between bypass (small datasets), grouped window rendering,\n * or standard row window rendering.\n * @internal Plugin API\n */\n refreshVirtualWindow(force = false): void {\n if (!this._bodyEl) return;\n\n const totalRows = this._rows.length;\n\n if (!this._virtualization.enabled) {\n this.#renderVisibleRows(0, totalRows);\n this.#pluginManager?.afterRender();\n return;\n }\n\n if (this._rows.length <= this._virtualization.bypassThreshold) {\n this._virtualization.start = 0;\n this._virtualization.end = totalRows;\n this._bodyEl.style.transform = 'translateY(0px)';\n this.#renderVisibleRows(0, totalRows, this.__rowRenderEpoch);\n if (this._virtualization.totalHeightEl) {\n // Account for horizontal scrollbar height even in bypass mode\n const scrollAreaEl = this.#shadow.querySelector('.tbw-scroll-area') as HTMLElement;\n const hScrollbarHeight = scrollAreaEl ? scrollAreaEl.offsetHeight - scrollAreaEl.clientHeight : 0;\n this._virtualization.totalHeightEl.style.height = `${totalRows * this._virtualization.rowHeight + hScrollbarHeight}px`;\n }\n // Set ARIA counts on inner grid element (not host, which may contain shell chrome)\n const innerGrid = this.#shadow.querySelector('.rows-body');\n innerGrid?.setAttribute('aria-rowcount', String(totalRows));\n innerGrid?.setAttribute('aria-colcount', String(this._visibleColumns.length));\n this.#pluginManager?.afterRender();\n return;\n }\n\n // --- Normal virtualization path with faux scrollbar pattern ---\n // Faux scrollbar provides scrollTop, viewport provides visible height\n const fauxScrollbar = this._virtualization.container ?? this;\n const viewportEl = this._virtualization.viewportEl ?? fauxScrollbar;\n const viewportHeight = viewportEl.clientHeight;\n const rowHeight = this._virtualization.rowHeight;\n const scrollTop = fauxScrollbar.scrollTop;\n\n // When plugins add extra height (e.g., expanded details), the scroll position\n // includes that extra height. We need to find the actual row at scrollTop\n // by iteratively accounting for cumulative extra heights.\n // This prevents jumping when scrolling past expanded content.\n let start = Math.floor(scrollTop / rowHeight);\n\n // Iteratively refine: the initial guess may be too high because scrollTop\n // includes extra heights from expanded rows before it. Adjust downward.\n let iterations = 0;\n const maxIterations = 10; // Prevent infinite loop\n while (iterations < maxIterations) {\n const extraHeightBefore = this.#pluginManager?.getExtraHeightBefore?.(start) ?? 0;\n const adjustedStart = Math.floor((scrollTop - extraHeightBefore) / rowHeight);\n if (adjustedStart >= start || adjustedStart < 0) break;\n start = adjustedStart;\n iterations++;\n }\n\n // Faux scrollbar pattern: calculate effective position for this start\n // With translateY(0), the first rendered row appears at viewport top\n // Round down to even number so DOM nth-child(even) always matches data row parity\n // This prevents zebra stripe flickering during scroll since rows shift in pairs\n start = start - (start % 2);\n if (start < 0) start = 0;\n\n // Allow plugins to extend the start index backwards\n // (e.g., to keep expanded detail rows visible as they scroll out)\n const pluginAdjustedStart = this.#pluginManager?.adjustVirtualStart(start, scrollTop, rowHeight);\n if (pluginAdjustedStart !== undefined && pluginAdjustedStart < start) {\n start = pluginAdjustedStart;\n // Re-apply even alignment after plugin adjustment\n start = start - (start % 2);\n if (start < 0) start = 0;\n }\n\n // Faux pattern buffer: render 2 extra rows below for smooth edge transition\n // This is smaller than traditional overscan since sub-pixel offset handles smoothness\n // +1 extra to account for the even-alignment above potentially showing 1 more row at top\n const visibleCount = Math.ceil(viewportHeight / rowHeight) + 3;\n let end = start + visibleCount;\n if (end > totalRows) end = totalRows;\n\n this._virtualization.start = start;\n this._virtualization.end = end;\n\n // Height spacer for scrollbar\n // Add 1 extra row height to account for even-alignment: when we round down\n // from odd to even start, we need extra scroll range to reveal the last row\n // Also add footer height: faux-vscroll is outside .tbw-scroll-area so it doesn't\n // shrink when footer is present - we need extra spacer to scroll past the footer\n const footerEl = this.#shadow.querySelector('.tbw-footer') as HTMLElement;\n const footerHeight = footerEl?.offsetHeight ?? 0;\n // Add extra height from plugins (e.g., expanded master-detail rows)\n // This ensures the scrollbar range accounts for all content including expanded details\n const pluginExtraHeight = this.#pluginManager?.getExtraHeight() ?? 0;\n // Add horizontal scrollbar height: when horizontal scrollbar is visible in .tbw-scroll-area,\n // it takes space at the bottom that the faux vertical scrollbar doesn't account for.\n // Detect by comparing offsetHeight (includes scrollbar) vs clientHeight (excludes scrollbar).\n const scrollAreaEl = this.#shadow.querySelector('.tbw-scroll-area') as HTMLElement;\n const hScrollbarHeight = scrollAreaEl ? scrollAreaEl.offsetHeight - scrollAreaEl.clientHeight : 0;\n if (this._virtualization.totalHeightEl) {\n this._virtualization.totalHeightEl.style.height = `${\n totalRows * rowHeight + rowHeight + footerHeight + pluginExtraHeight + hScrollbarHeight\n }px`;\n }\n\n // Smooth scroll: apply offset for fluid motion\n // Since start is even-aligned, offset is distance from that aligned position\n // This creates smooth sliding while preserving zebra stripe parity\n // Account for extra heights (expanded details) before the start row\n const extraHeightBeforeStart = this.#pluginManager?.getExtraHeightBefore?.(start) ?? 0;\n const subPixelOffset = -(scrollTop - start * rowHeight - extraHeightBeforeStart);\n this._bodyEl.style.transform = `translateY(${subPixelOffset}px)`;\n\n this.#renderVisibleRows(start, end, force ? ++this.__rowRenderEpoch : this.__rowRenderEpoch);\n\n // Set ARIA counts on inner grid element (not host, which may contain shell chrome)\n const innerGrid = this.#shadow.querySelector('.rows-body');\n innerGrid?.setAttribute('aria-rowcount', String(totalRows));\n innerGrid?.setAttribute('aria-colcount', String(this._visibleColumns.length));\n\n // Only run plugin afterRender hooks on force refresh (structural changes)\n // Skip on scroll-triggered renders for maximum performance\n if (force) {\n this.#pluginManager?.afterRender();\n }\n }\n\n // ---------------- Render ----------------\n #render(): void {\n // Parse light DOM shell elements before rendering\n parseLightDomShell(this, this.#shellState);\n\n // Get shell config\n const shellConfig = this.#effectiveConfig?.shell;\n\n // Determine if shell should be rendered\n const hasShell = shouldRenderShellHeader(shellConfig, this.#shellState);\n\n // Core grid content HTML\n // Uses faux scrollbar pattern (like AG Grid) for smooth virtualized scrolling:\n // - .tbw-grid-content: outer container (row layout: scroll-area + faux-vscroll)\n // - .tbw-scroll-area: horizontal scroll container (overflow-x: auto) - footer appends here\n // - .rows-body-wrapper: header + rows in column layout\n // - .faux-vscroll: vertical scrollbar at inline-end, sticky during horizontal scroll\n // - .rows-viewport: visible rows area (no scroll, overflow hidden)\n // - Scroll events come from faux scrollbar, content positioned via transforms\n // This prevents blank viewport during fast scroll - old content stays until new renders\n const gridContentHtml = `\n <div class=\"tbw-scroll-area\">\n <div class=\"rows-body-wrapper\">\n <div class=\"rows-body\" role=\"grid\">\n <div class=\"header\">\n <div class=\"header-row\" part=\"header-row\"></div>\n </div>\n <div class=\"rows-container\">\n <div class=\"rows-viewport\">\n <div class=\"rows\"></div>\n </div>\n </div>\n </div>\n </div>\n </div>\n <div class=\"faux-vscroll\">\n <div class=\"faux-vscroll-spacer\"></div>\n </div>\n `;\n\n if (hasShell) {\n // Build shell DOM structure\n const toolPanelIcon = this.#effectiveConfig?.icons?.toolPanel ?? DEFAULT_GRID_ICONS.toolPanel;\n const accordionIcons = {\n expand: this.#effectiveConfig?.icons?.expand ?? DEFAULT_GRID_ICONS.expand,\n collapse: this.#effectiveConfig?.icons?.collapse ?? DEFAULT_GRID_ICONS.collapse,\n };\n const shellHeaderHtml = renderShellHeader(shellConfig, this.#shellState, toolPanelIcon);\n const shellBodyHtml = renderShellBody(shellConfig, this.#shellState, gridContentHtml, accordionIcons);\n\n this.#shadow.innerHTML = `\n <div class=\"tbw-grid-root has-shell\">\n ${shellHeaderHtml}\n ${shellBodyHtml}\n </div>\n `;\n\n // Set up shell event listeners\n this.#setupShellListeners();\n\n // Mark shell as initialized\n this.#shellController.setInitialized(true);\n } else {\n // Build minimal DOM structure (no shell)\n // Wrap in .tbw-grid-content for consistent horizontal scroll behavior\n this.#shadow.innerHTML = `\n <div class=\"tbw-grid-root\">\n <div class=\"tbw-grid-content\">\n ${gridContentHtml}\n </div>\n </div>\n `;\n }\n }\n\n /**\n * Set up shell event listeners after render.\n */\n #setupShellListeners(): void {\n setupShellEventListeners(this.#shadow, this.#effectiveConfig?.shell, this.#shellState, {\n onPanelToggle: () => this.toggleToolPanel(),\n onSectionToggle: (sectionId: string) => this.toggleToolPanelSection(sectionId),\n onToolbarButtonClick: (buttonId) => this.#handleToolbarButtonClick(buttonId),\n });\n\n // Set up tool panel resize\n this.#resizeCleanup?.();\n this.#resizeCleanup = setupToolPanelResize(this.#shadow, this.#effectiveConfig?.shell, (width: number) => {\n // Update the CSS variable to persist the new width\n this.style.setProperty('--tbw-tool-panel-width', `${width}px`);\n });\n }\n\n /**\n * Handle toolbar button click (for config buttons with action).\n */\n #handleToolbarButtonClick(buttonId: string): void {\n // Check config buttons\n const configButtons = this.#effectiveConfig?.shell?.header?.toolbarButtons ?? [];\n const configBtn = configButtons.find((b) => b.id === buttonId);\n if (configBtn?.action) {\n configBtn.action();\n return;\n }\n\n // Check API-registered buttons\n const apiBtn = this.#shellState.toolbarButtons.get(buttonId);\n if (apiBtn?.action) {\n apiBtn.action();\n }\n }\n}\n\n// Self-registering custom element\nif (!customElements.get(DataGridElement.tagName)) {\n customElements.define(DataGridElement.tagName, DataGridElement);\n}\n\n// Type augmentation for querySelector/createElement\ndeclare global {\n interface HTMLElementTagNameMap {\n 'tbw-grid': DataGridElement;\n }\n}\n","/**\n * Base Grid Plugin Class\n *\n * All plugins extend this abstract class.\n * Plugins are instantiated per-grid and manage their own state.\n */\n\nimport type {\n ColumnConfig,\n ColumnState,\n GridPlugin,\n HeaderContentDefinition,\n IconValue,\n ToolPanelDefinition,\n} from '../types';\nimport { DEFAULT_GRID_ICONS } from '../types';\n\n// Forward declare to avoid circular imports\nexport interface GridElement {\n shadowRoot: ShadowRoot | null;\n rows: any[];\n columns: ColumnConfig[];\n gridConfig: any;\n /**\n * Current focused row index\n * @internal Plugin API\n */\n _focusRow: number;\n /**\n * Current focused column index\n * @internal Plugin API\n */\n _focusCol: number;\n /** AbortSignal that is aborted when the grid disconnects from the DOM */\n disconnectSignal: AbortSignal;\n requestRender(): void;\n requestAfterRender(): void;\n forceLayout(): Promise<void>;\n getPlugin<T extends BaseGridPlugin>(PluginClass: new (...args: any[]) => T): T | undefined;\n getPluginByName(name: string): BaseGridPlugin | undefined;\n dispatchEvent(event: Event): boolean;\n}\n\n/**\n * Keyboard modifier flags\n */\nexport interface KeyboardModifiers {\n ctrl?: boolean;\n shift?: boolean;\n alt?: boolean;\n meta?: boolean;\n}\n\n/**\n * Cell coordinates\n */\nexport interface CellCoords {\n row: number;\n col: number;\n}\n\n/**\n * Cell click event\n */\nexport interface CellClickEvent {\n rowIndex: number;\n colIndex: number;\n field: string;\n value: any;\n row: any;\n cellEl: HTMLElement;\n originalEvent: MouseEvent;\n}\n\n/**\n * Row click event\n */\nexport interface RowClickEvent {\n rowIndex: number;\n row: any;\n rowEl: HTMLElement;\n originalEvent: MouseEvent;\n}\n\n/**\n * Header click event\n */\nexport interface HeaderClickEvent {\n colIndex: number;\n field: string;\n column: ColumnConfig;\n headerEl: HTMLElement;\n originalEvent: MouseEvent;\n}\n\n/**\n * Scroll event\n */\nexport interface ScrollEvent {\n scrollTop: number;\n scrollLeft: number;\n scrollHeight: number;\n scrollWidth: number;\n clientHeight: number;\n clientWidth: number;\n originalEvent?: Event;\n}\n\n/**\n * Cell mouse event (for drag operations, selection, etc.)\n */\nexport interface CellMouseEvent {\n /** Event type: mousedown, mousemove, or mouseup */\n type: 'mousedown' | 'mousemove' | 'mouseup';\n /** Row index, undefined if not over a data cell */\n rowIndex?: number;\n /** Column index, undefined if not over a cell */\n colIndex?: number;\n /** Field name, undefined if not over a cell */\n field?: string;\n /** Cell value, undefined if not over a data cell */\n value?: unknown;\n /** Row data object, undefined if not over a data row */\n row?: unknown;\n /** Column configuration, undefined if not over a column */\n column?: ColumnConfig;\n /** The cell element, undefined if not over a cell */\n cellElement?: HTMLElement;\n /** The row element, undefined if not over a row */\n rowElement?: HTMLElement;\n /** Whether the event is over a header cell */\n isHeader: boolean;\n /** Cell coordinates if over a valid data cell */\n cell?: CellCoords;\n /** The original mouse event */\n originalEvent: MouseEvent;\n}\n\n/**\n * Context menu parameters\n */\nexport interface ContextMenuParams {\n x: number;\n y: number;\n rowIndex?: number;\n colIndex?: number;\n field?: string;\n value?: any;\n row?: any;\n column?: ColumnConfig;\n isHeader?: boolean;\n}\n\n/**\n * Context menu item (used by context-menu plugin query)\n */\nexport interface ContextMenuItem {\n id: string;\n label: string;\n icon?: string;\n disabled?: boolean;\n separator?: boolean;\n children?: ContextMenuItem[];\n action?: (params: ContextMenuParams) => void;\n}\n\n/**\n * Generic plugin query for inter-plugin communication.\n * Plugins can define their own query types as string constants\n * and respond to queries from other plugins.\n */\nexport interface PluginQuery<T = unknown> {\n /** Query type identifier (e.g., 'canMoveColumn', 'getContextMenuItems') */\n type: string;\n /** Query-specific context/parameters */\n context: T;\n}\n\n/**\n * Well-known plugin query types.\n * Plugins can define additional query types beyond these.\n */\nexport const PLUGIN_QUERIES = {\n /** Ask if a column can be moved. Context: ColumnConfig. Response: boolean | undefined */\n CAN_MOVE_COLUMN: 'canMoveColumn',\n /** Get context menu items. Context: ContextMenuParams. Response: ContextMenuItem[] */\n GET_CONTEXT_MENU_ITEMS: 'getContextMenuItems',\n} as const;\n\n/**\n * Cell render context for plugin cell renderers.\n * Provides full context including position and editing state.\n *\n * Note: This differs from the core `CellRenderContext` in types.ts which is\n * simpler and used for column view renderers. This version provides additional\n * context needed by plugins that register custom cell renderers.\n */\nexport interface PluginCellRenderContext {\n /** The cell value */\n value: any;\n /** The field/column key */\n field: string;\n /** The row data object */\n row: any;\n /** Row index in the data array */\n rowIndex: number;\n /** Column index */\n colIndex: number;\n /** Column configuration */\n column: ColumnConfig;\n /** Whether the cell is currently in edit mode */\n isEditing: boolean;\n}\n\n/**\n * Header render context for plugin header renderers.\n */\nexport interface PluginHeaderRenderContext {\n /** Column configuration */\n column: ColumnConfig;\n /** Column index */\n colIndex: number;\n}\n\n/**\n * Cell renderer function type for plugins.\n */\nexport type CellRenderer = (ctx: PluginCellRenderContext) => string | HTMLElement;\n\n/**\n * Header renderer function type for plugins.\n */\nexport type HeaderRenderer = (ctx: PluginHeaderRenderContext) => string | HTMLElement;\n\n/**\n * Cell editor interface for plugins.\n */\nexport interface CellEditor {\n create(ctx: PluginCellRenderContext, commitFn: (value: any) => void, cancelFn: () => void): HTMLElement;\n getValue?(element: HTMLElement): any;\n focus?(element: HTMLElement): void;\n}\n\n/**\n * Abstract base class for all grid plugins.\n *\n * @template TConfig - Configuration type for the plugin\n */\nexport abstract class BaseGridPlugin<TConfig = unknown> implements GridPlugin {\n /** Unique plugin identifier (derived from class name by default) */\n abstract readonly name: string;\n\n /** Plugin version - override in subclass if needed */\n readonly version: string = '1.0.0';\n\n /** CSS styles to inject into the grid's shadow DOM */\n readonly styles?: string;\n\n /** Custom cell renderers keyed by type name */\n readonly cellRenderers?: Record<string, CellRenderer>;\n\n /** Custom header renderers keyed by type name */\n readonly headerRenderers?: Record<string, HeaderRenderer>;\n\n /** Custom cell editors keyed by type name */\n readonly cellEditors?: Record<string, CellEditor>;\n\n /** The grid instance this plugin is attached to */\n protected grid!: GridElement;\n\n /** Plugin configuration - merged with defaults in attach() */\n protected config!: TConfig;\n\n /** User-provided configuration from constructor */\n protected readonly userConfig: Partial<TConfig>;\n\n /**\n * Default configuration - subclasses should override this getter.\n * Note: This must be a getter (not property initializer) for proper inheritance\n * since property initializers run after parent constructor.\n */\n protected get defaultConfig(): Partial<TConfig> {\n return {};\n }\n\n constructor(config: Partial<TConfig> = {}) {\n this.userConfig = config;\n }\n\n /**\n * Called when the plugin is attached to a grid.\n * Override to set up event listeners, initialize state, etc.\n */\n attach(grid: GridElement): void {\n this.grid = grid;\n // Merge config here (after subclass construction is complete)\n this.config = { ...this.defaultConfig, ...this.userConfig } as TConfig;\n }\n\n /**\n * Called when the plugin is detached from a grid.\n * Override to clean up event listeners, timers, etc.\n */\n detach(): void {\n // Override in subclass\n }\n\n /**\n * Get another plugin instance from the same grid.\n * Use for inter-plugin communication.\n */\n protected getPlugin<T extends BaseGridPlugin>(PluginClass: new (...args: any[]) => T): T | undefined {\n return this.grid?.getPlugin(PluginClass);\n }\n\n /**\n * Emit a custom event from the grid.\n */\n protected emit<T>(eventName: string, detail: T): void {\n this.grid?.dispatchEvent?.(new CustomEvent(eventName, { detail, bubbles: true }));\n }\n\n /**\n * Request a re-render of the grid.\n */\n protected requestRender(): void {\n this.grid?.requestRender?.();\n }\n\n /**\n * Request a lightweight style update without rebuilding DOM.\n * Use this instead of requestRender() when only CSS classes need updating.\n */\n protected requestAfterRender(): void {\n this.grid?.requestAfterRender?.();\n }\n\n /**\n * Get the current rows from the grid.\n */\n protected get rows(): any[] {\n return this.grid?.rows ?? [];\n }\n\n /**\n * Get the original unfiltered/unprocessed rows from the grid.\n * Use this when you need all source data regardless of active filters.\n */\n protected get sourceRows(): any[] {\n return (this.grid as any)?.sourceRows ?? [];\n }\n\n /**\n * Get the current columns from the grid.\n */\n protected get columns(): ColumnConfig[] {\n return this.grid?.columns ?? [];\n }\n\n /**\n * Get only visible columns from the grid (excludes hidden).\n * Use this for rendering that needs to match the grid template.\n */\n protected get visibleColumns(): ColumnConfig[] {\n return (this.grid as any)?._visibleColumns ?? [];\n }\n\n /**\n * Get the shadow root of the grid.\n */\n protected get shadowRoot(): ShadowRoot | null {\n return this.grid?.shadowRoot ?? null;\n }\n\n /**\n * Get the disconnect signal for event listener cleanup.\n * This signal is aborted when the grid disconnects from the DOM.\n * Use this when adding event listeners that should be cleaned up automatically.\n *\n * Best for:\n * - Document/window-level listeners added in attach()\n * - Listeners on the grid element itself\n * - Any listener that should persist across renders\n *\n * Not needed for:\n * - Listeners on elements created in afterRender() (removed with element)\n *\n * @example\n * element.addEventListener('click', handler, { signal: this.disconnectSignal });\n * document.addEventListener('keydown', handler, { signal: this.disconnectSignal });\n */\n protected get disconnectSignal(): AbortSignal {\n return this.grid?.disconnectSignal;\n }\n\n /**\n * Get the grid-level icons configuration.\n * Returns merged icons (user config + defaults).\n */\n protected get gridIcons(): typeof DEFAULT_GRID_ICONS {\n const userIcons = this.grid?.gridConfig?.icons ?? {};\n return { ...DEFAULT_GRID_ICONS, ...userIcons };\n }\n\n /**\n * Resolve an icon value to string or HTMLElement.\n * Checks plugin config first, then grid-level icons, then defaults.\n *\n * @param iconKey - The icon key in GridIcons (e.g., 'expand', 'collapse')\n * @param pluginOverride - Optional plugin-level override\n * @returns The resolved icon value\n */\n protected resolveIcon(iconKey: keyof typeof DEFAULT_GRID_ICONS, pluginOverride?: IconValue): IconValue {\n // Plugin override takes precedence\n if (pluginOverride !== undefined) {\n return pluginOverride;\n }\n // Then grid-level config\n return this.gridIcons[iconKey];\n }\n\n /**\n * Set an icon value on an element.\n * Handles both string (text/HTML) and HTMLElement values.\n *\n * @param element - The element to set the icon on\n * @param icon - The icon value (string or HTMLElement)\n */\n protected setIcon(element: HTMLElement, icon: IconValue): void {\n if (typeof icon === 'string') {\n element.innerHTML = icon;\n } else if (icon instanceof HTMLElement) {\n element.innerHTML = '';\n element.appendChild(icon.cloneNode(true));\n }\n }\n\n /**\n * Log a warning message.\n */\n protected warn(message: string): void {\n console.warn(`[tbw-grid:${this.name}] ${message}`);\n }\n\n // #region Lifecycle Hooks\n\n /**\n * Transform rows before rendering.\n * Called during each render cycle before rows are rendered to the DOM.\n * Use this to filter, sort, or add computed properties to rows.\n *\n * @param rows - The current rows array (readonly to encourage returning a new array)\n * @returns The modified rows array to render\n *\n * @example\n * ```ts\n * processRows(rows: readonly any[]): any[] {\n * // Filter out hidden rows\n * return rows.filter(row => !row._hidden);\n * }\n * ```\n *\n * @example\n * ```ts\n * processRows(rows: readonly any[]): any[] {\n * // Add computed properties\n * return rows.map(row => ({\n * ...row,\n * _fullName: `${row.firstName} ${row.lastName}`\n * }));\n * }\n * ```\n */\n processRows?(rows: readonly any[]): any[];\n\n /**\n * Transform columns before rendering.\n * Called during each render cycle before column headers and cells are rendered.\n * Use this to add, remove, or modify column definitions.\n *\n * @param columns - The current columns array (readonly to encourage returning a new array)\n * @returns The modified columns array to render\n *\n * @example\n * ```ts\n * processColumns(columns: readonly ColumnConfig[]): ColumnConfig[] {\n * // Add a selection checkbox column\n * return [\n * { field: '_select', header: '', width: 40 },\n * ...columns\n * ];\n * }\n * ```\n */\n processColumns?(columns: readonly ColumnConfig[]): ColumnConfig[];\n\n /**\n * Called before each render cycle begins.\n * Use this to prepare state or cache values needed during rendering.\n *\n * @example\n * ```ts\n * beforeRender(): void {\n * this.visibleRowCount = this.calculateVisibleRows();\n * }\n * ```\n */\n beforeRender?(): void;\n\n /**\n * Called after each render cycle completes.\n * Use this for DOM manipulation, adding event listeners to rendered elements,\n * or applying visual effects like selection highlights.\n *\n * @example\n * ```ts\n * afterRender(): void {\n * // Apply selection styling to rendered rows\n * const rows = this.shadowRoot?.querySelectorAll('.data-row');\n * rows?.forEach((row, i) => {\n * row.classList.toggle('selected', this.selectedRows.has(i));\n * });\n * }\n * ```\n */\n afterRender?(): void;\n\n /**\n * Called after scroll-triggered row rendering completes.\n * This is a lightweight hook for applying visual state to recycled DOM elements.\n * Use this instead of afterRender when you need to reapply styling during scroll.\n *\n * Performance note: This is called frequently during scroll. Keep implementation fast.\n *\n * @example\n * ```ts\n * onScrollRender(): void {\n * // Reapply selection state to visible cells\n * this.applySelectionToVisibleCells();\n * }\n * ```\n */\n onScrollRender?(): void;\n\n /**\n * Return extra height contributed by this plugin (e.g., expanded detail rows).\n * Used to adjust scrollbar height calculations for virtualization.\n *\n * @returns Total extra height in pixels\n *\n * @example\n * ```ts\n * getExtraHeight(): number {\n * return this.expandedRows.size * this.detailHeight;\n * }\n * ```\n */\n getExtraHeight?(): number;\n\n /**\n * Return extra height that appears before a given row index.\n * Used by virtualization to correctly calculate scroll positions when\n * there's variable height content (like expanded detail rows) above the viewport.\n *\n * @param beforeRowIndex - The row index to calculate extra height before\n * @returns Extra height in pixels that appears before this row\n *\n * @example\n * ```ts\n * getExtraHeightBefore(beforeRowIndex: number): number {\n * let height = 0;\n * for (const expandedRowIndex of this.expandedRowIndices) {\n * if (expandedRowIndex < beforeRowIndex) {\n * height += this.getDetailHeight(expandedRowIndex);\n * }\n * }\n * return height;\n * }\n * ```\n */\n getExtraHeightBefore?(beforeRowIndex: number): number;\n\n /**\n * Adjust the virtualization start index to render additional rows before the visible range.\n * Use this when expanded content (like detail rows) needs its parent row to remain rendered\n * even when the parent row itself has scrolled above the viewport.\n *\n * @param start - The calculated start row index\n * @param scrollTop - The current scroll position\n * @param rowHeight - The height of a single row\n * @returns The adjusted start index (lower than or equal to original start)\n *\n * @example\n * ```ts\n * adjustVirtualStart(start: number, scrollTop: number, rowHeight: number): number {\n * // If row 5 is expanded and scrolled partially, keep it rendered\n * for (const expandedRowIndex of this.expandedRowIndices) {\n * const expandedRowTop = expandedRowIndex * rowHeight;\n * const expandedRowBottom = expandedRowTop + rowHeight + this.detailHeight;\n * if (expandedRowBottom > scrollTop && expandedRowIndex < start) {\n * return expandedRowIndex;\n * }\n * }\n * return start;\n * }\n * ```\n */\n adjustVirtualStart?(start: number, scrollTop: number, rowHeight: number): number;\n\n /**\n * Render a custom row, bypassing the default row rendering.\n * Use this for special row types like group headers, detail rows, or footers.\n *\n * @param row - The row data object\n * @param rowEl - The row DOM element to render into\n * @param rowIndex - The index of the row in the data array\n * @returns `true` if the plugin handled rendering (prevents default), `false`/`void` for default rendering\n *\n * @example\n * ```ts\n * renderRow(row: any, rowEl: HTMLElement, rowIndex: number): boolean | void {\n * if (row._isGroupHeader) {\n * rowEl.innerHTML = `<div class=\"group-header\">${row._groupLabel}</div>`;\n * return true; // Handled - skip default rendering\n * }\n * // Return void to let default rendering proceed\n * }\n * ```\n */\n renderRow?(row: any, rowEl: HTMLElement, rowIndex: number): boolean | void;\n\n // #endregion\n\n // #region Inter-Plugin Communication\n\n /**\n * Handle queries from other plugins.\n * This is the generic mechanism for inter-plugin communication.\n * Plugins can respond to well-known query types or define their own.\n *\n * @param query - The query object with type and context\n * @returns Query-specific response, or undefined if not handling this query\n *\n * @example\n * ```ts\n * onPluginQuery(query: PluginQuery): unknown {\n * switch (query.type) {\n * case PLUGIN_QUERIES.CAN_MOVE_COLUMN:\n * // Prevent moving pinned columns\n * const column = query.context as ColumnConfig;\n * if (column.sticky === 'left' || column.sticky === 'right') {\n * return false;\n * }\n * break;\n * case PLUGIN_QUERIES.GET_CONTEXT_MENU_ITEMS:\n * const params = query.context as ContextMenuParams;\n * return [{ id: 'my-action', label: 'My Action', action: () => {} }];\n * }\n * }\n * ```\n */\n onPluginQuery?(query: PluginQuery): unknown;\n\n // #endregion\n\n // #region Interaction Hooks\n\n /**\n * Handle keyboard events on the grid.\n * Called when a key is pressed while the grid or a cell has focus.\n *\n * @param event - The native KeyboardEvent\n * @returns `true` to prevent default behavior and stop propagation, `false`/`void` to allow default\n *\n * @example\n * ```ts\n * onKeyDown(event: KeyboardEvent): boolean | void {\n * // Handle Ctrl+A for select all\n * if (event.ctrlKey && event.key === 'a') {\n * this.selectAllRows();\n * return true; // Prevent default browser select-all\n * }\n * }\n * ```\n */\n onKeyDown?(event: KeyboardEvent): boolean | void;\n\n /**\n * Handle cell click events.\n * Called when a data cell is clicked (not headers).\n *\n * @param event - Cell click event with row/column context\n * @returns `true` to prevent default behavior and stop propagation, `false`/`void` to allow default\n *\n * @example\n * ```ts\n * onCellClick(event: CellClickEvent): boolean | void {\n * if (event.field === '_select') {\n * this.toggleRowSelection(event.rowIndex);\n * return true; // Handled\n * }\n * }\n * ```\n */\n onCellClick?(event: CellClickEvent): boolean | void;\n\n /**\n * Handle row click events.\n * Called when any part of a data row is clicked.\n * Note: This is called in addition to onCellClick, not instead of.\n *\n * @param event - Row click event with row context\n * @returns `true` to prevent default behavior and stop propagation, `false`/`void` to allow default\n *\n * @example\n * ```ts\n * onRowClick(event: RowClickEvent): boolean | void {\n * if (this.config.mode === 'row') {\n * this.selectRow(event.rowIndex, event.originalEvent);\n * return true;\n * }\n * }\n * ```\n */\n onRowClick?(event: RowClickEvent): boolean | void;\n\n /**\n * Handle header click events.\n * Called when a column header is clicked. Commonly used for sorting.\n *\n * @param event - Header click event with column context\n * @returns `true` to prevent default behavior and stop propagation, `false`/`void` to allow default\n *\n * @example\n * ```ts\n * onHeaderClick(event: HeaderClickEvent): boolean | void {\n * if (event.column.sortable !== false) {\n * this.toggleSort(event.field);\n * return true;\n * }\n * }\n * ```\n */\n onHeaderClick?(event: HeaderClickEvent): boolean | void;\n\n /**\n * Handle scroll events on the grid viewport.\n * Called during scrolling. Note: This may be called frequently; debounce if needed.\n *\n * @param event - Scroll event with scroll position and viewport dimensions\n *\n * @example\n * ```ts\n * onScroll(event: ScrollEvent): void {\n * // Update sticky column positions\n * this.updateStickyPositions(event.scrollLeft);\n * }\n * ```\n */\n onScroll?(event: ScrollEvent): void;\n\n /**\n * Handle cell mousedown events.\n * Used for initiating drag operations like range selection or column resize.\n *\n * @param event - Mouse event with cell context\n * @returns `true` to indicate drag started (prevents text selection), `false`/`void` otherwise\n *\n * @example\n * ```ts\n * onCellMouseDown(event: CellMouseEvent): boolean | void {\n * if (event.rowIndex !== undefined && this.config.mode === 'range') {\n * this.startDragSelection(event.rowIndex, event.colIndex);\n * return true; // Prevent text selection\n * }\n * }\n * ```\n */\n onCellMouseDown?(event: CellMouseEvent): boolean | void;\n\n /**\n * Handle cell mousemove events during drag operations.\n * Only called when a drag is in progress (after mousedown returned true).\n *\n * @param event - Mouse event with current cell context\n * @returns `true` to continue handling the drag, `false`/`void` otherwise\n *\n * @example\n * ```ts\n * onCellMouseMove(event: CellMouseEvent): boolean | void {\n * if (this.isDragging && event.rowIndex !== undefined) {\n * this.extendSelection(event.rowIndex, event.colIndex);\n * return true;\n * }\n * }\n * ```\n */\n onCellMouseMove?(event: CellMouseEvent): boolean | void;\n\n /**\n * Handle cell mouseup events to end drag operations.\n *\n * @param event - Mouse event with final cell context\n * @returns `true` if drag was finalized, `false`/`void` otherwise\n *\n * @example\n * ```ts\n * onCellMouseUp(event: CellMouseEvent): boolean | void {\n * if (this.isDragging) {\n * this.finalizeDragSelection();\n * this.isDragging = false;\n * return true;\n * }\n * }\n * ```\n */\n onCellMouseUp?(event: CellMouseEvent): boolean | void;\n\n // Note: Context menu items are now provided via onPluginQuery with PLUGIN_QUERIES.GET_CONTEXT_MENU_ITEMS\n // This keeps the core decoupled from the context-menu plugin specifics.\n\n // #endregion\n\n // #region Column State Hooks\n\n /**\n * Contribute plugin-specific state for a column.\n * Called by the grid when collecting column state for serialization.\n * Plugins can add their own properties to the column state.\n *\n * @param field - The field name of the column\n * @returns Partial column state with plugin-specific properties, or undefined if no state to contribute\n *\n * @example\n * ```ts\n * getColumnState(field: string): Partial<ColumnState> | undefined {\n * const filterModel = this.filterModels.get(field);\n * if (filterModel) {\n * // Uses module augmentation to add filter property to ColumnState\n * return { filter: filterModel } as Partial<ColumnState>;\n * }\n * return undefined;\n * }\n * ```\n */\n getColumnState?(field: string): Partial<ColumnState> | undefined;\n\n /**\n * Apply plugin-specific state to a column.\n * Called by the grid when restoring column state from serialized data.\n * Plugins should restore their internal state based on the provided state.\n *\n * @param field - The field name of the column\n * @param state - The column state to apply (may contain plugin-specific properties)\n *\n * @example\n * ```ts\n * applyColumnState(field: string, state: ColumnState): void {\n * // Check for filter property added via module augmentation\n * const filter = (state as any).filter;\n * if (filter) {\n * this.filterModels.set(field, filter);\n * this.applyFilter();\n * }\n * }\n * ```\n */\n applyColumnState?(field: string, state: ColumnState): void;\n\n // #endregion\n\n // #region Scroll Boundary Hooks\n\n /**\n * Report horizontal scroll boundary offsets for this plugin.\n * Plugins that obscure part of the scroll area (e.g., pinned/sticky columns)\n * should return how much space they occupy on each side.\n * The keyboard navigation uses this to ensure focused cells are fully visible.\n *\n * @param rowEl - The row element (optional, for calculating widths from rendered cells)\n * @param focusedCell - The currently focused cell element (optional, to determine if scrolling should be skipped)\n * @returns Object with left/right pixel offsets and optional skipScroll flag, or undefined if plugin has no offsets\n *\n * @example\n * ```ts\n * getHorizontalScrollOffsets(rowEl?: HTMLElement, focusedCell?: HTMLElement): { left: number; right: number; skipScroll?: boolean } | undefined {\n * // Calculate total width of left-pinned columns\n * const leftCells = rowEl?.querySelectorAll('.sticky-left') ?? [];\n * let left = 0;\n * leftCells.forEach(el => { left += (el as HTMLElement).offsetWidth; });\n * // Skip scroll if focused cell is pinned (always visible)\n * const skipScroll = focusedCell?.classList.contains('sticky-left');\n * return { left, right: 0, skipScroll };\n * }\n * ```\n */\n getHorizontalScrollOffsets?(\n rowEl?: HTMLElement,\n focusedCell?: HTMLElement,\n ): { left: number; right: number; skipScroll?: boolean } | undefined;\n\n // #endregion\n\n // #region Shell Integration Hooks\n\n /**\n * Register a tool panel for this plugin.\n * Return undefined if plugin has no tool panel.\n * The shell will create a toolbar toggle button and render the panel content\n * when the user opens the panel.\n *\n * @returns Tool panel definition, or undefined if plugin has no panel\n *\n * @example\n * ```ts\n * getToolPanel(): ToolPanelDefinition | undefined {\n * return {\n * id: 'columns',\n * title: 'Columns',\n * icon: '☰',\n * tooltip: 'Show/hide columns',\n * order: 10,\n * render: (container) => {\n * this.renderColumnList(container);\n * return () => this.cleanup();\n * },\n * };\n * }\n * ```\n */\n getToolPanel?(): ToolPanelDefinition | undefined;\n\n /**\n * Register content for the shell header center section.\n * Return undefined if plugin has no header content.\n * Examples: search input, selection summary, status indicators.\n *\n * @returns Header content definition, or undefined if plugin has no header content\n *\n * @example\n * ```ts\n * getHeaderContent(): HeaderContentDefinition | undefined {\n * return {\n * id: 'quick-filter',\n * order: 10,\n * render: (container) => {\n * const input = document.createElement('input');\n * input.type = 'text';\n * input.placeholder = 'Search...';\n * input.addEventListener('input', this.handleInput);\n * container.appendChild(input);\n * return () => input.removeEventListener('input', this.handleInput);\n * },\n * };\n * }\n * ```\n */\n getHeaderContent?(): HeaderContentDefinition | undefined;\n\n // #endregion\n}\n","/**\n * Grid DOM Constants\n *\n * Centralized constants for CSS classes, data attributes, and selectors\n * used throughout the grid. Use these instead of magic strings.\n *\n * Note: Some constants here are used by plugins but defined in core because:\n * 1. The core CSS needs to style these elements (e.g., sticky positioning)\n * 2. Multiple plugins may share the same class names\n *\n * Plugins can define their own additional constants and export them.\n * See each plugin's index.ts for plugin-specific exports.\n */\n\n// #region CSS Classes\n\n/**\n * CSS class names used in the grid's shadow DOM.\n * Use these when adding/removing classes or querying elements.\n *\n * Classes are organized by:\n * - Core: Used by the grid core for structure and basic functionality\n * - Shared: Used by multiple features/plugins, styled by core CSS\n */\nexport const GridClasses = {\n // ─── Core Structure ───────────────────────────────────────────────\n ROOT: 'tbw-grid-root',\n HEADER: 'header',\n HEADER_ROW: 'header-row',\n HEADER_CELL: 'header-cell',\n\n // Body structure\n ROWS_VIEWPORT: 'rows-viewport',\n ROWS_SPACER: 'rows-spacer',\n ROWS_CONTAINER: 'rows',\n\n // Row elements\n DATA_ROW: 'data-row',\n GROUP_ROW: 'group-row',\n\n // Cell elements\n DATA_CELL: 'data-cell',\n\n // ─── Core States ──────────────────────────────────────────────────\n SELECTED: 'selected',\n FOCUSED: 'focused',\n EDITING: 'editing',\n EXPANDED: 'expanded',\n COLLAPSED: 'collapsed',\n DRAGGING: 'dragging',\n RESIZING: 'resizing',\n\n // Sorting (core feature)\n SORTABLE: 'sortable',\n SORTED_ASC: 'sorted-asc',\n SORTED_DESC: 'sorted-desc',\n\n // Visibility\n HIDDEN: 'hidden',\n\n // ─── Shared Classes (used by plugins, styled by core CSS) ────────\n // These are defined here because core CSS provides the base styling.\n // Plugins apply these classes; core CSS defines how they look.\n\n // Sticky positioning (PinnedColumnsPlugin applies, core CSS styles)\n STICKY_LEFT: 'sticky-left',\n STICKY_RIGHT: 'sticky-right',\n\n // Pinned rows (PinnedRowsPlugin applies, core CSS styles)\n PINNED_TOP: 'pinned-top',\n PINNED_BOTTOM: 'pinned-bottom',\n\n // Tree structure (TreePlugin applies, core CSS styles)\n TREE_TOGGLE: 'tree-toggle',\n TREE_INDENT: 'tree-indent',\n\n // Grouping (GroupingRowsPlugin applies, core CSS styles)\n GROUP_TOGGLE: 'group-toggle',\n GROUP_LABEL: 'group-label',\n GROUP_COUNT: 'group-count',\n\n // Selection (SelectionPlugin applies, core CSS styles)\n RANGE_SELECTION: 'range-selection',\n SELECTION_OVERLAY: 'selection-overlay',\n} as const;\n\n// #endregion\n\n// #region Data Attributes\n\n/**\n * Data attribute names used on grid elements.\n * Use these when getting/setting data attributes.\n */\nexport const GridDataAttrs = {\n // ─── Core Attributes ──────────────────────────────────────────────\n ROW_INDEX: 'data-row-index',\n COL_INDEX: 'data-col-index',\n FIELD: 'data-field',\n\n // ─── Shared Attributes (used by plugins) ──────────────────────────\n GROUP_KEY: 'data-group-key', // GroupingRowsPlugin\n TREE_LEVEL: 'data-tree-level', // TreePlugin\n STICKY: 'data-sticky', // PinnedColumnsPlugin\n} as const;\n\n// #endregion\n\n// #region Selectors\n\n/**\n * Common CSS selectors for querying grid elements.\n * Built from the class constants for consistency.\n */\nexport const GridSelectors = {\n ROOT: `.${GridClasses.ROOT}`,\n HEADER: `.${GridClasses.HEADER}`,\n HEADER_ROW: `.${GridClasses.HEADER_ROW}`,\n HEADER_CELL: `.${GridClasses.HEADER_CELL}`,\n ROWS_VIEWPORT: `.${GridClasses.ROWS_VIEWPORT}`,\n ROWS_CONTAINER: `.${GridClasses.ROWS_CONTAINER}`,\n DATA_ROW: `.${GridClasses.DATA_ROW}`,\n DATA_CELL: `.${GridClasses.DATA_CELL}`,\n GROUP_ROW: `.${GridClasses.GROUP_ROW}`,\n\n // By data attribute\n ROW_BY_INDEX: (index: number) => `.${GridClasses.DATA_ROW}[${GridDataAttrs.ROW_INDEX}=\"${index}\"]`,\n CELL_BY_FIELD: (field: string) => `.${GridClasses.DATA_CELL}[${GridDataAttrs.FIELD}=\"${field}\"]`,\n CELL_AT: (row: number, col: number) =>\n `.${GridClasses.DATA_ROW}[${GridDataAttrs.ROW_INDEX}=\"${row}\"] .${GridClasses.DATA_CELL}[${GridDataAttrs.COL_INDEX}=\"${col}\"]`,\n\n // State selectors\n SELECTED_ROWS: `.${GridClasses.DATA_ROW}.${GridClasses.SELECTED}`,\n EDITING_CELL: `.${GridClasses.DATA_CELL}.${GridClasses.EDITING}`,\n} as const;\n\n// #endregion\n\n// #region CSS Custom Properties\n\n/**\n * CSS custom property names for theming.\n * Use these when programmatically setting styles.\n */\nexport const GridCSSVars = {\n // Colors\n COLOR_BG: '--tbw-color-bg',\n COLOR_FG: '--tbw-color-fg',\n COLOR_FG_MUTED: '--tbw-color-fg-muted',\n COLOR_BORDER: '--tbw-color-border',\n COLOR_ACCENT: '--tbw-color-accent',\n COLOR_HEADER_BG: '--tbw-color-header-bg',\n COLOR_HEADER_FG: '--tbw-color-header-fg',\n COLOR_SELECTION: '--tbw-color-selection',\n COLOR_ROW_HOVER: '--tbw-color-row-hover',\n COLOR_ROW_ALT: '--tbw-color-row-alt',\n\n // Sizing\n ROW_HEIGHT: '--tbw-row-height',\n HEADER_HEIGHT: '--tbw-header-height',\n CELL_PADDING: '--tbw-cell-padding',\n\n // Typography\n FONT_FAMILY: '--tbw-font-family',\n FONT_SIZE: '--tbw-font-size',\n\n // Borders\n BORDER_RADIUS: '--tbw-border-radius',\n FOCUS_OUTLINE: '--tbw-focus-outline',\n} as const;\n\n// #endregion\n\n// Type helpers\nexport type GridClassName = (typeof GridClasses)[keyof typeof GridClasses];\nexport type GridDataAttr = (typeof GridDataAttrs)[keyof typeof GridDataAttrs];\nexport type GridCSSVar = (typeof GridCSSVars)[keyof typeof GridCSSVars];\n","// #region Public API surface - only export what consumers need\nexport { DataGridElement, DataGridElement as GridElement } from './lib/core/grid';\n\n// Event name constants for DataGrid (public API)\nexport const DGEvents = {\n CELL_COMMIT: 'cell-commit',\n ROW_COMMIT: 'row-commit',\n CHANGED_ROWS_RESET: 'changed-rows-reset',\n MOUNT_EXTERNAL_VIEW: 'mount-external-view',\n MOUNT_EXTERNAL_EDITOR: 'mount-external-editor',\n SORT_CHANGE: 'sort-change',\n COLUMN_RESIZE: 'column-resize',\n ACTIVATE_CELL: 'activate-cell',\n GROUP_TOGGLE: 'group-toggle',\n COLUMN_STATE_CHANGE: 'column-state-change',\n} as const;\n\nexport type DGEventName = (typeof DGEvents)[keyof typeof DGEvents];\n\n// Plugin event constants (mirrors DGEvents pattern)\nexport const PluginEvents = {\n // Selection plugin\n SELECTION_CHANGE: 'selection-change',\n // Tree plugin\n TREE_EXPAND: 'tree-expand',\n // Filtering plugin\n FILTER_CHANGE: 'filter-change',\n // Sorting plugin\n SORT_MODEL_CHANGE: 'sort-model-change',\n // Export plugin\n EXPORT_START: 'export-start',\n EXPORT_COMPLETE: 'export-complete',\n // Clipboard plugin\n CLIPBOARD_COPY: 'clipboard-copy',\n CLIPBOARD_PASTE: 'clipboard-paste',\n // Context menu plugin\n CONTEXT_MENU_OPEN: 'context-menu-open',\n CONTEXT_MENU_CLOSE: 'context-menu-close',\n // Undo/Redo plugin\n HISTORY_CHANGE: 'history-change',\n // Server-side plugin\n SERVER_LOADING: 'server-loading',\n SERVER_ERROR: 'server-error',\n // Visibility plugin\n COLUMN_VISIBILITY_CHANGE: 'column-visibility-change',\n // Reorder plugin\n COLUMN_REORDER: 'column-reorder',\n // Master-detail plugin\n DETAIL_EXPAND: 'detail-expand',\n // Grouping rows plugin\n GROUP_EXPAND: 'group-expand',\n} as const;\n\nexport type PluginEventName = (typeof PluginEvents)[keyof typeof PluginEvents];\n\n// Public type exports\nexport type {\n ActivateCellDetail,\n AggregatorRef,\n BaseColumnConfig,\n // Event detail types\n CellCommitDetail,\n CellRenderContext,\n ChangedRowsResetDetail,\n ColumnConfig,\n ColumnConfigMap,\n ColumnEditorContext,\n // Column features\n ColumnEditorSpec,\n ColumnResizeDetail,\n // Column state types\n ColumnSortState,\n ColumnState,\n ColumnViewRenderer,\n DataGridCustomEvent,\n DataGridElement as DataGridElementInterface,\n DataGridEventMap,\n ExternalMountEditorDetail,\n ExternalMountViewDetail,\n FitMode,\n GridColumnState,\n // Core configuration types\n GridConfig,\n // Icons\n GridIcons,\n // Plugin interface (minimal shape for type-checking)\n GridPlugin,\n // Shell types\n HeaderContentDefinition,\n IconValue,\n // Inference types\n InferredColumnResult,\n PrimitiveColumnType,\n // Public interface\n PublicGrid,\n RowCommitDetail,\n // Grouping & Footer types\n RowGroupRenderConfig,\n ShellConfig,\n ShellHeaderConfig,\n SortChangeDetail,\n ToolPanelConfig,\n ToolPanelDefinition,\n ToolbarButtonConfig,\n} from './lib/core/types';\n\n// Re-export FitModeEnum for runtime usage\nexport { DEFAULT_GRID_ICONS, FitModeEnum } from './lib/core/types';\n// #endregion\n\n// #region Plugin Types\n// Only export types that consumers need to use plugins\n// Plugin classes are available via @toolbox-web/grid/plugins/<name> or from 'all.ts'\n\n// Selection plugin\nexport type { CellRange, SelectionChangeDetail, SelectionConfig, SelectionMode } from './lib/plugins/selection/types';\n\n// Tree plugin\nexport type { TreeConfig, TreeExpandDetail } from './lib/plugins/tree/types';\n\n// Filtering plugin\nexport type { FilterConfig, FilterModel, FilterOperator, FilterType } from './lib/plugins/filtering/types';\n\n// Multi-sort plugin\nexport type { MultiSortConfig, SortModel } from './lib/plugins/multi-sort/types';\n\n// Export plugin\nexport type { ExportFormat, ExportParams } from './lib/plugins/export/types';\n\n// Pinned rows plugin\nexport type { PinnedRowsContext, PinnedRowsPanel } from './lib/plugins/pinned-rows/types';\n\n// Pivot plugin\nexport type { PivotConfig, PivotResult, PivotValueField } from './lib/plugins/pivot/types';\n\n// Server-side plugin\nexport type { GetRowsParams, GetRowsResult, ServerSideDataSource } from './lib/plugins/server-side/types';\n\n// Undo/Redo plugin\nexport type { EditAction } from './lib/plugins/undo-redo/types';\n\n// Grouping rows plugin\nexport type { GroupingRowsConfig } from './lib/plugins/grouping-rows/types';\n\n// Plugin base class - for creating custom plugins\nexport { BaseGridPlugin, PLUGIN_QUERIES } from './lib/core/plugin';\nexport type { PluginQuery } from './lib/core/plugin';\n\n// DOM constants - for querying grid elements and styling\nexport { GridCSSVars, GridClasses, GridDataAttrs, GridSelectors } from './lib/core/constants';\nexport type { GridCSSVar, GridClassName, GridDataAttr } from './lib/core/constants';\n// #endregion\n","/**\n * Aggregators Core Registry\n *\n * Provides a central registry for aggregator functions.\n * Built-in aggregators are provided by default.\n * Plugins can register additional aggregators.\n *\n * The registry is exposed as a singleton object that can be accessed:\n * - By ES module imports: import { aggregatorRegistry } from '@toolbox-web/grid'\n * - By UMD/CDN: TbwGrid.aggregatorRegistry\n * - By plugins via context: ctx.aggregatorRegistry\n */\n\n/* eslint-disable @typescript-eslint/no-explicit-any */\n\nexport type AggregatorFn = (rows: any[], field: string, column?: any) => any;\nexport type AggregatorRef = string | AggregatorFn;\n\n/** Built-in aggregator functions */\nconst builtInAggregators: Record<string, AggregatorFn> = {\n sum: (rows, field) => rows.reduce((acc, row) => acc + (Number(row[field]) || 0), 0),\n avg: (rows, field) => {\n const sum = rows.reduce((acc, row) => acc + (Number(row[field]) || 0), 0);\n return rows.length ? sum / rows.length : 0;\n },\n count: (rows) => rows.length,\n min: (rows, field) => Math.min(...rows.map((r) => Number(r[field]) || Infinity)),\n max: (rows, field) => Math.max(...rows.map((r) => Number(r[field]) || -Infinity)),\n first: (rows, field) => rows[0]?.[field],\n last: (rows, field) => rows[rows.length - 1]?.[field],\n};\n\n/** Custom aggregator registry (for plugins to add to) */\nconst customAggregators: Map<string, AggregatorFn> = new Map();\n\n/**\n * The aggregator registry singleton.\n * Plugins should access this through context or the global namespace.\n */\nexport const aggregatorRegistry = {\n /**\n * Register a custom aggregator function.\n */\n register(name: string, fn: AggregatorFn): void {\n customAggregators.set(name, fn);\n },\n\n /**\n * Unregister a custom aggregator function.\n */\n unregister(name: string): void {\n customAggregators.delete(name);\n },\n\n /**\n * Get an aggregator function by reference.\n */\n get(ref: AggregatorRef | undefined): AggregatorFn | undefined {\n if (ref === undefined) return undefined;\n if (typeof ref === 'function') return ref;\n // Check custom first, then built-in\n return customAggregators.get(ref) ?? builtInAggregators[ref];\n },\n\n /**\n * Run an aggregator on a set of rows.\n */\n run(ref: AggregatorRef | undefined, rows: any[], field: string, column?: any): any {\n const fn = this.get(ref);\n return fn ? fn(rows, field, column) : undefined;\n },\n\n /**\n * Check if an aggregator exists.\n */\n has(name: string): boolean {\n return customAggregators.has(name) || name in builtInAggregators;\n },\n\n /**\n * List all available aggregator names.\n */\n list(): string[] {\n return [...Object.keys(builtInAggregators), ...customAggregators.keys()];\n },\n};\n\n// #region Value-based Aggregators\n// Used by plugins like Pivot that work with pre-extracted numeric values\n\nexport type ValueAggregatorFn = (values: number[]) => number;\n\n/**\n * Built-in value-based aggregators.\n * These operate on arrays of numbers (unlike row-based aggregators).\n */\nconst builtInValueAggregators: Record<string, ValueAggregatorFn> = {\n sum: (vals) => vals.reduce((a, b) => a + b, 0),\n avg: (vals) => (vals.length ? vals.reduce((a, b) => a + b, 0) / vals.length : 0),\n count: (vals) => vals.length,\n min: (vals) => (vals.length ? Math.min(...vals) : 0),\n max: (vals) => (vals.length ? Math.max(...vals) : 0),\n first: (vals) => vals[0] ?? 0,\n last: (vals) => vals[vals.length - 1] ?? 0,\n};\n\n/**\n * Get a value-based aggregator function.\n * Used by Pivot plugin and other features that aggregate pre-extracted values.\n *\n * @param aggFunc - Aggregation function name ('sum', 'avg', 'count', 'min', 'max', 'first', 'last')\n * @returns Aggregator function that takes number[] and returns number\n */\nexport function getValueAggregator(aggFunc: string): ValueAggregatorFn {\n return builtInValueAggregators[aggFunc] ?? builtInValueAggregators.sum;\n}\n\n/**\n * Run a value-based aggregator on a set of values.\n *\n * @param aggFunc - Aggregation function name\n * @param values - Array of numbers to aggregate\n * @returns Aggregated result\n */\nexport function runValueAggregator(aggFunc: string, values: number[]): number {\n return getValueAggregator(aggFunc)(values);\n}\n// #endregion\n\n// Legacy function exports for backward compatibility\nexport const registerAggregator = aggregatorRegistry.register.bind(aggregatorRegistry);\nexport const unregisterAggregator = aggregatorRegistry.unregister.bind(aggregatorRegistry);\nexport const getAggregator = aggregatorRegistry.get.bind(aggregatorRegistry);\nexport const runAggregator = aggregatorRegistry.run.bind(aggregatorRegistry);\nexport const listAggregators = aggregatorRegistry.list.bind(aggregatorRegistry);\n"],"names":["getSortState","grid","sortMap","collectColumnState","plugins","columns","sortStates","col","index","state","internalCol","sortState","plugin","pluginState","applyColumnState","allColumns","stateMap","s","updatedColumns","updated","a","b","orderA","orderB","sortedByPriority","primarySort","colState","createStateChangeHandler","getPlugins","emit","timeoutId","FitModeEnum","DEFAULT_GRID_ICONS","inferType","value","inferColumns","rows","provided","typeMap","sample","k","v","type","c","EXPR_RE","EMPTY_SENTINEL","SAFE_EXPR","FORBIDDEN","DANGEROUS_TAGS","DANGEROUS_ATTR_PATTERN","URL_ATTRS","DANGEROUS_URL_PROTOCOL","sanitizeHTML","html","template","sanitizeNode","root","toRemove","elements","el","tagName","attr","attrsToRemove","attrName","name","evalTemplateString","raw","ctx","parts","evaluated","_m","expr","res","evalSingle","finalStr","postProcess","allEmpty","p","key","dotChain","out","str","finalCellScrub","cell","n","compileTemplate","forceBlank","fn","parseLightDomColumns","host","field","rawType","header","sortable","editable","config","optionsAttr","item","label","viewTpl","editorTpl","headerTpl","mergeColumns","programmatic","dom","domMap","merged","d","m","addPart","token","existing","getColumnConfiguration","lightDomColumns","autoSizeColumns","mode","headerCells","changed","i","headerCell","max","rowEl","w","updateTemplate","min","defaultEditorFor","column","input","e","select","opt","o","commitValue","values","handleGridKeyDown","maxRow","maxCol","editing","colType","path","target","isFormField","tag","ensureCellVisible","options","rowHeight","container","viewportEl","scrollEl","visibleHeight","y","rowIndex","vStart","vEnd","scrollArea","offsets","cellRect","scrollAreaRect","cellLeft","cellRight","visibleLeft","visibleRight","focusTarget","CELL_CACHE_KEY","CELL_CACHE_EPOCH_KEY","invalidateCellCache","renderVisibleRows","start","end","epoch","renderRowHook","needed","bodyEl","colLen","headerRowCount","handleRowClick","hasRenderRowPlugins","rowData","rowEpoch","prevRef","cellCount","structureValid","dataRefChanged","needsExternalRebuild","hasEditingCell","isActivelyEditedRow","renderInlineRow","fastPatchRow","children","inlineEnterEdit","isChanged","hasChangedClass","colsLen","childLen","minLen","focusRow","focusCol","hasSpecialCols","rowIndexStr","shouldHaveFocus","hasFocus","produced","displayStr","formatted","isTrue","editMode","gridEl","fragment","colIndex","format","compiled","tplHolder","viewRenderer","externalView","needsSanitization","spec","placeholder","context","output","blocked","rawTpl","tentative","textContent","currentRowIndex","currentColIndex","currentRowData","currentCol","startRowEdit","rowElCurrent","col2","selectEl","newVal","commitCellValue","isDbl","firstCell","cellEl","active","targetCell","editor","isSafePropertyKey","exitRowEdit","revert","snapshot","current","val","rowIdx","colIdx","rowEl2","newValue","firstTime","originalValue","editFinalized","commit","cancel","inputLike","editorHost","editorSpec","clone","compiledEditor","node","g","hasHTMLInput","toggleSort","applySort","r","renderHeader","h","dir","comparator","rA","rB","setIcon","element","icon","headerRow","maybeTpl","span","icons","iconValue","handle","createResizeController","resizeState","pendingRaf","prevCursor","prevUserSelect","onMove","delta","width","justFinishedResize","onUp","hadResize","rect","iconToString","createShellState","shouldRenderShellHeader","renderShellHeader","toolPanelIcon","title","hasTitle","iconStr","configButtons","hasConfigButtons","hasApiButtons","hasLightDomButtons","hasPanels","showSeparator","sortedConfigButtons","sortedApiButtons","toolbarHtml","btn","isOpen","renderShellBody","gridContentHtml","position","hasPanel","expandIcon","collapseIcon","sortedPanels","isSinglePanel","accordionHtml","panel","isExpanded","iconHtml","chevronHtml","panelHtml","parseLightDomShell","headerEl","headerContents","toolButtons","setupShellEventListeners","shadowRoot","callbacks","toolbar","customBtn","btnId","accordion","sectionId","setupToolPanelResize","onResize","shellBody","minWidth","startX","startWidth","maxWidth","isResizing","onMouseMove","newWidth","onMouseUp","finalWidth","onMouseDown","renderCustomToolbarButtons","allButtons","slot","existingCleanup","cleanup","renderHeaderContent","contentArea","sortedContents","content","renderPanelContent","panelId","section","chevron","updateToolbarActiveStates","panelToggle","updatePanelState","getToolbarButtonsInfo","result","cleanupShellState","createShellController","initialized","controller","firstPanel","shadow","updateAccordionSectionState","otherId","otherPanel","contentEl","renderAccordionSectionContent","contentId","button","buttonId","disabled","apiBtn","expanded","PluginManager","renderer","PluginClass","total","beforeRowIndex","scrollTop","adjustedStart","pluginStart","row","query","responses","response","event","focusedCell","left","right","skipScroll","panels","contents","DataGridElement","#shadow","#initialized","#readyPromise","#readyResolve","#rows","#columns","#gridConfig","#fitMode","#editOn","#effectiveConfig","#connected","#scrollRaf","#pendingScrollTop","#hasScrollPlugins","#renderRowHook","#isDragging","#touchStartY","#touchStartX","#touchScrollTop","#touchScrollLeft","#touchLastY","#touchLastX","#touchLastTime","#touchVelocityY","#touchVelocityX","#momentumRaf","#eventAbortController","#resizeObserver","#pluginManager","#stateChangeHandler","#initialColumnState","#shellState","#shellController","#resizeCleanup","#baseColumns","oldValue","#onRowsChanged","#onColsChanged","#onGridConfigChanged","#onFitChanged","#onEditModeChanged","#injectStyles","eventName","detail","#emit","sheet","styles","#rebuildRowModel","#processColumns","#initializePlugins","pluginsConfig","#injectAllPluginStyles","allStyles","styleEl","#updatePluginConfigs","#destroyPlugins","#collectPluginShellContributions","pluginPanels","pluginContents","#mergeEffectiveConfig","#render","#afterConnect","prop","gridRoot","defaultOpen","signal","#setup","fauxScrollbar","rowsEl","currentScrollTop","rawStart","evenAlignedStart","subPixelOffset","#onScrollBatched","gridContentEl","isHorizontal","scrollLeft","scrollWidth","clientWidth","scrollHeight","clientHeight","currentY","currentX","now","deltaY","deltaX","dt","maxScrollY","canScrollVertically","canScrollHorizontally","maxScrollX","#startMomentumScroll","#handleMouseDown","#handleMouseMove","#handleMouseUp","userRowHeight","firstRow","measuredHeight","#updateAriaSelection","isActiveRow","sourceColumns","visibleCols","hiddenCols","processedColumns","processedMap","processed","originalRows","processedRows","base","domCols","map","exist","internal","existingCols","#renderVisibleRows","configCols","existingHiddenMap","seeded","#applyColumnStateInternal","allCols","scrollEvent","cellClickEvent","rowClickEvent","headerClickEvent","#buildCellMouseEvent","elAtPoint","animate","scrollY","scrollX","silent","visible","wasHidden","willBeHidden","isCurrentlyHidden","order","columnMap","reordered","#applyColumnState","force","totalRows","scrollAreaEl","hScrollbarHeight","innerGrid","viewportHeight","iterations","maxIterations","extraHeightBefore","pluginAdjustedStart","visibleCount","footerHeight","pluginExtraHeight","extraHeightBeforeStart","shellConfig","hasShell","accordionIcons","shellHeaderHtml","shellBodyHtml","#setupShellListeners","#handleToolbarButtonClick","configBtn","PLUGIN_QUERIES","BaseGridPlugin","userIcons","iconKey","pluginOverride","message","GridClasses","GridDataAttrs","GridSelectors","GridCSSVars","DGEvents","PluginEvents","builtInAggregators","acc","sum","customAggregators","aggregatorRegistry","ref","builtInValueAggregators","vals","getValueAggregator","aggFunc","runValueAggregator","registerAggregator","unregisterAggregator","getAggregator","runAggregator","listAggregators"],"mappings":"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"}
|