@toolbox-web/grid-angular 2.0.0 → 2.2.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/fesm2022/toolbox-web-grid-angular-features-grouping-columns.mjs.map +1 -1
- package/fesm2022/toolbox-web-grid-angular-features-grouping-rows.mjs.map +1 -1
- package/fesm2022/toolbox-web-grid-angular-features-pinned-rows.mjs.map +1 -1
- package/fesm2022/toolbox-web-grid-angular-features-shell.mjs +23 -6
- package/fesm2022/toolbox-web-grid-angular-features-shell.mjs.map +1 -1
- package/fesm2022/toolbox-web-grid-angular.mjs +67 -1
- 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 +3 -2
- package/types/toolbox-web-grid-angular-features-editing.d.ts.map +1 -1
- package/types/toolbox-web-grid-angular-features-grouping-columns.d.ts +1 -5
- package/types/toolbox-web-grid-angular-features-grouping-columns.d.ts.map +1 -1
- package/types/toolbox-web-grid-angular-features-grouping-rows.d.ts +1 -3
- package/types/toolbox-web-grid-angular-features-grouping-rows.d.ts.map +1 -1
- package/types/toolbox-web-grid-angular-features-pinned-rows.d.ts +1 -11
- package/types/toolbox-web-grid-angular-features-pinned-rows.d.ts.map +1 -1
- package/types/toolbox-web-grid-angular-features-shell.d.ts +14 -4
- package/types/toolbox-web-grid-angular-features-shell.d.ts.map +1 -1
- package/types/toolbox-web-grid-angular.d.ts +13 -7
- package/types/toolbox-web-grid-angular.d.ts.map +1 -1
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"toolbox-web-grid-angular-features-grouping-columns.mjs","sources":["../../../../libs/grid-angular/features/grouping-columns/src/grid-grouping-columns.directive.ts","../../../../libs/grid-angular/features/grouping-columns/src/index.ts","../../../../libs/grid-angular/features/grouping-columns/src/toolbox-web-grid-angular-features-grouping-columns.ts"],"sourcesContent":["/**\n * `GridGroupingColumnsDirective` — owns `[groupingColumns]` on\n * `<tbw-grid>`. No event outputs. See `GridFilteringDirective` for the\n * full rationale.\n *\n * @category Directive\n */\nimport { Directive, ElementRef, inject, input, OnDestroy, type Type } from '@angular/core';\nimport type { DataGridElement } from '@toolbox-web/grid';\nimport { registerFeatureClaim, unregisterFeatureClaim } from '@toolbox-web/grid-angular';\nimport type {\n ColumnGroupDefinition as CoreColumnGroupDefinition,\n GroupingColumnsConfig as CoreGroupingColumnsConfig,\n GroupHeaderRenderParams,\n} from '@toolbox-web/grid/plugins/grouping-columns';\n\n/**\n * Column group definition widened to accept an Angular component class as\n * the per-group `renderer`.\n *\n * @since 1.7.0\n */\nexport type ColumnGroupDefinition = Omit<CoreColumnGroupDefinition, 'renderer'> & {\n renderer?: CoreColumnGroupDefinition['renderer'] | Type<unknown>;\n};\n\n/**\n * Grouping-columns config widened to accept Angular component classes for\n * `groupHeaderRenderer` and per-group `renderer` inside `columnGroups`.\n *\n * Component instances receive the {@link GroupHeaderRenderParams} fields as\n * inputs (`id`, `label`, `columns`, `firstIndex`, `isImplicit`).\n *\n * @since 1.7.0\n */\nexport type GroupingColumnsConfig = Omit<CoreGroupingColumnsConfig, 'groupHeaderRenderer' | 'columnGroups'> & {\n columnGroups?: ColumnGroupDefinition[];\n groupHeaderRenderer?: CoreGroupingColumnsConfig['groupHeaderRenderer'] | Type<unknown>;\n};\n\n
|
|
1
|
+
{"version":3,"file":"toolbox-web-grid-angular-features-grouping-columns.mjs","sources":["../../../../libs/grid-angular/features/grouping-columns/src/grid-grouping-columns.directive.ts","../../../../libs/grid-angular/features/grouping-columns/src/index.ts","../../../../libs/grid-angular/features/grouping-columns/src/toolbox-web-grid-angular-features-grouping-columns.ts"],"sourcesContent":["/**\n * `GridGroupingColumnsDirective` — owns `[groupingColumns]` on\n * `<tbw-grid>`. No event outputs. See `GridFilteringDirective` for the\n * full rationale.\n *\n * @category Directive\n */\nimport { Directive, ElementRef, inject, input, OnDestroy, type Type } from '@angular/core';\nimport type { DataGridElement } from '@toolbox-web/grid';\nimport { registerFeatureClaim, unregisterFeatureClaim } from '@toolbox-web/grid-angular';\nimport type {\n ColumnGroupDefinition as CoreColumnGroupDefinition,\n GroupingColumnsConfig as CoreGroupingColumnsConfig,\n GroupHeaderRenderParams,\n} from '@toolbox-web/grid/plugins/grouping-columns';\n\n/**\n * Column group definition widened to accept an Angular component class as\n * the per-group `renderer`.\n *\n * @since 1.7.0\n */\nexport type ColumnGroupDefinition = Omit<CoreColumnGroupDefinition, 'renderer'> & {\n renderer?: CoreColumnGroupDefinition['renderer'] | Type<unknown>;\n};\n\n/**\n * Grouping-columns config widened to accept Angular component classes for\n * `groupHeaderRenderer` and per-group `renderer` inside `columnGroups`.\n *\n * Component instances receive the {@link GroupHeaderRenderParams} fields as\n * inputs (`id`, `label`, `columns`, `firstIndex`, `isImplicit`).\n *\n * @since 1.7.0\n */\nexport type GroupingColumnsConfig = Omit<CoreGroupingColumnsConfig, 'groupHeaderRenderer' | 'columnGroups'> & {\n columnGroups?: ColumnGroupDefinition[];\n groupHeaderRenderer?: CoreGroupingColumnsConfig['groupHeaderRenderer'] | Type<unknown>;\n};\n\n/**\n * Owns the binding(s) `[groupingColumns]` on `<tbw-grid>` for the matching feature plugin. See `GridFilteringDirective` for the full rationale.\n *\n * @category Directive\n */\n@Directive({\n selector: 'tbw-grid[groupingColumns]',\n standalone: true,\n})\nexport class GridGroupingColumnsDirective implements OnDestroy {\n private readonly elementRef = inject(ElementRef<DataGridElement>);\n\n readonly groupingColumns = input<boolean | GroupingColumnsConfig>();\n\n constructor() {\n registerFeatureClaim(this.elementRef.nativeElement, 'groupingColumns', () => this.groupingColumns());\n }\n\n ngOnDestroy(): void {\n unregisterFeatureClaim(this.elementRef.nativeElement, 'groupingColumns');\n }\n}\n","/**\n * Column grouping feature for @toolbox-web/grid-angular\n *\n * Import this module to enable the `groupingColumns` input on Grid directive.\n *\n * @example\n * ```typescript\n * import '@toolbox-web/grid-angular/features/grouping-columns';\n *\n * <tbw-grid [groupingColumns]=\"{ columnGroups: [...] }\" />\n * ```\n *\n * @packageDocumentation\n */\n\nimport type { Type } from '@angular/core';\nimport { isComponentClass, registerFeatureConfigPreprocessor, type GridAdapter } from '@toolbox-web/grid-angular';\nimport '@toolbox-web/grid/features/grouping-columns';\nimport type {\n GroupingColumnsConfig as CoreGroupingColumnsConfig,\n GroupHeaderRenderParams,\n} from '@toolbox-web/grid/plugins/grouping-columns';\nexport {\n GridGroupingColumnsDirective,\n // Canonical (unprefixed) widening types.\n type ColumnGroupDefinition,\n type GroupingColumnsConfig,\n} from './grid-grouping-columns.directive';\nexport type { _Augmentation as _GroupingColumnsAugmentation } from '@toolbox-web/grid/features/grouping-columns';\n\n/**\n * Build a group-header renderer function from an Angular component class.\n * The component should accept group header inputs (id, label, columns, firstIndex, isImplicit).\n */\nfunction buildGroupHeaderRenderer(\n adapter: GridAdapter,\n componentClass: Type<unknown>,\n): (params: GroupHeaderRenderParams) => HTMLElement {\n const mount = adapter.mountComponentRenderer<GroupHeaderRenderParams>(componentClass, (p) => ({\n id: p.id,\n label: p.label,\n columns: p.columns,\n firstIndex: p.firstIndex,\n isImplicit: p.isImplicit,\n }));\n return (params) => mount(params).hostElement;\n}\n\n// Bridge any Angular component classes embedded in the user-supplied config\n// (e.g. group-header renderers) to plain renderer functions before the core\n// plugin factory consumes the config. Without this, raw component classes\n// would be invoked without `new`, causing runtime errors.\nregisterFeatureConfigPreprocessor('groupingColumns', (config, adapter) => {\n if (!config || typeof config !== 'object') return config;\n const cfg = config as CoreGroupingColumnsConfig;\n const processed = { ...cfg };\n let changed = false;\n\n // Bridge top-level groupHeaderRenderer component class\n if (cfg.groupHeaderRenderer && isComponentClass(cfg.groupHeaderRenderer)) {\n processed.groupHeaderRenderer = buildGroupHeaderRenderer(adapter, cfg.groupHeaderRenderer);\n changed = true;\n }\n\n // Bridge per-group renderer component classes inside columnGroups\n if (Array.isArray(cfg.columnGroups)) {\n let groupChanged = false;\n const mappedGroups = cfg.columnGroups.map((def) => {\n if (def.renderer && isComponentClass(def.renderer)) {\n groupChanged = true;\n return { ...def, renderer: buildGroupHeaderRenderer(adapter, def.renderer) };\n }\n return def;\n });\n if (groupChanged) {\n processed.columnGroups = mappedGroups;\n changed = true;\n }\n }\n\n return changed ? processed : cfg;\n});\n","/**\n * Generated bundle index. Do not edit.\n */\n\nexport * from './index';\n"],"names":[],"mappings":"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"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"toolbox-web-grid-angular-features-grouping-rows.mjs","sources":["../../../../libs/grid-angular/features/grouping-rows/src/grid-grouping-rows.directive.ts","../../../../libs/grid-angular/features/grouping-rows/src/index.ts","../../../../libs/grid-angular/features/grouping-rows/src/toolbox-web-grid-angular-features-grouping-rows.ts"],"sourcesContent":["/**\n * `GridGroupingRowsDirective` — owns `[groupingRows]` and the group\n * toggle/expand/collapse outputs on `<tbw-grid>`. See\n * `GridFilteringDirective` for the full rationale.\n *\n * @category Directive\n */\nimport { Directive, ElementRef, inject, input, OnDestroy, OnInit, output, type Type } from '@angular/core';\nimport type { DataGridElement } from '@toolbox-web/grid';\nimport { claimEvent, registerFeatureClaim, unclaimEvent, unregisterFeatureClaim } from '@toolbox-web/grid-angular';\nimport type {\n GroupingRowsConfig as CoreGroupingRowsConfig,\n GroupCollapseDetail,\n GroupExpandDetail,\n GroupRowRenderParams,\n GroupToggleDetail,\n} from '@toolbox-web/grid/plugins/grouping-rows';\n\n/**\n * Grouping-rows config widened to accept an Angular component class as\n * `groupRowRenderer`.\n *\n * Component instances receive the {@link GroupRowRenderParams} fields as\n * inputs (`key`, `value`, `depth`, `rows`, `expanded`, `toggleExpand`).\n *\n * @since 1.7.0\n */\nexport type GroupingRowsConfig = Omit<CoreGroupingRowsConfig, 'groupRowRenderer'> & {\n groupRowRenderer?: CoreGroupingRowsConfig['groupRowRenderer'] | Type<unknown>;\n};\n\n
|
|
1
|
+
{"version":3,"file":"toolbox-web-grid-angular-features-grouping-rows.mjs","sources":["../../../../libs/grid-angular/features/grouping-rows/src/grid-grouping-rows.directive.ts","../../../../libs/grid-angular/features/grouping-rows/src/index.ts","../../../../libs/grid-angular/features/grouping-rows/src/toolbox-web-grid-angular-features-grouping-rows.ts"],"sourcesContent":["/**\n * `GridGroupingRowsDirective` — owns `[groupingRows]` and the group\n * toggle/expand/collapse outputs on `<tbw-grid>`. See\n * `GridFilteringDirective` for the full rationale.\n *\n * @category Directive\n */\nimport { Directive, ElementRef, inject, input, OnDestroy, OnInit, output, type Type } from '@angular/core';\nimport type { DataGridElement } from '@toolbox-web/grid';\nimport { claimEvent, registerFeatureClaim, unclaimEvent, unregisterFeatureClaim } from '@toolbox-web/grid-angular';\nimport type {\n GroupingRowsConfig as CoreGroupingRowsConfig,\n GroupCollapseDetail,\n GroupExpandDetail,\n GroupRowRenderParams,\n GroupToggleDetail,\n} from '@toolbox-web/grid/plugins/grouping-rows';\n\n/**\n * Grouping-rows config widened to accept an Angular component class as\n * `groupRowRenderer`.\n *\n * Component instances receive the {@link GroupRowRenderParams} fields as\n * inputs (`key`, `value`, `depth`, `rows`, `expanded`, `toggleExpand`).\n *\n * @since 1.7.0\n */\nexport type GroupingRowsConfig = Omit<CoreGroupingRowsConfig, 'groupRowRenderer'> & {\n groupRowRenderer?: CoreGroupingRowsConfig['groupRowRenderer'] | Type<unknown>;\n};\n\n/**\n * Owns the binding(s) `[groupingRows], [groupToggle], [groupExpand], [groupCollapse]` on `<tbw-grid>` for the matching feature plugin. See `GridFilteringDirective` for the full rationale.\n *\n * @category Directive\n */\n@Directive({\n selector: 'tbw-grid[groupingRows], tbw-grid[groupToggle], tbw-grid[groupExpand], tbw-grid[groupCollapse]',\n standalone: true,\n})\nexport class GridGroupingRowsDirective implements OnInit, OnDestroy {\n private readonly elementRef = inject(ElementRef<DataGridElement>);\n\n readonly groupingRows = input<GroupingRowsConfig>();\n readonly groupToggle = output<GroupToggleDetail>();\n readonly groupExpand = output<GroupExpandDetail>();\n readonly groupCollapse = output<GroupCollapseDetail>();\n\n private readonly listeners = new Map<string, (e: Event) => void>();\n private static readonly EVENTS = ['group-toggle', 'group-expand', 'group-collapse'] as const;\n\n constructor() {\n const grid = this.elementRef.nativeElement;\n registerFeatureClaim(grid, 'groupingRows', () => this.groupingRows());\n for (const ev of GridGroupingRowsDirective.EVENTS) claimEvent(grid, ev);\n }\n\n ngOnInit(): void {\n const grid = this.elementRef.nativeElement;\n const wire = <T>(name: string, out: { emit: (v: T) => void }): void => {\n const l = (e: Event): void => out.emit((e as CustomEvent<T>).detail);\n grid.addEventListener(name, l);\n this.listeners.set(name, l);\n };\n wire<GroupToggleDetail>('group-toggle', this.groupToggle);\n wire<GroupExpandDetail>('group-expand', this.groupExpand);\n wire<GroupCollapseDetail>('group-collapse', this.groupCollapse);\n }\n\n ngOnDestroy(): void {\n const grid = this.elementRef.nativeElement;\n for (const [name, l] of this.listeners) grid.removeEventListener(name, l);\n this.listeners.clear();\n unregisterFeatureClaim(grid, 'groupingRows');\n for (const ev of GridGroupingRowsDirective.EVENTS) unclaimEvent(grid, ev);\n }\n}\n","/**\n * Row grouping feature for @toolbox-web/grid-angular\n *\n * Import this module to enable the `groupingRows` input on Grid directive.\n *\n * @example\n * ```typescript\n * import '@toolbox-web/grid-angular/features/grouping-rows';\n *\n * <tbw-grid [groupingRows]=\"{ groupBy: ['department'] }\" />\n * ```\n *\n * @packageDocumentation\n */\n\nimport { isComponentClass, registerFeatureConfigPreprocessor } from '@toolbox-web/grid-angular';\nimport '@toolbox-web/grid/features/grouping-rows';\nimport type {\n GroupingRowsConfig as CoreGroupingRowsConfig,\n GroupRowRenderParams,\n} from '@toolbox-web/grid/plugins/grouping-rows';\nexport { GridGroupingRowsDirective, type GroupingRowsConfig } from './grid-grouping-rows.directive';\nexport type { _Augmentation as _GroupingRowsAugmentation } from '@toolbox-web/grid/features/grouping-rows';\n\n// Bridge any Angular component classes embedded in the user-supplied config\n// (e.g. group-row renderer) to plain renderer functions before the core\n// plugin factory consumes the config.\nregisterFeatureConfigPreprocessor('groupingRows', (config, adapter) => {\n if (!config || typeof config !== 'object') return config;\n const cfg = config as CoreGroupingRowsConfig;\n if (cfg.groupRowRenderer && isComponentClass(cfg.groupRowRenderer)) {\n const mount = adapter.mountComponentRenderer<GroupRowRenderParams>(cfg.groupRowRenderer, (p) => ({\n key: p.key,\n value: p.value,\n depth: p.depth,\n rows: p.rows,\n expanded: p.expanded,\n toggleExpand: p.toggleExpand,\n }));\n return { ...cfg, groupRowRenderer: (params: GroupRowRenderParams) => mount(params).hostElement };\n }\n return cfg;\n});\n","/**\n * Generated bundle index. Do not edit.\n */\n\nexport * from './index';\n"],"names":[],"mappings":"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"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"toolbox-web-grid-angular-features-pinned-rows.mjs","sources":["../../../../libs/grid-angular/features/pinned-rows/src/cached-panel-renderer.ts","../../../../libs/grid-angular/features/pinned-rows/src/grid-pinned-rows.directive.ts","../../../../libs/grid-angular/features/pinned-rows/src/index.ts","../../../../libs/grid-angular/features/pinned-rows/src/toolbox-web-grid-angular-features-pinned-rows.ts"],"sourcesContent":["/**\n * @internal\n *\n * Cached panel-renderer factory for the Angular pinned-rows adapter (#354).\n *\n * Extracted into its own module so the pure caching logic can be unit-tested\n * without depending on the heavy `@toolbox-web/grid-angular` barrel (which\n * pulls in every directive at module-load and requires substantial Angular\n * DI mocking).\n *\n * @since 1.7.0\n */\nimport type { ComponentRef, Type } from '@angular/core';\nimport type { PinnedRowsContext } from '@toolbox-web/grid/plugins/pinned-rows';\n\n/**\n * Minimal structural shape of the adapter API used by {@link buildCachedPanelRenderer}.\n * Mirrors `GridAdapter.mountComponentRenderer` without the rest of the surface\n * so tests can pass a stub.\n *\n * @internal\n */\nexport interface PanelRendererAdapter {\n mountComponentRenderer<TCtx>(\n componentClass: Type<unknown>,\n mapInputs: (ctx: TCtx) => Record<string, unknown>,\n ): (ctx: TCtx) => { hostElement: HTMLElement; componentRef: ComponentRef<unknown> };\n}\n\n/**\n * Map a {@link PinnedRowsContext} to the Angular component input bag.\n * Centralized so both the initial `mountComponentRenderer` call and the\n * per-call input-refresh path stay in sync.\n *\n * @internal\n */\nexport function mapPinnedRowsInputs(ctx: PinnedRowsContext): Record<string, unknown> {\n return {\n totalRows: ctx.totalRows,\n filteredRows: ctx.filteredRows,\n selectedRows: ctx.selectedRows,\n columns: ctx.columns,\n rows: ctx.rows,\n grid: ctx.grid,\n };\n}\n\n/**\n * Build a pinned-rows panel renderer function from an Angular component class.\n * The component should accept inputs from {@link PinnedRowsContext}.\n *\n * Caches the mounted component across renders — the pinned-rows plugin\n * (`renderPanelSlot`) reference-checks renderer outputs to skip DOM mutation\n * when nothing changed. On subsequent calls inputs are refreshed via\n * `componentRef.setInput()` instead of mounting a fresh component.\n *\n * The cached `ComponentRef` is tracked in the adapter's render pool, so it is\n * destroyed automatically when the grid is disposed.\n *\n * @internal\n */\nexport function buildCachedPanelRenderer(\n adapter: PanelRendererAdapter,\n componentClass: Type<unknown>,\n): (ctx: PinnedRowsContext) => HTMLElement {\n const mount = adapter.mountComponentRenderer<PinnedRowsContext>(componentClass, mapPinnedRowsInputs);\n let cached: { hostElement: HTMLElement; componentRef: ComponentRef<unknown> } | null = null;\n return (ctx) => {\n if (!cached) {\n cached = mount(ctx);\n return cached.hostElement;\n }\n const inputs = mapPinnedRowsInputs(ctx);\n for (const name of Object.keys(inputs)) {\n cached.componentRef.setInput(name, inputs[name]);\n }\n cached.componentRef.changeDetectorRef.detectChanges();\n return cached.hostElement;\n };\n}\n","/**\n * `GridPinnedRowsDirective` — owns `[pinnedRows]` on `<tbw-grid>`. No\n * event outputs. See `GridFilteringDirective` for the full rationale.\n *\n * @category Directive\n */\nimport { Directive, ElementRef, inject, input, OnDestroy, type Type } from '@angular/core';\nimport type { DataGridElement } from '@toolbox-web/grid';\nimport { registerFeatureClaim, unregisterFeatureClaim } from '@toolbox-web/grid-angular';\nimport type {\n PinnedRowsConfig as CorePinnedRowsConfig,\n PanelZone,\n PinnedRowsContext,\n} from '@toolbox-web/grid/plugins/pinned-rows';\n\n/**\n * Angular-shaped panel-slot render: a renderer function (vanilla), an Angular\n * component class, or an array of zoned entries that each accept the same.\n *\n * Component instances receive the {@link PinnedRowsContext} fields as inputs.\n *\n * @since 1.7.1\n */\nexport type PanelRender = ((ctx: PinnedRowsContext) => HTMLElement | null) | Type<unknown>;\n\n/**\n * Angular-shaped zoned panel render entry.\n *\n * @since 1.7.1\n */\nexport interface ZonedPanelRender {\n zone?: PanelZone;\n render: PanelRender;\n}\n\n/**\n * Angular-shaped pinned-rows panel slot.\n *\n * @since 1.7.1\n */\nexport interface PanelSlot {\n id?: string;\n position?: 'top' | 'bottom';\n render: PanelRender | ZonedPanelRender[];\n}\n\ntype CoreSlot = NonNullable<CorePinnedRowsConfig['slots']>[number];\ntype CoreAggregationSlot = Exclude<CoreSlot, { render: unknown }>;\n\n/**\n * Angular-shaped pinned-rows slot \\u2014 either an aggregation slot (passthrough)\n * or a panel slot accepting Angular component classes as `render`.\n *\n * @since 1.7.1\n */\nexport type PinnedRowSlot = CoreAggregationSlot | PanelSlot;\n\n/**\n * Pinned-rows config widened to accept Angular component classes as `render`\n * inside `slots[]`. Bridging to vanilla DOM is handled\n * by the side-effect import `@toolbox-web/grid-angular/features/pinned-rows`.\n *\n * Re-exported under the same name as the core type so Angular users see a\n * single canonical `PinnedRowsConfig` from\n * `@toolbox-web/grid-angular/features/pinned-rows`.\n *\n * @since 1.7.1\n */\nexport type PinnedRowsConfig = Omit<CorePinnedRowsConfig, 'slots'> & {\n slots?: PinnedRowSlot[];\n};\n\n// ── Deprecated framework-prefixed aliases ──────────────────────────────────\n// Retained for backwards compatibility. New code should use the canonical\n// (unprefixed) names above.\n\n/** @deprecated Use {@link PanelRender} instead. */\nexport type AngularPanelRender = PanelRender;\n/** @deprecated Use {@link ZonedPanelRender} instead. */\nexport type AngularZonedPanelRender = ZonedPanelRender;\n/** @deprecated Use {@link PanelSlot} instead. */\nexport type AngularPanelSlot = PanelSlot;\n/** @deprecated Use {@link PinnedRowSlot} instead. */\nexport type AngularPinnedRowSlot = PinnedRowSlot;\n/** @deprecated Use {@link PinnedRowsConfig} instead. */\nexport type AngularPinnedRowsConfig = PinnedRowsConfig;\n\n/**\n * Owns the binding(s) `[pinnedRows]` on `<tbw-grid>` for the matching feature plugin. See `GridFilteringDirective` for the full rationale.\n *\n * @category Directive\n */\n@Directive({\n selector: 'tbw-grid[pinnedRows]',\n standalone: true,\n})\nexport class GridPinnedRowsDirective implements OnDestroy {\n private readonly elementRef = inject(ElementRef<DataGridElement>);\n\n readonly pinnedRows = input<boolean | PinnedRowsConfig>();\n\n constructor() {\n registerFeatureClaim(this.elementRef.nativeElement, 'pinnedRows', () => this.pinnedRows());\n }\n\n ngOnDestroy(): void {\n unregisterFeatureClaim(this.elementRef.nativeElement, 'pinnedRows');\n }\n}\n","/**\n * Pinned rows feature for @toolbox-web/grid-angular\n *\n * Import this module to enable the `pinnedRows` input on Grid directive.\n *\n * @example\n * ```typescript\n * import '@toolbox-web/grid-angular/features/pinned-rows';\n *\n * <tbw-grid [pinnedRows]=\"{ bottom: [{ type: 'aggregation' }] }\" />\n * ```\n *\n * @packageDocumentation\n */\n\nimport type { Type } from '@angular/core';\nimport { isComponentClass, registerFeatureConfigPreprocessor, type GridAdapter } from '@toolbox-web/grid-angular';\nimport '@toolbox-web/grid/features/pinned-rows';\nimport type {\n PinnedRowsConfig as CorePinnedRowsConfig,\n PinnedRowSlot as CorePinnedRowSlot,\n ZonedPanelRender as CoreZonedPanelRender,\n PinnedRowsContext,\n} from '@toolbox-web/grid/plugins/pinned-rows';\nimport { buildCachedPanelRenderer } from './cached-panel-renderer';\nexport { GridPinnedRowsDirective } from './grid-pinned-rows.directive';\nexport type {\n // Deprecated framework-prefixed aliases \\u2014 kept for backwards compatibility.\n AngularPanelRender,\n AngularPanelSlot,\n AngularPinnedRowsConfig,\n AngularPinnedRowSlot,\n AngularZonedPanelRender,\n // Canonical (unprefixed) widening types. Same names as the core types\n // from `@toolbox-web/grid` \\u2014 these accept Angular component classes in\n // addition to the vanilla `HTMLElement`-returning renderer functions.\n PanelRender,\n PanelSlot,\n PinnedRowsConfig,\n PinnedRowSlot,\n ZonedPanelRender,\n} from './grid-pinned-rows.directive';\nexport type { _Augmentation as _PinnedRowsAugmentation } from '@toolbox-web/grid/features/pinned-rows';\n\n/**\n * Build a pinned-rows panel renderer function from an Angular component class.\n * Thin wrapper around {@link buildCachedPanelRenderer} that fixes the adapter\n * type to the concrete `GridAdapter`.\n */\nfunction buildPanelRenderer(\n adapter: GridAdapter,\n componentClass: Type<unknown>,\n): (ctx: PinnedRowsContext) => HTMLElement {\n return buildCachedPanelRenderer(adapter, componentClass);\n}\n\n/**\n * Bridge a single pinned-row slot. Aggregation slots (no `render`) pass through.\n * For panel slots, wrap any component-class `render` (or array entry's `render`)\n * with the Angular component renderer.\n */\nfunction bridgeSlot(adapter: GridAdapter, slot: CorePinnedRowSlot): CorePinnedRowSlot {\n if (!('render' in slot) || slot.render == null) return slot;\n\n if (Array.isArray(slot.render)) {\n const zoned: CoreZonedPanelRender[] = slot.render.map((entry) => {\n if (entry?.render == null) return entry;\n if (isComponentClass(entry.render)) {\n return { zone: entry.zone, render: buildPanelRenderer(adapter, entry.render as Type<unknown>) };\n }\n return entry;\n });\n return { ...slot, render: zoned };\n }\n\n if (isComponentClass(slot.render)) {\n return { ...slot, render: buildPanelRenderer(adapter, slot.render as Type<unknown>) };\n }\n return slot;\n}\n\n// Bridge any Angular component classes embedded in `slots`\n// to plain renderer functions before the core plugin factory consumes the config.\nregisterFeatureConfigPreprocessor('pinnedRows', (config, adapter) => {\n if (!config || typeof config !== 'object') return config;\n const cfg = config as CorePinnedRowsConfig;\n let next: CorePinnedRowsConfig = cfg;\n\n // Slots[] bridging \\u2014 each PanelSlot.render may be a component class, or an\n // array of { zone?, render } where each render may be a component class.\n if (Array.isArray(cfg.slots)) {\n next = { ...next, slots: cfg.slots.map((slot) => bridgeSlot(adapter, slot)) };\n }\n\n return next;\n});\n","/**\n * Generated bundle index. Do not edit.\n */\n\nexport * from './index';\n"],"names":[],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"toolbox-web-grid-angular-features-pinned-rows.mjs","sources":["../../../../libs/grid-angular/features/pinned-rows/src/cached-panel-renderer.ts","../../../../libs/grid-angular/features/pinned-rows/src/grid-pinned-rows.directive.ts","../../../../libs/grid-angular/features/pinned-rows/src/index.ts","../../../../libs/grid-angular/features/pinned-rows/src/toolbox-web-grid-angular-features-pinned-rows.ts"],"sourcesContent":["/**\n * @internal\n *\n * Cached panel-renderer factory for the Angular pinned-rows adapter (#354).\n *\n * Extracted into its own module so the pure caching logic can be unit-tested\n * without depending on the heavy `@toolbox-web/grid-angular` barrel (which\n * pulls in every directive at module-load and requires substantial Angular\n * DI mocking).\n *\n * @since 1.7.0\n */\nimport type { ComponentRef, Type } from '@angular/core';\nimport type { PinnedRowsContext } from '@toolbox-web/grid/plugins/pinned-rows';\n\n/**\n * Minimal structural shape of the adapter API used by {@link buildCachedPanelRenderer}.\n * Mirrors `GridAdapter.mountComponentRenderer` without the rest of the surface\n * so tests can pass a stub.\n *\n * @internal\n */\nexport interface PanelRendererAdapter {\n mountComponentRenderer<TCtx>(\n componentClass: Type<unknown>,\n mapInputs: (ctx: TCtx) => Record<string, unknown>,\n ): (ctx: TCtx) => { hostElement: HTMLElement; componentRef: ComponentRef<unknown> };\n}\n\n/**\n * Map a {@link PinnedRowsContext} to the Angular component input bag.\n * Centralized so both the initial `mountComponentRenderer` call and the\n * per-call input-refresh path stay in sync.\n *\n * @internal\n */\nexport function mapPinnedRowsInputs(ctx: PinnedRowsContext): Record<string, unknown> {\n return {\n totalRows: ctx.totalRows,\n filteredRows: ctx.filteredRows,\n selectedRows: ctx.selectedRows,\n columns: ctx.columns,\n rows: ctx.rows,\n grid: ctx.grid,\n };\n}\n\n/**\n * Build a pinned-rows panel renderer function from an Angular component class.\n * The component should accept inputs from {@link PinnedRowsContext}.\n *\n * Caches the mounted component across renders — the pinned-rows plugin\n * (`renderPanelSlot`) reference-checks renderer outputs to skip DOM mutation\n * when nothing changed. On subsequent calls inputs are refreshed via\n * `componentRef.setInput()` instead of mounting a fresh component.\n *\n * The cached `ComponentRef` is tracked in the adapter's render pool, so it is\n * destroyed automatically when the grid is disposed.\n *\n * @internal\n */\nexport function buildCachedPanelRenderer(\n adapter: PanelRendererAdapter,\n componentClass: Type<unknown>,\n): (ctx: PinnedRowsContext) => HTMLElement {\n const mount = adapter.mountComponentRenderer<PinnedRowsContext>(componentClass, mapPinnedRowsInputs);\n let cached: { hostElement: HTMLElement; componentRef: ComponentRef<unknown> } | null = null;\n return (ctx) => {\n if (!cached) {\n cached = mount(ctx);\n return cached.hostElement;\n }\n const inputs = mapPinnedRowsInputs(ctx);\n for (const name of Object.keys(inputs)) {\n cached.componentRef.setInput(name, inputs[name]);\n }\n cached.componentRef.changeDetectorRef.detectChanges();\n return cached.hostElement;\n };\n}\n","/**\n * `GridPinnedRowsDirective` — owns `[pinnedRows]` on `<tbw-grid>`. No\n * event outputs. See `GridFilteringDirective` for the full rationale.\n *\n * @category Directive\n */\nimport { Directive, ElementRef, inject, input, OnDestroy, type Type } from '@angular/core';\nimport type { DataGridElement } from '@toolbox-web/grid';\nimport { registerFeatureClaim, unregisterFeatureClaim } from '@toolbox-web/grid-angular';\nimport type {\n PinnedRowsConfig as CorePinnedRowsConfig,\n PanelZone,\n PinnedRowsContext,\n} from '@toolbox-web/grid/plugins/pinned-rows';\n\n/**\n * Angular-shaped panel-slot render: a renderer function (vanilla), an Angular\n * component class, or an array of zoned entries that each accept the same.\n *\n * Component instances receive the {@link PinnedRowsContext} fields as inputs.\n *\n * @since 1.7.1\n */\nexport type PanelRender = ((ctx: PinnedRowsContext) => HTMLElement | null) | Type<unknown>;\n\n/**\n * Angular-shaped zoned panel render entry.\n *\n * @since 1.7.1\n */\nexport interface ZonedPanelRender {\n zone?: PanelZone;\n render: PanelRender;\n}\n\n/**\n * Angular-shaped pinned-rows panel slot.\n *\n * @since 1.7.1\n */\nexport interface PanelSlot {\n id?: string;\n position?: 'top' | 'bottom';\n render: PanelRender | ZonedPanelRender[];\n}\n\ntype CoreSlot = NonNullable<CorePinnedRowsConfig['slots']>[number];\ntype CoreAggregationSlot = Exclude<CoreSlot, { render: unknown }>;\n\n/**\n * Angular-shaped pinned-rows slot \\u2014 either an aggregation slot (passthrough)\n * or a panel slot accepting Angular component classes as `render`.\n *\n * @since 1.7.1\n */\nexport type PinnedRowSlot = CoreAggregationSlot | PanelSlot;\n\n/**\n * Pinned-rows config widened to accept Angular component classes as `render`\n * inside `slots[]`. Bridging to vanilla DOM is handled\n * by the side-effect import `@toolbox-web/grid-angular/features/pinned-rows`.\n *\n * Re-exported under the same name as the core type so Angular users see a\n * single canonical `PinnedRowsConfig` from\n * `@toolbox-web/grid-angular/features/pinned-rows`.\n *\n * @since 1.7.1\n */\nexport type PinnedRowsConfig = Omit<CorePinnedRowsConfig, 'slots'> & {\n slots?: PinnedRowSlot[];\n};\n\n/**\n * Owns the binding(s) `[pinnedRows]` on `<tbw-grid>` for the matching feature plugin. See `GridFilteringDirective` for the full rationale.\n *\n * @category Directive\n */\n@Directive({\n selector: 'tbw-grid[pinnedRows]',\n standalone: true,\n})\nexport class GridPinnedRowsDirective implements OnDestroy {\n private readonly elementRef = inject(ElementRef<DataGridElement>);\n\n readonly pinnedRows = input<boolean | PinnedRowsConfig>();\n\n constructor() {\n registerFeatureClaim(this.elementRef.nativeElement, 'pinnedRows', () => this.pinnedRows());\n }\n\n ngOnDestroy(): void {\n unregisterFeatureClaim(this.elementRef.nativeElement, 'pinnedRows');\n }\n}\n","/**\n * Pinned rows feature for @toolbox-web/grid-angular\n *\n * Import this module to enable the `pinnedRows` input on Grid directive.\n *\n * @example\n * ```typescript\n * import '@toolbox-web/grid-angular/features/pinned-rows';\n *\n * <tbw-grid [pinnedRows]=\"{ bottom: [{ type: 'aggregation' }] }\" />\n * ```\n *\n * @packageDocumentation\n */\n\nimport type { Type } from '@angular/core';\nimport { isComponentClass, registerFeatureConfigPreprocessor, type GridAdapter } from '@toolbox-web/grid-angular';\nimport '@toolbox-web/grid/features/pinned-rows';\nimport type {\n PinnedRowsConfig as CorePinnedRowsConfig,\n PinnedRowSlot as CorePinnedRowSlot,\n ZonedPanelRender as CoreZonedPanelRender,\n PinnedRowsContext,\n} from '@toolbox-web/grid/plugins/pinned-rows';\nimport { buildCachedPanelRenderer } from './cached-panel-renderer';\nexport { GridPinnedRowsDirective } from './grid-pinned-rows.directive';\nexport type {\n // Canonical (unprefixed) widening types. Same names as the core types\n // from `@toolbox-web/grid` \\u2014 these accept Angular component classes in\n // addition to the vanilla `HTMLElement`-returning renderer functions.\n PanelRender,\n PanelSlot,\n PinnedRowsConfig,\n PinnedRowSlot,\n ZonedPanelRender,\n} from './grid-pinned-rows.directive';\nexport type { _Augmentation as _PinnedRowsAugmentation } from '@toolbox-web/grid/features/pinned-rows';\n\n/**\n * Build a pinned-rows panel renderer function from an Angular component class.\n * Thin wrapper around {@link buildCachedPanelRenderer} that fixes the adapter\n * type to the concrete `GridAdapter`.\n */\nfunction buildPanelRenderer(\n adapter: GridAdapter,\n componentClass: Type<unknown>,\n): (ctx: PinnedRowsContext) => HTMLElement {\n return buildCachedPanelRenderer(adapter, componentClass);\n}\n\n/**\n * Bridge a single pinned-row slot. Aggregation slots (no `render`) pass through.\n * For panel slots, wrap any component-class `render` (or array entry's `render`)\n * with the Angular component renderer.\n */\nfunction bridgeSlot(adapter: GridAdapter, slot: CorePinnedRowSlot): CorePinnedRowSlot {\n if (!('render' in slot) || slot.render == null) return slot;\n\n if (Array.isArray(slot.render)) {\n const zoned: CoreZonedPanelRender[] = slot.render.map((entry) => {\n if (entry?.render == null) return entry;\n if (isComponentClass(entry.render)) {\n return { zone: entry.zone, render: buildPanelRenderer(adapter, entry.render as Type<unknown>) };\n }\n return entry;\n });\n return { ...slot, render: zoned };\n }\n\n if (isComponentClass(slot.render)) {\n return { ...slot, render: buildPanelRenderer(adapter, slot.render as Type<unknown>) };\n }\n return slot;\n}\n\n// Bridge any Angular component classes embedded in `slots`\n// to plain renderer functions before the core plugin factory consumes the config.\nregisterFeatureConfigPreprocessor('pinnedRows', (config, adapter) => {\n if (!config || typeof config !== 'object') return config;\n const cfg = config as CorePinnedRowsConfig;\n let next: CorePinnedRowsConfig = cfg;\n\n // Slots[] bridging \\u2014 each PanelSlot.render may be a component class, or an\n // array of { zone?, render } where each render may be a component class.\n if (Array.isArray(cfg.slots)) {\n next = { ...next, slots: cfg.slots.map((slot) => bridgeSlot(adapter, slot)) };\n }\n\n return next;\n});\n","/**\n * Generated bundle index. Do not edit.\n */\n\nexport * from './index';\n"],"names":[],"mappings":"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"}
|
|
@@ -49,7 +49,8 @@ function getToolPanelElements(gridElement) {
|
|
|
49
49
|
* ### Attributes
|
|
50
50
|
*
|
|
51
51
|
* - `id` (required): Unique identifier for the panel
|
|
52
|
-
* - `title` (
|
|
52
|
+
* - `title` (optional): Panel title shown in accordion header. Omit it when the
|
|
53
|
+
* panel content provides its own heading.
|
|
53
54
|
* - `icon`: Icon for accordion section header (emoji or text)
|
|
54
55
|
* - `tooltip`: Tooltip for accordion section header
|
|
55
56
|
* - `order`: Panel order priority (lower = first, default: 100)
|
|
@@ -83,8 +84,18 @@ class GridToolPanel {
|
|
|
83
84
|
elementRef = inject((ElementRef));
|
|
84
85
|
/** Unique panel identifier (required) */
|
|
85
86
|
id = input.required({ ...(ngDevMode ? { debugName: "id" } : /* istanbul ignore next */ {}), alias: 'id' });
|
|
86
|
-
/**
|
|
87
|
-
|
|
87
|
+
/**
|
|
88
|
+
* Panel title shown in accordion header (optional).
|
|
89
|
+
*
|
|
90
|
+
* Omit it when the panel content provides its own heading. With a single
|
|
91
|
+
* title-less panel the accordion header row is skipped; with multiple panels
|
|
92
|
+
* a title-less header still renders so the expand/collapse control stays
|
|
93
|
+
* available.
|
|
94
|
+
*
|
|
95
|
+
* @since 3.1.0 (previously required)
|
|
96
|
+
*/
|
|
97
|
+
title = input(/* @ts-ignore */
|
|
98
|
+
...(ngDevMode ? [undefined, { debugName: "title" }] : /* istanbul ignore next */ []));
|
|
88
99
|
/** Icon for accordion section header (emoji or text) */
|
|
89
100
|
icon = input(/* @ts-ignore */
|
|
90
101
|
...(ngDevMode ? [undefined, { debugName: "icon" }] : /* istanbul ignore next */ []));
|
|
@@ -106,7 +117,13 @@ class GridToolPanel {
|
|
|
106
117
|
if (template) {
|
|
107
118
|
// Set attributes from inputs (for light DOM parsing to read)
|
|
108
119
|
element.setAttribute('id', this.id());
|
|
109
|
-
|
|
120
|
+
const title = this.title();
|
|
121
|
+
if (title != null) {
|
|
122
|
+
element.setAttribute('title', title);
|
|
123
|
+
}
|
|
124
|
+
else {
|
|
125
|
+
element.removeAttribute('title');
|
|
126
|
+
}
|
|
110
127
|
const icon = this.icon();
|
|
111
128
|
if (icon)
|
|
112
129
|
element.setAttribute('icon', icon);
|
|
@@ -127,12 +144,12 @@ class GridToolPanel {
|
|
|
127
144
|
return true;
|
|
128
145
|
}
|
|
129
146
|
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "22.0.6", ngImport: i0, type: GridToolPanel, deps: [], target: i0.ɵɵFactoryTarget.Directive });
|
|
130
|
-
static ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "17.2.0", version: "22.0.6", type: GridToolPanel, isStandalone: true, selector: "tbw-grid-tool-panel", inputs: { id: { classPropertyName: "id", publicName: "id", isSignal: true, isRequired: true, transformFunction: null }, title: { classPropertyName: "title", publicName: "title", isSignal: true, isRequired:
|
|
147
|
+
static ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "17.2.0", version: "22.0.6", type: GridToolPanel, isStandalone: true, selector: "tbw-grid-tool-panel", inputs: { id: { classPropertyName: "id", publicName: "id", isSignal: true, isRequired: true, transformFunction: null }, title: { classPropertyName: "title", publicName: "title", isSignal: true, isRequired: false, transformFunction: null }, icon: { classPropertyName: "icon", publicName: "icon", isSignal: true, isRequired: false, transformFunction: null }, tooltip: { classPropertyName: "tooltip", publicName: "tooltip", isSignal: true, isRequired: false, transformFunction: null }, order: { classPropertyName: "order", publicName: "order", isSignal: true, isRequired: false, transformFunction: null } }, queries: [{ propertyName: "template", first: true, predicate: (TemplateRef), descendants: true, isSignal: true }], ngImport: i0 });
|
|
131
148
|
}
|
|
132
149
|
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.0.6", ngImport: i0, type: GridToolPanel, decorators: [{
|
|
133
150
|
type: Directive,
|
|
134
151
|
args: [{ selector: 'tbw-grid-tool-panel' }]
|
|
135
|
-
}], propDecorators: { id: [{ type: i0.Input, args: [{ isSignal: true, alias: "id", required: true }] }], title: [{ type: i0.Input, args: [{ isSignal: true, alias: "title", required:
|
|
152
|
+
}], propDecorators: { id: [{ type: i0.Input, args: [{ isSignal: true, alias: "id", required: true }] }], title: [{ type: i0.Input, args: [{ isSignal: true, alias: "title", required: false }] }], icon: [{ type: i0.Input, args: [{ isSignal: true, alias: "icon", required: false }] }], tooltip: [{ type: i0.Input, args: [{ isSignal: true, alias: "tooltip", required: false }] }], order: [{ type: i0.Input, args: [{ isSignal: true, alias: "order", required: false }] }], template: [{ type: i0.ContentChild, args: [i0.forwardRef(() => TemplateRef), { isSignal: true }] }] } });
|
|
136
153
|
|
|
137
154
|
let autoIdCounter$1 = 0;
|
|
138
155
|
/**
|
|
@@ -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` (required): Panel title shown in accordion header\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 /** Panel title shown in accordion header (required) */\n title = input.required<string>({ alias: 'title' });\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 element.setAttribute('title', this.title());\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 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,5 +1,5 @@
|
|
|
1
1
|
import * as i0 from '@angular/core';
|
|
2
|
-
import { inject, ElementRef, contentChild, TemplateRef, effect, Directive, InjectionToken, Injectable, makeEnvironmentProviders, createComponent, DestroyRef, signal, afterNextRender, computed, EnvironmentInjector, ApplicationRef, ViewContainerRef, input, output } from '@angular/core';
|
|
2
|
+
import { inject, ElementRef, contentChild, TemplateRef, effect, Directive, InjectionToken, Injectable, makeEnvironmentProviders, createComponent, DestroyRef, signal, afterNextRender, computed, EnvironmentInjector, ApplicationRef, ViewContainerRef, untracked, input, output } from '@angular/core';
|
|
3
3
|
import { createPluginFromFeature } from '@toolbox-web/grid/features/registry';
|
|
4
4
|
export { clearFeatureRegistry, createPluginFromFeature, getFeatureFactory, getRegisteredFeatures, isFeatureRegistered, registerFeature } from '@toolbox-web/grid/features/registry';
|
|
5
5
|
import { applyColumnDefaults, normalizeColumns, DataGridElement } from '@toolbox-web/grid';
|
|
@@ -2085,6 +2085,36 @@ function unclaimEvent(grid, eventName) {
|
|
|
2085
2085
|
eventClaims.get(grid)?.delete(eventName);
|
|
2086
2086
|
}
|
|
2087
2087
|
|
|
2088
|
+
/**
|
|
2089
|
+
* Computes the minimal set of row updates needed when only values have changed
|
|
2090
|
+
* (same row count, same row IDs in the same order).
|
|
2091
|
+
*
|
|
2092
|
+
* Returns an array of updates (possibly empty) when the diff is value-only, or
|
|
2093
|
+
* `null` when a structural change is detected (different count, different IDs
|
|
2094
|
+
* in sequence, or initial load from an empty snapshot).
|
|
2095
|
+
*
|
|
2096
|
+
* Called by the Angular `Grid` directive's rows effect to decide whether to
|
|
2097
|
+
* call `grid.updateRows()` (value-only, fast path) or `grid.rows =` (full
|
|
2098
|
+
* replace). Kept as a pure helper so it can be unit-tested without Angular.
|
|
2099
|
+
*/
|
|
2100
|
+
function computeRowDiff(next, prev, getId) {
|
|
2101
|
+
if (prev.length === 0 || next.length !== prev.length)
|
|
2102
|
+
return null;
|
|
2103
|
+
const updates = [];
|
|
2104
|
+
for (let i = 0; i < next.length; i++) {
|
|
2105
|
+
const nextRow = next[i];
|
|
2106
|
+
const prevRow = prev[i];
|
|
2107
|
+
const nextId = getId(nextRow);
|
|
2108
|
+
const prevId = getId(prevRow);
|
|
2109
|
+
if (nextId !== prevId)
|
|
2110
|
+
return null;
|
|
2111
|
+
if (prevRow !== nextRow) {
|
|
2112
|
+
updates.push({ id: nextId, changes: nextRow });
|
|
2113
|
+
}
|
|
2114
|
+
}
|
|
2115
|
+
return updates;
|
|
2116
|
+
}
|
|
2117
|
+
|
|
2088
2118
|
/**
|
|
2089
2119
|
* Directive that automatically registers the Angular adapter with tbw-grid elements.
|
|
2090
2120
|
*
|
|
@@ -2145,6 +2175,11 @@ class Grid {
|
|
|
2145
2175
|
viewContainerRef = inject(ViewContainerRef);
|
|
2146
2176
|
iconRegistry = inject(GridIconRegistry, { optional: true });
|
|
2147
2177
|
adapter = null;
|
|
2178
|
+
/**
|
|
2179
|
+
* Previous rows snapshot for in-place diffing — kept in sync by the rows
|
|
2180
|
+
* effect. Plain field so Angular's signal tracking ignores it.
|
|
2181
|
+
*/
|
|
2182
|
+
prevRows = [];
|
|
2148
2183
|
constructor() {
|
|
2149
2184
|
// Effect to process gridConfig and apply to grid
|
|
2150
2185
|
// This merges feature input plugins with the user's config plugins
|
|
@@ -2206,11 +2241,42 @@ class Grid {
|
|
|
2206
2241
|
grid.loading = loadingValue;
|
|
2207
2242
|
});
|
|
2208
2243
|
// Effect to sync rows to the grid element
|
|
2244
|
+
//
|
|
2245
|
+
// Smart diff: when getRowId is configured and the same rows appear in the
|
|
2246
|
+
// same order with only their values changed, route through updateRows() to
|
|
2247
|
+
// patch in-place. This triggers only RenderPhase.VIRTUALIZATION instead of
|
|
2248
|
+
// the heavier ROWS phase, which rebuilds the row model and re-applies
|
|
2249
|
+
// sort/filter. Mirrors the React and Vue adapters.
|
|
2209
2250
|
effect(() => {
|
|
2210
2251
|
const rowsValue = this.rows();
|
|
2211
2252
|
if (rowsValue === undefined)
|
|
2212
2253
|
return;
|
|
2213
2254
|
const grid = this.elementRef.nativeElement;
|
|
2255
|
+
const prev = this.prevRows;
|
|
2256
|
+
// Read getRowId without registering as a signal dependency so this effect
|
|
2257
|
+
// only re-runs on rows changes, not on every gridConfig change.
|
|
2258
|
+
const getId = untracked(() => this.gridConfig()?.getRowId);
|
|
2259
|
+
this.prevRows = rowsValue;
|
|
2260
|
+
if (getId) {
|
|
2261
|
+
const diff = computeRowDiff(rowsValue, prev, getId);
|
|
2262
|
+
if (diff !== null) {
|
|
2263
|
+
if (diff.length > 0) {
|
|
2264
|
+
// 'sync' source: authoritative host data, not a user edit — editing
|
|
2265
|
+
// plugin skips dirty marking / undo history for it.
|
|
2266
|
+
try {
|
|
2267
|
+
grid.updateRows(diff, 'sync');
|
|
2268
|
+
}
|
|
2269
|
+
catch {
|
|
2270
|
+
// getRowId changed alongside rows (grid still resolving ids with
|
|
2271
|
+
// the previous resolver) or an id vanished — fall back to a full
|
|
2272
|
+
// replace, which reapplies the whole array under the current resolver.
|
|
2273
|
+
grid.rows = rowsValue;
|
|
2274
|
+
}
|
|
2275
|
+
}
|
|
2276
|
+
return;
|
|
2277
|
+
}
|
|
2278
|
+
}
|
|
2279
|
+
// Structural change (adds/removes/reorder), no getRowId, or initial load — full replace.
|
|
2214
2280
|
grid.rows = rowsValue;
|
|
2215
2281
|
});
|
|
2216
2282
|
// Effect to sync columns to the grid element
|