@toolbox-web/grid 0.0.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (87) hide show
  1. package/all.d.ts +3518 -0
  2. package/all.js +3762 -0
  3. package/all.js.map +1 -0
  4. package/index.d.ts +2367 -0
  5. package/index.js +3105 -0
  6. package/index.js.map +1 -0
  7. package/lib/plugins/clipboard/index.js +365 -0
  8. package/lib/plugins/clipboard/index.js.map +1 -0
  9. package/lib/plugins/column-virtualization/index.js +255 -0
  10. package/lib/plugins/column-virtualization/index.js.map +1 -0
  11. package/lib/plugins/context-menu/index.js +341 -0
  12. package/lib/plugins/context-menu/index.js.map +1 -0
  13. package/lib/plugins/export/index.js +305 -0
  14. package/lib/plugins/export/index.js.map +1 -0
  15. package/lib/plugins/filtering/index.js +759 -0
  16. package/lib/plugins/filtering/index.js.map +1 -0
  17. package/lib/plugins/grouping-columns/index.js +283 -0
  18. package/lib/plugins/grouping-columns/index.js.map +1 -0
  19. package/lib/plugins/grouping-rows/index.js +494 -0
  20. package/lib/plugins/grouping-rows/index.js.map +1 -0
  21. package/lib/plugins/master-detail/index.js +303 -0
  22. package/lib/plugins/master-detail/index.js.map +1 -0
  23. package/lib/plugins/multi-sort/index.js +270 -0
  24. package/lib/plugins/multi-sort/index.js.map +1 -0
  25. package/lib/plugins/pinned-columns/index.js +221 -0
  26. package/lib/plugins/pinned-columns/index.js.map +1 -0
  27. package/lib/plugins/pinned-rows/index.js +459 -0
  28. package/lib/plugins/pinned-rows/index.js.map +1 -0
  29. package/lib/plugins/pivot/index.js +326 -0
  30. package/lib/plugins/pivot/index.js.map +1 -0
  31. package/lib/plugins/reorder/index.js +260 -0
  32. package/lib/plugins/reorder/index.js.map +1 -0
  33. package/lib/plugins/selection/index.js +426 -0
  34. package/lib/plugins/selection/index.js.map +1 -0
  35. package/lib/plugins/server-side/index.js +241 -0
  36. package/lib/plugins/server-side/index.js.map +1 -0
  37. package/lib/plugins/tree/index.js +383 -0
  38. package/lib/plugins/tree/index.js.map +1 -0
  39. package/lib/plugins/undo-redo/index.js +289 -0
  40. package/lib/plugins/undo-redo/index.js.map +1 -0
  41. package/lib/plugins/visibility/index.js +430 -0
  42. package/lib/plugins/visibility/index.js.map +1 -0
  43. package/package.json +53 -0
  44. package/themes/dg-theme-contrast.css +43 -0
  45. package/themes/dg-theme-large.css +54 -0
  46. package/themes/dg-theme-standard.css +19 -0
  47. package/themes/dg-theme-vibrant.css +16 -0
  48. package/umd/grid.all.umd.js +660 -0
  49. package/umd/grid.all.umd.js.map +1 -0
  50. package/umd/grid.umd.js +105 -0
  51. package/umd/grid.umd.js.map +1 -0
  52. package/umd/plugins/clipboard.umd.js +9 -0
  53. package/umd/plugins/clipboard.umd.js.map +1 -0
  54. package/umd/plugins/column-virtualization.umd.js +2 -0
  55. package/umd/plugins/column-virtualization.umd.js.map +1 -0
  56. package/umd/plugins/context-menu.umd.js +53 -0
  57. package/umd/plugins/context-menu.umd.js.map +1 -0
  58. package/umd/plugins/export.umd.js +14 -0
  59. package/umd/plugins/export.umd.js.map +1 -0
  60. package/umd/plugins/filtering.umd.js +175 -0
  61. package/umd/plugins/filtering.umd.js.map +1 -0
  62. package/umd/plugins/grouping-columns.umd.js +29 -0
  63. package/umd/plugins/grouping-columns.umd.js.map +1 -0
  64. package/umd/plugins/grouping-rows.umd.js +40 -0
  65. package/umd/plugins/grouping-rows.umd.js.map +1 -0
  66. package/umd/plugins/master-detail.umd.js +27 -0
  67. package/umd/plugins/master-detail.umd.js.map +1 -0
  68. package/umd/plugins/multi-sort.umd.js +26 -0
  69. package/umd/plugins/multi-sort.umd.js.map +1 -0
  70. package/umd/plugins/pinned-columns.umd.js +2 -0
  71. package/umd/plugins/pinned-columns.umd.js.map +1 -0
  72. package/umd/plugins/pinned-rows.umd.js +73 -0
  73. package/umd/plugins/pinned-rows.umd.js.map +1 -0
  74. package/umd/plugins/pivot.umd.js +8 -0
  75. package/umd/plugins/pivot.umd.js.map +1 -0
  76. package/umd/plugins/reorder.umd.js +31 -0
  77. package/umd/plugins/reorder.umd.js.map +1 -0
  78. package/umd/plugins/selection.umd.js +34 -0
  79. package/umd/plugins/selection.umd.js.map +1 -0
  80. package/umd/plugins/server-side.umd.js +2 -0
  81. package/umd/plugins/server-side.umd.js.map +1 -0
  82. package/umd/plugins/tree.umd.js +11 -0
  83. package/umd/plugins/tree.umd.js.map +1 -0
  84. package/umd/plugins/undo-redo.umd.js +2 -0
  85. package/umd/plugins/undo-redo.umd.js.map +1 -0
  86. package/umd/plugins/visibility.umd.js +94 -0
  87. package/umd/plugins/visibility.umd.js.map +1 -0
@@ -0,0 +1 @@
1
+ {"version":3,"file":"grid.umd.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/plugins/selection/range-selection.ts","../../../../libs/grid/src/lib/plugins/selection/SelectionPlugin.ts","../../../../libs/grid/src/lib/plugins/tree/tree-data.ts","../../../../libs/grid/src/lib/plugins/tree/tree-detect.ts","../../../../libs/grid/src/lib/plugins/tree/TreePlugin.ts","../../../../libs/grid/src/lib/core/constants.ts","../../../../libs/grid/src/public.ts","../../../../libs/grid/src/lib/core/internal/aggregators.ts"],"sourcesContent":["/**\r\n * Column State Module\r\n *\r\n * Handles collection and application of column state for persistence.\r\n * State includes user-driven changes: order, width, visibility, and sort.\r\n * Plugins can contribute additional state via getColumnState/applyColumnState hooks.\r\n */\r\n\r\nimport type { BaseGridPlugin } from '../plugin';\r\nimport type {\r\n ColumnConfig,\r\n ColumnInternal,\r\n ColumnSortState,\r\n ColumnState,\r\n GridColumnState,\r\n InternalGrid,\r\n} from '../types';\r\n\r\n/** Debounce timeout for state change events */\r\nconst STATE_CHANGE_DEBOUNCE_MS = 100;\r\n\r\n/**\r\n * Get sort state for a column from the grid's sortState.\r\n */\r\nfunction getSortState(grid: InternalGrid): Map<string, ColumnSortState> {\r\n const sortMap = new Map<string, ColumnSortState>();\r\n\r\n // Core sort state (single column)\r\n if (grid.sortState) {\r\n sortMap.set(grid.sortState.field, {\r\n direction: grid.sortState.direction === 1 ? 'asc' : 'desc',\r\n priority: 0,\r\n });\r\n }\r\n\r\n return sortMap;\r\n}\r\n\r\n/**\r\n * Collect column state from the grid and all plugins.\r\n * Returns a complete GridColumnState object ready for serialization.\r\n */\r\nexport function collectColumnState<T>(grid: InternalGrid<T>, plugins: BaseGridPlugin[]): GridColumnState {\r\n const columns = grid._columns;\r\n const sortStates = getSortState(grid);\r\n\r\n return {\r\n columns: columns.map((col, index) => {\r\n // 1. Core state\r\n const state: ColumnState = {\r\n field: col.field,\r\n order: index,\r\n visible: true, // If it's in _columns, it's visible (hidden columns are filtered out)\r\n };\r\n\r\n // Include width if set (either from config or resize)\r\n const internalCol = col as ColumnInternal<T>;\r\n if (internalCol.__renderedWidth !== undefined) {\r\n state.width = internalCol.__renderedWidth;\r\n } else if (col.width !== undefined) {\r\n state.width = typeof col.width === 'string' ? parseFloat(col.width) : col.width;\r\n }\r\n\r\n // Include sort state if present\r\n const sortState = sortStates.get(col.field);\r\n if (sortState) {\r\n state.sort = sortState;\r\n }\r\n\r\n // 2. Collect from each plugin\r\n for (const plugin of plugins) {\r\n if (plugin.getColumnState) {\r\n const pluginState = plugin.getColumnState(col.field);\r\n if (pluginState) {\r\n Object.assign(state, pluginState);\r\n }\r\n }\r\n }\r\n\r\n return state;\r\n }),\r\n };\r\n}\r\n\r\n/**\r\n * Apply column state to the grid and all plugins.\r\n * Modifies the grid's internal state and triggers plugin state restoration.\r\n *\r\n * @param grid - The grid instance\r\n * @param state - The state to apply\r\n * @param allColumns - All available columns (including hidden ones)\r\n * @param plugins - Plugins that may have applyColumnState hooks\r\n */\r\nexport function applyColumnState<T>(\r\n grid: InternalGrid<T>,\r\n state: GridColumnState,\r\n allColumns: ColumnConfig<T>[],\r\n plugins: BaseGridPlugin[]\r\n): void {\r\n if (!state.columns || state.columns.length === 0) return;\r\n\r\n const stateMap = new Map(state.columns.map((s) => [s.field, s]));\r\n\r\n // 1. Apply width and visibility to columns\r\n const updatedColumns = allColumns.map((col) => {\r\n const s = stateMap.get(col.field);\r\n if (!s) return col;\r\n\r\n const updated: ColumnInternal<T> = { ...col };\r\n\r\n // Apply width\r\n if (s.width !== undefined) {\r\n updated.width = s.width;\r\n updated.__renderedWidth = s.width;\r\n }\r\n\r\n // Apply visibility (hidden is inverse of visible)\r\n if (s.visible !== undefined) {\r\n updated.hidden = !s.visible;\r\n }\r\n\r\n return updated;\r\n });\r\n\r\n // 2. Reorder columns based on state\r\n updatedColumns.sort((a, b) => {\r\n const orderA = stateMap.get(a.field)?.order ?? Infinity;\r\n const orderB = stateMap.get(b.field)?.order ?? Infinity;\r\n return orderA - orderB;\r\n });\r\n\r\n // 3. Update grid's internal columns\r\n grid._columns = updatedColumns as ColumnInternal<T>[];\r\n\r\n // 4. Apply sort state (core single-column sort)\r\n // Find the column with highest sort priority\r\n const sortedByPriority = state.columns\r\n .filter((s) => s.sort !== undefined)\r\n .sort((a, b) => (a.sort?.priority ?? 0) - (b.sort?.priority ?? 0));\r\n\r\n if (sortedByPriority.length > 0) {\r\n const primarySort = sortedByPriority[0];\r\n if (primarySort.sort) {\r\n grid.sortState = {\r\n field: primarySort.field,\r\n direction: primarySort.sort.direction === 'asc' ? 1 : -1,\r\n };\r\n }\r\n } else {\r\n grid.sortState = null;\r\n }\r\n\r\n // 5. Let each plugin apply its state\r\n for (const plugin of plugins) {\r\n if (plugin.applyColumnState) {\r\n for (const colState of state.columns) {\r\n plugin.applyColumnState(colState.field, colState);\r\n }\r\n }\r\n }\r\n}\r\n\r\n/**\r\n * Create a state change handler with debouncing.\r\n * Returns a function that, when called, will eventually emit the state change event.\r\n */\r\nexport function createStateChangeHandler<T>(\r\n grid: InternalGrid<T>,\r\n getPlugins: () => BaseGridPlugin[],\r\n emit: (detail: GridColumnState) => void\r\n): () => void {\r\n let timeoutId: ReturnType<typeof setTimeout> | null = null;\r\n\r\n return () => {\r\n // Clear any pending timeout\r\n if (timeoutId !== null) {\r\n clearTimeout(timeoutId);\r\n }\r\n\r\n // Schedule the emit\r\n timeoutId = setTimeout(() => {\r\n timeoutId = null;\r\n const state = collectColumnState(grid, getPlugins());\r\n emit(state);\r\n }, STATE_CHANGE_DEBOUNCE_MS);\r\n };\r\n}\r\n\r\n/**\r\n * Compare two column states to check if they are equal.\r\n * Useful for preventing duplicate state change events.\r\n */\r\nexport function areColumnStatesEqual(a: GridColumnState, b: GridColumnState): boolean {\r\n if (a.columns.length !== b.columns.length) return false;\r\n\r\n for (let i = 0; i < a.columns.length; i++) {\r\n const colA = a.columns[i];\r\n const colB = b.columns[i];\r\n\r\n if (colA.field !== colB.field) return false;\r\n if (colA.order !== colB.order) return false;\r\n if (colA.visible !== colB.visible) return false;\r\n if (colA.width !== colB.width) return false;\r\n\r\n // Compare sort state\r\n const sortA = colA.sort;\r\n const sortB = colB.sort;\r\n if ((sortA === undefined) !== (sortB === undefined)) return false;\r\n if (sortA && sortB) {\r\n if (sortA.direction !== sortB.direction) return false;\r\n if (sortA.priority !== sortB.priority) return false;\r\n }\r\n }\r\n\r\n return true;\r\n}\r\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, any>;\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 /** 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: any }> | (() => Array<{ label: string; value: any }>);\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, any>;\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: any;\n props?: Record<string, any>;\n mount?: (options: {\n placeholder: HTMLElement;\n context: CellRenderContext<TRow, any>;\n spec: any;\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 = any, TValue = any> =\n | string // custom element tag name\n | ((context: ColumnEditorContext<TRow, TValue>) => HTMLElement | string)\n | {\n /** Arbitrary component reference (class, function, token) */\n component: any;\n /** Optional static props passed to mount */\n props?: Record<string, any>;\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: any;\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 = any, TValue = any> = (\n ctx: CellRenderContext<TRow, TValue>\n) => Node | string | void;\n\n// ================= 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: any;\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: any) => 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\n// ================= 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: any, 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: any[], field: string, column?: any) => any);\n\n/** Result of automatic column inference from sample rows. */\nexport interface InferredColumnResult<TRow = any> {\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\n// ================= 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 * 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?: any[];\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// ================= 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 header */\n title: string;\n /** Icon for toolbar button (SVG string or emoji) */\n icon: string;\n /** Toolbar button tooltip */\n tooltip?: string;\n /** Panel content factory - called when panel 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\n// ================= 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\n// ================= Public Event Detail Interfaces =================\nexport interface CellCommitDetail<TRow = any> {\n /** The mutated row after commit. */\n row: TRow;\n /** Field name whose value changed. */\n field: string;\n /** New value stored. */\n value: any;\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 = any> {\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 = any> {\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 = any> {\n placeholder: HTMLElement;\n spec: any;\n context: { row: TRow; value: any; field: string; column: any };\n}\n\nexport interface ExternalMountEditorDetail<TRow = any> {\n placeholder: HTMLElement;\n spec: any;\n context: { row: TRow; value: any; field: string; column: any; commit: (v: any) => void; cancel: () => void };\n}\n\nexport interface DataGridEventMap<TRow = any> {\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<any>, TRow = any> = DataGridEventMap<TRow>[K];\nexport type DataGridCustomEvent<K extends keyof DataGridEventMap<any>, TRow = any> = CustomEvent<\n DataGridEventMap<TRow>[K]\n>;\n\n// Internal code now reuses the public ColumnEditorContext; provide alias for backward compatibility\nexport type EditorContext<T = any> = ColumnEditorContext<T, any>;\n\nexport interface EvalContext {\n value: any;\n row: any;\n}\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__';\n// Distinct sentinel for a template that was forcefully blocked at compile time OR\n// produced only blocked content. This lets downstream rendering logic suppress any\n// fallback value population that might otherwise leak (e.g. the raw row value or a\n// function source string) when a dangerous token is detected.\nexport const BLOCKED_SENTINEL = '__DG_BLOCKED__';\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// ============================================================================\n// HTML SANITIZATION\n// ============================================================================\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\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 // eslint-disable-next-line no-new-func\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 ?? '';\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 ?? '';\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 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 grid.focusCol = 0;\n e.preventDefault();\n break;\n case 'End':\n grid.focusCol = maxCol;\n e.preventDefault();\n break;\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 * 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): void {\n if (grid.virtualization?.enabled) {\n const { rowHeight } = grid.virtualization;\n const viewport = grid as unknown as HTMLElement; // grid element is the scroll container post-refactor\n const y = grid.focusRow * rowHeight;\n if (y < viewport.scrollTop) viewport.scrollTop = y;\n else if (y + rowHeight > viewport.scrollTop + viewport.clientHeight)\n viewport.scrollTop = y - viewport.clientHeight + rowHeight;\n }\n grid.refreshVirtualWindow(false);\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 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 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 (dataRefChanged) {\n // Same structure, different row data - fast update\n fastPatchRow(grid, rowEl, rowData, rowIndex);\n (rowEl as any).__rowDataRef = rowData;\n } else {\n // Same row data reference - just patch if any values changed\n fastPatchRow(grid, rowEl, rowData, rowIndex);\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 * Ultra-fast row update for plain columns (no templates, renderers, or external views).\n * This is the hottest path during scroll - every microsecond counts.\n * Minimal operations: just update cell textContent directly.\n */\nfunction updateRowDataFast(grid: InternalGrid, rowEl: HTMLElement, rowData: Record<string, unknown>): void {\n const cells = rowEl.children;\n const columns = grid.visibleColumns;\n const len = columns.length;\n\n for (let i = 0; i < len; i++) {\n const cell = cells[i] as HTMLElement;\n if (!cell) continue;\n\n const col = columns[i];\n const value = rowData[col.field];\n\n // Direct textContent update - fastest possible path\n cell.textContent = value == null ? '' : String(value);\n }\n}\n\n/**\n * Update row data in-place without rebuilding DOM structure.\n * Used during scroll when showing different row data in the same row pool slot.\n * Handles special column types (templates, renderers, external views).\n */\nfunction updateRowDataInPlace(grid: InternalGrid, rowEl: HTMLElement, rowData: any, rowIndex: number): void {\n // Use children for faster access than querySelectorAll\n const cells = rowEl.children;\n const columns = grid.visibleColumns;\n const colsLen = columns.length;\n const focusRow = grid.focusRow;\n const focusCol = grid.focusCol;\n\n // Cache header row count on grid to avoid repeated DOM queries\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 // Update aria-rowindex on the row\n const newRowIndex = String(rowIndex + headerRowCount + 1);\n if (rowEl.getAttribute('aria-rowindex') !== newRowIndex) {\n rowEl.setAttribute('aria-rowindex', newRowIndex);\n }\n\n const rowIndexStr = String(rowIndex);\n\n for (let i = 0; i < colsLen; i++) {\n const col = columns[i];\n const cell = cells[i] as HTMLElement;\n if (!cell) continue;\n\n // Update data-row attribute only if changed\n if (cell.getAttribute('data-row') !== rowIndexStr) {\n cell.setAttribute('data-row', rowIndexStr);\n }\n\n // Skip cells with active editors\n if (cell.classList.contains('editing')) continue;\n\n // Handle external views - they need remounting for new data\n if ((col as any).externalView) {\n const placeholder = cell.querySelector('[data-external-view]');\n if (placeholder) {\n const spec = (col as any).externalView;\n const value = (rowData as any)[col.field];\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 }\n }\n continue;\n }\n\n // Handle compiled templates\n const compiled = (col as any).__compiledView as ((ctx: any) => string) | undefined;\n if (compiled) {\n const value = (rowData as any)[col.field];\n const output = compiled({ row: rowData, value, field: col.field, column: col });\n const blocked = (compiled as any).__blocked;\n cell.innerHTML = blocked ? '' : sanitizeHTML(output);\n if (blocked) {\n cell.textContent = '';\n cell.setAttribute('data-blocked-template', '');\n } else {\n cell.removeAttribute('data-blocked-template');\n }\n continue;\n }\n\n // Handle inline templates\n const tplHolder = (col as any).__viewTemplate as HTMLElement | undefined;\n if (tplHolder) {\n const rawTpl = tplHolder.innerHTML;\n const value = (rowData as any)[col.field];\n if (/Reflect\\.|\\bProxy\\b|ownKeys\\(/.test(rawTpl)) {\n cell.textContent = '';\n cell.setAttribute('data-blocked-template', '');\n } else {\n cell.innerHTML = sanitizeHTML(evalTemplateString(rawTpl, { row: rowData, value }));\n cell.removeAttribute('data-blocked-template');\n }\n continue;\n }\n\n // Handle viewRenderer\n const viewRenderer = (col as any).viewRenderer;\n if (viewRenderer) {\n const value = (rowData as any)[col.field];\n const produced = 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 // Plain value rendering - update content directly\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 // Convert to display string once\n let displayValue: string;\n if (col.type === 'date') {\n if (value == null || value === '') {\n displayValue = '';\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 displayValue = d ? d.toLocaleDateString() : '';\n }\n // Only update if changed\n if (cell.textContent !== displayValue) {\n cell.textContent = displayValue;\n }\n } else if (col.type === 'boolean') {\n const isTrue = !!value;\n const boolHtml = isTrue ? '&#x1F5F9;' : '&#9744;';\n // Boolean cells need innerHTML, check aria-checked to detect change\n const currentChecked = cell.getAttribute('aria-checked');\n if (currentChecked !== String(isTrue)) {\n cell.innerHTML = boolHtml;\n cell.setAttribute('aria-checked', String(isTrue));\n cell.setAttribute('aria-label', String(isTrue));\n }\n } else {\n displayValue = value == null ? '' : String(value);\n // Only update if changed\n if (cell.textContent !== displayValue) {\n cell.textContent = displayValue;\n }\n }\n\n // Update focus state - check before modifying\n const shouldHaveFocus = focusRow === rowIndex && focusCol === i;\n const hasFocus = cell.classList.contains('cell-focus');\n if (shouldHaveFocus !== hasFocus) {\n if (shouldHaveFocus) {\n cell.classList.add('cell-focus');\n cell.setAttribute('aria-selected', 'true');\n } else {\n cell.classList.remove('cell-focus');\n cell.setAttribute('aria-selected', 'false');\n }\n }\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\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 }\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 // Skip cells in edit mode\n if (cell.classList.contains('editing')) continue;\n\n // Skip templated / external / custom renderer cells\n if (col.__viewTemplate || col.__compiledView || col.viewRenderer || 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 } else if (col.type === 'boolean') {\n displayStr = value ? '\\u{1F5F9}' : '\\u2610';\n cell.setAttribute('aria-checked', String(!!value));\n } else {\n displayStr = value == null ? '' : String(value);\n }\n\n cell.textContent = displayStr;\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 // Role assigned conditionally; boolean cells later become checkbox.\n if ((col as any).type !== 'boolean') cell.setAttribute('role', 'gridcell');\n cell.setAttribute('data-col', String(colIndex));\n cell.setAttribute('data-row', String(rowIndex));\n // aria-colindex is 1-based\n cell.setAttribute('aria-colindex', String(colIndex + 1));\n if (col.type) cell.setAttribute('data-type', col.type as any);\n\n // Apply sticky class if column has sticky property\n const sticky = (col as any).sticky;\n if (sticky === 'left') {\n cell.classList.add('sticky-left');\n } else if (sticky === 'right') {\n cell.classList.add('sticky-right');\n }\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 cell.innerHTML = isTrue ? '&#x1F5F9;' : '&#9744;';\n cell.setAttribute('role', 'checkbox');\n cell.setAttribute('aria-checked', String(isTrue));\n cell.setAttribute('aria-label', String(isTrue));\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 grid.focusRow = rowIndex;\n grid.focusCol = colIndex;\n ensureCellVisible(grid);\n });\n if (editMode === 'click') {\n cell.addEventListener('click', (e) => {\n if (cell.classList.contains('editing')) return;\n e.stopPropagation();\n grid.focusRow = rowIndex;\n grid.focusCol = colIndex;\n inlineEnterEdit(grid, rowData, rowIndex, col, cell);\n });\n } else {\n cell.addEventListener('dblclick', (e) => {\n e.stopPropagation();\n startRowEdit(grid, rowIndex, rowData);\n const rowElCurrent = grid.findRenderedRowElement?.(rowIndex);\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, rowData, rowIndex, col2, children[i] as HTMLElement);\n }\n }\n });\n }\n cell.addEventListener('keydown', (e) => {\n if (\n (col.type === 'select' || col.type === 'typeahead') &&\n !cell.classList.contains('editing') &&\n e.key === 'Enter'\n ) {\n e.preventDefault();\n if (grid.activeEditRows !== rowIndex) startRowEdit(grid, rowIndex, rowData);\n inlineEnterEdit(grid, rowData, rowIndex, col, 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 (col.type === 'boolean' && e.key === ' ' && !cell.classList.contains('editing')) {\n e.preventDefault();\n if (grid.activeEditRows !== rowIndex) startRowEdit(grid, rowIndex, rowData);\n const newVal = !rowData[col.field];\n commitCellValue(grid, rowIndex, col, newVal, rowData);\n cell.innerHTML = newVal ? '&#x1F5F9;' : '&#9744;';\n cell.setAttribute('aria-label', String(!!newVal));\n return;\n }\n if (e.key === 'Enter' && !cell.classList.contains('editing')) {\n e.preventDefault();\n grid.focusRow = rowIndex;\n grid.focusCol = colIndex;\n if (typeof grid.beginBulkEdit === 'function') grid.beginBulkEdit(rowIndex);\n else inlineEnterEdit(grid, rowData, rowIndex, col, cell);\n return;\n }\n if (e.key === 'F2' && !cell.classList.contains('editing')) {\n e.preventDefault();\n inlineEnterEdit(grid, rowData, rowIndex, col, cell);\n return;\n }\n });\n } else if (col.type === 'boolean') {\n if (!cell.hasAttribute('tabindex')) cell.tabIndex = 0;\n cell.addEventListener('keydown', (e) => {\n if (e.key === ' ') {\n e.preventDefault();\n const newVal = !rowData[col.field];\n if (grid.activeEditRows !== rowIndex) startRowEdit(grid, rowIndex, rowData);\n commitCellValue(grid, rowIndex, col as any, newVal, rowData);\n cell.innerHTML = newVal ? '&#x1F5F9;' : '&#9744;';\n cell.setAttribute('role', 'checkbox');\n cell.setAttribute('aria-checked', String(!!newVal));\n cell.setAttribute('aria-label', String(!!newVal));\n }\n });\n }\n\n // Initialize selection attributes\n if (focusRow === rowIndex && focusCol === colIndex) cell.setAttribute('aria-selected', 'true');\n else cell.setAttribute('aria-selected', 'false');\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 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 { renderInlineRow } from './rows';\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 if (revert && snapshot && current) {\n Object.keys(snapshot).forEach((k) => (current[k] = snapshot[k]));\n grid._changedRowIndices.delete(rowIndex);\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 const rowEl = grid.findRenderedRowElement?.(rowIndex);\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 if (revert) {\n queueMicrotask(() => {\n try {\n (grid as unknown as HTMLElement).focus();\n const rowIdx = grid.focusRow;\n const colIdx = grid.focusCol;\n const rowEl2 = grid.findRenderedRowElement?.(rowIdx);\n if (rowEl2) {\n Array.from(grid.bodyEl.querySelectorAll('.cell-focus')).forEach((el: any) =>\n el.classList.remove('cell-focus')\n );\n const cell = rowEl2.querySelector(`.cell[data-row=\"${rowIdx}\"][data-col=\"${colIdx}\"]`);\n if (cell) (cell as HTMLElement).classList.add('cell-focus');\n }\n } catch {\n /* empty */\n }\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 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 = rowData[column.field];\n cell.classList.add('editing');\n const commit = (newValue: any) => {\n commitCellValue(grid, rowIndex, column, newValue, rowData);\n };\n const cancel = () => {\n rowData[column.field] = originalValue;\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 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 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 const val =\n hasHTMLInput && input instanceof HTMLInputElement && input.type === 'checkbox'\n ? input.checked\n : (input as any).value;\n commit(val);\n }\n if (e.key === 'Escape') cancel();\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","/**\r\n * Sorting Module\r\n *\r\n * Handles column sorting state transitions and row ordering.\r\n */\r\n\r\nimport type { ColumnConfig, InternalGrid } from '../types';\r\nimport { renderHeader } from './header';\r\n\r\n/**\r\n * Cycle sort state for a column: none -> ascending -> descending -> none.\r\n * Restores original row order when clearing sort.\r\n */\r\nexport function toggleSort(grid: InternalGrid, col: ColumnConfig<any>): void {\r\n if (!grid.sortState || grid.sortState.field !== col.field) {\r\n if (!grid.sortState) grid.__originalOrder = grid._rows.slice();\r\n applySort(grid, col, 1);\r\n } else if (grid.sortState.direction === 1) {\r\n applySort(grid, col, -1);\r\n } else {\r\n grid.sortState = null;\r\n // Force full row rebuild after clearing sort so templated cells reflect original order\r\n grid.__rowRenderEpoch++;\r\n // Invalidate existing pooled row epochs so virtualization triggers a full inline rebuild\r\n grid.rowPool.forEach((r) => ((r as any).__epoch = -1));\r\n grid._rows = grid.__originalOrder.slice();\r\n renderHeader(grid);\r\n // After re-render ensure cleared column shows aria-sort=\"none\" baseline.\r\n const headers = grid.headerRowEl?.querySelectorAll('[role=\"columnheader\"].sortable');\r\n headers?.forEach((h: any) => {\r\n if (!h.getAttribute('aria-sort')) h.setAttribute('aria-sort', 'none');\r\n else if (h.getAttribute('aria-sort') === 'ascending' || h.getAttribute('aria-sort') === 'descending') {\r\n // The active column was re-rendered already, but normalize any missing ones.\r\n if (!grid.sortState) h.setAttribute('aria-sort', 'none');\r\n }\r\n });\r\n grid.refreshVirtualWindow(true);\r\n (grid as unknown as HTMLElement).dispatchEvent(\r\n new CustomEvent('sort-change', { detail: { field: col.field, direction: 0 } })\r\n );\r\n // Trigger state change after sort is cleared\r\n grid.requestStateChange?.();\r\n }\r\n}\r\n\r\n/**\r\n * Apply a concrete sort direction to rows using either the column's custom comparator\r\n * or a default comparator aware of null/undefined ordering.\r\n */\r\nexport function applySort(grid: InternalGrid, col: ColumnConfig<any>, dir: 1 | -1): void {\r\n grid.sortState = { field: col.field, direction: dir };\r\n const comparator =\r\n (col as any).sortComparator ||\r\n ((a: any, b: any) => (a == null && b == null ? 0 : a == null ? -1 : b == null ? 1 : a > b ? 1 : a < b ? -1 : 0));\r\n grid._rows.sort((rA: any, rB: any) => comparator(rA[col.field], rB[col.field], rA, rB) * dir);\r\n // Bump epoch so renderVisibleRows triggers full inline rebuild (ensures templated / compiled view cells update)\r\n grid.__rowRenderEpoch++;\r\n // Invalidate pooled rows to guarantee rebuild even if epoch comparison logic changes\r\n grid.rowPool.forEach((r) => ((r as any).__epoch = -1));\r\n renderHeader(grid);\r\n grid.refreshVirtualWindow(true);\r\n (grid as unknown as HTMLElement).dispatchEvent(\r\n new CustomEvent('sort-change', { detail: { field: col.field, direction: dir } })\r\n );\r\n // Trigger state change after sort applied\r\n grid.requestStateChange?.();\r\n}\r\n","/**\n * Header Rendering Module\n *\n * Handles rendering of the grid header row with sorting and resize affordances.\n */\n\nimport type { ColumnConfig, InternalGrid } from '../types';\nimport { addPart } from './columns';\nimport { toggleSort } from './sorting';\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 // ARIA row index for header row is always 1\n headerRow.setAttribute('role', 'row');\n headerRow.setAttribute('aria-rowindex', '1');\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 // Apply sticky class if column has sticky property\n if ((col as any).sticky === 'left') {\n cell.classList.add('sticky-left');\n } else if ((col as any).sticky === 'right') {\n cell.classList.add('sticky-right');\n }\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 icon.textContent = active === 1 ? '▲' : active === -1 ? '▼' : '⇅';\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 // Only set position: relative if column is not sticky (sticky already creates positioning context)\n if (!(col as any).sticky) {\n cell.style.position = 'relative';\n }\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 // If a column grouping row exists (handled in component render), we also mirror grouped class onto header-group-row cells in a post-pass\n try {\n const hostRoot = (grid as any).shadowRoot as ShadowRoot | undefined;\n if (hostRoot) {\n const groupCells = hostRoot.querySelectorAll('.header-group-row .cell');\n groupCells.forEach((gc) => {\n const id = gc.getAttribute('data-group');\n if (id) gc.classList.add('grouped');\n });\n }\n } catch {\n /* empty */\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","/** Controller interface for column resize interactions (local minimal typing). */\r\nimport type { InternalGrid } from '../types';\r\n\r\ninterface ResizeController {\r\n start: (e: MouseEvent, colIndex: number, cell: HTMLElement) => void;\r\n dispose: () => void;\r\n /** True while a resize drag is in progress (used to suppress header click/sort). */\r\n isResizing: boolean;\r\n}\r\n\r\nexport function createResizeController(grid: InternalGrid): ResizeController {\r\n let resizeState: { startX: number; colIndex: number; startWidth: number } | null = null;\r\n let pendingRaf: number | null = null;\r\n let prevCursor: string | null = null;\r\n let prevUserSelect: string | null = null;\r\n const onMove = (e: MouseEvent) => {\r\n if (!resizeState) return;\r\n const delta = e.clientX - resizeState.startX;\r\n const width = Math.max(40, resizeState.startWidth + delta);\r\n const col = grid.visibleColumns[resizeState.colIndex];\r\n col.width = width;\r\n col.__userResized = true;\r\n col.__renderedWidth = width;\r\n if (pendingRaf == null) {\r\n pendingRaf = requestAnimationFrame(() => {\r\n pendingRaf = null;\r\n grid.updateTemplate?.();\r\n });\r\n }\r\n (grid as unknown as HTMLElement).dispatchEvent(\r\n new CustomEvent('column-resize', { detail: { field: col.field, width } })\r\n );\r\n };\r\n let justFinishedResize = false;\r\n const onUp = () => {\r\n const hadResize = resizeState !== null;\r\n // Set flag to suppress click events that fire immediately after mouseup\r\n if (hadResize) {\r\n justFinishedResize = true;\r\n requestAnimationFrame(() => {\r\n justFinishedResize = false;\r\n });\r\n }\r\n window.removeEventListener('mousemove', onMove);\r\n window.removeEventListener('mouseup', onUp);\r\n if (prevCursor !== null) {\r\n document.documentElement.style.cursor = prevCursor;\r\n prevCursor = null;\r\n }\r\n if (prevUserSelect !== null) {\r\n document.body.style.userSelect = prevUserSelect;\r\n prevUserSelect = null;\r\n }\r\n resizeState = null;\r\n // Trigger state change after resize completes\r\n if (hadResize && grid.requestStateChange) {\r\n grid.requestStateChange();\r\n }\r\n };\r\n return {\r\n get isResizing() {\r\n return resizeState !== null || justFinishedResize;\r\n },\r\n start(e, colIndex, cell) {\r\n e.preventDefault();\r\n const rect = cell.getBoundingClientRect();\r\n resizeState = { startX: e.clientX, colIndex, startWidth: rect.width };\r\n window.addEventListener('mousemove', onMove);\r\n window.addEventListener('mouseup', onUp);\r\n if (prevCursor === null) prevCursor = document.documentElement.style.cursor;\r\n document.documentElement.style.cursor = 'e-resize';\r\n if (prevUserSelect === null) prevUserSelect = document.body.style.userSelect;\r\n document.body.style.userSelect = 'none';\r\n },\r\n dispose() {\r\n onUp();\r\n },\r\n };\r\n}\r\n","/**\r\n * Shell infrastructure for grid header bar and tool panels.\r\n *\r\n * The shell is an optional wrapper layer that provides:\r\n * - Header bar with title, plugin content, and toolbar buttons\r\n * - Tool panels that plugins can register content into\r\n * - Light DOM parsing for framework-friendly configuration\r\n */\r\n\r\nimport type {\r\n HeaderContentDefinition,\r\n ShellConfig,\r\n ToolbarButtonConfig,\r\n ToolbarButtonInfo,\r\n ToolPanelDefinition,\r\n} from '../types';\r\n\r\n/**\r\n * State for managing shell UI.\r\n */\r\nexport interface ShellState {\r\n /** Registered tool panels (from plugins + consumer API) */\r\n toolPanels: Map<string, ToolPanelDefinition>;\r\n /** Registered header content (from plugins + consumer API) */\r\n headerContents: Map<string, HeaderContentDefinition>;\r\n /** Custom toolbar buttons registered via API */\r\n toolbarButtons: Map<string, ToolbarButtonConfig>;\r\n /** Light DOM toolbar buttons */\r\n lightDomButtons: HTMLElement[];\r\n /** Light DOM header content elements */\r\n lightDomHeaderContent: HTMLElement[];\r\n /** Currently open tool panel ID (null if closed) */\r\n activePanel: string | null;\r\n /** Cleanup functions for header content render returns */\r\n headerContentCleanups: Map<string, () => void>;\r\n /** Cleanup function for active panel render return */\r\n activePanelCleanup: (() => void) | null;\r\n /** Cleanup functions for toolbar button render returns */\r\n toolbarButtonCleanups: Map<string, () => void>;\r\n}\r\n\r\n/**\r\n * Create initial shell state.\r\n */\r\nexport function createShellState(): ShellState {\r\n return {\r\n toolPanels: new Map(),\r\n headerContents: new Map(),\r\n toolbarButtons: new Map(),\r\n lightDomButtons: [],\r\n lightDomHeaderContent: [],\r\n activePanel: null,\r\n headerContentCleanups: new Map(),\r\n activePanelCleanup: null,\r\n toolbarButtonCleanups: new Map(),\r\n };\r\n}\r\n\r\n/**\r\n * Determine if shell header should be rendered.\r\n */\r\nexport function shouldRenderShellHeader(config: ShellConfig | undefined, state: ShellState): boolean {\r\n // Check if title is configured\r\n if (config?.header?.title) return true;\r\n\r\n // Check if config has toolbar buttons\r\n if (config?.header?.toolbarButtons?.length) return true;\r\n\r\n // Check if any tool panels are registered (need toolbar buttons for them)\r\n if (state.toolPanels.size > 0) return true;\r\n\r\n // Check if any header content is registered\r\n if (state.headerContents.size > 0) return true;\r\n\r\n // Check if any API toolbar buttons registered\r\n if (state.toolbarButtons.size > 0) return true;\r\n\r\n // Check if light DOM has header elements\r\n if (state.lightDomButtons.length > 0 || state.lightDomHeaderContent.length > 0) return true;\r\n\r\n return false;\r\n}\r\n\r\n/**\r\n * Render the shell header HTML.\r\n */\r\nexport function renderShellHeader(config: ShellConfig | undefined, state: ShellState): string {\r\n const title = config?.header?.title ?? '';\r\n const hasTitle = !!title;\r\n\r\n // Collect all toolbar buttons in order\r\n // 1. Config buttons (sorted by order)\r\n // 2. API-registered buttons (sorted by order)\r\n // 3. Light DOM buttons via slot\r\n // 4. Panel toggle buttons (sorted by order)\r\n\r\n const configButtons = config?.header?.toolbarButtons ?? [];\r\n const hasConfigButtons = configButtons.length > 0;\r\n const hasApiButtons = state.toolbarButtons.size > 0;\r\n const hasLightDomButtons = state.lightDomButtons.length > 0;\r\n const hasPanelToggles = state.toolPanels.size > 0;\r\n const hasCustomButtons = hasConfigButtons || hasApiButtons || hasLightDomButtons;\r\n const showSeparator = hasCustomButtons && hasPanelToggles;\r\n\r\n // Sort config buttons by order\r\n const sortedConfigButtons = [...configButtons].sort((a, b) => (a.order ?? 100) - (b.order ?? 100));\r\n\r\n // Sort API buttons by order\r\n const sortedApiButtons = [...state.toolbarButtons.values()].sort((a, b) => (a.order ?? 100) - (b.order ?? 100));\r\n\r\n // Sort panel toggles by order\r\n const sortedPanels = [...state.toolPanels.values()].sort((a, b) => (a.order ?? 100) - (b.order ?? 100));\r\n\r\n // Build toolbar HTML\r\n let toolbarHtml = '';\r\n\r\n // Config buttons with icon/action (grid renders these)\r\n for (const btn of sortedConfigButtons) {\r\n if (btn.icon && btn.action) {\r\n toolbarHtml += `<button class=\"tbw-toolbar-btn\" data-btn=\"${btn.id}\" title=\"${btn.label}\" aria-label=\"${\r\n btn.label\r\n }\"${btn.disabled ? ' disabled' : ''}>${btn.icon}</button>`;\r\n }\r\n }\r\n\r\n // API buttons with icon/action\r\n for (const btn of sortedApiButtons) {\r\n if (btn.icon && btn.action) {\r\n toolbarHtml += `<button class=\"tbw-toolbar-btn\" data-btn=\"${btn.id}\" title=\"${btn.label}\" aria-label=\"${\r\n btn.label\r\n }\"${btn.disabled ? ' disabled' : ''}>${btn.icon}</button>`;\r\n }\r\n }\r\n\r\n // Placeholders for config/API buttons with element or render function\r\n for (const btn of sortedConfigButtons) {\r\n if (btn.element || btn.render) {\r\n toolbarHtml += `<div class=\"tbw-toolbar-btn-slot\" data-btn-slot=\"${btn.id}\"></div>`;\r\n }\r\n }\r\n for (const btn of sortedApiButtons) {\r\n if (btn.element || btn.render) {\r\n toolbarHtml += `<div class=\"tbw-toolbar-btn-slot\" data-btn-slot=\"${btn.id}\"></div>`;\r\n }\r\n }\r\n\r\n // Light DOM slot\r\n if (hasLightDomButtons) {\r\n toolbarHtml += '<slot name=\"toolbar\"></slot>';\r\n }\r\n\r\n // Separator\r\n if (showSeparator) {\r\n toolbarHtml += '<div class=\"tbw-toolbar-separator\"></div>';\r\n }\r\n\r\n // Panel toggle buttons\r\n for (const panel of sortedPanels) {\r\n const isActive = state.activePanel === panel.id;\r\n toolbarHtml += `<button class=\"tbw-toolbar-btn${isActive ? ' active' : ''}\" data-panel=\"${panel.id}\" title=\"${\r\n panel.tooltip ?? panel.title\r\n }\" aria-label=\"${panel.tooltip ?? panel.title}\" aria-pressed=\"${isActive}\" aria-controls=\"tbw-panel-${panel.id}\">${\r\n panel.icon\r\n }</button>`;\r\n }\r\n\r\n return `\r\n <div class=\"tbw-shell-header\" part=\"shell-header\" role=\"banner\">\r\n ${hasTitle ? `<div class=\"tbw-shell-title\">${title}</div>` : ''}\r\n <div class=\"tbw-shell-content\" part=\"shell-content\" role=\"region\" aria-label=\"Grid information\">\r\n <slot name=\"header-content\"></slot>\r\n </div>\r\n <div class=\"tbw-shell-toolbar\" part=\"shell-toolbar\" role=\"toolbar\" aria-label=\"Grid tools\">\r\n ${toolbarHtml}\r\n </div>\r\n </div>\r\n `;\r\n}\r\n\r\n/**\r\n * Render the shell body wrapper HTML (contains grid content + tool panel).\r\n */\r\nexport function renderShellBody(config: ShellConfig | undefined, state: ShellState, gridContentHtml: string): string {\r\n const position = config?.toolPanel?.position ?? 'right';\r\n const hasPanel = state.toolPanels.size > 0;\r\n const isOpen = state.activePanel !== null;\r\n const activePanel = state.activePanel ? state.toolPanels.get(state.activePanel) : null;\r\n\r\n const panelHtml = hasPanel\r\n ? `\r\n <aside class=\"tbw-tool-panel${\r\n isOpen ? ' open' : ''\r\n }\" part=\"tool-panel\" data-position=\"${position}\" role=\"complementary\" aria-label=\"${\r\n activePanel?.title ?? 'Tool panel'\r\n }\" id=\"tbw-panel-${state.activePanel ?? 'closed'}\">\r\n <div class=\"tbw-tool-panel-header\">\r\n <span class=\"tbw-tool-panel-title\">${activePanel?.title ?? ''}</span>\r\n <button class=\"tbw-tool-panel-close\" aria-label=\"Close panel\">✕</button>\r\n </div>\r\n <div class=\"tbw-tool-panel-content\" role=\"region\"></div>\r\n </aside>\r\n `\r\n : '';\r\n\r\n // For left position, panel comes before content in DOM order\r\n if (position === 'left') {\r\n return `\r\n <div class=\"tbw-shell-body\">\r\n ${panelHtml}\r\n <div class=\"tbw-grid-content\">\r\n ${gridContentHtml}\r\n </div>\r\n </div>\r\n `;\r\n }\r\n\r\n return `\r\n <div class=\"tbw-shell-body\">\r\n <div class=\"tbw-grid-content\">\r\n ${gridContentHtml}\r\n </div>\r\n ${panelHtml}\r\n </div>\r\n `;\r\n}\r\n\r\n/**\r\n * Parse light DOM shell elements (tbw-grid-header, etc.).\r\n */\r\nexport function parseLightDomShell(host: HTMLElement, state: ShellState): void {\r\n const headerEl = host.querySelector('tbw-grid-header');\r\n if (!headerEl) return;\r\n\r\n // Hide the light DOM container\r\n (headerEl as HTMLElement).style.display = 'none';\r\n\r\n // Parse header content elements\r\n const headerContents = headerEl.querySelectorAll('tbw-grid-header-content');\r\n state.lightDomHeaderContent = Array.from(headerContents) as HTMLElement[];\r\n\r\n // Assign slot names for slotting into shadow DOM\r\n state.lightDomHeaderContent.forEach((el, i) => {\r\n el.setAttribute('slot', 'header-content');\r\n });\r\n\r\n // Parse toolbar button elements\r\n const toolButtons = headerEl.querySelectorAll('tbw-grid-tool-button');\r\n state.lightDomButtons = Array.from(toolButtons) as HTMLElement[];\r\n\r\n // Sort by order attribute and assign slots\r\n state.lightDomButtons.sort((a, b) => {\r\n const orderA = parseInt(a.getAttribute('order') ?? '100', 10);\r\n const orderB = parseInt(b.getAttribute('order') ?? '100', 10);\r\n return orderA - orderB;\r\n });\r\n\r\n state.lightDomButtons.forEach((el) => {\r\n el.setAttribute('slot', 'toolbar');\r\n });\r\n}\r\n\r\n/**\r\n * Set up event listeners for shell toolbar buttons.\r\n */\r\nexport function setupShellEventListeners(\r\n shadowRoot: ShadowRoot,\r\n config: ShellConfig | undefined,\r\n state: ShellState,\r\n callbacks: {\r\n onPanelToggle: (panelId: string) => void;\r\n onPanelClose: () => void;\r\n onToolbarButtonClick: (buttonId: string) => void;\r\n }\r\n): void {\r\n const toolbar = shadowRoot.querySelector('.tbw-shell-toolbar');\r\n if (toolbar) {\r\n toolbar.addEventListener('click', (e) => {\r\n const target = e.target as HTMLElement;\r\n const btn = target.closest('[data-panel]') as HTMLElement | null;\r\n if (btn) {\r\n const panelId = btn.getAttribute('data-panel');\r\n if (panelId) {\r\n callbacks.onPanelToggle(panelId);\r\n }\r\n return;\r\n }\r\n\r\n const customBtn = target.closest('[data-btn]') as HTMLElement | null;\r\n if (customBtn) {\r\n const btnId = customBtn.getAttribute('data-btn');\r\n if (btnId) {\r\n callbacks.onToolbarButtonClick(btnId);\r\n }\r\n }\r\n });\r\n }\r\n\r\n const closeBtn = shadowRoot.querySelector('.tbw-tool-panel-close');\r\n if (closeBtn) {\r\n closeBtn.addEventListener('click', () => {\r\n callbacks.onPanelClose();\r\n });\r\n }\r\n}\r\n\r\n/**\r\n * Render custom button elements/render functions into toolbar slots.\r\n */\r\nexport function renderCustomToolbarButtons(\r\n shadowRoot: ShadowRoot,\r\n config: ShellConfig | undefined,\r\n state: ShellState\r\n): void {\r\n const allButtons = [...(config?.header?.toolbarButtons ?? []), ...state.toolbarButtons.values()];\r\n\r\n for (const btn of allButtons) {\r\n const slot = shadowRoot.querySelector(`[data-btn-slot=\"${btn.id}\"]`);\r\n if (!slot) continue;\r\n\r\n // Clean up previous render if any\r\n const existingCleanup = state.toolbarButtonCleanups.get(btn.id);\r\n if (existingCleanup) {\r\n existingCleanup();\r\n state.toolbarButtonCleanups.delete(btn.id);\r\n }\r\n\r\n if (btn.element) {\r\n slot.appendChild(btn.element);\r\n } else if (btn.render) {\r\n const cleanup = btn.render(slot as HTMLElement);\r\n if (cleanup) {\r\n state.toolbarButtonCleanups.set(btn.id, cleanup);\r\n }\r\n }\r\n }\r\n}\r\n\r\n/**\r\n * Render header content from plugins into the shell content area.\r\n */\r\nexport function renderHeaderContent(shadowRoot: ShadowRoot, state: ShellState): void {\r\n const contentArea = shadowRoot.querySelector('.tbw-shell-content');\r\n if (!contentArea) return;\r\n\r\n // Sort by order\r\n const sortedContents = [...state.headerContents.values()].sort((a, b) => (a.order ?? 100) - (b.order ?? 100));\r\n\r\n // Create containers for each content piece (before the slot)\r\n const slot = contentArea.querySelector('slot[name=\"header-content\"]');\r\n\r\n for (const content of sortedContents) {\r\n // Clean up previous render if any\r\n const existingCleanup = state.headerContentCleanups.get(content.id);\r\n if (existingCleanup) {\r\n existingCleanup();\r\n state.headerContentCleanups.delete(content.id);\r\n }\r\n\r\n // Check if container already exists\r\n let container = contentArea.querySelector(`[data-header-content=\"${content.id}\"]`) as HTMLElement | null;\r\n if (!container) {\r\n container = document.createElement('div');\r\n container.setAttribute('data-header-content', content.id);\r\n // Insert before the slot\r\n if (slot) {\r\n contentArea.insertBefore(container, slot);\r\n } else {\r\n contentArea.appendChild(container);\r\n }\r\n }\r\n\r\n const cleanup = content.render(container);\r\n if (cleanup) {\r\n state.headerContentCleanups.set(content.id, cleanup);\r\n }\r\n }\r\n}\r\n\r\n/**\r\n * Render tool panel content when panel opens.\r\n */\r\nexport function renderPanelContent(shadowRoot: ShadowRoot, state: ShellState): void {\r\n if (!state.activePanel) return;\r\n\r\n const panel = state.toolPanels.get(state.activePanel);\r\n if (!panel) return;\r\n\r\n const contentArea = shadowRoot.querySelector('.tbw-tool-panel-content');\r\n if (!contentArea) return;\r\n\r\n // Clean up previous panel content\r\n if (state.activePanelCleanup) {\r\n state.activePanelCleanup();\r\n state.activePanelCleanup = null;\r\n }\r\n\r\n // Clear content area\r\n contentArea.innerHTML = '';\r\n\r\n // Render new content\r\n const cleanup = panel.render(contentArea as HTMLElement);\r\n if (cleanup) {\r\n state.activePanelCleanup = cleanup;\r\n }\r\n}\r\n\r\n/**\r\n * Update toolbar button active states.\r\n */\r\nexport function updateToolbarActiveStates(shadowRoot: ShadowRoot, state: ShellState): void {\r\n const buttons = shadowRoot.querySelectorAll('[data-panel]');\r\n buttons.forEach((btn) => {\r\n const panelId = btn.getAttribute('data-panel');\r\n const isActive = panelId === state.activePanel;\r\n btn.classList.toggle('active', isActive);\r\n btn.setAttribute('aria-pressed', String(isActive));\r\n });\r\n}\r\n\r\n/**\r\n * Update tool panel open/close state.\r\n */\r\nexport function updatePanelState(shadowRoot: ShadowRoot, state: ShellState): void {\r\n const panel = shadowRoot.querySelector('.tbw-tool-panel');\r\n if (!panel) return;\r\n\r\n const isOpen = state.activePanel !== null;\r\n panel.classList.toggle('open', isOpen);\r\n\r\n if (isOpen && state.activePanel) {\r\n const panelDef = state.toolPanels.get(state.activePanel);\r\n const titleEl = panel.querySelector('.tbw-tool-panel-title');\r\n if (titleEl) {\r\n titleEl.textContent = panelDef?.title ?? '';\r\n }\r\n panel.setAttribute('aria-label', `${panelDef?.title ?? 'Tool'} panel`);\r\n panel.id = `tbw-panel-${state.activePanel}`;\r\n }\r\n}\r\n\r\n/**\r\n * Get all toolbar button info.\r\n */\r\nexport function getToolbarButtonsInfo(config: ShellConfig | undefined, state: ShellState): ToolbarButtonInfo[] {\r\n const result: ToolbarButtonInfo[] = [];\r\n\r\n // Config buttons\r\n for (const btn of config?.header?.toolbarButtons ?? []) {\r\n result.push({\r\n id: btn.id,\r\n label: btn.label,\r\n disabled: btn.disabled ?? false,\r\n source: 'config',\r\n });\r\n }\r\n\r\n // API buttons\r\n for (const btn of state.toolbarButtons.values()) {\r\n result.push({\r\n id: btn.id,\r\n label: btn.label,\r\n disabled: btn.disabled ?? false,\r\n source: 'config',\r\n });\r\n }\r\n\r\n // Light DOM buttons (limited info since user provides DOM)\r\n for (let i = 0; i < state.lightDomButtons.length; i++) {\r\n const el = state.lightDomButtons[i];\r\n const btn = el.querySelector('button');\r\n result.push({\r\n id: `light-dom-${i}`,\r\n label: btn?.getAttribute('title') ?? btn?.getAttribute('aria-label') ?? '',\r\n disabled: btn?.disabled ?? false,\r\n source: 'light-dom',\r\n });\r\n }\r\n\r\n // Panel toggles\r\n for (const panel of state.toolPanels.values()) {\r\n result.push({\r\n id: `panel-toggle-${panel.id}`,\r\n label: panel.tooltip ?? panel.title,\r\n disabled: false,\r\n source: 'panel-toggle',\r\n panelId: panel.id,\r\n });\r\n }\r\n\r\n return result;\r\n}\r\n\r\n/**\r\n * Cleanup all shell state when grid disconnects.\r\n */\r\nexport function cleanupShellState(state: ShellState): void {\r\n // Clean up header content\r\n for (const cleanup of state.headerContentCleanups.values()) {\r\n cleanup();\r\n }\r\n state.headerContentCleanups.clear();\r\n\r\n // Clean up active panel\r\n if (state.activePanelCleanup) {\r\n state.activePanelCleanup();\r\n state.activePanelCleanup = null;\r\n }\r\n\r\n // Clean up toolbar buttons\r\n for (const cleanup of state.toolbarButtonCleanups.values()) {\r\n cleanup();\r\n }\r\n state.toolbarButtonCleanups.clear();\r\n\r\n // Invoke panel onClose if open\r\n if (state.activePanel) {\r\n const panel = state.toolPanels.get(state.activePanel);\r\n panel?.onClose?.();\r\n }\r\n\r\n // Clear registrations\r\n state.toolPanels.clear();\r\n state.headerContents.clear();\r\n state.toolbarButtons.clear();\r\n state.lightDomButtons = [];\r\n state.lightDomHeaderContent = [];\r\n state.activePanel = null;\r\n}\r\n","/**\r\n * Plugin Manager\r\n *\r\n * Manages plugin instances for a single grid.\r\n * Each grid has its own PluginManager with its own set of plugin instances.\r\n */\r\n\r\nimport type { ColumnConfig } from '../types';\r\nimport type {\r\n BaseGridPlugin,\r\n CellClickEvent,\r\n CellEditor,\r\n CellMouseEvent,\r\n CellRenderer,\r\n ContextMenuItem,\r\n ContextMenuParams,\r\n HeaderClickEvent,\r\n HeaderRenderer,\r\n RowClickEvent,\r\n ScrollEvent,\r\n} from './base-plugin';\r\n\r\n/**\r\n * Manages plugins for a single grid instance.\r\n */\r\nexport class PluginManager {\r\n /** Plugin instances in order of attachment */\r\n private plugins: BaseGridPlugin[] = [];\r\n\r\n /** Map from plugin class to instance for fast lookup */\r\n private pluginMap: Map<new (...args: unknown[]) => BaseGridPlugin, BaseGridPlugin> = new Map();\r\n\r\n /** Cell renderers registered by plugins */\r\n private cellRenderers: Map<string, CellRenderer> = new Map();\r\n\r\n /** Header renderers registered by plugins */\r\n private headerRenderers: Map<string, HeaderRenderer> = new Map();\r\n\r\n /** Cell editors registered by plugins */\r\n private cellEditors: Map<string, CellEditor> = new Map();\r\n\r\n constructor(private grid: any) {}\r\n\r\n /**\r\n * Attach all plugins from the config.\r\n */\r\n attachAll(plugins: BaseGridPlugin[]): void {\r\n for (const plugin of plugins) {\r\n this.attach(plugin);\r\n }\r\n }\r\n\r\n /**\r\n * Attach a plugin to this grid.\r\n */\r\n attach(plugin: BaseGridPlugin): void {\r\n // Store by constructor for type-safe lookup\r\n this.pluginMap.set(plugin.constructor as new (...args: unknown[]) => BaseGridPlugin, plugin);\r\n this.plugins.push(plugin);\r\n\r\n // Register renderers/editors\r\n if (plugin.cellRenderers) {\r\n for (const [type, renderer] of Object.entries(plugin.cellRenderers)) {\r\n this.cellRenderers.set(type, renderer);\r\n }\r\n }\r\n if (plugin.headerRenderers) {\r\n for (const [type, renderer] of Object.entries(plugin.headerRenderers)) {\r\n this.headerRenderers.set(type, renderer);\r\n }\r\n }\r\n if (plugin.cellEditors) {\r\n for (const [type, editor] of Object.entries(plugin.cellEditors)) {\r\n this.cellEditors.set(type, editor);\r\n }\r\n }\r\n\r\n // Call attach lifecycle method\r\n plugin.attach(this.grid);\r\n }\r\n\r\n /**\r\n * Detach all plugins and clean up.\r\n */\r\n detachAll(): void {\r\n // Detach in reverse order\r\n for (let i = this.plugins.length - 1; i >= 0; i--) {\r\n this.plugins[i].detach();\r\n }\r\n this.plugins = [];\r\n this.pluginMap.clear();\r\n this.cellRenderers.clear();\r\n this.headerRenderers.clear();\r\n this.cellEditors.clear();\r\n }\r\n\r\n /**\r\n * Get a plugin instance by its class.\r\n */\r\n getPlugin<T extends BaseGridPlugin>(PluginClass: new (...args: any[]) => T): T | undefined {\r\n return this.pluginMap.get(PluginClass) as T | undefined;\r\n }\r\n\r\n /**\r\n * Get a plugin instance by its name.\r\n */\r\n getPluginByName(name: string): BaseGridPlugin | undefined {\r\n return this.plugins.find((p) => p.name === name);\r\n }\r\n\r\n /**\r\n * Check if a plugin is attached.\r\n */\r\n hasPlugin<T extends BaseGridPlugin>(PluginClass: new (...args: any[]) => T): boolean {\r\n return this.pluginMap.has(PluginClass);\r\n }\r\n\r\n /**\r\n * Get all attached plugins.\r\n */\r\n getAll(): readonly BaseGridPlugin[] {\r\n return this.plugins;\r\n }\r\n\r\n /**\r\n * Get a cell renderer by type name.\r\n */\r\n getCellRenderer(type: string): CellRenderer | undefined {\r\n return this.cellRenderers.get(type);\r\n }\r\n\r\n /**\r\n * Get a header renderer by type name.\r\n */\r\n getHeaderRenderer(type: string): HeaderRenderer | undefined {\r\n return this.headerRenderers.get(type);\r\n }\r\n\r\n /**\r\n * Get a cell editor by type name.\r\n */\r\n getCellEditor(type: string): CellEditor | undefined {\r\n return this.cellEditors.get(type);\r\n }\r\n\r\n /**\r\n * Get all CSS styles from all plugins.\r\n */\r\n getAllStyles(): string {\r\n return this.plugins\r\n .filter((p) => p.styles)\r\n .map((p) => p.styles)\r\n .join('\\n');\r\n }\r\n\r\n // ===== Hook execution methods =====\r\n\r\n /**\r\n * Execute processRows hook on all plugins.\r\n */\r\n processRows(rows: readonly any[]): any[] {\r\n let result = [...rows];\r\n for (const plugin of this.plugins) {\r\n if (plugin.processRows) {\r\n result = plugin.processRows(result);\r\n }\r\n }\r\n return result;\r\n }\r\n\r\n /**\r\n * Execute processColumns hook on all plugins.\r\n */\r\n processColumns(columns: readonly ColumnConfig[]): ColumnConfig[] {\r\n let result = [...columns];\r\n for (const plugin of this.plugins) {\r\n if (plugin.processColumns) {\r\n result = plugin.processColumns(result);\r\n }\r\n }\r\n return result;\r\n }\r\n\r\n /**\r\n * Execute beforeRender hook on all plugins.\r\n */\r\n beforeRender(): void {\r\n for (const plugin of this.plugins) {\r\n plugin.beforeRender?.();\r\n }\r\n }\r\n\r\n /**\r\n * Execute afterRender hook on all plugins.\r\n */\r\n afterRender(): void {\r\n for (const plugin of this.plugins) {\r\n plugin.afterRender?.();\r\n }\r\n }\r\n\r\n /**\r\n * Execute renderRow hook on all plugins.\r\n * Returns true if any plugin handled the row.\r\n */\r\n renderRow(row: any, rowEl: HTMLElement, rowIndex: number): boolean {\r\n for (const plugin of this.plugins) {\r\n if (plugin.renderRow?.(row, rowEl, rowIndex)) {\r\n return true;\r\n }\r\n }\r\n return false;\r\n }\r\n\r\n /**\r\n * Execute onKeyDown hook on all plugins.\r\n * Returns true if any plugin handled the event.\r\n */\r\n onKeyDown(event: KeyboardEvent): boolean {\r\n for (const plugin of this.plugins) {\r\n if (plugin.onKeyDown?.(event)) {\r\n return true;\r\n }\r\n }\r\n return false;\r\n }\r\n\r\n /**\r\n * Execute onCellClick hook on all plugins.\r\n * Returns true if any plugin handled the event.\r\n */\r\n onCellClick(event: CellClickEvent): boolean {\r\n for (const plugin of this.plugins) {\r\n if (plugin.onCellClick?.(event)) {\r\n return true;\r\n }\r\n }\r\n return false;\r\n }\r\n\r\n /**\r\n * Execute onRowClick hook on all plugins.\r\n * Returns true if any plugin handled the event.\r\n */\r\n onRowClick(event: RowClickEvent): boolean {\r\n for (const plugin of this.plugins) {\r\n if (plugin.onRowClick?.(event)) {\r\n return true;\r\n }\r\n }\r\n return false;\r\n }\r\n\r\n /**\r\n * Execute onHeaderClick hook on all plugins.\r\n * Returns true if any plugin handled the event.\r\n */\r\n onHeaderClick(event: HeaderClickEvent): boolean {\r\n for (const plugin of this.plugins) {\r\n if (plugin.onHeaderClick?.(event)) {\r\n return true;\r\n }\r\n }\r\n return false;\r\n }\r\n\r\n /**\r\n * Execute onScroll hook on all plugins.\r\n */\r\n onScroll(event: ScrollEvent): void {\r\n for (const plugin of this.plugins) {\r\n plugin.onScroll?.(event);\r\n }\r\n }\r\n\r\n /**\r\n * Execute onCellMouseDown hook on all plugins.\r\n * Returns true if any plugin handled the event.\r\n */\r\n onCellMouseDown(event: CellMouseEvent): boolean {\r\n for (const plugin of this.plugins) {\r\n if (plugin.onCellMouseDown?.(event)) {\r\n return true;\r\n }\r\n }\r\n return false;\r\n }\r\n\r\n /**\r\n * Execute onCellMouseMove hook on all plugins.\r\n * Returns true if any plugin handled the event.\r\n */\r\n onCellMouseMove(event: CellMouseEvent): boolean {\r\n for (const plugin of this.plugins) {\r\n if (plugin.onCellMouseMove?.(event)) {\r\n return true;\r\n }\r\n }\r\n return false;\r\n }\r\n\r\n /**\r\n * Execute onCellMouseUp hook on all plugins.\r\n * Returns true if any plugin handled the event.\r\n */\r\n onCellMouseUp(event: CellMouseEvent): boolean {\r\n for (const plugin of this.plugins) {\r\n if (plugin.onCellMouseUp?.(event)) {\r\n return true;\r\n }\r\n }\r\n return false;\r\n }\r\n\r\n /**\r\n * Collect context menu items from all plugins.\r\n */\r\n getContextMenuItems(params: ContextMenuParams): ContextMenuItem[] {\r\n const items: ContextMenuItem[] = [];\r\n for (const plugin of this.plugins) {\r\n const pluginItems = plugin.getContextMenuItems?.(params);\r\n if (pluginItems) {\r\n items.push(...pluginItems);\r\n }\r\n }\r\n return items;\r\n }\r\n\r\n // ===== Shell Integration Hooks =====\r\n\r\n /**\r\n * Collect tool panels from all plugins.\r\n * Returns panels sorted by order (ascending).\r\n */\r\n getToolPanels(): {\r\n plugin: BaseGridPlugin;\r\n panel: NonNullable<ReturnType<NonNullable<BaseGridPlugin['getToolPanel']>>>;\r\n }[] {\r\n const panels: {\r\n plugin: BaseGridPlugin;\r\n panel: NonNullable<ReturnType<NonNullable<BaseGridPlugin['getToolPanel']>>>;\r\n }[] = [];\r\n for (const plugin of this.plugins) {\r\n const panel = plugin.getToolPanel?.();\r\n if (panel) {\r\n panels.push({ plugin, panel });\r\n }\r\n }\r\n // Sort by order (ascending), default to 0\r\n return panels.sort((a, b) => (a.panel.order ?? 0) - (b.panel.order ?? 0));\r\n }\r\n\r\n /**\r\n * Collect header contents from all plugins.\r\n * Returns contents sorted by order (ascending).\r\n */\r\n getHeaderContents(): {\r\n plugin: BaseGridPlugin;\r\n content: NonNullable<ReturnType<NonNullable<BaseGridPlugin['getHeaderContent']>>>;\r\n }[] {\r\n const contents: {\r\n plugin: BaseGridPlugin;\r\n content: NonNullable<ReturnType<NonNullable<BaseGridPlugin['getHeaderContent']>>>;\r\n }[] = [];\r\n for (const plugin of this.plugins) {\r\n const content = plugin.getHeaderContent?.();\r\n if (content) {\r\n contents.push({ plugin, content });\r\n }\r\n }\r\n // Sort by order (ascending), default to 0\r\n return contents.sort((a, b) => (a.content.order ?? 0) - (b.content.order ?? 0));\r\n }\r\n}\r\n","import styles from './grid.css?inline';\r\nimport { applyColumnState, collectColumnState, createStateChangeHandler } from './internal/column-state';\r\nimport { autoSizeColumns, getColumnConfiguration, updateTemplate } from './internal/columns';\r\nimport { exitRowEdit, startRowEdit } from './internal/editing';\r\nimport { renderHeader } from './internal/header';\r\nimport { inferColumns } from './internal/inference';\r\nimport { handleGridKeyDown } from './internal/keyboard';\r\nimport { createResizeController } from './internal/resize';\r\nimport { invalidateCellCache, renderVisibleRows } from './internal/rows';\r\nimport {\r\n cleanupShellState,\r\n createShellState,\r\n getToolbarButtonsInfo,\r\n parseLightDomShell,\r\n renderCustomToolbarButtons,\r\n renderHeaderContent,\r\n renderPanelContent,\r\n renderShellBody,\r\n renderShellHeader,\r\n setupShellEventListeners,\r\n shouldRenderShellHeader,\r\n updatePanelState,\r\n updateToolbarActiveStates,\r\n type ShellState,\r\n} from './internal/shell';\r\nimport type { CellMouseEvent, ScrollEvent } from './plugin';\r\nimport type { BaseGridPlugin, CellClickEvent, HeaderClickEvent } from './plugin/base-plugin';\r\nimport { PluginManager } from './plugin/plugin-manager';\r\nimport type {\r\n ActivateCellDetail,\r\n CellCommitDetail,\r\n ColumnConfig,\r\n ColumnConfigMap,\r\n ColumnInternal,\r\n ColumnResizeDetail,\r\n FitMode,\r\n GridColumnState,\r\n GridConfig,\r\n HeaderContentDefinition,\r\n InternalGrid,\r\n ResizeController,\r\n RowCommitDetail,\r\n SortChangeDetail,\r\n ToolbarButtonConfig,\r\n ToolbarButtonInfo,\r\n ToolPanelDefinition,\r\n VirtualState,\r\n} from './types';\r\n\r\n/**\r\n * High-performance data grid web component.\r\n * During migration, uses tbw-grid tag to avoid conflicts with existing datagrid.\r\n * Will be renamed back to data-grid when migration is complete.\r\n *\r\n * ## Configuration Architecture\r\n *\r\n * The grid follows a **single source of truth** pattern where all configuration\r\n * converges into `#effectiveConfig`. Users can set configuration via multiple inputs:\r\n *\r\n * **Input Sources (precedence low → high):**\r\n * 1. `gridConfig` property - base configuration object\r\n * 2. Light DOM elements:\r\n * - `<tbw-grid-column>` → `effectiveConfig.columns`\r\n * - `<tbw-grid-header title=\"...\">` → `effectiveConfig.shell.header.title`\r\n * - `<tbw-grid-header-content>` → `effectiveConfig.shell.header.content`\r\n * 3. `columns` property → merged into `effectiveConfig.columns`\r\n * 4. `fitMode` property → merged into `effectiveConfig.fitMode`\r\n * 5. `editOn` property → merged into `effectiveConfig.editOn`\r\n * 6. Column inference from first row (if no columns defined)\r\n *\r\n * **Derived State:**\r\n * - `_columns` - processed columns from `effectiveConfig.columns` after plugin hooks\r\n * - `_rows` - processed rows after plugin hooks (grouping, filtering, etc.)\r\n *\r\n * The `#mergeEffectiveConfig()` method is the single place where all inputs converge.\r\n * All rendering and logic should read from `effectiveConfig` or derived state.\r\n *\r\n * @element tbw-grid\r\n *\r\n * @csspart container - The main grid container\r\n * @csspart header - The header row container\r\n * @csspart body - The body/rows container\r\n *\r\n * @fires cell-commit - Fired when a cell value is committed\r\n * @fires row-commit - Fired when a bulk row edit session commits\r\n * @fires changed-rows-reset - Fired after resetChangedRows() unless silent\r\n * @fires mount-external-view - Fired to request mounting of an external view renderer\r\n * @fires mount-external-editor - Fired to request mounting of an external editor renderer\r\n * @fires sort-change - Fired when sort state changes for a column\r\n * @fires column-resize - Fired after a column resize drag completes\r\n * @fires activate-cell - Fired when a cell activation intent occurs\r\n * @fires group-toggle - Fired when a group row is toggled\r\n *\r\n * @cssprop --tbw-color-bg - Background color\r\n * @cssprop --tbw-color-fg - Foreground/text color\r\n */\r\nexport class DataGridElement<T = any> extends HTMLElement implements InternalGrid<T> {\r\n // TODO: Rename to 'data-grid' when migration is complete\r\n static readonly tagName = 'tbw-grid';\r\n\r\n readonly #shadow: ShadowRoot;\r\n #initialized = false;\r\n\r\n // ---------------- Ready Promise ----------------\r\n #readyPromise: Promise<void>;\r\n #readyResolve?: () => void;\r\n\r\n // ================== INPUT PROPERTIES ==================\r\n // These backing fields store raw user input. They are merged into\r\n // #effectiveConfig by #mergeEffectiveConfig(). Never read directly\r\n // for rendering logic - always use effectiveConfig or derived state.\r\n #rows: T[] = [];\r\n #columns?: ColumnConfig<T>[] | ColumnConfigMap<T>;\r\n #gridConfig?: GridConfig<T>;\r\n #fitMode?: FitMode;\r\n #editOn?: string;\r\n\r\n // ================== SINGLE SOURCE OF TRUTH ==================\r\n // All input sources converge here. This is the canonical config\r\n // that all rendering and logic should read from.\r\n #effectiveConfig: GridConfig<T> = {};\r\n #connected = false;\r\n #scrollRaf = 0;\r\n #pendingScrollTop: number | null = null;\r\n #hasScrollPlugins = false; // Cached flag for plugin scroll handlers\r\n #renderRowHook?: (row: any, rowEl: HTMLElement, rowIndex: number) => boolean; // Cached hook to avoid closures\r\n #boundEsc?: (e: KeyboardEvent) => void;\r\n #boundOutside?: (e: MouseEvent) => void;\r\n #isDragging = false;\r\n #boundMouseMove?: (e: MouseEvent) => void;\r\n #boundMouseUp?: (e: MouseEvent) => void;\r\n\r\n // ---------------- Plugin System ----------------\r\n #pluginManager!: PluginManager;\r\n\r\n // ---------------- Column State ----------------\r\n #stateChangeHandler?: () => void;\r\n #initialColumnState?: GridColumnState;\r\n\r\n // ---------------- Shell State ----------------\r\n #shellState: ShellState = createShellState();\r\n #shellInitialized = false;\r\n\r\n // ================== DERIVED STATE ==================\r\n // _rows: result of applying plugin processRows hooks\r\n _rows: T[] = [];\r\n\r\n // _columns is a getter/setter that operates on effectiveConfig.columns\r\n // This ensures effectiveConfig.columns is the single source of truth for columns\r\n // _columns always contains ALL columns (including hidden)\r\n get _columns(): ColumnInternal<T>[] {\r\n return (this.#effectiveConfig.columns ?? []) as ColumnInternal<T>[];\r\n }\r\n set _columns(value: ColumnInternal<T>[]) {\r\n this.#effectiveConfig.columns = value as ColumnConfig<T>[];\r\n }\r\n\r\n // visibleColumns returns only visible columns for rendering\r\n // This is what header/row rendering should use\r\n get visibleColumns(): ColumnInternal<T>[] {\r\n return this._columns.filter((c) => !c.hidden);\r\n }\r\n\r\n // ================== RUNTIME STATE ==================\r\n // User-driven state changes at runtime (sort, etc.)\r\n // Visibility is stored in effectiveConfig.columns[].hidden\r\n rowPool: HTMLElement[] = [];\r\n __rowRenderEpoch = 0;\r\n activeEditRows = -1;\r\n resizeController!: ResizeController;\r\n __didInitialAutoSize = false;\r\n __lightDomColumnsCache?: ColumnInternal[];\r\n __originalColumnNodes?: HTMLElement[];\r\n headerRowEl!: HTMLElement;\r\n bodyEl!: HTMLElement;\r\n virtualization: VirtualState = {\r\n enabled: true,\r\n rowHeight: 28, // Initial state - will recalculate after first render\r\n bypassThreshold: 24, // Skip virtualization if <= this many rows (saves overhead)\r\n start: 0,\r\n end: 0,\r\n container: null, // Faux scrollbar element\r\n viewportEl: null, // Rows viewport for measuring visible height\r\n totalHeightEl: null, // Spacer for virtual height\r\n };\r\n sortState: { field: string; direction: 1 | -1 } | null = null;\r\n __originalOrder: T[] = [];\r\n focusRow = 0;\r\n focusCol = 0;\r\n gridTemplate = '';\r\n rowEditSnapshots = new Map<number, T>();\r\n _changedRowIndices = new Set<number>();\r\n\r\n // ---------------- Public API Props (getters/setters) ----------------\r\n // Getters return the EFFECTIVE value (after merging), not the raw input.\r\n // This is what consumers and plugins need - the current resolved state.\r\n // Setters update input properties which trigger re-merge into effectiveConfig.\r\n\r\n get rows(): T[] {\r\n return this._rows;\r\n }\r\n set rows(value: T[]) {\r\n const oldValue = this.#rows;\r\n this.#rows = value;\r\n if (oldValue !== value) {\r\n this.#onRowsChanged();\r\n }\r\n }\r\n\r\n /**\r\n * Get the original unfiltered/unprocessed rows.\r\n * Use this when you need access to all source data regardless of active filters.\r\n */\r\n get sourceRows(): T[] {\r\n return this.#rows;\r\n }\r\n\r\n get columns(): ColumnConfig<T>[] {\r\n return [...this._columns] as ColumnConfig<T>[];\r\n }\r\n set columns(value: ColumnConfig<T>[] | ColumnConfigMap<T> | undefined) {\r\n const oldValue = this.#columns;\r\n this.#columns = value;\r\n if (oldValue !== value) {\r\n this.#onColsChanged();\r\n }\r\n }\r\n\r\n get gridConfig(): GridConfig<T> {\r\n return this.#effectiveConfig;\r\n }\r\n set gridConfig(value: GridConfig<T> | undefined) {\r\n const oldValue = this.#gridConfig;\r\n this.#gridConfig = value;\r\n if (oldValue !== value) {\r\n this.#onGridConfigChanged();\r\n }\r\n }\r\n\r\n get fitMode(): FitMode {\r\n return this.#effectiveConfig.fitMode ?? 'stretch';\r\n }\r\n set fitMode(value: FitMode | undefined) {\r\n const oldValue = this.#fitMode;\r\n this.#fitMode = value;\r\n if (oldValue !== value) {\r\n this.#onFitChanged();\r\n }\r\n }\r\n\r\n get editOn(): string | undefined {\r\n return this.#effectiveConfig.editOn;\r\n }\r\n set editOn(value: string | undefined) {\r\n const oldValue = this.#editOn;\r\n this.#editOn = value;\r\n if (oldValue !== value) {\r\n this.#onEditModeChanged();\r\n }\r\n }\r\n\r\n // Effective config accessor for internal modules and plugins\r\n // Returns the merged config (single source of truth) before plugin processing\r\n // Use this when you need the raw merged config (e.g., for column definitions including hidden)\r\n get effectiveConfig(): GridConfig<T> {\r\n return this.#effectiveConfig;\r\n }\r\n\r\n constructor() {\r\n super();\r\n this.#shadow = this.attachShadow({ mode: 'open' });\r\n this.#injectStyles();\r\n this.#readyPromise = new Promise((res) => (this.#readyResolve = res));\r\n }\r\n\r\n #injectStyles(): void {\r\n const sheet = new CSSStyleSheet();\r\n sheet.replaceSync(styles);\r\n this.#shadow.adoptedStyleSheets = [sheet];\r\n }\r\n\r\n // ---------------- Plugin System ----------------\r\n\r\n /**\r\n * Get a plugin instance by its class.\r\n * Used by plugins for inter-plugin communication.\r\n */\r\n getPlugin<P extends BaseGridPlugin>(PluginClass: new (...args: any[]) => P): P | undefined {\r\n return this.#pluginManager?.getPlugin(PluginClass);\r\n }\r\n\r\n /**\r\n * Get a plugin instance by its name.\r\n * Used for loose coupling between plugins (avoids static imports).\r\n */\r\n getPluginByName(name: string): BaseGridPlugin | undefined {\r\n return this.#pluginManager?.getPluginByName(name);\r\n }\r\n\r\n /**\r\n * Request a full re-render of the grid.\r\n * Called by plugins when they need the grid to update.\r\n * Note: This does NOT reset plugin state - just re-processes rows/columns and renders.\r\n */\r\n requestRender(): void {\r\n this.#rebuildRowModel();\r\n this.#processColumns();\r\n this.#renderHeader();\r\n this.updateTemplate();\r\n this.refreshVirtualWindow(true);\r\n }\r\n\r\n /**\r\n * Request a lightweight style update without rebuilding DOM.\r\n * Called by plugins when they only need to update CSS classes/styles.\r\n * This runs all plugin afterRender hooks without rebuilding row/column DOM.\r\n */\r\n requestAfterRender(): void {\r\n this.#executeAfterRender();\r\n }\r\n\r\n /**\r\n * Initialize plugin system with instances from config.\r\n * Plugins are class instances passed in gridConfig.plugins[].\r\n */\r\n #initializePlugins(): void {\r\n // Create plugin manager for this grid\r\n this.#pluginManager = new PluginManager(this);\r\n\r\n // Get plugin instances from config - ensure it's an array\r\n const pluginsConfig = this.#effectiveConfig?.plugins;\r\n const plugins = Array.isArray(pluginsConfig) ? (pluginsConfig as BaseGridPlugin[]) : [];\r\n\r\n // Attach all plugins\r\n this.#pluginManager.attachAll(plugins);\r\n }\r\n\r\n /**\r\n * Inject all plugin styles into the shadow DOM.\r\n * Must be called after #render() since innerHTML wipes existing content.\r\n */\r\n #injectAllPluginStyles(): void {\r\n const allStyles = this.#pluginManager?.getAllStyles() ?? '';\r\n if (allStyles) {\r\n const styleEl = document.createElement('style');\r\n styleEl.setAttribute('data-plugin', 'all');\r\n styleEl.textContent = allStyles;\r\n this.#shadow.appendChild(styleEl);\r\n }\r\n }\r\n\r\n /**\r\n * Update plugins when grid config changes.\r\n * With class-based plugins, we need to detach old and attach new.\r\n */\r\n #updatePluginConfigs(): void {\r\n // With class-based plugins, config changes require re-initialization\r\n // The new plugins are in the new config - detach old, attach new\r\n if (this.#pluginManager) {\r\n this.#pluginManager.detachAll();\r\n }\r\n this.#initializePlugins();\r\n this.#injectAllPluginStyles();\r\n // Update cached scroll plugin flag\r\n this.#hasScrollPlugins = this.#pluginManager?.getAll().some((p) => p.onScroll) ?? false;\r\n }\r\n\r\n /**\r\n * Clean up plugin states when grid disconnects.\r\n */\r\n #destroyPlugins(): void {\r\n this.#pluginManager?.detachAll();\r\n }\r\n\r\n /**\r\n * Collect tool panels and header content from all plugins.\r\n * Called after plugins are attached but before render.\r\n */\r\n #collectPluginShellContributions(): void {\r\n if (!this.#pluginManager) return;\r\n\r\n // Collect tool panels from plugins\r\n const pluginPanels = this.#pluginManager.getToolPanels();\r\n for (const { panel } of pluginPanels) {\r\n // Skip if already registered (light DOM or API takes precedence)\r\n if (!this.#shellState.toolPanels.has(panel.id)) {\r\n this.#shellState.toolPanels.set(panel.id, panel);\r\n }\r\n }\r\n\r\n // Collect header contents from plugins\r\n const pluginContents = this.#pluginManager.getHeaderContents();\r\n for (const { content } of pluginContents) {\r\n // Skip if already registered (light DOM or API takes precedence)\r\n if (!this.#shellState.headerContents.has(content.id)) {\r\n this.#shellState.headerContents.set(content.id, content);\r\n }\r\n }\r\n }\r\n\r\n // ---------------- Lifecycle ----------------\r\n connectedCallback(): void {\r\n if (!this.hasAttribute('tabindex')) (this as any).tabIndex = 0;\r\n this._rows = Array.isArray(this.#rows) ? [...this.#rows] : [];\r\n\r\n // Merge all config sources into effectiveConfig (including columns)\r\n this.#mergeEffectiveConfig();\r\n\r\n // Initialize plugin system\r\n this.#initializePlugins();\r\n\r\n // Collect tool panels and header content from plugins (must be before render)\r\n this.#collectPluginShellContributions();\r\n\r\n if (!this.#initialized) {\r\n this.#render();\r\n this.#injectAllPluginStyles(); // Inject plugin styles after render\r\n this.#initialized = true;\r\n }\r\n this.#afterConnect();\r\n }\r\n\r\n disconnectedCallback(): void {\r\n // Clean up plugin states\r\n this.#destroyPlugins();\r\n\r\n // Clean up shell state\r\n cleanupShellState(this.#shellState);\r\n this.#shellInitialized = false;\r\n\r\n if (this.#boundEsc) {\r\n document.removeEventListener('keydown', this.#boundEsc, true);\r\n this.#boundEsc = undefined;\r\n }\r\n if (this.#boundOutside) {\r\n document.removeEventListener('mousedown', this.#boundOutside, false);\r\n this.#boundOutside = undefined;\r\n }\r\n if (this.#boundMouseMove) {\r\n document.removeEventListener('mousemove', this.#boundMouseMove);\r\n this.#boundMouseMove = undefined;\r\n }\r\n if (this.#boundMouseUp) {\r\n document.removeEventListener('mouseup', this.#boundMouseUp);\r\n this.#boundMouseUp = undefined;\r\n }\r\n if (this.resizeController) {\r\n this.resizeController.dispose();\r\n }\r\n this.#connected = false;\r\n }\r\n\r\n #afterConnect(): void {\r\n // Shell changes the DOM structure - need to find elements appropriately\r\n const gridContent = this.#shadow.querySelector('.tbw-grid-content');\r\n const gridRoot = gridContent ?? this.#shadow.querySelector('.tbw-grid-root');\r\n\r\n this.headerRowEl = gridRoot?.querySelector('.header-row') as HTMLElement;\r\n // Faux scrollbar pattern:\r\n // - .faux-vscroll-spacer sets virtual height\r\n // - .rows-viewport provides visible height for virtualization calculations\r\n this.virtualization.totalHeightEl = gridRoot?.querySelector('.faux-vscroll-spacer') as HTMLElement;\r\n this.virtualization.viewportEl = gridRoot?.querySelector('.rows-viewport') as HTMLElement;\r\n this.bodyEl = gridRoot?.querySelector('.rows') as HTMLElement;\r\n\r\n // Initialize shell header content and custom buttons if shell is active\r\n if (this.#shellInitialized) {\r\n // Render plugin header content\r\n renderHeaderContent(this.#shadow, this.#shellState);\r\n // Render custom toolbar buttons (element/render modes)\r\n renderCustomToolbarButtons(this.#shadow, this.#effectiveConfig?.shell, this.#shellState);\r\n // Open default panel if configured\r\n const defaultOpen = this.#effectiveConfig?.shell?.toolPanel?.defaultOpen;\r\n if (defaultOpen && this.#shellState.toolPanels.has(defaultOpen)) {\r\n this.openToolPanel(defaultOpen);\r\n }\r\n }\r\n\r\n // Mark for tests that afterConnect ran\r\n this.setAttribute('data-upgraded', '');\r\n if (!this.hasAttribute('role')) this.setAttribute('role', 'grid');\r\n this.#connected = true;\r\n\r\n // Run setup\r\n this.#setup();\r\n\r\n this.addEventListener('keydown', (e) => handleGridKeyDown(this as any, e));\r\n\r\n // Global listeners\r\n if (!this.#boundEsc) {\r\n this.#boundEsc = (e: KeyboardEvent) => {\r\n if (e.key === 'Escape' && this.activeEditRows !== -1) {\r\n this.#exitRowEdit(this.activeEditRows, true);\r\n }\r\n };\r\n document.addEventListener('keydown', this.#boundEsc, true);\r\n }\r\n\r\n if (!this.#boundOutside) {\r\n this.#boundOutside = (e: MouseEvent) => {\r\n if (this.activeEditRows === -1) return;\r\n const rowEl = this.findRenderedRowElement(this.activeEditRows);\r\n if (!rowEl) return;\r\n const path = (e.composedPath && e.composedPath()) || [];\r\n if (path.includes(rowEl)) return;\r\n this.#exitRowEdit(this.activeEditRows, false);\r\n };\r\n document.addEventListener('mousedown', this.#boundOutside, false);\r\n }\r\n\r\n // Faux scrollbar pattern: scroll events come from the fake scrollbar element\r\n // Content area doesn't scroll - rows are positioned via transforms\r\n // This prevents blank viewport: old content stays until transforms are updated\r\n // Reuse gridRoot from earlier in this function\r\n const fauxScrollbar = gridRoot?.querySelector('.faux-vscroll') as HTMLElement;\r\n const rowsEl = gridRoot?.querySelector('.rows') as HTMLElement;\r\n\r\n // Store reference for scroll position reading in refreshVirtualWindow\r\n this.virtualization.container = fauxScrollbar ?? this;\r\n\r\n // Cache whether any plugin has scroll handlers (checked once during setup)\r\n this.#hasScrollPlugins = this.#pluginManager?.getAll().some((p) => p.onScroll) ?? false;\r\n\r\n if (fauxScrollbar && rowsEl) {\r\n fauxScrollbar.addEventListener(\r\n 'scroll',\r\n () => {\r\n // Fast exit if no scroll processing needed\r\n if (!this.virtualization.enabled && !this.#hasScrollPlugins) return;\r\n\r\n const currentScrollTop = fauxScrollbar.scrollTop;\r\n const rowHeight = this.virtualization.rowHeight;\r\n\r\n // Smooth scroll: apply sub-pixel offset immediately\r\n // This creates fluid motion as user scrolls, before RAF updates content\r\n // The offset is the remainder after dividing by rowHeight\r\n const subPixelOffset = -(currentScrollTop % rowHeight);\r\n rowsEl.style.transform = `translateY(${subPixelOffset}px)`;\r\n\r\n // Batch content update with requestAnimationFrame\r\n // Old content stays visible with smooth offset until new content renders\r\n this.#pendingScrollTop = currentScrollTop;\r\n if (!this.#scrollRaf) {\r\n this.#scrollRaf = requestAnimationFrame(() => {\r\n this.#scrollRaf = 0;\r\n if (this.#pendingScrollTop !== null) {\r\n this.#onScrollBatched(this.#pendingScrollTop);\r\n this.#pendingScrollTop = null;\r\n }\r\n });\r\n }\r\n },\r\n { passive: true }\r\n );\r\n\r\n // Forward wheel events from content area to faux scrollbar\r\n // Without this, mouse wheel over content wouldn't scroll\r\n const rowsBody = gridRoot?.querySelector('.rows-body') as HTMLElement;\r\n if (rowsBody) {\r\n rowsBody.addEventListener(\r\n 'wheel',\r\n (e: WheelEvent) => {\r\n // Prevent default to stop any residual scroll behavior\r\n e.preventDefault();\r\n // Apply wheel delta to faux scrollbar\r\n fauxScrollbar.scrollTop += e.deltaY;\r\n },\r\n { passive: false }\r\n );\r\n }\r\n }\r\n\r\n this.resizeController = createResizeController(this as any);\r\n\r\n // Central mouse event handling for plugins\r\n this.#shadow.addEventListener('mousedown', (e) => this.#handleMouseDown(e as MouseEvent));\r\n\r\n // Track global mousemove/mouseup for drag operations\r\n if (!this.#boundMouseMove) {\r\n this.#boundMouseMove = (e: MouseEvent) => this.#handleMouseMove(e);\r\n document.addEventListener('mousemove', this.#boundMouseMove);\r\n }\r\n if (!this.#boundMouseUp) {\r\n this.#boundMouseUp = (e: MouseEvent) => this.#handleMouseUp(e);\r\n document.addEventListener('mouseup', this.#boundMouseUp);\r\n }\r\n\r\n if (this.virtualization.enabled) {\r\n requestAnimationFrame(() => this.refreshVirtualWindow(true));\r\n }\r\n\r\n // Measure actual row height after first paint for accurate spacer sizing\r\n requestAnimationFrame(() => {\r\n const firstRow = this.bodyEl.querySelector('.data-grid-row');\r\n if (firstRow) {\r\n const h = (firstRow as HTMLElement).getBoundingClientRect().height;\r\n if (h && Math.abs(h - this.virtualization.rowHeight) > 0.1) {\r\n this.virtualization.rowHeight = h;\r\n this.refreshVirtualWindow(true);\r\n }\r\n }\r\n });\r\n\r\n // Initialize ARIA selection state\r\n queueMicrotask(() => this.#updateAriaSelection());\r\n\r\n requestAnimationFrame(() => requestAnimationFrame(() => this.#readyResolve?.()));\r\n }\r\n\r\n // ---------------- Event Emitters ----------------\r\n #emit<D>(eventName: string, detail: D): void {\r\n this.dispatchEvent(new CustomEvent(eventName, { detail, bubbles: true, composed: true }));\r\n }\r\n\r\n emitCellCommit(detail: CellCommitDetail<T>): void {\r\n this.#emit('cell-commit', detail);\r\n }\r\n\r\n emitRowCommit(detail: RowCommitDetail<T>): void {\r\n this.#emit('row-commit', detail);\r\n }\r\n\r\n emitSortChange(detail: SortChangeDetail): void {\r\n this.#emit('sort-change', detail);\r\n }\r\n\r\n emitColumnResize(detail: ColumnResizeDetail): void {\r\n this.#emit('column-resize', detail);\r\n }\r\n\r\n emitActivateCell(detail: ActivateCellDetail): void {\r\n this.#emit('activate-cell', detail);\r\n }\r\n\r\n /** Update ARIA selection attributes on rendered rows/cells */\r\n #updateAriaSelection(): void {\r\n // Mark active row and cell with aria-selected\r\n const rows = this.bodyEl?.querySelectorAll('.data-grid-row');\r\n rows?.forEach((row, rowIdx) => {\r\n const isActiveRow = rowIdx === this.focusRow;\r\n row.setAttribute('aria-selected', String(isActiveRow));\r\n row.querySelectorAll('.cell').forEach((cell, colIdx) => {\r\n (cell as HTMLElement).setAttribute('aria-selected', String(isActiveRow && colIdx === this.focusCol));\r\n });\r\n });\r\n }\r\n\r\n // ---------------- Watch Handlers ----------------\r\n #onFitChanged(): void {\r\n if (!this.#connected) return;\r\n this.#mergeEffectiveConfig();\r\n const mode = this.#effectiveConfig.fitMode;\r\n if (mode === 'fixed') {\r\n this.__didInitialAutoSize = false;\r\n this.#autoSizeColumns();\r\n } else {\r\n this._columns.forEach((c: any) => {\r\n if (!c.__userResized && c.__autoSized) delete c.width;\r\n });\r\n this.updateTemplate();\r\n }\r\n }\r\n\r\n #onEditModeChanged(): void {\r\n if (!this.#connected) return;\r\n this.#mergeEffectiveConfig();\r\n this.rowPool.length = 0;\r\n if (this.bodyEl) this.bodyEl.innerHTML = '';\r\n this.__rowRenderEpoch++;\r\n this.refreshVirtualWindow(true);\r\n }\r\n\r\n #onRowsChanged(): void {\r\n this._rows = Array.isArray(this.#rows) ? [...this.#rows] : [];\r\n this.#rebuildRowModel();\r\n // If no explicit columns provided, trigger full setup so inference runs\r\n if (!this.#columns || (Array.isArray(this.#columns) && this.#columns.length === 0)) {\r\n this.#setup();\r\n } else {\r\n this.refreshVirtualWindow(true);\r\n }\r\n }\r\n\r\n #onColsChanged(): void {\r\n // Invalidate caches that depend on column configuration\r\n invalidateCellCache(this as unknown as any);\r\n\r\n // Re-merge config and setup - _columns will be set through effectiveConfig\r\n if (this.#connected) {\r\n this.#mergeEffectiveConfig();\r\n this.#setup();\r\n }\r\n }\r\n\r\n #onGridConfigChanged(): void {\r\n if (!this.#connected) return;\r\n this.#mergeEffectiveConfig();\r\n this.#updatePluginConfigs(); // Sync plugin configs with new grid config\r\n this.#rebuildRowModel();\r\n this.#processColumns(); // Process columns after rows for tree plugin\r\n this.#renderHeader();\r\n this.updateTemplate();\r\n this.refreshVirtualWindow(true);\r\n }\r\n\r\n // ---------------- Helper Wrappers ----------------\r\n #getColumnConfiguration(): void {\r\n getColumnConfiguration(this as unknown as any);\r\n }\r\n\r\n #renderHeader(): void {\r\n renderHeader(this as unknown as any);\r\n // Grouped header cell classes are applied by plugins via afterRender\r\n }\r\n\r\n updateTemplate(): void {\r\n updateTemplate(this as unknown as any);\r\n }\r\n\r\n #autoSizeColumns(): void {\r\n autoSizeColumns(this as unknown as any);\r\n }\r\n\r\n #processColumns(): void {\r\n // Let plugins process visible columns (column grouping, etc.)\r\n // Note: _columns always contains ALL columns; plugins work on visible subset\r\n if (this.#pluginManager) {\r\n // Get visible columns for plugin processing\r\n const visibleCols = this._columns.filter((c) => !c.hidden);\r\n const processedColumns = this.#pluginManager.processColumns([...visibleCols] as any[]);\r\n\r\n // If plugins modified visible columns, update them in place preserving hidden column positions\r\n if (processedColumns !== visibleCols) {\r\n // Build a map of processed columns by field for quick lookup\r\n const processedMap = new Map(processedColumns.map((c: any, i: number) => [c.field, { col: c, order: i }]));\r\n\r\n // Update visible columns in _columns with their processed versions\r\n // Hidden columns keep their original position\r\n const updatedColumns = this._columns.map((c) => {\r\n if (c.hidden) return c; // Keep hidden columns unchanged\r\n const processed = processedMap.get(c.field);\r\n return processed ? processed.col : c;\r\n });\r\n\r\n this._columns = updatedColumns as ColumnInternal<T>[];\r\n }\r\n }\r\n }\r\n\r\n /** Execute all plugin afterRender hooks */\r\n #executeAfterRender(): void {\r\n this.#pluginManager?.afterRender();\r\n }\r\n\r\n /** Recompute row model via plugin hooks (grouping, tree, filtering, etc.). */\r\n #rebuildRowModel(): void {\r\n // Invalidate cell display value cache - rows are changing\r\n invalidateCellCache(this as unknown as any);\r\n\r\n // Start fresh from original rows (plugins will transform them)\r\n const originalRows = Array.isArray(this.#rows) ? [...this.#rows] : [];\r\n\r\n // Let plugins process rows (row grouping, tree, filtering, etc.)\r\n // Plugins can transform the rows array, adding markers like __isGroupRow\r\n // The renderRow hook will handle rendering specialized row types\r\n const processedRows = this.#pluginManager?.processRows(originalRows) ?? originalRows;\r\n\r\n // Store processed rows for rendering\r\n // Note: processedRows may contain group markers that plugins handle via renderRow hook\r\n this._rows = processedRows as T[];\r\n }\r\n\r\n /**\r\n * Build the canonical effective configuration by merging all input sources.\r\n *\r\n * This is the **single source of truth** for the grid's configuration.\r\n * All inputs (gridConfig, light DOM, individual props) converge here.\r\n *\r\n * **Precedence (lowest → highest):**\r\n * 1. `gridConfig` property - base config object\r\n * 2. Light DOM `<tbw-grid-column>` elements - declarative columns\r\n * 3. `columns` property - programmatic columns override\r\n * 4. Inferred columns - auto-detected from row data\r\n * 5. Individual props (`fitMode`, `editOn`) - convenience overrides\r\n *\r\n * After this method runs:\r\n * - `#effectiveConfig` contains the merged result\r\n * - `_columns` is NOT set here (done by #getColumnConfiguration + #processColumns)\r\n * - Plugins receive config via their attach() method\r\n */\r\n #mergeEffectiveConfig(): void {\r\n const base: GridConfig<T> = this.#gridConfig ? { ...this.#gridConfig } : {};\r\n let columns: ColumnConfig<T>[] = Array.isArray(base.columns) ? [...base.columns] : [];\r\n\r\n // Light DOM cached parse (if already parsed by columns pipeline); non-invasive merge (fill gaps only)\r\n const domCols: ColumnConfig<T>[] = ((this as any).__lightDomColumnsCache || []).map((c: ColumnConfig<T>) => ({\r\n ...c,\r\n }));\r\n if (domCols.length) {\r\n const map: Record<string, ColumnConfig<T>> = {};\r\n columns.forEach((c) => (map[(c as any).field] = c));\r\n domCols.forEach((c: any) => {\r\n const exist = map[c.field];\r\n if (!exist) {\r\n columns.push(c);\r\n map[c.field] = c;\r\n } else {\r\n if (c.header && !exist.header) exist.header = c.header;\r\n if (c.type && !exist.type) exist.type = c.type;\r\n exist.sortable = exist.sortable || c.sortable;\r\n if (c.resizable) exist.resizable = true;\r\n if (c.editable) exist.editable = true;\r\n }\r\n });\r\n }\r\n\r\n // Columns prop highest structural precedence\r\n if (this.#columns && (this.#columns as ColumnConfig<T>[]).length) {\r\n columns = [...(this.#columns as ColumnConfig<T>[])];\r\n }\r\n\r\n // Inference if still empty\r\n if ((!columns || columns.length === 0) && this._rows.length) {\r\n const result = inferColumns(this._rows as Record<string, unknown>[]);\r\n columns = result.columns as ColumnConfig<T>[];\r\n }\r\n\r\n if (columns.length) {\r\n // Apply per-column defaults (sortable/resizable default true unless explicitly false)\r\n columns.forEach((c) => {\r\n if (c.sortable === undefined) c.sortable = true;\r\n if (c.resizable === undefined) c.resizable = true;\r\n });\r\n // Preserve processed columns (with __compiledView etc.) if already set by #getColumnConfiguration\r\n // Only set base.columns if effectiveConfig.columns is empty or doesn't have compiled templates\r\n const existingCols = this.#effectiveConfig.columns as ColumnInternal<T>[] | undefined;\r\n const alreadyProcessed = existingCols?.some((c) => c.__compiledView || c.__compiledEditor);\r\n if (alreadyProcessed) {\r\n // Keep existing processed columns\r\n base.columns = existingCols as ColumnConfig<T>[];\r\n } else {\r\n base.columns = columns;\r\n }\r\n } else {\r\n // No new columns computed, but preserve existing if processed\r\n const existingCols = this.#effectiveConfig.columns as ColumnInternal<T>[] | undefined;\r\n if (existingCols?.some((c) => c.__compiledView || c.__compiledEditor)) {\r\n base.columns = existingCols as ColumnConfig<T>[];\r\n }\r\n }\r\n\r\n // Individual prop overrides (behavioral)\r\n if (this.#fitMode) base.fitMode = this.#fitMode;\r\n if (!base.fitMode) base.fitMode = 'stretch';\r\n if (this.#editOn) base.editOn = this.#editOn;\r\n\r\n // Store columnState from gridConfig if not already set\r\n if (base.columnState && !this.#initialColumnState) {\r\n this.#initialColumnState = base.columnState;\r\n }\r\n\r\n this.#effectiveConfig = base;\r\n // Note: _columns is a getter/setter for effectiveConfig.columns\r\n // #getColumnConfiguration() populates it, and we preserve those processed columns above\r\n // Plugins (like ReorderPlugin) modify effectiveConfig.columns via the _columns setter\r\n\r\n // If fixed mode and width not specified: assign default 80px\r\n if (base.fitMode === 'fixed') {\r\n this._columns.forEach((c) => {\r\n if (c.width == null) (c as ColumnConfig<T>).width = 80;\r\n });\r\n }\r\n }\r\n\r\n // ---------------- Delegate Wrappers ----------------\r\n #renderVisibleRows(start: number, end: number, epoch = this.__rowRenderEpoch): void {\r\n // Use cached hook to avoid creating closures on every render (hot path optimization)\r\n if (!this.#renderRowHook) {\r\n this.#renderRowHook = (row: any, rowEl: HTMLElement, rowIndex: number): boolean => {\r\n return this.#pluginManager?.renderRow(row, rowEl, rowIndex) ?? false;\r\n };\r\n }\r\n renderVisibleRows(this as any, start, end, epoch, this.#renderRowHook);\r\n }\r\n\r\n #startRowEdit(rowIndex: number, rowData: any): void {\r\n startRowEdit(this as unknown as any, rowIndex, rowData);\r\n }\r\n\r\n #exitRowEdit(rowIndex: number, revert: boolean): void {\r\n exitRowEdit(this as unknown as any, rowIndex, revert);\r\n }\r\n\r\n // ---------------- Core Helpers ----------------\r\n #setup(): void {\r\n if (!this.isConnected) return;\r\n if (!this.headerRowEl || !this.bodyEl) {\r\n return;\r\n }\r\n\r\n // Seed effectiveConfig.columns from config sources before getColumnConfiguration\r\n // This ensures columns from gridConfig/columns prop are available for merging with light DOM\r\n // Preserve hidden state from existing columns (visibility is runtime state)\r\n const configCols = (this.#gridConfig?.columns || this.#columns || []) as ColumnConfig<T>[];\r\n if (configCols.length) {\r\n // Preserve hidden state from existing effectiveConfig.columns\r\n const existingHiddenMap = new Map(this._columns.filter((c) => c.hidden).map((c) => [c.field, true]));\r\n const seeded = configCols.map((c) => ({\r\n ...c,\r\n hidden: existingHiddenMap.get(c.field) ?? c.hidden,\r\n }));\r\n this._columns = seeded as ColumnInternal<T>[];\r\n }\r\n\r\n this.#getColumnConfiguration();\r\n this.#mergeEffectiveConfig();\r\n this.#updatePluginConfigs(); // Sync plugin configs (including auto-detection) before processing\r\n this.#rebuildRowModel(); // Runs processRows hooks (must run before processColumns for tree plugin)\r\n this.#processColumns(); // Runs processColumns hooks\r\n\r\n // Apply initial column state (from gridConfig.columnState or columnState setter)\r\n if (this.#initialColumnState) {\r\n const state = this.#initialColumnState;\r\n this.#initialColumnState = undefined; // Clear to avoid re-applying\r\n this.#applyColumnStateInternal(state);\r\n }\r\n\r\n this.#renderHeader();\r\n this.updateTemplate();\r\n this.refreshVirtualWindow(true);\r\n\r\n const mode = this.#effectiveConfig.fitMode;\r\n if (mode === 'fixed' && !this.__didInitialAutoSize) {\r\n requestAnimationFrame(() => this.#autoSizeColumns());\r\n }\r\n\r\n // Ensure legacy inline grid styles are cleared from container\r\n if (this.bodyEl) {\r\n this.bodyEl.style.display = '';\r\n this.bodyEl.style.gridTemplateColumns = '';\r\n }\r\n\r\n // Run plugin afterRender hooks (column groups, sticky, etc.)\r\n queueMicrotask(() => this.#executeAfterRender());\r\n }\r\n\r\n /** Internal method to apply column state without triggering setup loop */\r\n #applyColumnStateInternal(state: GridColumnState): void {\r\n // Get all columns from effectiveConfig (single source of truth)\r\n const allCols = (this.#effectiveConfig.columns ?? []) as ColumnInternal<T>[];\r\n\r\n const plugins = (this.#pluginManager?.getAll() ?? []) as BaseGridPlugin[];\r\n applyColumnState(this, state, allCols, plugins);\r\n\r\n // Update hidden property on columns based on state\r\n for (const colState of state.columns) {\r\n const col = allCols.find((c) => c.field === colState.field);\r\n if (col) {\r\n col.hidden = !colState.visible;\r\n }\r\n }\r\n }\r\n\r\n #shouldBypassVirtualization(): boolean {\r\n return this._rows.length <= this.virtualization.bypassThreshold;\r\n }\r\n\r\n #onScrollBatched(scrollTop: number): void {\r\n // Faux scrollbar pattern: content never scrolls, just update transforms\r\n // Old content stays visible until new transforms are applied\r\n this.refreshVirtualWindow(false);\r\n\r\n // Dispatch to plugins (using cached flag)\r\n if (this.#hasScrollPlugins) {\r\n const fauxScrollbar = this.virtualization.container;\r\n const scrollEvent: ScrollEvent = {\r\n scrollTop,\r\n scrollLeft: fauxScrollbar?.scrollLeft ?? 0,\r\n scrollHeight: fauxScrollbar?.scrollHeight ?? 0,\r\n scrollWidth: fauxScrollbar?.scrollWidth ?? 0,\r\n clientHeight: fauxScrollbar?.clientHeight ?? 0,\r\n clientWidth: fauxScrollbar?.clientWidth ?? 0,\r\n originalEvent: new Event('scroll'),\r\n };\r\n this.#pluginManager?.onScroll(scrollEvent);\r\n }\r\n }\r\n\r\n findHeaderRow(): HTMLElement {\r\n return this.#shadow.querySelector('.header-row') as HTMLElement;\r\n }\r\n\r\n findRenderedRowElement(rowIndex: number): HTMLElement | null {\r\n return (\r\n (Array.from(this.bodyEl.querySelectorAll('.data-grid-row')) as HTMLElement[]).find((r) => {\r\n const cell = r.querySelector('.cell[data-row]');\r\n return cell && Number(cell.getAttribute('data-row')) === rowIndex;\r\n }) || null\r\n );\r\n }\r\n\r\n /**\r\n * Dispatch a cell click event to the plugin system.\r\n * Returns true if any plugin handled the event.\r\n */\r\n dispatchCellClick(event: MouseEvent, rowIndex: number, colIndex: number, cellEl: HTMLElement): boolean {\r\n const row = this._rows[rowIndex];\r\n const col = this._columns[colIndex];\r\n if (!row || !col) return false;\r\n\r\n const cellClickEvent: CellClickEvent = {\r\n row,\r\n rowIndex,\r\n colIndex,\r\n field: col.field,\r\n value: (row as any)[col.field],\r\n cellEl,\r\n originalEvent: event,\r\n };\r\n\r\n return this.#pluginManager?.onCellClick(cellClickEvent) ?? false;\r\n }\r\n\r\n /**\r\n * Dispatch a header click event to the plugin system.\r\n * Returns true if any plugin handled the event.\r\n */\r\n dispatchHeaderClick(event: MouseEvent, colIndex: number, headerEl: HTMLElement): boolean {\r\n const col = this._columns[colIndex];\r\n if (!col) return false;\r\n\r\n const headerClickEvent: HeaderClickEvent = {\r\n colIndex,\r\n field: col.field,\r\n column: col,\r\n headerEl,\r\n originalEvent: event,\r\n };\r\n\r\n return this.#pluginManager?.onHeaderClick(headerClickEvent) ?? false;\r\n }\r\n\r\n /**\r\n * Dispatch a keyboard event to the plugin system.\r\n * Returns true if any plugin handled the event.\r\n */\r\n dispatchKeyDown(event: KeyboardEvent): boolean {\r\n return this.#pluginManager?.onKeyDown(event) ?? false;\r\n }\r\n\r\n /**\r\n * Build a CellMouseEvent from a native MouseEvent.\r\n * Extracts cell/row information from the event target.\r\n */\r\n #buildCellMouseEvent(e: MouseEvent, type: 'mousedown' | 'mousemove' | 'mouseup'): CellMouseEvent {\r\n // For document-level events (mousemove/mouseup during drag), e.target won't be inside shadow DOM.\r\n // Use composedPath to find elements inside shadow roots, or fall back to elementFromPoint.\r\n let target: Element | null = null;\r\n\r\n // composedPath gives us the full path including shadow DOM elements\r\n const path = e.composedPath?.() as Element[] | undefined;\r\n if (path && path.length > 0) {\r\n target = path[0];\r\n } else {\r\n target = e.target as Element;\r\n }\r\n\r\n // If target is still not inside our shadow root (e.g., for document-level events),\r\n // use elementFromPoint to find the actual element under the mouse\r\n if (target && !this.#shadow.contains(target)) {\r\n const elAtPoint = this.#shadow.elementFromPoint(e.clientX, e.clientY);\r\n if (elAtPoint) {\r\n target = elAtPoint;\r\n }\r\n }\r\n\r\n // Cells have data-col and data-row attributes\r\n const cellEl = target?.closest?.('[data-col]') as HTMLElement | null;\r\n const rowEl = target?.closest?.('.data-grid-row') as HTMLElement | null;\r\n const headerEl = target?.closest?.('.header-row') as HTMLElement | null;\r\n\r\n let rowIndex: number | undefined;\r\n let colIndex: number | undefined;\r\n let row: T | undefined;\r\n let field: string | undefined;\r\n let value: unknown;\r\n let column: any;\r\n\r\n if (cellEl) {\r\n // Get indices from cell attributes\r\n rowIndex = parseInt(cellEl.getAttribute('data-row') ?? '-1', 10);\r\n colIndex = parseInt(cellEl.getAttribute('data-col') ?? '-1', 10);\r\n if (rowIndex >= 0 && colIndex >= 0) {\r\n row = this._rows[rowIndex];\r\n column = this._columns[colIndex];\r\n field = column?.field;\r\n value = row && field ? (row as any)[field] : undefined;\r\n }\r\n }\r\n\r\n return {\r\n type,\r\n row,\r\n rowIndex: rowIndex !== undefined && rowIndex >= 0 ? rowIndex : undefined,\r\n colIndex: colIndex !== undefined && colIndex >= 0 ? colIndex : undefined,\r\n field,\r\n value,\r\n column,\r\n originalEvent: e,\r\n cellElement: cellEl ?? undefined,\r\n rowElement: rowEl ?? undefined,\r\n isHeader: !!headerEl,\r\n cell:\r\n rowIndex !== undefined && colIndex !== undefined && rowIndex >= 0 && colIndex >= 0\r\n ? { row: rowIndex, col: colIndex }\r\n : undefined,\r\n };\r\n }\r\n\r\n /**\r\n * Handle mousedown events and dispatch to plugin system.\r\n */\r\n #handleMouseDown(e: MouseEvent): void {\r\n const event = this.#buildCellMouseEvent(e, 'mousedown');\r\n const handled = this.#pluginManager?.onCellMouseDown(event) ?? false;\r\n\r\n // If any plugin handled mousedown, start tracking for drag\r\n if (handled) {\r\n this.#isDragging = true;\r\n }\r\n }\r\n\r\n /**\r\n * Handle mousemove events (only when dragging).\r\n */\r\n #handleMouseMove(e: MouseEvent): void {\r\n if (!this.#isDragging) return;\r\n\r\n const event = this.#buildCellMouseEvent(e, 'mousemove');\r\n this.#pluginManager?.onCellMouseMove(event);\r\n }\r\n\r\n /**\r\n * Handle mouseup events.\r\n */\r\n #handleMouseUp(e: MouseEvent): void {\r\n if (!this.#isDragging) return;\r\n\r\n const event = this.#buildCellMouseEvent(e, 'mouseup');\r\n this.#pluginManager?.onCellMouseUp(event);\r\n this.#isDragging = false;\r\n }\r\n\r\n // API consumed by internal utils (rows.ts)\r\n get changedRows(): T[] {\r\n return Array.from(this._changedRowIndices).map((i) => this._rows[i]);\r\n }\r\n\r\n get changedRowIndices(): number[] {\r\n return Array.from(this._changedRowIndices);\r\n }\r\n\r\n async resetChangedRows(silent?: boolean): Promise<void> {\r\n this._changedRowIndices.clear();\r\n if (!silent) {\r\n this.#emit('changed-rows-reset', { rows: this.changedRows, indices: this.changedRowIndices });\r\n }\r\n this.rowPool.forEach((r) => r.classList.remove('changed'));\r\n }\r\n\r\n async beginBulkEdit(rowIndex: number): Promise<void> {\r\n this.#startRowEdit(rowIndex, this._rows[rowIndex]);\r\n }\r\n\r\n async commitActiveRowEdit(): Promise<void> {\r\n if (this.activeEditRows !== -1) {\r\n this.#exitRowEdit(this.activeEditRows, false);\r\n }\r\n }\r\n\r\n async ready(): Promise<void> {\r\n return this.#readyPromise;\r\n }\r\n\r\n async forceLayout(): Promise<void> {\r\n this.#setup();\r\n await new Promise((r) => requestAnimationFrame(() => requestAnimationFrame(r)));\r\n }\r\n\r\n /** Public method: returns a frozen snapshot of the merged effective configuration */\r\n async getConfig(): Promise<Readonly<GridConfig<T>>> {\r\n return Object.freeze({ ...(this.#effectiveConfig || {}) });\r\n }\r\n\r\n // ---------------- Column Visibility API ----------------\r\n\r\n /**\r\n * Set the visibility of a column.\r\n * @param field - The field name of the column\r\n * @param visible - Whether the column should be visible\r\n * @returns True if visibility was changed, false if column not found or locked\r\n */\r\n setColumnVisible(field: string, visible: boolean): boolean {\r\n // Find the column in effectiveConfig.columns (includes hidden columns)\r\n const allCols = this.#effectiveConfig.columns as ColumnInternal<T>[] | undefined;\r\n const col = allCols?.find((c) => c.field === field);\r\n\r\n // If column not found, cannot change visibility\r\n if (!col) return false;\r\n\r\n // Check lockVisible - cannot hide locked columns\r\n if (!visible && col.lockVisible) return false;\r\n\r\n // Check if at least one column would remain visible\r\n if (!visible) {\r\n const currentVisible = (allCols ?? []).filter((c) => !c.hidden && c.field !== field).length;\r\n if (currentVisible === 0) return false;\r\n }\r\n\r\n const wasHidden = !!col.hidden;\r\n const willBeHidden = !visible;\r\n\r\n // Only refresh if visibility actually changed\r\n if (wasHidden !== willBeHidden) {\r\n // Update the hidden property on the column in effectiveConfig\r\n col.hidden = willBeHidden;\r\n\r\n // Emit event for consumer preference saving\r\n this.#emit('column-visibility', {\r\n field,\r\n visible,\r\n visibleColumns: (allCols ?? []).filter((c) => !c.hidden).map((c) => c.field),\r\n });\r\n\r\n // Clear row pool to force complete rebuild with new column count\r\n this.rowPool.length = 0;\r\n if (this.bodyEl) this.bodyEl.innerHTML = '';\r\n this.__rowRenderEpoch++;\r\n\r\n // Re-setup to rebuild columns with updated visibility\r\n this.#setup();\r\n\r\n // Trigger state change after visibility change\r\n this.requestStateChange();\r\n return true;\r\n }\r\n return false;\r\n }\r\n\r\n /**\r\n * Toggle the visibility of a column.\r\n * @param field - The field name of the column\r\n * @returns True if visibility was toggled, false if column not found or locked\r\n */\r\n toggleColumnVisibility(field: string): boolean {\r\n const allCols = this.#effectiveConfig.columns as ColumnInternal<T>[] | undefined;\r\n const col = allCols?.find((c) => c.field === field);\r\n const isCurrentlyHidden = !!col?.hidden;\r\n return this.setColumnVisible(field, isCurrentlyHidden);\r\n }\r\n\r\n /**\r\n * Check if a column is currently visible.\r\n * @param field - The field name of the column\r\n * @returns True if visible, false if hidden or not found\r\n */\r\n isColumnVisible(field: string): boolean {\r\n const allCols = this.#effectiveConfig.columns as ColumnInternal<T>[] | undefined;\r\n const col = allCols?.find((c) => c.field === field);\r\n return col ? !col.hidden : false;\r\n }\r\n\r\n /**\r\n * Show all columns.\r\n */\r\n showAllColumns(): void {\r\n const allCols = this.#effectiveConfig.columns as ColumnInternal<T>[] | undefined;\r\n const hasHidden = allCols?.some((c) => c.hidden);\r\n if (!hasHidden) return;\r\n\r\n // Clear hidden flag on all columns\r\n allCols?.forEach((c) => {\r\n c.hidden = false;\r\n });\r\n\r\n this.#emit('column-visibility', {\r\n visibleColumns: (allCols ?? []).map((c) => c.field),\r\n });\r\n\r\n // Clear row pool to force complete rebuild with new column count\r\n this.rowPool.length = 0;\r\n if (this.bodyEl) this.bodyEl.innerHTML = '';\r\n this.__rowRenderEpoch++;\r\n\r\n this.#setup();\r\n\r\n // Trigger state change after visibility change\r\n this.requestStateChange();\r\n }\r\n\r\n /**\r\n * Get list of all column fields (including hidden).\r\n * Returns columns reflecting current display order (after reordering).\r\n * Hidden columns are interleaved at their original relative positions.\r\n * @returns Array of all field names with their visibility status\r\n */\r\n getAllColumns(): Array<{ field: string; header: string; visible: boolean; lockVisible?: boolean }> {\r\n // effectiveConfig.columns is the single source of truth\r\n const allCols = (this.#effectiveConfig.columns ?? []) as ColumnInternal<T>[];\r\n\r\n // Return all columns with their current visibility state\r\n return allCols.map((c) => ({\r\n field: c.field,\r\n header: c.header || c.field,\r\n visible: !c.hidden,\r\n lockVisible: c.lockVisible,\r\n }));\r\n }\r\n\r\n /**\r\n * Reorder columns according to the specified field order.\r\n * This directly updates _columns in place without going through processColumns.\r\n * @param order - Array of field names in the desired order\r\n */\r\n setColumnOrder(order: string[]): void {\r\n if (!order.length) return;\r\n\r\n const columnMap = new Map<string, ColumnInternal<T>>(this._columns.map((c) => [c.field as string, c]));\r\n const reordered: ColumnInternal<T>[] = [];\r\n\r\n // Add columns in specified order\r\n for (const field of order) {\r\n const col = columnMap.get(field);\r\n if (col) {\r\n reordered.push(col);\r\n columnMap.delete(field);\r\n }\r\n }\r\n\r\n // Add any remaining columns not in order\r\n for (const col of columnMap.values()) {\r\n reordered.push(col);\r\n }\r\n\r\n this._columns = reordered;\r\n\r\n // Re-render with new order\r\n this.#renderHeader();\r\n this.updateTemplate();\r\n this.refreshVirtualWindow(true);\r\n }\r\n\r\n /**\r\n * Get the current column order as an array of field names.\r\n * @returns Array of field names in display order\r\n */\r\n getColumnOrder(): string[] {\r\n return this._columns.map((c) => c.field);\r\n }\r\n\r\n // ---------------- Column State API ----------------\r\n\r\n /**\r\n * Get the current column state, including order, width, visibility, sort, and plugin state.\r\n * Returns a serializable object suitable for localStorage or database storage.\r\n */\r\n getColumnState(): GridColumnState {\r\n const plugins = this.#pluginManager?.getAll() ?? [];\r\n return collectColumnState(this, plugins as BaseGridPlugin[]);\r\n }\r\n\r\n /**\r\n * Set the column state, restoring order, width, visibility, sort, and plugin state.\r\n * Use this to restore previously saved column state.\r\n */\r\n set columnState(state: GridColumnState | undefined) {\r\n if (!state) return;\r\n\r\n // Store for use after initialization if called before ready\r\n this.#initialColumnState = state;\r\n\r\n // If already initialized, apply immediately\r\n if (this.#initialized) {\r\n this.#applyColumnState(state);\r\n }\r\n }\r\n\r\n /**\r\n * Get the current column state.\r\n */\r\n get columnState(): GridColumnState | undefined {\r\n return this.getColumnState();\r\n }\r\n\r\n /**\r\n * Apply column state internally.\r\n */\r\n #applyColumnState(state: GridColumnState): void {\r\n // Clear hidden flags before applying state\r\n const allCols = (this.#effectiveConfig.columns ?? []) as ColumnInternal<T>[];\r\n allCols.forEach((c) => {\r\n c.hidden = false;\r\n });\r\n\r\n this.#applyColumnStateInternal(state);\r\n\r\n // Re-setup to apply changes\r\n this.#setup();\r\n }\r\n\r\n /**\r\n * Request a state change event to be emitted.\r\n * Called internally after resize, reorder, visibility, or sort changes.\r\n * Plugins should call this after changing their state.\r\n * The event is debounced to avoid excessive events during drag operations.\r\n */\r\n requestStateChange(): void {\r\n if (!this.#stateChangeHandler) {\r\n this.#stateChangeHandler = createStateChangeHandler(\r\n this,\r\n () => (this.#pluginManager?.getAll() ?? []) as BaseGridPlugin[],\r\n (state) => this.#emit('column-state-change', state)\r\n );\r\n }\r\n this.#stateChangeHandler();\r\n }\r\n\r\n /**\r\n * Reset column state to initial configuration.\r\n * Clears all user modifications (order, width, visibility, sort).\r\n */\r\n resetColumnState(): void {\r\n // Clear initial state\r\n this.#initialColumnState = undefined;\r\n\r\n // Clear hidden flag on all columns\r\n const allCols = (this.#effectiveConfig.columns ?? []) as ColumnInternal<T>[];\r\n allCols.forEach((c) => {\r\n c.hidden = false;\r\n });\r\n\r\n // Reset sort state\r\n this.sortState = null;\r\n this.__originalOrder = [];\r\n\r\n // Re-initialize columns from config\r\n this.#mergeEffectiveConfig();\r\n this.#setup();\r\n\r\n // Notify plugins to reset their state\r\n const plugins = (this.#pluginManager?.getAll() ?? []) as BaseGridPlugin[];\r\n for (const plugin of plugins) {\r\n if (plugin.applyColumnState) {\r\n // Pass empty state to indicate reset\r\n for (const col of this._columns) {\r\n plugin.applyColumnState(col.field, {\r\n field: col.field,\r\n order: 0,\r\n visible: true,\r\n });\r\n }\r\n }\r\n }\r\n\r\n // Emit state change\r\n this.requestStateChange();\r\n }\r\n\r\n // ---------------- Shell / Tool Panel API ----------------\r\n\r\n /**\r\n * Get the currently active tool panel ID, or null if none is open.\r\n */\r\n get activeToolPanel(): string | null {\r\n return this.#shellState.activePanel;\r\n }\r\n\r\n /**\r\n * Open a tool panel by ID.\r\n * Closes any currently open panel first.\r\n */\r\n openToolPanel(panelId: string): void {\r\n const panel = this.#shellState.toolPanels.get(panelId);\r\n if (!panel) {\r\n console.warn(`[tbw-grid] Tool panel \"${panelId}\" not found`);\r\n return;\r\n }\r\n\r\n // Close current panel if different\r\n if (this.#shellState.activePanel && this.#shellState.activePanel !== panelId) {\r\n this.closeToolPanel();\r\n }\r\n\r\n // Set active panel\r\n this.#shellState.activePanel = panelId;\r\n\r\n // Update UI\r\n updateToolbarActiveStates(this.#shadow, this.#shellState);\r\n updatePanelState(this.#shadow, this.#shellState);\r\n\r\n // Render panel content\r\n renderPanelContent(this.#shadow, this.#shellState);\r\n\r\n // Emit event\r\n this.#emit('tool-panel-open', { id: panelId });\r\n }\r\n\r\n /**\r\n * Close the currently open tool panel.\r\n */\r\n closeToolPanel(): void {\r\n if (!this.#shellState.activePanel) return;\r\n\r\n const panelId = this.#shellState.activePanel;\r\n const panel = this.#shellState.toolPanels.get(panelId);\r\n\r\n // Clean up panel content\r\n if (this.#shellState.activePanelCleanup) {\r\n this.#shellState.activePanelCleanup();\r\n this.#shellState.activePanelCleanup = null;\r\n }\r\n\r\n // Call panel's onClose callback\r\n panel?.onClose?.();\r\n\r\n // Clear active panel\r\n this.#shellState.activePanel = null;\r\n\r\n // Update UI\r\n updateToolbarActiveStates(this.#shadow, this.#shellState);\r\n updatePanelState(this.#shadow, this.#shellState);\r\n\r\n // Emit event\r\n this.#emit('tool-panel-close', { id: panelId });\r\n }\r\n\r\n /**\r\n * Toggle a tool panel open/closed.\r\n */\r\n toggleToolPanel(panelId: string): void {\r\n if (this.#shellState.activePanel === panelId) {\r\n this.closeToolPanel();\r\n } else {\r\n this.openToolPanel(panelId);\r\n }\r\n }\r\n\r\n /**\r\n * Get registered tool panel definitions.\r\n */\r\n getToolPanels(): ToolPanelDefinition[] {\r\n return [...this.#shellState.toolPanels.values()];\r\n }\r\n\r\n /**\r\n * Register a custom tool panel (without creating a plugin).\r\n */\r\n registerToolPanel(panel: ToolPanelDefinition): void {\r\n if (this.#shellState.toolPanels.has(panel.id)) {\r\n console.warn(`[tbw-grid] Tool panel \"${panel.id}\" already registered`);\r\n return;\r\n }\r\n this.#shellState.toolPanels.set(panel.id, panel);\r\n\r\n // Re-render shell if needed to show new toolbar button\r\n if (this.#shellInitialized) {\r\n this.#refreshShellHeader();\r\n }\r\n }\r\n\r\n /**\r\n * Unregister a custom tool panel.\r\n */\r\n unregisterToolPanel(panelId: string): void {\r\n // Close panel if it's open\r\n if (this.#shellState.activePanel === panelId) {\r\n this.closeToolPanel();\r\n }\r\n\r\n this.#shellState.toolPanels.delete(panelId);\r\n\r\n // Re-render shell if needed to remove toolbar button\r\n if (this.#shellInitialized) {\r\n this.#refreshShellHeader();\r\n }\r\n }\r\n\r\n /**\r\n * Get registered header content definitions.\r\n */\r\n getHeaderContents(): HeaderContentDefinition[] {\r\n return [...this.#shellState.headerContents.values()];\r\n }\r\n\r\n /**\r\n * Register custom header content (without creating a plugin).\r\n */\r\n registerHeaderContent(content: HeaderContentDefinition): void {\r\n if (this.#shellState.headerContents.has(content.id)) {\r\n console.warn(`[tbw-grid] Header content \"${content.id}\" already registered`);\r\n return;\r\n }\r\n this.#shellState.headerContents.set(content.id, content);\r\n\r\n // Render the content if shell is initialized\r\n if (this.#shellInitialized) {\r\n renderHeaderContent(this.#shadow, this.#shellState);\r\n }\r\n }\r\n\r\n /**\r\n * Unregister custom header content.\r\n */\r\n unregisterHeaderContent(contentId: string): void {\r\n // Clean up\r\n const cleanup = this.#shellState.headerContentCleanups.get(contentId);\r\n if (cleanup) {\r\n cleanup();\r\n this.#shellState.headerContentCleanups.delete(contentId);\r\n }\r\n\r\n // Call onDestroy\r\n const content = this.#shellState.headerContents.get(contentId);\r\n content?.onDestroy?.();\r\n\r\n this.#shellState.headerContents.delete(contentId);\r\n\r\n // Remove DOM element\r\n const el = this.#shadow.querySelector(`[data-header-content=\"${contentId}\"]`);\r\n el?.remove();\r\n }\r\n\r\n /**\r\n * Get all registered toolbar buttons.\r\n */\r\n getToolbarButtons(): ToolbarButtonInfo[] {\r\n return getToolbarButtonsInfo(this.#effectiveConfig?.shell, this.#shellState);\r\n }\r\n\r\n /**\r\n * Register a custom toolbar button programmatically.\r\n */\r\n registerToolbarButton(button: ToolbarButtonConfig): void {\r\n if (this.#shellState.toolbarButtons.has(button.id)) {\r\n console.warn(`[tbw-grid] Toolbar button \"${button.id}\" already registered`);\r\n return;\r\n }\r\n this.#shellState.toolbarButtons.set(button.id, button);\r\n\r\n // Re-render shell if needed\r\n if (this.#shellInitialized) {\r\n this.#refreshShellHeader();\r\n }\r\n }\r\n\r\n /**\r\n * Unregister a custom toolbar button.\r\n */\r\n unregisterToolbarButton(buttonId: string): void {\r\n // Clean up\r\n const cleanup = this.#shellState.toolbarButtonCleanups.get(buttonId);\r\n if (cleanup) {\r\n cleanup();\r\n this.#shellState.toolbarButtonCleanups.delete(buttonId);\r\n }\r\n\r\n this.#shellState.toolbarButtons.delete(buttonId);\r\n\r\n // Re-render shell if needed\r\n if (this.#shellInitialized) {\r\n this.#refreshShellHeader();\r\n }\r\n }\r\n\r\n /**\r\n * Enable/disable a toolbar button by ID.\r\n */\r\n setToolbarButtonDisabled(buttonId: string, disabled: boolean): void {\r\n // Check API-registered buttons\r\n const apiBtn = this.#shellState.toolbarButtons.get(buttonId);\r\n if (apiBtn) {\r\n apiBtn.disabled = disabled;\r\n }\r\n\r\n // Update DOM\r\n const btn = this.#shadow.querySelector(`[data-btn=\"${buttonId}\"]`) as HTMLButtonElement | null;\r\n if (btn) {\r\n btn.disabled = disabled;\r\n }\r\n }\r\n\r\n /**\r\n * Re-parse light DOM shell elements and refresh shell header.\r\n * Call this after dynamically modifying <tbw-grid-header> children.\r\n */\r\n refreshShellHeader(): void {\r\n this.#refreshShellHeader();\r\n }\r\n\r\n /**\r\n * Internal shell header refresh.\r\n */\r\n #refreshShellHeader(): void {\r\n // Re-parse light DOM\r\n parseLightDomShell(this, this.#shellState);\r\n\r\n // Re-render the entire grid (shell structure may change)\r\n this.#render();\r\n this.#afterConnect();\r\n }\r\n\r\n // ---------------- Virtual Window ----------------\r\n /**\r\n * Core virtualization routine. Chooses between bypass (small datasets), grouped window rendering,\r\n * or standard row window rendering.\r\n */\r\n refreshVirtualWindow(force = false): void {\r\n if (!this.bodyEl) return;\r\n\r\n const totalRows = this._rows.length;\r\n\r\n if (!this.virtualization.enabled) {\r\n this.#renderVisibleRows(0, totalRows);\r\n this.#executeAfterRender();\r\n return;\r\n }\r\n\r\n if (this.#shouldBypassVirtualization()) {\r\n this.virtualization.start = 0;\r\n this.virtualization.end = totalRows;\r\n this.bodyEl.style.transform = 'translateY(0px)';\r\n this.#renderVisibleRows(0, totalRows, this.__rowRenderEpoch);\r\n if (this.virtualization.totalHeightEl) {\r\n this.virtualization.totalHeightEl.style.height = `${totalRows * this.virtualization.rowHeight}px`;\r\n }\r\n this.setAttribute('aria-rowcount', String(totalRows));\r\n this.setAttribute('aria-colcount', String(this.visibleColumns.length));\r\n this.#executeAfterRender();\r\n return;\r\n }\r\n\r\n // --- Normal virtualization path with faux scrollbar pattern ---\r\n // Faux scrollbar provides scrollTop, viewport provides visible height\r\n const fauxScrollbar = this.virtualization.container ?? this;\r\n const viewportEl = this.virtualization.viewportEl ?? fauxScrollbar;\r\n const viewportHeight = viewportEl.clientHeight;\r\n const rowHeight = this.virtualization.rowHeight;\r\n const scrollTop = fauxScrollbar.scrollTop;\r\n\r\n // Faux scrollbar pattern: no overscan adjustment for start\r\n // With translateY(0), the first rendered row appears at viewport top\r\n // (Overscan before start would make extra rows visible, not hidden)\r\n let start = Math.floor(scrollTop / rowHeight);\r\n if (start < 0) start = 0;\r\n\r\n // Faux pattern buffer: render 2 extra rows below for smooth edge transition\r\n // This is smaller than traditional overscan since sub-pixel offset handles smoothness\r\n const visibleCount = Math.ceil(viewportHeight / rowHeight) + 2;\r\n let end = start + visibleCount;\r\n if (end > totalRows) end = totalRows;\r\n\r\n this.virtualization.start = start;\r\n this.virtualization.end = end;\r\n\r\n // Height spacer for scrollbar\r\n if (this.virtualization.totalHeightEl) {\r\n this.virtualization.totalHeightEl.style.height = `${totalRows * rowHeight}px`;\r\n }\r\n\r\n // Smooth scroll: apply sub-pixel offset for fluid motion\r\n // This is the remainder after dividing scrollTop by rowHeight\r\n // Creates smooth sliding effect as rows scroll between row boundaries\r\n const subPixelOffset = -(scrollTop % rowHeight);\r\n this.bodyEl.style.transform = `translateY(${subPixelOffset}px)`;\r\n\r\n this.#renderVisibleRows(start, end, force ? ++this.__rowRenderEpoch : this.__rowRenderEpoch);\r\n\r\n this.setAttribute('aria-rowcount', String(totalRows));\r\n this.setAttribute('aria-colcount', String(this.visibleColumns.length));\r\n\r\n // Only run plugin afterRender hooks on force refresh (structural changes)\r\n // Skip on scroll-triggered renders for maximum performance\r\n if (force) {\r\n this.#executeAfterRender();\r\n }\r\n }\r\n\r\n // ---------------- Render ----------------\r\n #render(): void {\r\n // Parse light DOM shell elements before rendering\r\n parseLightDomShell(this, this.#shellState);\r\n\r\n // Get shell config\r\n const shellConfig = this.#effectiveConfig?.shell;\r\n\r\n // Determine if shell should be rendered\r\n const hasShell = shouldRenderShellHeader(shellConfig, this.#shellState);\r\n\r\n // Core grid content HTML\r\n // Uses faux scrollbar pattern (like AG Grid) for smooth virtualized scrolling:\r\n // - .tbw-grid-content: outer container (row layout: scroll-area + faux-vscroll)\r\n // - .tbw-scroll-area: horizontal scroll container (overflow-x: auto) - footer appends here\r\n // - .rows-body-wrapper: header + rows in column layout\r\n // - .faux-vscroll: vertical scrollbar at inline-end, sticky during horizontal scroll\r\n // - .rows-viewport: visible rows area (no scroll, overflow hidden)\r\n // - Scroll events come from faux scrollbar, content positioned via transforms\r\n // This prevents blank viewport during fast scroll - old content stays until new renders\r\n const gridContentHtml = `\r\n <div class=\"tbw-scroll-area\">\r\n <div class=\"rows-body-wrapper\">\r\n <div class=\"rows-body\">\r\n <div class=\"header\">\r\n <div class=\"header-row\" part=\"header-row\"></div>\r\n </div>\r\n <div class=\"rows-container\">\r\n <div class=\"rows-viewport\">\r\n <div class=\"rows\"></div>\r\n </div>\r\n </div>\r\n </div>\r\n </div>\r\n </div>\r\n <div class=\"faux-vscroll\">\r\n <div class=\"faux-vscroll-spacer\"></div>\r\n </div>\r\n `;\r\n\r\n if (hasShell) {\r\n // Build shell DOM structure\r\n const shellHeaderHtml = renderShellHeader(shellConfig, this.#shellState);\r\n const shellBodyHtml = renderShellBody(shellConfig, this.#shellState, gridContentHtml);\r\n\r\n this.#shadow.innerHTML = `\r\n <div class=\"tbw-grid-root has-shell\">\r\n ${shellHeaderHtml}\r\n ${shellBodyHtml}\r\n </div>\r\n `;\r\n\r\n // Set up shell event listeners\r\n this.#setupShellListeners();\r\n\r\n // Mark shell as initialized\r\n this.#shellInitialized = true;\r\n } else {\r\n // Build minimal DOM structure (no shell)\r\n // Wrap in .tbw-grid-content for consistent horizontal scroll behavior\r\n this.#shadow.innerHTML = `\r\n <div class=\"tbw-grid-root\">\r\n <div class=\"tbw-grid-content\">\r\n ${gridContentHtml}\r\n </div>\r\n </div>\r\n `;\r\n }\r\n }\r\n\r\n /**\r\n * Set up shell event listeners after render.\r\n */\r\n #setupShellListeners(): void {\r\n setupShellEventListeners(this.#shadow, this.#effectiveConfig?.shell, this.#shellState, {\r\n onPanelToggle: (panelId) => this.toggleToolPanel(panelId),\r\n onPanelClose: () => this.closeToolPanel(),\r\n onToolbarButtonClick: (buttonId) => this.#handleToolbarButtonClick(buttonId),\r\n });\r\n }\r\n\r\n /**\r\n * Handle toolbar button click (for config buttons with action).\r\n */\r\n #handleToolbarButtonClick(buttonId: string): void {\r\n // Check config buttons\r\n const configButtons = this.#effectiveConfig?.shell?.header?.toolbarButtons ?? [];\r\n const configBtn = configButtons.find((b) => b.id === buttonId);\r\n if (configBtn?.action) {\r\n configBtn.action();\r\n return;\r\n }\r\n\r\n // Check API-registered buttons\r\n const apiBtn = this.#shellState.toolbarButtons.get(buttonId);\r\n if (apiBtn?.action) {\r\n apiBtn.action();\r\n }\r\n }\r\n}\r\n\r\n// Self-registering custom element\r\nif (!customElements.get(DataGridElement.tagName)) {\r\n customElements.define(DataGridElement.tagName, DataGridElement);\r\n}\r\n\r\n// Type augmentation for querySelector/createElement\r\ndeclare global {\r\n interface HTMLElementTagNameMap {\r\n 'tbw-grid': DataGridElement;\r\n }\r\n}\r\n","/**\r\n * Base Grid Plugin Class\r\n *\r\n * All plugins extend this abstract class.\r\n * Plugins are instantiated per-grid and manage their own state.\r\n */\r\n\r\nimport type { ColumnConfig, ColumnState, HeaderContentDefinition, ToolPanelDefinition } from '../types';\r\n\r\n// Forward declare to avoid circular imports\r\nexport interface GridElement {\r\n shadowRoot: ShadowRoot | null;\r\n rows: any[];\r\n columns: ColumnConfig[];\r\n gridConfig: any;\r\n requestRender(): void;\r\n requestAfterRender(): void;\r\n forceLayout(): Promise<void>;\r\n getPlugin<T extends BaseGridPlugin>(PluginClass: new (...args: any[]) => T): T | undefined;\r\n getPluginByName(name: string): BaseGridPlugin | undefined;\r\n dispatchEvent(event: Event): boolean;\r\n}\r\n\r\n/**\r\n * Keyboard modifier flags\r\n */\r\nexport interface KeyboardModifiers {\r\n ctrl?: boolean;\r\n shift?: boolean;\r\n alt?: boolean;\r\n meta?: boolean;\r\n}\r\n\r\n/**\r\n * Cell coordinates\r\n */\r\nexport interface CellCoords {\r\n row: number;\r\n col: number;\r\n}\r\n\r\n/**\r\n * Cell click event\r\n */\r\nexport interface CellClickEvent {\r\n rowIndex: number;\r\n colIndex: number;\r\n field: string;\r\n value: any;\r\n row: any;\r\n cellEl: HTMLElement;\r\n originalEvent: MouseEvent;\r\n}\r\n\r\n/**\r\n * Row click event\r\n */\r\nexport interface RowClickEvent {\r\n rowIndex: number;\r\n row: any;\r\n rowEl: HTMLElement;\r\n originalEvent: MouseEvent;\r\n}\r\n\r\n/**\r\n * Header click event\r\n */\r\nexport interface HeaderClickEvent {\r\n colIndex: number;\r\n field: string;\r\n column: ColumnConfig;\r\n headerEl: HTMLElement;\r\n originalEvent: MouseEvent;\r\n}\r\n\r\n/**\r\n * Scroll event\r\n */\r\nexport interface ScrollEvent {\r\n scrollTop: number;\r\n scrollLeft: number;\r\n scrollHeight: number;\r\n scrollWidth: number;\r\n clientHeight: number;\r\n clientWidth: number;\r\n originalEvent?: Event;\r\n}\r\n\r\n/**\r\n * Cell mouse event (for drag operations, selection, etc.)\r\n */\r\nexport interface CellMouseEvent {\r\n /** Event type: mousedown, mousemove, or mouseup */\r\n type: 'mousedown' | 'mousemove' | 'mouseup';\r\n /** Row index, undefined if not over a data cell */\r\n rowIndex?: number;\r\n /** Column index, undefined if not over a cell */\r\n colIndex?: number;\r\n /** Field name, undefined if not over a cell */\r\n field?: string;\r\n /** Cell value, undefined if not over a data cell */\r\n value?: unknown;\r\n /** Row data object, undefined if not over a data row */\r\n row?: unknown;\r\n /** Column configuration, undefined if not over a column */\r\n column?: ColumnConfig;\r\n /** The cell element, undefined if not over a cell */\r\n cellElement?: HTMLElement;\r\n /** The row element, undefined if not over a row */\r\n rowElement?: HTMLElement;\r\n /** Whether the event is over a header cell */\r\n isHeader: boolean;\r\n /** Cell coordinates if over a valid data cell */\r\n cell?: CellCoords;\r\n /** The original mouse event */\r\n originalEvent: MouseEvent;\r\n}\r\n\r\n/**\r\n * Context menu parameters\r\n */\r\nexport interface ContextMenuParams {\r\n x: number;\r\n y: number;\r\n rowIndex?: number;\r\n colIndex?: number;\r\n field?: string;\r\n value?: any;\r\n row?: any;\r\n column?: ColumnConfig;\r\n isHeader?: boolean;\r\n}\r\n\r\n/**\r\n * Context menu item\r\n */\r\nexport interface ContextMenuItem {\r\n id: string;\r\n label: string;\r\n icon?: string;\r\n disabled?: boolean;\r\n separator?: boolean;\r\n children?: ContextMenuItem[];\r\n action?: (params: ContextMenuParams) => void;\r\n}\r\n\r\n/**\r\n * Cell render context for plugin cell renderers.\r\n * Provides full context including position and editing state.\r\n *\r\n * Note: This differs from the core `CellRenderContext` in types.ts which is\r\n * simpler and used for column view renderers. This version provides additional\r\n * context needed by plugins that register custom cell renderers.\r\n */\r\nexport interface PluginCellRenderContext {\r\n /** The cell value */\r\n value: any;\r\n /** The field/column key */\r\n field: string;\r\n /** The row data object */\r\n row: any;\r\n /** Row index in the data array */\r\n rowIndex: number;\r\n /** Column index */\r\n colIndex: number;\r\n /** Column configuration */\r\n column: ColumnConfig;\r\n /** Whether the cell is currently in edit mode */\r\n isEditing: boolean;\r\n}\r\n\r\n/**\r\n * Header render context for plugin header renderers.\r\n */\r\nexport interface PluginHeaderRenderContext {\r\n /** Column configuration */\r\n column: ColumnConfig;\r\n /** Column index */\r\n colIndex: number;\r\n}\r\n\r\n/**\r\n * Cell renderer function type for plugins.\r\n */\r\nexport type CellRenderer = (ctx: PluginCellRenderContext) => string | HTMLElement;\r\n\r\n/**\r\n * Header renderer function type for plugins.\r\n */\r\nexport type HeaderRenderer = (ctx: PluginHeaderRenderContext) => string | HTMLElement;\r\n\r\n/**\r\n * Cell editor interface for plugins.\r\n */\r\nexport interface CellEditor {\r\n create(ctx: PluginCellRenderContext, commitFn: (value: any) => void, cancelFn: () => void): HTMLElement;\r\n getValue?(element: HTMLElement): any;\r\n focus?(element: HTMLElement): void;\r\n}\r\n\r\n/**\r\n * Abstract base class for all grid plugins.\r\n *\r\n * @template TConfig - Configuration type for the plugin\r\n */\r\nexport abstract class BaseGridPlugin<TConfig = unknown> {\r\n /** Unique plugin identifier (derived from class name by default) */\r\n abstract readonly name: string;\r\n\r\n /** Plugin version - override in subclass if needed */\r\n readonly version: string = '1.0.0';\r\n\r\n /** CSS styles to inject into the grid's shadow DOM */\r\n readonly styles?: string;\r\n\r\n /** Custom cell renderers keyed by type name */\r\n readonly cellRenderers?: Record<string, CellRenderer>;\r\n\r\n /** Custom header renderers keyed by type name */\r\n readonly headerRenderers?: Record<string, HeaderRenderer>;\r\n\r\n /** Custom cell editors keyed by type name */\r\n readonly cellEditors?: Record<string, CellEditor>;\r\n\r\n /** The grid instance this plugin is attached to */\r\n protected grid!: GridElement;\r\n\r\n /** Plugin configuration - merged with defaults in attach() */\r\n protected config!: TConfig;\r\n\r\n /** User-provided configuration from constructor */\r\n private readonly userConfig: Partial<TConfig>;\r\n\r\n /**\r\n * Default configuration - subclasses should override this getter.\r\n * Note: This must be a getter (not property initializer) for proper inheritance\r\n * since property initializers run after parent constructor.\r\n */\r\n protected get defaultConfig(): Partial<TConfig> {\r\n return {};\r\n }\r\n\r\n constructor(config: Partial<TConfig> = {}) {\r\n this.userConfig = config;\r\n }\r\n\r\n /**\r\n * Called when the plugin is attached to a grid.\r\n * Override to set up event listeners, initialize state, etc.\r\n */\r\n attach(grid: GridElement): void {\r\n this.grid = grid;\r\n // Merge config here (after subclass construction is complete)\r\n this.config = { ...this.defaultConfig, ...this.userConfig } as TConfig;\r\n }\r\n\r\n /**\r\n * Called when the plugin is detached from a grid.\r\n * Override to clean up event listeners, timers, etc.\r\n */\r\n detach(): void {\r\n // Override in subclass\r\n }\r\n\r\n /**\r\n * Get another plugin instance from the same grid.\r\n * Use for inter-plugin communication.\r\n */\r\n protected getPlugin<T extends BaseGridPlugin>(PluginClass: new (...args: any[]) => T): T | undefined {\r\n return this.grid?.getPlugin(PluginClass);\r\n }\r\n\r\n /**\r\n * Emit a custom event from the grid.\r\n */\r\n protected emit<T>(eventName: string, detail: T): void {\r\n this.grid?.dispatchEvent?.(new CustomEvent(eventName, { detail, bubbles: true }));\r\n }\r\n\r\n /**\r\n * Request a re-render of the grid.\r\n */\r\n protected requestRender(): void {\r\n this.grid?.requestRender?.();\r\n }\r\n\r\n /**\r\n * Request a lightweight style update without rebuilding DOM.\r\n * Use this instead of requestRender() when only CSS classes need updating.\r\n */\r\n protected requestAfterRender(): void {\r\n this.grid?.requestAfterRender?.();\r\n }\r\n\r\n /**\r\n * Get the current rows from the grid.\r\n */\r\n protected get rows(): any[] {\r\n return this.grid?.rows ?? [];\r\n }\r\n\r\n /**\r\n * Get the original unfiltered/unprocessed rows from the grid.\r\n * Use this when you need all source data regardless of active filters.\r\n */\r\n protected get sourceRows(): any[] {\r\n return (this.grid as any)?.sourceRows ?? [];\r\n }\r\n\r\n /**\r\n * Get the current columns from the grid.\r\n */\r\n protected get columns(): ColumnConfig[] {\r\n return this.grid?.columns ?? [];\r\n }\r\n\r\n /**\r\n * Get only visible columns from the grid (excludes hidden).\r\n * Use this for rendering that needs to match the grid template.\r\n */\r\n protected get visibleColumns(): ColumnConfig[] {\r\n return (this.grid as any)?.visibleColumns ?? [];\r\n }\r\n\r\n /**\r\n * Get the shadow root of the grid.\r\n */\r\n protected get shadowRoot(): ShadowRoot | null {\r\n return this.grid?.shadowRoot ?? null;\r\n }\r\n\r\n /**\r\n * Log a warning message.\r\n */\r\n protected warn(message: string): void {\r\n console.warn(`[tbw-grid:${this.name}] ${message}`);\r\n }\r\n\r\n // ===== Lifecycle Hooks (override as needed) =====\r\n\r\n /**\r\n * Transform rows before rendering.\r\n * Called during each render cycle before rows are rendered to the DOM.\r\n * Use this to filter, sort, or add computed properties to rows.\r\n *\r\n * @param rows - The current rows array (readonly to encourage returning a new array)\r\n * @returns The modified rows array to render\r\n *\r\n * @example\r\n * ```ts\r\n * processRows(rows: readonly any[]): any[] {\r\n * // Filter out hidden rows\r\n * return rows.filter(row => !row._hidden);\r\n * }\r\n * ```\r\n *\r\n * @example\r\n * ```ts\r\n * processRows(rows: readonly any[]): any[] {\r\n * // Add computed properties\r\n * return rows.map(row => ({\r\n * ...row,\r\n * _fullName: `${row.firstName} ${row.lastName}`\r\n * }));\r\n * }\r\n * ```\r\n */\r\n processRows?(rows: readonly any[]): any[];\r\n\r\n /**\r\n * Transform columns before rendering.\r\n * Called during each render cycle before column headers and cells are rendered.\r\n * Use this to add, remove, or modify column definitions.\r\n *\r\n * @param columns - The current columns array (readonly to encourage returning a new array)\r\n * @returns The modified columns array to render\r\n *\r\n * @example\r\n * ```ts\r\n * processColumns(columns: readonly ColumnConfig[]): ColumnConfig[] {\r\n * // Add a selection checkbox column\r\n * return [\r\n * { field: '_select', header: '', width: 40 },\r\n * ...columns\r\n * ];\r\n * }\r\n * ```\r\n */\r\n processColumns?(columns: readonly ColumnConfig[]): ColumnConfig[];\r\n\r\n /**\r\n * Called before each render cycle begins.\r\n * Use this to prepare state or cache values needed during rendering.\r\n *\r\n * @example\r\n * ```ts\r\n * beforeRender(): void {\r\n * this.visibleRowCount = this.calculateVisibleRows();\r\n * }\r\n * ```\r\n */\r\n beforeRender?(): void;\r\n\r\n /**\r\n * Called after each render cycle completes.\r\n * Use this for DOM manipulation, adding event listeners to rendered elements,\r\n * or applying visual effects like selection highlights.\r\n *\r\n * @example\r\n * ```ts\r\n * afterRender(): void {\r\n * // Apply selection styling to rendered rows\r\n * const rows = this.shadowRoot?.querySelectorAll('.data-row');\r\n * rows?.forEach((row, i) => {\r\n * row.classList.toggle('selected', this.selectedRows.has(i));\r\n * });\r\n * }\r\n * ```\r\n */\r\n afterRender?(): void;\r\n\r\n /**\r\n * Render a custom row, bypassing the default row rendering.\r\n * Use this for special row types like group headers, detail rows, or footers.\r\n *\r\n * @param row - The row data object\r\n * @param rowEl - The row DOM element to render into\r\n * @param rowIndex - The index of the row in the data array\r\n * @returns `true` if the plugin handled rendering (prevents default), `false`/`void` for default rendering\r\n *\r\n * @example\r\n * ```ts\r\n * renderRow(row: any, rowEl: HTMLElement, rowIndex: number): boolean | void {\r\n * if (row._isGroupHeader) {\r\n * rowEl.innerHTML = `<div class=\"group-header\">${row._groupLabel}</div>`;\r\n * return true; // Handled - skip default rendering\r\n * }\r\n * // Return void to let default rendering proceed\r\n * }\r\n * ```\r\n */\r\n renderRow?(row: any, rowEl: HTMLElement, rowIndex: number): boolean | void;\r\n\r\n // ===== Interaction Hooks (override as needed) =====\r\n\r\n /**\r\n * Handle keyboard events on the grid.\r\n * Called when a key is pressed while the grid or a cell has focus.\r\n *\r\n * @param event - The native KeyboardEvent\r\n * @returns `true` to prevent default behavior and stop propagation, `false`/`void` to allow default\r\n *\r\n * @example\r\n * ```ts\r\n * onKeyDown(event: KeyboardEvent): boolean | void {\r\n * // Handle Ctrl+A for select all\r\n * if (event.ctrlKey && event.key === 'a') {\r\n * this.selectAllRows();\r\n * return true; // Prevent default browser select-all\r\n * }\r\n * }\r\n * ```\r\n */\r\n onKeyDown?(event: KeyboardEvent): boolean | void;\r\n\r\n /**\r\n * Handle cell click events.\r\n * Called when a data cell is clicked (not headers).\r\n *\r\n * @param event - Cell click event with row/column context\r\n * @returns `true` to prevent default behavior and stop propagation, `false`/`void` to allow default\r\n *\r\n * @example\r\n * ```ts\r\n * onCellClick(event: CellClickEvent): boolean | void {\r\n * if (event.field === '_select') {\r\n * this.toggleRowSelection(event.rowIndex);\r\n * return true; // Handled\r\n * }\r\n * }\r\n * ```\r\n */\r\n onCellClick?(event: CellClickEvent): boolean | void;\r\n\r\n /**\r\n * Handle row click events.\r\n * Called when any part of a data row is clicked.\r\n * Note: This is called in addition to onCellClick, not instead of.\r\n *\r\n * @param event - Row click event with row context\r\n * @returns `true` to prevent default behavior and stop propagation, `false`/`void` to allow default\r\n *\r\n * @example\r\n * ```ts\r\n * onRowClick(event: RowClickEvent): boolean | void {\r\n * if (this.config.mode === 'row') {\r\n * this.selectRow(event.rowIndex, event.originalEvent);\r\n * return true;\r\n * }\r\n * }\r\n * ```\r\n */\r\n onRowClick?(event: RowClickEvent): boolean | void;\r\n\r\n /**\r\n * Handle header click events.\r\n * Called when a column header is clicked. Commonly used for sorting.\r\n *\r\n * @param event - Header click event with column context\r\n * @returns `true` to prevent default behavior and stop propagation, `false`/`void` to allow default\r\n *\r\n * @example\r\n * ```ts\r\n * onHeaderClick(event: HeaderClickEvent): boolean | void {\r\n * if (event.column.sortable !== false) {\r\n * this.toggleSort(event.field);\r\n * return true;\r\n * }\r\n * }\r\n * ```\r\n */\r\n onHeaderClick?(event: HeaderClickEvent): boolean | void;\r\n\r\n /**\r\n * Handle scroll events on the grid viewport.\r\n * Called during scrolling. Note: This may be called frequently; debounce if needed.\r\n *\r\n * @param event - Scroll event with scroll position and viewport dimensions\r\n *\r\n * @example\r\n * ```ts\r\n * onScroll(event: ScrollEvent): void {\r\n * // Update sticky column positions\r\n * this.updateStickyPositions(event.scrollLeft);\r\n * }\r\n * ```\r\n */\r\n onScroll?(event: ScrollEvent): void;\r\n\r\n /**\r\n * Handle cell mousedown events.\r\n * Used for initiating drag operations like range selection or column resize.\r\n *\r\n * @param event - Mouse event with cell context\r\n * @returns `true` to indicate drag started (prevents text selection), `false`/`void` otherwise\r\n *\r\n * @example\r\n * ```ts\r\n * onCellMouseDown(event: CellMouseEvent): boolean | void {\r\n * if (event.rowIndex !== undefined && this.config.mode === 'range') {\r\n * this.startDragSelection(event.rowIndex, event.colIndex);\r\n * return true; // Prevent text selection\r\n * }\r\n * }\r\n * ```\r\n */\r\n onCellMouseDown?(event: CellMouseEvent): boolean | void;\r\n\r\n /**\r\n * Handle cell mousemove events during drag operations.\r\n * Only called when a drag is in progress (after mousedown returned true).\r\n *\r\n * @param event - Mouse event with current cell context\r\n * @returns `true` to continue handling the drag, `false`/`void` otherwise\r\n *\r\n * @example\r\n * ```ts\r\n * onCellMouseMove(event: CellMouseEvent): boolean | void {\r\n * if (this.isDragging && event.rowIndex !== undefined) {\r\n * this.extendSelection(event.rowIndex, event.colIndex);\r\n * return true;\r\n * }\r\n * }\r\n * ```\r\n */\r\n onCellMouseMove?(event: CellMouseEvent): boolean | void;\r\n\r\n /**\r\n * Handle cell mouseup events to end drag operations.\r\n *\r\n * @param event - Mouse event with final cell context\r\n * @returns `true` if drag was finalized, `false`/`void` otherwise\r\n *\r\n * @example\r\n * ```ts\r\n * onCellMouseUp(event: CellMouseEvent): boolean | void {\r\n * if (this.isDragging) {\r\n * this.finalizeDragSelection();\r\n * this.isDragging = false;\r\n * return true;\r\n * }\r\n * }\r\n * ```\r\n */\r\n onCellMouseUp?(event: CellMouseEvent): boolean | void;\r\n\r\n /**\r\n * Provide context menu items when right-clicking on the grid.\r\n * Multiple plugins can contribute items; they are merged into a single menu.\r\n *\r\n * @param params - Context about where the menu was triggered (row, column, etc.)\r\n * @returns Array of menu items to display\r\n *\r\n * @example\r\n * ```ts\r\n * getContextMenuItems(params: ContextMenuParams): ContextMenuItem[] {\r\n * if (params.isHeader) {\r\n * return [\r\n * { id: 'sort-asc', label: 'Sort Ascending', action: () => this.sortAsc(params.field) },\r\n * { id: 'sort-desc', label: 'Sort Descending', action: () => this.sortDesc(params.field) },\r\n * ];\r\n * }\r\n * return [\r\n * { id: 'copy', label: 'Copy Cell', action: () => this.copyCell(params) },\r\n * ];\r\n * }\r\n * ```\r\n */\r\n getContextMenuItems?(params: ContextMenuParams): ContextMenuItem[];\r\n\r\n // ===== Column State Hooks (override as needed) =====\r\n\r\n /**\r\n * Contribute plugin-specific state for a column.\r\n * Called by the grid when collecting column state for serialization.\r\n * Plugins can add their own properties to the column state.\r\n *\r\n * @param field - The field name of the column\r\n * @returns Partial column state with plugin-specific properties, or undefined if no state to contribute\r\n *\r\n * @example\r\n * ```ts\r\n * getColumnState(field: string): Partial<ColumnState> | undefined {\r\n * const filterModel = this.filterModels.get(field);\r\n * if (filterModel) {\r\n * // Uses module augmentation to add filter property to ColumnState\r\n * return { filter: filterModel } as Partial<ColumnState>;\r\n * }\r\n * return undefined;\r\n * }\r\n * ```\r\n */\r\n getColumnState?(field: string): Partial<ColumnState> | undefined;\r\n\r\n /**\r\n * Apply plugin-specific state to a column.\r\n * Called by the grid when restoring column state from serialized data.\r\n * Plugins should restore their internal state based on the provided state.\r\n *\r\n * @param field - The field name of the column\r\n * @param state - The column state to apply (may contain plugin-specific properties)\r\n *\r\n * @example\r\n * ```ts\r\n * applyColumnState(field: string, state: ColumnState): void {\r\n * // Check for filter property added via module augmentation\r\n * const filter = (state as any).filter;\r\n * if (filter) {\r\n * this.filterModels.set(field, filter);\r\n * this.applyFilter();\r\n * }\r\n * }\r\n * ```\r\n */\r\n applyColumnState?(field: string, state: ColumnState): void;\r\n\r\n // ===== Shell Integration Hooks (override as needed) =====\r\n\r\n /**\r\n * Register a tool panel for this plugin.\r\n * Return undefined if plugin has no tool panel.\r\n * The shell will create a toolbar toggle button and render the panel content\r\n * when the user opens the panel.\r\n *\r\n * @returns Tool panel definition, or undefined if plugin has no panel\r\n *\r\n * @example\r\n * ```ts\r\n * getToolPanel(): ToolPanelDefinition | undefined {\r\n * return {\r\n * id: 'columns',\r\n * title: 'Columns',\r\n * icon: '☰',\r\n * tooltip: 'Show/hide columns',\r\n * order: 10,\r\n * render: (container) => {\r\n * this.renderColumnList(container);\r\n * return () => this.cleanup();\r\n * },\r\n * };\r\n * }\r\n * ```\r\n */\r\n getToolPanel?(): ToolPanelDefinition | undefined;\r\n\r\n /**\r\n * Register content for the shell header center section.\r\n * Return undefined if plugin has no header content.\r\n * Examples: search input, selection summary, status indicators.\r\n *\r\n * @returns Header content definition, or undefined if plugin has no header content\r\n *\r\n * @example\r\n * ```ts\r\n * getHeaderContent(): HeaderContentDefinition | undefined {\r\n * return {\r\n * id: 'quick-filter',\r\n * order: 10,\r\n * render: (container) => {\r\n * const input = document.createElement('input');\r\n * input.type = 'text';\r\n * input.placeholder = 'Search...';\r\n * input.addEventListener('input', this.handleInput);\r\n * container.appendChild(input);\r\n * return () => input.removeEventListener('input', this.handleInput);\r\n * },\r\n * };\r\n * }\r\n * ```\r\n */\r\n getHeaderContent?(): HeaderContentDefinition | undefined;\r\n}\r\n","/**\n * Cell Range Selection Core Logic\n *\n * Pure functions for cell range selection operations.\n */\n\nimport type { InternalCellRange, CellRange } from './types';\n\n/**\n * Normalize a range so startRow/startCol are always <= endRow/endCol.\n * This handles cases where user drags from bottom-right to top-left.\n *\n * @param range - The range to normalize\n * @returns Normalized range with start <= end for both dimensions\n */\nexport function normalizeRange(range: InternalCellRange): InternalCellRange {\n return {\n startRow: Math.min(range.startRow, range.endRow),\n startCol: Math.min(range.startCol, range.endCol),\n endRow: Math.max(range.startRow, range.endRow),\n endCol: Math.max(range.startCol, range.endCol),\n };\n}\n\n/**\n * Convert an internal range to the public event format.\n *\n * @param range - The internal range to convert\n * @returns Public CellRange format with from/to coordinates\n */\nexport function toPublicRange(range: InternalCellRange): CellRange {\n const normalized = normalizeRange(range);\n return {\n from: { row: normalized.startRow, col: normalized.startCol },\n to: { row: normalized.endRow, col: normalized.endCol },\n };\n}\n\n/**\n * Convert multiple internal ranges to public format.\n *\n * @param ranges - Array of internal ranges\n * @returns Array of public CellRange format\n */\nexport function toPublicRanges(ranges: InternalCellRange[]): CellRange[] {\n return ranges.map(toPublicRange);\n}\n\n/**\n * Check if a cell is within a specific range.\n *\n * @param row - The row index to check\n * @param col - The column index to check\n * @param range - The range to check against\n * @returns True if the cell is within the range\n */\nexport function isCellInRange(row: number, col: number, range: InternalCellRange): boolean {\n const normalized = normalizeRange(range);\n return (\n row >= normalized.startRow && row <= normalized.endRow && col >= normalized.startCol && col <= normalized.endCol\n );\n}\n\n/**\n * Check if a cell is within any of the provided ranges.\n *\n * @param row - The row index to check\n * @param col - The column index to check\n * @param ranges - Array of ranges to check against\n * @returns True if the cell is within any range\n */\nexport function isCellInAnyRange(row: number, col: number, ranges: InternalCellRange[]): boolean {\n return ranges.some((range) => isCellInRange(row, col, range));\n}\n\n/**\n * Get all cells within a range as an array of {row, col} objects.\n *\n * @param range - The range to enumerate\n * @returns Array of all cell coordinates in the range\n */\nexport function getCellsInRange(range: InternalCellRange): Array<{ row: number; col: number }> {\n const cells: Array<{ row: number; col: number }> = [];\n const normalized = normalizeRange(range);\n\n for (let row = normalized.startRow; row <= normalized.endRow; row++) {\n for (let col = normalized.startCol; col <= normalized.endCol; col++) {\n cells.push({ row, col });\n }\n }\n\n return cells;\n}\n\n/**\n * Get all unique cells across multiple ranges.\n * Deduplicates cells that appear in overlapping ranges.\n *\n * @param ranges - Array of ranges to enumerate\n * @returns Array of unique cell coordinates\n */\nexport function getAllCellsInRanges(ranges: InternalCellRange[]): Array<{ row: number; col: number }> {\n const cellMap = new Map<string, { row: number; col: number }>();\n\n for (const range of ranges) {\n for (const cell of getCellsInRange(range)) {\n cellMap.set(`${cell.row},${cell.col}`, cell);\n }\n }\n\n return [...cellMap.values()];\n}\n\n/**\n * Merge overlapping or adjacent ranges into fewer ranges.\n * Simple implementation - returns ranges as-is for now.\n * More complex merging logic can be added later for optimization.\n *\n * @param ranges - Array of ranges to merge\n * @returns Merged array of ranges\n */\nexport function mergeRanges(ranges: InternalCellRange[]): InternalCellRange[] {\n // Simple implementation - more complex merging can be added later\n return ranges;\n}\n\n/**\n * Create a range from an anchor cell to a current cell position.\n * The range is not normalized - it preserves the direction of selection.\n *\n * @param anchor - The anchor cell (where selection started)\n * @param current - The current cell (where selection ends)\n * @returns An InternalCellRange from anchor to current\n */\nexport function createRangeFromAnchor(\n anchor: { row: number; col: number },\n current: { row: number; col: number }\n): InternalCellRange {\n return {\n startRow: anchor.row,\n startCol: anchor.col,\n endRow: current.row,\n endCol: current.col,\n };\n}\n\n/**\n * Calculate the number of cells in a range.\n *\n * @param range - The range to measure\n * @returns Total number of cells in the range\n */\nexport function getRangeCellCount(range: InternalCellRange): number {\n const normalized = normalizeRange(range);\n const rowCount = normalized.endRow - normalized.startRow + 1;\n const colCount = normalized.endCol - normalized.startCol + 1;\n return rowCount * colCount;\n}\n\n/**\n * Check if two ranges are equal (same boundaries).\n *\n * @param a - First range\n * @param b - Second range\n * @returns True if ranges have same boundaries after normalization\n */\nexport function rangesEqual(a: InternalCellRange, b: InternalCellRange): boolean {\n const normA = normalizeRange(a);\n const normB = normalizeRange(b);\n return (\n normA.startRow === normB.startRow &&\n normA.startCol === normB.startCol &&\n normA.endRow === normB.endRow &&\n normA.endCol === normB.endCol\n );\n}\n\n/**\n * Check if a range is a single cell (1x1).\n *\n * @param range - The range to check\n * @returns True if the range is exactly one cell\n */\nexport function isSingleCell(range: InternalCellRange): boolean {\n const normalized = normalizeRange(range);\n return normalized.startRow === normalized.endRow && normalized.startCol === normalized.endCol;\n}\n","/**\n * Selection Plugin (Class-based)\n *\n * Provides selection functionality for tbw-grid.\n * Supports three modes:\n * - 'cell': Single cell selection (default). No border, just focus highlight.\n * - 'row': Row selection. Clicking a cell selects the entire row.\n * - 'range': Range selection. Shift+click or drag to select rectangular cell ranges.\n */\n\nimport { BaseGridPlugin, CellClickEvent, CellMouseEvent } from '../../core/plugin/base-plugin';\nimport {\n createRangeFromAnchor,\n getAllCellsInRanges,\n isCellInAnyRange,\n normalizeRange,\n toPublicRanges,\n} from './range-selection';\nimport type { CellRange, InternalCellRange, SelectionChangeDetail, SelectionConfig, SelectionMode } from './types';\n\n/**\n * Build the selection change event detail for the current state.\n */\nfunction buildSelectionEvent(\n mode: SelectionMode,\n state: {\n selectedCell: { row: number; col: number } | null;\n selected: Set<number>;\n ranges: InternalCellRange[];\n },\n colCount: number\n): SelectionChangeDetail {\n if (mode === 'cell' && state.selectedCell) {\n return {\n mode,\n ranges: [\n {\n from: { row: state.selectedCell.row, col: state.selectedCell.col },\n to: { row: state.selectedCell.row, col: state.selectedCell.col },\n },\n ],\n };\n }\n\n if (mode === 'row' && state.selected.size > 0) {\n const ranges = [...state.selected].map((rowIndex) => ({\n from: { row: rowIndex, col: 0 },\n to: { row: rowIndex, col: colCount - 1 },\n }));\n return { mode, ranges };\n }\n\n if (mode === 'range' && state.ranges.length > 0) {\n return { mode, ranges: toPublicRanges(state.ranges) };\n }\n\n return { mode, ranges: [] };\n}\n\n/**\n * Selection Plugin for tbw-grid\n *\n * @example\n * ```ts\n * new SelectionPlugin({ mode: 'range' })\n * ```\n */\nexport class SelectionPlugin extends BaseGridPlugin<SelectionConfig> {\n readonly name = 'selection';\n override readonly version = '1.0.0';\n\n protected override get defaultConfig(): Partial<SelectionConfig> {\n return {\n mode: 'cell',\n };\n }\n\n // ===== Internal State =====\n /** Row selection state (row mode) */\n private selected = new Set<number>();\n private lastSelected: number | null = null;\n private anchor: number | null = null;\n\n /** Range selection state (range mode) */\n private ranges: InternalCellRange[] = [];\n private activeRange: InternalCellRange | null = null;\n private cellAnchor: { row: number; col: number } | null = null;\n private isDragging = false;\n\n /** Cell selection state (cell mode) */\n private selectedCell: { row: number; col: number } | null = null;\n\n // ===== Lifecycle =====\n\n override detach(): void {\n this.selected.clear();\n this.ranges = [];\n this.activeRange = null;\n this.cellAnchor = null;\n this.isDragging = false;\n this.selectedCell = null;\n }\n\n // ===== Event Handlers =====\n\n override onCellClick(event: CellClickEvent): boolean {\n const { rowIndex, colIndex, originalEvent } = event;\n const { mode } = this.config;\n\n // ===== CELL MODE: Single cell selection =====\n if (mode === 'cell') {\n this.selectedCell = { row: rowIndex, col: colIndex };\n this.emit<SelectionChangeDetail>('selection-change', this.#buildEvent());\n this.requestAfterRender();\n return false;\n }\n\n // ===== ROW MODE: Select entire row =====\n if (mode === 'row') {\n this.selected.clear();\n this.selected.add(rowIndex);\n this.lastSelected = rowIndex;\n\n this.emit<SelectionChangeDetail>('selection-change', this.#buildEvent());\n this.requestAfterRender();\n return false;\n }\n\n // ===== RANGE MODE: Shift+click extends selection, click starts new =====\n if (mode === 'range') {\n const shiftKey = originalEvent.shiftKey;\n const ctrlKey = originalEvent.ctrlKey || originalEvent.metaKey;\n\n if (shiftKey && this.cellAnchor) {\n // Extend selection from anchor\n const newRange = createRangeFromAnchor(this.cellAnchor, { row: rowIndex, col: colIndex });\n\n if (ctrlKey) {\n if (this.ranges.length > 0) {\n this.ranges[this.ranges.length - 1] = newRange;\n } else {\n this.ranges.push(newRange);\n }\n } else {\n this.ranges = [newRange];\n }\n this.activeRange = newRange;\n } else if (ctrlKey) {\n const newRange: InternalCellRange = {\n startRow: rowIndex,\n startCol: colIndex,\n endRow: rowIndex,\n endCol: colIndex,\n };\n this.ranges.push(newRange);\n this.activeRange = newRange;\n this.cellAnchor = { row: rowIndex, col: colIndex };\n } else {\n const newRange: InternalCellRange = {\n startRow: rowIndex,\n startCol: colIndex,\n endRow: rowIndex,\n endCol: colIndex,\n };\n this.ranges = [newRange];\n this.activeRange = newRange;\n this.cellAnchor = { row: rowIndex, col: colIndex };\n }\n\n this.emit<SelectionChangeDetail>('selection-change', this.#buildEvent());\n\n this.requestAfterRender();\n return false;\n }\n\n return false;\n }\n\n override onKeyDown(event: KeyboardEvent): boolean {\n const { mode } = this.config;\n\n // Escape clears selection in all modes\n if (event.key === 'Escape') {\n if (mode === 'cell') {\n this.selectedCell = null;\n } else if (mode === 'row') {\n this.selected.clear();\n this.anchor = null;\n } else if (mode === 'range') {\n this.ranges = [];\n this.activeRange = null;\n this.cellAnchor = null;\n }\n this.emit<SelectionChangeDetail>('selection-change', this.#buildEvent());\n this.requestAfterRender();\n return true;\n }\n\n // Ctrl+A selects all in range mode\n if (mode === 'range' && event.key === 'a' && (event.ctrlKey || event.metaKey)) {\n const rowCount = this.rows.length;\n const colCount = this.columns.length;\n if (rowCount > 0 && colCount > 0) {\n const allRange: InternalCellRange = {\n startRow: 0,\n startCol: 0,\n endRow: rowCount - 1,\n endCol: colCount - 1,\n };\n this.ranges = [allRange];\n this.activeRange = allRange;\n this.emit<SelectionChangeDetail>('selection-change', this.#buildEvent());\n this.requestAfterRender();\n return true;\n }\n }\n\n return false;\n }\n\n override onCellMouseDown(event: CellMouseEvent): boolean | void {\n if (this.config.mode !== 'range') return;\n if (event.rowIndex === undefined || event.colIndex === undefined) return;\n if (event.rowIndex < 0) return; // Header\n\n // Let onCellClick handle shift+click for range extension\n if (event.originalEvent.shiftKey && this.cellAnchor) {\n return;\n }\n\n // Start drag selection\n this.isDragging = true;\n const rowIndex = event.rowIndex;\n const colIndex = event.colIndex;\n this.cellAnchor = { row: rowIndex, col: colIndex };\n\n const ctrlKey = event.originalEvent.ctrlKey || event.originalEvent.metaKey;\n if (!ctrlKey) {\n this.ranges = [];\n }\n\n const newRange: InternalCellRange = {\n startRow: rowIndex,\n startCol: colIndex,\n endRow: rowIndex,\n endCol: colIndex,\n };\n this.ranges.push(newRange);\n this.activeRange = newRange;\n\n this.emit<SelectionChangeDetail>('selection-change', this.#buildEvent());\n this.requestAfterRender();\n return true;\n }\n\n override onCellMouseMove(event: CellMouseEvent): boolean | void {\n if (this.config.mode !== 'range') return;\n if (!this.isDragging || !this.cellAnchor) return;\n if (event.rowIndex === undefined || event.colIndex === undefined) return;\n if (event.rowIndex < 0) return;\n\n const newRange = createRangeFromAnchor(this.cellAnchor, { row: event.rowIndex, col: event.colIndex });\n\n if (this.ranges.length > 0) {\n this.ranges[this.ranges.length - 1] = newRange;\n } else {\n this.ranges.push(newRange);\n }\n this.activeRange = newRange;\n\n this.emit<SelectionChangeDetail>('selection-change', this.#buildEvent());\n this.requestAfterRender();\n return true;\n }\n\n override onCellMouseUp(_event: CellMouseEvent): boolean | void {\n if (this.config.mode !== 'range') return;\n if (this.isDragging) {\n this.isDragging = false;\n return true;\n }\n }\n\n override afterRender(): void {\n const shadowRoot = this.shadowRoot;\n if (!shadowRoot) return;\n\n const container = shadowRoot.children[0];\n const { mode } = this.config;\n\n // Set data attribute on host for CSS variable scoping\n (this.grid as unknown as Element).setAttribute('data-selection-mode', mode);\n\n // Toggle .selecting class during drag to prevent text selection\n if (container) {\n container.classList.toggle('selecting', this.isDragging);\n }\n\n // Clear all selection classes first\n const allCells = shadowRoot.querySelectorAll('.cell');\n allCells.forEach((cell) => {\n cell.classList.remove('selected', 'top', 'bottom', 'first', 'last');\n });\n\n const allRows = shadowRoot.querySelectorAll('.data-grid-row');\n allRows.forEach((row) => {\n row.classList.remove('selected');\n });\n\n // ===== ROW MODE: Add row-focus class to selected rows =====\n if (mode === 'row') {\n allRows.forEach((row) => row.classList.remove('row-focus'));\n\n allRows.forEach((row) => {\n const firstCell = row.querySelector('.cell[data-row]');\n const rowIndex = parseInt(firstCell?.getAttribute('data-row') ?? '-1', 10);\n if (rowIndex >= 0 && this.selected.has(rowIndex)) {\n row.classList.add('selected', 'row-focus');\n }\n });\n }\n\n // ===== RANGE MODE: Add selected and edge classes to cells =====\n if (mode === 'range' && this.ranges.length > 0) {\n const normalized = this.activeRange ? normalizeRange(this.activeRange) : null;\n\n const cells = shadowRoot.querySelectorAll('.cell[data-row][data-col]');\n cells.forEach((cell) => {\n const rowIndex = parseInt(cell.getAttribute('data-row') ?? '-1', 10);\n const colIndex = parseInt(cell.getAttribute('data-col') ?? '-1', 10);\n if (rowIndex >= 0 && colIndex >= 0) {\n const inRange = isCellInAnyRange(rowIndex, colIndex, this.ranges);\n\n if (inRange) {\n cell.classList.add('selected');\n\n if (normalized) {\n if (rowIndex === normalized.startRow) cell.classList.add('top');\n if (rowIndex === normalized.endRow) cell.classList.add('bottom');\n if (colIndex === normalized.startCol) cell.classList.add('first');\n if (colIndex === normalized.endCol) cell.classList.add('last');\n }\n }\n }\n });\n }\n }\n\n // ===== Public API =====\n\n /**\n * Get the selected cell (cell mode only).\n */\n getSelectedCell(): { row: number; col: number } | null {\n return this.selectedCell;\n }\n\n /**\n * Get all selected row indices (row mode).\n */\n getSelectedRows(): number[] {\n return [...this.selected];\n }\n\n /**\n * Get all selected cell ranges in public format.\n */\n getRanges(): CellRange[] {\n return toPublicRanges(this.ranges);\n }\n\n /**\n * Get all selected cells across all ranges.\n */\n getSelectedCells(): Array<{ row: number; col: number }> {\n return getAllCellsInRanges(this.ranges);\n }\n\n /**\n * Check if a specific cell is in range selection.\n */\n isCellSelected(row: number, col: number): boolean {\n return isCellInAnyRange(row, col, this.ranges);\n }\n\n /**\n * Clear all selection.\n */\n clearSelection(): void {\n this.selectedCell = null;\n this.selected.clear();\n this.anchor = null;\n this.ranges = [];\n this.activeRange = null;\n this.cellAnchor = null;\n this.emit<SelectionChangeDetail>('selection-change', { mode: this.config.mode, ranges: [] });\n this.requestAfterRender();\n }\n\n /**\n * Set selected ranges programmatically.\n */\n setRanges(ranges: CellRange[]): void {\n this.ranges = ranges.map((r) => ({\n startRow: r.from.row,\n startCol: r.from.col,\n endRow: r.to.row,\n endCol: r.to.col,\n }));\n this.activeRange = this.ranges.length > 0 ? this.ranges[this.ranges.length - 1] : null;\n this.emit<SelectionChangeDetail>('selection-change', {\n mode: this.config.mode,\n ranges: toPublicRanges(this.ranges),\n });\n this.requestAfterRender();\n }\n\n // ===== Private Helpers =====\n\n #buildEvent(): SelectionChangeDetail {\n return buildSelectionEvent(\n this.config.mode,\n {\n selectedCell: this.selectedCell,\n selected: this.selected,\n ranges: this.ranges,\n },\n this.columns.length\n );\n }\n\n // ===== Styles =====\n\n override readonly styles = `\n /* Prevent text selection during range drag */\n :host .selecting .data-grid-row > .cell {\n user-select: none;\n }\n\n /* Row selection - use accent color for row focus */\n :host .data-grid-row.row-focus {\n background-color: var(--tbw-focus-background, rgba(from var(--tbw-color-accent) r g b / 12%));\n }\n\n /* Disable cell-focus outline in row mode - row is the focus unit */\n :host([data-selection-mode=\"row\"]) .cell-focus {\n outline: none;\n }\n\n /* Selection cell styles - for range mode */\n :host .data-grid-row > .cell.selected {\n background-color: var(--tbw-range-selection-bg);\n }\n :host .data-grid-row > .cell.selected.top {\n border-top: 2px solid var(--tbw-range-border-color);\n }\n :host .data-grid-row > .cell.selected.bottom {\n border-bottom: 2px solid var(--tbw-range-border-color);\n }\n :host .data-grid-row > .cell.selected.first {\n border-left: 2px solid var(--tbw-range-border-color);\n }\n :host .data-grid-row > .cell.selected.last {\n border-right: 2px solid var(--tbw-range-border-color);\n }\n `;\n}\n","/**\n * Core Tree Data Logic\n *\n * Pure functions for tree flattening, expansion, and traversal.\n */\n\n/* eslint-disable @typescript-eslint/no-explicit-any */\n// The tree plugin intentionally uses `any` for maximum flexibility with user-defined row types.\n\nimport type { FlattenedTreeRow, TreeConfig } from './types';\n\n/**\n * Generates a unique key for a row.\n * Uses row.id if available, otherwise generates from path.\n */\nexport function generateRowKey(row: any, index: number, parentKey: string | null): string {\n if (row.id !== undefined) return String(row.id);\n return parentKey ? `${parentKey}-${index}` : String(index);\n}\n\n/**\n * Flattens a hierarchical tree into a flat array of rows with metadata.\n * Only includes children of expanded nodes.\n */\nexport function flattenTree(\n rows: any[],\n config: TreeConfig,\n expandedKeys: Set<string>,\n parentKey: string | null = null,\n depth = 0\n): FlattenedTreeRow[] {\n const childrenField = config.childrenField ?? 'children';\n const result: FlattenedTreeRow[] = [];\n\n for (let i = 0; i < rows.length; i++) {\n const row = rows[i];\n const key = generateRowKey(row, i, parentKey);\n const children = row[childrenField];\n const hasChildren = Array.isArray(children) && children.length > 0;\n const isExpanded = expandedKeys.has(key);\n\n result.push({\n key,\n data: row,\n depth,\n hasChildren,\n isExpanded,\n parentKey,\n });\n\n // Recursively add children if expanded\n if (hasChildren && isExpanded) {\n const childRows = flattenTree(children, config, expandedKeys, key, depth + 1);\n result.push(...childRows);\n }\n }\n\n return result;\n}\n\n/**\n * Toggles the expansion state of a row.\n * Returns a new Set with the toggled state.\n */\nexport function toggleExpand(expandedKeys: Set<string>, key: string): Set<string> {\n const newExpanded = new Set(expandedKeys);\n if (newExpanded.has(key)) {\n newExpanded.delete(key);\n } else {\n newExpanded.add(key);\n }\n return newExpanded;\n}\n\n/**\n * Expands all nodes in the tree.\n * Returns a Set of all parent row keys.\n */\nexport function expandAll(rows: any[], config: TreeConfig, parentKey: string | null = null, depth = 0): Set<string> {\n const childrenField = config.childrenField ?? 'children';\n const keys = new Set<string>();\n\n for (let i = 0; i < rows.length; i++) {\n const row = rows[i];\n const key = generateRowKey(row, i, parentKey);\n const children = row[childrenField];\n\n if (Array.isArray(children) && children.length > 0) {\n keys.add(key);\n const childKeys = expandAll(children, config, key, depth + 1);\n for (const k of childKeys) keys.add(k);\n }\n }\n\n return keys;\n}\n\n/**\n * Collapses all nodes.\n * Returns an empty Set.\n */\nexport function collapseAll(): Set<string> {\n return new Set();\n}\n\n/**\n * Gets all descendants of a node from the flattened row list.\n * Useful for operations that need to affect an entire subtree.\n */\nexport function getDescendants(flattenedRows: FlattenedTreeRow[], parentKey: string): FlattenedTreeRow[] {\n const descendants: FlattenedTreeRow[] = [];\n let collecting = false;\n let parentDepth = -1;\n\n for (const row of flattenedRows) {\n if (row.key === parentKey) {\n collecting = true;\n parentDepth = row.depth;\n continue;\n }\n\n if (collecting) {\n if (row.depth > parentDepth) {\n descendants.push(row);\n } else {\n break; // No longer a descendant\n }\n }\n }\n\n return descendants;\n}\n\n/**\n * Finds the path from root to a specific row key.\n * Returns an array of keys from root to the target (inclusive).\n */\nexport function getPathToKey(\n rows: any[],\n targetKey: string,\n config: TreeConfig,\n parentKey: string | null = null,\n depth = 0\n): string[] | null {\n const childrenField = config.childrenField ?? 'children';\n\n for (let i = 0; i < rows.length; i++) {\n const row = rows[i];\n const key = generateRowKey(row, i, parentKey);\n\n if (key === targetKey) {\n return [key];\n }\n\n const children = row[childrenField];\n if (Array.isArray(children) && children.length > 0) {\n const childPath = getPathToKey(children, targetKey, config, key, depth + 1);\n if (childPath) {\n return [key, ...childPath];\n }\n }\n }\n\n return null;\n}\n\n/**\n * Expands all ancestors of a specific row to make it visible.\n * Returns a new Set with the required keys added.\n */\nexport function expandToKey(\n rows: any[],\n targetKey: string,\n config: TreeConfig,\n existingExpanded: Set<string>\n): Set<string> {\n const path = getPathToKey(rows, targetKey, config);\n if (!path) return existingExpanded;\n\n const newExpanded = new Set(existingExpanded);\n // Add all keys except the last one (the target itself)\n for (let i = 0; i < path.length - 1; i++) {\n newExpanded.add(path[i]);\n }\n return newExpanded;\n}\n","/**\n * Tree Structure Auto-Detection\n *\n * Utilities for detecting hierarchical tree data structures.\n */\n\n/* eslint-disable @typescript-eslint/no-explicit-any */\n// The tree plugin intentionally uses `any` for maximum flexibility with user-defined row types.\n\n/**\n * Detects if the data has a tree structure by checking for children arrays.\n */\nexport function detectTreeStructure(rows: any[], childrenField = 'children'): boolean {\n if (!Array.isArray(rows) || rows.length === 0) return false;\n\n // Check if any row has a non-empty children array\n for (const row of rows) {\n if (row && Array.isArray(row[childrenField]) && row[childrenField].length > 0) {\n return true;\n }\n }\n\n return false;\n}\n\n/**\n * Attempts to infer the children field name from common patterns.\n * Returns the first field that contains an array with items.\n */\nexport function inferChildrenField(rows: any[]): string | null {\n if (!Array.isArray(rows) || rows.length === 0) return null;\n\n const commonArrayFields = ['children', 'items', 'nodes', 'subRows', 'nested'];\n\n for (const row of rows) {\n if (!row || typeof row !== 'object') continue;\n\n for (const field of commonArrayFields) {\n if (Array.isArray(row[field]) && row[field].length > 0) {\n return field;\n }\n }\n }\n\n return null;\n}\n\n/**\n * Calculates the maximum depth of the tree.\n * Useful for layout calculations and virtualization.\n */\nexport function getMaxDepth(rows: any[], childrenField = 'children', currentDepth = 0): number {\n if (!Array.isArray(rows) || rows.length === 0) return currentDepth;\n\n let maxDepth = currentDepth;\n\n for (const row of rows) {\n if (!row) continue;\n const children = row[childrenField];\n if (Array.isArray(children) && children.length > 0) {\n const childDepth = getMaxDepth(children, childrenField, currentDepth + 1);\n if (childDepth > maxDepth) {\n maxDepth = childDepth;\n }\n }\n }\n\n return maxDepth;\n}\n\n/**\n * Counts total nodes in the tree (including all descendants).\n */\nexport function countNodes(rows: any[], childrenField = 'children'): number {\n if (!Array.isArray(rows)) return 0;\n\n let count = 0;\n for (const row of rows) {\n if (!row) continue;\n count++;\n const children = row[childrenField];\n if (Array.isArray(children)) {\n count += countNodes(children, childrenField);\n }\n }\n\n return count;\n}\n","/**\n * Tree Data Plugin (Class-based)\n *\n * Enables hierarchical tree data with expand/collapse and auto-detection.\n */\n\n/* eslint-disable @typescript-eslint/no-explicit-any */\n// The tree plugin intentionally uses `any` for maximum flexibility with user-defined row types.\n\nimport { BaseGridPlugin, CellClickEvent } from '../../core/plugin/base-plugin';\nimport type { ColumnConfig } from '../../core/types';\nimport { collapseAll, expandAll, expandToKey, flattenTree, toggleExpand } from './tree-data';\nimport { detectTreeStructure, inferChildrenField } from './tree-detect';\nimport type { FlattenedTreeRow, TreeConfig, TreeExpandDetail } from './types';\n\n/**\n * Tree Data Plugin for tbw-grid\n *\n * Provides hierarchical tree data display with expand/collapse functionality.\n *\n * @example\n * ```ts\n * new TreePlugin({ defaultExpanded: true, indentWidth: 24 })\n * ```\n */\nexport class TreePlugin extends BaseGridPlugin<TreeConfig> {\n readonly name = 'tree';\n override readonly version = '1.0.0';\n\n protected override get defaultConfig(): Partial<TreeConfig> {\n return {\n enabled: true,\n childrenField: 'children',\n autoDetect: true,\n defaultExpanded: false,\n indentWidth: 20,\n showExpandIcons: true,\n };\n }\n\n // ===== Internal State =====\n\n /** Set of expanded row keys */\n private expandedKeys = new Set<string>();\n\n /** Whether initial expansion (based on defaultExpanded config) has been applied */\n private initialExpansionDone = false;\n\n /** Flattened tree rows for rendering */\n private flattenedRows: FlattenedTreeRow[] = [];\n\n /** Map from key to flattened row for quick lookup */\n private rowKeyMap = new Map<string, FlattenedTreeRow>();\n\n // ===== Lifecycle =====\n\n override detach(): void {\n this.expandedKeys.clear();\n this.initialExpansionDone = false;\n this.flattenedRows = [];\n this.rowKeyMap.clear();\n }\n\n // ===== Auto-Detection =====\n\n /**\n * Detects if tree functionality should be enabled based on data structure.\n * Called by the grid during plugin initialization.\n */\n detect(rows: readonly unknown[]): boolean {\n if (!this.config.autoDetect) return false;\n const childrenField = this.config.childrenField ?? inferChildrenField(rows as any[]) ?? 'children';\n return detectTreeStructure(rows as any[], childrenField);\n }\n\n // ===== Data Processing =====\n\n override processRows(rows: readonly unknown[]): any[] {\n const childrenField = this.config.childrenField ?? 'children';\n\n // Check if data is actually a tree\n if (!detectTreeStructure(rows as any[], childrenField)) {\n this.flattenedRows = [];\n this.rowKeyMap.clear();\n return [...rows];\n }\n\n // Initialize expansion state if needed (only once per grid lifecycle)\n if (this.config.defaultExpanded && !this.initialExpansionDone) {\n this.expandedKeys = expandAll(rows as any[], this.config);\n this.initialExpansionDone = true;\n }\n\n // Flatten tree\n this.flattenedRows = flattenTree(rows as any[], this.config, this.expandedKeys);\n\n // Build key map\n this.rowKeyMap.clear();\n for (const flatRow of this.flattenedRows) {\n this.rowKeyMap.set(flatRow.key, flatRow);\n }\n\n // Return flattened data for rendering with tree metadata\n return this.flattenedRows.map((fr) => ({\n ...fr.data,\n __treeKey: fr.key,\n __treeDepth: fr.depth,\n __treeHasChildren: fr.hasChildren,\n __treeExpanded: fr.isExpanded,\n }));\n }\n\n override processColumns(columns: readonly ColumnConfig[]): ColumnConfig[] {\n if (this.flattenedRows.length === 0) return [...columns];\n\n const indentWidth = this.config.indentWidth ?? 20;\n const showExpandIcons = this.config.showExpandIcons ?? true;\n\n // Wrap first column's renderer to add tree indentation\n const cols = [...columns] as ColumnConfig[];\n if (cols.length > 0) {\n const firstCol = { ...cols[0] };\n const originalRenderer = firstCol.viewRenderer;\n\n firstCol.viewRenderer = (renderCtx) => {\n const { value, row, column: colConfig } = renderCtx;\n const depth = row.__treeDepth ?? 0;\n const hasChildren = row.__treeHasChildren ?? false;\n const isExpanded = row.__treeExpanded ?? false;\n\n const container = document.createElement('span');\n container.style.display = 'flex';\n container.style.alignItems = 'center';\n container.style.paddingLeft = `${depth * indentWidth}px`;\n\n // Expand/collapse icon\n if (hasChildren && showExpandIcons) {\n const icon = document.createElement('span');\n icon.className = 'tree-toggle';\n icon.textContent = isExpanded ? '▼' : '▶';\n icon.style.cursor = 'pointer';\n icon.style.marginRight = '4px';\n icon.style.fontSize = '10px';\n icon.setAttribute('data-tree-key', row.__treeKey);\n container.appendChild(icon);\n } else if (showExpandIcons) {\n // Spacer for alignment\n const spacer = document.createElement('span');\n spacer.style.width = '14px';\n spacer.style.display = 'inline-block';\n container.appendChild(spacer);\n }\n\n // Cell content\n const content = document.createElement('span');\n if (originalRenderer) {\n const rendered = originalRenderer(renderCtx);\n if (rendered instanceof Node) {\n content.appendChild(rendered);\n } else {\n content.textContent = String(rendered ?? value ?? '');\n }\n } else {\n content.textContent = String(value ?? '');\n }\n container.appendChild(content);\n\n return container;\n };\n\n cols[0] = firstCol;\n }\n\n return cols;\n }\n\n // ===== Event Handlers =====\n\n override onCellClick(event: CellClickEvent): boolean {\n const target = event.originalEvent?.target as HTMLElement;\n if (!target?.classList.contains('tree-toggle')) return false;\n\n const key = target.getAttribute('data-tree-key');\n if (!key) return false;\n\n const flatRow = this.rowKeyMap.get(key);\n if (!flatRow) return false;\n\n this.expandedKeys = toggleExpand(this.expandedKeys, key);\n\n this.emit<TreeExpandDetail>('tree-expand', {\n key,\n row: flatRow.data,\n expanded: this.expandedKeys.has(key),\n depth: flatRow.depth,\n });\n\n this.requestRender();\n return true;\n }\n\n // ===== Public API =====\n\n /**\n * Expand a specific node by key.\n */\n expand(key: string): void {\n this.expandedKeys.add(key);\n this.requestRender();\n }\n\n /**\n * Collapse a specific node by key.\n */\n collapse(key: string): void {\n this.expandedKeys.delete(key);\n this.requestRender();\n }\n\n /**\n * Toggle the expansion state of a node.\n */\n toggle(key: string): void {\n this.expandedKeys = toggleExpand(this.expandedKeys, key);\n this.requestRender();\n }\n\n /**\n * Expand all nodes in the tree.\n */\n expandAll(): void {\n this.expandedKeys = expandAll(this.rows as any[], this.config);\n this.requestRender();\n }\n\n /**\n * Collapse all nodes in the tree.\n */\n collapseAll(): void {\n this.expandedKeys = collapseAll();\n this.requestRender();\n }\n\n /**\n * Check if a node is currently expanded.\n */\n isExpanded(key: string): boolean {\n return this.expandedKeys.has(key);\n }\n\n /**\n * Get all currently expanded keys.\n */\n getExpandedKeys(): string[] {\n return [...this.expandedKeys];\n }\n\n /**\n * Get the flattened tree rows with metadata.\n */\n getFlattenedRows(): FlattenedTreeRow[] {\n return [...this.flattenedRows];\n }\n\n /**\n * Get a row's original data by its key.\n */\n getRowByKey(key: string): any | undefined {\n return this.rowKeyMap.get(key)?.data;\n }\n\n /**\n * Expand all ancestors of a node to make it visible.\n */\n expandToKey(key: string): void {\n this.expandedKeys = expandToKey(this.rows as any[], key, this.config, this.expandedKeys);\n this.requestRender();\n }\n\n // ===== Styles =====\n\n override readonly styles = `\n .tree-toggle {\n cursor: pointer;\n user-select: none;\n transition: transform 0.2s;\n }\n .tree-toggle:hover {\n color: var(--tbw-tree-accent, var(--tbw-color-accent));\n }\n `;\n}\n","/**\r\n * Grid DOM Constants\r\n *\r\n * Centralized constants for CSS classes, data attributes, and selectors\r\n * used throughout the grid. Use these instead of magic strings.\r\n */\r\n\r\n// ================= CSS Classes =================\r\n\r\n/**\r\n * CSS class names used in the grid's shadow DOM.\r\n * Use these when adding/removing classes or querying elements.\r\n */\r\nexport const GridClasses = {\r\n // Root structure\r\n ROOT: 'tbw-grid-root',\r\n HEADER: 'header',\r\n HEADER_ROW: 'header-row',\r\n HEADER_CELL: 'header-cell',\r\n\r\n // Body structure\r\n ROWS_VIEWPORT: 'rows-viewport',\r\n ROWS_SPACER: 'rows-spacer',\r\n ROWS_CONTAINER: 'rows',\r\n\r\n // Row elements\r\n DATA_ROW: 'data-row',\r\n GROUP_ROW: 'group-row',\r\n\r\n // Cell elements\r\n DATA_CELL: 'data-cell',\r\n\r\n // States\r\n SELECTED: 'selected',\r\n FOCUSED: 'focused',\r\n EDITING: 'editing',\r\n EXPANDED: 'expanded',\r\n COLLAPSED: 'collapsed',\r\n DRAGGING: 'dragging',\r\n RESIZING: 'resizing',\r\n\r\n // Sorting\r\n SORTABLE: 'sortable',\r\n SORTED_ASC: 'sorted-asc',\r\n SORTED_DESC: 'sorted-desc',\r\n\r\n // Visibility\r\n HIDDEN: 'hidden',\r\n\r\n // Sticky/pinned\r\n STICKY_LEFT: 'sticky-left',\r\n STICKY_RIGHT: 'sticky-right',\r\n\r\n // Special rows\r\n PINNED_TOP: 'pinned-top',\r\n PINNED_BOTTOM: 'pinned-bottom',\r\n\r\n // Tree\r\n TREE_TOGGLE: 'tree-toggle',\r\n TREE_INDENT: 'tree-indent',\r\n\r\n // Grouping\r\n GROUP_TOGGLE: 'group-toggle',\r\n GROUP_LABEL: 'group-label',\r\n GROUP_COUNT: 'group-count',\r\n\r\n // Selection\r\n RANGE_SELECTION: 'range-selection',\r\n SELECTION_OVERLAY: 'selection-overlay',\r\n} as const;\r\n\r\n// ================= Data Attributes =================\r\n\r\n/**\r\n * Data attribute names used on grid elements.\r\n * Use these when getting/setting data attributes.\r\n */\r\nexport const GridDataAttrs = {\r\n ROW_INDEX: 'data-row-index',\r\n COL_INDEX: 'data-col-index',\r\n FIELD: 'data-field',\r\n GROUP_KEY: 'data-group-key',\r\n TREE_LEVEL: 'data-tree-level',\r\n STICKY: 'data-sticky',\r\n} as const;\r\n\r\n// ================= Selectors =================\r\n\r\n/**\r\n * Common CSS selectors for querying grid elements.\r\n * Built from the class constants for consistency.\r\n */\r\nexport const GridSelectors = {\r\n ROOT: `.${GridClasses.ROOT}`,\r\n HEADER: `.${GridClasses.HEADER}`,\r\n HEADER_ROW: `.${GridClasses.HEADER_ROW}`,\r\n HEADER_CELL: `.${GridClasses.HEADER_CELL}`,\r\n ROWS_VIEWPORT: `.${GridClasses.ROWS_VIEWPORT}`,\r\n ROWS_CONTAINER: `.${GridClasses.ROWS_CONTAINER}`,\r\n DATA_ROW: `.${GridClasses.DATA_ROW}`,\r\n DATA_CELL: `.${GridClasses.DATA_CELL}`,\r\n GROUP_ROW: `.${GridClasses.GROUP_ROW}`,\r\n\r\n // By data attribute\r\n ROW_BY_INDEX: (index: number) => `.${GridClasses.DATA_ROW}[${GridDataAttrs.ROW_INDEX}=\"${index}\"]`,\r\n CELL_BY_FIELD: (field: string) => `.${GridClasses.DATA_CELL}[${GridDataAttrs.FIELD}=\"${field}\"]`,\r\n CELL_AT: (row: number, col: number) =>\r\n `.${GridClasses.DATA_ROW}[${GridDataAttrs.ROW_INDEX}=\"${row}\"] .${GridClasses.DATA_CELL}[${GridDataAttrs.COL_INDEX}=\"${col}\"]`,\r\n\r\n // State selectors\r\n SELECTED_ROWS: `.${GridClasses.DATA_ROW}.${GridClasses.SELECTED}`,\r\n EDITING_CELL: `.${GridClasses.DATA_CELL}.${GridClasses.EDITING}`,\r\n} as const;\r\n\r\n// ================= CSS Custom Properties =================\r\n\r\n/**\r\n * CSS custom property names for theming.\r\n * Use these when programmatically setting styles.\r\n */\r\nexport const GridCSSVars = {\r\n // Colors\r\n COLOR_BG: '--tbw-color-bg',\r\n COLOR_FG: '--tbw-color-fg',\r\n COLOR_FG_MUTED: '--tbw-color-fg-muted',\r\n COLOR_BORDER: '--tbw-color-border',\r\n COLOR_ACCENT: '--tbw-color-accent',\r\n COLOR_HEADER_BG: '--tbw-color-header-bg',\r\n COLOR_HEADER_FG: '--tbw-color-header-fg',\r\n COLOR_SELECTION: '--tbw-color-selection',\r\n COLOR_ROW_HOVER: '--tbw-color-row-hover',\r\n COLOR_ROW_ALT: '--tbw-color-row-alt',\r\n\r\n // Sizing\r\n ROW_HEIGHT: '--tbw-row-height',\r\n HEADER_HEIGHT: '--tbw-header-height',\r\n CELL_PADDING: '--tbw-cell-padding',\r\n\r\n // Typography\r\n FONT_FAMILY: '--tbw-font-family',\r\n FONT_SIZE: '--tbw-font-size',\r\n\r\n // Borders\r\n BORDER_RADIUS: '--tbw-border-radius',\r\n FOCUS_OUTLINE: '--tbw-focus-outline',\r\n} as const;\r\n\r\n// Type helpers\r\nexport type GridClassName = (typeof GridClasses)[keyof typeof GridClasses];\r\nexport type GridDataAttr = (typeof GridDataAttrs)[keyof typeof GridDataAttrs];\r\nexport type GridCSSVar = (typeof GridCSSVars)[keyof typeof GridCSSVars];\r\n","// Public API surface - only export what consumers need\r\nexport { DataGridElement, DataGridElement as GridElement } from './lib/core/grid';\r\n\r\n// Event name constants for DataGrid (public API)\r\nexport const DGEvents = {\r\n CELL_COMMIT: 'cell-commit',\r\n ROW_COMMIT: 'row-commit',\r\n CHANGED_ROWS_RESET: 'changed-rows-reset',\r\n MOUNT_EXTERNAL_VIEW: 'mount-external-view',\r\n MOUNT_EXTERNAL_EDITOR: 'mount-external-editor',\r\n SORT_CHANGE: 'sort-change',\r\n COLUMN_RESIZE: 'column-resize',\r\n ACTIVATE_CELL: 'activate-cell',\r\n GROUP_TOGGLE: 'group-toggle',\r\n COLUMN_STATE_CHANGE: 'column-state-change',\r\n} as const;\r\n\r\nexport type DGEventName = (typeof DGEvents)[keyof typeof DGEvents];\r\n\r\n// Plugin event constants (mirrors DGEvents pattern)\r\nexport const PluginEvents = {\r\n // Selection plugin\r\n SELECTION_CHANGE: 'selection-change',\r\n // Tree plugin\r\n TREE_EXPAND: 'tree-expand',\r\n // Filtering plugin\r\n FILTER_CHANGE: 'filter-change',\r\n // Sorting plugin\r\n SORT_MODEL_CHANGE: 'sort-model-change',\r\n // Export plugin\r\n EXPORT_START: 'export-start',\r\n EXPORT_COMPLETE: 'export-complete',\r\n // Clipboard plugin\r\n CLIPBOARD_COPY: 'clipboard-copy',\r\n CLIPBOARD_PASTE: 'clipboard-paste',\r\n // Context menu plugin\r\n CONTEXT_MENU_OPEN: 'context-menu-open',\r\n CONTEXT_MENU_CLOSE: 'context-menu-close',\r\n // Undo/Redo plugin\r\n HISTORY_CHANGE: 'history-change',\r\n // Server-side plugin\r\n SERVER_LOADING: 'server-loading',\r\n SERVER_ERROR: 'server-error',\r\n // Visibility plugin\r\n COLUMN_VISIBILITY_CHANGE: 'column-visibility-change',\r\n // Reorder plugin\r\n COLUMN_REORDER: 'column-reorder',\r\n // Master-detail plugin\r\n DETAIL_EXPAND: 'detail-expand',\r\n // Grouping rows plugin\r\n GROUP_EXPAND: 'group-expand',\r\n} as const;\r\n\r\nexport type PluginEventName = (typeof PluginEvents)[keyof typeof PluginEvents];\r\n\r\n// Public type exports\r\nexport type {\r\n ActivateCellDetail,\r\n AggregatorRef,\r\n BaseColumnConfig,\r\n // Event detail types\r\n CellCommitDetail,\r\n CellRenderContext,\r\n ChangedRowsResetDetail,\r\n ColumnConfig,\r\n ColumnConfigMap,\r\n ColumnEditorContext,\r\n // Column features\r\n ColumnEditorSpec,\r\n ColumnResizeDetail,\r\n // Column state types\r\n ColumnSortState,\r\n ColumnState,\r\n ColumnViewRenderer,\r\n DataGridCustomEvent,\r\n DataGridElement as DataGridElementInterface,\r\n DataGridEventMap,\r\n ExternalMountEditorDetail,\r\n ExternalMountViewDetail,\r\n FitMode,\r\n GridColumnState,\r\n // Core configuration types\r\n GridConfig,\r\n // Shell types\r\n HeaderContentDefinition,\r\n // Inference types\r\n InferredColumnResult,\r\n PrimitiveColumnType,\r\n // Public interface\r\n PublicGrid,\r\n RowCommitDetail,\r\n // Grouping & Footer types\r\n RowGroupRenderConfig,\r\n ShellConfig,\r\n ShellHeaderConfig,\r\n SortChangeDetail,\r\n ToolPanelConfig,\r\n ToolPanelDefinition,\r\n ToolbarButtonConfig,\r\n} from './lib/core/types';\r\n\r\n// Re-export FitModeEnum for runtime usage\r\nexport { FitModeEnum } from './lib/core/types';\r\n\r\n// ================= Plugin Types =================\r\n// Only export types that consumers need to use plugins\r\n\r\n// Selection plugin\r\nexport { SelectionPlugin } from './lib/plugins/selection/SelectionPlugin';\r\nexport type { CellRange, SelectionChangeDetail, SelectionConfig, SelectionMode } from './lib/plugins/selection/types';\r\n\r\n// Tree plugin\r\nexport { TreePlugin } from './lib/plugins/tree/TreePlugin';\r\nexport type { TreeConfig, TreeExpandDetail } from './lib/plugins/tree/types';\r\n\r\n// Filtering plugin\r\nexport type { FilterConfig, FilterModel, FilterOperator, FilterType } from './lib/plugins/filtering/types';\r\n\r\n// Multi-sort plugin\r\nexport type { MultiSortConfig, SortModel } from './lib/plugins/multi-sort/types';\r\n\r\n// Export plugin\r\nexport type { ExportFormat, ExportParams } from './lib/plugins/export/types';\r\n\r\n// Pinned rows plugin\r\nexport type { PinnedRowsContext, PinnedRowsPanel } from './lib/plugins/pinned-rows/types';\r\n\r\n// Pivot plugin\r\nexport type { PivotConfig, PivotResult, PivotValueField } from './lib/plugins/pivot/types';\r\n\r\n// Server-side plugin\r\nexport type { GetRowsParams, GetRowsResult, ServerSideDataSource } from './lib/plugins/server-side/types';\r\n\r\n// Undo/Redo plugin\r\nexport type { EditAction } from './lib/plugins/undo-redo/types';\r\n\r\n// Grouping rows plugin\r\nexport type { GroupingRowsConfig } from './lib/plugins/grouping-rows/types';\r\n\r\n// Plugin base class - for creating custom plugins\r\nexport { BaseGridPlugin } from './lib/core/plugin';\r\n\r\n// DOM constants - for querying grid elements and styling\r\nexport { GridCSSVars, GridClasses, GridDataAttrs, GridSelectors } from './lib/core/constants';\r\nexport type { GridCSSVar, GridClassName, GridDataAttr } from './lib/core/constants';\r\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// 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","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","rowHeight","viewport","y","rowIndex","vStart","vEnd","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","renderInlineRow","fastPatchRow","isChanged","hasChangedClass","children","colsLen","childLen","minLen","hasSpecialCols","rowIndexStr","displayStr","formatted","focusRow","focusCol","editMode","gridEl","fragment","colIndex","sticky","format","compiled","tplHolder","viewRenderer","externalView","needsSanitization","produced","spec","placeholder","context","output","blocked","rawTpl","tentative","isTrue","textContent","inlineEnterEdit","startRowEdit","rowElCurrent","col2","selectEl","newVal","commitCellValue","isDbl","firstCell","cellEl","active","targetCell","editor","exitRowEdit","revert","snapshot","current","rowIdx","colIdx","rowEl2","newValue","firstTime","originalValue","commit","cancel","inputLike","editorHost","editorSpec","clone","compiledEditor","node","g","hasHTMLInput","val","toggleSort","applySort","r","renderHeader","h","dir","comparator","rA","rB","headerRow","maybeTpl","span","icon","handle","hostRoot","gc","createResizeController","resizeState","pendingRaf","prevCursor","prevUserSelect","onMove","delta","width","justFinishedResize","onUp","hadResize","rect","createShellState","shouldRenderShellHeader","renderShellHeader","title","hasTitle","configButtons","hasConfigButtons","hasApiButtons","hasLightDomButtons","hasPanelToggles","showSeparator","sortedConfigButtons","sortedApiButtons","sortedPanels","toolbarHtml","btn","panel","isActive","renderShellBody","gridContentHtml","position","hasPanel","isOpen","activePanel","panelHtml","parseLightDomShell","headerEl","headerContents","toolButtons","setupShellEventListeners","shadowRoot","callbacks","toolbar","panelId","customBtn","btnId","closeBtn","renderCustomToolbarButtons","allButtons","slot","existingCleanup","cleanup","renderHeaderContent","contentArea","sortedContents","content","container","renderPanelContent","updateToolbarActiveStates","updatePanelState","panelDef","titleEl","getToolbarButtonsInfo","result","cleanupShellState","PluginManager","renderer","PluginClass","row","event","params","items","pluginItems","panels","contents","DataGridElement","#shadow","#initialized","#readyPromise","#readyResolve","#rows","#columns","#gridConfig","#fitMode","#editOn","#effectiveConfig","#connected","#scrollRaf","#pendingScrollTop","#hasScrollPlugins","#renderRowHook","#boundEsc","#boundOutside","#isDragging","#boundMouseMove","#boundMouseUp","#pluginManager","#stateChangeHandler","#initialColumnState","#shellState","#shellInitialized","oldValue","#onRowsChanged","#onColsChanged","#onGridConfigChanged","#onFitChanged","#onEditModeChanged","#injectStyles","sheet","styles","#rebuildRowModel","#processColumns","#renderHeader","#executeAfterRender","#initializePlugins","pluginsConfig","#injectAllPluginStyles","allStyles","styleEl","#updatePluginConfigs","#destroyPlugins","#collectPluginShellContributions","pluginPanels","pluginContents","#mergeEffectiveConfig","#render","#afterConnect","gridRoot","defaultOpen","#setup","#exitRowEdit","fauxScrollbar","rowsEl","currentScrollTop","subPixelOffset","#onScrollBatched","rowsBody","#handleMouseDown","#handleMouseMove","#handleMouseUp","firstRow","#updateAriaSelection","#emit","eventName","detail","isActiveRow","#autoSizeColumns","#getColumnConfiguration","visibleCols","processedColumns","processedMap","processed","originalRows","processedRows","base","domCols","map","exist","existingCols","#renderVisibleRows","#startRowEdit","configCols","existingHiddenMap","seeded","#applyColumnStateInternal","allCols","#shouldBypassVirtualization","scrollTop","scrollEvent","cellClickEvent","headerClickEvent","#buildCellMouseEvent","elAtPoint","silent","visible","wasHidden","willBeHidden","isCurrentlyHidden","order","columnMap","reordered","#applyColumnState","#refreshShellHeader","contentId","button","buttonId","disabled","apiBtn","force","totalRows","viewportHeight","visibleCount","shellConfig","hasShell","shellHeaderHtml","shellBodyHtml","#setupShellListeners","#handleToolbarButtonClick","configBtn","BaseGridPlugin","message","normalizeRange","range","toPublicRange","normalized","toPublicRanges","ranges","isCellInRange","isCellInAnyRange","getCellsInRange","cells","getAllCellsInRanges","cellMap","createRangeFromAnchor","anchor","buildSelectionEvent","colCount","SelectionPlugin","originalEvent","#buildEvent","shiftKey","ctrlKey","newRange","rowCount","allRange","_event","allRows","generateRowKey","parentKey","flattenTree","expandedKeys","depth","childrenField","hasChildren","isExpanded","childRows","toggleExpand","newExpanded","expandAll","keys","childKeys","collapseAll","getPathToKey","targetKey","childPath","expandToKey","existingExpanded","detectTreeStructure","inferChildrenField","commonArrayFields","TreePlugin","flatRow","fr","indentWidth","showExpandIcons","cols","firstCol","originalRenderer","renderCtx","colConfig","spacer","rendered","GridClasses","GridDataAttrs","GridSelectors","GridCSSVars","DGEvents","PluginEvents","builtInAggregators","acc","sum","customAggregators","aggregatorRegistry","ref","registerAggregator","unregisterAggregator","getAggregator","runAggregator","listAggregators"],"mappings":"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"}