@toolbox-web/grid-angular 2.2.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.
- package/README.md +25 -55
- package/fesm2022/toolbox-web-grid-angular-features-editing.mjs +14 -4
- package/fesm2022/toolbox-web-grid-angular-features-editing.mjs.map +1 -1
- package/fesm2022/toolbox-web-grid-angular-features-filtering.mjs +10 -30
- package/fesm2022/toolbox-web-grid-angular-features-filtering.mjs.map +1 -1
- package/fesm2022/toolbox-web-grid-angular-features-shell.mjs +2 -3
- package/fesm2022/toolbox-web-grid-angular-features-shell.mjs.map +1 -1
- package/fesm2022/toolbox-web-grid-angular-features-tree.mjs +47 -14
- package/fesm2022/toolbox-web-grid-angular-features-tree.mjs.map +1 -1
- package/fesm2022/toolbox-web-grid-angular.mjs +7 -0
- package/fesm2022/toolbox-web-grid-angular.mjs.map +1 -1
- package/package.json +1 -1
- package/types/toolbox-web-grid-angular-features-editing.d.ts +11 -3
- package/types/toolbox-web-grid-angular-features-editing.d.ts.map +1 -1
- package/types/toolbox-web-grid-angular-features-filtering.d.ts +6 -22
- package/types/toolbox-web-grid-angular-features-filtering.d.ts.map +1 -1
- package/types/toolbox-web-grid-angular-features-tree.d.ts +23 -4
- package/types/toolbox-web-grid-angular-features-tree.d.ts.map +1 -1
- package/types/toolbox-web-grid-angular.d.ts +7 -1
- 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
|
-
* ##
|
|
38
|
+
* ## Feature claims
|
|
39
39
|
*
|
|
40
|
-
* The
|
|
41
|
-
*
|
|
42
|
-
*
|
|
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.
|
|
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
|
-
*
|
|
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
|
-
*
|
|
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
|
-
*
|
|
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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"}
|
|
@@ -458,9 +458,8 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.0.6", ngImpor
|
|
|
458
458
|
* Shell feature for @toolbox-web/grid-angular
|
|
459
459
|
*
|
|
460
460
|
* Import this module to opt the grid shell (header bar + tool panels) into
|
|
461
|
-
* the build. The shell
|
|
462
|
-
*
|
|
463
|
-
* 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.
|
|
464
463
|
*
|
|
465
464
|
* The shell is configured through `gridConfig` (`features: { shell }` or the
|
|
466
465
|
* `<tbw-grid-header-content>` / `<tbw-grid-toolbar-content>` /
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"toolbox-web-grid-angular-features-shell.mjs","sources":["../../../../libs/grid-angular/features/shell/src/grid-tool-panel.directive.ts","../../../../libs/grid-angular/features/shell/src/grid-header-content.directive.ts","../../../../libs/grid-angular/features/shell/src/grid-toolbar-content.directive.ts","../../../../libs/grid-angular/features/shell/src/index.ts","../../../../libs/grid-angular/features/shell/src/toolbox-web-grid-angular-features-shell.ts"],"sourcesContent":["import { contentChild, Directive, effect, ElementRef, inject, input, TemplateRef } from '@angular/core';\n\n/**\n * Context object passed to the tool panel template.\n * Provides access to grid-related information for the panel content.\n * @since 0.1.0\n */\nexport interface GridToolPanelContext {\n /** The grid element (implicit binding) */\n $implicit: HTMLElement;\n /** The grid element */\n grid: HTMLElement;\n}\n\n// Global registry mapping DOM elements to their templates\nconst toolPanelTemplateRegistry = new Map<HTMLElement, TemplateRef<GridToolPanelContext>>();\n\n/**\n * Gets the tool panel template registered for a given tool panel element.\n * Used by AngularGridAdapter to retrieve templates at render time.\n */\nexport function getToolPanelTemplate(panelElement: HTMLElement): TemplateRef<GridToolPanelContext> | undefined {\n return toolPanelTemplateRegistry.get(panelElement);\n}\n\n/**\n * Gets all tool panel elements with registered templates within a grid element.\n */\nexport function getToolPanelElements(gridElement: HTMLElement): HTMLElement[] {\n const panelElements = gridElement.querySelectorAll('tbw-grid-tool-panel');\n return Array.from(panelElements).filter((el) => toolPanelTemplateRegistry.has(el as HTMLElement)) as HTMLElement[];\n}\n\n/**\n * Directive that captures an `<ng-template>` for use as a custom tool panel.\n *\n * This enables declarative Angular component usage for tool panels\n * that appear in the grid's side panel.\n *\n * ## Usage\n *\n * ```html\n * <tbw-grid [rows]=\"rows\" [gridConfig]=\"config\">\n * <tbw-grid-tool-panel\n * id=\"quick-filters\"\n * title=\"Quick Filters\"\n * icon=\"🔍\"\n * tooltip=\"Apply quick filters\"\n * [order]=\"10\"\n * >\n * <ng-template let-grid>\n * <app-quick-filters [grid]=\"grid\" />\n * </ng-template>\n * </tbw-grid-tool-panel>\n * </tbw-grid>\n * ```\n *\n * The template context provides:\n * - `$implicit` / `grid`: The grid element reference\n *\n * ### Attributes\n *\n * - `id` (required): Unique identifier for the panel\n * - `title` (optional): Panel title shown in accordion header. Omit it when the\n * panel content provides its own heading.\n * - `icon`: Icon for accordion section header (emoji or text)\n * - `tooltip`: Tooltip for accordion section header\n * - `order`: Panel order priority (lower = first, default: 100)\n *\n * Import the directive in your component:\n *\n * ```typescript\n * import { GridToolPanel } from '@toolbox-web/grid-angular/features/shell';\n *\n * @Component({\n * imports: [GridToolPanel],\n * // ...\n * })\n * ```\n *\n * @example\n * ```html\n * <tbw-grid [rows]=\"rows\">\n * <tbw-grid-tool-panel id=\"quick-filters\" title=\"Quick Filters\" icon=\"\\uD83D\\uDD0D\">\n * <ng-template let-grid>\n * <app-quick-filters [grid]=\"grid\" />\n * </ng-template>\n * </tbw-grid-tool-panel>\n * </tbw-grid>\n * ```\n *\n * @category Directive\n * @since 0.1.0\n */\n@Directive({ selector: 'tbw-grid-tool-panel' })\nexport class GridToolPanel {\n private elementRef = inject(ElementRef<HTMLElement>);\n\n /** Unique panel identifier (required) */\n id = input.required<string>({ alias: 'id' });\n\n /**\n * Panel title shown in accordion header (optional).\n *\n * Omit it when the panel content provides its own heading. With a single\n * title-less panel the accordion header row is skipped; with multiple panels\n * a title-less header still renders so the expand/collapse control stays\n * available.\n *\n * @since 3.1.0 (previously required)\n */\n title = input<string>();\n\n /** Icon for accordion section header (emoji or text) */\n icon = input<string>();\n\n /** Tooltip for accordion section header */\n tooltip = input<string>();\n\n /** Panel order priority (lower = first, default: 100) */\n order = input<number>(100);\n\n /**\n * Query for the ng-template content child.\n */\n template = contentChild(TemplateRef<GridToolPanelContext>);\n\n /** Effect that triggers when the template is available */\n private onTemplateReceived = effect(() => {\n const template = this.template();\n const element = this.elementRef.nativeElement;\n\n if (template) {\n // Set attributes from inputs (for light DOM parsing to read)\n element.setAttribute('id', this.id());\n\n const title = this.title();\n if (title != null) {\n element.setAttribute('title', title);\n } else {\n element.removeAttribute('title');\n }\n\n const icon = this.icon();\n if (icon) element.setAttribute('icon', icon);\n\n const tooltip = this.tooltip();\n if (tooltip) element.setAttribute('tooltip', tooltip);\n\n element.setAttribute('order', String(this.order()));\n\n // Register the template for this element\n toolPanelTemplateRegistry.set(element, template);\n }\n });\n\n /**\n * Static type guard for template context.\n * Enables type inference in templates.\n */\n static ngTemplateContextGuard(dir: GridToolPanel, ctx: unknown): ctx is GridToolPanelContext {\n return true;\n }\n}\n","import {\n afterNextRender,\n contentChild,\n DestroyRef,\n Directive,\n effect,\n ElementRef,\n EmbeddedViewRef,\n inject,\n input,\n TemplateRef,\n ViewContainerRef,\n} from '@angular/core';\nimport type { DataGridElement } from '@toolbox-web/grid';\nimport type { HeaderContentDefinition } from '@toolbox-web/grid/plugins/shell';\n\n/**\n * Context object passed to the header content template.\n * @since 1.7.0\n */\nexport interface GridHeaderContentContext {\n /** The grid element (implicit binding for `let-grid`). */\n $implicit: DataGridElement;\n /** The grid element. */\n grid: DataGridElement;\n}\n\nlet autoIdCounter = 0;\n\n/**\n * Declarative wrapper around the grid's imperative\n * {@link ShellPlugin.registerHeaderContent} API.\n *\n * Captures an `<ng-template>` and mounts it as an Angular embedded view into\n * the slot the grid provides for header content. Must be a child of\n * `<tbw-grid>`.\n *\n * ## Usage\n *\n * ```html\n * <tbw-grid [rows]=\"rows\" [gridConfig]=\"config\">\n * <tbw-grid-header-content id=\"calendar-nav\" [order]=\"0\">\n * <ng-template let-grid>\n * <app-header-nav [year]=\"year()\" (yearChange)=\"setYear($event)\" />\n * </ng-template>\n * </tbw-grid-header-content>\n * </tbw-grid>\n * ```\n *\n * @category Directive\n * @since 1.7.0\n */\n@Directive({ selector: 'tbw-grid-header-content', standalone: true })\nexport class GridHeaderContent {\n private elementRef = inject(ElementRef<HTMLElement>);\n private viewContainerRef = inject(ViewContainerRef);\n private destroyRef = inject(DestroyRef);\n\n /** Unique identifier for this header content entry. Optional — defaults to a stable generated id. */\n id = input<string | undefined>(undefined);\n\n /** Render order priority. Lower values appear first. @default 100 */\n order = input<number>(100);\n\n /** The template to mount into the grid's header content slot. */\n template = contentChild(TemplateRef<GridHeaderContentContext>);\n\n private viewRef: EmbeddedViewRef<GridHeaderContentContext> | null = null;\n private registeredId: string | null = null;\n private resolvedId = `tbw-header-content-${++autoIdCounter}`;\n private destroyed = false;\n\n constructor() {\n afterNextRender(() => {\n void this.register();\n });\n\n this.destroyRef.onDestroy(() => {\n this.destroyed = true;\n this.unregister();\n });\n\n // Re-register when id or order changes after mount.\n effect(() => {\n const nextId = this.id() ?? this.resolvedId;\n const nextOrder = this.order();\n if (this.registeredId && this.registeredId !== nextId) {\n this.unregister();\n void this.register();\n return;\n }\n if (this.registeredId && nextOrder !== this.lastOrder) {\n this.unregister();\n void this.register();\n }\n this.lastOrder = nextOrder;\n });\n }\n\n private lastOrder: number | undefined;\n\n private async register(): Promise<void> {\n const grid = this.findGrid();\n if (!grid) return;\n try {\n await grid.ready?.();\n } catch {\n return;\n }\n if (this.destroyed) return;\n\n const template = this.template();\n const id = this.id() ?? this.resolvedId;\n const order = this.order();\n\n const def: HeaderContentDefinition = {\n id,\n order,\n render: (container) => {\n if (!template) return undefined;\n // Sticky container: the shell may re-invoke `render` with the SAME\n // container across refreshes. If our embedded view is still attached\n // inside it, the previous render is live and this is a refresh — do\n // nothing (no-op cleanup preserves child state).\n const firstNode = this.viewRef?.rootNodes[0] as Node | undefined;\n if (this.viewRef && firstNode && container.contains(firstNode)) {\n return () => {\n /* intentionally empty */\n };\n }\n // Fresh container (first render or container was replaced) — destroy\n // any stale view, then build a new one.\n if (this.viewRef) {\n this.viewRef.destroy();\n this.viewRef = null;\n }\n this.viewRef = this.viewContainerRef.createEmbeddedView(template, {\n $implicit: grid,\n grid,\n });\n this.viewRef.detectChanges();\n for (const node of this.viewRef.rootNodes as Node[]) {\n container.appendChild(node);\n }\n // No-op cleanup: the grid may call this between re-renders before\n // invoking `render` again with the SAME container. Tearing the view\n // down here would destroy any internal state in the projected\n // template on every shell refresh. Teardown happens in `unregister`\n // (component destroy / id / order change).\n return () => {\n /* intentionally empty */\n };\n },\n };\n // Route through the shell plugin (#370). The shell is opt-in at v3 —\n // content registers only when a shell plugin is present.\n grid.getPluginByName?.('shell')?.registerHeaderContent(def);\n this.registeredId = id;\n }\n\n private unregister(): void {\n const grid = this.findGrid();\n if (grid && this.registeredId) {\n grid.getPluginByName?.('shell')?.unregisterHeaderContent(this.registeredId);\n }\n this.registeredId = null;\n if (this.viewRef) {\n this.viewRef.destroy();\n this.viewRef = null;\n }\n }\n\n private findGrid(): DataGridElement | null {\n const host = this.elementRef.nativeElement;\n // Use the stable `[data-tbw-grid]` attribute (set by core on connect) rather\n // than the literal `tbw-grid` tag, so a version-suffixed grid host (e.g.\n // `<tbw-grid-v2-15-0>`) is still found. See the multi-version guide.\n const grid = host.closest('[data-tbw-grid]') as DataGridElement | null;\n return grid;\n }\n\n /** Type guard for template context inference. */\n static ngTemplateContextGuard(_dir: GridHeaderContent, ctx: unknown): ctx is GridHeaderContentContext {\n return true;\n }\n}\n","import {\n afterNextRender,\n contentChild,\n DestroyRef,\n Directive,\n effect,\n ElementRef,\n EmbeddedViewRef,\n inject,\n input,\n TemplateRef,\n ViewContainerRef,\n} from '@angular/core';\nimport type { DataGridElement } from '@toolbox-web/grid';\nimport type { ToolbarContentDefinition } from '@toolbox-web/grid/plugins/shell';\n\n/**\n * Context object passed to the toolbar content template.\n * @since 1.7.0\n */\nexport interface GridToolbarContentContext {\n /** The grid element (implicit binding for `let-grid`). */\n $implicit: DataGridElement;\n /** The grid element. */\n grid: DataGridElement;\n}\n\nlet autoIdCounter = 0;\n\n/**\n * Declarative wrapper around the grid's imperative\n * {@link ShellPlugin.registerToolbarContent} API.\n *\n * Captures an `<ng-template>` and mounts it as an Angular embedded view into\n * the slot the grid provides for toolbar content. Must be a child of\n * `<tbw-grid>`.\n *\n * Prefer this over `<tbw-grid-tool-buttons>` (light DOM) when you need\n * Angular template bindings to component state. Use the light-DOM form for\n * static markup that should be moved verbatim into the toolbar.\n *\n * ## Usage\n *\n * ```html\n * <tbw-grid [rows]=\"rows\" [gridConfig]=\"config\">\n * <tbw-grid-toolbar-content id=\"calendar-nav\" [order]=\"0\">\n * <ng-template let-grid>\n * <app-toolbar-nav (prev)=\"prev()\" (today)=\"today()\" (next)=\"next()\" />\n * </ng-template>\n * </tbw-grid-toolbar-content>\n * </tbw-grid>\n * ```\n *\n * @category Directive\n * @since 1.7.0\n */\n@Directive({ selector: 'tbw-grid-toolbar-content', standalone: true })\nexport class GridToolbarContent {\n private elementRef = inject(ElementRef<HTMLElement>);\n private viewContainerRef = inject(ViewContainerRef);\n private destroyRef = inject(DestroyRef);\n\n id = input<string | undefined>(undefined);\n order = input<number>(100);\n template = contentChild(TemplateRef<GridToolbarContentContext>);\n\n private viewRef: EmbeddedViewRef<GridToolbarContentContext> | null = null;\n private registeredId: string | null = null;\n private resolvedId = `tbw-toolbar-content-${++autoIdCounter}`;\n private lastOrder: number | undefined;\n private destroyed = false;\n\n constructor() {\n afterNextRender(() => {\n void this.register();\n });\n\n this.destroyRef.onDestroy(() => {\n this.destroyed = true;\n this.unregister();\n });\n\n effect(() => {\n const nextId = this.id() ?? this.resolvedId;\n const nextOrder = this.order();\n if (this.registeredId && this.registeredId !== nextId) {\n this.unregister();\n void this.register();\n return;\n }\n if (this.registeredId && nextOrder !== this.lastOrder) {\n this.unregister();\n void this.register();\n }\n this.lastOrder = nextOrder;\n });\n }\n\n private async register(): Promise<void> {\n const grid = this.findGrid();\n if (!grid) return;\n try {\n await grid.ready?.();\n } catch {\n return;\n }\n if (this.destroyed) return;\n\n const template = this.template();\n const id = this.id() ?? this.resolvedId;\n const order = this.order();\n\n const def: ToolbarContentDefinition = {\n id,\n order,\n render: (container) => {\n if (!template) return undefined;\n // Sticky container: see grid-header-content.directive.ts for rationale.\n const firstNode = this.viewRef?.rootNodes[0] as Node | undefined;\n if (this.viewRef && firstNode && container.contains(firstNode)) {\n return () => {\n /* intentionally empty */\n };\n }\n if (this.viewRef) {\n this.viewRef.destroy();\n this.viewRef = null;\n }\n this.viewRef = this.viewContainerRef.createEmbeddedView(template, {\n $implicit: grid,\n grid,\n });\n this.viewRef.detectChanges();\n for (const node of this.viewRef.rootNodes as Node[]) {\n container.appendChild(node);\n }\n // No-op cleanup — see comment in grid-header-content.directive.ts.\n return () => {\n /* intentionally empty */\n };\n },\n };\n // Route through the shell plugin (#370). The shell is opt-in at v3 —\n // content registers only when a shell plugin is present.\n grid.getPluginByName?.('shell')?.registerToolbarContent(def);\n this.registeredId = id;\n }\n\n private unregister(): void {\n const grid = this.findGrid();\n if (grid && this.registeredId) {\n grid.getPluginByName?.('shell')?.unregisterToolbarContent(this.registeredId);\n }\n this.registeredId = null;\n if (this.viewRef) {\n this.viewRef.destroy();\n this.viewRef = null;\n }\n }\n\n private findGrid(): DataGridElement | null {\n const host = this.elementRef.nativeElement;\n // Use the stable `[data-tbw-grid]` attribute (set by core on connect) rather\n // than the literal `tbw-grid` tag, so a version-suffixed grid host (e.g.\n // `<tbw-grid-v2-15-0>`) is still found. See the multi-version guide.\n return host.closest('[data-tbw-grid]') as DataGridElement | null;\n }\n\n static ngTemplateContextGuard(_dir: GridToolbarContent, ctx: unknown): ctx is GridToolbarContentContext {\n return true;\n }\n}\n","/**\n * Shell feature for @toolbox-web/grid-angular\n *\n * Import this module to opt the grid shell (header bar + tool panels) into\n * the build. The shell also auto-registers in v2.x (so it is on by default\n * and non-breaking); importing this module makes the opt-in explicit and\n * tree-shakeable for v3, where the auto-register is removed.\n *\n * The shell is configured through `gridConfig` (`features: { shell }` or the\n * `<tbw-grid-header-content>` / `<tbw-grid-toolbar-content>` /\n * `<tbw-grid-tool-panel>` directives), not a boolean input.\n *\n * @example\n * ```typescript\n * // In your bootstrap (e.g. main.ts or app.component.ts):\n * import '@toolbox-web/grid-angular/features/shell';\n * ```\n *\n * ```html\n * <tbw-grid [gridConfig]=\"{ features: { shell: { header: { title: 'Employees' } } } }\">\n * </tbw-grid>\n * ```\n *\n * @packageDocumentation\n */\n\nimport { registerToolPanelRendererBridge, type GridAdapter } from '@toolbox-web/grid-angular';\nimport '@toolbox-web/grid/features/shell';\nimport { getToolPanelTemplate, type GridToolPanelContext } from './grid-tool-panel.directive';\n\nexport type { _Augmentation as _ShellAugmentation } from '@toolbox-web/grid/features/shell';\n\n// ---------------------------------------------------------------------------\n// Shell-owned directives + helpers. These physically live in this secondary\n// entry (the runtime behaviour lives here too).\n// ---------------------------------------------------------------------------\nexport { GridHeaderContent } from './grid-header-content.directive';\nexport type { GridHeaderContentContext } from './grid-header-content.directive';\nexport { getToolPanelElements, getToolPanelTemplate, GridToolPanel } from './grid-tool-panel.directive';\nexport type { GridToolPanelContext } from './grid-tool-panel.directive';\nexport { GridToolbarContent } from './grid-toolbar-content.directive';\nexport type { GridToolbarContentContext } from './grid-toolbar-content.directive';\n\n// Install the tool-panel renderer bridge on the adapter. This is what\n// `adapter.createToolPanelRenderer(element)` delegates to. Without this import,\n// the method returns undefined and light-DOM `<tbw-grid-tool-panel>` Angular\n// templates are never mounted by the core ShellPlugin.\nregisterToolPanelRendererBridge((element: HTMLElement, adapter: GridAdapter) => {\n // Type inferred from `getToolPanelTemplate` (same package instance as the\n // adapter), not from a local `import type { TemplateRef } from '@angular/core'`\n // — the latter resolves through Bun's `.bun/` cache during ng-packagr build\n // and produces a brand-incompatible TemplateRef vs the built adapter `.d.ts`.\n const template = getToolPanelTemplate(element);\n if (!template) return undefined;\n\n // Find the parent grid element for context.\n const gridElement = element.closest('tbw-grid, [data-tbw-grid]') as HTMLElement | null;\n\n return (container: HTMLElement) => {\n const context: GridToolPanelContext = {\n $implicit: gridElement ?? container,\n grid: gridElement ?? container,\n };\n const viewRef = adapter.createTrackedEmbeddedView(template, context);\n viewRef.rootNodes.forEach((node: Node) => container.appendChild(node));\n return () => viewRef.destroy();\n };\n});\n","/**\n * Generated bundle index. Do not edit.\n */\n\nexport * from './index';\n"],"names":["autoIdCounter"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"toolbox-web-grid-angular-features-shell.mjs","sources":["../../../../libs/grid-angular/features/shell/src/grid-tool-panel.directive.ts","../../../../libs/grid-angular/features/shell/src/grid-header-content.directive.ts","../../../../libs/grid-angular/features/shell/src/grid-toolbar-content.directive.ts","../../../../libs/grid-angular/features/shell/src/index.ts","../../../../libs/grid-angular/features/shell/src/toolbox-web-grid-angular-features-shell.ts"],"sourcesContent":["import { contentChild, Directive, effect, ElementRef, inject, input, TemplateRef } from '@angular/core';\n\n/**\n * Context object passed to the tool panel template.\n * Provides access to grid-related information for the panel content.\n * @since 0.1.0\n */\nexport interface GridToolPanelContext {\n /** The grid element (implicit binding) */\n $implicit: HTMLElement;\n /** The grid element */\n grid: HTMLElement;\n}\n\n// Global registry mapping DOM elements to their templates\nconst toolPanelTemplateRegistry = new Map<HTMLElement, TemplateRef<GridToolPanelContext>>();\n\n/**\n * Gets the tool panel template registered for a given tool panel element.\n * Used by AngularGridAdapter to retrieve templates at render time.\n */\nexport function getToolPanelTemplate(panelElement: HTMLElement): TemplateRef<GridToolPanelContext> | undefined {\n return toolPanelTemplateRegistry.get(panelElement);\n}\n\n/**\n * Gets all tool panel elements with registered templates within a grid element.\n */\nexport function getToolPanelElements(gridElement: HTMLElement): HTMLElement[] {\n const panelElements = gridElement.querySelectorAll('tbw-grid-tool-panel');\n return Array.from(panelElements).filter((el) => toolPanelTemplateRegistry.has(el as HTMLElement)) as HTMLElement[];\n}\n\n/**\n * Directive that captures an `<ng-template>` for use as a custom tool panel.\n *\n * This enables declarative Angular component usage for tool panels\n * that appear in the grid's side panel.\n *\n * ## Usage\n *\n * ```html\n * <tbw-grid [rows]=\"rows\" [gridConfig]=\"config\">\n * <tbw-grid-tool-panel\n * id=\"quick-filters\"\n * title=\"Quick Filters\"\n * icon=\"🔍\"\n * tooltip=\"Apply quick filters\"\n * [order]=\"10\"\n * >\n * <ng-template let-grid>\n * <app-quick-filters [grid]=\"grid\" />\n * </ng-template>\n * </tbw-grid-tool-panel>\n * </tbw-grid>\n * ```\n *\n * The template context provides:\n * - `$implicit` / `grid`: The grid element reference\n *\n * ### Attributes\n *\n * - `id` (required): Unique identifier for the panel\n * - `title` (optional): Panel title shown in accordion header. Omit it when the\n * panel content provides its own heading.\n * - `icon`: Icon for accordion section header (emoji or text)\n * - `tooltip`: Tooltip for accordion section header\n * - `order`: Panel order priority (lower = first, default: 100)\n *\n * Import the directive in your component:\n *\n * ```typescript\n * import { GridToolPanel } from '@toolbox-web/grid-angular/features/shell';\n *\n * @Component({\n * imports: [GridToolPanel],\n * // ...\n * })\n * ```\n *\n * @example\n * ```html\n * <tbw-grid [rows]=\"rows\">\n * <tbw-grid-tool-panel id=\"quick-filters\" title=\"Quick Filters\" icon=\"\\uD83D\\uDD0D\">\n * <ng-template let-grid>\n * <app-quick-filters [grid]=\"grid\" />\n * </ng-template>\n * </tbw-grid-tool-panel>\n * </tbw-grid>\n * ```\n *\n * @category Directive\n * @since 0.1.0\n */\n@Directive({ selector: 'tbw-grid-tool-panel' })\nexport class GridToolPanel {\n private elementRef = inject(ElementRef<HTMLElement>);\n\n /** Unique panel identifier (required) */\n id = input.required<string>({ alias: 'id' });\n\n /**\n * Panel title shown in accordion header (optional).\n *\n * Omit it when the panel content provides its own heading. With a single\n * title-less panel the accordion header row is skipped; with multiple panels\n * a title-less header still renders so the expand/collapse control stays\n * available.\n *\n * @since 3.1.0 (previously required)\n */\n title = input<string>();\n\n /** Icon for accordion section header (emoji or text) */\n icon = input<string>();\n\n /** Tooltip for accordion section header */\n tooltip = input<string>();\n\n /** Panel order priority (lower = first, default: 100) */\n order = input<number>(100);\n\n /**\n * Query for the ng-template content child.\n */\n template = contentChild(TemplateRef<GridToolPanelContext>);\n\n /** Effect that triggers when the template is available */\n private onTemplateReceived = effect(() => {\n const template = this.template();\n const element = this.elementRef.nativeElement;\n\n if (template) {\n // Set attributes from inputs (for light DOM parsing to read)\n element.setAttribute('id', this.id());\n\n const title = this.title();\n if (title != null) {\n element.setAttribute('title', title);\n } else {\n element.removeAttribute('title');\n }\n\n const icon = this.icon();\n if (icon) element.setAttribute('icon', icon);\n\n const tooltip = this.tooltip();\n if (tooltip) element.setAttribute('tooltip', tooltip);\n\n element.setAttribute('order', String(this.order()));\n\n // Register the template for this element\n toolPanelTemplateRegistry.set(element, template);\n }\n });\n\n /**\n * Static type guard for template context.\n * Enables type inference in templates.\n */\n static ngTemplateContextGuard(dir: GridToolPanel, ctx: unknown): ctx is GridToolPanelContext {\n return true;\n }\n}\n","import {\n afterNextRender,\n contentChild,\n DestroyRef,\n Directive,\n effect,\n ElementRef,\n EmbeddedViewRef,\n inject,\n input,\n TemplateRef,\n ViewContainerRef,\n} from '@angular/core';\nimport type { DataGridElement } from '@toolbox-web/grid';\nimport type { HeaderContentDefinition } from '@toolbox-web/grid/plugins/shell';\n\n/**\n * Context object passed to the header content template.\n * @since 1.7.0\n */\nexport interface GridHeaderContentContext {\n /** The grid element (implicit binding for `let-grid`). */\n $implicit: DataGridElement;\n /** The grid element. */\n grid: DataGridElement;\n}\n\nlet autoIdCounter = 0;\n\n/**\n * Declarative wrapper around the grid's imperative\n * {@link ShellPlugin.registerHeaderContent} API.\n *\n * Captures an `<ng-template>` and mounts it as an Angular embedded view into\n * the slot the grid provides for header content. Must be a child of\n * `<tbw-grid>`.\n *\n * ## Usage\n *\n * ```html\n * <tbw-grid [rows]=\"rows\" [gridConfig]=\"config\">\n * <tbw-grid-header-content id=\"calendar-nav\" [order]=\"0\">\n * <ng-template let-grid>\n * <app-header-nav [year]=\"year()\" (yearChange)=\"setYear($event)\" />\n * </ng-template>\n * </tbw-grid-header-content>\n * </tbw-grid>\n * ```\n *\n * @category Directive\n * @since 1.7.0\n */\n@Directive({ selector: 'tbw-grid-header-content', standalone: true })\nexport class GridHeaderContent {\n private elementRef = inject(ElementRef<HTMLElement>);\n private viewContainerRef = inject(ViewContainerRef);\n private destroyRef = inject(DestroyRef);\n\n /** Unique identifier for this header content entry. Optional — defaults to a stable generated id. */\n id = input<string | undefined>(undefined);\n\n /** Render order priority. Lower values appear first. @default 100 */\n order = input<number>(100);\n\n /** The template to mount into the grid's header content slot. */\n template = contentChild(TemplateRef<GridHeaderContentContext>);\n\n private viewRef: EmbeddedViewRef<GridHeaderContentContext> | null = null;\n private registeredId: string | null = null;\n private resolvedId = `tbw-header-content-${++autoIdCounter}`;\n private destroyed = false;\n\n constructor() {\n afterNextRender(() => {\n void this.register();\n });\n\n this.destroyRef.onDestroy(() => {\n this.destroyed = true;\n this.unregister();\n });\n\n // Re-register when id or order changes after mount.\n effect(() => {\n const nextId = this.id() ?? this.resolvedId;\n const nextOrder = this.order();\n if (this.registeredId && this.registeredId !== nextId) {\n this.unregister();\n void this.register();\n return;\n }\n if (this.registeredId && nextOrder !== this.lastOrder) {\n this.unregister();\n void this.register();\n }\n this.lastOrder = nextOrder;\n });\n }\n\n private lastOrder: number | undefined;\n\n private async register(): Promise<void> {\n const grid = this.findGrid();\n if (!grid) return;\n try {\n await grid.ready?.();\n } catch {\n return;\n }\n if (this.destroyed) return;\n\n const template = this.template();\n const id = this.id() ?? this.resolvedId;\n const order = this.order();\n\n const def: HeaderContentDefinition = {\n id,\n order,\n render: (container) => {\n if (!template) return undefined;\n // Sticky container: the shell may re-invoke `render` with the SAME\n // container across refreshes. If our embedded view is still attached\n // inside it, the previous render is live and this is a refresh — do\n // nothing (no-op cleanup preserves child state).\n const firstNode = this.viewRef?.rootNodes[0] as Node | undefined;\n if (this.viewRef && firstNode && container.contains(firstNode)) {\n return () => {\n /* intentionally empty */\n };\n }\n // Fresh container (first render or container was replaced) — destroy\n // any stale view, then build a new one.\n if (this.viewRef) {\n this.viewRef.destroy();\n this.viewRef = null;\n }\n this.viewRef = this.viewContainerRef.createEmbeddedView(template, {\n $implicit: grid,\n grid,\n });\n this.viewRef.detectChanges();\n for (const node of this.viewRef.rootNodes as Node[]) {\n container.appendChild(node);\n }\n // No-op cleanup: the grid may call this between re-renders before\n // invoking `render` again with the SAME container. Tearing the view\n // down here would destroy any internal state in the projected\n // template on every shell refresh. Teardown happens in `unregister`\n // (component destroy / id / order change).\n return () => {\n /* intentionally empty */\n };\n },\n };\n // Route through the shell plugin (#370). The shell is opt-in at v3 —\n // content registers only when a shell plugin is present.\n grid.getPluginByName?.('shell')?.registerHeaderContent(def);\n this.registeredId = id;\n }\n\n private unregister(): void {\n const grid = this.findGrid();\n if (grid && this.registeredId) {\n grid.getPluginByName?.('shell')?.unregisterHeaderContent(this.registeredId);\n }\n this.registeredId = null;\n if (this.viewRef) {\n this.viewRef.destroy();\n this.viewRef = null;\n }\n }\n\n private findGrid(): DataGridElement | null {\n const host = this.elementRef.nativeElement;\n // Use the stable `[data-tbw-grid]` attribute (set by core on connect) rather\n // than the literal `tbw-grid` tag, so a version-suffixed grid host (e.g.\n // `<tbw-grid-v2-15-0>`) is still found. See the multi-version guide.\n const grid = host.closest('[data-tbw-grid]') as DataGridElement | null;\n return grid;\n }\n\n /** Type guard for template context inference. */\n static ngTemplateContextGuard(_dir: GridHeaderContent, ctx: unknown): ctx is GridHeaderContentContext {\n return true;\n }\n}\n","import {\n afterNextRender,\n contentChild,\n DestroyRef,\n Directive,\n effect,\n ElementRef,\n EmbeddedViewRef,\n inject,\n input,\n TemplateRef,\n ViewContainerRef,\n} from '@angular/core';\nimport type { DataGridElement } from '@toolbox-web/grid';\nimport type { ToolbarContentDefinition } from '@toolbox-web/grid/plugins/shell';\n\n/**\n * Context object passed to the toolbar content template.\n * @since 1.7.0\n */\nexport interface GridToolbarContentContext {\n /** The grid element (implicit binding for `let-grid`). */\n $implicit: DataGridElement;\n /** The grid element. */\n grid: DataGridElement;\n}\n\nlet autoIdCounter = 0;\n\n/**\n * Declarative wrapper around the grid's imperative\n * {@link ShellPlugin.registerToolbarContent} API.\n *\n * Captures an `<ng-template>` and mounts it as an Angular embedded view into\n * the slot the grid provides for toolbar content. Must be a child of\n * `<tbw-grid>`.\n *\n * Prefer this over `<tbw-grid-tool-buttons>` (light DOM) when you need\n * Angular template bindings to component state. Use the light-DOM form for\n * static markup that should be moved verbatim into the toolbar.\n *\n * ## Usage\n *\n * ```html\n * <tbw-grid [rows]=\"rows\" [gridConfig]=\"config\">\n * <tbw-grid-toolbar-content id=\"calendar-nav\" [order]=\"0\">\n * <ng-template let-grid>\n * <app-toolbar-nav (prev)=\"prev()\" (today)=\"today()\" (next)=\"next()\" />\n * </ng-template>\n * </tbw-grid-toolbar-content>\n * </tbw-grid>\n * ```\n *\n * @category Directive\n * @since 1.7.0\n */\n@Directive({ selector: 'tbw-grid-toolbar-content', standalone: true })\nexport class GridToolbarContent {\n private elementRef = inject(ElementRef<HTMLElement>);\n private viewContainerRef = inject(ViewContainerRef);\n private destroyRef = inject(DestroyRef);\n\n id = input<string | undefined>(undefined);\n order = input<number>(100);\n template = contentChild(TemplateRef<GridToolbarContentContext>);\n\n private viewRef: EmbeddedViewRef<GridToolbarContentContext> | null = null;\n private registeredId: string | null = null;\n private resolvedId = `tbw-toolbar-content-${++autoIdCounter}`;\n private lastOrder: number | undefined;\n private destroyed = false;\n\n constructor() {\n afterNextRender(() => {\n void this.register();\n });\n\n this.destroyRef.onDestroy(() => {\n this.destroyed = true;\n this.unregister();\n });\n\n effect(() => {\n const nextId = this.id() ?? this.resolvedId;\n const nextOrder = this.order();\n if (this.registeredId && this.registeredId !== nextId) {\n this.unregister();\n void this.register();\n return;\n }\n if (this.registeredId && nextOrder !== this.lastOrder) {\n this.unregister();\n void this.register();\n }\n this.lastOrder = nextOrder;\n });\n }\n\n private async register(): Promise<void> {\n const grid = this.findGrid();\n if (!grid) return;\n try {\n await grid.ready?.();\n } catch {\n return;\n }\n if (this.destroyed) return;\n\n const template = this.template();\n const id = this.id() ?? this.resolvedId;\n const order = this.order();\n\n const def: ToolbarContentDefinition = {\n id,\n order,\n render: (container) => {\n if (!template) return undefined;\n // Sticky container: see grid-header-content.directive.ts for rationale.\n const firstNode = this.viewRef?.rootNodes[0] as Node | undefined;\n if (this.viewRef && firstNode && container.contains(firstNode)) {\n return () => {\n /* intentionally empty */\n };\n }\n if (this.viewRef) {\n this.viewRef.destroy();\n this.viewRef = null;\n }\n this.viewRef = this.viewContainerRef.createEmbeddedView(template, {\n $implicit: grid,\n grid,\n });\n this.viewRef.detectChanges();\n for (const node of this.viewRef.rootNodes as Node[]) {\n container.appendChild(node);\n }\n // No-op cleanup — see comment in grid-header-content.directive.ts.\n return () => {\n /* intentionally empty */\n };\n },\n };\n // Route through the shell plugin (#370). The shell is opt-in at v3 —\n // content registers only when a shell plugin is present.\n grid.getPluginByName?.('shell')?.registerToolbarContent(def);\n this.registeredId = id;\n }\n\n private unregister(): void {\n const grid = this.findGrid();\n if (grid && this.registeredId) {\n grid.getPluginByName?.('shell')?.unregisterToolbarContent(this.registeredId);\n }\n this.registeredId = null;\n if (this.viewRef) {\n this.viewRef.destroy();\n this.viewRef = null;\n }\n }\n\n private findGrid(): DataGridElement | null {\n const host = this.elementRef.nativeElement;\n // Use the stable `[data-tbw-grid]` attribute (set by core on connect) rather\n // than the literal `tbw-grid` tag, so a version-suffixed grid host (e.g.\n // `<tbw-grid-v2-15-0>`) is still found. See the multi-version guide.\n return host.closest('[data-tbw-grid]') as DataGridElement | null;\n }\n\n static ngTemplateContextGuard(_dir: GridToolbarContent, ctx: unknown): ctx is GridToolbarContentContext {\n return true;\n }\n}\n","/**\n * Shell feature for @toolbox-web/grid-angular\n *\n * Import this module to opt the grid shell (header bar + tool panels) into\n * the build. The shell is opt-in and tree-shakeable — nothing is registered\n * unless this entry point is imported.\n *\n * The shell is configured through `gridConfig` (`features: { shell }` or the\n * `<tbw-grid-header-content>` / `<tbw-grid-toolbar-content>` /\n * `<tbw-grid-tool-panel>` directives), not a boolean input.\n *\n * @example\n * ```typescript\n * // In your bootstrap (e.g. main.ts or app.component.ts):\n * import '@toolbox-web/grid-angular/features/shell';\n * ```\n *\n * ```html\n * <tbw-grid [gridConfig]=\"{ features: { shell: { header: { title: 'Employees' } } } }\">\n * </tbw-grid>\n * ```\n *\n * @packageDocumentation\n */\n\nimport { registerToolPanelRendererBridge, type GridAdapter } from '@toolbox-web/grid-angular';\nimport '@toolbox-web/grid/features/shell';\nimport { getToolPanelTemplate, type GridToolPanelContext } from './grid-tool-panel.directive';\n\nexport type { _Augmentation as _ShellAugmentation } from '@toolbox-web/grid/features/shell';\n\n// ---------------------------------------------------------------------------\n// Shell-owned directives + helpers. These physically live in this secondary\n// entry (the runtime behaviour lives here too).\n// ---------------------------------------------------------------------------\nexport { GridHeaderContent } from './grid-header-content.directive';\nexport type { GridHeaderContentContext } from './grid-header-content.directive';\nexport { getToolPanelElements, getToolPanelTemplate, GridToolPanel } from './grid-tool-panel.directive';\nexport type { GridToolPanelContext } from './grid-tool-panel.directive';\nexport { GridToolbarContent } from './grid-toolbar-content.directive';\nexport type { GridToolbarContentContext } from './grid-toolbar-content.directive';\n\n// Install the tool-panel renderer bridge on the adapter. This is what\n// `adapter.createToolPanelRenderer(element)` delegates to. Without this import,\n// the method returns undefined and light-DOM `<tbw-grid-tool-panel>` Angular\n// templates are never mounted by the core ShellPlugin.\nregisterToolPanelRendererBridge((element: HTMLElement, adapter: GridAdapter) => {\n // Type inferred from `getToolPanelTemplate` (same package instance as the\n // adapter), not from a local `import type { TemplateRef } from '@angular/core'`\n // — the latter resolves through Bun's `.bun/` cache during ng-packagr build\n // and produces a brand-incompatible TemplateRef vs the built adapter `.d.ts`.\n const template = getToolPanelTemplate(element);\n if (!template) return undefined;\n\n // Find the parent grid element for context.\n const gridElement = element.closest('tbw-grid, [data-tbw-grid]') as HTMLElement | null;\n\n return (container: HTMLElement) => {\n const context: GridToolPanelContext = {\n $implicit: gridElement ?? container,\n grid: gridElement ?? container,\n };\n const viewRef = adapter.createTrackedEmbeddedView(template, context);\n viewRef.rootNodes.forEach((node: Node) => container.appendChild(node));\n return () => viewRef.destroy();\n };\n});\n","/**\n * Generated bundle index. Do not edit.\n */\n\nexport * from './index';\n"],"names":["autoIdCounter"],"mappings":"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"}
|
|
@@ -4,13 +4,13 @@ import { inject, ElementRef, input, output, Directive } from '@angular/core';
|
|
|
4
4
|
import { registerFeatureClaim, claimEvent, unregisterFeatureClaim, unclaimEvent } from '@toolbox-web/grid-angular';
|
|
5
5
|
|
|
6
6
|
/**
|
|
7
|
-
* `GridTreeDirective` — owns `[tree]` and
|
|
7
|
+
* `GridTreeDirective` — owns `[tree]` and the tree outputs on `<tbw-grid>`.
|
|
8
8
|
* See `GridFilteringDirective` for the full rationale.
|
|
9
9
|
*
|
|
10
10
|
* @category Directive
|
|
11
11
|
*/
|
|
12
12
|
/**
|
|
13
|
-
* Owns the binding(s) `[tree], [treeExpand]` on `<tbw-grid>` for the matching feature plugin. See `GridFilteringDirective` for the full rationale.
|
|
13
|
+
* Owns the binding(s) `[tree], [treeExpand], [treeLoadStart], [treeLoadEnd], [treeLoadError]` on `<tbw-grid>` for the matching feature plugin. See `GridFilteringDirective` for the full rationale.
|
|
14
14
|
*
|
|
15
15
|
* @category Directive
|
|
16
16
|
*/
|
|
@@ -20,37 +20,70 @@ class GridTreeDirective {
|
|
|
20
20
|
...(ngDevMode ? [undefined, { debugName: "tree" }] : /* istanbul ignore next */ []));
|
|
21
21
|
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
22
22
|
treeExpand = output();
|
|
23
|
-
|
|
23
|
+
/**
|
|
24
|
+
* Fired when lazy child loading starts for a tree node.
|
|
25
|
+
*
|
|
26
|
+
* @since 2.3.0
|
|
27
|
+
*/
|
|
28
|
+
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
29
|
+
treeLoadStart = output();
|
|
30
|
+
/**
|
|
31
|
+
* Fired when lazy child loading completes and children are merged into the parent row.
|
|
32
|
+
*
|
|
33
|
+
* @since 2.3.0
|
|
34
|
+
*/
|
|
35
|
+
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
36
|
+
treeLoadEnd = output();
|
|
37
|
+
/**
|
|
38
|
+
* Fired when lazy child loading fails. Re-expanding the node retries the fetch.
|
|
39
|
+
*
|
|
40
|
+
* @since 2.3.0
|
|
41
|
+
*/
|
|
42
|
+
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
43
|
+
treeLoadError = output();
|
|
44
|
+
listeners = new Map();
|
|
45
|
+
static EVENTS = ['tree-expand', 'tree-load-start', 'tree-load-end', 'tree-load-error'];
|
|
24
46
|
constructor() {
|
|
25
47
|
const grid = this.elementRef.nativeElement;
|
|
26
48
|
registerFeatureClaim(grid, 'tree', () => this.tree());
|
|
27
|
-
|
|
49
|
+
for (const ev of GridTreeDirective.EVENTS)
|
|
50
|
+
claimEvent(grid, ev);
|
|
28
51
|
}
|
|
29
52
|
ngOnInit() {
|
|
30
53
|
const grid = this.elementRef.nativeElement;
|
|
54
|
+
const wire = (name, out) => {
|
|
55
|
+
const l = (e) => out.emit(e.detail);
|
|
56
|
+
grid.addEventListener(name, l);
|
|
57
|
+
this.listeners.set(name, l);
|
|
58
|
+
};
|
|
59
|
+
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
60
|
+
wire('tree-expand', this.treeExpand);
|
|
61
|
+
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
62
|
+
wire('tree-load-start', this.treeLoadStart);
|
|
63
|
+
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
64
|
+
wire('tree-load-end', this.treeLoadEnd);
|
|
31
65
|
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
32
|
-
|
|
33
|
-
grid.addEventListener('tree-expand', this.listener);
|
|
66
|
+
wire('tree-load-error', this.treeLoadError);
|
|
34
67
|
}
|
|
35
68
|
ngOnDestroy() {
|
|
36
69
|
const grid = this.elementRef.nativeElement;
|
|
37
|
-
|
|
38
|
-
grid.removeEventListener(
|
|
39
|
-
|
|
40
|
-
}
|
|
70
|
+
for (const [name, l] of this.listeners)
|
|
71
|
+
grid.removeEventListener(name, l);
|
|
72
|
+
this.listeners.clear();
|
|
41
73
|
unregisterFeatureClaim(grid, 'tree');
|
|
42
|
-
|
|
74
|
+
for (const ev of GridTreeDirective.EVENTS)
|
|
75
|
+
unclaimEvent(grid, ev);
|
|
43
76
|
}
|
|
44
77
|
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "22.0.6", ngImport: i0, type: GridTreeDirective, deps: [], target: i0.ɵɵFactoryTarget.Directive });
|
|
45
|
-
static ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "17.1.0", version: "22.0.6", type: GridTreeDirective, isStandalone: true, selector: "tbw-grid[tree], tbw-grid[treeExpand]", inputs: { tree: { classPropertyName: "tree", publicName: "tree", isSignal: true, isRequired: false, transformFunction: null } }, outputs: { treeExpand: "treeExpand" }, ngImport: i0 });
|
|
78
|
+
static ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "17.1.0", version: "22.0.6", type: GridTreeDirective, isStandalone: true, selector: "tbw-grid[tree], tbw-grid[treeExpand], tbw-grid[treeLoadStart], tbw-grid[treeLoadEnd], tbw-grid[treeLoadError]", inputs: { tree: { classPropertyName: "tree", publicName: "tree", isSignal: true, isRequired: false, transformFunction: null } }, outputs: { treeExpand: "treeExpand", treeLoadStart: "treeLoadStart", treeLoadEnd: "treeLoadEnd", treeLoadError: "treeLoadError" }, ngImport: i0 });
|
|
46
79
|
}
|
|
47
80
|
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.0.6", ngImport: i0, type: GridTreeDirective, decorators: [{
|
|
48
81
|
type: Directive,
|
|
49
82
|
args: [{
|
|
50
|
-
selector: 'tbw-grid[tree], tbw-grid[treeExpand]',
|
|
83
|
+
selector: 'tbw-grid[tree], tbw-grid[treeExpand], tbw-grid[treeLoadStart], tbw-grid[treeLoadEnd], tbw-grid[treeLoadError]',
|
|
51
84
|
standalone: true,
|
|
52
85
|
}]
|
|
53
|
-
}], ctorParameters: () => [], propDecorators: { tree: [{ type: i0.Input, args: [{ isSignal: true, alias: "tree", required: false }] }], treeExpand: [{ type: i0.Output, args: ["treeExpand"] }] } });
|
|
86
|
+
}], ctorParameters: () => [], propDecorators: { tree: [{ type: i0.Input, args: [{ isSignal: true, alias: "tree", required: false }] }], treeExpand: [{ type: i0.Output, args: ["treeExpand"] }], treeLoadStart: [{ type: i0.Output, args: ["treeLoadStart"] }], treeLoadEnd: [{ type: i0.Output, args: ["treeLoadEnd"] }], treeLoadError: [{ type: i0.Output, args: ["treeLoadError"] }] } });
|
|
54
87
|
|
|
55
88
|
/**
|
|
56
89
|
* Tree feature for @toolbox-web/grid-angular
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"toolbox-web-grid-angular-features-tree.mjs","sources":["../../../../libs/grid-angular/features/tree/src/grid-tree.directive.ts","../../../../libs/grid-angular/features/tree/src/index.ts","../../../../libs/grid-angular/features/tree/src/toolbox-web-grid-angular-features-tree.ts"],"sourcesContent":["/**\n * `GridTreeDirective` — owns `[tree]` and
|
|
1
|
+
{"version":3,"file":"toolbox-web-grid-angular-features-tree.mjs","sources":["../../../../libs/grid-angular/features/tree/src/grid-tree.directive.ts","../../../../libs/grid-angular/features/tree/src/index.ts","../../../../libs/grid-angular/features/tree/src/toolbox-web-grid-angular-features-tree.ts"],"sourcesContent":["/**\n * `GridTreeDirective` — owns `[tree]` and the tree outputs on `<tbw-grid>`.\n * See `GridFilteringDirective` for the full rationale.\n *\n * @category Directive\n */\nimport { Directive, ElementRef, inject, input, OnDestroy, OnInit, output } from '@angular/core';\nimport type { DataGridElement } from '@toolbox-web/grid';\nimport { claimEvent, registerFeatureClaim, unclaimEvent, unregisterFeatureClaim } from '@toolbox-web/grid-angular';\nimport type {\n TreeConfig,\n TreeExpandDetail,\n TreeLoadEndDetail,\n TreeLoadErrorDetail,\n TreeLoadStartDetail,\n} from '@toolbox-web/grid/plugins/tree';\n\n/**\n * Owns the binding(s) `[tree], [treeExpand], [treeLoadStart], [treeLoadEnd], [treeLoadError]` on `<tbw-grid>` for the matching feature plugin. See `GridFilteringDirective` for the full rationale.\n *\n * @category Directive\n */\n@Directive({\n selector:\n 'tbw-grid[tree], tbw-grid[treeExpand], tbw-grid[treeLoadStart], tbw-grid[treeLoadEnd], tbw-grid[treeLoadError]',\n standalone: true,\n})\nexport class GridTreeDirective implements OnInit, OnDestroy {\n private readonly elementRef = inject(ElementRef<DataGridElement>);\n\n readonly tree = input<boolean | TreeConfig>();\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\n readonly treeExpand = output<TreeExpandDetail<any>>();\n /**\n * Fired when lazy child loading starts for a tree node.\n *\n * @since 2.3.0\n */\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\n readonly treeLoadStart = output<TreeLoadStartDetail<any>>();\n /**\n * Fired when lazy child loading completes and children are merged into the parent row.\n *\n * @since 2.3.0\n */\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\n readonly treeLoadEnd = output<TreeLoadEndDetail<any>>();\n /**\n * Fired when lazy child loading fails. Re-expanding the node retries the fetch.\n *\n * @since 2.3.0\n */\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\n readonly treeLoadError = output<TreeLoadErrorDetail<any>>();\n\n private readonly listeners = new Map<string, (e: Event) => void>();\n private static readonly EVENTS = ['tree-expand', 'tree-load-start', 'tree-load-end', 'tree-load-error'] as const;\n\n constructor() {\n const grid = this.elementRef.nativeElement;\n registerFeatureClaim(grid, 'tree', () => this.tree());\n for (const ev of GridTreeDirective.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 // eslint-disable-next-line @typescript-eslint/no-explicit-any\n wire<TreeExpandDetail<any>>('tree-expand', this.treeExpand);\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\n wire<TreeLoadStartDetail<any>>('tree-load-start', this.treeLoadStart);\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\n wire<TreeLoadEndDetail<any>>('tree-load-end', this.treeLoadEnd);\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\n wire<TreeLoadErrorDetail<any>>('tree-load-error', this.treeLoadError);\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, 'tree');\n for (const ev of GridTreeDirective.EVENTS) unclaimEvent(grid, ev);\n }\n}\n","/**\n * Tree feature for @toolbox-web/grid-angular\n *\n * Import this module to enable the `tree` input on Grid directive.\n *\n * @example\n * ```typescript\n * import '@toolbox-web/grid-angular/features/tree';\n *\n * <tbw-grid [tree]=\"{ childrenField: 'children' }\" />\n * ```\n *\n * @packageDocumentation\n */\n\nimport '@toolbox-web/grid/features/tree';\nexport { GridTreeDirective } from './grid-tree.directive';\nexport type { _Augmentation as _TreeAugmentation } from '@toolbox-web/grid/features/tree';\n","/**\n * Generated bundle index. Do not edit.\n */\n\nexport * from './index';\n"],"names":[],"mappings":"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"}
|
|
@@ -2693,6 +2693,13 @@ class Grid {
|
|
|
2693
2693
|
tbwScroll: 'tbw-scroll',
|
|
2694
2694
|
render: 'render',
|
|
2695
2695
|
};
|
|
2696
|
+
/**
|
|
2697
|
+
* Compile-time assertion — assigning `true` only type-checks while the
|
|
2698
|
+
* conditional below resolves to `true`. Do not turn this back into a
|
|
2699
|
+
* `declare`d property: a bare declaration is never checked, which silently
|
|
2700
|
+
* disabled this guard for several releases.
|
|
2701
|
+
*/
|
|
2702
|
+
_assertEventOutputMapCoversCore = true;
|
|
2696
2703
|
// Store event listeners for cleanup
|
|
2697
2704
|
eventListeners = new Map();
|
|
2698
2705
|
ngOnInit() {
|