@toolbox-web/grid 0.3.1 → 0.3.3

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 (47) hide show
  1. package/README.md +5 -4
  2. package/index.js +1210 -1188
  3. package/index.js.map +1 -1
  4. package/lib/core/grid.d.ts +2 -8
  5. package/lib/core/grid.d.ts.map +1 -1
  6. package/lib/core/internal/columns.d.ts +2 -69
  7. package/lib/core/internal/columns.d.ts.map +1 -1
  8. package/lib/core/internal/dom-builder.d.ts +7 -11
  9. package/lib/core/internal/dom-builder.d.ts.map +1 -1
  10. package/lib/core/internal/editing.d.ts.map +1 -1
  11. package/lib/core/internal/idle-scheduler.d.ts +0 -8
  12. package/lib/core/internal/idle-scheduler.d.ts.map +1 -1
  13. package/lib/core/internal/rows.d.ts +0 -5
  14. package/lib/core/internal/rows.d.ts.map +1 -1
  15. package/lib/core/internal/sanitize.d.ts +8 -0
  16. package/lib/core/internal/sanitize.d.ts.map +1 -1
  17. package/lib/core/internal/shell.d.ts +34 -18
  18. package/lib/core/internal/shell.d.ts.map +1 -1
  19. package/lib/core/internal/utils.d.ts +0 -7
  20. package/lib/core/internal/utils.d.ts.map +1 -1
  21. package/lib/core/types.d.ts +42 -15
  22. package/lib/core/types.d.ts.map +1 -1
  23. package/lib/plugins/clipboard/index.js.map +1 -1
  24. package/lib/plugins/column-virtualization/index.js.map +1 -1
  25. package/lib/plugins/context-menu/index.js.map +1 -1
  26. package/lib/plugins/export/index.js.map +1 -1
  27. package/lib/plugins/filtering/index.js.map +1 -1
  28. package/lib/plugins/grouping-columns/index.js.map +1 -1
  29. package/lib/plugins/grouping-rows/index.js.map +1 -1
  30. package/lib/plugins/master-detail/index.js.map +1 -1
  31. package/lib/plugins/multi-sort/index.js.map +1 -1
  32. package/lib/plugins/pinned-columns/index.js.map +1 -1
  33. package/lib/plugins/pinned-rows/index.js.map +1 -1
  34. package/lib/plugins/pivot/index.js.map +1 -1
  35. package/lib/plugins/reorder/index.js.map +1 -1
  36. package/lib/plugins/selection/index.js.map +1 -1
  37. package/lib/plugins/server-side/index.js.map +1 -1
  38. package/lib/plugins/tree/index.js.map +1 -1
  39. package/lib/plugins/undo-redo/index.js.map +1 -1
  40. package/lib/plugins/visibility/index.js.map +1 -1
  41. package/package.json +1 -1
  42. package/public.d.ts +6 -0
  43. package/public.d.ts.map +1 -1
  44. package/umd/grid.all.umd.js +21 -21
  45. package/umd/grid.all.umd.js.map +1 -1
  46. package/umd/grid.umd.js +11 -11
  47. package/umd/grid.umd.js.map +1 -1
@@ -1 +1 @@
1
- {"version":3,"file":"index.js","sources":["../../../../../../libs/grid/src/lib/core/types.ts","../../../../../../libs/grid/src/lib/core/plugin/base-plugin.ts","../../../../../../libs/grid/src/lib/core/internal/aggregators.ts","../../../../../../libs/grid/src/lib/plugins/pivot/pivot-model.ts","../../../../../../libs/grid/src/lib/plugins/pivot/pivot-engine.ts","../../../../../../libs/grid/src/lib/plugins/pivot/pivot-panel.ts","../../../../../../libs/grid/src/lib/plugins/pivot/pivot-rows.ts","../../../../../../libs/grid/src/lib/plugins/pivot/PivotPlugin.ts"],"sourcesContent":["import type { PluginQuery } from './plugin/base-plugin';\n\n/**\n * The compiled webcomponent interface for DataGrid\n */\nexport interface DataGridElement extends PublicGrid, HTMLElement {}\n\n/**\n * Public API interface for DataGrid component.\n *\n * **Property Getters vs Setters:**\n *\n * Property getters return the EFFECTIVE (resolved) value after merging all config sources.\n * This is the \"current situation\" - what consumers and plugins need to know.\n *\n * Property setters accept input values which are merged into the effective config.\n * Multiple sources can contribute (gridConfig, columns prop, light DOM, individual props).\n *\n * For example:\n * - `grid.fitMode` returns the resolved fitMode (e.g., 'stretch' even if you set undefined)\n * - `grid.columns` returns the effective columns after merging\n * - `grid.gridConfig` returns the full effective config\n */\nexport interface PublicGrid<T = any> {\n /**\n * Full config object. Setter merges with other inputs per precedence rules.\n * Getter returns the effective (resolved) config.\n */\n gridConfig?: GridConfig<T>;\n /**\n * Column definitions.\n * Getter returns effective columns (after merging config, light DOM, inference).\n */\n columns?: ColumnConfig<T>[];\n /** Current row data (after plugin processing like grouping, filtering). */\n rows?: T[];\n /** Resolves once the component has finished initial work (layout, inference). */\n ready?: () => Promise<void>;\n /** Force a layout / measurement pass (e.g. after container resize). */\n forceLayout?: () => Promise<void>;\n /** Return effective resolved config (after inference & precedence). */\n getConfig?: () => Promise<Readonly<GridConfig<T>>>;\n /** Toggle expansion state of a group row by its generated key. */\n toggleGroup?: (key: string) => Promise<void>;\n\n // Custom Styles API\n /**\n * Register custom CSS styles to be injected into the grid's shadow DOM.\n * Use this to style custom cell renderers, editors, or detail panels.\n * @param id - Unique identifier for the style block (for removal/updates)\n * @param css - CSS string to inject\n */\n registerStyles?: (id: string, css: string) => void;\n /**\n * Remove previously registered custom styles.\n * @param id - The ID used when registering the styles\n */\n unregisterStyles?: (id: string) => void;\n /**\n * Get list of registered custom style IDs.\n */\n getRegisteredStyles?: () => string[];\n}\n\n/**\n * Internal-only augmented interface for DataGrid component\n */\nexport interface InternalGrid<T = any> extends PublicGrid<T>, GridConfig<T> {\n shadowRoot: ShadowRoot | null;\n _rows: T[];\n _columns: ColumnInternal<T>[];\n /** Visible columns only (excludes hidden). Use for rendering. */\n _visibleColumns: ColumnInternal<T>[];\n _headerRowEl: HTMLElement;\n _bodyEl: HTMLElement;\n _rowPool: HTMLElement[];\n _resizeController: ResizeController;\n _sortState: { field: string; direction: 1 | -1 } | null;\n __originalOrder: T[];\n __rowRenderEpoch: number;\n __didInitialAutoSize?: boolean;\n __lightDomColumnsCache?: ColumnInternal[];\n __originalColumnNodes?: HTMLElement[];\n _gridTemplate: string;\n _virtualization: VirtualState;\n _focusRow: number;\n _focusCol: number;\n _activeEditRows: number;\n _rowEditSnapshots: Map<number, T>;\n _changedRowIndices: Set<number>;\n changedRows?: T[];\n changedRowIndices?: number[];\n effectiveConfig?: GridConfig<T>;\n findHeaderRow?: () => HTMLElement;\n refreshVirtualWindow: (full: boolean) => void;\n updateTemplate?: () => void;\n findRenderedRowElement?: (rowIndex: number) => HTMLElement | null;\n beginBulkEdit?: (rowIndex: number) => void;\n commitActiveRowEdit?: () => void;\n /** Dispatch cell click to plugin system, returns true if handled */\n _dispatchCellClick?: (event: MouseEvent, rowIndex: number, colIndex: number, cellEl: HTMLElement) => boolean;\n /** Dispatch row click to plugin system, returns true if handled */\n _dispatchRowClick?: (event: MouseEvent, rowIndex: number, row: any, rowEl: HTMLElement) => boolean;\n /** Dispatch header click to plugin system, returns true if handled */\n _dispatchHeaderClick?: (event: MouseEvent, colIndex: number, headerEl: HTMLElement) => boolean;\n /** Dispatch keydown to plugin system, returns true if handled */\n _dispatchKeyDown?: (event: KeyboardEvent) => boolean;\n /** Get horizontal scroll boundary offsets from plugins */\n _getHorizontalScrollOffsets?: (\n rowEl?: HTMLElement,\n focusedCell?: HTMLElement,\n ) => { left: number; right: number; skipScroll?: boolean };\n /** Query all plugins with a generic query and collect responses */\n queryPlugins?: <T>(query: PluginQuery) => T[];\n /** Request emission of column-state-change event (debounced) */\n requestStateChange?: () => void;\n}\n\nexport type PrimitiveColumnType = 'number' | 'string' | 'date' | 'boolean' | 'select' | 'typeahead';\n\n/**\n * Base contract for a column. Public; kept intentionally lean so host apps can extend via intersection types.\n * Prefer adding optional properties here only when broadly useful to most grids.\n */\nexport interface BaseColumnConfig<TRow = any, TValue = any> {\n /** Unique field key referencing property in row objects */\n field: keyof TRow & string;\n /** Visible header label; defaults to capitalized field */\n header?: string;\n /** Column data type; inferred if omitted */\n type?: PrimitiveColumnType;\n /** Column width in pixels; fixed size (no flexibility) */\n width?: string | number;\n /** Minimum column width in pixels (stretch mode only); when set, column uses minmax(minWidth, 1fr) */\n minWidth?: number;\n /** Whether column can be sorted */\n sortable?: boolean;\n /** Whether column can be resized by user */\n resizable?: boolean;\n /** Optional custom comparator for sorting (a,b) -> number */\n sortComparator?: (a: TValue, b: TValue, rowA: TRow, rowB: TRow) => number;\n /** Whether the field is editable (enables editors) */\n editable?: boolean;\n /** Optional custom editor factory or element tag name */\n editor?: ColumnEditorSpec<TRow, TValue>;\n /** For select/typeahead types - available options */\n options?: Array<{ label: string; value: unknown }> | (() => Array<{ label: string; value: unknown }>);\n /** For select/typeahead - allow multi select */\n multi?: boolean;\n /** Optional formatter */\n format?: (value: TValue, row: TRow) => string;\n /** Arbitrary extra metadata */\n meta?: Record<string, unknown>;\n}\n\n/**\n * Full column configuration including optional custom view/renderer & grouping metadata.\n */\nexport interface ColumnConfig<TRow = any> extends BaseColumnConfig<TRow, any> {\n /** Optional custom view renderer used instead of default text rendering */\n viewRenderer?: ColumnViewRenderer<TRow, any>;\n /** External view spec (lets host app mount any framework component) */\n externalView?: {\n component: unknown;\n props?: Record<string, unknown>;\n mount?: (options: {\n placeholder: HTMLElement;\n context: CellRenderContext<TRow, unknown>;\n spec: unknown;\n }) => void | { dispose?: () => void };\n };\n /** Whether the column is initially hidden */\n hidden?: boolean;\n /** Prevent this column from being hidden programmatically */\n lockVisible?: boolean;\n}\n\nexport type ColumnConfigMap<TRow = any> = ColumnConfig<TRow>[];\n\n/** External editor spec: tag name, factory function, or external mount spec */\nexport type ColumnEditorSpec<TRow = unknown, TValue = unknown> =\n | string // custom element tag name\n | ((context: ColumnEditorContext<TRow, TValue>) => HTMLElement | string)\n | {\n /** Arbitrary component reference (class, function, token) */\n component: unknown;\n /** Optional static props passed to mount */\n props?: Record<string, unknown>;\n /** Optional custom mount function; if provided we call it directly instead of emitting an event */\n mount?: (options: {\n placeholder: HTMLElement;\n context: ColumnEditorContext<TRow, TValue>;\n spec: unknown;\n }) => void | { dispose?: () => void };\n };\n\n/**\n * Context object provided to editor factories allowing mutation (commit/cancel) of a cell value.\n */\nexport interface ColumnEditorContext<TRow = any, TValue = any> {\n /** Underlying full row object for the active edit. */\n row: TRow;\n /** Current cell value (mutable only via commit). */\n value: TValue;\n /** Field name being edited. */\n field: keyof TRow & string;\n /** Column configuration reference. */\n column: ColumnConfig<TRow>;\n /** Accept the edit; triggers change tracking + rerender. */\n commit: (newValue: TValue) => void;\n /** Abort edit without persisting changes. */\n cancel: () => void;\n}\n\n/**\n * Context passed to custom view renderers (pure display – no commit helpers).\n */\nexport interface CellRenderContext<TRow = any, TValue = any> {\n /** Row object for the cell being rendered. */\n row: TRow;\n /** Value at field. */\n value: TValue;\n /** Field key. */\n field: keyof TRow & string;\n /** Column configuration reference. */\n column: ColumnConfig<TRow>;\n}\n\nexport type ColumnViewRenderer<TRow = unknown, TValue = unknown> = (\n ctx: CellRenderContext<TRow, TValue>,\n) => Node | string | void;\n\n/**\n * Framework adapter interface for handling framework-specific component instantiation.\n * Allows framework libraries (Angular, React, Vue) to register handlers that convert\n * declarative light DOM elements into functional renderers/editors.\n *\n * @example\n * ```typescript\n * // In @toolbox-web/grid-angular\n * class AngularGridAdapter implements FrameworkAdapter {\n * canHandle(element: HTMLElement): boolean {\n * return element.tagName.startsWith('APP-');\n * }\n * createRenderer(element: HTMLElement): ColumnViewRenderer {\n * return (ctx) => {\n * // Angular-specific instantiation logic\n * const componentRef = createComponent(...);\n * componentRef.setInput('value', ctx.value);\n * return componentRef.location.nativeElement;\n * };\n * }\n * createEditor(element: HTMLElement): ColumnEditorSpec {\n * return (ctx) => {\n * // Angular-specific editor with commit/cancel\n * const componentRef = createComponent(...);\n * componentRef.setInput('value', ctx.value);\n * // Subscribe to commit/cancel outputs\n * return componentRef.location.nativeElement;\n * };\n * }\n * }\n *\n * // User registers adapter once in their app\n * GridElement.registerAdapter(new AngularGridAdapter(injector, appRef));\n * ```\n */\nexport interface FrameworkAdapter {\n /**\n * Determines if this adapter can handle the given element.\n * Typically checks tag name, attributes, or other conventions.\n */\n canHandle(element: HTMLElement): boolean;\n\n /**\n * Creates a view renderer function from a light DOM element.\n * The renderer receives cell context and returns DOM or string.\n */\n createRenderer<TRow = unknown, TValue = unknown>(element: HTMLElement): ColumnViewRenderer<TRow, TValue>;\n\n /**\n * Creates an editor spec from a light DOM element.\n * The editor receives context with commit/cancel and returns DOM.\n */\n createEditor<TRow = unknown, TValue = unknown>(element: HTMLElement): ColumnEditorSpec<TRow, TValue>;\n\n /**\n * Creates a tool panel renderer from a light DOM element.\n * The renderer receives a container element and optionally returns a cleanup function.\n */\n createToolPanelRenderer?(element: HTMLElement): ((container: HTMLElement) => void | (() => void)) | undefined;\n}\n\n// #region Internal-only augmented types (not re-exported publicly)\nexport interface ColumnInternal<T = any> extends ColumnConfig<T> {\n __autoSized?: boolean;\n __userResized?: boolean;\n __renderedWidth?: number;\n /** Original configured width (for reset on double-click) */\n __originalWidth?: number;\n __viewTemplate?: HTMLElement;\n __editorTemplate?: HTMLElement;\n __headerTemplate?: HTMLElement;\n __compiledView?: (ctx: CellContext<T>) => string;\n __compiledEditor?: (ctx: EditorExecContext<T>) => string;\n}\n\n/**\n * Runtime cell context used internally for compiled template execution.\n */\nexport interface CellContext<T = any> {\n row: T;\n value: unknown;\n field: string;\n column: ColumnInternal<T>;\n}\n\n/**\n * Internal editor execution context extending the generic cell context with commit helpers.\n */\nexport interface EditorExecContext<T = any> extends CellContext<T> {\n commit: (newValue: unknown) => void;\n cancel: () => void;\n}\n\n/** Controller managing drag-based column resize lifecycle. */\nexport interface ResizeController {\n start: (e: MouseEvent, colIndex: number, cell: HTMLElement) => void;\n /** Reset a column to its configured width (or auto-size if none configured). */\n resetColumn: (colIndex: number) => void;\n dispose: () => void;\n /** True while a resize drag is in progress (used to suppress header click/sort). */\n isResizing: boolean;\n}\n\n/** Virtual window bookkeeping; modified in-place as scroll position changes. */\nexport interface VirtualState {\n enabled: boolean;\n rowHeight: number;\n /** Threshold for bypassing virtualization (renders all rows if totalRows <= bypassThreshold) */\n bypassThreshold: number;\n start: number;\n end: number;\n /** Faux scrollbar element that provides scroll events (AG Grid pattern) */\n container: HTMLElement | null;\n /** Rows viewport element for measuring visible area height */\n viewportEl: HTMLElement | null;\n /** Spacer element inside faux scrollbar for setting virtual height */\n totalHeightEl: HTMLElement | null;\n}\n// #endregion\n\n// #region Grouping & Footer Public Types\n/**\n * Group row rendering customization options.\n * Used within grouping-rows plugin config for presentation of group rows.\n */\nexport interface RowGroupRenderConfig {\n /** If true, group rows span all columns (single full-width cell). Default false. */\n fullWidth?: boolean;\n /** Optional label formatter override. Receives raw group value + depth. */\n formatLabel?: (value: unknown, depth: number, key: string) => string;\n /** Optional aggregate overrides per field for group summary cells (only when not fullWidth). */\n aggregators?: Record<string, AggregatorRef>;\n /** Additional CSS class applied to each group row root element. */\n class?: string;\n}\n\nexport type AggregatorRef = string | ((rows: unknown[], field: string, column?: unknown) => unknown);\n\n/** Result of automatic column inference from sample rows. */\nexport interface InferredColumnResult<TRow = unknown> {\n columns: ColumnConfigMap<TRow>;\n typeMap: Record<string, PrimitiveColumnType>;\n}\n\nexport const FitModeEnum = {\n STRETCH: 'stretch',\n FIXED: 'fixed',\n} as const;\nexport type FitMode = (typeof FitModeEnum)[keyof typeof FitModeEnum]; // evaluates to 'stretch' | 'fixed'\n// #endregion\n\n// #region Plugin Interface\n/**\n * Minimal plugin interface for type-checking.\n * This interface is defined here to avoid circular imports with BaseGridPlugin.\n * All plugins must satisfy this shape (BaseGridPlugin implements it).\n */\nexport interface GridPlugin {\n /** Unique plugin identifier */\n readonly name: string;\n /** Plugin version */\n readonly version: string;\n /** CSS styles to inject into grid's shadow DOM */\n readonly styles?: string;\n}\n// #endregion\n\n// #region Grid Config\n/**\n * Grid configuration object - the **single source of truth** for grid behavior.\n *\n * Users can configure the grid via multiple input methods, all of which converge\n * into an effective `GridConfig` internally:\n *\n * **Configuration Input Methods:**\n * - `gridConfig` property - direct assignment of this object\n * - `columns` property - shorthand for `gridConfig.columns`\n * - `fitMode` property - shorthand for `gridConfig.fitMode`\n * - `editOn` property - shorthand for `gridConfig.editOn`\n * - Light DOM `<tbw-grid-column>` - declarative columns (merged into `columns`)\n * - Light DOM `<tbw-grid-header>` - declarative shell header (merged into `shell.header`)\n *\n * **Precedence (when same property set multiple ways):**\n * Individual props (`fitMode`, `editOn`) > `columns` prop > Light DOM > `gridConfig`\n *\n * @example\n * ```ts\n * // Via gridConfig (recommended for complex setups)\n * grid.gridConfig = {\n * columns: [{ field: 'name' }, { field: 'age' }],\n * fitMode: 'stretch',\n * plugins: [new SelectionPlugin()],\n * shell: { header: { title: 'My Grid' } }\n * };\n *\n * // Via individual props (convenience for simple cases)\n * grid.columns = [{ field: 'name' }, { field: 'age' }];\n * grid.fitMode = 'stretch';\n * ```\n */\nexport interface GridConfig<TRow = any> {\n /** Column definitions. Can also be set via `columns` prop or `<tbw-grid-column>` light DOM. */\n columns?: ColumnConfigMap<TRow>;\n /** Sizing mode for columns. Can also be set via `fitMode` prop. */\n fitMode?: FitMode;\n /** Edit activation mode ('click' | 'dblClick' | false). Set to false to disable editing. Can also be set via `editOn` prop. */\n editOn?: string | boolean;\n /**\n * Row height in pixels for virtualization calculations.\n * The virtualization system assumes uniform row heights for performance.\n *\n * If not specified, the grid measures the first rendered row's height,\n * which respects the CSS variable `--tbw-row-height` set by themes.\n *\n * Set this explicitly when:\n * - Row content may wrap to multiple lines (also set `--tbw-cell-white-space: normal`)\n * - Using custom row templates with variable content\n * - You want to override theme-defined row height\n *\n * @default Auto-measured from first row (respects --tbw-row-height CSS variable)\n *\n * @example\n * ```ts\n * // Fixed height for rows that may wrap to 2 lines\n * gridConfig = { rowHeight: 56 };\n * ```\n */\n rowHeight?: number;\n /**\n * Array of plugin instances.\n * Each plugin is instantiated with its configuration and attached to this grid.\n *\n * @example\n * ```ts\n * plugins: [\n * new SelectionPlugin({ mode: 'range' }),\n * new MultiSortPlugin(),\n * new FilteringPlugin({ debounceMs: 150 }),\n * ]\n * ```\n */\n plugins?: GridPlugin[];\n\n /**\n * Saved column state to restore on initialization.\n * Includes order, width, visibility, sort, and plugin-contributed state.\n */\n columnState?: GridColumnState;\n\n /**\n * Shell configuration for header bar and tool panels.\n * When configured, adds an optional wrapper with title, toolbar, and collapsible side panels.\n */\n shell?: ShellConfig;\n\n /**\n * Grid-wide icon configuration.\n * Provides consistent icons across all plugins (tree, grouping, sorting, etc.).\n * Plugins will use these by default but can override with their own config.\n */\n icons?: GridIcons;\n\n /**\n * Grid-wide animation configuration.\n * Controls animations for expand/collapse, reordering, and other visual transitions.\n * Individual plugins can override these defaults in their own config.\n */\n animation?: AnimationConfig;\n\n /**\n * Custom sort handler for full control over sorting behavior.\n *\n * When provided, this handler is called instead of the built-in sorting logic.\n * Enables custom sorting algorithms, server-side sorting, or plugin-specific sorting.\n *\n * The handler receives:\n * - `rows`: Current row array to sort\n * - `sortState`: Sort field and direction (1 = asc, -1 = desc)\n * - `columns`: Column configurations (for accessing sortComparator)\n *\n * Return the sorted array (sync) or a Promise that resolves to the sorted array (async).\n * For server-side sorting, return a Promise that resolves when data is fetched.\n *\n * @example\n * ```ts\n * // Custom stable sort\n * sortHandler: (rows, state, cols) => {\n * return stableSort(rows, (a, b) => compare(a[state.field], b[state.field]) * state.direction);\n * }\n *\n * // Server-side sorting\n * sortHandler: async (rows, state) => {\n * const response = await fetch(`/api/data?sort=${state.field}&dir=${state.direction}`);\n * return response.json();\n * }\n * ```\n */\n sortHandler?: SortHandler<TRow>;\n}\n// #endregion\n\n// #region Animation\n\n/**\n * Sort state passed to custom sort handlers.\n */\nexport interface SortState {\n /** Field to sort by */\n field: string;\n /** Sort direction: 1 = ascending, -1 = descending */\n direction: 1 | -1;\n}\n\n/**\n * Custom sort handler function signature.\n *\n * @param rows - Current row array to sort\n * @param sortState - Sort field and direction\n * @param columns - Column configurations (for accessing sortComparator)\n * @returns Sorted array (sync) or Promise resolving to sorted array (async)\n */\nexport type SortHandler<TRow = any> = (\n rows: TRow[],\n sortState: SortState,\n columns: ColumnConfig<TRow>[],\n) => TRow[] | Promise<TRow[]>;\n\n/**\n * Animation behavior mode.\n * - `true` or `'on'`: Animations always enabled\n * - `false` or `'off'`: Animations always disabled\n * - `'reduced-motion'`: Respects `prefers-reduced-motion` media query (default)\n */\nexport type AnimationMode = boolean | 'on' | 'off' | 'reduced-motion';\n\n/**\n * Animation style for visual transitions.\n * - `'slide'`: Slide/transform animation (e.g., expand down, slide left/right)\n * - `'fade'`: Opacity fade animation\n * - `'flip'`: FLIP technique for position changes (First, Last, Invert, Play)\n * - `false`: No animation for this specific feature\n */\nexport type AnimationStyle = 'slide' | 'fade' | 'flip' | false;\n\n/**\n * Animation style for expand/collapse operations.\n * Subset of AnimationStyle - excludes 'flip' which is for position changes.\n * - `'slide'`: Slide down/up animation for expanding/collapsing content\n * - `'fade'`: Fade in/out animation\n * - `false`: No animation\n */\nexport type ExpandCollapseAnimation = 'slide' | 'fade' | false;\n\n/**\n * Grid-wide animation configuration.\n * Controls global animation behavior - individual plugins define their own animation styles.\n * Duration and easing values set corresponding CSS variables on the grid element.\n */\nexport interface AnimationConfig {\n /**\n * Global animation mode.\n * @default 'reduced-motion'\n */\n mode?: AnimationMode;\n\n /**\n * Default animation duration in milliseconds.\n * Sets `--tbw-animation-duration` CSS variable.\n * @default 200\n */\n duration?: number;\n\n /**\n * Default easing function.\n * Sets `--tbw-animation-easing` CSS variable.\n * @default 'ease-out'\n */\n easing?: string;\n}\n\n/** Default animation configuration */\nexport const DEFAULT_ANIMATION_CONFIG: Required<Omit<AnimationConfig, 'sort'>> = {\n mode: 'reduced-motion',\n duration: 200,\n easing: 'ease-out',\n};\n\n// #endregion\n\n// #region Grid Icons\n\n/** Icon value - can be a string (text/HTML) or HTMLElement */\nexport type IconValue = string | HTMLElement;\n\n/**\n * Grid-wide icon configuration.\n * All icons are optional - sensible defaults are used when not specified.\n */\nexport interface GridIcons {\n /** Expand icon for collapsed items (trees, groups, details). Default: '▶' */\n expand?: IconValue;\n /** Collapse icon for expanded items (trees, groups, details). Default: '▼' */\n collapse?: IconValue;\n /** Sort ascending indicator. Default: '▲' */\n sortAsc?: IconValue;\n /** Sort descending indicator. Default: '▼' */\n sortDesc?: IconValue;\n /** Sort neutral/unsorted indicator. Default: '⇅' */\n sortNone?: IconValue;\n /** Submenu arrow for context menus. Default: '▶' */\n submenuArrow?: IconValue;\n /** Drag handle icon for reordering. Default: '⋮⋮' */\n dragHandle?: IconValue;\n /** Tool panel toggle icon in toolbar. Default: '☰' */\n toolPanel?: IconValue;\n}\n\n/** Default icons used when not overridden */\nexport const DEFAULT_GRID_ICONS: Required<GridIcons> = {\n expand: '▶',\n collapse: '▼',\n sortAsc: '▲',\n sortDesc: '▼',\n sortNone: '⇅',\n submenuArrow: '▶',\n dragHandle: '⋮⋮',\n toolPanel: '☰',\n};\n// #endregion\n\n// #region Shell Configuration\n\n/**\n * Shell configuration for the grid's optional header bar and tool panels.\n */\nexport interface ShellConfig {\n /** Shell header bar configuration */\n header?: ShellHeaderConfig;\n /** Tool panel configuration */\n toolPanel?: ToolPanelConfig;\n}\n\n/**\n * Shell header bar configuration\n */\nexport interface ShellHeaderConfig {\n /** Grid title displayed on the left (optional) */\n title?: string;\n /** Custom toolbar buttons (rendered before tool panel toggles) */\n toolbarButtons?: ToolbarButtonConfig[];\n}\n\n/**\n * Tool panel configuration\n */\nexport interface ToolPanelConfig {\n /** Panel position: 'left' | 'right' (default: 'right') */\n position?: 'left' | 'right';\n /** Default panel width in pixels (default: 280) */\n width?: number;\n /** Panel ID to open by default on load */\n defaultOpen?: string;\n /** Whether to persist open/closed state (requires Column State Events) */\n persistState?: boolean;\n}\n\n/**\n * Toolbar button defined via config (programmatic approach).\n * Supports three modes:\n * - Simple: provide `icon` + `action` for grid to create button\n * - Element: provide `element` for user-created DOM\n * - Render: provide `render` function for complex widgets\n */\nexport interface ToolbarButtonConfig {\n /** Unique button ID */\n id: string;\n /** Tooltip / aria-label (required for accessibility) */\n label: string;\n /** Order priority (lower = first, default: 100) */\n order?: number;\n /** Whether button is disabled (only applies to grid-rendered buttons) */\n disabled?: boolean;\n\n // ===== Option A: Simple - Grid renders the button =====\n /** Button content: SVG string, emoji, or text. Grid creates <button> with this. */\n icon?: string;\n /** Click handler (required when using icon) */\n action?: () => void;\n\n // ===== Option B: Custom DOM - User provides element or render function =====\n /**\n * User-provided element. Grid wraps it but doesn't modify it.\n * User is responsible for event handlers.\n */\n element?: HTMLElement;\n /**\n * Render function called once. Receives container, user appends their DOM.\n * User is responsible for event handlers.\n * Return a cleanup function (optional).\n */\n render?: (container: HTMLElement) => void | (() => void);\n}\n\n/**\n * Toolbar button info returned by getToolbarButtons().\n */\nexport interface ToolbarButtonInfo {\n id: string;\n label: string;\n disabled: boolean;\n /** Source of this button: 'config' | 'light-dom' | 'panel-toggle' */\n source: 'config' | 'light-dom' | 'panel-toggle';\n /** For panel toggles, the associated panel ID */\n panelId?: string;\n}\n\n/**\n * Tool panel definition registered by plugins or consumers.\n */\nexport interface ToolPanelDefinition {\n /** Unique panel ID */\n id: string;\n /** Panel title shown in accordion header */\n title: string;\n /** Icon for accordion section header (optional, emoji or SVG) */\n icon?: string;\n /** Tooltip for accordion section header */\n tooltip?: string;\n /** Panel content factory - called when panel section opens */\n render: (container: HTMLElement) => void | (() => void);\n /** Called when panel closes (for cleanup) */\n onClose?: () => void;\n /** Panel order priority (lower = first, default: 100) */\n order?: number;\n}\n\n/**\n * Header content definition for plugins contributing to shell header center section.\n */\nexport interface HeaderContentDefinition {\n /** Unique content ID */\n id: string;\n /** Content factory - called once when shell header renders */\n render: (container: HTMLElement) => void | (() => void);\n /** Called when content is removed (for cleanup) */\n onDestroy?: () => void;\n /** Order priority (lower = first, default: 100) */\n order?: number;\n}\n// #endregion\n\n// #region Column State (Persistence)\n\n/**\n * State for a single column. Captures user-driven changes at runtime.\n * Plugins can extend this interface via module augmentation to add their own state.\n *\n * @example\n * ```ts\n * // In filtering plugin\n * declare module '@toolbox-web/grid' {\n * interface ColumnState {\n * filter?: FilterValue;\n * }\n * }\n * ```\n */\nexport interface ColumnState {\n /** Column field identifier */\n field: string;\n /** Position index after reordering (0-based) */\n order: number;\n /** Width in pixels (undefined = use default) */\n width?: number;\n /** Visibility state */\n visible: boolean;\n /** Sort state (undefined = not sorted) */\n sort?: ColumnSortState;\n}\n\n/**\n * Sort state for a column\n */\nexport interface ColumnSortState {\n /** Sort direction */\n direction: 'asc' | 'desc';\n /** Priority for multi-sort (0 = primary, 1 = secondary, etc.) */\n priority: number;\n}\n\n/**\n * Complete grid column state for persistence.\n * Contains state for all columns, including plugin-contributed properties.\n */\nexport interface GridColumnState {\n columns: ColumnState[];\n}\n// #endregion\n\n// #region Public Event Detail Interfaces\nexport interface CellCommitDetail<TRow = unknown> {\n /** The mutated row after commit. */\n row: TRow;\n /** Field name whose value changed. */\n field: string;\n /** New value stored. */\n value: unknown;\n /** Index of the row in current data set. */\n rowIndex: number;\n /** All rows that have at least one committed change (snapshot list). */\n changedRows: TRow[];\n /** Indices parallel to changedRows. */\n changedRowIndices: number[];\n /** True if this row just entered the changed set. */\n firstTimeForRow: boolean;\n}\n\n/** Detail payload for a committed row edit (may or may not include changes). */\nexport interface RowCommitDetail<TRow = unknown> {\n /** Row index that lost edit focus. */\n rowIndex: number;\n /** Row object reference. */\n row: TRow;\n /** Whether any cell changes were actually committed in this row during the session. */\n changed: boolean;\n /** Current changed row collection. */\n changedRows: TRow[];\n /** Indices of changed rows. */\n changedRowIndices: number[];\n}\n\n/** Emitted when the changed rows tracking set is cleared programmatically. */\nexport interface ChangedRowsResetDetail<TRow = unknown> {\n /** New (empty) changed rows array after reset. */\n rows: TRow[];\n /** Parallel indices (likely empty). */\n indices: number[];\n}\n\n/** Detail for a sort change (direction 0 indicates cleared sort). */\nexport interface SortChangeDetail {\n /** Sorted field key. */\n field: string;\n /** Direction: 1 ascending, -1 descending, 0 cleared. */\n direction: 1 | -1 | 0;\n}\n\n/** Column resize event detail containing final pixel width. */\nexport interface ColumnResizeDetail {\n /** Resized column field key. */\n field: string;\n /** New width in pixels. */\n width: number;\n}\n\n/** Fired when keyboard navigation or programmatic focus changes active cell. */\nexport interface ActivateCellDetail {\n /** Zero-based row index now focused. */\n row: number;\n /** Zero-based column index now focused. */\n col: number;\n}\n\nexport interface ExternalMountViewDetail<TRow = unknown> {\n placeholder: HTMLElement;\n spec: unknown;\n context: { row: TRow; value: unknown; field: string; column: unknown };\n}\n\nexport interface ExternalMountEditorDetail<TRow = unknown> {\n placeholder: HTMLElement;\n spec: unknown;\n context: {\n row: TRow;\n value: unknown;\n field: string;\n column: unknown;\n commit: (v: unknown) => void;\n cancel: () => void;\n };\n}\n\nexport interface DataGridEventMap<TRow = unknown> {\n 'cell-commit': CellCommitDetail<TRow>;\n 'row-commit': RowCommitDetail<TRow>;\n 'changed-rows-reset': ChangedRowsResetDetail<TRow>;\n 'mount-external-view': ExternalMountViewDetail<TRow>;\n 'mount-external-editor': ExternalMountEditorDetail<TRow>;\n 'sort-change': SortChangeDetail;\n 'column-resize': ColumnResizeDetail;\n 'activate-cell': ActivateCellDetail;\n 'column-state-change': GridColumnState;\n}\n\nexport type DataGridEventDetail<K extends keyof DataGridEventMap<unknown>, TRow = unknown> = DataGridEventMap<TRow>[K];\nexport type DataGridCustomEvent<K extends keyof DataGridEventMap<unknown>, TRow = unknown> = CustomEvent<\n DataGridEventMap<TRow>[K]\n>;\n\n// Internal code now reuses the public ColumnEditorContext; provide alias for backward compatibility\nexport type EditorContext<T = unknown> = ColumnEditorContext<T, unknown>;\n\nexport interface EvalContext {\n value: unknown;\n row: Record<string, unknown> | null;\n}\n// #endregion\n","/**\n * Base Grid Plugin Class\n *\n * All plugins extend this abstract class.\n * Plugins are instantiated per-grid and manage their own state.\n */\n\nimport type {\n ColumnConfig,\n ColumnState,\n GridPlugin,\n HeaderContentDefinition,\n IconValue,\n ToolPanelDefinition,\n} from '../types';\nimport { DEFAULT_GRID_ICONS } from '../types';\n\n// Re-export shared plugin types for convenience\nexport { PLUGIN_QUERIES } from './types';\nexport type {\n CellClickEvent,\n CellCoords,\n CellEditor,\n CellMouseEvent,\n CellRenderer,\n ContextMenuItem,\n ContextMenuParams,\n GridElementRef,\n HeaderClickEvent,\n HeaderRenderer,\n KeyboardModifiers,\n PluginCellRenderContext,\n PluginQuery,\n RowClickEvent,\n ScrollEvent,\n} from './types';\n\nimport type {\n CellClickEvent,\n CellEditor,\n CellMouseEvent,\n CellRenderer,\n GridElementRef,\n HeaderClickEvent,\n HeaderRenderer,\n PluginQuery,\n RowClickEvent,\n ScrollEvent,\n} from './types';\n\n/**\n * Grid element interface for plugins.\n * Extends GridElementRef with plugin-specific methods.\n */\nexport interface GridElement extends GridElementRef {\n getPlugin<T extends BaseGridPlugin>(PluginClass: new (...args: any[]) => T): T | undefined;\n getPluginByName(name: string): BaseGridPlugin | undefined;\n}\n\n/**\n * Header render context for plugin header renderers.\n */\nexport interface PluginHeaderRenderContext {\n /** Column configuration */\n column: ColumnConfig;\n /** Column index */\n colIndex: number;\n}\n\n/**\n * Abstract base class for all grid plugins.\n *\n * @template TConfig - Configuration type for the plugin\n */\nexport abstract class BaseGridPlugin<TConfig = unknown> implements GridPlugin {\n /** Unique plugin identifier (derived from class name by default) */\n abstract readonly name: string;\n\n /** Plugin version - override in subclass if needed */\n readonly version: string = '1.0.0';\n\n /** CSS styles to inject into the grid's shadow DOM */\n readonly styles?: string;\n\n /** Custom cell renderers keyed by type name */\n readonly cellRenderers?: Record<string, CellRenderer>;\n\n /** Custom header renderers keyed by type name */\n readonly headerRenderers?: Record<string, HeaderRenderer>;\n\n /** Custom cell editors keyed by type name */\n readonly cellEditors?: Record<string, CellEditor>;\n\n /** The grid instance this plugin is attached to */\n protected grid!: GridElement;\n\n /** Plugin configuration - merged with defaults in attach() */\n protected config!: TConfig;\n\n /** User-provided configuration from constructor */\n protected readonly userConfig: Partial<TConfig>;\n\n /**\n * Default configuration - subclasses should override this getter.\n * Note: This must be a getter (not property initializer) for proper inheritance\n * since property initializers run after parent constructor.\n */\n protected get defaultConfig(): Partial<TConfig> {\n return {};\n }\n\n constructor(config: Partial<TConfig> = {}) {\n this.userConfig = config;\n }\n\n /**\n * Called when the plugin is attached to a grid.\n * Override to set up event listeners, initialize state, etc.\n */\n attach(grid: GridElement): void {\n this.grid = grid;\n // Merge config here (after subclass construction is complete)\n this.config = { ...this.defaultConfig, ...this.userConfig } as TConfig;\n }\n\n /**\n * Called when the plugin is detached from a grid.\n * Override to clean up event listeners, timers, etc.\n */\n detach(): void {\n // Override in subclass\n }\n\n /**\n * Get another plugin instance from the same grid.\n * Use for inter-plugin communication.\n */\n protected getPlugin<T extends BaseGridPlugin>(PluginClass: new (...args: any[]) => T): T | undefined {\n return this.grid?.getPlugin(PluginClass);\n }\n\n /**\n * Emit a custom event from the grid.\n */\n protected emit<T>(eventName: string, detail: T): void {\n this.grid?.dispatchEvent?.(new CustomEvent(eventName, { detail, bubbles: true }));\n }\n\n /**\n * Request a re-render of the grid.\n */\n protected requestRender(): void {\n this.grid?.requestRender?.();\n }\n\n /**\n * Request a lightweight style update without rebuilding DOM.\n * Use this instead of requestRender() when only CSS classes need updating.\n */\n protected requestAfterRender(): void {\n this.grid?.requestAfterRender?.();\n }\n\n /**\n * Get the current rows from the grid.\n */\n protected get rows(): any[] {\n return this.grid?.rows ?? [];\n }\n\n /**\n * Get the original unfiltered/unprocessed rows from the grid.\n * Use this when you need all source data regardless of active filters.\n */\n protected get sourceRows(): any[] {\n return (this.grid as any)?.sourceRows ?? [];\n }\n\n /**\n * Get the current columns from the grid.\n */\n protected get columns(): ColumnConfig[] {\n return this.grid?.columns ?? [];\n }\n\n /**\n * Get only visible columns from the grid (excludes hidden).\n * Use this for rendering that needs to match the grid template.\n */\n protected get visibleColumns(): ColumnConfig[] {\n return (this.grid as any)?._visibleColumns ?? [];\n }\n\n /**\n * Get the shadow root of the grid.\n */\n protected get shadowRoot(): ShadowRoot | null {\n return this.grid?.shadowRoot ?? null;\n }\n\n /**\n * Get the disconnect signal for event listener cleanup.\n * This signal is aborted when the grid disconnects from the DOM.\n * Use this when adding event listeners that should be cleaned up automatically.\n *\n * Best for:\n * - Document/window-level listeners added in attach()\n * - Listeners on the grid element itself\n * - Any listener that should persist across renders\n *\n * Not needed for:\n * - Listeners on elements created in afterRender() (removed with element)\n *\n * @example\n * element.addEventListener('click', handler, { signal: this.disconnectSignal });\n * document.addEventListener('keydown', handler, { signal: this.disconnectSignal });\n */\n protected get disconnectSignal(): AbortSignal {\n return this.grid?.disconnectSignal;\n }\n\n /**\n * Get the grid-level icons configuration.\n * Returns merged icons (user config + defaults).\n */\n protected get gridIcons(): typeof DEFAULT_GRID_ICONS {\n const userIcons = this.grid?.gridConfig?.icons ?? {};\n return { ...DEFAULT_GRID_ICONS, ...userIcons };\n }\n\n /**\n * Resolve an icon value to string or HTMLElement.\n * Checks plugin config first, then grid-level icons, then defaults.\n *\n * @param iconKey - The icon key in GridIcons (e.g., 'expand', 'collapse')\n * @param pluginOverride - Optional plugin-level override\n * @returns The resolved icon value\n */\n protected resolveIcon(iconKey: keyof typeof DEFAULT_GRID_ICONS, pluginOverride?: IconValue): IconValue {\n // Plugin override takes precedence\n if (pluginOverride !== undefined) {\n return pluginOverride;\n }\n // Then grid-level config\n return this.gridIcons[iconKey];\n }\n\n /**\n * Set an icon value on an element.\n * Handles both string (text/HTML) and HTMLElement values.\n *\n * @param element - The element to set the icon on\n * @param icon - The icon value (string or HTMLElement)\n */\n protected setIcon(element: HTMLElement, icon: IconValue): void {\n if (typeof icon === 'string') {\n element.innerHTML = icon;\n } else if (icon instanceof HTMLElement) {\n element.innerHTML = '';\n element.appendChild(icon.cloneNode(true));\n }\n }\n\n /**\n * Log a warning message.\n */\n protected warn(message: string): void {\n console.warn(`[tbw-grid:${this.name}] ${message}`);\n }\n\n // #region Lifecycle Hooks\n\n /**\n * Transform rows before rendering.\n * Called during each render cycle before rows are rendered to the DOM.\n * Use this to filter, sort, or add computed properties to rows.\n *\n * @param rows - The current rows array (readonly to encourage returning a new array)\n * @returns The modified rows array to render\n *\n * @example\n * ```ts\n * processRows(rows: readonly any[]): any[] {\n * // Filter out hidden rows\n * return rows.filter(row => !row._hidden);\n * }\n * ```\n *\n * @example\n * ```ts\n * processRows(rows: readonly any[]): any[] {\n * // Add computed properties\n * return rows.map(row => ({\n * ...row,\n * _fullName: `${row.firstName} ${row.lastName}`\n * }));\n * }\n * ```\n */\n processRows?(rows: readonly any[]): any[];\n\n /**\n * Transform columns before rendering.\n * Called during each render cycle before column headers and cells are rendered.\n * Use this to add, remove, or modify column definitions.\n *\n * @param columns - The current columns array (readonly to encourage returning a new array)\n * @returns The modified columns array to render\n *\n * @example\n * ```ts\n * processColumns(columns: readonly ColumnConfig[]): ColumnConfig[] {\n * // Add a selection checkbox column\n * return [\n * { field: '_select', header: '', width: 40 },\n * ...columns\n * ];\n * }\n * ```\n */\n processColumns?(columns: readonly ColumnConfig[]): ColumnConfig[];\n\n /**\n * Called before each render cycle begins.\n * Use this to prepare state or cache values needed during rendering.\n *\n * @example\n * ```ts\n * beforeRender(): void {\n * this.visibleRowCount = this.calculateVisibleRows();\n * }\n * ```\n */\n beforeRender?(): void;\n\n /**\n * Called after each render cycle completes.\n * Use this for DOM manipulation, adding event listeners to rendered elements,\n * or applying visual effects like selection highlights.\n *\n * @example\n * ```ts\n * afterRender(): void {\n * // Apply selection styling to rendered rows\n * const rows = this.shadowRoot?.querySelectorAll('.data-row');\n * rows?.forEach((row, i) => {\n * row.classList.toggle('selected', this.selectedRows.has(i));\n * });\n * }\n * ```\n */\n afterRender?(): void;\n\n /**\n * Called after scroll-triggered row rendering completes.\n * This is a lightweight hook for applying visual state to recycled DOM elements.\n * Use this instead of afterRender when you need to reapply styling during scroll.\n *\n * Performance note: This is called frequently during scroll. Keep implementation fast.\n *\n * @example\n * ```ts\n * onScrollRender(): void {\n * // Reapply selection state to visible cells\n * this.applySelectionToVisibleCells();\n * }\n * ```\n */\n onScrollRender?(): void;\n\n /**\n * Return extra height contributed by this plugin (e.g., expanded detail rows).\n * Used to adjust scrollbar height calculations for virtualization.\n *\n * @returns Total extra height in pixels\n *\n * @example\n * ```ts\n * getExtraHeight(): number {\n * return this.expandedRows.size * this.detailHeight;\n * }\n * ```\n */\n getExtraHeight?(): number;\n\n /**\n * Return extra height that appears before a given row index.\n * Used by virtualization to correctly calculate scroll positions when\n * there's variable height content (like expanded detail rows) above the viewport.\n *\n * @param beforeRowIndex - The row index to calculate extra height before\n * @returns Extra height in pixels that appears before this row\n *\n * @example\n * ```ts\n * getExtraHeightBefore(beforeRowIndex: number): number {\n * let height = 0;\n * for (const expandedRowIndex of this.expandedRowIndices) {\n * if (expandedRowIndex < beforeRowIndex) {\n * height += this.getDetailHeight(expandedRowIndex);\n * }\n * }\n * return height;\n * }\n * ```\n */\n getExtraHeightBefore?(beforeRowIndex: number): number;\n\n /**\n * Adjust the virtualization start index to render additional rows before the visible range.\n * Use this when expanded content (like detail rows) needs its parent row to remain rendered\n * even when the parent row itself has scrolled above the viewport.\n *\n * @param start - The calculated start row index\n * @param scrollTop - The current scroll position\n * @param rowHeight - The height of a single row\n * @returns The adjusted start index (lower than or equal to original start)\n *\n * @example\n * ```ts\n * adjustVirtualStart(start: number, scrollTop: number, rowHeight: number): number {\n * // If row 5 is expanded and scrolled partially, keep it rendered\n * for (const expandedRowIndex of this.expandedRowIndices) {\n * const expandedRowTop = expandedRowIndex * rowHeight;\n * const expandedRowBottom = expandedRowTop + rowHeight + this.detailHeight;\n * if (expandedRowBottom > scrollTop && expandedRowIndex < start) {\n * return expandedRowIndex;\n * }\n * }\n * return start;\n * }\n * ```\n */\n adjustVirtualStart?(start: number, scrollTop: number, rowHeight: number): number;\n\n /**\n * Render a custom row, bypassing the default row rendering.\n * Use this for special row types like group headers, detail rows, or footers.\n *\n * @param row - The row data object\n * @param rowEl - The row DOM element to render into\n * @param rowIndex - The index of the row in the data array\n * @returns `true` if the plugin handled rendering (prevents default), `false`/`void` for default rendering\n *\n * @example\n * ```ts\n * renderRow(row: any, rowEl: HTMLElement, rowIndex: number): boolean | void {\n * if (row._isGroupHeader) {\n * rowEl.innerHTML = `<div class=\"group-header\">${row._groupLabel}</div>`;\n * return true; // Handled - skip default rendering\n * }\n * // Return void to let default rendering proceed\n * }\n * ```\n */\n renderRow?(row: any, rowEl: HTMLElement, rowIndex: number): boolean | void;\n\n // #endregion\n\n // #region Inter-Plugin Communication\n\n /**\n * Handle queries from other plugins.\n * This is the generic mechanism for inter-plugin communication.\n * Plugins can respond to well-known query types or define their own.\n *\n * @param query - The query object with type and context\n * @returns Query-specific response, or undefined if not handling this query\n *\n * @example\n * ```ts\n * onPluginQuery(query: PluginQuery): unknown {\n * switch (query.type) {\n * case PLUGIN_QUERIES.CAN_MOVE_COLUMN:\n * // Prevent moving pinned columns\n * const column = query.context as ColumnConfig;\n * if (column.sticky === 'left' || column.sticky === 'right') {\n * return false;\n * }\n * break;\n * case PLUGIN_QUERIES.GET_CONTEXT_MENU_ITEMS:\n * const params = query.context as ContextMenuParams;\n * return [{ id: 'my-action', label: 'My Action', action: () => {} }];\n * }\n * }\n * ```\n */\n onPluginQuery?(query: PluginQuery): unknown;\n\n // #endregion\n\n // #region Interaction Hooks\n\n /**\n * Handle keyboard events on the grid.\n * Called when a key is pressed while the grid or a cell has focus.\n *\n * @param event - The native KeyboardEvent\n * @returns `true` to prevent default behavior and stop propagation, `false`/`void` to allow default\n *\n * @example\n * ```ts\n * onKeyDown(event: KeyboardEvent): boolean | void {\n * // Handle Ctrl+A for select all\n * if (event.ctrlKey && event.key === 'a') {\n * this.selectAllRows();\n * return true; // Prevent default browser select-all\n * }\n * }\n * ```\n */\n onKeyDown?(event: KeyboardEvent): boolean | void;\n\n /**\n * Handle cell click events.\n * Called when a data cell is clicked (not headers).\n *\n * @param event - Cell click event with row/column context\n * @returns `true` to prevent default behavior and stop propagation, `false`/`void` to allow default\n *\n * @example\n * ```ts\n * onCellClick(event: CellClickEvent): boolean | void {\n * if (event.field === '_select') {\n * this.toggleRowSelection(event.rowIndex);\n * return true; // Handled\n * }\n * }\n * ```\n */\n onCellClick?(event: CellClickEvent): boolean | void;\n\n /**\n * Handle row click events.\n * Called when any part of a data row is clicked.\n * Note: This is called in addition to onCellClick, not instead of.\n *\n * @param event - Row click event with row context\n * @returns `true` to prevent default behavior and stop propagation, `false`/`void` to allow default\n *\n * @example\n * ```ts\n * onRowClick(event: RowClickEvent): boolean | void {\n * if (this.config.mode === 'row') {\n * this.selectRow(event.rowIndex, event.originalEvent);\n * return true;\n * }\n * }\n * ```\n */\n onRowClick?(event: RowClickEvent): boolean | void;\n\n /**\n * Handle header click events.\n * Called when a column header is clicked. Commonly used for sorting.\n *\n * @param event - Header click event with column context\n * @returns `true` to prevent default behavior and stop propagation, `false`/`void` to allow default\n *\n * @example\n * ```ts\n * onHeaderClick(event: HeaderClickEvent): boolean | void {\n * if (event.column.sortable !== false) {\n * this.toggleSort(event.field);\n * return true;\n * }\n * }\n * ```\n */\n onHeaderClick?(event: HeaderClickEvent): boolean | void;\n\n /**\n * Handle scroll events on the grid viewport.\n * Called during scrolling. Note: This may be called frequently; debounce if needed.\n *\n * @param event - Scroll event with scroll position and viewport dimensions\n *\n * @example\n * ```ts\n * onScroll(event: ScrollEvent): void {\n * // Update sticky column positions\n * this.updateStickyPositions(event.scrollLeft);\n * }\n * ```\n */\n onScroll?(event: ScrollEvent): void;\n\n /**\n * Handle cell mousedown events.\n * Used for initiating drag operations like range selection or column resize.\n *\n * @param event - Mouse event with cell context\n * @returns `true` to indicate drag started (prevents text selection), `false`/`void` otherwise\n *\n * @example\n * ```ts\n * onCellMouseDown(event: CellMouseEvent): boolean | void {\n * if (event.rowIndex !== undefined && this.config.mode === 'range') {\n * this.startDragSelection(event.rowIndex, event.colIndex);\n * return true; // Prevent text selection\n * }\n * }\n * ```\n */\n onCellMouseDown?(event: CellMouseEvent): boolean | void;\n\n /**\n * Handle cell mousemove events during drag operations.\n * Only called when a drag is in progress (after mousedown returned true).\n *\n * @param event - Mouse event with current cell context\n * @returns `true` to continue handling the drag, `false`/`void` otherwise\n *\n * @example\n * ```ts\n * onCellMouseMove(event: CellMouseEvent): boolean | void {\n * if (this.isDragging && event.rowIndex !== undefined) {\n * this.extendSelection(event.rowIndex, event.colIndex);\n * return true;\n * }\n * }\n * ```\n */\n onCellMouseMove?(event: CellMouseEvent): boolean | void;\n\n /**\n * Handle cell mouseup events to end drag operations.\n *\n * @param event - Mouse event with final cell context\n * @returns `true` if drag was finalized, `false`/`void` otherwise\n *\n * @example\n * ```ts\n * onCellMouseUp(event: CellMouseEvent): boolean | void {\n * if (this.isDragging) {\n * this.finalizeDragSelection();\n * this.isDragging = false;\n * return true;\n * }\n * }\n * ```\n */\n onCellMouseUp?(event: CellMouseEvent): boolean | void;\n\n // Note: Context menu items are now provided via onPluginQuery with PLUGIN_QUERIES.GET_CONTEXT_MENU_ITEMS\n // This keeps the core decoupled from the context-menu plugin specifics.\n\n // #endregion\n\n // #region Column State Hooks\n\n /**\n * Contribute plugin-specific state for a column.\n * Called by the grid when collecting column state for serialization.\n * Plugins can add their own properties to the column state.\n *\n * @param field - The field name of the column\n * @returns Partial column state with plugin-specific properties, or undefined if no state to contribute\n *\n * @example\n * ```ts\n * getColumnState(field: string): Partial<ColumnState> | undefined {\n * const filterModel = this.filterModels.get(field);\n * if (filterModel) {\n * // Uses module augmentation to add filter property to ColumnState\n * return { filter: filterModel } as Partial<ColumnState>;\n * }\n * return undefined;\n * }\n * ```\n */\n getColumnState?(field: string): Partial<ColumnState> | undefined;\n\n /**\n * Apply plugin-specific state to a column.\n * Called by the grid when restoring column state from serialized data.\n * Plugins should restore their internal state based on the provided state.\n *\n * @param field - The field name of the column\n * @param state - The column state to apply (may contain plugin-specific properties)\n *\n * @example\n * ```ts\n * applyColumnState(field: string, state: ColumnState): void {\n * // Check for filter property added via module augmentation\n * const filter = (state as any).filter;\n * if (filter) {\n * this.filterModels.set(field, filter);\n * this.applyFilter();\n * }\n * }\n * ```\n */\n applyColumnState?(field: string, state: ColumnState): void;\n\n // #endregion\n\n // #region Scroll Boundary Hooks\n\n /**\n * Report horizontal scroll boundary offsets for this plugin.\n * Plugins that obscure part of the scroll area (e.g., pinned/sticky columns)\n * should return how much space they occupy on each side.\n * The keyboard navigation uses this to ensure focused cells are fully visible.\n *\n * @param rowEl - The row element (optional, for calculating widths from rendered cells)\n * @param focusedCell - The currently focused cell element (optional, to determine if scrolling should be skipped)\n * @returns Object with left/right pixel offsets and optional skipScroll flag, or undefined if plugin has no offsets\n *\n * @example\n * ```ts\n * getHorizontalScrollOffsets(rowEl?: HTMLElement, focusedCell?: HTMLElement): { left: number; right: number; skipScroll?: boolean } | undefined {\n * // Calculate total width of left-pinned columns\n * const leftCells = rowEl?.querySelectorAll('.sticky-left') ?? [];\n * let left = 0;\n * leftCells.forEach(el => { left += (el as HTMLElement).offsetWidth; });\n * // Skip scroll if focused cell is pinned (always visible)\n * const skipScroll = focusedCell?.classList.contains('sticky-left');\n * return { left, right: 0, skipScroll };\n * }\n * ```\n */\n getHorizontalScrollOffsets?(\n rowEl?: HTMLElement,\n focusedCell?: HTMLElement,\n ): { left: number; right: number; skipScroll?: boolean } | undefined;\n\n // #endregion\n\n // #region Shell Integration Hooks\n\n /**\n * Register a tool panel for this plugin.\n * Return undefined if plugin has no tool panel.\n * The shell will create a toolbar toggle button and render the panel content\n * when the user opens the panel.\n *\n * @returns Tool panel definition, or undefined if plugin has no panel\n *\n * @example\n * ```ts\n * getToolPanel(): ToolPanelDefinition | undefined {\n * return {\n * id: 'columns',\n * title: 'Columns',\n * icon: '☰',\n * tooltip: 'Show/hide columns',\n * order: 10,\n * render: (container) => {\n * this.renderColumnList(container);\n * return () => this.cleanup();\n * },\n * };\n * }\n * ```\n */\n getToolPanel?(): ToolPanelDefinition | undefined;\n\n /**\n * Register content for the shell header center section.\n * Return undefined if plugin has no header content.\n * Examples: search input, selection summary, status indicators.\n *\n * @returns Header content definition, or undefined if plugin has no header content\n *\n * @example\n * ```ts\n * getHeaderContent(): HeaderContentDefinition | undefined {\n * return {\n * id: 'quick-filter',\n * order: 10,\n * render: (container) => {\n * const input = document.createElement('input');\n * input.type = 'text';\n * input.placeholder = 'Search...';\n * input.addEventListener('input', this.handleInput);\n * container.appendChild(input);\n * return () => input.removeEventListener('input', this.handleInput);\n * },\n * };\n * }\n * ```\n */\n getHeaderContent?(): HeaderContentDefinition | undefined;\n\n // #endregion\n}\n","/**\n * Aggregators Core Registry\n *\n * Provides a central registry for aggregator functions.\n * Built-in aggregators are provided by default.\n * Plugins can register additional aggregators.\n *\n * The registry is exposed as a singleton object that can be accessed:\n * - By ES module imports: import { aggregatorRegistry } from '@toolbox-web/grid'\n * - By UMD/CDN: TbwGrid.aggregatorRegistry\n * - By plugins via context: ctx.aggregatorRegistry\n */\n\n/* eslint-disable @typescript-eslint/no-explicit-any */\n\nexport type AggregatorFn = (rows: any[], field: string, column?: any) => any;\nexport type AggregatorRef = string | AggregatorFn;\n\n/** Built-in aggregator functions */\nconst builtInAggregators: Record<string, AggregatorFn> = {\n sum: (rows, field) => rows.reduce((acc, row) => acc + (Number(row[field]) || 0), 0),\n avg: (rows, field) => {\n const sum = rows.reduce((acc, row) => acc + (Number(row[field]) || 0), 0);\n return rows.length ? sum / rows.length : 0;\n },\n count: (rows) => rows.length,\n min: (rows, field) => Math.min(...rows.map((r) => Number(r[field]) || Infinity)),\n max: (rows, field) => Math.max(...rows.map((r) => Number(r[field]) || -Infinity)),\n first: (rows, field) => rows[0]?.[field],\n last: (rows, field) => rows[rows.length - 1]?.[field],\n};\n\n/** Custom aggregator registry (for plugins to add to) */\nconst customAggregators: Map<string, AggregatorFn> = new Map();\n\n/**\n * The aggregator registry singleton.\n * Plugins should access this through context or the global namespace.\n */\nexport const aggregatorRegistry = {\n /**\n * Register a custom aggregator function.\n */\n register(name: string, fn: AggregatorFn): void {\n customAggregators.set(name, fn);\n },\n\n /**\n * Unregister a custom aggregator function.\n */\n unregister(name: string): void {\n customAggregators.delete(name);\n },\n\n /**\n * Get an aggregator function by reference.\n */\n get(ref: AggregatorRef | undefined): AggregatorFn | undefined {\n if (ref === undefined) return undefined;\n if (typeof ref === 'function') return ref;\n // Check custom first, then built-in\n return customAggregators.get(ref) ?? builtInAggregators[ref];\n },\n\n /**\n * Run an aggregator on a set of rows.\n */\n run(ref: AggregatorRef | undefined, rows: any[], field: string, column?: any): any {\n const fn = this.get(ref);\n return fn ? fn(rows, field, column) : undefined;\n },\n\n /**\n * Check if an aggregator exists.\n */\n has(name: string): boolean {\n return customAggregators.has(name) || name in builtInAggregators;\n },\n\n /**\n * List all available aggregator names.\n */\n list(): string[] {\n return [...Object.keys(builtInAggregators), ...customAggregators.keys()];\n },\n};\n\n// #region Value-based Aggregators\n// Used by plugins like Pivot that work with pre-extracted numeric values\n\nexport type ValueAggregatorFn = (values: number[]) => number;\n\n/**\n * Built-in value-based aggregators.\n * These operate on arrays of numbers (unlike row-based aggregators).\n */\nconst builtInValueAggregators: Record<string, ValueAggregatorFn> = {\n sum: (vals) => vals.reduce((a, b) => a + b, 0),\n avg: (vals) => (vals.length ? vals.reduce((a, b) => a + b, 0) / vals.length : 0),\n count: (vals) => vals.length,\n min: (vals) => (vals.length ? Math.min(...vals) : 0),\n max: (vals) => (vals.length ? Math.max(...vals) : 0),\n first: (vals) => vals[0] ?? 0,\n last: (vals) => vals[vals.length - 1] ?? 0,\n};\n\n/**\n * Get a value-based aggregator function.\n * Used by Pivot plugin and other features that aggregate pre-extracted values.\n *\n * @param aggFunc - Aggregation function name ('sum', 'avg', 'count', 'min', 'max', 'first', 'last')\n * @returns Aggregator function that takes number[] and returns number\n */\nexport function getValueAggregator(aggFunc: string): ValueAggregatorFn {\n return builtInValueAggregators[aggFunc] ?? builtInValueAggregators.sum;\n}\n\n/**\n * Run a value-based aggregator on a set of values.\n *\n * @param aggFunc - Aggregation function name\n * @param values - Array of numbers to aggregate\n * @returns Aggregated result\n */\nexport function runValueAggregator(aggFunc: string, values: number[]): number {\n return getValueAggregator(aggFunc)(values);\n}\n// #endregion\n\n// Legacy function exports for backward compatibility\nexport const registerAggregator = aggregatorRegistry.register.bind(aggregatorRegistry);\nexport const unregisterAggregator = aggregatorRegistry.unregister.bind(aggregatorRegistry);\nexport const getAggregator = aggregatorRegistry.get.bind(aggregatorRegistry);\nexport const runAggregator = aggregatorRegistry.run.bind(aggregatorRegistry);\nexport const listAggregators = aggregatorRegistry.list.bind(aggregatorRegistry);\n","import { getValueAggregator } from '../../core/internal/aggregators';\nimport type { PivotConfig } from './types';\n\n// Re-export for backward compatibility within pivot plugin\nexport const getPivotAggregator = getValueAggregator;\n\nexport function validatePivotConfig(config: PivotConfig): string[] {\n const errors: string[] = [];\n\n if (!config.rowGroupFields?.length && !config.columnGroupFields?.length) {\n errors.push('At least one row or column group field is required');\n }\n\n if (!config.valueFields?.length) {\n errors.push('At least one value field is required');\n }\n\n return errors;\n}\n\nexport function createValueKey(columnValues: string[], valueField: string): string {\n return [...columnValues, valueField].join('|');\n}\n","import { createValueKey, getPivotAggregator } from './pivot-model';\nimport type { PivotConfig, PivotResult, PivotRow, PivotValueField } from './types';\n\nexport type PivotDataRow = Record<string, unknown>;\n\n/**\n * Build a hierarchical pivot result from flat data.\n * Supports multiple row group fields for nested hierarchy.\n */\nexport function buildPivot(rows: PivotDataRow[], config: PivotConfig): PivotResult {\n const rowGroupFields = config.rowGroupFields ?? [];\n const columnGroupFields = config.columnGroupFields ?? [];\n const valueFields = config.valueFields ?? [];\n\n // Get unique column combinations\n const columnKeys = getUniqueColumnKeys(rows, columnGroupFields);\n\n // Build hierarchical pivot rows\n const pivotRows = buildHierarchicalPivotRows(\n rows,\n rowGroupFields,\n columnGroupFields,\n columnKeys,\n valueFields,\n 0, // starting depth\n '', // parent key prefix\n );\n\n // Calculate grand totals\n const totals = calculateTotals(pivotRows, columnKeys, valueFields);\n const grandTotal = Object.values(totals).reduce((a, b) => a + b, 0);\n\n return {\n rows: pivotRows,\n columnKeys,\n totals,\n grandTotal,\n };\n}\n\n/**\n * Get unique column key combinations from the data.\n */\nexport function getUniqueColumnKeys(rows: PivotDataRow[], columnFields: string[]): string[] {\n if (columnFields.length === 0) return ['value'];\n\n const keys = new Set<string>();\n for (const row of rows) {\n const key = columnFields.map((f) => String(row[f] ?? '')).join('|');\n keys.add(key);\n }\n return [...keys].sort();\n}\n\n/**\n * Group rows by a single field.\n */\nexport function groupByField(rows: PivotDataRow[], field: string): Map<string, PivotDataRow[]> {\n const groups = new Map<string, PivotDataRow[]>();\n\n for (const row of rows) {\n const key = String(row[field] ?? '');\n const existing = groups.get(key);\n if (existing) {\n existing.push(row);\n } else {\n groups.set(key, [row]);\n }\n }\n\n return groups;\n}\n\n/**\n * Group rows by multiple fields (legacy flat grouping).\n */\nexport function groupByFields(rows: PivotDataRow[], fields: string[]): Map<string, PivotDataRow[]> {\n const groups = new Map<string, PivotDataRow[]>();\n\n for (const row of rows) {\n const key = fields.map((f) => String(row[f] ?? '')).join('|');\n const existing = groups.get(key);\n if (existing) {\n existing.push(row);\n } else {\n groups.set(key, [row]);\n }\n }\n\n return groups;\n}\n\n/**\n * Build hierarchical pivot rows recursively.\n * Each level of rowGroupFields creates a new depth level.\n */\nexport function buildHierarchicalPivotRows(\n rows: PivotDataRow[],\n rowGroupFields: string[],\n columnFields: string[],\n columnKeys: string[],\n valueFields: PivotValueField[],\n depth: number,\n parentKey: string,\n): PivotRow[] {\n const result: PivotRow[] = [];\n\n // If no more row group fields, we're at the leaf level - aggregate the data\n if (rowGroupFields.length === 0) {\n // This shouldn't normally happen as we need at least one grouping field\n // But handle it by creating a single aggregated row\n const values = aggregateValues(rows, columnFields, columnKeys, valueFields);\n const total = calculateRowTotal(values);\n result.push({\n rowKey: parentKey || 'all',\n rowLabel: parentKey || 'All',\n depth,\n values,\n total,\n isGroup: false,\n rowCount: rows.length,\n });\n return result;\n }\n\n // Get the current grouping field\n const currentField = rowGroupFields[0];\n const remainingFields = rowGroupFields.slice(1);\n const hasChildren = remainingFields.length > 0;\n\n // Group rows by current field\n const grouped = groupByField(rows, currentField);\n\n for (const [groupValue, groupRows] of grouped) {\n const rowKey = parentKey ? `${parentKey}|${groupValue}` : groupValue;\n\n // Aggregate values for this group (sum of all child rows)\n const values = aggregateValues(groupRows, columnFields, columnKeys, valueFields);\n const total = calculateRowTotal(values);\n\n // Build children if there are more grouping levels\n let children: PivotRow[] | undefined;\n if (hasChildren) {\n children = buildHierarchicalPivotRows(\n groupRows,\n remainingFields,\n columnFields,\n columnKeys,\n valueFields,\n depth + 1,\n rowKey,\n );\n }\n\n result.push({\n rowKey,\n rowLabel: groupValue || '(blank)',\n depth,\n values,\n total,\n isGroup: hasChildren,\n children,\n rowCount: groupRows.length,\n });\n }\n\n return result;\n}\n\n/**\n * Aggregate values for a set of rows across all column keys.\n */\nexport function aggregateValues(\n rows: PivotDataRow[],\n columnFields: string[],\n columnKeys: string[],\n valueFields: PivotValueField[],\n): Record<string, number | null> {\n const values: Record<string, number | null> = {};\n\n for (const colKey of columnKeys) {\n for (const vf of valueFields) {\n // Filter rows that match this column key\n const matchingRows =\n columnFields.length > 0\n ? rows.filter((r) => columnFields.map((f) => String(r[f] ?? '')).join('|') === colKey)\n : rows;\n\n const nums = matchingRows.map((r) => Number(r[vf.field]) || 0);\n const aggregator = getPivotAggregator(vf.aggFunc);\n const aggregatedResult = nums.length > 0 ? aggregator(nums) : null;\n\n const valueKey = createValueKey([colKey], vf.field);\n values[valueKey] = aggregatedResult;\n }\n }\n\n return values;\n}\n\n/**\n * Calculate the total for a row's values.\n */\nexport function calculateRowTotal(values: Record<string, number | null>): number {\n let sum = 0;\n for (const val of Object.values(values)) {\n sum += val ?? 0;\n }\n return sum;\n}\n\n/**\n * Legacy flat pivot row building (for backwards compatibility).\n */\nexport function buildPivotRows(\n groupedData: Map<string, PivotDataRow[]>,\n columnFields: string[],\n columnKeys: string[],\n valueFields: PivotValueField[],\n depth: number,\n): PivotRow[] {\n const result: PivotRow[] = [];\n\n for (const [rowKey, groupRows] of groupedData) {\n const values = aggregateValues(groupRows, columnFields, columnKeys, valueFields);\n const total = calculateRowTotal(values);\n\n result.push({\n rowKey,\n rowLabel: rowKey || '(blank)',\n depth,\n values,\n total,\n isGroup: false,\n rowCount: groupRows.length,\n });\n }\n\n return result;\n}\n\n/**\n * Calculate grand totals across all pivot rows.\n */\nexport function calculateTotals(\n pivotRows: PivotRow[],\n columnKeys: string[],\n valueFields: PivotValueField[],\n): Record<string, number> {\n const totals: Record<string, number> = {};\n\n // Recursively sum all rows (including nested children)\n function sumRows(rows: PivotRow[]) {\n for (const row of rows) {\n // Only count leaf rows to avoid double-counting\n if (!row.isGroup || !row.children?.length) {\n for (const colKey of columnKeys) {\n for (const vf of valueFields) {\n const valueKey = createValueKey([colKey], vf.field);\n totals[valueKey] = (totals[valueKey] ?? 0) + (row.values[valueKey] ?? 0);\n }\n }\n } else if (row.children) {\n sumRows(row.children);\n }\n }\n }\n\n sumRows(pivotRows);\n return totals;\n}\n\n/**\n * Flatten hierarchical pivot rows for rendering.\n * Respects expanded state - only includes children of expanded groups.\n */\nexport function flattenPivotRows(rows: PivotRow[], expandedKeys?: Set<string>, defaultExpanded = true): PivotRow[] {\n const result: PivotRow[] = [];\n\n function flatten(row: PivotRow) {\n result.push(row);\n\n // Check if this group is expanded\n const isExpanded = expandedKeys ? expandedKeys.has(row.rowKey) : defaultExpanded;\n\n // Only include children if expanded\n if (row.children && isExpanded) {\n for (const child of row.children) {\n flatten(child);\n }\n }\n }\n\n for (const row of rows) {\n flatten(row);\n }\n\n return result;\n}\n\n/**\n * Get all group keys from pivot rows (for expand all / collapse all).\n */\nexport function getAllGroupKeys(rows: PivotRow[]): string[] {\n const keys: string[] = [];\n\n function collectKeys(row: PivotRow) {\n if (row.isGroup) {\n keys.push(row.rowKey);\n }\n if (row.children) {\n for (const child of row.children) {\n collectKeys(child);\n }\n }\n }\n\n for (const row of rows) {\n collectKeys(row);\n }\n\n return keys;\n}\n","/**\n * Pivot Tool Panel Rendering\n *\n * Pure functions for rendering the pivot configuration panel.\n * Separated from PivotPlugin for better code organization.\n */\n\nimport type { AggFunc, PivotConfig, PivotValueField } from './types';\n\n/** All available aggregation functions */\nexport const AGG_FUNCS: AggFunc[] = ['sum', 'avg', 'count', 'min', 'max', 'first', 'last'];\n\n/** Field info for available fields */\nexport interface FieldInfo {\n field: string;\n header: string;\n}\n\n/** Callbacks for panel interactions */\nexport interface PanelCallbacks {\n onTogglePivot: (enabled: boolean) => void;\n onAddFieldToZone: (field: string, zone: 'rowGroups' | 'columnGroups') => void;\n onRemoveFieldFromZone: (field: string, zone: 'rowGroups' | 'columnGroups') => void;\n onAddValueField: (field: string, aggFunc: AggFunc) => void;\n onRemoveValueField: (field: string) => void;\n onUpdateValueAggFunc: (field: string, aggFunc: AggFunc) => void;\n onOptionChange: (option: 'showTotals' | 'showGrandTotal', value: boolean) => void;\n getAvailableFields: () => FieldInfo[];\n}\n\n/** Internal context passed to rendering functions */\ninterface RenderContext {\n config: PivotConfig;\n callbacks: PanelCallbacks;\n signal: AbortSignal;\n}\n\n/**\n * Render the complete pivot panel content.\n * Returns a cleanup function that removes all event listeners and DOM elements.\n */\nexport function renderPivotPanel(\n container: HTMLElement,\n config: PivotConfig,\n isActive: boolean,\n callbacks: PanelCallbacks,\n): () => void {\n // Create AbortController for automatic listener cleanup\n const controller = new AbortController();\n const ctx: RenderContext = { config, callbacks, signal: controller.signal };\n\n const wrapper = document.createElement('div');\n wrapper.className = 'tbw-pivot-panel';\n\n // Options section (at top, includes pivot toggle)\n wrapper.appendChild(createSection('Options', () => createOptionsPanel(isActive, ctx)));\n\n // Row Groups section\n wrapper.appendChild(createSection('Row Groups', () => createFieldZone('rowGroups', ctx)));\n\n // Column Groups section\n wrapper.appendChild(createSection('Column Groups', () => createFieldZone('columnGroups', ctx)));\n\n // Values section\n wrapper.appendChild(createSection('Values', () => createValuesZone(ctx)));\n\n // Available fields section\n wrapper.appendChild(createSection('Available Fields', () => createAvailableFieldsZone(ctx)));\n\n container.appendChild(wrapper);\n\n // Cleanup: abort all listeners, then remove DOM\n return () => {\n controller.abort();\n wrapper.remove();\n };\n}\n\n/**\n * Create a collapsible section wrapper.\n */\nfunction createSection(title: string, contentFactory: () => HTMLElement): HTMLElement {\n const section = document.createElement('div');\n section.className = 'tbw-pivot-section';\n\n const header = document.createElement('div');\n header.className = 'tbw-pivot-section-header';\n header.textContent = title;\n\n const content = document.createElement('div');\n content.className = 'tbw-pivot-section-content';\n content.appendChild(contentFactory());\n\n section.appendChild(header);\n section.appendChild(content);\n\n return section;\n}\n\n/**\n * Create a drop zone for row/column group fields.\n */\nfunction createFieldZone(zoneType: 'rowGroups' | 'columnGroups', ctx: RenderContext): HTMLElement {\n const { config, callbacks, signal } = ctx;\n const zone = document.createElement('div');\n zone.className = 'tbw-pivot-drop-zone';\n zone.setAttribute('data-zone', zoneType);\n\n const currentFields = zoneType === 'rowGroups' ? (config.rowGroupFields ?? []) : (config.columnGroupFields ?? []);\n\n if (currentFields.length === 0) {\n const placeholder = document.createElement('div');\n placeholder.className = 'tbw-pivot-placeholder';\n placeholder.textContent = 'Drag fields here or click to add';\n zone.appendChild(placeholder);\n } else {\n for (const field of currentFields) {\n zone.appendChild(createFieldChip(field, zoneType, ctx));\n }\n }\n\n // Drop handling\n zone.addEventListener(\n 'dragover',\n (e) => {\n e.preventDefault();\n zone.classList.add('drag-over');\n },\n { signal },\n );\n\n zone.addEventListener(\n 'dragleave',\n () => {\n zone.classList.remove('drag-over');\n },\n { signal },\n );\n\n zone.addEventListener(\n 'drop',\n (e) => {\n e.preventDefault();\n zone.classList.remove('drag-over');\n\n const field = e.dataTransfer?.getData('text/plain');\n if (field) {\n callbacks.onAddFieldToZone(field, zoneType);\n }\n },\n { signal },\n );\n\n return zone;\n}\n\n/**\n * Create a field chip for row/column zones.\n */\nfunction createFieldChip(field: string, zoneType: 'rowGroups' | 'columnGroups', ctx: RenderContext): HTMLElement {\n const { callbacks, signal } = ctx;\n const chip = document.createElement('div');\n chip.className = 'tbw-pivot-field-chip';\n chip.draggable = true;\n\n const fieldInfo = callbacks.getAvailableFields().find((f) => f.field === field);\n const label = document.createElement('span');\n label.className = 'tbw-pivot-chip-label';\n label.textContent = fieldInfo?.header ?? field;\n\n const removeBtn = document.createElement('button');\n removeBtn.className = 'tbw-pivot-chip-remove';\n removeBtn.innerHTML = '×';\n removeBtn.title = 'Remove field';\n removeBtn.addEventListener(\n 'click',\n (e) => {\n e.stopPropagation();\n callbacks.onRemoveFieldFromZone(field, zoneType);\n },\n { signal },\n );\n\n chip.appendChild(label);\n chip.appendChild(removeBtn);\n\n // Drag handling for reordering\n chip.addEventListener(\n 'dragstart',\n (e) => {\n e.dataTransfer?.setData('text/plain', field);\n e.dataTransfer?.setData('source-zone', zoneType);\n chip.classList.add('dragging');\n },\n { signal },\n );\n\n chip.addEventListener(\n 'dragend',\n () => {\n chip.classList.remove('dragging');\n },\n { signal },\n );\n\n return chip;\n}\n\n/**\n * Create the values zone with aggregation controls.\n */\nfunction createValuesZone(ctx: RenderContext): HTMLElement {\n const { config, callbacks, signal } = ctx;\n const zone = document.createElement('div');\n zone.className = 'tbw-pivot-drop-zone tbw-pivot-values-zone';\n zone.setAttribute('data-zone', 'values');\n\n const currentValues = config.valueFields ?? [];\n\n if (currentValues.length === 0) {\n const placeholder = document.createElement('div');\n placeholder.className = 'tbw-pivot-placeholder';\n placeholder.textContent = 'Drag numeric fields here for aggregation';\n zone.appendChild(placeholder);\n } else {\n for (const valueField of currentValues) {\n zone.appendChild(createValueChip(valueField, ctx));\n }\n }\n\n // Drop handling with signal for cleanup\n zone.addEventListener(\n 'dragover',\n (e) => {\n e.preventDefault();\n zone.classList.add('drag-over');\n },\n { signal },\n );\n\n zone.addEventListener(\n 'dragleave',\n () => {\n zone.classList.remove('drag-over');\n },\n { signal },\n );\n\n zone.addEventListener(\n 'drop',\n (e) => {\n e.preventDefault();\n zone.classList.remove('drag-over');\n const field = e.dataTransfer?.getData('text/plain');\n if (field) {\n callbacks.onAddValueField(field, 'sum');\n }\n },\n { signal },\n );\n\n return zone;\n}\n\n/**\n * Create a value chip with aggregation selector.\n */\nfunction createValueChip(valueField: PivotValueField, ctx: RenderContext): HTMLElement {\n const { callbacks, signal } = ctx;\n const chip = document.createElement('div');\n chip.className = 'tbw-pivot-field-chip tbw-pivot-value-chip';\n\n const fieldInfo = callbacks.getAvailableFields().find((f) => f.field === valueField.field);\n\n const labelWrapper = document.createElement('div');\n labelWrapper.className = 'tbw-pivot-value-label-wrapper';\n\n const label = document.createElement('span');\n label.className = 'tbw-pivot-chip-label';\n label.textContent = fieldInfo?.header ?? valueField.field;\n\n const aggSelect = document.createElement('select');\n aggSelect.className = 'tbw-pivot-agg-select';\n aggSelect.title = 'Aggregation function';\n\n for (const aggFunc of AGG_FUNCS) {\n const option = document.createElement('option');\n option.value = aggFunc;\n option.textContent = aggFunc.toUpperCase();\n option.selected = aggFunc === valueField.aggFunc;\n aggSelect.appendChild(option);\n }\n\n aggSelect.addEventListener(\n 'change',\n () => {\n callbacks.onUpdateValueAggFunc(valueField.field, aggSelect.value as AggFunc);\n },\n { signal },\n );\n\n const removeBtn = document.createElement('button');\n removeBtn.className = 'tbw-pivot-chip-remove';\n removeBtn.innerHTML = '×';\n removeBtn.title = 'Remove value field';\n removeBtn.addEventListener(\n 'click',\n (e) => {\n e.stopPropagation();\n callbacks.onRemoveValueField(valueField.field);\n },\n { signal },\n );\n\n labelWrapper.appendChild(label);\n labelWrapper.appendChild(aggSelect);\n\n chip.appendChild(labelWrapper);\n chip.appendChild(removeBtn);\n\n return chip;\n}\n\n/**\n * Create the available fields zone.\n */\nfunction createAvailableFieldsZone(ctx: RenderContext): HTMLElement {\n const { config, callbacks, signal } = ctx;\n const zone = document.createElement('div');\n zone.className = 'tbw-pivot-available-fields';\n\n const allFields = callbacks.getAvailableFields();\n const usedFields = new Set([\n ...(config.rowGroupFields ?? []),\n ...(config.columnGroupFields ?? []),\n ...(config.valueFields?.map((v) => v.field) ?? []),\n ]);\n\n // Filter to show only unused fields\n const availableFields = allFields.filter((f) => !usedFields.has(f.field));\n\n if (availableFields.length === 0) {\n const empty = document.createElement('div');\n empty.className = 'tbw-pivot-placeholder';\n empty.textContent = 'All fields are in use';\n zone.appendChild(empty);\n } else {\n for (const field of availableFields) {\n const chip = document.createElement('div');\n chip.className = 'tbw-pivot-field-chip available';\n chip.textContent = field.header;\n chip.draggable = true;\n chip.title = `Drag to add \"${field.field}\" to a zone`;\n\n chip.addEventListener(\n 'dragstart',\n (e) => {\n e.dataTransfer?.setData('text/plain', field.field);\n chip.classList.add('dragging');\n },\n { signal },\n );\n\n chip.addEventListener(\n 'dragend',\n () => {\n chip.classList.remove('dragging');\n },\n { signal },\n );\n\n zone.appendChild(chip);\n }\n }\n\n return zone;\n}\n\n/**\n * Create the options panel with pivot toggle and checkboxes for totals.\n */\nfunction createOptionsPanel(isActive: boolean, ctx: RenderContext): HTMLElement {\n const { config, callbacks, signal } = ctx;\n const panel = document.createElement('div');\n panel.className = 'tbw-pivot-options';\n\n // Pivot Mode toggle\n panel.appendChild(\n createCheckbox(\n 'Enable Pivot View',\n isActive,\n (checked) => {\n callbacks.onTogglePivot(checked);\n },\n signal,\n ),\n );\n\n // Show Totals checkbox\n panel.appendChild(\n createCheckbox(\n 'Show Row Totals',\n config.showTotals ?? true,\n (checked) => {\n callbacks.onOptionChange('showTotals', checked);\n },\n signal,\n ),\n );\n\n // Show Grand Total checkbox\n panel.appendChild(\n createCheckbox(\n 'Show Grand Total',\n config.showGrandTotal ?? true,\n (checked) => {\n callbacks.onOptionChange('showGrandTotal', checked);\n },\n signal,\n ),\n );\n\n return panel;\n}\n\n/**\n * Create a checkbox with label.\n */\nfunction createCheckbox(\n label: string,\n checked: boolean,\n onChange: (checked: boolean) => void,\n signal: AbortSignal,\n): HTMLElement {\n const wrapper = document.createElement('label');\n wrapper.className = 'tbw-pivot-checkbox';\n\n const input = document.createElement('input');\n input.type = 'checkbox';\n input.checked = checked;\n input.addEventListener('change', () => onChange(input.checked), { signal });\n\n const span = document.createElement('span');\n span.textContent = label;\n\n wrapper.appendChild(input);\n wrapper.appendChild(span);\n\n return wrapper;\n}\n","/**\n * Pivot Row Rendering\n *\n * Pure functions for rendering pivot rows (group rows, leaf rows, grand total).\n * Separated from PivotPlugin for better code organization.\n */\n\nimport type { ColumnConfig, IconValue } from '../../core/types';\n\n/** Row data with pivot metadata */\nexport interface PivotRowData {\n __pivotRowKey?: string;\n __pivotLabel?: string;\n __pivotDepth?: number;\n __pivotIndent?: number;\n __pivotExpanded?: boolean;\n __pivotHasChildren?: boolean;\n __pivotRowCount?: number;\n __pivotIsGrandTotal?: boolean;\n [key: string]: unknown;\n}\n\n/** Context for row rendering */\nexport interface RowRenderContext {\n columns: ColumnConfig[];\n onToggle: (key: string) => void;\n resolveIcon: (iconKey: 'expand' | 'collapse') => IconValue;\n setIcon: (element: HTMLElement, icon: IconValue) => void;\n}\n\n/**\n * Render a pivot group row (has children, can expand/collapse).\n */\nexport function renderPivotGroupRow(row: PivotRowData, rowEl: HTMLElement, ctx: RowRenderContext): boolean {\n rowEl.className = 'pivot-group-row';\n rowEl.setAttribute('data-pivot-depth', String(row.__pivotDepth ?? 0));\n rowEl.setAttribute('data-pivot-key', String(row.__pivotRowKey ?? ''));\n rowEl.setAttribute('role', 'row');\n // Note: aria-expanded is not set here because it's only valid in treegrid, not grid\n // The expand/collapse state is conveyed via the toggle button's aria-label\n rowEl.innerHTML = '';\n\n ctx.columns.forEach((col, colIdx) => {\n const cell = document.createElement('div');\n cell.className = 'cell';\n cell.setAttribute('data-col', String(colIdx));\n cell.setAttribute('role', 'gridcell');\n\n if (colIdx === 0) {\n // First column: indent + toggle + label + count\n const indent = Number(row.__pivotIndent) || 0;\n cell.style.paddingLeft = `${indent}px`;\n\n // Toggle button\n const rowKey = String(row.__pivotRowKey);\n const btn = document.createElement('button');\n btn.type = 'button';\n btn.className = 'pivot-toggle';\n btn.setAttribute('aria-label', row.__pivotExpanded ? 'Collapse group' : 'Expand group');\n ctx.setIcon(btn, ctx.resolveIcon(row.__pivotExpanded ? 'collapse' : 'expand'));\n btn.addEventListener('click', (e) => {\n e.stopPropagation();\n ctx.onToggle(rowKey);\n });\n cell.appendChild(btn);\n\n // Group label\n const label = document.createElement('span');\n label.className = 'pivot-label';\n label.textContent = String(row.__pivotLabel ?? '');\n cell.appendChild(label);\n\n // Row count\n const count = document.createElement('span');\n count.className = 'pivot-count';\n count.textContent = ` (${Number(row.__pivotRowCount) || 0})`;\n cell.appendChild(count);\n } else {\n // Other columns: render value\n const value = row[col.field];\n cell.textContent = value != null ? String(value) : '';\n }\n\n rowEl.appendChild(cell);\n });\n\n return true;\n}\n\n/**\n * Render a pivot leaf row (no children, just indentation).\n */\nexport function renderPivotLeafRow(row: PivotRowData, rowEl: HTMLElement, columns: ColumnConfig[]): boolean {\n rowEl.className = 'pivot-leaf-row';\n rowEl.setAttribute('data-pivot-depth', String(row.__pivotDepth ?? 0));\n rowEl.setAttribute('data-pivot-key', String(row.__pivotRowKey ?? ''));\n rowEl.innerHTML = '';\n\n columns.forEach((col, colIdx) => {\n const cell = document.createElement('div');\n cell.className = 'cell';\n cell.setAttribute('data-col', String(colIdx));\n cell.setAttribute('role', 'gridcell');\n\n if (colIdx === 0) {\n // First column: indent + label (no toggle for leaves)\n const indent = Number(row.__pivotIndent) || 0;\n // Add extra indent for alignment with toggle button\n cell.style.paddingLeft = `${indent + 20}px`;\n\n const label = document.createElement('span');\n label.className = 'pivot-label';\n label.textContent = String(row.__pivotLabel ?? '');\n cell.appendChild(label);\n } else {\n // Other columns: render value\n const value = row[col.field];\n cell.textContent = value != null ? String(value) : '';\n }\n\n rowEl.appendChild(cell);\n });\n\n return true;\n}\n\n/**\n * Render the grand total row.\n */\nexport function renderPivotGrandTotalRow(row: PivotRowData, rowEl: HTMLElement, columns: ColumnConfig[]): boolean {\n rowEl.className = 'pivot-grand-total-row';\n // Use role=presentation since grand total is rendered outside the role=grid element\n rowEl.setAttribute('role', 'presentation');\n rowEl.innerHTML = '';\n\n columns.forEach((col, colIdx) => {\n const cell = document.createElement('div');\n cell.className = 'cell';\n cell.setAttribute('data-col', String(colIdx));\n // No role attribute - parent row has role=presentation so children don't need grid semantics\n\n if (colIdx === 0) {\n // First column: Grand Total label\n const label = document.createElement('span');\n label.className = 'pivot-label';\n label.textContent = 'Grand Total';\n cell.appendChild(label);\n } else {\n // Other columns: render totals\n const value = row[col.field];\n cell.textContent = value != null ? String(value) : '';\n }\n\n rowEl.appendChild(cell);\n });\n\n return true;\n}\n","/**\n * Pivot Plugin (Class-based)\n *\n * Provides pivot table functionality for tbw-grid.\n * Transforms flat data into grouped, aggregated pivot views.\n * Includes a tool panel for interactive pivot configuration.\n */\n\nimport { BaseGridPlugin } from '../../core/plugin/base-plugin';\nimport type { ColumnConfig, GridConfig, ToolPanelDefinition } from '../../core/types';\nimport { buildPivot, flattenPivotRows, getAllGroupKeys, type PivotDataRow } from './pivot-engine';\nimport { createValueKey, validatePivotConfig } from './pivot-model';\nimport { renderPivotPanel, type FieldInfo, type PanelCallbacks } from './pivot-panel';\nimport { renderPivotGrandTotalRow, renderPivotGroupRow, renderPivotLeafRow, type PivotRowData } from './pivot-rows';\nimport type { AggFunc, ExpandCollapseAnimation, PivotConfig, PivotResult, PivotValueField } from './types';\n\n// Import CSS as inline string (Vite handles this)\nimport styles from './pivot.css?inline';\n\n/** Extended grid interface with column access */\ninterface GridWithColumns {\n shadowRoot: ShadowRoot | null;\n effectiveConfig?: GridConfig;\n getAllColumns(): Array<{ field: string; header: string; visible: boolean }>;\n columns: unknown[];\n rows: unknown[];\n requestRender(): void;\n openToolPanel(id: string): void;\n closeToolPanel(): void;\n toggleToolPanel(id: string): void;\n activeToolPanel: string | undefined;\n}\n\n/**\n * Pivot Plugin for tbw-grid\n *\n * @example\n * ```ts\n * new PivotPlugin({\n * rowGroupFields: ['category'],\n * columnGroupFields: ['region'],\n * valueFields: [{ field: 'sales', aggFunc: 'sum' }]\n * })\n * ```\n */\nexport class PivotPlugin extends BaseGridPlugin<PivotConfig> {\n readonly name = 'pivot';\n override readonly version = '1.0.0';\n\n /** Tool panel ID for shell integration */\n static readonly PANEL_ID = 'pivot';\n\n protected override get defaultConfig(): Partial<PivotConfig> {\n return {\n active: true,\n showTotals: true,\n showGrandTotal: true,\n showToolPanel: true,\n animation: 'slide',\n };\n }\n\n // #region Internal State\n private isActive = false;\n private hasInitialized = false;\n private pivotResult: PivotResult | null = null;\n private fieldHeaderMap: Map<string, string> = new Map();\n private expandedKeys: Set<string> = new Set();\n private defaultExpanded = true;\n private originalColumns: Array<{ field: string; header: string }> = [];\n private panelContainer: HTMLElement | null = null;\n private grandTotalFooter: HTMLElement | null = null;\n private previousVisibleKeys = new Set<string>();\n private keysToAnimate = new Set<string>();\n\n /**\n * Check if the plugin has valid pivot configuration (at least value fields).\n */\n private hasValidPivotConfig(): boolean {\n return (this.config.valueFields?.length ?? 0) > 0;\n }\n\n /**\n * Get animation style respecting grid-level animation mode.\n */\n private get animationStyle(): ExpandCollapseAnimation {\n const gridEl = this.grid as unknown as GridWithColumns;\n const mode = gridEl.effectiveConfig?.animation?.mode ?? 'reduced-motion';\n\n if (mode === false || mode === 'off') return false;\n if (mode !== true && mode !== 'on') {\n const host = this.shadowRoot?.host as HTMLElement | undefined;\n if (host && getComputedStyle(host).getPropertyValue('--tbw-animation-enabled').trim() === '0') {\n return false;\n }\n }\n return this.config.animation ?? 'slide';\n }\n\n // #endregion\n\n // #region Lifecycle\n\n override detach(): void {\n this.isActive = false;\n this.hasInitialized = false;\n this.pivotResult = null;\n this.fieldHeaderMap.clear();\n this.originalColumns = [];\n this.panelContainer = null;\n this.cleanupGrandTotalFooter();\n this.previousVisibleKeys.clear();\n this.keysToAnimate.clear();\n }\n\n // #endregion\n\n // #region Shell Integration\n\n override getToolPanel(): ToolPanelDefinition | undefined {\n // Allow users to disable the tool panel for programmatic-only pivot\n // Check userConfig first (works before attach), then merged config\n const showToolPanel = this.config?.showToolPanel ?? this.userConfig?.showToolPanel ?? true;\n if (showToolPanel === false) {\n return undefined;\n }\n\n return {\n id: PivotPlugin.PANEL_ID,\n title: 'Pivot',\n icon: '⊞',\n tooltip: 'Configure pivot table',\n order: 90,\n render: (container) => this.renderPanel(container),\n };\n }\n\n // #endregion\n\n // #region Hooks\n\n override processRows(rows: readonly unknown[]): PivotDataRow[] {\n // Auto-enable pivot if config.active is true and we have valid pivot fields\n if (!this.hasInitialized && this.config.active !== false && this.hasValidPivotConfig()) {\n this.hasInitialized = true;\n this.isActive = true;\n }\n\n if (!this.isActive) {\n return [...rows] as PivotDataRow[];\n }\n\n const errors = validatePivotConfig(this.config);\n if (errors.length > 0) {\n this.warn(`Config errors: ${errors.join(', ')}`);\n return [...rows] as PivotDataRow[];\n }\n\n this.buildFieldHeaderMap();\n this.defaultExpanded = this.config.defaultExpanded ?? true;\n\n // Initialize expanded state with defaults if first build\n if (this.expandedKeys.size === 0 && this.defaultExpanded && this.pivotResult) {\n const allKeys = getAllGroupKeys(this.pivotResult.rows);\n for (const key of allKeys) {\n this.expandedKeys.add(key);\n }\n }\n\n // Build pivot\n this.pivotResult = buildPivot(rows as PivotDataRow[], this.config);\n\n // If default expanded and we just built the pivot, add all group keys\n if (this.expandedKeys.size === 0 && this.defaultExpanded) {\n const allKeys = getAllGroupKeys(this.pivotResult.rows);\n for (const key of allKeys) {\n this.expandedKeys.add(key);\n }\n }\n\n // Return flattened pivot rows respecting expanded state\n const indentWidth = this.config.indentWidth ?? 20;\n const flatRows: PivotDataRow[] = flattenPivotRows(\n this.pivotResult.rows,\n this.expandedKeys,\n this.defaultExpanded,\n ).map((pr) => ({\n __pivotRowKey: pr.rowKey,\n __pivotLabel: pr.rowLabel,\n __pivotDepth: pr.depth,\n __pivotIsGroup: pr.isGroup,\n __pivotHasChildren: Boolean(pr.children?.length),\n __pivotExpanded: this.expandedKeys.has(pr.rowKey),\n __pivotRowCount: pr.rowCount ?? 0,\n __pivotIndent: pr.depth * indentWidth,\n __pivotTotal: pr.total,\n ...pr.values,\n }));\n\n // Track which rows are newly visible (for animation)\n this.keysToAnimate.clear();\n const currentVisibleKeys = new Set<string>();\n for (const row of flatRows) {\n const key = row.__pivotRowKey as string;\n currentVisibleKeys.add(key);\n // Animate non-root rows that weren't previously visible\n if (!this.previousVisibleKeys.has(key) && (row.__pivotDepth as number) > 0) {\n this.keysToAnimate.add(key);\n }\n }\n this.previousVisibleKeys = currentVisibleKeys;\n\n // Grand total is rendered as a pinned footer row in afterRender,\n // not as part of the scrolling row data\n\n return flatRows;\n }\n\n override processColumns(columns: readonly ColumnConfig[]): ColumnConfig[] {\n if (!this.isActive || !this.pivotResult) {\n return [...columns];\n }\n\n const pivotColumns: ColumnConfig[] = [];\n\n // Row label column\n const rowGroupHeaders = (this.config.rowGroupFields ?? []).map((f) => this.fieldHeaderMap.get(f) ?? f).join(' / ');\n pivotColumns.push({\n field: '__pivotLabel',\n header: rowGroupHeaders || 'Group',\n width: 200,\n });\n\n // Value columns for each column key\n for (const colKey of this.pivotResult.columnKeys) {\n for (const vf of this.config.valueFields ?? []) {\n const valueKey = createValueKey([colKey], vf.field);\n const valueHeader = vf.header || this.fieldHeaderMap.get(vf.field) || vf.field;\n pivotColumns.push({\n field: valueKey,\n header: `${colKey} - ${valueHeader} (${vf.aggFunc})`,\n width: 120,\n type: 'number',\n });\n }\n }\n\n // Totals column\n if (this.config.showTotals) {\n pivotColumns.push({\n field: '__pivotTotal',\n header: 'Total',\n width: 100,\n type: 'number',\n });\n }\n\n return pivotColumns;\n }\n\n override renderRow(row: Record<string, unknown>, rowEl: HTMLElement): boolean {\n const pivotRow = row as PivotRowData;\n\n // Handle pivot group row (has children)\n if (pivotRow.__pivotRowKey && pivotRow.__pivotHasChildren) {\n return renderPivotGroupRow(pivotRow, rowEl, {\n columns: this.gridColumns,\n onToggle: (key) => this.toggle(key),\n resolveIcon: (iconKey) => this.resolveIcon(iconKey),\n setIcon: (el, icon) => this.setIcon(el, icon),\n });\n }\n\n // Handle pivot leaf row (no children but in pivot mode)\n if (pivotRow.__pivotRowKey !== undefined && this.isActive) {\n return renderPivotLeafRow(pivotRow, rowEl, this.gridColumns);\n }\n\n // Clean up any leftover pivot styling from pooled row elements\n this.cleanupPivotStyling(rowEl);\n\n return false;\n }\n\n /**\n * Remove pivot-specific classes, attributes, and inline styles from a row element.\n * Called when pivot mode is disabled to clean up reused DOM elements.\n * Clears innerHTML so the grid's default renderer can rebuild the row.\n */\n private cleanupPivotStyling(rowEl: HTMLElement): void {\n // Check if this row was previously rendered by pivot (has pivot classes)\n const wasPivotRow =\n rowEl.classList.contains('pivot-group-row') ||\n rowEl.classList.contains('pivot-leaf-row') ||\n rowEl.classList.contains('pivot-grand-total-row');\n\n if (wasPivotRow) {\n // Remove pivot row classes and restore the default grid row class\n rowEl.classList.remove('pivot-group-row', 'pivot-leaf-row', 'pivot-grand-total-row');\n rowEl.classList.add('data-grid-row');\n\n // Remove pivot-specific attributes\n rowEl.removeAttribute('data-pivot-depth');\n\n // Clear the row content so the default renderer can rebuild it\n rowEl.innerHTML = '';\n }\n }\n\n override afterRender(): void {\n // Render grand total as a sticky pinned footer when pivot is active\n if (this.isActive && this.config.showGrandTotal && this.pivotResult) {\n this.renderGrandTotalFooter();\n } else {\n this.cleanupGrandTotalFooter();\n }\n\n // Apply animations to newly visible rows\n const style = this.animationStyle;\n if (style === false || this.keysToAnimate.size === 0) return;\n\n const body = this.shadowRoot?.querySelector('.rows');\n if (!body) return;\n\n const animClass = style === 'fade' ? 'tbw-pivot-fade-in' : 'tbw-pivot-slide-in';\n for (const rowEl of body.querySelectorAll('.pivot-group-row, .pivot-leaf-row')) {\n const key = (rowEl as HTMLElement).dataset.pivotKey;\n if (key && this.keysToAnimate.has(key)) {\n rowEl.classList.add(animClass);\n rowEl.addEventListener('animationend', () => rowEl.classList.remove(animClass), { once: true });\n }\n }\n this.keysToAnimate.clear();\n }\n\n /**\n * Render the grand total row as a sticky footer pinned to the bottom.\n */\n private renderGrandTotalFooter(): void {\n if (!this.pivotResult) return;\n\n const shadowRoot = this.shadowRoot;\n if (!shadowRoot) return;\n\n // Find the scroll container to append the footer\n const container =\n shadowRoot.querySelector('.tbw-scroll-area') ??\n shadowRoot.querySelector('.tbw-grid-content') ??\n shadowRoot.children[0];\n if (!container) return;\n\n // Create footer if it doesn't exist\n if (!this.grandTotalFooter) {\n this.grandTotalFooter = document.createElement('div');\n this.grandTotalFooter.className = 'pivot-grand-total-footer';\n container.appendChild(this.grandTotalFooter);\n }\n\n // Build the row data for grand total\n const grandTotalRow: PivotRowData = {\n __pivotRowKey: '__grandTotal',\n __pivotLabel: 'Grand Total',\n __pivotIsGrandTotal: true,\n __pivotTotal: this.pivotResult.grandTotal,\n ...this.pivotResult.totals,\n };\n\n // Render the grand total row into the footer\n renderPivotGrandTotalRow(grandTotalRow, this.grandTotalFooter, this.gridColumns);\n }\n\n /**\n * Remove the grand total footer element.\n */\n private cleanupGrandTotalFooter(): void {\n if (this.grandTotalFooter) {\n this.grandTotalFooter.remove();\n this.grandTotalFooter = null;\n }\n }\n\n // #endregion\n\n // #region Expand/Collapse API\n\n toggle(key: string): void {\n if (this.expandedKeys.has(key)) {\n this.expandedKeys.delete(key);\n } else {\n this.expandedKeys.add(key);\n }\n this.requestRender();\n }\n\n expand(key: string): void {\n this.expandedKeys.add(key);\n this.requestRender();\n }\n\n collapse(key: string): void {\n this.expandedKeys.delete(key);\n this.requestRender();\n }\n\n expandAll(): void {\n if (this.pivotResult) {\n const allKeys = getAllGroupKeys(this.pivotResult.rows);\n for (const key of allKeys) {\n this.expandedKeys.add(key);\n }\n this.requestRender();\n }\n }\n\n collapseAll(): void {\n this.expandedKeys.clear();\n this.requestRender();\n }\n\n isExpanded(key: string): boolean {\n return this.expandedKeys.has(key);\n }\n\n // #endregion\n\n // #region Public API\n\n enablePivot(): void {\n if (this.originalColumns.length === 0) {\n this.captureOriginalColumns();\n }\n this.isActive = true;\n this.requestRender();\n }\n\n disablePivot(): void {\n this.isActive = false;\n this.pivotResult = null;\n this.requestRender();\n }\n\n isPivotActive(): boolean {\n return this.isActive;\n }\n\n getPivotResult(): PivotResult | null {\n return this.pivotResult;\n }\n\n setRowGroupFields(fields: string[]): void {\n this.config.rowGroupFields = fields;\n this.requestRender();\n }\n\n setColumnGroupFields(fields: string[]): void {\n this.config.columnGroupFields = fields;\n this.requestRender();\n }\n\n setValueFields(fields: PivotValueField[]): void {\n this.config.valueFields = fields;\n this.requestRender();\n }\n\n refresh(): void {\n this.pivotResult = null;\n this.requestRender();\n }\n\n // #endregion\n\n // #region Tool Panel API\n\n showPanel(): void {\n const grid = this.grid as unknown as GridWithColumns;\n grid.openToolPanel(PivotPlugin.PANEL_ID);\n }\n\n hidePanel(): void {\n const grid = this.grid as unknown as GridWithColumns;\n grid.closeToolPanel();\n }\n\n togglePanel(): void {\n const grid = this.grid as unknown as GridWithColumns;\n grid.toggleToolPanel(PivotPlugin.PANEL_ID);\n }\n\n isPanelVisible(): boolean {\n const grid = this.grid as unknown as GridWithColumns;\n return grid.activeToolPanel === PivotPlugin.PANEL_ID;\n }\n\n // #endregion\n\n // #region Private Helpers\n\n private get gridColumns(): ColumnConfig[] {\n const grid = this.grid as unknown as GridWithColumns;\n return (grid.columns ?? []) as ColumnConfig[];\n }\n\n private buildFieldHeaderMap(): void {\n const availableFields = this.getAvailableFields();\n this.fieldHeaderMap.clear();\n for (const field of availableFields) {\n this.fieldHeaderMap.set(field.field, field.header);\n }\n }\n\n private getAvailableFields(): FieldInfo[] {\n if (this.originalColumns.length > 0) {\n return this.originalColumns;\n }\n return this.captureOriginalColumns();\n }\n\n private captureOriginalColumns(): FieldInfo[] {\n const grid = this.grid as unknown as GridWithColumns;\n try {\n const columns = grid.getAllColumns?.() ?? grid.columns ?? [];\n this.originalColumns = columns\n .filter((col: { field: string }) => !col.field.startsWith('__pivot'))\n .map((col: { field: string; header?: string }) => ({\n field: col.field,\n header: col.header ?? col.field,\n }));\n return this.originalColumns;\n } catch {\n return [];\n }\n }\n\n private renderPanel(container: HTMLElement): (() => void) | void {\n this.panelContainer = container;\n\n if (this.originalColumns.length === 0) {\n this.captureOriginalColumns();\n }\n\n const callbacks: PanelCallbacks = {\n onTogglePivot: (enabled) => {\n if (enabled) {\n this.enablePivot();\n } else {\n this.disablePivot();\n }\n this.refreshPanel();\n },\n onAddFieldToZone: (field, zone) => this.addFieldToZone(field, zone),\n onRemoveFieldFromZone: (field, zone) => this.removeFieldFromZone(field, zone),\n onAddValueField: (field, aggFunc) => this.addValueField(field, aggFunc),\n onRemoveValueField: (field) => this.removeValueField(field),\n onUpdateValueAggFunc: (field, aggFunc) => this.updateValueAggFunc(field, aggFunc),\n onOptionChange: (option, value) => {\n this.config[option] = value;\n if (this.isActive) this.refresh();\n },\n getAvailableFields: () => this.getAvailableFields(),\n };\n\n return renderPivotPanel(container, this.config, this.isActive, callbacks);\n }\n\n private refreshPanel(): void {\n if (!this.panelContainer) return;\n this.panelContainer.innerHTML = '';\n this.renderPanel(this.panelContainer);\n }\n\n private addFieldToZone(field: string, zoneType: 'rowGroups' | 'columnGroups'): void {\n if (zoneType === 'rowGroups') {\n const current = this.config.rowGroupFields ?? [];\n if (!current.includes(field)) {\n this.config.rowGroupFields = [...current, field];\n }\n } else {\n const current = this.config.columnGroupFields ?? [];\n if (!current.includes(field)) {\n this.config.columnGroupFields = [...current, field];\n }\n }\n\n this.removeFromOtherZones(field, zoneType);\n if (this.isActive) this.refresh();\n this.refreshPanel();\n }\n\n private removeFieldFromZone(field: string, zoneType: 'rowGroups' | 'columnGroups'): void {\n if (zoneType === 'rowGroups') {\n this.config.rowGroupFields = (this.config.rowGroupFields ?? []).filter((f) => f !== field);\n } else {\n this.config.columnGroupFields = (this.config.columnGroupFields ?? []).filter((f) => f !== field);\n }\n\n if (this.isActive) this.refresh();\n this.refreshPanel();\n }\n\n private removeFromOtherZones(field: string, targetZone: 'rowGroups' | 'columnGroups' | 'values'): void {\n if (targetZone !== 'rowGroups') {\n this.config.rowGroupFields = (this.config.rowGroupFields ?? []).filter((f) => f !== field);\n }\n if (targetZone !== 'columnGroups') {\n this.config.columnGroupFields = (this.config.columnGroupFields ?? []).filter((f) => f !== field);\n }\n if (targetZone !== 'values') {\n this.config.valueFields = (this.config.valueFields ?? []).filter((v) => v.field !== field);\n }\n }\n\n private addValueField(field: string, aggFunc: AggFunc): void {\n const current = this.config.valueFields ?? [];\n if (!current.some((v) => v.field === field)) {\n this.config.valueFields = [...current, { field, aggFunc }];\n }\n\n this.removeFromOtherZones(field, 'values');\n if (this.isActive) this.refresh();\n this.refreshPanel();\n }\n\n private removeValueField(field: string): void {\n this.config.valueFields = (this.config.valueFields ?? []).filter((v) => v.field !== field);\n if (this.isActive) this.refresh();\n this.refreshPanel();\n }\n\n private updateValueAggFunc(field: string, aggFunc: AggFunc): void {\n const valueFields = this.config.valueFields ?? [];\n const fieldIndex = valueFields.findIndex((v) => v.field === field);\n if (fieldIndex >= 0) {\n valueFields[fieldIndex] = { ...valueFields[fieldIndex], aggFunc };\n this.config.valueFields = [...valueFields];\n }\n if (this.isActive) this.refresh();\n }\n\n // #endregion\n\n // #region Styles\n\n override readonly styles = styles;\n\n // #endregion\n}\n"],"names":["DEFAULT_GRID_ICONS","BaseGridPlugin","config","grid","PluginClass","eventName","detail","userIcons","iconKey","pluginOverride","element","icon","message","builtInAggregators","rows","field","acc","row","sum","r","customAggregators","aggregatorRegistry","name","fn","ref","column","builtInValueAggregators","vals","a","b","getValueAggregator","aggFunc","getPivotAggregator","validatePivotConfig","errors","createValueKey","columnValues","valueField","buildPivot","rowGroupFields","columnGroupFields","valueFields","columnKeys","getUniqueColumnKeys","pivotRows","buildHierarchicalPivotRows","totals","calculateTotals","grandTotal","columnFields","keys","key","f","groupByField","groups","existing","depth","parentKey","result","values","aggregateValues","total","calculateRowTotal","currentField","remainingFields","hasChildren","grouped","groupValue","groupRows","rowKey","children","colKey","vf","nums","aggregator","aggregatedResult","valueKey","val","sumRows","flattenPivotRows","expandedKeys","defaultExpanded","flatten","isExpanded","child","getAllGroupKeys","collectKeys","AGG_FUNCS","renderPivotPanel","container","isActive","callbacks","controller","ctx","wrapper","createSection","createOptionsPanel","createFieldZone","createValuesZone","createAvailableFieldsZone","title","contentFactory","section","header","content","zoneType","signal","zone","currentFields","placeholder","createFieldChip","e","chip","fieldInfo","label","removeBtn","currentValues","createValueChip","labelWrapper","aggSelect","option","allFields","usedFields","v","availableFields","empty","panel","createCheckbox","checked","onChange","input","span","renderPivotGroupRow","rowEl","col","colIdx","cell","indent","btn","count","value","renderPivotLeafRow","columns","renderPivotGrandTotalRow","PivotPlugin","mode","host","allKeys","indentWidth","flatRows","pr","currentVisibleKeys","pivotColumns","rowGroupHeaders","valueHeader","pivotRow","el","style","body","animClass","shadowRoot","grandTotalRow","fields","enabled","current","targetZone","fieldIndex","styles"],"mappings":"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"}
1
+ {"version":3,"file":"index.js","sources":["../../../../../../libs/grid/src/lib/core/types.ts","../../../../../../libs/grid/src/lib/core/plugin/base-plugin.ts","../../../../../../libs/grid/src/lib/core/internal/aggregators.ts","../../../../../../libs/grid/src/lib/plugins/pivot/pivot-model.ts","../../../../../../libs/grid/src/lib/plugins/pivot/pivot-engine.ts","../../../../../../libs/grid/src/lib/plugins/pivot/pivot-panel.ts","../../../../../../libs/grid/src/lib/plugins/pivot/pivot-rows.ts","../../../../../../libs/grid/src/lib/plugins/pivot/PivotPlugin.ts"],"sourcesContent":["import type { PluginQuery } from './plugin/base-plugin';\n\n/**\n * The compiled webcomponent interface for DataGrid\n */\nexport interface DataGridElement extends PublicGrid, HTMLElement {}\n\n/**\n * Public API interface for DataGrid component.\n *\n * **Property Getters vs Setters:**\n *\n * Property getters return the EFFECTIVE (resolved) value after merging all config sources.\n * This is the \"current situation\" - what consumers and plugins need to know.\n *\n * Property setters accept input values which are merged into the effective config.\n * Multiple sources can contribute (gridConfig, columns prop, light DOM, individual props).\n *\n * For example:\n * - `grid.fitMode` returns the resolved fitMode (e.g., 'stretch' even if you set undefined)\n * - `grid.columns` returns the effective columns after merging\n * - `grid.gridConfig` returns the full effective config\n */\nexport interface PublicGrid<T = any> {\n /**\n * Full config object. Setter merges with other inputs per precedence rules.\n * Getter returns the effective (resolved) config.\n */\n gridConfig?: GridConfig<T>;\n /**\n * Column definitions.\n * Getter returns effective columns (after merging config, light DOM, inference).\n */\n columns?: ColumnConfig<T>[];\n /** Current row data (after plugin processing like grouping, filtering). */\n rows?: T[];\n /** Resolves once the component has finished initial work (layout, inference). */\n ready?: () => Promise<void>;\n /** Force a layout / measurement pass (e.g. after container resize). */\n forceLayout?: () => Promise<void>;\n /** Return effective resolved config (after inference & precedence). */\n getConfig?: () => Promise<Readonly<GridConfig<T>>>;\n /** Toggle expansion state of a group row by its generated key. */\n toggleGroup?: (key: string) => Promise<void>;\n\n // Custom Styles API\n /**\n * Register custom CSS styles to be injected into the grid's shadow DOM.\n * Use this to style custom cell renderers, editors, or detail panels.\n * @param id - Unique identifier for the style block (for removal/updates)\n * @param css - CSS string to inject\n */\n registerStyles?: (id: string, css: string) => void;\n /**\n * Remove previously registered custom styles.\n * @param id - The ID used when registering the styles\n */\n unregisterStyles?: (id: string) => void;\n /**\n * Get list of registered custom style IDs.\n */\n getRegisteredStyles?: () => string[];\n}\n\n/**\n * Internal-only augmented interface for DataGrid component\n */\nexport interface InternalGrid<T = any> extends PublicGrid<T>, GridConfig<T> {\n shadowRoot: ShadowRoot | null;\n _rows: T[];\n _columns: ColumnInternal<T>[];\n /** Visible columns only (excludes hidden). Use for rendering. */\n _visibleColumns: ColumnInternal<T>[];\n _headerRowEl: HTMLElement;\n _bodyEl: HTMLElement;\n _rowPool: HTMLElement[];\n _resizeController: ResizeController;\n _sortState: { field: string; direction: 1 | -1 } | null;\n __originalOrder: T[];\n __rowRenderEpoch: number;\n __didInitialAutoSize?: boolean;\n __lightDomColumnsCache?: ColumnInternal[];\n __originalColumnNodes?: HTMLElement[];\n _gridTemplate: string;\n _virtualization: VirtualState;\n _focusRow: number;\n _focusCol: number;\n _activeEditRows: number;\n _rowEditSnapshots: Map<number, T>;\n _changedRowIndices: Set<number>;\n changedRows?: T[];\n changedRowIndices?: number[];\n effectiveConfig?: GridConfig<T>;\n findHeaderRow?: () => HTMLElement;\n refreshVirtualWindow: (full: boolean) => void;\n updateTemplate?: () => void;\n findRenderedRowElement?: (rowIndex: number) => HTMLElement | null;\n beginBulkEdit?: (rowIndex: number) => void;\n commitActiveRowEdit?: () => void;\n /** Dispatch cell click to plugin system, returns true if handled */\n _dispatchCellClick?: (event: MouseEvent, rowIndex: number, colIndex: number, cellEl: HTMLElement) => boolean;\n /** Dispatch row click to plugin system, returns true if handled */\n _dispatchRowClick?: (event: MouseEvent, rowIndex: number, row: any, rowEl: HTMLElement) => boolean;\n /** Dispatch header click to plugin system, returns true if handled */\n _dispatchHeaderClick?: (event: MouseEvent, colIndex: number, headerEl: HTMLElement) => boolean;\n /** Dispatch keydown to plugin system, returns true if handled */\n _dispatchKeyDown?: (event: KeyboardEvent) => boolean;\n /** Get horizontal scroll boundary offsets from plugins */\n _getHorizontalScrollOffsets?: (\n rowEl?: HTMLElement,\n focusedCell?: HTMLElement,\n ) => { left: number; right: number; skipScroll?: boolean };\n /** Query all plugins with a generic query and collect responses */\n queryPlugins?: <T>(query: PluginQuery) => T[];\n /** Request emission of column-state-change event (debounced) */\n requestStateChange?: () => void;\n}\n\nexport type PrimitiveColumnType = 'number' | 'string' | 'date' | 'boolean' | 'select' | 'typeahead';\n\n/**\n * Base contract for a column. Public; kept intentionally lean so host apps can extend via intersection types.\n * Prefer adding optional properties here only when broadly useful to most grids.\n */\nexport interface BaseColumnConfig<TRow = any, TValue = any> {\n /** Unique field key referencing property in row objects */\n field: keyof TRow & string;\n /** Visible header label; defaults to capitalized field */\n header?: string;\n /** Column data type; inferred if omitted */\n type?: PrimitiveColumnType;\n /** Column width in pixels; fixed size (no flexibility) */\n width?: string | number;\n /** Minimum column width in pixels (stretch mode only); when set, column uses minmax(minWidth, 1fr) */\n minWidth?: number;\n /** Whether column can be sorted */\n sortable?: boolean;\n /** Whether column can be resized by user */\n resizable?: boolean;\n /** Optional custom comparator for sorting (a,b) -> number */\n sortComparator?: (a: TValue, b: TValue, rowA: TRow, rowB: TRow) => number;\n /** Whether the field is editable (enables editors) */\n editable?: boolean;\n /** Optional custom editor factory or element tag name */\n editor?: ColumnEditorSpec<TRow, TValue>;\n /** For select/typeahead types - available options */\n options?: Array<{ label: string; value: unknown }> | (() => Array<{ label: string; value: unknown }>);\n /** For select/typeahead - allow multi select */\n multi?: boolean;\n /** Optional formatter */\n format?: (value: TValue, row: TRow) => string;\n /** Arbitrary extra metadata */\n meta?: Record<string, unknown>;\n}\n\n/**\n * Full column configuration including optional custom view/renderer & grouping metadata.\n */\nexport interface ColumnConfig<TRow = any> extends BaseColumnConfig<TRow, any> {\n /**\n * Optional custom cell renderer function. Alias for `viewRenderer`.\n * Can return an HTMLElement, a Node, or an HTML string (which will be sanitized).\n *\n * @example\n * ```typescript\n * // Simple string template\n * renderer: (ctx) => `<span class=\"badge\">${ctx.value}</span>`\n *\n * // DOM element\n * renderer: (ctx) => {\n * const el = document.createElement('span');\n * el.textContent = ctx.value;\n * return el;\n * }\n * ```\n */\n renderer?: ColumnViewRenderer<TRow, any>;\n /** Optional custom view renderer used instead of default text rendering */\n viewRenderer?: ColumnViewRenderer<TRow, any>;\n /** External view spec (lets host app mount any framework component) */\n externalView?: {\n component: unknown;\n props?: Record<string, unknown>;\n mount?: (options: {\n placeholder: HTMLElement;\n context: CellRenderContext<TRow, unknown>;\n spec: unknown;\n }) => void | { dispose?: () => void };\n };\n /** Whether the column is initially hidden */\n hidden?: boolean;\n /** Prevent this column from being hidden programmatically */\n lockVisible?: boolean;\n}\n\nexport type ColumnConfigMap<TRow = any> = ColumnConfig<TRow>[];\n\n/** External editor spec: tag name, factory function, or external mount spec */\nexport type ColumnEditorSpec<TRow = unknown, TValue = unknown> =\n | string // custom element tag name\n | ((context: ColumnEditorContext<TRow, TValue>) => HTMLElement | string)\n | {\n /** Arbitrary component reference (class, function, token) */\n component: unknown;\n /** Optional static props passed to mount */\n props?: Record<string, unknown>;\n /** Optional custom mount function; if provided we call it directly instead of emitting an event */\n mount?: (options: {\n placeholder: HTMLElement;\n context: ColumnEditorContext<TRow, TValue>;\n spec: unknown;\n }) => void | { dispose?: () => void };\n };\n\n/**\n * Context object provided to editor factories allowing mutation (commit/cancel) of a cell value.\n */\nexport interface ColumnEditorContext<TRow = any, TValue = any> {\n /** Underlying full row object for the active edit. */\n row: TRow;\n /** Current cell value (mutable only via commit). */\n value: TValue;\n /** Field name being edited. */\n field: keyof TRow & string;\n /** Column configuration reference. */\n column: ColumnConfig<TRow>;\n /** Accept the edit; triggers change tracking + rerender. */\n commit: (newValue: TValue) => void;\n /** Abort edit without persisting changes. */\n cancel: () => void;\n}\n\n/**\n * Context passed to custom view renderers (pure display – no commit helpers).\n */\nexport interface CellRenderContext<TRow = any, TValue = any> {\n /** Row object for the cell being rendered. */\n row: TRow;\n /** Value at field. */\n value: TValue;\n /** Field key. */\n field: keyof TRow & string;\n /** Column configuration reference. */\n column: ColumnConfig<TRow>;\n /**\n * The cell DOM element being rendered into.\n * Framework adapters can use this to cache per-cell state (e.g., React roots).\n * @internal\n */\n cellEl?: HTMLElement;\n}\n\nexport type ColumnViewRenderer<TRow = unknown, TValue = unknown> = (\n ctx: CellRenderContext<TRow, TValue>,\n) => Node | string | void;\n\n/**\n * Framework adapter interface for handling framework-specific component instantiation.\n * Allows framework libraries (Angular, React, Vue) to register handlers that convert\n * declarative light DOM elements into functional renderers/editors.\n *\n * @example\n * ```typescript\n * // In @toolbox-web/grid-angular\n * class AngularGridAdapter implements FrameworkAdapter {\n * canHandle(element: HTMLElement): boolean {\n * return element.tagName.startsWith('APP-');\n * }\n * createRenderer(element: HTMLElement): ColumnViewRenderer {\n * return (ctx) => {\n * // Angular-specific instantiation logic\n * const componentRef = createComponent(...);\n * componentRef.setInput('value', ctx.value);\n * return componentRef.location.nativeElement;\n * };\n * }\n * createEditor(element: HTMLElement): ColumnEditorSpec {\n * return (ctx) => {\n * // Angular-specific editor with commit/cancel\n * const componentRef = createComponent(...);\n * componentRef.setInput('value', ctx.value);\n * // Subscribe to commit/cancel outputs\n * return componentRef.location.nativeElement;\n * };\n * }\n * }\n *\n * // User registers adapter once in their app\n * GridElement.registerAdapter(new AngularGridAdapter(injector, appRef));\n * ```\n */\nexport interface FrameworkAdapter {\n /**\n * Determines if this adapter can handle the given element.\n * Typically checks tag name, attributes, or other conventions.\n */\n canHandle(element: HTMLElement): boolean;\n\n /**\n * Creates a view renderer function from a light DOM element.\n * The renderer receives cell context and returns DOM or string.\n */\n createRenderer<TRow = unknown, TValue = unknown>(element: HTMLElement): ColumnViewRenderer<TRow, TValue>;\n\n /**\n * Creates an editor spec from a light DOM element.\n * The editor receives context with commit/cancel and returns DOM.\n */\n createEditor<TRow = unknown, TValue = unknown>(element: HTMLElement): ColumnEditorSpec<TRow, TValue>;\n\n /**\n * Creates a tool panel renderer from a light DOM element.\n * The renderer receives a container element and optionally returns a cleanup function.\n */\n createToolPanelRenderer?(element: HTMLElement): ((container: HTMLElement) => void | (() => void)) | undefined;\n}\n\n// #region Internal-only augmented types (not re-exported publicly)\nexport interface ColumnInternal<T = any> extends ColumnConfig<T> {\n __autoSized?: boolean;\n __userResized?: boolean;\n __renderedWidth?: number;\n /** Original configured width (for reset on double-click) */\n __originalWidth?: number;\n __viewTemplate?: HTMLElement;\n __editorTemplate?: HTMLElement;\n __headerTemplate?: HTMLElement;\n __compiledView?: (ctx: CellContext<T>) => string;\n __compiledEditor?: (ctx: EditorExecContext<T>) => string;\n}\n\n/**\n * Runtime cell context used internally for compiled template execution.\n */\nexport interface CellContext<T = any> {\n row: T;\n value: unknown;\n field: string;\n column: ColumnInternal<T>;\n}\n\n/**\n * Internal editor execution context extending the generic cell context with commit helpers.\n */\nexport interface EditorExecContext<T = any> extends CellContext<T> {\n commit: (newValue: unknown) => void;\n cancel: () => void;\n}\n\n/** Controller managing drag-based column resize lifecycle. */\nexport interface ResizeController {\n start: (e: MouseEvent, colIndex: number, cell: HTMLElement) => void;\n /** Reset a column to its configured width (or auto-size if none configured). */\n resetColumn: (colIndex: number) => void;\n dispose: () => void;\n /** True while a resize drag is in progress (used to suppress header click/sort). */\n isResizing: boolean;\n}\n\n/** Virtual window bookkeeping; modified in-place as scroll position changes. */\nexport interface VirtualState {\n enabled: boolean;\n rowHeight: number;\n /** Threshold for bypassing virtualization (renders all rows if totalRows <= bypassThreshold) */\n bypassThreshold: number;\n start: number;\n end: number;\n /** Faux scrollbar element that provides scroll events (AG Grid pattern) */\n container: HTMLElement | null;\n /** Rows viewport element for measuring visible area height */\n viewportEl: HTMLElement | null;\n /** Spacer element inside faux scrollbar for setting virtual height */\n totalHeightEl: HTMLElement | null;\n}\n// #endregion\n\n// #region Grouping & Footer Public Types\n/**\n * Group row rendering customization options.\n * Used within grouping-rows plugin config for presentation of group rows.\n */\nexport interface RowGroupRenderConfig {\n /** If true, group rows span all columns (single full-width cell). Default false. */\n fullWidth?: boolean;\n /** Optional label formatter override. Receives raw group value + depth. */\n formatLabel?: (value: unknown, depth: number, key: string) => string;\n /** Optional aggregate overrides per field for group summary cells (only when not fullWidth). */\n aggregators?: Record<string, AggregatorRef>;\n /** Additional CSS class applied to each group row root element. */\n class?: string;\n}\n\nexport type AggregatorRef = string | ((rows: unknown[], field: string, column?: unknown) => unknown);\n\n/** Result of automatic column inference from sample rows. */\nexport interface InferredColumnResult<TRow = unknown> {\n columns: ColumnConfigMap<TRow>;\n typeMap: Record<string, PrimitiveColumnType>;\n}\n\nexport const FitModeEnum = {\n STRETCH: 'stretch',\n FIXED: 'fixed',\n} as const;\nexport type FitMode = (typeof FitModeEnum)[keyof typeof FitModeEnum]; // evaluates to 'stretch' | 'fixed'\n// #endregion\n\n// #region Plugin Interface\n/**\n * Minimal plugin interface for type-checking.\n * This interface is defined here to avoid circular imports with BaseGridPlugin.\n * All plugins must satisfy this shape (BaseGridPlugin implements it).\n */\nexport interface GridPlugin {\n /** Unique plugin identifier */\n readonly name: string;\n /** Plugin version */\n readonly version: string;\n /** CSS styles to inject into grid's shadow DOM */\n readonly styles?: string;\n}\n// #endregion\n\n// #region Grid Config\n/**\n * Grid configuration object - the **single source of truth** for grid behavior.\n *\n * Users can configure the grid via multiple input methods, all of which converge\n * into an effective `GridConfig` internally:\n *\n * **Configuration Input Methods:**\n * - `gridConfig` property - direct assignment of this object\n * - `columns` property - shorthand for `gridConfig.columns`\n * - `fitMode` property - shorthand for `gridConfig.fitMode`\n * - `editOn` property - shorthand for `gridConfig.editOn`\n * - Light DOM `<tbw-grid-column>` - declarative columns (merged into `columns`)\n * - Light DOM `<tbw-grid-header>` - declarative shell header (merged into `shell.header`)\n *\n * **Precedence (when same property set multiple ways):**\n * Individual props (`fitMode`, `editOn`) > `columns` prop > Light DOM > `gridConfig`\n *\n * @example\n * ```ts\n * // Via gridConfig (recommended for complex setups)\n * grid.gridConfig = {\n * columns: [{ field: 'name' }, { field: 'age' }],\n * fitMode: 'stretch',\n * plugins: [new SelectionPlugin()],\n * shell: { header: { title: 'My Grid' } }\n * };\n *\n * // Via individual props (convenience for simple cases)\n * grid.columns = [{ field: 'name' }, { field: 'age' }];\n * grid.fitMode = 'stretch';\n * ```\n */\nexport interface GridConfig<TRow = any> {\n /** Column definitions. Can also be set via `columns` prop or `<tbw-grid-column>` light DOM. */\n columns?: ColumnConfigMap<TRow>;\n /** Sizing mode for columns. Can also be set via `fitMode` prop. */\n fitMode?: FitMode;\n /** Edit activation mode ('click' | 'dblClick' | false). Set to false to disable editing. Can also be set via `editOn` prop. */\n editOn?: string | boolean;\n /**\n * Row height in pixels for virtualization calculations.\n * The virtualization system assumes uniform row heights for performance.\n *\n * If not specified, the grid measures the first rendered row's height,\n * which respects the CSS variable `--tbw-row-height` set by themes.\n *\n * Set this explicitly when:\n * - Row content may wrap to multiple lines (also set `--tbw-cell-white-space: normal`)\n * - Using custom row templates with variable content\n * - You want to override theme-defined row height\n *\n * @default Auto-measured from first row (respects --tbw-row-height CSS variable)\n *\n * @example\n * ```ts\n * // Fixed height for rows that may wrap to 2 lines\n * gridConfig = { rowHeight: 56 };\n * ```\n */\n rowHeight?: number;\n /**\n * Array of plugin instances.\n * Each plugin is instantiated with its configuration and attached to this grid.\n *\n * @example\n * ```ts\n * plugins: [\n * new SelectionPlugin({ mode: 'range' }),\n * new MultiSortPlugin(),\n * new FilteringPlugin({ debounceMs: 150 }),\n * ]\n * ```\n */\n plugins?: GridPlugin[];\n\n /**\n * Saved column state to restore on initialization.\n * Includes order, width, visibility, sort, and plugin-contributed state.\n */\n columnState?: GridColumnState;\n\n /**\n * Shell configuration for header bar and tool panels.\n * When configured, adds an optional wrapper with title, toolbar, and collapsible side panels.\n */\n shell?: ShellConfig;\n\n /**\n * Grid-wide icon configuration.\n * Provides consistent icons across all plugins (tree, grouping, sorting, etc.).\n * Plugins will use these by default but can override with their own config.\n */\n icons?: GridIcons;\n\n /**\n * Grid-wide animation configuration.\n * Controls animations for expand/collapse, reordering, and other visual transitions.\n * Individual plugins can override these defaults in their own config.\n */\n animation?: AnimationConfig;\n\n /**\n * Custom sort handler for full control over sorting behavior.\n *\n * When provided, this handler is called instead of the built-in sorting logic.\n * Enables custom sorting algorithms, server-side sorting, or plugin-specific sorting.\n *\n * The handler receives:\n * - `rows`: Current row array to sort\n * - `sortState`: Sort field and direction (1 = asc, -1 = desc)\n * - `columns`: Column configurations (for accessing sortComparator)\n *\n * Return the sorted array (sync) or a Promise that resolves to the sorted array (async).\n * For server-side sorting, return a Promise that resolves when data is fetched.\n *\n * @example\n * ```ts\n * // Custom stable sort\n * sortHandler: (rows, state, cols) => {\n * return stableSort(rows, (a, b) => compare(a[state.field], b[state.field]) * state.direction);\n * }\n *\n * // Server-side sorting\n * sortHandler: async (rows, state) => {\n * const response = await fetch(`/api/data?sort=${state.field}&dir=${state.direction}`);\n * return response.json();\n * }\n * ```\n */\n sortHandler?: SortHandler<TRow>;\n}\n// #endregion\n\n// #region Animation\n\n/**\n * Sort state passed to custom sort handlers.\n */\nexport interface SortState {\n /** Field to sort by */\n field: string;\n /** Sort direction: 1 = ascending, -1 = descending */\n direction: 1 | -1;\n}\n\n/**\n * Custom sort handler function signature.\n *\n * @param rows - Current row array to sort\n * @param sortState - Sort field and direction\n * @param columns - Column configurations (for accessing sortComparator)\n * @returns Sorted array (sync) or Promise resolving to sorted array (async)\n */\nexport type SortHandler<TRow = any> = (\n rows: TRow[],\n sortState: SortState,\n columns: ColumnConfig<TRow>[],\n) => TRow[] | Promise<TRow[]>;\n\n/**\n * Animation behavior mode.\n * - `true` or `'on'`: Animations always enabled\n * - `false` or `'off'`: Animations always disabled\n * - `'reduced-motion'`: Respects `prefers-reduced-motion` media query (default)\n */\nexport type AnimationMode = boolean | 'on' | 'off' | 'reduced-motion';\n\n/**\n * Animation style for visual transitions.\n * - `'slide'`: Slide/transform animation (e.g., expand down, slide left/right)\n * - `'fade'`: Opacity fade animation\n * - `'flip'`: FLIP technique for position changes (First, Last, Invert, Play)\n * - `false`: No animation for this specific feature\n */\nexport type AnimationStyle = 'slide' | 'fade' | 'flip' | false;\n\n/**\n * Animation style for expand/collapse operations.\n * Subset of AnimationStyle - excludes 'flip' which is for position changes.\n * - `'slide'`: Slide down/up animation for expanding/collapsing content\n * - `'fade'`: Fade in/out animation\n * - `false`: No animation\n */\nexport type ExpandCollapseAnimation = 'slide' | 'fade' | false;\n\n/**\n * Grid-wide animation configuration.\n * Controls global animation behavior - individual plugins define their own animation styles.\n * Duration and easing values set corresponding CSS variables on the grid element.\n */\nexport interface AnimationConfig {\n /**\n * Global animation mode.\n * @default 'reduced-motion'\n */\n mode?: AnimationMode;\n\n /**\n * Default animation duration in milliseconds.\n * Sets `--tbw-animation-duration` CSS variable.\n * @default 200\n */\n duration?: number;\n\n /**\n * Default easing function.\n * Sets `--tbw-animation-easing` CSS variable.\n * @default 'ease-out'\n */\n easing?: string;\n}\n\n/** Default animation configuration */\nexport const DEFAULT_ANIMATION_CONFIG: Required<Omit<AnimationConfig, 'sort'>> = {\n mode: 'reduced-motion',\n duration: 200,\n easing: 'ease-out',\n};\n\n// #endregion\n\n// #region Grid Icons\n\n/** Icon value - can be a string (text/HTML) or HTMLElement */\nexport type IconValue = string | HTMLElement;\n\n/**\n * Grid-wide icon configuration.\n * All icons are optional - sensible defaults are used when not specified.\n */\nexport interface GridIcons {\n /** Expand icon for collapsed items (trees, groups, details). Default: '▶' */\n expand?: IconValue;\n /** Collapse icon for expanded items (trees, groups, details). Default: '▼' */\n collapse?: IconValue;\n /** Sort ascending indicator. Default: '▲' */\n sortAsc?: IconValue;\n /** Sort descending indicator. Default: '▼' */\n sortDesc?: IconValue;\n /** Sort neutral/unsorted indicator. Default: '⇅' */\n sortNone?: IconValue;\n /** Submenu arrow for context menus. Default: '▶' */\n submenuArrow?: IconValue;\n /** Drag handle icon for reordering. Default: '⋮⋮' */\n dragHandle?: IconValue;\n /** Tool panel toggle icon in toolbar. Default: '☰' */\n toolPanel?: IconValue;\n}\n\n/** Default icons used when not overridden */\nexport const DEFAULT_GRID_ICONS: Required<GridIcons> = {\n expand: '▶',\n collapse: '▼',\n sortAsc: '▲',\n sortDesc: '▼',\n sortNone: '⇅',\n submenuArrow: '▶',\n dragHandle: '⋮⋮',\n toolPanel: '☰',\n};\n// #endregion\n\n// #region Shell Configuration\n\n/**\n * Shell configuration for the grid's optional header bar and tool panels.\n */\nexport interface ShellConfig {\n /** Shell header bar configuration */\n header?: ShellHeaderConfig;\n /** Tool panel configuration */\n toolPanel?: ToolPanelConfig;\n}\n\n/**\n * Shell header bar configuration\n */\nexport interface ShellHeaderConfig {\n /** Grid title displayed on the left (optional) */\n title?: string;\n /** Custom toolbar buttons (rendered before tool panel toggles) */\n toolbarButtons?: ToolbarButtonConfig[];\n}\n\n/**\n * Tool panel configuration\n */\nexport interface ToolPanelConfig {\n /** Panel position: 'left' | 'right' (default: 'right') */\n position?: 'left' | 'right';\n /** Default panel width in pixels (default: 280) */\n width?: number;\n /** Panel ID to open by default on load */\n defaultOpen?: string;\n /** Whether to persist open/closed state (requires Column State Events) */\n persistState?: boolean;\n}\n\n/**\n * Toolbar button defined via config (programmatic approach).\n *\n * The grid does NOT create buttons - developers have full control over their own buttons.\n * Provide either:\n * - `element`: A ready-made DOM element (grid appends it to toolbar)\n * - `render`: A factory function that receives a container and appends content\n *\n * For declarative HTML buttons, use light-dom instead:\n * ```html\n * <tbw-grid>\n * <tbw-grid-header>\n * <button slot=\"toolbar\">My Button</button>\n * </tbw-grid-header>\n * </tbw-grid>\n * ```\n */\nexport interface ToolbarButtonConfig {\n /** Unique button ID */\n id: string;\n /** Tooltip / aria-label (for accessibility, used when grid generates panel toggle) */\n label?: string;\n /** Order priority (lower = first, default: 100) */\n order?: number;\n\n /**\n * User-provided element. Grid appends it to the toolbar.\n * User is responsible for styling, event handlers, accessibility, etc.\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 /** Source of this button: 'config' | 'light-dom' | 'panel-toggle' */\n source: 'config' | 'light-dom' | 'panel-toggle';\n /** For panel toggles, the associated panel ID */\n panelId?: string;\n}\n\n/**\n * Tool panel definition registered by plugins or consumers.\n */\nexport interface ToolPanelDefinition {\n /** Unique panel ID */\n id: string;\n /** Panel title shown in accordion header */\n title: string;\n /** Icon for accordion section header (optional, emoji or SVG) */\n icon?: string;\n /** Tooltip for accordion section header */\n tooltip?: string;\n /** Panel content factory - called when panel section opens */\n render: (container: HTMLElement) => void | (() => void);\n /** Called when panel closes (for cleanup) */\n onClose?: () => void;\n /** Panel order priority (lower = first, default: 100) */\n order?: number;\n}\n\n/**\n * Header content definition for plugins contributing to shell header center section.\n */\nexport interface HeaderContentDefinition {\n /** Unique content ID */\n id: string;\n /** Content factory - called once when shell header renders */\n render: (container: HTMLElement) => void | (() => void);\n /** Called when content is removed (for cleanup) */\n onDestroy?: () => void;\n /** Order priority (lower = first, default: 100) */\n order?: number;\n}\n// #endregion\n\n// #region Column State (Persistence)\n\n/**\n * State for a single column. Captures user-driven changes at runtime.\n * Plugins can extend this interface via module augmentation to add their own state.\n *\n * @example\n * ```ts\n * // In filtering plugin\n * declare module '@toolbox-web/grid' {\n * interface ColumnState {\n * filter?: FilterValue;\n * }\n * }\n * ```\n */\nexport interface ColumnState {\n /** Column field identifier */\n field: string;\n /** Position index after reordering (0-based) */\n order: number;\n /** Width in pixels (undefined = use default) */\n width?: number;\n /** Visibility state */\n visible: boolean;\n /** Sort state (undefined = not sorted) */\n sort?: ColumnSortState;\n}\n\n/**\n * Sort state for a column\n */\nexport interface ColumnSortState {\n /** Sort direction */\n direction: 'asc' | 'desc';\n /** Priority for multi-sort (0 = primary, 1 = secondary, etc.) */\n priority: number;\n}\n\n/**\n * Complete grid column state for persistence.\n * Contains state for all columns, including plugin-contributed properties.\n */\nexport interface GridColumnState {\n columns: ColumnState[];\n}\n// #endregion\n\n// #region Public Event Detail Interfaces\nexport interface CellCommitDetail<TRow = unknown> {\n /** The mutated row after commit. */\n row: TRow;\n /** Field name whose value changed. */\n field: string;\n /** New value stored. */\n value: unknown;\n /** Index of the row in current data set. */\n rowIndex: number;\n /** All rows that have at least one committed change (snapshot list). */\n changedRows: TRow[];\n /** Indices parallel to changedRows. */\n changedRowIndices: number[];\n /** True if this row just entered the changed set. */\n firstTimeForRow: boolean;\n}\n\n/** Detail payload for a committed row edit (may or may not include changes). */\nexport interface RowCommitDetail<TRow = unknown> {\n /** Row index that lost edit focus. */\n rowIndex: number;\n /** Row object reference. */\n row: TRow;\n /** Whether any cell changes were actually committed in this row during the session. */\n changed: boolean;\n /** Current changed row collection. */\n changedRows: TRow[];\n /** Indices of changed rows. */\n changedRowIndices: number[];\n}\n\n/** Emitted when the changed rows tracking set is cleared programmatically. */\nexport interface ChangedRowsResetDetail<TRow = unknown> {\n /** New (empty) changed rows array after reset. */\n rows: TRow[];\n /** Parallel indices (likely empty). */\n indices: number[];\n}\n\n/** Detail for a sort change (direction 0 indicates cleared sort). */\nexport interface SortChangeDetail {\n /** Sorted field key. */\n field: string;\n /** Direction: 1 ascending, -1 descending, 0 cleared. */\n direction: 1 | -1 | 0;\n}\n\n/** Column resize event detail containing final pixel width. */\nexport interface ColumnResizeDetail {\n /** Resized column field key. */\n field: string;\n /** New width in pixels. */\n width: number;\n}\n\n/** Fired when keyboard navigation or programmatic focus changes active cell. */\nexport interface ActivateCellDetail {\n /** Zero-based row index now focused. */\n row: number;\n /** Zero-based column index now focused. */\n col: number;\n}\n\nexport interface ExternalMountViewDetail<TRow = unknown> {\n placeholder: HTMLElement;\n spec: unknown;\n context: { row: TRow; value: unknown; field: string; column: unknown };\n}\n\nexport interface ExternalMountEditorDetail<TRow = unknown> {\n placeholder: HTMLElement;\n spec: unknown;\n context: {\n row: TRow;\n value: unknown;\n field: string;\n column: unknown;\n commit: (v: unknown) => void;\n cancel: () => void;\n };\n}\n\nexport interface DataGridEventMap<TRow = unknown> {\n 'cell-commit': CellCommitDetail<TRow>;\n 'row-commit': RowCommitDetail<TRow>;\n 'changed-rows-reset': ChangedRowsResetDetail<TRow>;\n 'mount-external-view': ExternalMountViewDetail<TRow>;\n 'mount-external-editor': ExternalMountEditorDetail<TRow>;\n 'sort-change': SortChangeDetail;\n 'column-resize': ColumnResizeDetail;\n 'activate-cell': ActivateCellDetail;\n 'column-state-change': GridColumnState;\n}\n\nexport type DataGridEventDetail<K extends keyof DataGridEventMap<unknown>, TRow = unknown> = DataGridEventMap<TRow>[K];\nexport type DataGridCustomEvent<K extends keyof DataGridEventMap<unknown>, TRow = unknown> = CustomEvent<\n DataGridEventMap<TRow>[K]\n>;\n\n// Internal code now reuses the public ColumnEditorContext; provide alias for backward compatibility\nexport type EditorContext<T = unknown> = ColumnEditorContext<T, unknown>;\n\nexport interface EvalContext {\n value: unknown;\n row: Record<string, unknown> | null;\n}\n// #endregion\n","/**\n * Base Grid Plugin Class\n *\n * All plugins extend this abstract class.\n * Plugins are instantiated per-grid and manage their own state.\n */\n\nimport type {\n ColumnConfig,\n ColumnState,\n GridPlugin,\n HeaderContentDefinition,\n IconValue,\n ToolPanelDefinition,\n} from '../types';\nimport { DEFAULT_GRID_ICONS } from '../types';\n\n// Re-export shared plugin types for convenience\nexport { PLUGIN_QUERIES } from './types';\nexport type {\n CellClickEvent,\n CellCoords,\n CellEditor,\n CellMouseEvent,\n CellRenderer,\n ContextMenuItem,\n ContextMenuParams,\n GridElementRef,\n HeaderClickEvent,\n HeaderRenderer,\n KeyboardModifiers,\n PluginCellRenderContext,\n PluginQuery,\n RowClickEvent,\n ScrollEvent,\n} from './types';\n\nimport type {\n CellClickEvent,\n CellEditor,\n CellMouseEvent,\n CellRenderer,\n GridElementRef,\n HeaderClickEvent,\n HeaderRenderer,\n PluginQuery,\n RowClickEvent,\n ScrollEvent,\n} from './types';\n\n/**\n * Grid element interface for plugins.\n * Extends GridElementRef with plugin-specific methods.\n */\nexport interface GridElement extends GridElementRef {\n getPlugin<T extends BaseGridPlugin>(PluginClass: new (...args: any[]) => T): T | undefined;\n getPluginByName(name: string): BaseGridPlugin | undefined;\n}\n\n/**\n * Header render context for plugin header renderers.\n */\nexport interface PluginHeaderRenderContext {\n /** Column configuration */\n column: ColumnConfig;\n /** Column index */\n colIndex: number;\n}\n\n/**\n * Abstract base class for all grid plugins.\n *\n * @template TConfig - Configuration type for the plugin\n */\nexport abstract class BaseGridPlugin<TConfig = unknown> implements GridPlugin {\n /** Unique plugin identifier (derived from class name by default) */\n abstract readonly name: string;\n\n /** Plugin version - override in subclass if needed */\n readonly version: string = '1.0.0';\n\n /** CSS styles to inject into the grid's shadow DOM */\n readonly styles?: string;\n\n /** Custom cell renderers keyed by type name */\n readonly cellRenderers?: Record<string, CellRenderer>;\n\n /** Custom header renderers keyed by type name */\n readonly headerRenderers?: Record<string, HeaderRenderer>;\n\n /** Custom cell editors keyed by type name */\n readonly cellEditors?: Record<string, CellEditor>;\n\n /** The grid instance this plugin is attached to */\n protected grid!: GridElement;\n\n /** Plugin configuration - merged with defaults in attach() */\n protected config!: TConfig;\n\n /** User-provided configuration from constructor */\n protected readonly userConfig: Partial<TConfig>;\n\n /**\n * Default configuration - subclasses should override this getter.\n * Note: This must be a getter (not property initializer) for proper inheritance\n * since property initializers run after parent constructor.\n */\n protected get defaultConfig(): Partial<TConfig> {\n return {};\n }\n\n constructor(config: Partial<TConfig> = {}) {\n this.userConfig = config;\n }\n\n /**\n * Called when the plugin is attached to a grid.\n * Override to set up event listeners, initialize state, etc.\n */\n attach(grid: GridElement): void {\n this.grid = grid;\n // Merge config here (after subclass construction is complete)\n this.config = { ...this.defaultConfig, ...this.userConfig } as TConfig;\n }\n\n /**\n * Called when the plugin is detached from a grid.\n * Override to clean up event listeners, timers, etc.\n */\n detach(): void {\n // Override in subclass\n }\n\n /**\n * Get another plugin instance from the same grid.\n * Use for inter-plugin communication.\n */\n protected getPlugin<T extends BaseGridPlugin>(PluginClass: new (...args: any[]) => T): T | undefined {\n return this.grid?.getPlugin(PluginClass);\n }\n\n /**\n * Emit a custom event from the grid.\n */\n protected emit<T>(eventName: string, detail: T): void {\n this.grid?.dispatchEvent?.(new CustomEvent(eventName, { detail, bubbles: true }));\n }\n\n /**\n * Request a re-render of the grid.\n */\n protected requestRender(): void {\n this.grid?.requestRender?.();\n }\n\n /**\n * Request a lightweight style update without rebuilding DOM.\n * Use this instead of requestRender() when only CSS classes need updating.\n */\n protected requestAfterRender(): void {\n this.grid?.requestAfterRender?.();\n }\n\n /**\n * Get the current rows from the grid.\n */\n protected get rows(): any[] {\n return this.grid?.rows ?? [];\n }\n\n /**\n * Get the original unfiltered/unprocessed rows from the grid.\n * Use this when you need all source data regardless of active filters.\n */\n protected get sourceRows(): any[] {\n return (this.grid as any)?.sourceRows ?? [];\n }\n\n /**\n * Get the current columns from the grid.\n */\n protected get columns(): ColumnConfig[] {\n return this.grid?.columns ?? [];\n }\n\n /**\n * Get only visible columns from the grid (excludes hidden).\n * Use this for rendering that needs to match the grid template.\n */\n protected get visibleColumns(): ColumnConfig[] {\n return (this.grid as any)?._visibleColumns ?? [];\n }\n\n /**\n * Get the shadow root of the grid.\n */\n protected get shadowRoot(): ShadowRoot | null {\n return this.grid?.shadowRoot ?? null;\n }\n\n /**\n * Get the disconnect signal for event listener cleanup.\n * This signal is aborted when the grid disconnects from the DOM.\n * Use this when adding event listeners that should be cleaned up automatically.\n *\n * Best for:\n * - Document/window-level listeners added in attach()\n * - Listeners on the grid element itself\n * - Any listener that should persist across renders\n *\n * Not needed for:\n * - Listeners on elements created in afterRender() (removed with element)\n *\n * @example\n * element.addEventListener('click', handler, { signal: this.disconnectSignal });\n * document.addEventListener('keydown', handler, { signal: this.disconnectSignal });\n */\n protected get disconnectSignal(): AbortSignal {\n return this.grid?.disconnectSignal;\n }\n\n /**\n * Get the grid-level icons configuration.\n * Returns merged icons (user config + defaults).\n */\n protected get gridIcons(): typeof DEFAULT_GRID_ICONS {\n const userIcons = this.grid?.gridConfig?.icons ?? {};\n return { ...DEFAULT_GRID_ICONS, ...userIcons };\n }\n\n /**\n * Resolve an icon value to string or HTMLElement.\n * Checks plugin config first, then grid-level icons, then defaults.\n *\n * @param iconKey - The icon key in GridIcons (e.g., 'expand', 'collapse')\n * @param pluginOverride - Optional plugin-level override\n * @returns The resolved icon value\n */\n protected resolveIcon(iconKey: keyof typeof DEFAULT_GRID_ICONS, pluginOverride?: IconValue): IconValue {\n // Plugin override takes precedence\n if (pluginOverride !== undefined) {\n return pluginOverride;\n }\n // Then grid-level config\n return this.gridIcons[iconKey];\n }\n\n /**\n * Set an icon value on an element.\n * Handles both string (text/HTML) and HTMLElement values.\n *\n * @param element - The element to set the icon on\n * @param icon - The icon value (string or HTMLElement)\n */\n protected setIcon(element: HTMLElement, icon: IconValue): void {\n if (typeof icon === 'string') {\n element.innerHTML = icon;\n } else if (icon instanceof HTMLElement) {\n element.innerHTML = '';\n element.appendChild(icon.cloneNode(true));\n }\n }\n\n /**\n * Log a warning message.\n */\n protected warn(message: string): void {\n console.warn(`[tbw-grid:${this.name}] ${message}`);\n }\n\n // #region Lifecycle Hooks\n\n /**\n * Transform rows before rendering.\n * Called during each render cycle before rows are rendered to the DOM.\n * Use this to filter, sort, or add computed properties to rows.\n *\n * @param rows - The current rows array (readonly to encourage returning a new array)\n * @returns The modified rows array to render\n *\n * @example\n * ```ts\n * processRows(rows: readonly any[]): any[] {\n * // Filter out hidden rows\n * return rows.filter(row => !row._hidden);\n * }\n * ```\n *\n * @example\n * ```ts\n * processRows(rows: readonly any[]): any[] {\n * // Add computed properties\n * return rows.map(row => ({\n * ...row,\n * _fullName: `${row.firstName} ${row.lastName}`\n * }));\n * }\n * ```\n */\n processRows?(rows: readonly any[]): any[];\n\n /**\n * Transform columns before rendering.\n * Called during each render cycle before column headers and cells are rendered.\n * Use this to add, remove, or modify column definitions.\n *\n * @param columns - The current columns array (readonly to encourage returning a new array)\n * @returns The modified columns array to render\n *\n * @example\n * ```ts\n * processColumns(columns: readonly ColumnConfig[]): ColumnConfig[] {\n * // Add a selection checkbox column\n * return [\n * { field: '_select', header: '', width: 40 },\n * ...columns\n * ];\n * }\n * ```\n */\n processColumns?(columns: readonly ColumnConfig[]): ColumnConfig[];\n\n /**\n * Called before each render cycle begins.\n * Use this to prepare state or cache values needed during rendering.\n *\n * @example\n * ```ts\n * beforeRender(): void {\n * this.visibleRowCount = this.calculateVisibleRows();\n * }\n * ```\n */\n beforeRender?(): void;\n\n /**\n * Called after each render cycle completes.\n * Use this for DOM manipulation, adding event listeners to rendered elements,\n * or applying visual effects like selection highlights.\n *\n * @example\n * ```ts\n * afterRender(): void {\n * // Apply selection styling to rendered rows\n * const rows = this.shadowRoot?.querySelectorAll('.data-row');\n * rows?.forEach((row, i) => {\n * row.classList.toggle('selected', this.selectedRows.has(i));\n * });\n * }\n * ```\n */\n afterRender?(): void;\n\n /**\n * Called after scroll-triggered row rendering completes.\n * This is a lightweight hook for applying visual state to recycled DOM elements.\n * Use this instead of afterRender when you need to reapply styling during scroll.\n *\n * Performance note: This is called frequently during scroll. Keep implementation fast.\n *\n * @example\n * ```ts\n * onScrollRender(): void {\n * // Reapply selection state to visible cells\n * this.applySelectionToVisibleCells();\n * }\n * ```\n */\n onScrollRender?(): void;\n\n /**\n * Return extra height contributed by this plugin (e.g., expanded detail rows).\n * Used to adjust scrollbar height calculations for virtualization.\n *\n * @returns Total extra height in pixels\n *\n * @example\n * ```ts\n * getExtraHeight(): number {\n * return this.expandedRows.size * this.detailHeight;\n * }\n * ```\n */\n getExtraHeight?(): number;\n\n /**\n * Return extra height that appears before a given row index.\n * Used by virtualization to correctly calculate scroll positions when\n * there's variable height content (like expanded detail rows) above the viewport.\n *\n * @param beforeRowIndex - The row index to calculate extra height before\n * @returns Extra height in pixels that appears before this row\n *\n * @example\n * ```ts\n * getExtraHeightBefore(beforeRowIndex: number): number {\n * let height = 0;\n * for (const expandedRowIndex of this.expandedRowIndices) {\n * if (expandedRowIndex < beforeRowIndex) {\n * height += this.getDetailHeight(expandedRowIndex);\n * }\n * }\n * return height;\n * }\n * ```\n */\n getExtraHeightBefore?(beforeRowIndex: number): number;\n\n /**\n * Adjust the virtualization start index to render additional rows before the visible range.\n * Use this when expanded content (like detail rows) needs its parent row to remain rendered\n * even when the parent row itself has scrolled above the viewport.\n *\n * @param start - The calculated start row index\n * @param scrollTop - The current scroll position\n * @param rowHeight - The height of a single row\n * @returns The adjusted start index (lower than or equal to original start)\n *\n * @example\n * ```ts\n * adjustVirtualStart(start: number, scrollTop: number, rowHeight: number): number {\n * // If row 5 is expanded and scrolled partially, keep it rendered\n * for (const expandedRowIndex of this.expandedRowIndices) {\n * const expandedRowTop = expandedRowIndex * rowHeight;\n * const expandedRowBottom = expandedRowTop + rowHeight + this.detailHeight;\n * if (expandedRowBottom > scrollTop && expandedRowIndex < start) {\n * return expandedRowIndex;\n * }\n * }\n * return start;\n * }\n * ```\n */\n adjustVirtualStart?(start: number, scrollTop: number, rowHeight: number): number;\n\n /**\n * Render a custom row, bypassing the default row rendering.\n * Use this for special row types like group headers, detail rows, or footers.\n *\n * @param row - The row data object\n * @param rowEl - The row DOM element to render into\n * @param rowIndex - The index of the row in the data array\n * @returns `true` if the plugin handled rendering (prevents default), `false`/`void` for default rendering\n *\n * @example\n * ```ts\n * renderRow(row: any, rowEl: HTMLElement, rowIndex: number): boolean | void {\n * if (row._isGroupHeader) {\n * rowEl.innerHTML = `<div class=\"group-header\">${row._groupLabel}</div>`;\n * return true; // Handled - skip default rendering\n * }\n * // Return void to let default rendering proceed\n * }\n * ```\n */\n renderRow?(row: any, rowEl: HTMLElement, rowIndex: number): boolean | void;\n\n // #endregion\n\n // #region Inter-Plugin Communication\n\n /**\n * Handle queries from other plugins.\n * This is the generic mechanism for inter-plugin communication.\n * Plugins can respond to well-known query types or define their own.\n *\n * @param query - The query object with type and context\n * @returns Query-specific response, or undefined if not handling this query\n *\n * @example\n * ```ts\n * onPluginQuery(query: PluginQuery): unknown {\n * switch (query.type) {\n * case PLUGIN_QUERIES.CAN_MOVE_COLUMN:\n * // Prevent moving pinned columns\n * const column = query.context as ColumnConfig;\n * if (column.sticky === 'left' || column.sticky === 'right') {\n * return false;\n * }\n * break;\n * case PLUGIN_QUERIES.GET_CONTEXT_MENU_ITEMS:\n * const params = query.context as ContextMenuParams;\n * return [{ id: 'my-action', label: 'My Action', action: () => {} }];\n * }\n * }\n * ```\n */\n onPluginQuery?(query: PluginQuery): unknown;\n\n // #endregion\n\n // #region Interaction Hooks\n\n /**\n * Handle keyboard events on the grid.\n * Called when a key is pressed while the grid or a cell has focus.\n *\n * @param event - The native KeyboardEvent\n * @returns `true` to prevent default behavior and stop propagation, `false`/`void` to allow default\n *\n * @example\n * ```ts\n * onKeyDown(event: KeyboardEvent): boolean | void {\n * // Handle Ctrl+A for select all\n * if (event.ctrlKey && event.key === 'a') {\n * this.selectAllRows();\n * return true; // Prevent default browser select-all\n * }\n * }\n * ```\n */\n onKeyDown?(event: KeyboardEvent): boolean | void;\n\n /**\n * Handle cell click events.\n * Called when a data cell is clicked (not headers).\n *\n * @param event - Cell click event with row/column context\n * @returns `true` to prevent default behavior and stop propagation, `false`/`void` to allow default\n *\n * @example\n * ```ts\n * onCellClick(event: CellClickEvent): boolean | void {\n * if (event.field === '_select') {\n * this.toggleRowSelection(event.rowIndex);\n * return true; // Handled\n * }\n * }\n * ```\n */\n onCellClick?(event: CellClickEvent): boolean | void;\n\n /**\n * Handle row click events.\n * Called when any part of a data row is clicked.\n * Note: This is called in addition to onCellClick, not instead of.\n *\n * @param event - Row click event with row context\n * @returns `true` to prevent default behavior and stop propagation, `false`/`void` to allow default\n *\n * @example\n * ```ts\n * onRowClick(event: RowClickEvent): boolean | void {\n * if (this.config.mode === 'row') {\n * this.selectRow(event.rowIndex, event.originalEvent);\n * return true;\n * }\n * }\n * ```\n */\n onRowClick?(event: RowClickEvent): boolean | void;\n\n /**\n * Handle header click events.\n * Called when a column header is clicked. Commonly used for sorting.\n *\n * @param event - Header click event with column context\n * @returns `true` to prevent default behavior and stop propagation, `false`/`void` to allow default\n *\n * @example\n * ```ts\n * onHeaderClick(event: HeaderClickEvent): boolean | void {\n * if (event.column.sortable !== false) {\n * this.toggleSort(event.field);\n * return true;\n * }\n * }\n * ```\n */\n onHeaderClick?(event: HeaderClickEvent): boolean | void;\n\n /**\n * Handle scroll events on the grid viewport.\n * Called during scrolling. Note: This may be called frequently; debounce if needed.\n *\n * @param event - Scroll event with scroll position and viewport dimensions\n *\n * @example\n * ```ts\n * onScroll(event: ScrollEvent): void {\n * // Update sticky column positions\n * this.updateStickyPositions(event.scrollLeft);\n * }\n * ```\n */\n onScroll?(event: ScrollEvent): void;\n\n /**\n * Handle cell mousedown events.\n * Used for initiating drag operations like range selection or column resize.\n *\n * @param event - Mouse event with cell context\n * @returns `true` to indicate drag started (prevents text selection), `false`/`void` otherwise\n *\n * @example\n * ```ts\n * onCellMouseDown(event: CellMouseEvent): boolean | void {\n * if (event.rowIndex !== undefined && this.config.mode === 'range') {\n * this.startDragSelection(event.rowIndex, event.colIndex);\n * return true; // Prevent text selection\n * }\n * }\n * ```\n */\n onCellMouseDown?(event: CellMouseEvent): boolean | void;\n\n /**\n * Handle cell mousemove events during drag operations.\n * Only called when a drag is in progress (after mousedown returned true).\n *\n * @param event - Mouse event with current cell context\n * @returns `true` to continue handling the drag, `false`/`void` otherwise\n *\n * @example\n * ```ts\n * onCellMouseMove(event: CellMouseEvent): boolean | void {\n * if (this.isDragging && event.rowIndex !== undefined) {\n * this.extendSelection(event.rowIndex, event.colIndex);\n * return true;\n * }\n * }\n * ```\n */\n onCellMouseMove?(event: CellMouseEvent): boolean | void;\n\n /**\n * Handle cell mouseup events to end drag operations.\n *\n * @param event - Mouse event with final cell context\n * @returns `true` if drag was finalized, `false`/`void` otherwise\n *\n * @example\n * ```ts\n * onCellMouseUp(event: CellMouseEvent): boolean | void {\n * if (this.isDragging) {\n * this.finalizeDragSelection();\n * this.isDragging = false;\n * return true;\n * }\n * }\n * ```\n */\n onCellMouseUp?(event: CellMouseEvent): boolean | void;\n\n // Note: Context menu items are now provided via onPluginQuery with PLUGIN_QUERIES.GET_CONTEXT_MENU_ITEMS\n // This keeps the core decoupled from the context-menu plugin specifics.\n\n // #endregion\n\n // #region Column State Hooks\n\n /**\n * Contribute plugin-specific state for a column.\n * Called by the grid when collecting column state for serialization.\n * Plugins can add their own properties to the column state.\n *\n * @param field - The field name of the column\n * @returns Partial column state with plugin-specific properties, or undefined if no state to contribute\n *\n * @example\n * ```ts\n * getColumnState(field: string): Partial<ColumnState> | undefined {\n * const filterModel = this.filterModels.get(field);\n * if (filterModel) {\n * // Uses module augmentation to add filter property to ColumnState\n * return { filter: filterModel } as Partial<ColumnState>;\n * }\n * return undefined;\n * }\n * ```\n */\n getColumnState?(field: string): Partial<ColumnState> | undefined;\n\n /**\n * Apply plugin-specific state to a column.\n * Called by the grid when restoring column state from serialized data.\n * Plugins should restore their internal state based on the provided state.\n *\n * @param field - The field name of the column\n * @param state - The column state to apply (may contain plugin-specific properties)\n *\n * @example\n * ```ts\n * applyColumnState(field: string, state: ColumnState): void {\n * // Check for filter property added via module augmentation\n * const filter = (state as any).filter;\n * if (filter) {\n * this.filterModels.set(field, filter);\n * this.applyFilter();\n * }\n * }\n * ```\n */\n applyColumnState?(field: string, state: ColumnState): void;\n\n // #endregion\n\n // #region Scroll Boundary Hooks\n\n /**\n * Report horizontal scroll boundary offsets for this plugin.\n * Plugins that obscure part of the scroll area (e.g., pinned/sticky columns)\n * should return how much space they occupy on each side.\n * The keyboard navigation uses this to ensure focused cells are fully visible.\n *\n * @param rowEl - The row element (optional, for calculating widths from rendered cells)\n * @param focusedCell - The currently focused cell element (optional, to determine if scrolling should be skipped)\n * @returns Object with left/right pixel offsets and optional skipScroll flag, or undefined if plugin has no offsets\n *\n * @example\n * ```ts\n * getHorizontalScrollOffsets(rowEl?: HTMLElement, focusedCell?: HTMLElement): { left: number; right: number; skipScroll?: boolean } | undefined {\n * // Calculate total width of left-pinned columns\n * const leftCells = rowEl?.querySelectorAll('.sticky-left') ?? [];\n * let left = 0;\n * leftCells.forEach(el => { left += (el as HTMLElement).offsetWidth; });\n * // Skip scroll if focused cell is pinned (always visible)\n * const skipScroll = focusedCell?.classList.contains('sticky-left');\n * return { left, right: 0, skipScroll };\n * }\n * ```\n */\n getHorizontalScrollOffsets?(\n rowEl?: HTMLElement,\n focusedCell?: HTMLElement,\n ): { left: number; right: number; skipScroll?: boolean } | undefined;\n\n // #endregion\n\n // #region Shell Integration Hooks\n\n /**\n * Register a tool panel for this plugin.\n * Return undefined if plugin has no tool panel.\n * The shell will create a toolbar toggle button and render the panel content\n * when the user opens the panel.\n *\n * @returns Tool panel definition, or undefined if plugin has no panel\n *\n * @example\n * ```ts\n * getToolPanel(): ToolPanelDefinition | undefined {\n * return {\n * id: 'columns',\n * title: 'Columns',\n * icon: '☰',\n * tooltip: 'Show/hide columns',\n * order: 10,\n * render: (container) => {\n * this.renderColumnList(container);\n * return () => this.cleanup();\n * },\n * };\n * }\n * ```\n */\n getToolPanel?(): ToolPanelDefinition | undefined;\n\n /**\n * Register content for the shell header center section.\n * Return undefined if plugin has no header content.\n * Examples: search input, selection summary, status indicators.\n *\n * @returns Header content definition, or undefined if plugin has no header content\n *\n * @example\n * ```ts\n * getHeaderContent(): HeaderContentDefinition | undefined {\n * return {\n * id: 'quick-filter',\n * order: 10,\n * render: (container) => {\n * const input = document.createElement('input');\n * input.type = 'text';\n * input.placeholder = 'Search...';\n * input.addEventListener('input', this.handleInput);\n * container.appendChild(input);\n * return () => input.removeEventListener('input', this.handleInput);\n * },\n * };\n * }\n * ```\n */\n getHeaderContent?(): HeaderContentDefinition | undefined;\n\n // #endregion\n}\n","/**\n * Aggregators Core Registry\n *\n * Provides a central registry for aggregator functions.\n * Built-in aggregators are provided by default.\n * Plugins can register additional aggregators.\n *\n * The registry is exposed as a singleton object that can be accessed:\n * - By ES module imports: import { aggregatorRegistry } from '@toolbox-web/grid'\n * - By UMD/CDN: TbwGrid.aggregatorRegistry\n * - By plugins via context: ctx.aggregatorRegistry\n */\n\n/* eslint-disable @typescript-eslint/no-explicit-any */\n\nexport type AggregatorFn = (rows: any[], field: string, column?: any) => any;\nexport type AggregatorRef = string | AggregatorFn;\n\n/** Built-in aggregator functions */\nconst builtInAggregators: Record<string, AggregatorFn> = {\n sum: (rows, field) => rows.reduce((acc, row) => acc + (Number(row[field]) || 0), 0),\n avg: (rows, field) => {\n const sum = rows.reduce((acc, row) => acc + (Number(row[field]) || 0), 0);\n return rows.length ? sum / rows.length : 0;\n },\n count: (rows) => rows.length,\n min: (rows, field) => Math.min(...rows.map((r) => Number(r[field]) || Infinity)),\n max: (rows, field) => Math.max(...rows.map((r) => Number(r[field]) || -Infinity)),\n first: (rows, field) => rows[0]?.[field],\n last: (rows, field) => rows[rows.length - 1]?.[field],\n};\n\n/** Custom aggregator registry (for plugins to add to) */\nconst customAggregators: Map<string, AggregatorFn> = new Map();\n\n/**\n * The aggregator registry singleton.\n * Plugins should access this through context or the global namespace.\n */\nexport const aggregatorRegistry = {\n /**\n * Register a custom aggregator function.\n */\n register(name: string, fn: AggregatorFn): void {\n customAggregators.set(name, fn);\n },\n\n /**\n * Unregister a custom aggregator function.\n */\n unregister(name: string): void {\n customAggregators.delete(name);\n },\n\n /**\n * Get an aggregator function by reference.\n */\n get(ref: AggregatorRef | undefined): AggregatorFn | undefined {\n if (ref === undefined) return undefined;\n if (typeof ref === 'function') return ref;\n // Check custom first, then built-in\n return customAggregators.get(ref) ?? builtInAggregators[ref];\n },\n\n /**\n * Run an aggregator on a set of rows.\n */\n run(ref: AggregatorRef | undefined, rows: any[], field: string, column?: any): any {\n const fn = this.get(ref);\n return fn ? fn(rows, field, column) : undefined;\n },\n\n /**\n * Check if an aggregator exists.\n */\n has(name: string): boolean {\n return customAggregators.has(name) || name in builtInAggregators;\n },\n\n /**\n * List all available aggregator names.\n */\n list(): string[] {\n return [...Object.keys(builtInAggregators), ...customAggregators.keys()];\n },\n};\n\n// #region Value-based Aggregators\n// Used by plugins like Pivot that work with pre-extracted numeric values\n\nexport type ValueAggregatorFn = (values: number[]) => number;\n\n/**\n * Built-in value-based aggregators.\n * These operate on arrays of numbers (unlike row-based aggregators).\n */\nconst builtInValueAggregators: Record<string, ValueAggregatorFn> = {\n sum: (vals) => vals.reduce((a, b) => a + b, 0),\n avg: (vals) => (vals.length ? vals.reduce((a, b) => a + b, 0) / vals.length : 0),\n count: (vals) => vals.length,\n min: (vals) => (vals.length ? Math.min(...vals) : 0),\n max: (vals) => (vals.length ? Math.max(...vals) : 0),\n first: (vals) => vals[0] ?? 0,\n last: (vals) => vals[vals.length - 1] ?? 0,\n};\n\n/**\n * Get a value-based aggregator function.\n * Used by Pivot plugin and other features that aggregate pre-extracted values.\n *\n * @param aggFunc - Aggregation function name ('sum', 'avg', 'count', 'min', 'max', 'first', 'last')\n * @returns Aggregator function that takes number[] and returns number\n */\nexport function getValueAggregator(aggFunc: string): ValueAggregatorFn {\n return builtInValueAggregators[aggFunc] ?? builtInValueAggregators.sum;\n}\n\n/**\n * Run a value-based aggregator on a set of values.\n *\n * @param aggFunc - Aggregation function name\n * @param values - Array of numbers to aggregate\n * @returns Aggregated result\n */\nexport function runValueAggregator(aggFunc: string, values: number[]): number {\n return getValueAggregator(aggFunc)(values);\n}\n// #endregion\n\n// Legacy function exports for backward compatibility\nexport const registerAggregator = aggregatorRegistry.register.bind(aggregatorRegistry);\nexport const unregisterAggregator = aggregatorRegistry.unregister.bind(aggregatorRegistry);\nexport const getAggregator = aggregatorRegistry.get.bind(aggregatorRegistry);\nexport const runAggregator = aggregatorRegistry.run.bind(aggregatorRegistry);\nexport const listAggregators = aggregatorRegistry.list.bind(aggregatorRegistry);\n","import { getValueAggregator } from '../../core/internal/aggregators';\nimport type { PivotConfig } from './types';\n\n// Re-export for backward compatibility within pivot plugin\nexport const getPivotAggregator = getValueAggregator;\n\nexport function validatePivotConfig(config: PivotConfig): string[] {\n const errors: string[] = [];\n\n if (!config.rowGroupFields?.length && !config.columnGroupFields?.length) {\n errors.push('At least one row or column group field is required');\n }\n\n if (!config.valueFields?.length) {\n errors.push('At least one value field is required');\n }\n\n return errors;\n}\n\nexport function createValueKey(columnValues: string[], valueField: string): string {\n return [...columnValues, valueField].join('|');\n}\n","import { createValueKey, getPivotAggregator } from './pivot-model';\nimport type { PivotConfig, PivotResult, PivotRow, PivotValueField } from './types';\n\nexport type PivotDataRow = Record<string, unknown>;\n\n/**\n * Build a hierarchical pivot result from flat data.\n * Supports multiple row group fields for nested hierarchy.\n */\nexport function buildPivot(rows: PivotDataRow[], config: PivotConfig): PivotResult {\n const rowGroupFields = config.rowGroupFields ?? [];\n const columnGroupFields = config.columnGroupFields ?? [];\n const valueFields = config.valueFields ?? [];\n\n // Get unique column combinations\n const columnKeys = getUniqueColumnKeys(rows, columnGroupFields);\n\n // Build hierarchical pivot rows\n const pivotRows = buildHierarchicalPivotRows(\n rows,\n rowGroupFields,\n columnGroupFields,\n columnKeys,\n valueFields,\n 0, // starting depth\n '', // parent key prefix\n );\n\n // Calculate grand totals\n const totals = calculateTotals(pivotRows, columnKeys, valueFields);\n const grandTotal = Object.values(totals).reduce((a, b) => a + b, 0);\n\n return {\n rows: pivotRows,\n columnKeys,\n totals,\n grandTotal,\n };\n}\n\n/**\n * Get unique column key combinations from the data.\n */\nexport function getUniqueColumnKeys(rows: PivotDataRow[], columnFields: string[]): string[] {\n if (columnFields.length === 0) return ['value'];\n\n const keys = new Set<string>();\n for (const row of rows) {\n const key = columnFields.map((f) => String(row[f] ?? '')).join('|');\n keys.add(key);\n }\n return [...keys].sort();\n}\n\n/**\n * Group rows by a single field.\n */\nexport function groupByField(rows: PivotDataRow[], field: string): Map<string, PivotDataRow[]> {\n const groups = new Map<string, PivotDataRow[]>();\n\n for (const row of rows) {\n const key = String(row[field] ?? '');\n const existing = groups.get(key);\n if (existing) {\n existing.push(row);\n } else {\n groups.set(key, [row]);\n }\n }\n\n return groups;\n}\n\n/**\n * Group rows by multiple fields (legacy flat grouping).\n */\nexport function groupByFields(rows: PivotDataRow[], fields: string[]): Map<string, PivotDataRow[]> {\n const groups = new Map<string, PivotDataRow[]>();\n\n for (const row of rows) {\n const key = fields.map((f) => String(row[f] ?? '')).join('|');\n const existing = groups.get(key);\n if (existing) {\n existing.push(row);\n } else {\n groups.set(key, [row]);\n }\n }\n\n return groups;\n}\n\n/**\n * Build hierarchical pivot rows recursively.\n * Each level of rowGroupFields creates a new depth level.\n */\nexport function buildHierarchicalPivotRows(\n rows: PivotDataRow[],\n rowGroupFields: string[],\n columnFields: string[],\n columnKeys: string[],\n valueFields: PivotValueField[],\n depth: number,\n parentKey: string,\n): PivotRow[] {\n const result: PivotRow[] = [];\n\n // If no more row group fields, we're at the leaf level - aggregate the data\n if (rowGroupFields.length === 0) {\n // This shouldn't normally happen as we need at least one grouping field\n // But handle it by creating a single aggregated row\n const values = aggregateValues(rows, columnFields, columnKeys, valueFields);\n const total = calculateRowTotal(values);\n result.push({\n rowKey: parentKey || 'all',\n rowLabel: parentKey || 'All',\n depth,\n values,\n total,\n isGroup: false,\n rowCount: rows.length,\n });\n return result;\n }\n\n // Get the current grouping field\n const currentField = rowGroupFields[0];\n const remainingFields = rowGroupFields.slice(1);\n const hasChildren = remainingFields.length > 0;\n\n // Group rows by current field\n const grouped = groupByField(rows, currentField);\n\n for (const [groupValue, groupRows] of grouped) {\n const rowKey = parentKey ? `${parentKey}|${groupValue}` : groupValue;\n\n // Aggregate values for this group (sum of all child rows)\n const values = aggregateValues(groupRows, columnFields, columnKeys, valueFields);\n const total = calculateRowTotal(values);\n\n // Build children if there are more grouping levels\n let children: PivotRow[] | undefined;\n if (hasChildren) {\n children = buildHierarchicalPivotRows(\n groupRows,\n remainingFields,\n columnFields,\n columnKeys,\n valueFields,\n depth + 1,\n rowKey,\n );\n }\n\n result.push({\n rowKey,\n rowLabel: groupValue || '(blank)',\n depth,\n values,\n total,\n isGroup: hasChildren,\n children,\n rowCount: groupRows.length,\n });\n }\n\n return result;\n}\n\n/**\n * Aggregate values for a set of rows across all column keys.\n */\nexport function aggregateValues(\n rows: PivotDataRow[],\n columnFields: string[],\n columnKeys: string[],\n valueFields: PivotValueField[],\n): Record<string, number | null> {\n const values: Record<string, number | null> = {};\n\n for (const colKey of columnKeys) {\n for (const vf of valueFields) {\n // Filter rows that match this column key\n const matchingRows =\n columnFields.length > 0\n ? rows.filter((r) => columnFields.map((f) => String(r[f] ?? '')).join('|') === colKey)\n : rows;\n\n const nums = matchingRows.map((r) => Number(r[vf.field]) || 0);\n const aggregator = getPivotAggregator(vf.aggFunc);\n const aggregatedResult = nums.length > 0 ? aggregator(nums) : null;\n\n const valueKey = createValueKey([colKey], vf.field);\n values[valueKey] = aggregatedResult;\n }\n }\n\n return values;\n}\n\n/**\n * Calculate the total for a row's values.\n */\nexport function calculateRowTotal(values: Record<string, number | null>): number {\n let sum = 0;\n for (const val of Object.values(values)) {\n sum += val ?? 0;\n }\n return sum;\n}\n\n/**\n * Legacy flat pivot row building (for backwards compatibility).\n */\nexport function buildPivotRows(\n groupedData: Map<string, PivotDataRow[]>,\n columnFields: string[],\n columnKeys: string[],\n valueFields: PivotValueField[],\n depth: number,\n): PivotRow[] {\n const result: PivotRow[] = [];\n\n for (const [rowKey, groupRows] of groupedData) {\n const values = aggregateValues(groupRows, columnFields, columnKeys, valueFields);\n const total = calculateRowTotal(values);\n\n result.push({\n rowKey,\n rowLabel: rowKey || '(blank)',\n depth,\n values,\n total,\n isGroup: false,\n rowCount: groupRows.length,\n });\n }\n\n return result;\n}\n\n/**\n * Calculate grand totals across all pivot rows.\n */\nexport function calculateTotals(\n pivotRows: PivotRow[],\n columnKeys: string[],\n valueFields: PivotValueField[],\n): Record<string, number> {\n const totals: Record<string, number> = {};\n\n // Recursively sum all rows (including nested children)\n function sumRows(rows: PivotRow[]) {\n for (const row of rows) {\n // Only count leaf rows to avoid double-counting\n if (!row.isGroup || !row.children?.length) {\n for (const colKey of columnKeys) {\n for (const vf of valueFields) {\n const valueKey = createValueKey([colKey], vf.field);\n totals[valueKey] = (totals[valueKey] ?? 0) + (row.values[valueKey] ?? 0);\n }\n }\n } else if (row.children) {\n sumRows(row.children);\n }\n }\n }\n\n sumRows(pivotRows);\n return totals;\n}\n\n/**\n * Flatten hierarchical pivot rows for rendering.\n * Respects expanded state - only includes children of expanded groups.\n */\nexport function flattenPivotRows(rows: PivotRow[], expandedKeys?: Set<string>, defaultExpanded = true): PivotRow[] {\n const result: PivotRow[] = [];\n\n function flatten(row: PivotRow) {\n result.push(row);\n\n // Check if this group is expanded\n const isExpanded = expandedKeys ? expandedKeys.has(row.rowKey) : defaultExpanded;\n\n // Only include children if expanded\n if (row.children && isExpanded) {\n for (const child of row.children) {\n flatten(child);\n }\n }\n }\n\n for (const row of rows) {\n flatten(row);\n }\n\n return result;\n}\n\n/**\n * Get all group keys from pivot rows (for expand all / collapse all).\n */\nexport function getAllGroupKeys(rows: PivotRow[]): string[] {\n const keys: string[] = [];\n\n function collectKeys(row: PivotRow) {\n if (row.isGroup) {\n keys.push(row.rowKey);\n }\n if (row.children) {\n for (const child of row.children) {\n collectKeys(child);\n }\n }\n }\n\n for (const row of rows) {\n collectKeys(row);\n }\n\n return keys;\n}\n","/**\n * Pivot Tool Panel Rendering\n *\n * Pure functions for rendering the pivot configuration panel.\n * Separated from PivotPlugin for better code organization.\n */\n\nimport type { AggFunc, PivotConfig, PivotValueField } from './types';\n\n/** All available aggregation functions */\nexport const AGG_FUNCS: AggFunc[] = ['sum', 'avg', 'count', 'min', 'max', 'first', 'last'];\n\n/** Field info for available fields */\nexport interface FieldInfo {\n field: string;\n header: string;\n}\n\n/** Callbacks for panel interactions */\nexport interface PanelCallbacks {\n onTogglePivot: (enabled: boolean) => void;\n onAddFieldToZone: (field: string, zone: 'rowGroups' | 'columnGroups') => void;\n onRemoveFieldFromZone: (field: string, zone: 'rowGroups' | 'columnGroups') => void;\n onAddValueField: (field: string, aggFunc: AggFunc) => void;\n onRemoveValueField: (field: string) => void;\n onUpdateValueAggFunc: (field: string, aggFunc: AggFunc) => void;\n onOptionChange: (option: 'showTotals' | 'showGrandTotal', value: boolean) => void;\n getAvailableFields: () => FieldInfo[];\n}\n\n/** Internal context passed to rendering functions */\ninterface RenderContext {\n config: PivotConfig;\n callbacks: PanelCallbacks;\n signal: AbortSignal;\n}\n\n/**\n * Render the complete pivot panel content.\n * Returns a cleanup function that removes all event listeners and DOM elements.\n */\nexport function renderPivotPanel(\n container: HTMLElement,\n config: PivotConfig,\n isActive: boolean,\n callbacks: PanelCallbacks,\n): () => void {\n // Create AbortController for automatic listener cleanup\n const controller = new AbortController();\n const ctx: RenderContext = { config, callbacks, signal: controller.signal };\n\n const wrapper = document.createElement('div');\n wrapper.className = 'tbw-pivot-panel';\n\n // Options section (at top, includes pivot toggle)\n wrapper.appendChild(createSection('Options', () => createOptionsPanel(isActive, ctx)));\n\n // Row Groups section\n wrapper.appendChild(createSection('Row Groups', () => createFieldZone('rowGroups', ctx)));\n\n // Column Groups section\n wrapper.appendChild(createSection('Column Groups', () => createFieldZone('columnGroups', ctx)));\n\n // Values section\n wrapper.appendChild(createSection('Values', () => createValuesZone(ctx)));\n\n // Available fields section\n wrapper.appendChild(createSection('Available Fields', () => createAvailableFieldsZone(ctx)));\n\n container.appendChild(wrapper);\n\n // Cleanup: abort all listeners, then remove DOM\n return () => {\n controller.abort();\n wrapper.remove();\n };\n}\n\n/**\n * Create a collapsible section wrapper.\n */\nfunction createSection(title: string, contentFactory: () => HTMLElement): HTMLElement {\n const section = document.createElement('div');\n section.className = 'tbw-pivot-section';\n\n const header = document.createElement('div');\n header.className = 'tbw-pivot-section-header';\n header.textContent = title;\n\n const content = document.createElement('div');\n content.className = 'tbw-pivot-section-content';\n content.appendChild(contentFactory());\n\n section.appendChild(header);\n section.appendChild(content);\n\n return section;\n}\n\n/**\n * Create a drop zone for row/column group fields.\n */\nfunction createFieldZone(zoneType: 'rowGroups' | 'columnGroups', ctx: RenderContext): HTMLElement {\n const { config, callbacks, signal } = ctx;\n const zone = document.createElement('div');\n zone.className = 'tbw-pivot-drop-zone';\n zone.setAttribute('data-zone', zoneType);\n\n const currentFields = zoneType === 'rowGroups' ? (config.rowGroupFields ?? []) : (config.columnGroupFields ?? []);\n\n if (currentFields.length === 0) {\n const placeholder = document.createElement('div');\n placeholder.className = 'tbw-pivot-placeholder';\n placeholder.textContent = 'Drag fields here or click to add';\n zone.appendChild(placeholder);\n } else {\n for (const field of currentFields) {\n zone.appendChild(createFieldChip(field, zoneType, ctx));\n }\n }\n\n // Drop handling\n zone.addEventListener(\n 'dragover',\n (e) => {\n e.preventDefault();\n zone.classList.add('drag-over');\n },\n { signal },\n );\n\n zone.addEventListener(\n 'dragleave',\n () => {\n zone.classList.remove('drag-over');\n },\n { signal },\n );\n\n zone.addEventListener(\n 'drop',\n (e) => {\n e.preventDefault();\n zone.classList.remove('drag-over');\n\n const field = e.dataTransfer?.getData('text/plain');\n if (field) {\n callbacks.onAddFieldToZone(field, zoneType);\n }\n },\n { signal },\n );\n\n return zone;\n}\n\n/**\n * Create a field chip for row/column zones.\n */\nfunction createFieldChip(field: string, zoneType: 'rowGroups' | 'columnGroups', ctx: RenderContext): HTMLElement {\n const { callbacks, signal } = ctx;\n const chip = document.createElement('div');\n chip.className = 'tbw-pivot-field-chip';\n chip.draggable = true;\n\n const fieldInfo = callbacks.getAvailableFields().find((f) => f.field === field);\n const label = document.createElement('span');\n label.className = 'tbw-pivot-chip-label';\n label.textContent = fieldInfo?.header ?? field;\n\n const removeBtn = document.createElement('button');\n removeBtn.className = 'tbw-pivot-chip-remove';\n removeBtn.innerHTML = '×';\n removeBtn.title = 'Remove field';\n removeBtn.addEventListener(\n 'click',\n (e) => {\n e.stopPropagation();\n callbacks.onRemoveFieldFromZone(field, zoneType);\n },\n { signal },\n );\n\n chip.appendChild(label);\n chip.appendChild(removeBtn);\n\n // Drag handling for reordering\n chip.addEventListener(\n 'dragstart',\n (e) => {\n e.dataTransfer?.setData('text/plain', field);\n e.dataTransfer?.setData('source-zone', zoneType);\n chip.classList.add('dragging');\n },\n { signal },\n );\n\n chip.addEventListener(\n 'dragend',\n () => {\n chip.classList.remove('dragging');\n },\n { signal },\n );\n\n return chip;\n}\n\n/**\n * Create the values zone with aggregation controls.\n */\nfunction createValuesZone(ctx: RenderContext): HTMLElement {\n const { config, callbacks, signal } = ctx;\n const zone = document.createElement('div');\n zone.className = 'tbw-pivot-drop-zone tbw-pivot-values-zone';\n zone.setAttribute('data-zone', 'values');\n\n const currentValues = config.valueFields ?? [];\n\n if (currentValues.length === 0) {\n const placeholder = document.createElement('div');\n placeholder.className = 'tbw-pivot-placeholder';\n placeholder.textContent = 'Drag numeric fields here for aggregation';\n zone.appendChild(placeholder);\n } else {\n for (const valueField of currentValues) {\n zone.appendChild(createValueChip(valueField, ctx));\n }\n }\n\n // Drop handling with signal for cleanup\n zone.addEventListener(\n 'dragover',\n (e) => {\n e.preventDefault();\n zone.classList.add('drag-over');\n },\n { signal },\n );\n\n zone.addEventListener(\n 'dragleave',\n () => {\n zone.classList.remove('drag-over');\n },\n { signal },\n );\n\n zone.addEventListener(\n 'drop',\n (e) => {\n e.preventDefault();\n zone.classList.remove('drag-over');\n const field = e.dataTransfer?.getData('text/plain');\n if (field) {\n callbacks.onAddValueField(field, 'sum');\n }\n },\n { signal },\n );\n\n return zone;\n}\n\n/**\n * Create a value chip with aggregation selector.\n */\nfunction createValueChip(valueField: PivotValueField, ctx: RenderContext): HTMLElement {\n const { callbacks, signal } = ctx;\n const chip = document.createElement('div');\n chip.className = 'tbw-pivot-field-chip tbw-pivot-value-chip';\n\n const fieldInfo = callbacks.getAvailableFields().find((f) => f.field === valueField.field);\n\n const labelWrapper = document.createElement('div');\n labelWrapper.className = 'tbw-pivot-value-label-wrapper';\n\n const label = document.createElement('span');\n label.className = 'tbw-pivot-chip-label';\n label.textContent = fieldInfo?.header ?? valueField.field;\n\n const aggSelect = document.createElement('select');\n aggSelect.className = 'tbw-pivot-agg-select';\n aggSelect.title = 'Aggregation function';\n\n for (const aggFunc of AGG_FUNCS) {\n const option = document.createElement('option');\n option.value = aggFunc;\n option.textContent = aggFunc.toUpperCase();\n option.selected = aggFunc === valueField.aggFunc;\n aggSelect.appendChild(option);\n }\n\n aggSelect.addEventListener(\n 'change',\n () => {\n callbacks.onUpdateValueAggFunc(valueField.field, aggSelect.value as AggFunc);\n },\n { signal },\n );\n\n const removeBtn = document.createElement('button');\n removeBtn.className = 'tbw-pivot-chip-remove';\n removeBtn.innerHTML = '×';\n removeBtn.title = 'Remove value field';\n removeBtn.addEventListener(\n 'click',\n (e) => {\n e.stopPropagation();\n callbacks.onRemoveValueField(valueField.field);\n },\n { signal },\n );\n\n labelWrapper.appendChild(label);\n labelWrapper.appendChild(aggSelect);\n\n chip.appendChild(labelWrapper);\n chip.appendChild(removeBtn);\n\n return chip;\n}\n\n/**\n * Create the available fields zone.\n */\nfunction createAvailableFieldsZone(ctx: RenderContext): HTMLElement {\n const { config, callbacks, signal } = ctx;\n const zone = document.createElement('div');\n zone.className = 'tbw-pivot-available-fields';\n\n const allFields = callbacks.getAvailableFields();\n const usedFields = new Set([\n ...(config.rowGroupFields ?? []),\n ...(config.columnGroupFields ?? []),\n ...(config.valueFields?.map((v) => v.field) ?? []),\n ]);\n\n // Filter to show only unused fields\n const availableFields = allFields.filter((f) => !usedFields.has(f.field));\n\n if (availableFields.length === 0) {\n const empty = document.createElement('div');\n empty.className = 'tbw-pivot-placeholder';\n empty.textContent = 'All fields are in use';\n zone.appendChild(empty);\n } else {\n for (const field of availableFields) {\n const chip = document.createElement('div');\n chip.className = 'tbw-pivot-field-chip available';\n chip.textContent = field.header;\n chip.draggable = true;\n chip.title = `Drag to add \"${field.field}\" to a zone`;\n\n chip.addEventListener(\n 'dragstart',\n (e) => {\n e.dataTransfer?.setData('text/plain', field.field);\n chip.classList.add('dragging');\n },\n { signal },\n );\n\n chip.addEventListener(\n 'dragend',\n () => {\n chip.classList.remove('dragging');\n },\n { signal },\n );\n\n zone.appendChild(chip);\n }\n }\n\n return zone;\n}\n\n/**\n * Create the options panel with pivot toggle and checkboxes for totals.\n */\nfunction createOptionsPanel(isActive: boolean, ctx: RenderContext): HTMLElement {\n const { config, callbacks, signal } = ctx;\n const panel = document.createElement('div');\n panel.className = 'tbw-pivot-options';\n\n // Pivot Mode toggle\n panel.appendChild(\n createCheckbox(\n 'Enable Pivot View',\n isActive,\n (checked) => {\n callbacks.onTogglePivot(checked);\n },\n signal,\n ),\n );\n\n // Show Totals checkbox\n panel.appendChild(\n createCheckbox(\n 'Show Row Totals',\n config.showTotals ?? true,\n (checked) => {\n callbacks.onOptionChange('showTotals', checked);\n },\n signal,\n ),\n );\n\n // Show Grand Total checkbox\n panel.appendChild(\n createCheckbox(\n 'Show Grand Total',\n config.showGrandTotal ?? true,\n (checked) => {\n callbacks.onOptionChange('showGrandTotal', checked);\n },\n signal,\n ),\n );\n\n return panel;\n}\n\n/**\n * Create a checkbox with label.\n */\nfunction createCheckbox(\n label: string,\n checked: boolean,\n onChange: (checked: boolean) => void,\n signal: AbortSignal,\n): HTMLElement {\n const wrapper = document.createElement('label');\n wrapper.className = 'tbw-pivot-checkbox';\n\n const input = document.createElement('input');\n input.type = 'checkbox';\n input.checked = checked;\n input.addEventListener('change', () => onChange(input.checked), { signal });\n\n const span = document.createElement('span');\n span.textContent = label;\n\n wrapper.appendChild(input);\n wrapper.appendChild(span);\n\n return wrapper;\n}\n","/**\n * Pivot Row Rendering\n *\n * Pure functions for rendering pivot rows (group rows, leaf rows, grand total).\n * Separated from PivotPlugin for better code organization.\n */\n\nimport type { ColumnConfig, IconValue } from '../../core/types';\n\n/** Row data with pivot metadata */\nexport interface PivotRowData {\n __pivotRowKey?: string;\n __pivotLabel?: string;\n __pivotDepth?: number;\n __pivotIndent?: number;\n __pivotExpanded?: boolean;\n __pivotHasChildren?: boolean;\n __pivotRowCount?: number;\n __pivotIsGrandTotal?: boolean;\n [key: string]: unknown;\n}\n\n/** Context for row rendering */\nexport interface RowRenderContext {\n columns: ColumnConfig[];\n onToggle: (key: string) => void;\n resolveIcon: (iconKey: 'expand' | 'collapse') => IconValue;\n setIcon: (element: HTMLElement, icon: IconValue) => void;\n}\n\n/**\n * Render a pivot group row (has children, can expand/collapse).\n */\nexport function renderPivotGroupRow(row: PivotRowData, rowEl: HTMLElement, ctx: RowRenderContext): boolean {\n rowEl.className = 'pivot-group-row';\n rowEl.setAttribute('data-pivot-depth', String(row.__pivotDepth ?? 0));\n rowEl.setAttribute('data-pivot-key', String(row.__pivotRowKey ?? ''));\n rowEl.setAttribute('role', 'row');\n // Note: aria-expanded is not set here because it's only valid in treegrid, not grid\n // The expand/collapse state is conveyed via the toggle button's aria-label\n rowEl.innerHTML = '';\n\n ctx.columns.forEach((col, colIdx) => {\n const cell = document.createElement('div');\n cell.className = 'cell';\n cell.setAttribute('data-col', String(colIdx));\n cell.setAttribute('role', 'gridcell');\n\n if (colIdx === 0) {\n // First column: indent + toggle + label + count\n const indent = Number(row.__pivotIndent) || 0;\n cell.style.paddingLeft = `${indent}px`;\n\n // Toggle button\n const rowKey = String(row.__pivotRowKey);\n const btn = document.createElement('button');\n btn.type = 'button';\n btn.className = 'pivot-toggle';\n btn.setAttribute('aria-label', row.__pivotExpanded ? 'Collapse group' : 'Expand group');\n ctx.setIcon(btn, ctx.resolveIcon(row.__pivotExpanded ? 'collapse' : 'expand'));\n btn.addEventListener('click', (e) => {\n e.stopPropagation();\n ctx.onToggle(rowKey);\n });\n cell.appendChild(btn);\n\n // Group label\n const label = document.createElement('span');\n label.className = 'pivot-label';\n label.textContent = String(row.__pivotLabel ?? '');\n cell.appendChild(label);\n\n // Row count\n const count = document.createElement('span');\n count.className = 'pivot-count';\n count.textContent = ` (${Number(row.__pivotRowCount) || 0})`;\n cell.appendChild(count);\n } else {\n // Other columns: render value\n const value = row[col.field];\n cell.textContent = value != null ? String(value) : '';\n }\n\n rowEl.appendChild(cell);\n });\n\n return true;\n}\n\n/**\n * Render a pivot leaf row (no children, just indentation).\n */\nexport function renderPivotLeafRow(row: PivotRowData, rowEl: HTMLElement, columns: ColumnConfig[]): boolean {\n rowEl.className = 'pivot-leaf-row';\n rowEl.setAttribute('data-pivot-depth', String(row.__pivotDepth ?? 0));\n rowEl.setAttribute('data-pivot-key', String(row.__pivotRowKey ?? ''));\n rowEl.innerHTML = '';\n\n columns.forEach((col, colIdx) => {\n const cell = document.createElement('div');\n cell.className = 'cell';\n cell.setAttribute('data-col', String(colIdx));\n cell.setAttribute('role', 'gridcell');\n\n if (colIdx === 0) {\n // First column: indent + label (no toggle for leaves)\n const indent = Number(row.__pivotIndent) || 0;\n // Add extra indent for alignment with toggle button\n cell.style.paddingLeft = `${indent + 20}px`;\n\n const label = document.createElement('span');\n label.className = 'pivot-label';\n label.textContent = String(row.__pivotLabel ?? '');\n cell.appendChild(label);\n } else {\n // Other columns: render value\n const value = row[col.field];\n cell.textContent = value != null ? String(value) : '';\n }\n\n rowEl.appendChild(cell);\n });\n\n return true;\n}\n\n/**\n * Render the grand total row.\n */\nexport function renderPivotGrandTotalRow(row: PivotRowData, rowEl: HTMLElement, columns: ColumnConfig[]): boolean {\n rowEl.className = 'pivot-grand-total-row';\n // Use role=presentation since grand total is rendered outside the role=grid element\n rowEl.setAttribute('role', 'presentation');\n rowEl.innerHTML = '';\n\n columns.forEach((col, colIdx) => {\n const cell = document.createElement('div');\n cell.className = 'cell';\n cell.setAttribute('data-col', String(colIdx));\n // No role attribute - parent row has role=presentation so children don't need grid semantics\n\n if (colIdx === 0) {\n // First column: Grand Total label\n const label = document.createElement('span');\n label.className = 'pivot-label';\n label.textContent = 'Grand Total';\n cell.appendChild(label);\n } else {\n // Other columns: render totals\n const value = row[col.field];\n cell.textContent = value != null ? String(value) : '';\n }\n\n rowEl.appendChild(cell);\n });\n\n return true;\n}\n","/**\n * Pivot Plugin (Class-based)\n *\n * Provides pivot table functionality for tbw-grid.\n * Transforms flat data into grouped, aggregated pivot views.\n * Includes a tool panel for interactive pivot configuration.\n */\n\nimport { BaseGridPlugin } from '../../core/plugin/base-plugin';\nimport type { ColumnConfig, GridConfig, ToolPanelDefinition } from '../../core/types';\nimport { buildPivot, flattenPivotRows, getAllGroupKeys, type PivotDataRow } from './pivot-engine';\nimport { createValueKey, validatePivotConfig } from './pivot-model';\nimport { renderPivotPanel, type FieldInfo, type PanelCallbacks } from './pivot-panel';\nimport { renderPivotGrandTotalRow, renderPivotGroupRow, renderPivotLeafRow, type PivotRowData } from './pivot-rows';\nimport type { AggFunc, ExpandCollapseAnimation, PivotConfig, PivotResult, PivotValueField } from './types';\n\n// Import CSS as inline string (Vite handles this)\nimport styles from './pivot.css?inline';\n\n/** Extended grid interface with column access */\ninterface GridWithColumns {\n shadowRoot: ShadowRoot | null;\n effectiveConfig?: GridConfig;\n getAllColumns(): Array<{ field: string; header: string; visible: boolean }>;\n columns: unknown[];\n rows: unknown[];\n requestRender(): void;\n openToolPanel(id: string): void;\n closeToolPanel(): void;\n toggleToolPanel(id: string): void;\n activeToolPanel: string | undefined;\n}\n\n/**\n * Pivot Plugin for tbw-grid\n *\n * @example\n * ```ts\n * new PivotPlugin({\n * rowGroupFields: ['category'],\n * columnGroupFields: ['region'],\n * valueFields: [{ field: 'sales', aggFunc: 'sum' }]\n * })\n * ```\n */\nexport class PivotPlugin extends BaseGridPlugin<PivotConfig> {\n readonly name = 'pivot';\n override readonly version = '1.0.0';\n\n /** Tool panel ID for shell integration */\n static readonly PANEL_ID = 'pivot';\n\n protected override get defaultConfig(): Partial<PivotConfig> {\n return {\n active: true,\n showTotals: true,\n showGrandTotal: true,\n showToolPanel: true,\n animation: 'slide',\n };\n }\n\n // #region Internal State\n private isActive = false;\n private hasInitialized = false;\n private pivotResult: PivotResult | null = null;\n private fieldHeaderMap: Map<string, string> = new Map();\n private expandedKeys: Set<string> = new Set();\n private defaultExpanded = true;\n private originalColumns: Array<{ field: string; header: string }> = [];\n private panelContainer: HTMLElement | null = null;\n private grandTotalFooter: HTMLElement | null = null;\n private previousVisibleKeys = new Set<string>();\n private keysToAnimate = new Set<string>();\n\n /**\n * Check if the plugin has valid pivot configuration (at least value fields).\n */\n private hasValidPivotConfig(): boolean {\n return (this.config.valueFields?.length ?? 0) > 0;\n }\n\n /**\n * Get animation style respecting grid-level animation mode.\n */\n private get animationStyle(): ExpandCollapseAnimation {\n const gridEl = this.grid as unknown as GridWithColumns;\n const mode = gridEl.effectiveConfig?.animation?.mode ?? 'reduced-motion';\n\n if (mode === false || mode === 'off') return false;\n if (mode !== true && mode !== 'on') {\n const host = this.shadowRoot?.host as HTMLElement | undefined;\n if (host && getComputedStyle(host).getPropertyValue('--tbw-animation-enabled').trim() === '0') {\n return false;\n }\n }\n return this.config.animation ?? 'slide';\n }\n\n // #endregion\n\n // #region Lifecycle\n\n override detach(): void {\n this.isActive = false;\n this.hasInitialized = false;\n this.pivotResult = null;\n this.fieldHeaderMap.clear();\n this.originalColumns = [];\n this.panelContainer = null;\n this.cleanupGrandTotalFooter();\n this.previousVisibleKeys.clear();\n this.keysToAnimate.clear();\n }\n\n // #endregion\n\n // #region Shell Integration\n\n override getToolPanel(): ToolPanelDefinition | undefined {\n // Allow users to disable the tool panel for programmatic-only pivot\n // Check userConfig first (works before attach), then merged config\n const showToolPanel = this.config?.showToolPanel ?? this.userConfig?.showToolPanel ?? true;\n if (showToolPanel === false) {\n return undefined;\n }\n\n return {\n id: PivotPlugin.PANEL_ID,\n title: 'Pivot',\n icon: '⊞',\n tooltip: 'Configure pivot table',\n order: 90,\n render: (container) => this.renderPanel(container),\n };\n }\n\n // #endregion\n\n // #region Hooks\n\n override processRows(rows: readonly unknown[]): PivotDataRow[] {\n // Auto-enable pivot if config.active is true and we have valid pivot fields\n if (!this.hasInitialized && this.config.active !== false && this.hasValidPivotConfig()) {\n this.hasInitialized = true;\n this.isActive = true;\n }\n\n if (!this.isActive) {\n return [...rows] as PivotDataRow[];\n }\n\n const errors = validatePivotConfig(this.config);\n if (errors.length > 0) {\n this.warn(`Config errors: ${errors.join(', ')}`);\n return [...rows] as PivotDataRow[];\n }\n\n this.buildFieldHeaderMap();\n this.defaultExpanded = this.config.defaultExpanded ?? true;\n\n // Initialize expanded state with defaults if first build\n if (this.expandedKeys.size === 0 && this.defaultExpanded && this.pivotResult) {\n const allKeys = getAllGroupKeys(this.pivotResult.rows);\n for (const key of allKeys) {\n this.expandedKeys.add(key);\n }\n }\n\n // Build pivot\n this.pivotResult = buildPivot(rows as PivotDataRow[], this.config);\n\n // If default expanded and we just built the pivot, add all group keys\n if (this.expandedKeys.size === 0 && this.defaultExpanded) {\n const allKeys = getAllGroupKeys(this.pivotResult.rows);\n for (const key of allKeys) {\n this.expandedKeys.add(key);\n }\n }\n\n // Return flattened pivot rows respecting expanded state\n const indentWidth = this.config.indentWidth ?? 20;\n const flatRows: PivotDataRow[] = flattenPivotRows(\n this.pivotResult.rows,\n this.expandedKeys,\n this.defaultExpanded,\n ).map((pr) => ({\n __pivotRowKey: pr.rowKey,\n __pivotLabel: pr.rowLabel,\n __pivotDepth: pr.depth,\n __pivotIsGroup: pr.isGroup,\n __pivotHasChildren: Boolean(pr.children?.length),\n __pivotExpanded: this.expandedKeys.has(pr.rowKey),\n __pivotRowCount: pr.rowCount ?? 0,\n __pivotIndent: pr.depth * indentWidth,\n __pivotTotal: pr.total,\n ...pr.values,\n }));\n\n // Track which rows are newly visible (for animation)\n this.keysToAnimate.clear();\n const currentVisibleKeys = new Set<string>();\n for (const row of flatRows) {\n const key = row.__pivotRowKey as string;\n currentVisibleKeys.add(key);\n // Animate non-root rows that weren't previously visible\n if (!this.previousVisibleKeys.has(key) && (row.__pivotDepth as number) > 0) {\n this.keysToAnimate.add(key);\n }\n }\n this.previousVisibleKeys = currentVisibleKeys;\n\n // Grand total is rendered as a pinned footer row in afterRender,\n // not as part of the scrolling row data\n\n return flatRows;\n }\n\n override processColumns(columns: readonly ColumnConfig[]): ColumnConfig[] {\n if (!this.isActive || !this.pivotResult) {\n return [...columns];\n }\n\n const pivotColumns: ColumnConfig[] = [];\n\n // Row label column\n const rowGroupHeaders = (this.config.rowGroupFields ?? []).map((f) => this.fieldHeaderMap.get(f) ?? f).join(' / ');\n pivotColumns.push({\n field: '__pivotLabel',\n header: rowGroupHeaders || 'Group',\n width: 200,\n });\n\n // Value columns for each column key\n for (const colKey of this.pivotResult.columnKeys) {\n for (const vf of this.config.valueFields ?? []) {\n const valueKey = createValueKey([colKey], vf.field);\n const valueHeader = vf.header || this.fieldHeaderMap.get(vf.field) || vf.field;\n pivotColumns.push({\n field: valueKey,\n header: `${colKey} - ${valueHeader} (${vf.aggFunc})`,\n width: 120,\n type: 'number',\n });\n }\n }\n\n // Totals column\n if (this.config.showTotals) {\n pivotColumns.push({\n field: '__pivotTotal',\n header: 'Total',\n width: 100,\n type: 'number',\n });\n }\n\n return pivotColumns;\n }\n\n override renderRow(row: Record<string, unknown>, rowEl: HTMLElement): boolean {\n const pivotRow = row as PivotRowData;\n\n // Handle pivot group row (has children)\n if (pivotRow.__pivotRowKey && pivotRow.__pivotHasChildren) {\n return renderPivotGroupRow(pivotRow, rowEl, {\n columns: this.gridColumns,\n onToggle: (key) => this.toggle(key),\n resolveIcon: (iconKey) => this.resolveIcon(iconKey),\n setIcon: (el, icon) => this.setIcon(el, icon),\n });\n }\n\n // Handle pivot leaf row (no children but in pivot mode)\n if (pivotRow.__pivotRowKey !== undefined && this.isActive) {\n return renderPivotLeafRow(pivotRow, rowEl, this.gridColumns);\n }\n\n // Clean up any leftover pivot styling from pooled row elements\n this.cleanupPivotStyling(rowEl);\n\n return false;\n }\n\n /**\n * Remove pivot-specific classes, attributes, and inline styles from a row element.\n * Called when pivot mode is disabled to clean up reused DOM elements.\n * Clears innerHTML so the grid's default renderer can rebuild the row.\n */\n private cleanupPivotStyling(rowEl: HTMLElement): void {\n // Check if this row was previously rendered by pivot (has pivot classes)\n const wasPivotRow =\n rowEl.classList.contains('pivot-group-row') ||\n rowEl.classList.contains('pivot-leaf-row') ||\n rowEl.classList.contains('pivot-grand-total-row');\n\n if (wasPivotRow) {\n // Remove pivot row classes and restore the default grid row class\n rowEl.classList.remove('pivot-group-row', 'pivot-leaf-row', 'pivot-grand-total-row');\n rowEl.classList.add('data-grid-row');\n\n // Remove pivot-specific attributes\n rowEl.removeAttribute('data-pivot-depth');\n\n // Clear the row content so the default renderer can rebuild it\n rowEl.innerHTML = '';\n }\n }\n\n override afterRender(): void {\n // Render grand total as a sticky pinned footer when pivot is active\n if (this.isActive && this.config.showGrandTotal && this.pivotResult) {\n this.renderGrandTotalFooter();\n } else {\n this.cleanupGrandTotalFooter();\n }\n\n // Apply animations to newly visible rows\n const style = this.animationStyle;\n if (style === false || this.keysToAnimate.size === 0) return;\n\n const body = this.shadowRoot?.querySelector('.rows');\n if (!body) return;\n\n const animClass = style === 'fade' ? 'tbw-pivot-fade-in' : 'tbw-pivot-slide-in';\n for (const rowEl of body.querySelectorAll('.pivot-group-row, .pivot-leaf-row')) {\n const key = (rowEl as HTMLElement).dataset.pivotKey;\n if (key && this.keysToAnimate.has(key)) {\n rowEl.classList.add(animClass);\n rowEl.addEventListener('animationend', () => rowEl.classList.remove(animClass), { once: true });\n }\n }\n this.keysToAnimate.clear();\n }\n\n /**\n * Render the grand total row as a sticky footer pinned to the bottom.\n */\n private renderGrandTotalFooter(): void {\n if (!this.pivotResult) return;\n\n const shadowRoot = this.shadowRoot;\n if (!shadowRoot) return;\n\n // Find the scroll container to append the footer\n const container =\n shadowRoot.querySelector('.tbw-scroll-area') ??\n shadowRoot.querySelector('.tbw-grid-content') ??\n shadowRoot.children[0];\n if (!container) return;\n\n // Create footer if it doesn't exist\n if (!this.grandTotalFooter) {\n this.grandTotalFooter = document.createElement('div');\n this.grandTotalFooter.className = 'pivot-grand-total-footer';\n container.appendChild(this.grandTotalFooter);\n }\n\n // Build the row data for grand total\n const grandTotalRow: PivotRowData = {\n __pivotRowKey: '__grandTotal',\n __pivotLabel: 'Grand Total',\n __pivotIsGrandTotal: true,\n __pivotTotal: this.pivotResult.grandTotal,\n ...this.pivotResult.totals,\n };\n\n // Render the grand total row into the footer\n renderPivotGrandTotalRow(grandTotalRow, this.grandTotalFooter, this.gridColumns);\n }\n\n /**\n * Remove the grand total footer element.\n */\n private cleanupGrandTotalFooter(): void {\n if (this.grandTotalFooter) {\n this.grandTotalFooter.remove();\n this.grandTotalFooter = null;\n }\n }\n\n // #endregion\n\n // #region Expand/Collapse API\n\n toggle(key: string): void {\n if (this.expandedKeys.has(key)) {\n this.expandedKeys.delete(key);\n } else {\n this.expandedKeys.add(key);\n }\n this.requestRender();\n }\n\n expand(key: string): void {\n this.expandedKeys.add(key);\n this.requestRender();\n }\n\n collapse(key: string): void {\n this.expandedKeys.delete(key);\n this.requestRender();\n }\n\n expandAll(): void {\n if (this.pivotResult) {\n const allKeys = getAllGroupKeys(this.pivotResult.rows);\n for (const key of allKeys) {\n this.expandedKeys.add(key);\n }\n this.requestRender();\n }\n }\n\n collapseAll(): void {\n this.expandedKeys.clear();\n this.requestRender();\n }\n\n isExpanded(key: string): boolean {\n return this.expandedKeys.has(key);\n }\n\n // #endregion\n\n // #region Public API\n\n enablePivot(): void {\n if (this.originalColumns.length === 0) {\n this.captureOriginalColumns();\n }\n this.isActive = true;\n this.requestRender();\n }\n\n disablePivot(): void {\n this.isActive = false;\n this.pivotResult = null;\n this.requestRender();\n }\n\n isPivotActive(): boolean {\n return this.isActive;\n }\n\n getPivotResult(): PivotResult | null {\n return this.pivotResult;\n }\n\n setRowGroupFields(fields: string[]): void {\n this.config.rowGroupFields = fields;\n this.requestRender();\n }\n\n setColumnGroupFields(fields: string[]): void {\n this.config.columnGroupFields = fields;\n this.requestRender();\n }\n\n setValueFields(fields: PivotValueField[]): void {\n this.config.valueFields = fields;\n this.requestRender();\n }\n\n refresh(): void {\n this.pivotResult = null;\n this.requestRender();\n }\n\n // #endregion\n\n // #region Tool Panel API\n\n showPanel(): void {\n const grid = this.grid as unknown as GridWithColumns;\n grid.openToolPanel(PivotPlugin.PANEL_ID);\n }\n\n hidePanel(): void {\n const grid = this.grid as unknown as GridWithColumns;\n grid.closeToolPanel();\n }\n\n togglePanel(): void {\n const grid = this.grid as unknown as GridWithColumns;\n grid.toggleToolPanel(PivotPlugin.PANEL_ID);\n }\n\n isPanelVisible(): boolean {\n const grid = this.grid as unknown as GridWithColumns;\n return grid.activeToolPanel === PivotPlugin.PANEL_ID;\n }\n\n // #endregion\n\n // #region Private Helpers\n\n private get gridColumns(): ColumnConfig[] {\n const grid = this.grid as unknown as GridWithColumns;\n return (grid.columns ?? []) as ColumnConfig[];\n }\n\n private buildFieldHeaderMap(): void {\n const availableFields = this.getAvailableFields();\n this.fieldHeaderMap.clear();\n for (const field of availableFields) {\n this.fieldHeaderMap.set(field.field, field.header);\n }\n }\n\n private getAvailableFields(): FieldInfo[] {\n if (this.originalColumns.length > 0) {\n return this.originalColumns;\n }\n return this.captureOriginalColumns();\n }\n\n private captureOriginalColumns(): FieldInfo[] {\n const grid = this.grid as unknown as GridWithColumns;\n try {\n const columns = grid.getAllColumns?.() ?? grid.columns ?? [];\n this.originalColumns = columns\n .filter((col: { field: string }) => !col.field.startsWith('__pivot'))\n .map((col: { field: string; header?: string }) => ({\n field: col.field,\n header: col.header ?? col.field,\n }));\n return this.originalColumns;\n } catch {\n return [];\n }\n }\n\n private renderPanel(container: HTMLElement): (() => void) | void {\n this.panelContainer = container;\n\n if (this.originalColumns.length === 0) {\n this.captureOriginalColumns();\n }\n\n const callbacks: PanelCallbacks = {\n onTogglePivot: (enabled) => {\n if (enabled) {\n this.enablePivot();\n } else {\n this.disablePivot();\n }\n this.refreshPanel();\n },\n onAddFieldToZone: (field, zone) => this.addFieldToZone(field, zone),\n onRemoveFieldFromZone: (field, zone) => this.removeFieldFromZone(field, zone),\n onAddValueField: (field, aggFunc) => this.addValueField(field, aggFunc),\n onRemoveValueField: (field) => this.removeValueField(field),\n onUpdateValueAggFunc: (field, aggFunc) => this.updateValueAggFunc(field, aggFunc),\n onOptionChange: (option, value) => {\n this.config[option] = value;\n if (this.isActive) this.refresh();\n },\n getAvailableFields: () => this.getAvailableFields(),\n };\n\n return renderPivotPanel(container, this.config, this.isActive, callbacks);\n }\n\n private refreshPanel(): void {\n if (!this.panelContainer) return;\n this.panelContainer.innerHTML = '';\n this.renderPanel(this.panelContainer);\n }\n\n private addFieldToZone(field: string, zoneType: 'rowGroups' | 'columnGroups'): void {\n if (zoneType === 'rowGroups') {\n const current = this.config.rowGroupFields ?? [];\n if (!current.includes(field)) {\n this.config.rowGroupFields = [...current, field];\n }\n } else {\n const current = this.config.columnGroupFields ?? [];\n if (!current.includes(field)) {\n this.config.columnGroupFields = [...current, field];\n }\n }\n\n this.removeFromOtherZones(field, zoneType);\n if (this.isActive) this.refresh();\n this.refreshPanel();\n }\n\n private removeFieldFromZone(field: string, zoneType: 'rowGroups' | 'columnGroups'): void {\n if (zoneType === 'rowGroups') {\n this.config.rowGroupFields = (this.config.rowGroupFields ?? []).filter((f) => f !== field);\n } else {\n this.config.columnGroupFields = (this.config.columnGroupFields ?? []).filter((f) => f !== field);\n }\n\n if (this.isActive) this.refresh();\n this.refreshPanel();\n }\n\n private removeFromOtherZones(field: string, targetZone: 'rowGroups' | 'columnGroups' | 'values'): void {\n if (targetZone !== 'rowGroups') {\n this.config.rowGroupFields = (this.config.rowGroupFields ?? []).filter((f) => f !== field);\n }\n if (targetZone !== 'columnGroups') {\n this.config.columnGroupFields = (this.config.columnGroupFields ?? []).filter((f) => f !== field);\n }\n if (targetZone !== 'values') {\n this.config.valueFields = (this.config.valueFields ?? []).filter((v) => v.field !== field);\n }\n }\n\n private addValueField(field: string, aggFunc: AggFunc): void {\n const current = this.config.valueFields ?? [];\n if (!current.some((v) => v.field === field)) {\n this.config.valueFields = [...current, { field, aggFunc }];\n }\n\n this.removeFromOtherZones(field, 'values');\n if (this.isActive) this.refresh();\n this.refreshPanel();\n }\n\n private removeValueField(field: string): void {\n this.config.valueFields = (this.config.valueFields ?? []).filter((v) => v.field !== field);\n if (this.isActive) this.refresh();\n this.refreshPanel();\n }\n\n private updateValueAggFunc(field: string, aggFunc: AggFunc): void {\n const valueFields = this.config.valueFields ?? [];\n const fieldIndex = valueFields.findIndex((v) => v.field === field);\n if (fieldIndex >= 0) {\n valueFields[fieldIndex] = { ...valueFields[fieldIndex], aggFunc };\n this.config.valueFields = [...valueFields];\n }\n if (this.isActive) this.refresh();\n }\n\n // #endregion\n\n // #region Styles\n\n override readonly styles = styles;\n\n // #endregion\n}\n"],"names":["DEFAULT_GRID_ICONS","BaseGridPlugin","config","grid","PluginClass","eventName","detail","userIcons","iconKey","pluginOverride","element","icon","message","builtInAggregators","rows","field","acc","row","sum","r","customAggregators","aggregatorRegistry","name","fn","ref","column","builtInValueAggregators","vals","a","b","getValueAggregator","aggFunc","getPivotAggregator","validatePivotConfig","errors","createValueKey","columnValues","valueField","buildPivot","rowGroupFields","columnGroupFields","valueFields","columnKeys","getUniqueColumnKeys","pivotRows","buildHierarchicalPivotRows","totals","calculateTotals","grandTotal","columnFields","keys","key","f","groupByField","groups","existing","depth","parentKey","result","values","aggregateValues","total","calculateRowTotal","currentField","remainingFields","hasChildren","grouped","groupValue","groupRows","rowKey","children","colKey","vf","nums","aggregator","aggregatedResult","valueKey","val","sumRows","flattenPivotRows","expandedKeys","defaultExpanded","flatten","isExpanded","child","getAllGroupKeys","collectKeys","AGG_FUNCS","renderPivotPanel","container","isActive","callbacks","controller","ctx","wrapper","createSection","createOptionsPanel","createFieldZone","createValuesZone","createAvailableFieldsZone","title","contentFactory","section","header","content","zoneType","signal","zone","currentFields","placeholder","createFieldChip","e","chip","fieldInfo","label","removeBtn","currentValues","createValueChip","labelWrapper","aggSelect","option","allFields","usedFields","v","availableFields","empty","panel","createCheckbox","checked","onChange","input","span","renderPivotGroupRow","rowEl","col","colIdx","cell","indent","btn","count","value","renderPivotLeafRow","columns","renderPivotGrandTotalRow","PivotPlugin","mode","host","allKeys","indentWidth","flatRows","pr","currentVisibleKeys","pivotColumns","rowGroupHeaders","valueHeader","pivotRow","el","style","body","animClass","shadowRoot","grandTotalRow","fields","enabled","current","targetZone","fieldIndex","styles"],"mappings":"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"}