@toolbox-web/grid-angular 2.1.0 → 2.3.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (31) hide show
  1. package/README.md +25 -55
  2. package/fesm2022/toolbox-web-grid-angular-features-editing.mjs +14 -4
  3. package/fesm2022/toolbox-web-grid-angular-features-editing.mjs.map +1 -1
  4. package/fesm2022/toolbox-web-grid-angular-features-filtering.mjs +10 -30
  5. package/fesm2022/toolbox-web-grid-angular-features-filtering.mjs.map +1 -1
  6. package/fesm2022/toolbox-web-grid-angular-features-grouping-columns.mjs.map +1 -1
  7. package/fesm2022/toolbox-web-grid-angular-features-grouping-rows.mjs.map +1 -1
  8. package/fesm2022/toolbox-web-grid-angular-features-pinned-rows.mjs.map +1 -1
  9. package/fesm2022/toolbox-web-grid-angular-features-shell.mjs +25 -9
  10. package/fesm2022/toolbox-web-grid-angular-features-shell.mjs.map +1 -1
  11. package/fesm2022/toolbox-web-grid-angular-features-tree.mjs +47 -14
  12. package/fesm2022/toolbox-web-grid-angular-features-tree.mjs.map +1 -1
  13. package/fesm2022/toolbox-web-grid-angular.mjs +7 -0
  14. package/fesm2022/toolbox-web-grid-angular.mjs.map +1 -1
  15. package/package.json +1 -1
  16. package/types/toolbox-web-grid-angular-features-editing.d.ts +14 -5
  17. package/types/toolbox-web-grid-angular-features-editing.d.ts.map +1 -1
  18. package/types/toolbox-web-grid-angular-features-filtering.d.ts +6 -22
  19. package/types/toolbox-web-grid-angular-features-filtering.d.ts.map +1 -1
  20. package/types/toolbox-web-grid-angular-features-grouping-columns.d.ts +1 -5
  21. package/types/toolbox-web-grid-angular-features-grouping-columns.d.ts.map +1 -1
  22. package/types/toolbox-web-grid-angular-features-grouping-rows.d.ts +1 -3
  23. package/types/toolbox-web-grid-angular-features-grouping-rows.d.ts.map +1 -1
  24. package/types/toolbox-web-grid-angular-features-pinned-rows.d.ts +1 -11
  25. package/types/toolbox-web-grid-angular-features-pinned-rows.d.ts.map +1 -1
  26. package/types/toolbox-web-grid-angular-features-shell.d.ts +14 -4
  27. package/types/toolbox-web-grid-angular-features-shell.d.ts.map +1 -1
  28. package/types/toolbox-web-grid-angular-features-tree.d.ts +23 -4
  29. package/types/toolbox-web-grid-angular-features-tree.d.ts.map +1 -1
  30. package/types/toolbox-web-grid-angular.d.ts +15 -8
  31. package/types/toolbox-web-grid-angular.d.ts.map +1 -1
@@ -35,15 +35,11 @@ import '@toolbox-web/grid/features/filtering';
35
35
  * export class AppGridComponent {}
36
36
  * ```
37
37
  *
38
- * ## Backward compatibility (v1.x)
38
+ * ## Feature claims
39
39
  *
40
- * The matching `filtering` input and `filterChange` output also still exist
41
- * on `Grid` (marked `@deprecated`) so existing apps that bind them without
42
- * importing `GridFilteringDirective` continue to work — those will be
43
- * removed in v2.0.0. When both this directive and the deprecated bindings
44
- * are present, the directive wins via the per-grid claims registry in
45
- * `internal/feature-claims.ts`: `Grid` consults the registry and skips its
46
- * own plugin creation + event wiring for any claimed feature.
40
+ * The directive registers a per-grid feature claim (see
41
+ * `internal/feature-claims.ts`), so `Grid` skips its own plugin creation and
42
+ * event wiring for any feature that a per-feature directive has claimed.
47
43
  *
48
44
  * @category Directive
49
45
  */
@@ -58,8 +54,7 @@ import '@toolbox-web/grid/features/filtering';
58
54
  class GridFilteringDirective {
59
55
  elementRef = inject((ElementRef));
60
56
  /**
61
- * Enable column filtering. Identical semantics to the deprecated input on
62
- * `Grid` — this directive owns the binding when both are present.
57
+ * Enable column filtering.
63
58
  *
64
59
  * @example
65
60
  * ```html
@@ -216,20 +211,13 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.0.6", ngImpor
216
211
  /**
217
212
  * Filtering feature for @toolbox-web/grid-angular
218
213
  *
219
- * Two ways to use:
214
+ * Add `GridFilteringDirective` to your component's `imports`. The directive
215
+ * owns the `[filtering]` input and `(filterChange)` output, so the typed
216
+ * surface tree-shakes away when the feature is not imported.
220
217
  *
221
- * 1. **Recommended (tree-shakeable surface):** add `GridFilteringDirective`
222
- * to your component's `imports`. The directive owns the `[filtering]`
223
- * input and `(filterChange)` output, so the typed surface tree-shakes
224
- * away when the feature is not imported.
225
- * 2. **Legacy (non-breaking, deprecated):** side-effect import the feature
226
- * entry; the matching `[filtering]` / `(filterChange)` bindings on the
227
- * central `Grid` directive will work as in v1.x. These bindings on `Grid`
228
- * are marked `@deprecated` and will be removed in v2.0.0.
218
+ * `injectGridFiltering()` is available for programmatic control.
229
219
  *
230
- * Either way `injectGridFiltering()` is available for programmatic control.
231
- *
232
- * @example Recommended (directive-owned binding)
220
+ * @example Directive-owned binding
233
221
  * ```typescript
234
222
  * import { Grid } from '@toolbox-web/grid-angular';
235
223
  * import { GridFilteringDirective } from '@toolbox-web/grid-angular/features/filtering';
@@ -240,14 +228,6 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.0.6", ngImpor
240
228
  * })
241
229
  * ```
242
230
  *
243
- * @example Legacy (deprecated; works without importing the directive)
244
- * ```typescript
245
- * import '@toolbox-web/grid-angular/features/filtering';
246
- *
247
- * <tbw-grid [filtering]="true" />
248
- * <tbw-grid [filtering]="{ debounceMs: 200 }" />
249
- * ```
250
- *
251
231
  * @example Using injectGridFiltering
252
232
  * ```typescript
253
233
  * import { injectGridFiltering } from '@toolbox-web/grid-angular/features/filtering';
@@ -1 +1 @@
1
- {"version":3,"file":"toolbox-web-grid-angular-features-filtering.mjs","sources":["../../../../libs/grid-angular/features/filtering/src/grid-filtering.directive.ts","../../../../libs/grid-angular/features/filtering/src/base-filter-panel.ts","../../../../libs/grid-angular/features/filtering/src/index.ts","../../../../libs/grid-angular/features/filtering/src/toolbox-web-grid-angular-features-filtering.ts"],"sourcesContent":["/**\n * `GridFilteringDirective` — attribute-selector directive that owns the\n * `filtering` input and the `filterChange` output on `<tbw-grid>`.\n *\n * ## Why this exists\n *\n * Historically these bindings lived on the central `Grid` directive in\n * `@toolbox-web/grid-angular`. That meant the typed surface for the\n * filtering plugin shipped in the core bundle of every consumer, even those\n * that never imported the filtering feature. Moving them here lets the\n * surface tree-shake away with the rest of the feature when it is not\n * imported, matching the philosophy of the React / Vue adapters and the\n * web-component core (where unloaded plugins simply don't exist on the\n * element).\n *\n * ## Usage\n *\n * ```typescript\n * import { Component } from '@angular/core';\n * import { Grid } from '@toolbox-web/grid-angular';\n * import { GridFilteringDirective } from '@toolbox-web/grid-angular/features/filtering';\n *\n * @Component({\n * selector: 'app-grid',\n * imports: [Grid, GridFilteringDirective],\n * template: `\n * <tbw-grid [rows]=\"rows\" [filtering]=\"true\" (filterChange)=\"onFilter($event)\" />\n * `,\n * })\n * export class AppGridComponent {}\n * ```\n *\n * ## Backward compatibility (v1.x)\n *\n * The matching `filtering` input and `filterChange` output also still exist\n * on `Grid` (marked `@deprecated`) so existing apps that bind them without\n * importing `GridFilteringDirective` continue to work — those will be\n * removed in v2.0.0. When both this directive and the deprecated bindings\n * are present, the directive wins via the per-grid claims registry in\n * `internal/feature-claims.ts`: `Grid` consults the registry and skips its\n * own plugin creation + event wiring for any claimed feature.\n *\n * @category Directive\n */\nimport { Directive, ElementRef, inject, input, OnDestroy, OnInit, output, type Type } from '@angular/core';\nimport type { DataGridElement } from '@toolbox-web/grid';\nimport {\n claimEvent,\n registerFeatureClaim,\n unclaimEvent,\n unregisterFeatureClaim,\n type FilterPanel,\n} from '@toolbox-web/grid-angular';\nimport type { FilterConfig as CoreFilterConfig, FilterChangeDetail } from '@toolbox-web/grid/plugins/filtering';\n\n/**\n * Angular-specific filter config that allows an Angular component class as\n * the plugin-level `filterPanelRenderer`.\n *\n * Extends the core `FilterConfig` to accept a `Type<FilterPanel>` for\n * `filterPanelRenderer` in addition to the vanilla\n * `(container, params) => void` signature. Bridging to vanilla DOM is handled\n * by the side-effect import `@toolbox-web/grid-angular/features/filtering`.\n *\n * Re-exported from the feature entry under the same name as the core type\n * so Angular consumers see a single canonical `FilterConfig` from\n * `@toolbox-web/grid-angular/features/filtering`.\n *\n * @since 1.7.1\n */\n// eslint-disable-next-line @typescript-eslint/no-explicit-any\nexport type FilterConfig<TRow = any> = Omit<CoreFilterConfig<TRow>, 'filterPanelRenderer'> & {\n filterPanelRenderer?: CoreFilterConfig<TRow>['filterPanelRenderer'] | Type<FilterPanel>;\n};\n\n/**\n * Owns the `[filtering]` input and `(filterChange)` output on `<tbw-grid>`.\n *\n * Selector matches when *either* binding is present so users can pick the\n * style that suits their template — both go through the same claim and the\n * same wiring.\n * @category Directive\n */\n@Directive({\n selector: 'tbw-grid[filtering], tbw-grid[filterChange]',\n standalone: true,\n})\nexport class GridFilteringDirective implements OnInit, OnDestroy {\n private readonly elementRef = inject(ElementRef<DataGridElement>);\n\n /**\n * Enable column filtering. Identical semantics to the deprecated input on\n * `Grid` — this directive owns the binding when both are present.\n *\n * @example\n * ```html\n * <tbw-grid [filtering]=\"true\" />\n * <tbw-grid [filtering]=\"{ debounceMs: 200 }\" />\n * ```\n */\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\n readonly filtering = input<boolean | FilterConfig<any>>();\n\n /**\n * Emitted when filter values change.\n *\n * @example\n * ```html\n * <tbw-grid (filterChange)=\"onFilterChange($event)\" />\n * ```\n */\n readonly filterChange = output<FilterChangeDetail>();\n\n // Listener kept so we can detach in `ngOnDestroy`.\n private listener?: (e: Event) => void;\n\n constructor() {\n const grid = this.elementRef.nativeElement;\n // Tell `Grid` we own this feature's input. Reading `this.filtering()`\n // inside the getter establishes a reactive dependency in `Grid`'s\n // `createFeaturePlugins` effect — when our input changes, that effect\n // re-runs and the plugin config is updated.\n registerFeatureClaim(grid, 'filtering', () => this.filtering());\n // Tell `Grid` we own the matching event so it doesn't double-emit on\n // its own deprecated `filterChange` output.\n claimEvent(grid, 'filter-change');\n }\n\n ngOnInit(): void {\n const grid = this.elementRef.nativeElement;\n this.listener = (e: Event) => {\n this.filterChange.emit((e as CustomEvent<FilterChangeDetail>).detail);\n };\n grid.addEventListener('filter-change', this.listener);\n }\n\n ngOnDestroy(): void {\n const grid = this.elementRef.nativeElement;\n if (this.listener) {\n grid.removeEventListener('filter-change', this.listener);\n this.listener = undefined;\n }\n // Drop the claims so that, if the directive is removed via *ngIf but\n // the host `<tbw-grid>` survives, `Grid`'s deprecated bindings take\n // back over without leaving stale ownership behind.\n unregisterFeatureClaim(grid, 'filtering');\n unclaimEvent(grid, 'filter-change');\n }\n}\n","import { Directive, input } from '@angular/core';\nimport type { FilterPanel } from '@toolbox-web/grid-angular';\n\ntype FilterPanelParams = ReturnType<FilterPanel['params']>;\n\n/**\n * Base class for Angular filter panel components.\n *\n * Provides a ready-made `params` input and common lifecycle helpers\n * (`applyAndClose`, `clearAndClose`) so consumers only need to implement\n * their filter logic in `applyFilter()`.\n *\n * ## Usage\n *\n * ```typescript\n * import { Component, viewChild, ElementRef } from '@angular/core';\n * import { BaseFilterPanel } from '@toolbox-web/grid-angular/features/filtering';\n *\n * @Component({\n * selector: 'app-text-filter',\n * template: `\n * <input #input (keydown.enter)=\"applyAndClose()\" />\n * <button (click)=\"applyAndClose()\">Apply</button>\n * <button (click)=\"clearAndClose()\">Clear</button>\n * `\n * })\n * export class TextFilterComponent extends BaseFilterPanel {\n * input = viewChild.required<ElementRef<HTMLInputElement>>('input');\n *\n * applyFilter(): void {\n * this.params().applyTextFilter('contains', this.input().nativeElement.value);\n * }\n * }\n * ```\n *\n * ## Template Syntax\n *\n * The grid's filtering plugin will mount this component and provide `params`\n * automatically. No manual wiring is required:\n *\n * ```typescript\n * gridConfig = {\n * columns: [\n * { field: 'name', filterable: true, filterPanel: TextFilterComponent },\n * ],\n * };\n * ```\n *\n * @typeParam TRow - The row data type (available via `params().column`)\n *\n * @since 0.13.0\n */\n@Directive()\nexport abstract class BaseFilterPanel implements FilterPanel {\n /**\n * Filter panel parameters injected by the grid's filtering plugin.\n *\n * Provides access to:\n * - `field` — the column field name\n * - `column` — full column configuration\n * - `uniqueValues` — distinct values in the column\n * - `excludedValues` — currently excluded values (set filter)\n * - `searchText` — current search text\n * - `applySetFilter(excluded)` — apply a set-based (include/exclude) filter\n * - `applyTextFilter(operator, value, valueTo?)` — apply a text/number filter\n * - `clearFilter()` — clear the filter for this column\n * - `closePanel()` — close the filter panel\n */\n readonly params = input.required<FilterPanelParams>();\n\n /**\n * Implement this to apply your filter logic.\n *\n * Called by {@link applyAndClose} before closing the panel.\n * Use `this.params()` to access the filter API.\n *\n * @example\n * ```typescript\n * applyFilter(): void {\n * this.params().applyTextFilter('contains', this.searchText);\n * }\n * ```\n */\n abstract applyFilter(): void;\n\n /**\n * Apply the filter then close the panel.\n *\n * Calls {@link applyFilter} followed by `params().closePanel()`.\n * Bind this to your \"Apply\" button or Enter key handler.\n */\n applyAndClose(): void {\n this.applyFilter();\n this.params().closePanel();\n }\n\n /**\n * Clear the filter then close the panel.\n *\n * Calls `params().clearFilter()` followed by `params().closePanel()`.\n * Bind this to your \"Clear\" / \"Reset\" button.\n */\n clearAndClose(): void {\n this.params().clearFilter();\n this.params().closePanel();\n }\n}\n","/**\n * Filtering feature for @toolbox-web/grid-angular\n *\n * Two ways to use:\n *\n * 1. **Recommended (tree-shakeable surface):** add `GridFilteringDirective`\n * to your component's `imports`. The directive owns the `[filtering]`\n * input and `(filterChange)` output, so the typed surface tree-shakes\n * away when the feature is not imported.\n * 2. **Legacy (non-breaking, deprecated):** side-effect import the feature\n * entry; the matching `[filtering]` / `(filterChange)` bindings on the\n * central `Grid` directive will work as in v1.x. These bindings on `Grid`\n * are marked `@deprecated` and will be removed in v2.0.0.\n *\n * Either way `injectGridFiltering()` is available for programmatic control.\n *\n * @example Recommended (directive-owned binding)\n * ```typescript\n * import { Grid } from '@toolbox-web/grid-angular';\n * import { GridFilteringDirective } from '@toolbox-web/grid-angular/features/filtering';\n *\n * @Component({\n * imports: [Grid, GridFilteringDirective],\n * template: `<tbw-grid [filtering]=\"true\" (filterChange)=\"onChange($event)\" />`,\n * })\n * ```\n *\n * @example Legacy (deprecated; works without importing the directive)\n * ```typescript\n * import '@toolbox-web/grid-angular/features/filtering';\n *\n * <tbw-grid [filtering]=\"true\" />\n * <tbw-grid [filtering]=\"{ debounceMs: 200 }\" />\n * ```\n *\n * @example Using injectGridFiltering\n * ```typescript\n * import { injectGridFiltering } from '@toolbox-web/grid-angular/features/filtering';\n *\n * @Component({...})\n * export class MyComponent {\n * private filtering = injectGridFiltering();\n *\n * filterByStatus(status: string) {\n * this.filtering.setFilter('status', { operator: 'equals', value: status });\n * }\n * }\n * ```\n *\n * @packageDocumentation\n */\n\nimport { afterNextRender, DestroyRef, ElementRef, inject, signal, type Signal, type Type } from '@angular/core';\nimport type { DataGridElement } from '@toolbox-web/grid';\nimport {\n isComponentClass,\n registerFeatureConfigPreprocessor,\n registerFilterPanelTypeDefaultBridge,\n type FilterPanel,\n type GridAdapter,\n} from '@toolbox-web/grid-angular';\nimport '@toolbox-web/grid/features/filtering';\nimport {\n FilteringPlugin,\n type BlankMode,\n type FilterConfig as CoreFilterConfig,\n type FilterModel,\n} from '@toolbox-web/grid/plugins/filtering';\nexport type { _Augmentation as _FilteringAugmentation } from '@toolbox-web/grid/features/filtering';\n\n// Attribute-selector directive that owns the `[filtering]` input and\n// `(filterChange)` output on `<tbw-grid>`. Add to your component's `imports`\n// alongside `Grid` to opt into the feature directly via the binding. The\n// matching deprecated bindings on `Grid` remain as a v1.x compatibility\n// shim and will be removed in v2.0.0.\nexport { GridFilteringDirective } from './grid-filtering.directive';\nexport type { FilterConfig } from './grid-filtering.directive';\n\n// `BaseFilterPanel` is filtering-specific (implements `FilterPanel` from the\n// filtering plugin) and physically lives in this secondary entry.\nexport { BaseFilterPanel } from './base-filter-panel';\n\ntype FilterPanelParams = ReturnType<FilterPanel['params']>;\n\n// Bridge any Angular component classes used as `filterPanelRenderer` (in\n// `gridConfig.typeDefaults` or via `provideGridTypeDefaults`) to the\n// `(container, params) => void` form required by FilteringPlugin. Without\n// this import, component-class filterPanelRenderers are silently dropped \\u2014\n// the same precondition as the FilteringPlugin itself (TBW031).\nregisterFilterPanelTypeDefaultBridge((rendererValue: unknown, adapter: GridAdapter) => {\n const componentClass = rendererValue as Type<unknown>;\n const mount = adapter.mountComponentRenderer<FilterPanelParams>(componentClass, (params) => ({ params }));\n return (container: HTMLElement, params: FilterPanelParams) => {\n container.appendChild(mount(params).hostElement);\n };\n});\n\n/**\n * Bridge an Angular component class used as the plugin-level\n * `filterPanelRenderer` (in `FilterConfig`) to the `(container, params) => void`\n * form required by FilteringPlugin. Mirrors `registerFilterPanelTypeDefaultBridge`\n * above, but for the plugin-wide renderer rather than per-type defaults.\n *\n * Without this preprocessor, passing a component class as\n * `filtering.filterPanelRenderer` would be invoked as a function at render\n * time and crash.\n *\n * @since 1.7.1\n */\nregisterFeatureConfigPreprocessor('filtering', (config, adapter) => {\n if (!config || typeof config === 'boolean' || typeof config !== 'object') return config;\n const cfg = config as CoreFilterConfig;\n if (!isComponentClass(cfg.filterPanelRenderer)) return config;\n\n type PluginFilterPanelRenderer = NonNullable<CoreFilterConfig['filterPanelRenderer']>;\n type PluginFilterPanelParams = Parameters<PluginFilterPanelRenderer>[1];\n\n const componentClass = cfg.filterPanelRenderer as Type<unknown>;\n const mount = adapter.mountComponentRenderer<PluginFilterPanelParams>(componentClass, (params) => ({ params }));\n const filterPanelRenderer: CoreFilterConfig['filterPanelRenderer'] = (container, params) => {\n container.appendChild(mount(params).hostElement);\n };\n return { ...cfg, filterPanelRenderer };\n});\n\n/**\n * Filtering methods returned from injectGridFiltering.\n *\n * Uses lazy discovery - the grid is found on first method call, not during initialization.\n */\nexport interface FilteringMethods {\n /**\n * Set a filter on a specific field.\n * @param field - The field name to filter\n * @param filter - Filter configuration, or null to remove\n * @param options - `{ silent: true }` applies the filter without emitting `filter-change`\n */\n setFilter: (field: string, filter: Omit<FilterModel, 'field'> | null, options?: { silent?: boolean }) => void;\n\n /**\n * Get the current filter for a field.\n */\n getFilter: (field: string) => FilterModel | undefined;\n\n /**\n * Get all active filters.\n */\n getFilters: () => FilterModel[];\n\n /**\n * Set all filters at once (replaces existing).\n * @param options - `{ silent: true }` applies filters without emitting `filter-change`\n */\n setFilterModel: (filters: FilterModel[], options?: { silent?: boolean }) => void;\n\n /**\n * Clear all active filters.\n * @param options - `{ silent: true }` clears filters without emitting `filter-change`\n */\n clearAllFilters: (options?: { silent?: boolean }) => void;\n\n /**\n * Clear filter for a specific field.\n * @param options - `{ silent: true }` clears filter without emitting `filter-change`\n */\n clearFieldFilter: (field: string, options?: { silent?: boolean }) => void;\n\n /**\n * Check if a field has an active filter.\n */\n isFieldFiltered: (field: string) => boolean;\n\n /**\n * Get the count of rows after filtering.\n */\n getFilteredRowCount: () => number;\n\n /**\n * Get unique values for a field (for building filter dropdowns).\n */\n getUniqueValues: (field: string) => unknown[];\n\n /**\n * Get set filters whose values no longer match any rows in the current data.\n */\n getStaleFilters: () => FilterModel[];\n\n /**\n * Get the current blank mode for a field.\n */\n getBlankMode: (field: string) => BlankMode;\n\n /**\n * Toggle blank filter mode for a field.\n */\n toggleBlankFilter: (field: string, mode: BlankMode) => void;\n\n /**\n * Signal indicating if grid is ready.\n */\n isReady: Signal<boolean>;\n}\n\n/**\n * Angular inject function for programmatic filter control.\n *\n * Uses **lazy grid discovery** - the grid element is found when methods are called,\n * not during initialization.\n *\n * @example\n * ```typescript\n * import { Component } from '@angular/core';\n * import { Grid } from '@toolbox-web/grid-angular';\n * import '@toolbox-web/grid-angular/features/filtering';\n * import { injectGridFiltering } from '@toolbox-web/grid-angular/features/filtering';\n *\n * @Component({\n * selector: 'app-my-grid',\n * imports: [Grid],\n * template: `\n * <input (input)=\"applyFilter($event)\" placeholder=\"Filter by name...\" />\n * <span>{{ filtering.getFilteredRowCount() }} results</span>\n * <button (click)=\"filtering.clearAllFilters()\">Clear</button>\n * <tbw-grid [rows]=\"rows\" [filtering]=\"true\"></tbw-grid>\n * `\n * })\n * export class MyGridComponent {\n * filtering = injectGridFiltering();\n *\n * applyFilter(event: Event) {\n * const value = (event.target as HTMLInputElement).value;\n * this.filtering.setFilter('name', value ? { operator: 'contains', value } : null);\n * }\n * }\n * ```\n *\n * @param selector - Optional CSS selector to target a specific grid element.\n * Defaults to `'tbw-grid'` (first grid in the component). Use when the\n * component contains multiple grids, e.g. `'tbw-grid.primary'` or `'#my-grid'`.\n */\nexport function injectGridFiltering(selector = 'tbw-grid'): FilteringMethods {\n const elementRef = inject(ElementRef);\n const destroyRef = inject(DestroyRef);\n const isReady = signal(false);\n\n let cachedGrid: DataGridElement | null = null;\n let readyPromiseStarted = false;\n\n const getGrid = (): DataGridElement | null => {\n if (cachedGrid) return cachedGrid;\n\n const grid = elementRef.nativeElement.querySelector(selector) as DataGridElement | null;\n if (grid) {\n cachedGrid = grid;\n if (!readyPromiseStarted) {\n readyPromiseStarted = true;\n grid.ready?.().then(() => {\n // If the plugin is already attached, signal readiness immediately.\n // Otherwise, Angular's Grid directive may not have applied gridConfig\n // yet (it uses effect + queueMicrotask). Defer to let pending\n // microtasks flush before signaling readiness.\n if (grid.getPluginByName('filtering')) {\n isReady.set(true);\n } else {\n setTimeout(() => isReady.set(true), 0);\n }\n });\n }\n }\n return grid;\n };\n\n const getPlugin = (): FilteringPlugin | undefined => {\n return getGrid()?.getPluginByName('filtering') as FilteringPlugin | undefined;\n };\n\n // Eagerly discover the grid after the first render so isReady updates\n // without requiring a programmatic method call. Falls back to a\n // MutationObserver for lazy-rendered tabs, *ngIf, @defer, etc.\n afterNextRender(() => {\n if (getGrid()) return;\n\n const host = elementRef.nativeElement as HTMLElement;\n const observer = new MutationObserver(() => {\n if (getGrid()) observer.disconnect();\n });\n observer.observe(host, { childList: true, subtree: true });\n\n destroyRef.onDestroy(() => observer.disconnect());\n });\n\n return {\n isReady: isReady.asReadonly(),\n\n setFilter: (field: string, filter: Omit<FilterModel, 'field'> | null, options?: { silent?: boolean }) => {\n const plugin = getPlugin();\n if (!plugin) {\n console.warn(\n `[tbw-grid:filtering] FilteringPlugin not found.\\n\\n` +\n ` → Enable filtering on the grid:\\n` +\n ` <tbw-grid [filtering]=\"true\" />`,\n );\n return;\n }\n plugin.setFilter(field, filter, options);\n },\n\n getFilter: (field: string) => getPlugin()?.getFilter(field),\n\n getFilters: () => getPlugin()?.getFilters() ?? [],\n\n setFilterModel: (filters: FilterModel[], options?: { silent?: boolean }) => {\n const plugin = getPlugin();\n if (!plugin) {\n console.warn(\n `[tbw-grid:filtering] FilteringPlugin not found.\\n\\n` +\n ` → Enable filtering on the grid:\\n` +\n ` <tbw-grid [filtering]=\"true\" />`,\n );\n return;\n }\n plugin.setFilterModel(filters, options);\n },\n\n clearAllFilters: (options?: { silent?: boolean }) => {\n const plugin = getPlugin();\n if (!plugin) {\n console.warn(\n `[tbw-grid:filtering] FilteringPlugin not found.\\n\\n` +\n ` → Enable filtering on the grid:\\n` +\n ` <tbw-grid [filtering]=\"true\" />`,\n );\n return;\n }\n plugin.clearAllFilters(options);\n },\n\n clearFieldFilter: (field: string, options?: { silent?: boolean }) => {\n const plugin = getPlugin();\n if (!plugin) {\n console.warn(\n `[tbw-grid:filtering] FilteringPlugin not found.\\n\\n` +\n ` → Enable filtering on the grid:\\n` +\n ` <tbw-grid [filtering]=\"true\" />`,\n );\n return;\n }\n plugin.clearFieldFilter(field, options);\n },\n\n isFieldFiltered: (field: string) => getPlugin()?.isFieldFiltered(field) ?? false,\n\n getFilteredRowCount: () => getPlugin()?.getFilteredRowCount() ?? 0,\n\n getUniqueValues: (field: string) => getPlugin()?.getUniqueValues(field) ?? [],\n\n getStaleFilters: () => getPlugin()?.getStaleFilters() ?? [],\n\n getBlankMode: (field: string) => getPlugin()?.getBlankMode(field) ?? 'all',\n\n toggleBlankFilter: (field: string, mode: BlankMode) => {\n const plugin = getPlugin();\n if (!plugin) {\n console.warn(\n `[tbw-grid:filtering] FilteringPlugin not found.\\n\\n` +\n ` → Enable filtering on the grid:\\n` +\n ` <tbw-grid [filtering]=\"true\" />`,\n );\n return;\n }\n plugin.toggleBlankFilter(field, mode);\n },\n };\n}\n","/**\n * Generated bundle index. Do not edit.\n */\n\nexport * from './index';\n"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"toolbox-web-grid-angular-features-filtering.mjs","sources":["../../../../libs/grid-angular/features/filtering/src/grid-filtering.directive.ts","../../../../libs/grid-angular/features/filtering/src/base-filter-panel.ts","../../../../libs/grid-angular/features/filtering/src/index.ts","../../../../libs/grid-angular/features/filtering/src/toolbox-web-grid-angular-features-filtering.ts"],"sourcesContent":["/**\n * `GridFilteringDirective` — attribute-selector directive that owns the\n * `filtering` input and the `filterChange` output on `<tbw-grid>`.\n *\n * ## Why this exists\n *\n * Historically these bindings lived on the central `Grid` directive in\n * `@toolbox-web/grid-angular`. That meant the typed surface for the\n * filtering plugin shipped in the core bundle of every consumer, even those\n * that never imported the filtering feature. Moving them here lets the\n * surface tree-shake away with the rest of the feature when it is not\n * imported, matching the philosophy of the React / Vue adapters and the\n * web-component core (where unloaded plugins simply don't exist on the\n * element).\n *\n * ## Usage\n *\n * ```typescript\n * import { Component } from '@angular/core';\n * import { Grid } from '@toolbox-web/grid-angular';\n * import { GridFilteringDirective } from '@toolbox-web/grid-angular/features/filtering';\n *\n * @Component({\n * selector: 'app-grid',\n * imports: [Grid, GridFilteringDirective],\n * template: `\n * <tbw-grid [rows]=\"rows\" [filtering]=\"true\" (filterChange)=\"onFilter($event)\" />\n * `,\n * })\n * export class AppGridComponent {}\n * ```\n *\n * ## Feature claims\n *\n * The directive registers a per-grid feature claim (see\n * `internal/feature-claims.ts`), so `Grid` skips its own plugin creation and\n * event wiring for any feature that a per-feature directive has claimed.\n *\n * @category Directive\n */\nimport { Directive, ElementRef, inject, input, OnDestroy, OnInit, output, type Type } from '@angular/core';\nimport type { DataGridElement } from '@toolbox-web/grid';\nimport {\n claimEvent,\n registerFeatureClaim,\n unclaimEvent,\n unregisterFeatureClaim,\n type FilterPanel,\n} from '@toolbox-web/grid-angular';\nimport type { FilterConfig as CoreFilterConfig, FilterChangeDetail } from '@toolbox-web/grid/plugins/filtering';\n\n/**\n * Angular-specific filter config that allows an Angular component class as\n * the plugin-level `filterPanelRenderer`.\n *\n * Extends the core `FilterConfig` to accept a `Type<FilterPanel>` for\n * `filterPanelRenderer` in addition to the vanilla\n * `(container, params) => void` signature. Bridging to vanilla DOM is handled\n * by the side-effect import `@toolbox-web/grid-angular/features/filtering`.\n *\n * Re-exported from the feature entry under the same name as the core type\n * so Angular consumers see a single canonical `FilterConfig` from\n * `@toolbox-web/grid-angular/features/filtering`.\n *\n * @since 1.7.1\n */\n// eslint-disable-next-line @typescript-eslint/no-explicit-any\nexport type FilterConfig<TRow = any> = Omit<CoreFilterConfig<TRow>, 'filterPanelRenderer'> & {\n filterPanelRenderer?: CoreFilterConfig<TRow>['filterPanelRenderer'] | Type<FilterPanel>;\n};\n\n/**\n * Owns the `[filtering]` input and `(filterChange)` output on `<tbw-grid>`.\n *\n * Selector matches when *either* binding is present so users can pick the\n * style that suits their template — both go through the same claim and the\n * same wiring.\n * @category Directive\n */\n@Directive({\n selector: 'tbw-grid[filtering], tbw-grid[filterChange]',\n standalone: true,\n})\nexport class GridFilteringDirective implements OnInit, OnDestroy {\n private readonly elementRef = inject(ElementRef<DataGridElement>);\n\n /**\n * Enable column filtering.\n *\n * @example\n * ```html\n * <tbw-grid [filtering]=\"true\" />\n * <tbw-grid [filtering]=\"{ debounceMs: 200 }\" />\n * ```\n */\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\n readonly filtering = input<boolean | FilterConfig<any>>();\n\n /**\n * Emitted when filter values change.\n *\n * @example\n * ```html\n * <tbw-grid (filterChange)=\"onFilterChange($event)\" />\n * ```\n */\n readonly filterChange = output<FilterChangeDetail>();\n\n // Listener kept so we can detach in `ngOnDestroy`.\n private listener?: (e: Event) => void;\n\n constructor() {\n const grid = this.elementRef.nativeElement;\n // Tell `Grid` we own this feature's input. Reading `this.filtering()`\n // inside the getter establishes a reactive dependency in `Grid`'s\n // `createFeaturePlugins` effect — when our input changes, that effect\n // re-runs and the plugin config is updated.\n registerFeatureClaim(grid, 'filtering', () => this.filtering());\n // Tell `Grid` we own the matching event so it doesn't double-emit on\n // its own deprecated `filterChange` output.\n claimEvent(grid, 'filter-change');\n }\n\n ngOnInit(): void {\n const grid = this.elementRef.nativeElement;\n this.listener = (e: Event) => {\n this.filterChange.emit((e as CustomEvent<FilterChangeDetail>).detail);\n };\n grid.addEventListener('filter-change', this.listener);\n }\n\n ngOnDestroy(): void {\n const grid = this.elementRef.nativeElement;\n if (this.listener) {\n grid.removeEventListener('filter-change', this.listener);\n this.listener = undefined;\n }\n // Drop the claims so that, if the directive is removed via *ngIf but\n // the host `<tbw-grid>` survives, `Grid`'s deprecated bindings take\n // back over without leaving stale ownership behind.\n unregisterFeatureClaim(grid, 'filtering');\n unclaimEvent(grid, 'filter-change');\n }\n}\n","import { Directive, input } from '@angular/core';\nimport type { FilterPanel } from '@toolbox-web/grid-angular';\n\ntype FilterPanelParams = ReturnType<FilterPanel['params']>;\n\n/**\n * Base class for Angular filter panel components.\n *\n * Provides a ready-made `params` input and common lifecycle helpers\n * (`applyAndClose`, `clearAndClose`) so consumers only need to implement\n * their filter logic in `applyFilter()`.\n *\n * ## Usage\n *\n * ```typescript\n * import { Component, viewChild, ElementRef } from '@angular/core';\n * import { BaseFilterPanel } from '@toolbox-web/grid-angular/features/filtering';\n *\n * @Component({\n * selector: 'app-text-filter',\n * template: `\n * <input #input (keydown.enter)=\"applyAndClose()\" />\n * <button (click)=\"applyAndClose()\">Apply</button>\n * <button (click)=\"clearAndClose()\">Clear</button>\n * `\n * })\n * export class TextFilterComponent extends BaseFilterPanel {\n * input = viewChild.required<ElementRef<HTMLInputElement>>('input');\n *\n * applyFilter(): void {\n * this.params().applyTextFilter('contains', this.input().nativeElement.value);\n * }\n * }\n * ```\n *\n * ## Template Syntax\n *\n * The grid's filtering plugin will mount this component and provide `params`\n * automatically. No manual wiring is required:\n *\n * ```typescript\n * gridConfig = {\n * columns: [\n * { field: 'name', filterable: true, filterPanel: TextFilterComponent },\n * ],\n * };\n * ```\n *\n * @typeParam TRow - The row data type (available via `params().column`)\n *\n * @since 0.13.0\n */\n@Directive()\nexport abstract class BaseFilterPanel implements FilterPanel {\n /**\n * Filter panel parameters injected by the grid's filtering plugin.\n *\n * Provides access to:\n * - `field` — the column field name\n * - `column` — full column configuration\n * - `uniqueValues` — distinct values in the column\n * - `excludedValues` — currently excluded values (set filter)\n * - `searchText` — current search text\n * - `applySetFilter(excluded)` — apply a set-based (include/exclude) filter\n * - `applyTextFilter(operator, value, valueTo?)` — apply a text/number filter\n * - `clearFilter()` — clear the filter for this column\n * - `closePanel()` — close the filter panel\n */\n readonly params = input.required<FilterPanelParams>();\n\n /**\n * Implement this to apply your filter logic.\n *\n * Called by {@link applyAndClose} before closing the panel.\n * Use `this.params()` to access the filter API.\n *\n * @example\n * ```typescript\n * applyFilter(): void {\n * this.params().applyTextFilter('contains', this.searchText);\n * }\n * ```\n */\n abstract applyFilter(): void;\n\n /**\n * Apply the filter then close the panel.\n *\n * Calls {@link applyFilter} followed by `params().closePanel()`.\n * Bind this to your \"Apply\" button or Enter key handler.\n */\n applyAndClose(): void {\n this.applyFilter();\n this.params().closePanel();\n }\n\n /**\n * Clear the filter then close the panel.\n *\n * Calls `params().clearFilter()` followed by `params().closePanel()`.\n * Bind this to your \"Clear\" / \"Reset\" button.\n */\n clearAndClose(): void {\n this.params().clearFilter();\n this.params().closePanel();\n }\n}\n","/**\n * Filtering feature for @toolbox-web/grid-angular\n *\n * Add `GridFilteringDirective` to your component's `imports`. The directive\n * owns the `[filtering]` input and `(filterChange)` output, so the typed\n * surface tree-shakes away when the feature is not imported.\n *\n * `injectGridFiltering()` is available for programmatic control.\n *\n * @example Directive-owned binding\n * ```typescript\n * import { Grid } from '@toolbox-web/grid-angular';\n * import { GridFilteringDirective } from '@toolbox-web/grid-angular/features/filtering';\n *\n * @Component({\n * imports: [Grid, GridFilteringDirective],\n * template: `<tbw-grid [filtering]=\"true\" (filterChange)=\"onChange($event)\" />`,\n * })\n * ```\n *\n * @example Using injectGridFiltering\n * ```typescript\n * import { injectGridFiltering } from '@toolbox-web/grid-angular/features/filtering';\n *\n * @Component({...})\n * export class MyComponent {\n * private filtering = injectGridFiltering();\n *\n * filterByStatus(status: string) {\n * this.filtering.setFilter('status', { operator: 'equals', value: status });\n * }\n * }\n * ```\n *\n * @packageDocumentation\n */\n\nimport { afterNextRender, DestroyRef, ElementRef, inject, signal, type Signal, type Type } from '@angular/core';\nimport type { DataGridElement } from '@toolbox-web/grid';\nimport {\n isComponentClass,\n registerFeatureConfigPreprocessor,\n registerFilterPanelTypeDefaultBridge,\n type FilterPanel,\n type GridAdapter,\n} from '@toolbox-web/grid-angular';\nimport '@toolbox-web/grid/features/filtering';\nimport {\n FilteringPlugin,\n type BlankMode,\n type FilterConfig as CoreFilterConfig,\n type FilterModel,\n} from '@toolbox-web/grid/plugins/filtering';\nexport type { _Augmentation as _FilteringAugmentation } from '@toolbox-web/grid/features/filtering';\n\n// Attribute-selector directive that owns the `[filtering]` input and\n// `(filterChange)` output on `<tbw-grid>`. Add to your component's `imports`\n// alongside `Grid` to opt into the feature directly via the binding. The\n// matching deprecated bindings on `Grid` remain as a v1.x compatibility\n// shim and will be removed in v2.0.0.\nexport { GridFilteringDirective } from './grid-filtering.directive';\nexport type { FilterConfig } from './grid-filtering.directive';\n\n// `BaseFilterPanel` is filtering-specific (implements `FilterPanel` from the\n// filtering plugin) and physically lives in this secondary entry.\nexport { BaseFilterPanel } from './base-filter-panel';\n\ntype FilterPanelParams = ReturnType<FilterPanel['params']>;\n\n// Bridge any Angular component classes used as `filterPanelRenderer` (in\n// `gridConfig.typeDefaults` or via `provideGridTypeDefaults`) to the\n// `(container, params) => void` form required by FilteringPlugin. Without\n// this import, component-class filterPanelRenderers are silently dropped \\u2014\n// the same precondition as the FilteringPlugin itself (TBW031).\nregisterFilterPanelTypeDefaultBridge((rendererValue: unknown, adapter: GridAdapter) => {\n const componentClass = rendererValue as Type<unknown>;\n const mount = adapter.mountComponentRenderer<FilterPanelParams>(componentClass, (params) => ({ params }));\n return (container: HTMLElement, params: FilterPanelParams) => {\n container.appendChild(mount(params).hostElement);\n };\n});\n\n/**\n * Bridge an Angular component class used as the plugin-level\n * `filterPanelRenderer` (in `FilterConfig`) to the `(container, params) => void`\n * form required by FilteringPlugin. Mirrors `registerFilterPanelTypeDefaultBridge`\n * above, but for the plugin-wide renderer rather than per-type defaults.\n *\n * Without this preprocessor, passing a component class as\n * `filtering.filterPanelRenderer` would be invoked as a function at render\n * time and crash.\n *\n * @since 1.7.1\n */\nregisterFeatureConfigPreprocessor('filtering', (config, adapter) => {\n if (!config || typeof config === 'boolean' || typeof config !== 'object') return config;\n const cfg = config as CoreFilterConfig;\n if (!isComponentClass(cfg.filterPanelRenderer)) return config;\n\n type PluginFilterPanelRenderer = NonNullable<CoreFilterConfig['filterPanelRenderer']>;\n type PluginFilterPanelParams = Parameters<PluginFilterPanelRenderer>[1];\n\n const componentClass = cfg.filterPanelRenderer as Type<unknown>;\n const mount = adapter.mountComponentRenderer<PluginFilterPanelParams>(componentClass, (params) => ({ params }));\n const filterPanelRenderer: CoreFilterConfig['filterPanelRenderer'] = (container, params) => {\n container.appendChild(mount(params).hostElement);\n };\n return { ...cfg, filterPanelRenderer };\n});\n\n/**\n * Filtering methods returned from injectGridFiltering.\n *\n * Uses lazy discovery - the grid is found on first method call, not during initialization.\n */\nexport interface FilteringMethods {\n /**\n * Set a filter on a specific field.\n * @param field - The field name to filter\n * @param filter - Filter configuration, or null to remove\n * @param options - `{ silent: true }` applies the filter without emitting `filter-change`\n */\n setFilter: (field: string, filter: Omit<FilterModel, 'field'> | null, options?: { silent?: boolean }) => void;\n\n /**\n * Get the current filter for a field.\n */\n getFilter: (field: string) => FilterModel | undefined;\n\n /**\n * Get all active filters.\n */\n getFilters: () => FilterModel[];\n\n /**\n * Set all filters at once (replaces existing).\n * @param options - `{ silent: true }` applies filters without emitting `filter-change`\n */\n setFilterModel: (filters: FilterModel[], options?: { silent?: boolean }) => void;\n\n /**\n * Clear all active filters.\n * @param options - `{ silent: true }` clears filters without emitting `filter-change`\n */\n clearAllFilters: (options?: { silent?: boolean }) => void;\n\n /**\n * Clear filter for a specific field.\n * @param options - `{ silent: true }` clears filter without emitting `filter-change`\n */\n clearFieldFilter: (field: string, options?: { silent?: boolean }) => void;\n\n /**\n * Check if a field has an active filter.\n */\n isFieldFiltered: (field: string) => boolean;\n\n /**\n * Get the count of rows after filtering.\n */\n getFilteredRowCount: () => number;\n\n /**\n * Get unique values for a field (for building filter dropdowns).\n */\n getUniqueValues: (field: string) => unknown[];\n\n /**\n * Get set filters whose values no longer match any rows in the current data.\n */\n getStaleFilters: () => FilterModel[];\n\n /**\n * Get the current blank mode for a field.\n */\n getBlankMode: (field: string) => BlankMode;\n\n /**\n * Toggle blank filter mode for a field.\n */\n toggleBlankFilter: (field: string, mode: BlankMode) => void;\n\n /**\n * Signal indicating if grid is ready.\n */\n isReady: Signal<boolean>;\n}\n\n/**\n * Angular inject function for programmatic filter control.\n *\n * Uses **lazy grid discovery** - the grid element is found when methods are called,\n * not during initialization.\n *\n * @example\n * ```typescript\n * import { Component } from '@angular/core';\n * import { Grid } from '@toolbox-web/grid-angular';\n * import '@toolbox-web/grid-angular/features/filtering';\n * import { injectGridFiltering } from '@toolbox-web/grid-angular/features/filtering';\n *\n * @Component({\n * selector: 'app-my-grid',\n * imports: [Grid],\n * template: `\n * <input (input)=\"applyFilter($event)\" placeholder=\"Filter by name...\" />\n * <span>{{ filtering.getFilteredRowCount() }} results</span>\n * <button (click)=\"filtering.clearAllFilters()\">Clear</button>\n * <tbw-grid [rows]=\"rows\" [filtering]=\"true\"></tbw-grid>\n * `\n * })\n * export class MyGridComponent {\n * filtering = injectGridFiltering();\n *\n * applyFilter(event: Event) {\n * const value = (event.target as HTMLInputElement).value;\n * this.filtering.setFilter('name', value ? { operator: 'contains', value } : null);\n * }\n * }\n * ```\n *\n * @param selector - Optional CSS selector to target a specific grid element.\n * Defaults to `'tbw-grid'` (first grid in the component). Use when the\n * component contains multiple grids, e.g. `'tbw-grid.primary'` or `'#my-grid'`.\n */\nexport function injectGridFiltering(selector = 'tbw-grid'): FilteringMethods {\n const elementRef = inject(ElementRef);\n const destroyRef = inject(DestroyRef);\n const isReady = signal(false);\n\n let cachedGrid: DataGridElement | null = null;\n let readyPromiseStarted = false;\n\n const getGrid = (): DataGridElement | null => {\n if (cachedGrid) return cachedGrid;\n\n const grid = elementRef.nativeElement.querySelector(selector) as DataGridElement | null;\n if (grid) {\n cachedGrid = grid;\n if (!readyPromiseStarted) {\n readyPromiseStarted = true;\n grid.ready?.().then(() => {\n // If the plugin is already attached, signal readiness immediately.\n // Otherwise, Angular's Grid directive may not have applied gridConfig\n // yet (it uses effect + queueMicrotask). Defer to let pending\n // microtasks flush before signaling readiness.\n if (grid.getPluginByName('filtering')) {\n isReady.set(true);\n } else {\n setTimeout(() => isReady.set(true), 0);\n }\n });\n }\n }\n return grid;\n };\n\n const getPlugin = (): FilteringPlugin | undefined => {\n return getGrid()?.getPluginByName('filtering') as FilteringPlugin | undefined;\n };\n\n // Eagerly discover the grid after the first render so isReady updates\n // without requiring a programmatic method call. Falls back to a\n // MutationObserver for lazy-rendered tabs, *ngIf, @defer, etc.\n afterNextRender(() => {\n if (getGrid()) return;\n\n const host = elementRef.nativeElement as HTMLElement;\n const observer = new MutationObserver(() => {\n if (getGrid()) observer.disconnect();\n });\n observer.observe(host, { childList: true, subtree: true });\n\n destroyRef.onDestroy(() => observer.disconnect());\n });\n\n return {\n isReady: isReady.asReadonly(),\n\n setFilter: (field: string, filter: Omit<FilterModel, 'field'> | null, options?: { silent?: boolean }) => {\n const plugin = getPlugin();\n if (!plugin) {\n console.warn(\n `[tbw-grid:filtering] FilteringPlugin not found.\\n\\n` +\n ` → Enable filtering on the grid:\\n` +\n ` <tbw-grid [filtering]=\"true\" />`,\n );\n return;\n }\n plugin.setFilter(field, filter, options);\n },\n\n getFilter: (field: string) => getPlugin()?.getFilter(field),\n\n getFilters: () => getPlugin()?.getFilters() ?? [],\n\n setFilterModel: (filters: FilterModel[], options?: { silent?: boolean }) => {\n const plugin = getPlugin();\n if (!plugin) {\n console.warn(\n `[tbw-grid:filtering] FilteringPlugin not found.\\n\\n` +\n ` → Enable filtering on the grid:\\n` +\n ` <tbw-grid [filtering]=\"true\" />`,\n );\n return;\n }\n plugin.setFilterModel(filters, options);\n },\n\n clearAllFilters: (options?: { silent?: boolean }) => {\n const plugin = getPlugin();\n if (!plugin) {\n console.warn(\n `[tbw-grid:filtering] FilteringPlugin not found.\\n\\n` +\n ` → Enable filtering on the grid:\\n` +\n ` <tbw-grid [filtering]=\"true\" />`,\n );\n return;\n }\n plugin.clearAllFilters(options);\n },\n\n clearFieldFilter: (field: string, options?: { silent?: boolean }) => {\n const plugin = getPlugin();\n if (!plugin) {\n console.warn(\n `[tbw-grid:filtering] FilteringPlugin not found.\\n\\n` +\n ` → Enable filtering on the grid:\\n` +\n ` <tbw-grid [filtering]=\"true\" />`,\n );\n return;\n }\n plugin.clearFieldFilter(field, options);\n },\n\n isFieldFiltered: (field: string) => getPlugin()?.isFieldFiltered(field) ?? false,\n\n getFilteredRowCount: () => getPlugin()?.getFilteredRowCount() ?? 0,\n\n getUniqueValues: (field: string) => getPlugin()?.getUniqueValues(field) ?? [],\n\n getStaleFilters: () => getPlugin()?.getStaleFilters() ?? [],\n\n getBlankMode: (field: string) => getPlugin()?.getBlankMode(field) ?? 'all',\n\n toggleBlankFilter: (field: string, mode: BlankMode) => {\n const plugin = getPlugin();\n if (!plugin) {\n console.warn(\n `[tbw-grid:filtering] FilteringPlugin not found.\\n\\n` +\n ` → Enable filtering on the grid:\\n` +\n ` <tbw-grid [filtering]=\"true\" />`,\n );\n return;\n }\n plugin.toggleBlankFilter(field, mode);\n },\n };\n}\n","/**\n * Generated bundle index. Do not edit.\n */\n\nexport * from './index';\n"],"names":[],"mappings":"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"}
@@ -1 +1 @@
1
- {"version":3,"file":"toolbox-web-grid-angular-features-grouping-columns.mjs","sources":["../../../../libs/grid-angular/features/grouping-columns/src/grid-grouping-columns.directive.ts","../../../../libs/grid-angular/features/grouping-columns/src/index.ts","../../../../libs/grid-angular/features/grouping-columns/src/toolbox-web-grid-angular-features-grouping-columns.ts"],"sourcesContent":["/**\n * `GridGroupingColumnsDirective` — owns `[groupingColumns]` on\n * `<tbw-grid>`. No event outputs. See `GridFilteringDirective` for the\n * full rationale.\n *\n * @category Directive\n */\nimport { Directive, ElementRef, inject, input, OnDestroy, type Type } from '@angular/core';\nimport type { DataGridElement } from '@toolbox-web/grid';\nimport { registerFeatureClaim, unregisterFeatureClaim } from '@toolbox-web/grid-angular';\nimport type {\n ColumnGroupDefinition as CoreColumnGroupDefinition,\n GroupingColumnsConfig as CoreGroupingColumnsConfig,\n GroupHeaderRenderParams,\n} from '@toolbox-web/grid/plugins/grouping-columns';\n\n/**\n * Column group definition widened to accept an Angular component class as\n * the per-group `renderer`.\n *\n * @since 1.7.0\n */\nexport type ColumnGroupDefinition = Omit<CoreColumnGroupDefinition, 'renderer'> & {\n renderer?: CoreColumnGroupDefinition['renderer'] | Type<unknown>;\n};\n\n/**\n * Grouping-columns config widened to accept Angular component classes for\n * `groupHeaderRenderer` and per-group `renderer` inside `columnGroups`.\n *\n * Component instances receive the {@link GroupHeaderRenderParams} fields as\n * inputs (`id`, `label`, `columns`, `firstIndex`, `isImplicit`).\n *\n * @since 1.7.0\n */\nexport type GroupingColumnsConfig = Omit<CoreGroupingColumnsConfig, 'groupHeaderRenderer' | 'columnGroups'> & {\n columnGroups?: ColumnGroupDefinition[];\n groupHeaderRenderer?: CoreGroupingColumnsConfig['groupHeaderRenderer'] | Type<unknown>;\n};\n\n// ── Deprecated framework-prefixed aliases ────────────────────────────────\n// Retained for backwards compatibility. New code should use the canonical\n// (unprefixed) names above.\n\n/** @deprecated Use {@link ColumnGroupDefinition} instead. */\nexport type AngularColumnGroupDefinition = ColumnGroupDefinition;\n/** @deprecated Use {@link GroupingColumnsConfig} instead. */\nexport type AngularGroupingColumnsConfig = GroupingColumnsConfig;\n\n/**\n * Owns the binding(s) `[groupingColumns]` on `<tbw-grid>` for the matching feature plugin. See `GridFilteringDirective` for the full rationale.\n *\n * @category Directive\n */\n@Directive({\n selector: 'tbw-grid[groupingColumns]',\n standalone: true,\n})\nexport class GridGroupingColumnsDirective implements OnDestroy {\n private readonly elementRef = inject(ElementRef<DataGridElement>);\n\n readonly groupingColumns = input<boolean | GroupingColumnsConfig>();\n\n constructor() {\n registerFeatureClaim(this.elementRef.nativeElement, 'groupingColumns', () => this.groupingColumns());\n }\n\n ngOnDestroy(): void {\n unregisterFeatureClaim(this.elementRef.nativeElement, 'groupingColumns');\n }\n}\n","/**\n * Column grouping feature for @toolbox-web/grid-angular\n *\n * Import this module to enable the `groupingColumns` input on Grid directive.\n *\n * @example\n * ```typescript\n * import '@toolbox-web/grid-angular/features/grouping-columns';\n *\n * <tbw-grid [groupingColumns]=\"{ columnGroups: [...] }\" />\n * ```\n *\n * @packageDocumentation\n */\n\nimport type { Type } from '@angular/core';\nimport { isComponentClass, registerFeatureConfigPreprocessor, type GridAdapter } from '@toolbox-web/grid-angular';\nimport '@toolbox-web/grid/features/grouping-columns';\nimport type {\n GroupingColumnsConfig as CoreGroupingColumnsConfig,\n GroupHeaderRenderParams,\n} from '@toolbox-web/grid/plugins/grouping-columns';\nexport {\n GridGroupingColumnsDirective,\n // Deprecated framework-prefixed aliases.\n type AngularColumnGroupDefinition,\n type AngularGroupingColumnsConfig,\n // Canonical (unprefixed) widening types.\n type ColumnGroupDefinition,\n type GroupingColumnsConfig,\n} from './grid-grouping-columns.directive';\nexport type { _Augmentation as _GroupingColumnsAugmentation } from '@toolbox-web/grid/features/grouping-columns';\n\n/**\n * Build a group-header renderer function from an Angular component class.\n * The component should accept group header inputs (id, label, columns, firstIndex, isImplicit).\n */\nfunction buildGroupHeaderRenderer(\n adapter: GridAdapter,\n componentClass: Type<unknown>,\n): (params: GroupHeaderRenderParams) => HTMLElement {\n const mount = adapter.mountComponentRenderer<GroupHeaderRenderParams>(componentClass, (p) => ({\n id: p.id,\n label: p.label,\n columns: p.columns,\n firstIndex: p.firstIndex,\n isImplicit: p.isImplicit,\n }));\n return (params) => mount(params).hostElement;\n}\n\n// Bridge any Angular component classes embedded in the user-supplied config\n// (e.g. group-header renderers) to plain renderer functions before the core\n// plugin factory consumes the config. Without this, raw component classes\n// would be invoked without `new`, causing runtime errors.\nregisterFeatureConfigPreprocessor('groupingColumns', (config, adapter) => {\n if (!config || typeof config !== 'object') return config;\n const cfg = config as CoreGroupingColumnsConfig;\n const processed = { ...cfg };\n let changed = false;\n\n // Bridge top-level groupHeaderRenderer component class\n if (cfg.groupHeaderRenderer && isComponentClass(cfg.groupHeaderRenderer)) {\n processed.groupHeaderRenderer = buildGroupHeaderRenderer(adapter, cfg.groupHeaderRenderer);\n changed = true;\n }\n\n // Bridge per-group renderer component classes inside columnGroups\n if (Array.isArray(cfg.columnGroups)) {\n let groupChanged = false;\n const mappedGroups = cfg.columnGroups.map((def) => {\n if (def.renderer && isComponentClass(def.renderer)) {\n groupChanged = true;\n return { ...def, renderer: buildGroupHeaderRenderer(adapter, def.renderer) };\n }\n return def;\n });\n if (groupChanged) {\n processed.columnGroups = mappedGroups;\n changed = true;\n }\n }\n\n return changed ? processed : cfg;\n});\n","/**\n * Generated bundle index. Do not edit.\n */\n\nexport * from './index';\n"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"toolbox-web-grid-angular-features-grouping-columns.mjs","sources":["../../../../libs/grid-angular/features/grouping-columns/src/grid-grouping-columns.directive.ts","../../../../libs/grid-angular/features/grouping-columns/src/index.ts","../../../../libs/grid-angular/features/grouping-columns/src/toolbox-web-grid-angular-features-grouping-columns.ts"],"sourcesContent":["/**\n * `GridGroupingColumnsDirective` — owns `[groupingColumns]` on\n * `<tbw-grid>`. No event outputs. See `GridFilteringDirective` for the\n * full rationale.\n *\n * @category Directive\n */\nimport { Directive, ElementRef, inject, input, OnDestroy, type Type } from '@angular/core';\nimport type { DataGridElement } from '@toolbox-web/grid';\nimport { registerFeatureClaim, unregisterFeatureClaim } from '@toolbox-web/grid-angular';\nimport type {\n ColumnGroupDefinition as CoreColumnGroupDefinition,\n GroupingColumnsConfig as CoreGroupingColumnsConfig,\n GroupHeaderRenderParams,\n} from '@toolbox-web/grid/plugins/grouping-columns';\n\n/**\n * Column group definition widened to accept an Angular component class as\n * the per-group `renderer`.\n *\n * @since 1.7.0\n */\nexport type ColumnGroupDefinition = Omit<CoreColumnGroupDefinition, 'renderer'> & {\n renderer?: CoreColumnGroupDefinition['renderer'] | Type<unknown>;\n};\n\n/**\n * Grouping-columns config widened to accept Angular component classes for\n * `groupHeaderRenderer` and per-group `renderer` inside `columnGroups`.\n *\n * Component instances receive the {@link GroupHeaderRenderParams} fields as\n * inputs (`id`, `label`, `columns`, `firstIndex`, `isImplicit`).\n *\n * @since 1.7.0\n */\nexport type GroupingColumnsConfig = Omit<CoreGroupingColumnsConfig, 'groupHeaderRenderer' | 'columnGroups'> & {\n columnGroups?: ColumnGroupDefinition[];\n groupHeaderRenderer?: CoreGroupingColumnsConfig['groupHeaderRenderer'] | Type<unknown>;\n};\n\n/**\n * Owns the binding(s) `[groupingColumns]` on `<tbw-grid>` for the matching feature plugin. See `GridFilteringDirective` for the full rationale.\n *\n * @category Directive\n */\n@Directive({\n selector: 'tbw-grid[groupingColumns]',\n standalone: true,\n})\nexport class GridGroupingColumnsDirective implements OnDestroy {\n private readonly elementRef = inject(ElementRef<DataGridElement>);\n\n readonly groupingColumns = input<boolean | GroupingColumnsConfig>();\n\n constructor() {\n registerFeatureClaim(this.elementRef.nativeElement, 'groupingColumns', () => this.groupingColumns());\n }\n\n ngOnDestroy(): void {\n unregisterFeatureClaim(this.elementRef.nativeElement, 'groupingColumns');\n }\n}\n","/**\n * Column grouping feature for @toolbox-web/grid-angular\n *\n * Import this module to enable the `groupingColumns` input on Grid directive.\n *\n * @example\n * ```typescript\n * import '@toolbox-web/grid-angular/features/grouping-columns';\n *\n * <tbw-grid [groupingColumns]=\"{ columnGroups: [...] }\" />\n * ```\n *\n * @packageDocumentation\n */\n\nimport type { Type } from '@angular/core';\nimport { isComponentClass, registerFeatureConfigPreprocessor, type GridAdapter } from '@toolbox-web/grid-angular';\nimport '@toolbox-web/grid/features/grouping-columns';\nimport type {\n GroupingColumnsConfig as CoreGroupingColumnsConfig,\n GroupHeaderRenderParams,\n} from '@toolbox-web/grid/plugins/grouping-columns';\nexport {\n GridGroupingColumnsDirective,\n // Canonical (unprefixed) widening types.\n type ColumnGroupDefinition,\n type GroupingColumnsConfig,\n} from './grid-grouping-columns.directive';\nexport type { _Augmentation as _GroupingColumnsAugmentation } from '@toolbox-web/grid/features/grouping-columns';\n\n/**\n * Build a group-header renderer function from an Angular component class.\n * The component should accept group header inputs (id, label, columns, firstIndex, isImplicit).\n */\nfunction buildGroupHeaderRenderer(\n adapter: GridAdapter,\n componentClass: Type<unknown>,\n): (params: GroupHeaderRenderParams) => HTMLElement {\n const mount = adapter.mountComponentRenderer<GroupHeaderRenderParams>(componentClass, (p) => ({\n id: p.id,\n label: p.label,\n columns: p.columns,\n firstIndex: p.firstIndex,\n isImplicit: p.isImplicit,\n }));\n return (params) => mount(params).hostElement;\n}\n\n// Bridge any Angular component classes embedded in the user-supplied config\n// (e.g. group-header renderers) to plain renderer functions before the core\n// plugin factory consumes the config. Without this, raw component classes\n// would be invoked without `new`, causing runtime errors.\nregisterFeatureConfigPreprocessor('groupingColumns', (config, adapter) => {\n if (!config || typeof config !== 'object') return config;\n const cfg = config as CoreGroupingColumnsConfig;\n const processed = { ...cfg };\n let changed = false;\n\n // Bridge top-level groupHeaderRenderer component class\n if (cfg.groupHeaderRenderer && isComponentClass(cfg.groupHeaderRenderer)) {\n processed.groupHeaderRenderer = buildGroupHeaderRenderer(adapter, cfg.groupHeaderRenderer);\n changed = true;\n }\n\n // Bridge per-group renderer component classes inside columnGroups\n if (Array.isArray(cfg.columnGroups)) {\n let groupChanged = false;\n const mappedGroups = cfg.columnGroups.map((def) => {\n if (def.renderer && isComponentClass(def.renderer)) {\n groupChanged = true;\n return { ...def, renderer: buildGroupHeaderRenderer(adapter, def.renderer) };\n }\n return def;\n });\n if (groupChanged) {\n processed.columnGroups = mappedGroups;\n changed = true;\n }\n }\n\n return changed ? processed : cfg;\n});\n","/**\n * Generated bundle index. Do not edit.\n */\n\nexport * from './index';\n"],"names":[],"mappings":";;;;;AAAA;;;;;;AAMG;AAkCH;;;;AAIG;MAKU,4BAA4B,CAAA;AACtB,IAAA,UAAU,GAAG,MAAM,EAAC,UAA2B,EAAC;AAExD,IAAA,eAAe,GAAG,KAAK;mGAAmC;AAEnE,IAAA,WAAA,GAAA;AACE,QAAA,oBAAoB,CAAC,IAAI,CAAC,UAAU,CAAC,aAAa,EAAE,iBAAiB,EAAE,MAAM,IAAI,CAAC,eAAe,EAAE,CAAC;IACtG;IAEA,WAAW,GAAA;QACT,sBAAsB,CAAC,IAAI,CAAC,UAAU,CAAC,aAAa,EAAE,iBAAiB,CAAC;IAC1E;uGAXW,4BAA4B,EAAA,IAAA,EAAA,EAAA,EAAA,MAAA,EAAA,EAAA,CAAA,eAAA,CAAA,SAAA,EAAA,CAAA;2FAA5B,4BAA4B,EAAA,YAAA,EAAA,IAAA,EAAA,QAAA,EAAA,2BAAA,EAAA,MAAA,EAAA,EAAA,eAAA,EAAA,EAAA,iBAAA,EAAA,iBAAA,EAAA,UAAA,EAAA,iBAAA,EAAA,QAAA,EAAA,IAAA,EAAA,UAAA,EAAA,KAAA,EAAA,iBAAA,EAAA,IAAA,EAAA,EAAA,EAAA,QAAA,EAAA,EAAA,EAAA,CAAA;;2FAA5B,4BAA4B,EAAA,UAAA,EAAA,CAAA;kBAJxC,SAAS;AAAC,YAAA,IAAA,EAAA,CAAA;AACT,oBAAA,QAAQ,EAAE,2BAA2B;AACrC,oBAAA,UAAU,EAAE,IAAI;AACjB,iBAAA;;;AChDD;;;;;;;;;;;;;AAaG;AAiBH;;;AAGG;AACH,SAAS,wBAAwB,CAC/B,OAAoB,EACpB,cAA6B,EAAA;AAE7B,IAAA,MAAM,KAAK,GAAG,OAAO,CAAC,sBAAsB,CAA0B,cAAc,EAAE,CAAC,CAAC,MAAM;QAC5F,EAAE,EAAE,CAAC,CAAC,EAAE;QACR,KAAK,EAAE,CAAC,CAAC,KAAK;QACd,OAAO,EAAE,CAAC,CAAC,OAAO;QAClB,UAAU,EAAE,CAAC,CAAC,UAAU;QACxB,UAAU,EAAE,CAAC,CAAC,UAAU;AACzB,KAAA,CAAC,CAAC;IACH,OAAO,CAAC,MAAM,KAAK,KAAK,CAAC,MAAM,CAAC,CAAC,WAAW;AAC9C;AAEA;AACA;AACA;AACA;AACA,iCAAiC,CAAC,iBAAiB,EAAE,CAAC,MAAM,EAAE,OAAO,KAAI;AACvE,IAAA,IAAI,CAAC,MAAM,IAAI,OAAO,MAAM,KAAK,QAAQ;AAAE,QAAA,OAAO,MAAM;IACxD,MAAM,GAAG,GAAG,MAAmC;AAC/C,IAAA,MAAM,SAAS,GAAG,EAAE,GAAG,GAAG,EAAE;IAC5B,IAAI,OAAO,GAAG,KAAK;;IAGnB,IAAI,GAAG,CAAC,mBAAmB,IAAI,gBAAgB,CAAC,GAAG,CAAC,mBAAmB,CAAC,EAAE;QACxE,SAAS,CAAC,mBAAmB,GAAG,wBAAwB,CAAC,OAAO,EAAE,GAAG,CAAC,mBAAmB,CAAC;QAC1F,OAAO,GAAG,IAAI;IAChB;;IAGA,IAAI,KAAK,CAAC,OAAO,CAAC,GAAG,CAAC,YAAY,CAAC,EAAE;QACnC,IAAI,YAAY,GAAG,KAAK;QACxB,MAAM,YAAY,GAAG,GAAG,CAAC,YAAY,CAAC,GAAG,CAAC,CAAC,GAAG,KAAI;YAChD,IAAI,GAAG,CAAC,QAAQ,IAAI,gBAAgB,CAAC,GAAG,CAAC,QAAQ,CAAC,EAAE;gBAClD,YAAY,GAAG,IAAI;AACnB,gBAAA,OAAO,EAAE,GAAG,GAAG,EAAE,QAAQ,EAAE,wBAAwB,CAAC,OAAO,EAAE,GAAG,CAAC,QAAQ,CAAC,EAAE;YAC9E;AACA,YAAA,OAAO,GAAG;AACZ,QAAA,CAAC,CAAC;QACF,IAAI,YAAY,EAAE;AAChB,YAAA,SAAS,CAAC,YAAY,GAAG,YAAY;YACrC,OAAO,GAAG,IAAI;QAChB;IACF;IAEA,OAAO,OAAO,GAAG,SAAS,GAAG,GAAG;AAClC,CAAC,CAAC;;ACjFF;;AAEG;;;;"}
@@ -1 +1 @@
1
- {"version":3,"file":"toolbox-web-grid-angular-features-grouping-rows.mjs","sources":["../../../../libs/grid-angular/features/grouping-rows/src/grid-grouping-rows.directive.ts","../../../../libs/grid-angular/features/grouping-rows/src/index.ts","../../../../libs/grid-angular/features/grouping-rows/src/toolbox-web-grid-angular-features-grouping-rows.ts"],"sourcesContent":["/**\n * `GridGroupingRowsDirective` — owns `[groupingRows]` and the group\n * toggle/expand/collapse outputs on `<tbw-grid>`. See\n * `GridFilteringDirective` for the full rationale.\n *\n * @category Directive\n */\nimport { Directive, ElementRef, inject, input, OnDestroy, OnInit, output, type Type } from '@angular/core';\nimport type { DataGridElement } from '@toolbox-web/grid';\nimport { claimEvent, registerFeatureClaim, unclaimEvent, unregisterFeatureClaim } from '@toolbox-web/grid-angular';\nimport type {\n GroupingRowsConfig as CoreGroupingRowsConfig,\n GroupCollapseDetail,\n GroupExpandDetail,\n GroupRowRenderParams,\n GroupToggleDetail,\n} from '@toolbox-web/grid/plugins/grouping-rows';\n\n/**\n * Grouping-rows config widened to accept an Angular component class as\n * `groupRowRenderer`.\n *\n * Component instances receive the {@link GroupRowRenderParams} fields as\n * inputs (`key`, `value`, `depth`, `rows`, `expanded`, `toggleExpand`).\n *\n * @since 1.7.0\n */\nexport type GroupingRowsConfig = Omit<CoreGroupingRowsConfig, 'groupRowRenderer'> & {\n groupRowRenderer?: CoreGroupingRowsConfig['groupRowRenderer'] | Type<unknown>;\n};\n\n// ── Deprecated framework-prefixed alias ─────────────────────────────────\n/** @deprecated Use {@link GroupingRowsConfig} instead. */\nexport type AngularGroupingRowsConfig = GroupingRowsConfig;\n\n/**\n * Owns the binding(s) `[groupingRows], [groupToggle], [groupExpand], [groupCollapse]` on `<tbw-grid>` for the matching feature plugin. See `GridFilteringDirective` for the full rationale.\n *\n * @category Directive\n */\n@Directive({\n selector: 'tbw-grid[groupingRows], tbw-grid[groupToggle], tbw-grid[groupExpand], tbw-grid[groupCollapse]',\n standalone: true,\n})\nexport class GridGroupingRowsDirective implements OnInit, OnDestroy {\n private readonly elementRef = inject(ElementRef<DataGridElement>);\n\n readonly groupingRows = input<GroupingRowsConfig>();\n readonly groupToggle = output<GroupToggleDetail>();\n readonly groupExpand = output<GroupExpandDetail>();\n readonly groupCollapse = output<GroupCollapseDetail>();\n\n private readonly listeners = new Map<string, (e: Event) => void>();\n private static readonly EVENTS = ['group-toggle', 'group-expand', 'group-collapse'] as const;\n\n constructor() {\n const grid = this.elementRef.nativeElement;\n registerFeatureClaim(grid, 'groupingRows', () => this.groupingRows());\n for (const ev of GridGroupingRowsDirective.EVENTS) claimEvent(grid, ev);\n }\n\n ngOnInit(): void {\n const grid = this.elementRef.nativeElement;\n const wire = <T>(name: string, out: { emit: (v: T) => void }): void => {\n const l = (e: Event): void => out.emit((e as CustomEvent<T>).detail);\n grid.addEventListener(name, l);\n this.listeners.set(name, l);\n };\n wire<GroupToggleDetail>('group-toggle', this.groupToggle);\n wire<GroupExpandDetail>('group-expand', this.groupExpand);\n wire<GroupCollapseDetail>('group-collapse', this.groupCollapse);\n }\n\n ngOnDestroy(): void {\n const grid = this.elementRef.nativeElement;\n for (const [name, l] of this.listeners) grid.removeEventListener(name, l);\n this.listeners.clear();\n unregisterFeatureClaim(grid, 'groupingRows');\n for (const ev of GridGroupingRowsDirective.EVENTS) unclaimEvent(grid, ev);\n }\n}\n","/**\n * Row grouping feature for @toolbox-web/grid-angular\n *\n * Import this module to enable the `groupingRows` input on Grid directive.\n *\n * @example\n * ```typescript\n * import '@toolbox-web/grid-angular/features/grouping-rows';\n *\n * <tbw-grid [groupingRows]=\"{ groupBy: ['department'] }\" />\n * ```\n *\n * @packageDocumentation\n */\n\nimport { isComponentClass, registerFeatureConfigPreprocessor } from '@toolbox-web/grid-angular';\nimport '@toolbox-web/grid/features/grouping-rows';\nimport type {\n GroupingRowsConfig as CoreGroupingRowsConfig,\n GroupRowRenderParams,\n} from '@toolbox-web/grid/plugins/grouping-rows';\nexport {\n GridGroupingRowsDirective,\n type AngularGroupingRowsConfig,\n type GroupingRowsConfig,\n} from './grid-grouping-rows.directive';\nexport type { _Augmentation as _GroupingRowsAugmentation } from '@toolbox-web/grid/features/grouping-rows';\n\n// Bridge any Angular component classes embedded in the user-supplied config\n// (e.g. group-row renderer) to plain renderer functions before the core\n// plugin factory consumes the config.\nregisterFeatureConfigPreprocessor('groupingRows', (config, adapter) => {\n if (!config || typeof config !== 'object') return config;\n const cfg = config as CoreGroupingRowsConfig;\n if (cfg.groupRowRenderer && isComponentClass(cfg.groupRowRenderer)) {\n const mount = adapter.mountComponentRenderer<GroupRowRenderParams>(cfg.groupRowRenderer, (p) => ({\n key: p.key,\n value: p.value,\n depth: p.depth,\n rows: p.rows,\n expanded: p.expanded,\n toggleExpand: p.toggleExpand,\n }));\n return { ...cfg, groupRowRenderer: (params: GroupRowRenderParams) => mount(params).hostElement };\n }\n return cfg;\n});\n","/**\n * Generated bundle index. Do not edit.\n */\n\nexport * from './index';\n"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"toolbox-web-grid-angular-features-grouping-rows.mjs","sources":["../../../../libs/grid-angular/features/grouping-rows/src/grid-grouping-rows.directive.ts","../../../../libs/grid-angular/features/grouping-rows/src/index.ts","../../../../libs/grid-angular/features/grouping-rows/src/toolbox-web-grid-angular-features-grouping-rows.ts"],"sourcesContent":["/**\n * `GridGroupingRowsDirective` — owns `[groupingRows]` and the group\n * toggle/expand/collapse outputs on `<tbw-grid>`. See\n * `GridFilteringDirective` for the full rationale.\n *\n * @category Directive\n */\nimport { Directive, ElementRef, inject, input, OnDestroy, OnInit, output, type Type } from '@angular/core';\nimport type { DataGridElement } from '@toolbox-web/grid';\nimport { claimEvent, registerFeatureClaim, unclaimEvent, unregisterFeatureClaim } from '@toolbox-web/grid-angular';\nimport type {\n GroupingRowsConfig as CoreGroupingRowsConfig,\n GroupCollapseDetail,\n GroupExpandDetail,\n GroupRowRenderParams,\n GroupToggleDetail,\n} from '@toolbox-web/grid/plugins/grouping-rows';\n\n/**\n * Grouping-rows config widened to accept an Angular component class as\n * `groupRowRenderer`.\n *\n * Component instances receive the {@link GroupRowRenderParams} fields as\n * inputs (`key`, `value`, `depth`, `rows`, `expanded`, `toggleExpand`).\n *\n * @since 1.7.0\n */\nexport type GroupingRowsConfig = Omit<CoreGroupingRowsConfig, 'groupRowRenderer'> & {\n groupRowRenderer?: CoreGroupingRowsConfig['groupRowRenderer'] | Type<unknown>;\n};\n\n/**\n * Owns the binding(s) `[groupingRows], [groupToggle], [groupExpand], [groupCollapse]` on `<tbw-grid>` for the matching feature plugin. See `GridFilteringDirective` for the full rationale.\n *\n * @category Directive\n */\n@Directive({\n selector: 'tbw-grid[groupingRows], tbw-grid[groupToggle], tbw-grid[groupExpand], tbw-grid[groupCollapse]',\n standalone: true,\n})\nexport class GridGroupingRowsDirective implements OnInit, OnDestroy {\n private readonly elementRef = inject(ElementRef<DataGridElement>);\n\n readonly groupingRows = input<GroupingRowsConfig>();\n readonly groupToggle = output<GroupToggleDetail>();\n readonly groupExpand = output<GroupExpandDetail>();\n readonly groupCollapse = output<GroupCollapseDetail>();\n\n private readonly listeners = new Map<string, (e: Event) => void>();\n private static readonly EVENTS = ['group-toggle', 'group-expand', 'group-collapse'] as const;\n\n constructor() {\n const grid = this.elementRef.nativeElement;\n registerFeatureClaim(grid, 'groupingRows', () => this.groupingRows());\n for (const ev of GridGroupingRowsDirective.EVENTS) claimEvent(grid, ev);\n }\n\n ngOnInit(): void {\n const grid = this.elementRef.nativeElement;\n const wire = <T>(name: string, out: { emit: (v: T) => void }): void => {\n const l = (e: Event): void => out.emit((e as CustomEvent<T>).detail);\n grid.addEventListener(name, l);\n this.listeners.set(name, l);\n };\n wire<GroupToggleDetail>('group-toggle', this.groupToggle);\n wire<GroupExpandDetail>('group-expand', this.groupExpand);\n wire<GroupCollapseDetail>('group-collapse', this.groupCollapse);\n }\n\n ngOnDestroy(): void {\n const grid = this.elementRef.nativeElement;\n for (const [name, l] of this.listeners) grid.removeEventListener(name, l);\n this.listeners.clear();\n unregisterFeatureClaim(grid, 'groupingRows');\n for (const ev of GridGroupingRowsDirective.EVENTS) unclaimEvent(grid, ev);\n }\n}\n","/**\n * Row grouping feature for @toolbox-web/grid-angular\n *\n * Import this module to enable the `groupingRows` input on Grid directive.\n *\n * @example\n * ```typescript\n * import '@toolbox-web/grid-angular/features/grouping-rows';\n *\n * <tbw-grid [groupingRows]=\"{ groupBy: ['department'] }\" />\n * ```\n *\n * @packageDocumentation\n */\n\nimport { isComponentClass, registerFeatureConfigPreprocessor } from '@toolbox-web/grid-angular';\nimport '@toolbox-web/grid/features/grouping-rows';\nimport type {\n GroupingRowsConfig as CoreGroupingRowsConfig,\n GroupRowRenderParams,\n} from '@toolbox-web/grid/plugins/grouping-rows';\nexport { GridGroupingRowsDirective, type GroupingRowsConfig } from './grid-grouping-rows.directive';\nexport type { _Augmentation as _GroupingRowsAugmentation } from '@toolbox-web/grid/features/grouping-rows';\n\n// Bridge any Angular component classes embedded in the user-supplied config\n// (e.g. group-row renderer) to plain renderer functions before the core\n// plugin factory consumes the config.\nregisterFeatureConfigPreprocessor('groupingRows', (config, adapter) => {\n if (!config || typeof config !== 'object') return config;\n const cfg = config as CoreGroupingRowsConfig;\n if (cfg.groupRowRenderer && isComponentClass(cfg.groupRowRenderer)) {\n const mount = adapter.mountComponentRenderer<GroupRowRenderParams>(cfg.groupRowRenderer, (p) => ({\n key: p.key,\n value: p.value,\n depth: p.depth,\n rows: p.rows,\n expanded: p.expanded,\n toggleExpand: p.toggleExpand,\n }));\n return { ...cfg, groupRowRenderer: (params: GroupRowRenderParams) => mount(params).hostElement };\n }\n return cfg;\n});\n","/**\n * Generated bundle index. Do not edit.\n */\n\nexport * from './index';\n"],"names":[],"mappings":";;;;;AAAA;;;;;;AAMG;AAyBH;;;;AAIG;MAKU,yBAAyB,CAAA;AACnB,IAAA,UAAU,GAAG,MAAM,EAAC,UAA2B,EAAC;AAExD,IAAA,YAAY,GAAG,KAAK;gGAAsB;IAC1C,WAAW,GAAG,MAAM,EAAqB;IACzC,WAAW,GAAG,MAAM,EAAqB;IACzC,aAAa,GAAG,MAAM,EAAuB;AAErC,IAAA,SAAS,GAAG,IAAI,GAAG,EAA8B;IAC1D,OAAgB,MAAM,GAAG,CAAC,cAAc,EAAE,cAAc,EAAE,gBAAgB,CAAU;AAE5F,IAAA,WAAA,GAAA;AACE,QAAA,MAAM,IAAI,GAAG,IAAI,CAAC,UAAU,CAAC,aAAa;AAC1C,QAAA,oBAAoB,CAAC,IAAI,EAAE,cAAc,EAAE,MAAM,IAAI,CAAC,YAAY,EAAE,CAAC;AACrE,QAAA,KAAK,MAAM,EAAE,IAAI,yBAAyB,CAAC,MAAM;AAAE,YAAA,UAAU,CAAC,IAAI,EAAE,EAAE,CAAC;IACzE;IAEA,QAAQ,GAAA;AACN,QAAA,MAAM,IAAI,GAAG,IAAI,CAAC,UAAU,CAAC,aAAa;AAC1C,QAAA,MAAM,IAAI,GAAG,CAAI,IAAY,EAAE,GAA6B,KAAU;AACpE,YAAA,MAAM,CAAC,GAAG,CAAC,CAAQ,KAAW,GAAG,CAAC,IAAI,CAAE,CAAoB,CAAC,MAAM,CAAC;AACpE,YAAA,IAAI,CAAC,gBAAgB,CAAC,IAAI,EAAE,CAAC,CAAC;YAC9B,IAAI,CAAC,SAAS,CAAC,GAAG,CAAC,IAAI,EAAE,CAAC,CAAC;AAC7B,QAAA,CAAC;AACD,QAAA,IAAI,CAAoB,cAAc,EAAE,IAAI,CAAC,WAAW,CAAC;AACzD,QAAA,IAAI,CAAoB,cAAc,EAAE,IAAI,CAAC,WAAW,CAAC;AACzD,QAAA,IAAI,CAAsB,gBAAgB,EAAE,IAAI,CAAC,aAAa,CAAC;IACjE;IAEA,WAAW,GAAA;AACT,QAAA,MAAM,IAAI,GAAG,IAAI,CAAC,UAAU,CAAC,aAAa;QAC1C,KAAK,MAAM,CAAC,IAAI,EAAE,CAAC,CAAC,IAAI,IAAI,CAAC,SAAS;AAAE,YAAA,IAAI,CAAC,mBAAmB,CAAC,IAAI,EAAE,CAAC,CAAC;AACzE,QAAA,IAAI,CAAC,SAAS,CAAC,KAAK,EAAE;AACtB,QAAA,sBAAsB,CAAC,IAAI,EAAE,cAAc,CAAC;AAC5C,QAAA,KAAK,MAAM,EAAE,IAAI,yBAAyB,CAAC,MAAM;AAAE,YAAA,YAAY,CAAC,IAAI,EAAE,EAAE,CAAC;IAC3E;uGAnCW,yBAAyB,EAAA,IAAA,EAAA,EAAA,EAAA,MAAA,EAAA,EAAA,CAAA,eAAA,CAAA,SAAA,EAAA,CAAA;2FAAzB,yBAAyB,EAAA,YAAA,EAAA,IAAA,EAAA,QAAA,EAAA,+FAAA,EAAA,MAAA,EAAA,EAAA,YAAA,EAAA,EAAA,iBAAA,EAAA,cAAA,EAAA,UAAA,EAAA,cAAA,EAAA,QAAA,EAAA,IAAA,EAAA,UAAA,EAAA,KAAA,EAAA,iBAAA,EAAA,IAAA,EAAA,EAAA,EAAA,OAAA,EAAA,EAAA,WAAA,EAAA,aAAA,EAAA,WAAA,EAAA,aAAA,EAAA,aAAA,EAAA,eAAA,EAAA,EAAA,QAAA,EAAA,EAAA,EAAA,CAAA;;2FAAzB,yBAAyB,EAAA,UAAA,EAAA,CAAA;kBAJrC,SAAS;AAAC,YAAA,IAAA,EAAA,CAAA;AACT,oBAAA,QAAQ,EAAE,+FAA+F;AACzG,oBAAA,UAAU,EAAE,IAAI;AACjB,iBAAA;;;ACvCD;;;;;;;;;;;;;AAaG;AAWH;AACA;AACA;AACA,iCAAiC,CAAC,cAAc,EAAE,CAAC,MAAM,EAAE,OAAO,KAAI;AACpE,IAAA,IAAI,CAAC,MAAM,IAAI,OAAO,MAAM,KAAK,QAAQ;AAAE,QAAA,OAAO,MAAM;IACxD,MAAM,GAAG,GAAG,MAAgC;IAC5C,IAAI,GAAG,CAAC,gBAAgB,IAAI,gBAAgB,CAAC,GAAG,CAAC,gBAAgB,CAAC,EAAE;AAClE,QAAA,MAAM,KAAK,GAAG,OAAO,CAAC,sBAAsB,CAAuB,GAAG,CAAC,gBAAgB,EAAE,CAAC,CAAC,MAAM;YAC/F,GAAG,EAAE,CAAC,CAAC,GAAG;YACV,KAAK,EAAE,CAAC,CAAC,KAAK;YACd,KAAK,EAAE,CAAC,CAAC,KAAK;YACd,IAAI,EAAE,CAAC,CAAC,IAAI;YACZ,QAAQ,EAAE,CAAC,CAAC,QAAQ;YACpB,YAAY,EAAE,CAAC,CAAC,YAAY;AAC7B,SAAA,CAAC,CAAC;AACH,QAAA,OAAO,EAAE,GAAG,GAAG,EAAE,gBAAgB,EAAE,CAAC,MAA4B,KAAK,KAAK,CAAC,MAAM,CAAC,CAAC,WAAW,EAAE;IAClG;AACA,IAAA,OAAO,GAAG;AACZ,CAAC,CAAC;;AC1CF;;AAEG;;;;"}
@@ -1 +1 @@
1
- {"version":3,"file":"toolbox-web-grid-angular-features-pinned-rows.mjs","sources":["../../../../libs/grid-angular/features/pinned-rows/src/cached-panel-renderer.ts","../../../../libs/grid-angular/features/pinned-rows/src/grid-pinned-rows.directive.ts","../../../../libs/grid-angular/features/pinned-rows/src/index.ts","../../../../libs/grid-angular/features/pinned-rows/src/toolbox-web-grid-angular-features-pinned-rows.ts"],"sourcesContent":["/**\n * @internal\n *\n * Cached panel-renderer factory for the Angular pinned-rows adapter (#354).\n *\n * Extracted into its own module so the pure caching logic can be unit-tested\n * without depending on the heavy `@toolbox-web/grid-angular` barrel (which\n * pulls in every directive at module-load and requires substantial Angular\n * DI mocking).\n *\n * @since 1.7.0\n */\nimport type { ComponentRef, Type } from '@angular/core';\nimport type { PinnedRowsContext } from '@toolbox-web/grid/plugins/pinned-rows';\n\n/**\n * Minimal structural shape of the adapter API used by {@link buildCachedPanelRenderer}.\n * Mirrors `GridAdapter.mountComponentRenderer` without the rest of the surface\n * so tests can pass a stub.\n *\n * @internal\n */\nexport interface PanelRendererAdapter {\n mountComponentRenderer<TCtx>(\n componentClass: Type<unknown>,\n mapInputs: (ctx: TCtx) => Record<string, unknown>,\n ): (ctx: TCtx) => { hostElement: HTMLElement; componentRef: ComponentRef<unknown> };\n}\n\n/**\n * Map a {@link PinnedRowsContext} to the Angular component input bag.\n * Centralized so both the initial `mountComponentRenderer` call and the\n * per-call input-refresh path stay in sync.\n *\n * @internal\n */\nexport function mapPinnedRowsInputs(ctx: PinnedRowsContext): Record<string, unknown> {\n return {\n totalRows: ctx.totalRows,\n filteredRows: ctx.filteredRows,\n selectedRows: ctx.selectedRows,\n columns: ctx.columns,\n rows: ctx.rows,\n grid: ctx.grid,\n };\n}\n\n/**\n * Build a pinned-rows panel renderer function from an Angular component class.\n * The component should accept inputs from {@link PinnedRowsContext}.\n *\n * Caches the mounted component across renders — the pinned-rows plugin\n * (`renderPanelSlot`) reference-checks renderer outputs to skip DOM mutation\n * when nothing changed. On subsequent calls inputs are refreshed via\n * `componentRef.setInput()` instead of mounting a fresh component.\n *\n * The cached `ComponentRef` is tracked in the adapter's render pool, so it is\n * destroyed automatically when the grid is disposed.\n *\n * @internal\n */\nexport function buildCachedPanelRenderer(\n adapter: PanelRendererAdapter,\n componentClass: Type<unknown>,\n): (ctx: PinnedRowsContext) => HTMLElement {\n const mount = adapter.mountComponentRenderer<PinnedRowsContext>(componentClass, mapPinnedRowsInputs);\n let cached: { hostElement: HTMLElement; componentRef: ComponentRef<unknown> } | null = null;\n return (ctx) => {\n if (!cached) {\n cached = mount(ctx);\n return cached.hostElement;\n }\n const inputs = mapPinnedRowsInputs(ctx);\n for (const name of Object.keys(inputs)) {\n cached.componentRef.setInput(name, inputs[name]);\n }\n cached.componentRef.changeDetectorRef.detectChanges();\n return cached.hostElement;\n };\n}\n","/**\n * `GridPinnedRowsDirective` — owns `[pinnedRows]` on `<tbw-grid>`. No\n * event outputs. See `GridFilteringDirective` for the full rationale.\n *\n * @category Directive\n */\nimport { Directive, ElementRef, inject, input, OnDestroy, type Type } from '@angular/core';\nimport type { DataGridElement } from '@toolbox-web/grid';\nimport { registerFeatureClaim, unregisterFeatureClaim } from '@toolbox-web/grid-angular';\nimport type {\n PinnedRowsConfig as CorePinnedRowsConfig,\n PanelZone,\n PinnedRowsContext,\n} from '@toolbox-web/grid/plugins/pinned-rows';\n\n/**\n * Angular-shaped panel-slot render: a renderer function (vanilla), an Angular\n * component class, or an array of zoned entries that each accept the same.\n *\n * Component instances receive the {@link PinnedRowsContext} fields as inputs.\n *\n * @since 1.7.1\n */\nexport type PanelRender = ((ctx: PinnedRowsContext) => HTMLElement | null) | Type<unknown>;\n\n/**\n * Angular-shaped zoned panel render entry.\n *\n * @since 1.7.1\n */\nexport interface ZonedPanelRender {\n zone?: PanelZone;\n render: PanelRender;\n}\n\n/**\n * Angular-shaped pinned-rows panel slot.\n *\n * @since 1.7.1\n */\nexport interface PanelSlot {\n id?: string;\n position?: 'top' | 'bottom';\n render: PanelRender | ZonedPanelRender[];\n}\n\ntype CoreSlot = NonNullable<CorePinnedRowsConfig['slots']>[number];\ntype CoreAggregationSlot = Exclude<CoreSlot, { render: unknown }>;\n\n/**\n * Angular-shaped pinned-rows slot \\u2014 either an aggregation slot (passthrough)\n * or a panel slot accepting Angular component classes as `render`.\n *\n * @since 1.7.1\n */\nexport type PinnedRowSlot = CoreAggregationSlot | PanelSlot;\n\n/**\n * Pinned-rows config widened to accept Angular component classes as `render`\n * inside `slots[]`. Bridging to vanilla DOM is handled\n * by the side-effect import `@toolbox-web/grid-angular/features/pinned-rows`.\n *\n * Re-exported under the same name as the core type so Angular users see a\n * single canonical `PinnedRowsConfig` from\n * `@toolbox-web/grid-angular/features/pinned-rows`.\n *\n * @since 1.7.1\n */\nexport type PinnedRowsConfig = Omit<CorePinnedRowsConfig, 'slots'> & {\n slots?: PinnedRowSlot[];\n};\n\n// ── Deprecated framework-prefixed aliases ──────────────────────────────────\n// Retained for backwards compatibility. New code should use the canonical\n// (unprefixed) names above.\n\n/** @deprecated Use {@link PanelRender} instead. */\nexport type AngularPanelRender = PanelRender;\n/** @deprecated Use {@link ZonedPanelRender} instead. */\nexport type AngularZonedPanelRender = ZonedPanelRender;\n/** @deprecated Use {@link PanelSlot} instead. */\nexport type AngularPanelSlot = PanelSlot;\n/** @deprecated Use {@link PinnedRowSlot} instead. */\nexport type AngularPinnedRowSlot = PinnedRowSlot;\n/** @deprecated Use {@link PinnedRowsConfig} instead. */\nexport type AngularPinnedRowsConfig = PinnedRowsConfig;\n\n/**\n * Owns the binding(s) `[pinnedRows]` on `<tbw-grid>` for the matching feature plugin. See `GridFilteringDirective` for the full rationale.\n *\n * @category Directive\n */\n@Directive({\n selector: 'tbw-grid[pinnedRows]',\n standalone: true,\n})\nexport class GridPinnedRowsDirective implements OnDestroy {\n private readonly elementRef = inject(ElementRef<DataGridElement>);\n\n readonly pinnedRows = input<boolean | PinnedRowsConfig>();\n\n constructor() {\n registerFeatureClaim(this.elementRef.nativeElement, 'pinnedRows', () => this.pinnedRows());\n }\n\n ngOnDestroy(): void {\n unregisterFeatureClaim(this.elementRef.nativeElement, 'pinnedRows');\n }\n}\n","/**\n * Pinned rows feature for @toolbox-web/grid-angular\n *\n * Import this module to enable the `pinnedRows` input on Grid directive.\n *\n * @example\n * ```typescript\n * import '@toolbox-web/grid-angular/features/pinned-rows';\n *\n * <tbw-grid [pinnedRows]=\"{ bottom: [{ type: 'aggregation' }] }\" />\n * ```\n *\n * @packageDocumentation\n */\n\nimport type { Type } from '@angular/core';\nimport { isComponentClass, registerFeatureConfigPreprocessor, type GridAdapter } from '@toolbox-web/grid-angular';\nimport '@toolbox-web/grid/features/pinned-rows';\nimport type {\n PinnedRowsConfig as CorePinnedRowsConfig,\n PinnedRowSlot as CorePinnedRowSlot,\n ZonedPanelRender as CoreZonedPanelRender,\n PinnedRowsContext,\n} from '@toolbox-web/grid/plugins/pinned-rows';\nimport { buildCachedPanelRenderer } from './cached-panel-renderer';\nexport { GridPinnedRowsDirective } from './grid-pinned-rows.directive';\nexport type {\n // Deprecated framework-prefixed aliases \\u2014 kept for backwards compatibility.\n AngularPanelRender,\n AngularPanelSlot,\n AngularPinnedRowsConfig,\n AngularPinnedRowSlot,\n AngularZonedPanelRender,\n // Canonical (unprefixed) widening types. Same names as the core types\n // from `@toolbox-web/grid` \\u2014 these accept Angular component classes in\n // addition to the vanilla `HTMLElement`-returning renderer functions.\n PanelRender,\n PanelSlot,\n PinnedRowsConfig,\n PinnedRowSlot,\n ZonedPanelRender,\n} from './grid-pinned-rows.directive';\nexport type { _Augmentation as _PinnedRowsAugmentation } from '@toolbox-web/grid/features/pinned-rows';\n\n/**\n * Build a pinned-rows panel renderer function from an Angular component class.\n * Thin wrapper around {@link buildCachedPanelRenderer} that fixes the adapter\n * type to the concrete `GridAdapter`.\n */\nfunction buildPanelRenderer(\n adapter: GridAdapter,\n componentClass: Type<unknown>,\n): (ctx: PinnedRowsContext) => HTMLElement {\n return buildCachedPanelRenderer(adapter, componentClass);\n}\n\n/**\n * Bridge a single pinned-row slot. Aggregation slots (no `render`) pass through.\n * For panel slots, wrap any component-class `render` (or array entry's `render`)\n * with the Angular component renderer.\n */\nfunction bridgeSlot(adapter: GridAdapter, slot: CorePinnedRowSlot): CorePinnedRowSlot {\n if (!('render' in slot) || slot.render == null) return slot;\n\n if (Array.isArray(slot.render)) {\n const zoned: CoreZonedPanelRender[] = slot.render.map((entry) => {\n if (entry?.render == null) return entry;\n if (isComponentClass(entry.render)) {\n return { zone: entry.zone, render: buildPanelRenderer(adapter, entry.render as Type<unknown>) };\n }\n return entry;\n });\n return { ...slot, render: zoned };\n }\n\n if (isComponentClass(slot.render)) {\n return { ...slot, render: buildPanelRenderer(adapter, slot.render as Type<unknown>) };\n }\n return slot;\n}\n\n// Bridge any Angular component classes embedded in `slots`\n// to plain renderer functions before the core plugin factory consumes the config.\nregisterFeatureConfigPreprocessor('pinnedRows', (config, adapter) => {\n if (!config || typeof config !== 'object') return config;\n const cfg = config as CorePinnedRowsConfig;\n let next: CorePinnedRowsConfig = cfg;\n\n // Slots[] bridging \\u2014 each PanelSlot.render may be a component class, or an\n // array of { zone?, render } where each render may be a component class.\n if (Array.isArray(cfg.slots)) {\n next = { ...next, slots: cfg.slots.map((slot) => bridgeSlot(adapter, slot)) };\n }\n\n return next;\n});\n","/**\n * Generated bundle index. Do not edit.\n */\n\nexport * from './index';\n"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"toolbox-web-grid-angular-features-pinned-rows.mjs","sources":["../../../../libs/grid-angular/features/pinned-rows/src/cached-panel-renderer.ts","../../../../libs/grid-angular/features/pinned-rows/src/grid-pinned-rows.directive.ts","../../../../libs/grid-angular/features/pinned-rows/src/index.ts","../../../../libs/grid-angular/features/pinned-rows/src/toolbox-web-grid-angular-features-pinned-rows.ts"],"sourcesContent":["/**\n * @internal\n *\n * Cached panel-renderer factory for the Angular pinned-rows adapter (#354).\n *\n * Extracted into its own module so the pure caching logic can be unit-tested\n * without depending on the heavy `@toolbox-web/grid-angular` barrel (which\n * pulls in every directive at module-load and requires substantial Angular\n * DI mocking).\n *\n * @since 1.7.0\n */\nimport type { ComponentRef, Type } from '@angular/core';\nimport type { PinnedRowsContext } from '@toolbox-web/grid/plugins/pinned-rows';\n\n/**\n * Minimal structural shape of the adapter API used by {@link buildCachedPanelRenderer}.\n * Mirrors `GridAdapter.mountComponentRenderer` without the rest of the surface\n * so tests can pass a stub.\n *\n * @internal\n */\nexport interface PanelRendererAdapter {\n mountComponentRenderer<TCtx>(\n componentClass: Type<unknown>,\n mapInputs: (ctx: TCtx) => Record<string, unknown>,\n ): (ctx: TCtx) => { hostElement: HTMLElement; componentRef: ComponentRef<unknown> };\n}\n\n/**\n * Map a {@link PinnedRowsContext} to the Angular component input bag.\n * Centralized so both the initial `mountComponentRenderer` call and the\n * per-call input-refresh path stay in sync.\n *\n * @internal\n */\nexport function mapPinnedRowsInputs(ctx: PinnedRowsContext): Record<string, unknown> {\n return {\n totalRows: ctx.totalRows,\n filteredRows: ctx.filteredRows,\n selectedRows: ctx.selectedRows,\n columns: ctx.columns,\n rows: ctx.rows,\n grid: ctx.grid,\n };\n}\n\n/**\n * Build a pinned-rows panel renderer function from an Angular component class.\n * The component should accept inputs from {@link PinnedRowsContext}.\n *\n * Caches the mounted component across renders — the pinned-rows plugin\n * (`renderPanelSlot`) reference-checks renderer outputs to skip DOM mutation\n * when nothing changed. On subsequent calls inputs are refreshed via\n * `componentRef.setInput()` instead of mounting a fresh component.\n *\n * The cached `ComponentRef` is tracked in the adapter's render pool, so it is\n * destroyed automatically when the grid is disposed.\n *\n * @internal\n */\nexport function buildCachedPanelRenderer(\n adapter: PanelRendererAdapter,\n componentClass: Type<unknown>,\n): (ctx: PinnedRowsContext) => HTMLElement {\n const mount = adapter.mountComponentRenderer<PinnedRowsContext>(componentClass, mapPinnedRowsInputs);\n let cached: { hostElement: HTMLElement; componentRef: ComponentRef<unknown> } | null = null;\n return (ctx) => {\n if (!cached) {\n cached = mount(ctx);\n return cached.hostElement;\n }\n const inputs = mapPinnedRowsInputs(ctx);\n for (const name of Object.keys(inputs)) {\n cached.componentRef.setInput(name, inputs[name]);\n }\n cached.componentRef.changeDetectorRef.detectChanges();\n return cached.hostElement;\n };\n}\n","/**\n * `GridPinnedRowsDirective` — owns `[pinnedRows]` on `<tbw-grid>`. No\n * event outputs. See `GridFilteringDirective` for the full rationale.\n *\n * @category Directive\n */\nimport { Directive, ElementRef, inject, input, OnDestroy, type Type } from '@angular/core';\nimport type { DataGridElement } from '@toolbox-web/grid';\nimport { registerFeatureClaim, unregisterFeatureClaim } from '@toolbox-web/grid-angular';\nimport type {\n PinnedRowsConfig as CorePinnedRowsConfig,\n PanelZone,\n PinnedRowsContext,\n} from '@toolbox-web/grid/plugins/pinned-rows';\n\n/**\n * Angular-shaped panel-slot render: a renderer function (vanilla), an Angular\n * component class, or an array of zoned entries that each accept the same.\n *\n * Component instances receive the {@link PinnedRowsContext} fields as inputs.\n *\n * @since 1.7.1\n */\nexport type PanelRender = ((ctx: PinnedRowsContext) => HTMLElement | null) | Type<unknown>;\n\n/**\n * Angular-shaped zoned panel render entry.\n *\n * @since 1.7.1\n */\nexport interface ZonedPanelRender {\n zone?: PanelZone;\n render: PanelRender;\n}\n\n/**\n * Angular-shaped pinned-rows panel slot.\n *\n * @since 1.7.1\n */\nexport interface PanelSlot {\n id?: string;\n position?: 'top' | 'bottom';\n render: PanelRender | ZonedPanelRender[];\n}\n\ntype CoreSlot = NonNullable<CorePinnedRowsConfig['slots']>[number];\ntype CoreAggregationSlot = Exclude<CoreSlot, { render: unknown }>;\n\n/**\n * Angular-shaped pinned-rows slot \\u2014 either an aggregation slot (passthrough)\n * or a panel slot accepting Angular component classes as `render`.\n *\n * @since 1.7.1\n */\nexport type PinnedRowSlot = CoreAggregationSlot | PanelSlot;\n\n/**\n * Pinned-rows config widened to accept Angular component classes as `render`\n * inside `slots[]`. Bridging to vanilla DOM is handled\n * by the side-effect import `@toolbox-web/grid-angular/features/pinned-rows`.\n *\n * Re-exported under the same name as the core type so Angular users see a\n * single canonical `PinnedRowsConfig` from\n * `@toolbox-web/grid-angular/features/pinned-rows`.\n *\n * @since 1.7.1\n */\nexport type PinnedRowsConfig = Omit<CorePinnedRowsConfig, 'slots'> & {\n slots?: PinnedRowSlot[];\n};\n\n/**\n * Owns the binding(s) `[pinnedRows]` on `<tbw-grid>` for the matching feature plugin. See `GridFilteringDirective` for the full rationale.\n *\n * @category Directive\n */\n@Directive({\n selector: 'tbw-grid[pinnedRows]',\n standalone: true,\n})\nexport class GridPinnedRowsDirective implements OnDestroy {\n private readonly elementRef = inject(ElementRef<DataGridElement>);\n\n readonly pinnedRows = input<boolean | PinnedRowsConfig>();\n\n constructor() {\n registerFeatureClaim(this.elementRef.nativeElement, 'pinnedRows', () => this.pinnedRows());\n }\n\n ngOnDestroy(): void {\n unregisterFeatureClaim(this.elementRef.nativeElement, 'pinnedRows');\n }\n}\n","/**\n * Pinned rows feature for @toolbox-web/grid-angular\n *\n * Import this module to enable the `pinnedRows` input on Grid directive.\n *\n * @example\n * ```typescript\n * import '@toolbox-web/grid-angular/features/pinned-rows';\n *\n * <tbw-grid [pinnedRows]=\"{ bottom: [{ type: 'aggregation' }] }\" />\n * ```\n *\n * @packageDocumentation\n */\n\nimport type { Type } from '@angular/core';\nimport { isComponentClass, registerFeatureConfigPreprocessor, type GridAdapter } from '@toolbox-web/grid-angular';\nimport '@toolbox-web/grid/features/pinned-rows';\nimport type {\n PinnedRowsConfig as CorePinnedRowsConfig,\n PinnedRowSlot as CorePinnedRowSlot,\n ZonedPanelRender as CoreZonedPanelRender,\n PinnedRowsContext,\n} from '@toolbox-web/grid/plugins/pinned-rows';\nimport { buildCachedPanelRenderer } from './cached-panel-renderer';\nexport { GridPinnedRowsDirective } from './grid-pinned-rows.directive';\nexport type {\n // Canonical (unprefixed) widening types. Same names as the core types\n // from `@toolbox-web/grid` \\u2014 these accept Angular component classes in\n // addition to the vanilla `HTMLElement`-returning renderer functions.\n PanelRender,\n PanelSlot,\n PinnedRowsConfig,\n PinnedRowSlot,\n ZonedPanelRender,\n} from './grid-pinned-rows.directive';\nexport type { _Augmentation as _PinnedRowsAugmentation } from '@toolbox-web/grid/features/pinned-rows';\n\n/**\n * Build a pinned-rows panel renderer function from an Angular component class.\n * Thin wrapper around {@link buildCachedPanelRenderer} that fixes the adapter\n * type to the concrete `GridAdapter`.\n */\nfunction buildPanelRenderer(\n adapter: GridAdapter,\n componentClass: Type<unknown>,\n): (ctx: PinnedRowsContext) => HTMLElement {\n return buildCachedPanelRenderer(adapter, componentClass);\n}\n\n/**\n * Bridge a single pinned-row slot. Aggregation slots (no `render`) pass through.\n * For panel slots, wrap any component-class `render` (or array entry's `render`)\n * with the Angular component renderer.\n */\nfunction bridgeSlot(adapter: GridAdapter, slot: CorePinnedRowSlot): CorePinnedRowSlot {\n if (!('render' in slot) || slot.render == null) return slot;\n\n if (Array.isArray(slot.render)) {\n const zoned: CoreZonedPanelRender[] = slot.render.map((entry) => {\n if (entry?.render == null) return entry;\n if (isComponentClass(entry.render)) {\n return { zone: entry.zone, render: buildPanelRenderer(adapter, entry.render as Type<unknown>) };\n }\n return entry;\n });\n return { ...slot, render: zoned };\n }\n\n if (isComponentClass(slot.render)) {\n return { ...slot, render: buildPanelRenderer(adapter, slot.render as Type<unknown>) };\n }\n return slot;\n}\n\n// Bridge any Angular component classes embedded in `slots`\n// to plain renderer functions before the core plugin factory consumes the config.\nregisterFeatureConfigPreprocessor('pinnedRows', (config, adapter) => {\n if (!config || typeof config !== 'object') return config;\n const cfg = config as CorePinnedRowsConfig;\n let next: CorePinnedRowsConfig = cfg;\n\n // Slots[] bridging \\u2014 each PanelSlot.render may be a component class, or an\n // array of { zone?, render } where each render may be a component class.\n if (Array.isArray(cfg.slots)) {\n next = { ...next, slots: cfg.slots.map((slot) => bridgeSlot(adapter, slot)) };\n }\n\n return next;\n});\n","/**\n * Generated bundle index. Do not edit.\n */\n\nexport * from './index';\n"],"names":[],"mappings":"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"}
@@ -49,7 +49,8 @@ function getToolPanelElements(gridElement) {
49
49
  * ### Attributes
50
50
  *
51
51
  * - `id` (required): Unique identifier for the panel
52
- * - `title` (required): Panel title shown in accordion header
52
+ * - `title` (optional): Panel title shown in accordion header. Omit it when the
53
+ * panel content provides its own heading.
53
54
  * - `icon`: Icon for accordion section header (emoji or text)
54
55
  * - `tooltip`: Tooltip for accordion section header
55
56
  * - `order`: Panel order priority (lower = first, default: 100)
@@ -83,8 +84,18 @@ class GridToolPanel {
83
84
  elementRef = inject((ElementRef));
84
85
  /** Unique panel identifier (required) */
85
86
  id = input.required({ ...(ngDevMode ? { debugName: "id" } : /* istanbul ignore next */ {}), alias: 'id' });
86
- /** Panel title shown in accordion header (required) */
87
- title = input.required({ ...(ngDevMode ? { debugName: "title" } : /* istanbul ignore next */ {}), alias: 'title' });
87
+ /**
88
+ * Panel title shown in accordion header (optional).
89
+ *
90
+ * Omit it when the panel content provides its own heading. With a single
91
+ * title-less panel the accordion header row is skipped; with multiple panels
92
+ * a title-less header still renders so the expand/collapse control stays
93
+ * available.
94
+ *
95
+ * @since 3.1.0 (previously required)
96
+ */
97
+ title = input(/* @ts-ignore */
98
+ ...(ngDevMode ? [undefined, { debugName: "title" }] : /* istanbul ignore next */ []));
88
99
  /** Icon for accordion section header (emoji or text) */
89
100
  icon = input(/* @ts-ignore */
90
101
  ...(ngDevMode ? [undefined, { debugName: "icon" }] : /* istanbul ignore next */ []));
@@ -106,7 +117,13 @@ class GridToolPanel {
106
117
  if (template) {
107
118
  // Set attributes from inputs (for light DOM parsing to read)
108
119
  element.setAttribute('id', this.id());
109
- element.setAttribute('title', this.title());
120
+ const title = this.title();
121
+ if (title != null) {
122
+ element.setAttribute('title', title);
123
+ }
124
+ else {
125
+ element.removeAttribute('title');
126
+ }
110
127
  const icon = this.icon();
111
128
  if (icon)
112
129
  element.setAttribute('icon', icon);
@@ -127,12 +144,12 @@ class GridToolPanel {
127
144
  return true;
128
145
  }
129
146
  static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "22.0.6", ngImport: i0, type: GridToolPanel, deps: [], target: i0.ɵɵFactoryTarget.Directive });
130
- static ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "17.2.0", version: "22.0.6", type: GridToolPanel, isStandalone: true, selector: "tbw-grid-tool-panel", inputs: { id: { classPropertyName: "id", publicName: "id", isSignal: true, isRequired: true, transformFunction: null }, title: { classPropertyName: "title", publicName: "title", isSignal: true, isRequired: true, transformFunction: null }, icon: { classPropertyName: "icon", publicName: "icon", isSignal: true, isRequired: false, transformFunction: null }, tooltip: { classPropertyName: "tooltip", publicName: "tooltip", isSignal: true, isRequired: false, transformFunction: null }, order: { classPropertyName: "order", publicName: "order", isSignal: true, isRequired: false, transformFunction: null } }, queries: [{ propertyName: "template", first: true, predicate: (TemplateRef), descendants: true, isSignal: true }], ngImport: i0 });
147
+ static ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "17.2.0", version: "22.0.6", type: GridToolPanel, isStandalone: true, selector: "tbw-grid-tool-panel", inputs: { id: { classPropertyName: "id", publicName: "id", isSignal: true, isRequired: true, transformFunction: null }, title: { classPropertyName: "title", publicName: "title", isSignal: true, isRequired: false, transformFunction: null }, icon: { classPropertyName: "icon", publicName: "icon", isSignal: true, isRequired: false, transformFunction: null }, tooltip: { classPropertyName: "tooltip", publicName: "tooltip", isSignal: true, isRequired: false, transformFunction: null }, order: { classPropertyName: "order", publicName: "order", isSignal: true, isRequired: false, transformFunction: null } }, queries: [{ propertyName: "template", first: true, predicate: (TemplateRef), descendants: true, isSignal: true }], ngImport: i0 });
131
148
  }
132
149
  i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.0.6", ngImport: i0, type: GridToolPanel, decorators: [{
133
150
  type: Directive,
134
151
  args: [{ selector: 'tbw-grid-tool-panel' }]
135
- }], propDecorators: { id: [{ type: i0.Input, args: [{ isSignal: true, alias: "id", required: true }] }], title: [{ type: i0.Input, args: [{ isSignal: true, alias: "title", required: true }] }], icon: [{ type: i0.Input, args: [{ isSignal: true, alias: "icon", required: false }] }], tooltip: [{ type: i0.Input, args: [{ isSignal: true, alias: "tooltip", required: false }] }], order: [{ type: i0.Input, args: [{ isSignal: true, alias: "order", required: false }] }], template: [{ type: i0.ContentChild, args: [i0.forwardRef(() => TemplateRef), { isSignal: true }] }] } });
152
+ }], propDecorators: { id: [{ type: i0.Input, args: [{ isSignal: true, alias: "id", required: true }] }], title: [{ type: i0.Input, args: [{ isSignal: true, alias: "title", required: false }] }], icon: [{ type: i0.Input, args: [{ isSignal: true, alias: "icon", required: false }] }], tooltip: [{ type: i0.Input, args: [{ isSignal: true, alias: "tooltip", required: false }] }], order: [{ type: i0.Input, args: [{ isSignal: true, alias: "order", required: false }] }], template: [{ type: i0.ContentChild, args: [i0.forwardRef(() => TemplateRef), { isSignal: true }] }] } });
136
153
 
137
154
  let autoIdCounter$1 = 0;
138
155
  /**
@@ -441,9 +458,8 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.0.6", ngImpor
441
458
  * Shell feature for @toolbox-web/grid-angular
442
459
  *
443
460
  * Import this module to opt the grid shell (header bar + tool panels) into
444
- * the build. The shell also auto-registers in v2.x (so it is on by default
445
- * and non-breaking); importing this module makes the opt-in explicit and
446
- * tree-shakeable for v3, where the auto-register is removed.
461
+ * the build. The shell is opt-in and tree-shakeable — nothing is registered
462
+ * unless this entry point is imported.
447
463
  *
448
464
  * The shell is configured through `gridConfig` (`features: { shell }` or the
449
465
  * `<tbw-grid-header-content>` / `<tbw-grid-toolbar-content>` /