@zambon-dev/framework 1.2.1 → 1.3.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/CHANGELOG.md CHANGED
@@ -23,6 +23,83 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
23
23
 
24
24
  ### ⚠ Breaking Changes / Migration
25
25
 
26
+ ## [1.3.1] - 2026-09-10
27
+
28
+ ### Fixed
29
+
30
+ - **Returning to an already-open tab no longer crashes with `Maximum call stack size exceeded`.**
31
+ It affected any screen whose route nests two empty-path levels — the shape every list screen uses:
32
+ `path: ''` with `DefaultTabViewComponent`, and a child `path: ''` with the list component.
33
+
34
+ `CustomReuseStrategy` keyed its detached-view cache on `route.component.name`, and a production
35
+ build renames every class: esbuild wraps each component as `X = (() => { class i { } return i; })()`,
36
+ so the name is one mangled letter that the whole chunk shares. An empty path contributes no URL
37
+ segment, so both levels also resolved to the same URL — which left the two cache keys identical.
38
+ Storing one handle overwrote the other, both route levels were then handed the same detached view,
39
+ and Angular blew the stack building a router state whose node was its own descendant.
40
+
41
+ The key is now built from the component's **identity** and the route's depth rather than its name.
42
+ Applications need to change nothing. Worth knowing when reading old reports of this crash: it only
43
+ ever reproduced in a minified build — `ng serve` keeps real class names — and only on the screens
44
+ whose chunk happened to mangle to the same letter as the framework's, so a rebuild could move the
45
+ symptom from one screen to another.
46
+
47
+ ## [1.3.0] - 2026-07-30
48
+
49
+ ### Added
50
+
51
+ - `framework-button-export` now accepts a **`defaultOption` `@Input()`** — the index into `options`
52
+ exported when the main button itself is clicked, defaulting to `0` (Excel). This mirrors the input
53
+ `framework-button-save` already had; `-1` means "no default" and makes the button only toggle its
54
+ dropdown. See **Changed** below for the behaviour this changes by default.
55
+
56
+ ### Changed
57
+
58
+ - **`framework-button-export` now exports on a single click**, to Excel by default, instead of only
59
+ opening its format menu. `RibbonButtonComponent` treats a `defaultOption` of -1 as "no default" and
60
+ merely toggles the dropdown; Export never set one, so the common case took two clicks while
61
+ `framework-button-save` (which sets 0) took one. Export now sets 0 as well, through the new
62
+ `defaultOption` `@Input()`. The format menu is unchanged and still reachable from the button's
63
+ dropdown caret, so every format remains available.
64
+
65
+ ### Fixed
66
+
67
+ - **Routed list views now fill the available height automatically.** `DefaultTabViewComponent` gave its
68
+ routed child no layout and `lib-data-grid` has no `flex-grow` of its own, so a grid collapsed to its
69
+ `rowsToDisplay × rowHeight` minimum with empty space beneath it, and every consuming list component
70
+ had to repeat the same `:host { flex; flex-grow; overflow: hidden }` + `lib-data-grid { flex-grow }`
71
+ stylesheet to compensate. `TabViewList` now carries a `framework-view-list` host class — inherited by
72
+ every subclass — which `DefaultTabViewComponent` styles, so **consuming apps can delete those
73
+ per-component stylesheets**. Routed screens that do not extend `TabViewList` (forms, dashboards) are
74
+ unaffected.
75
+
76
+ - `framework-default-tab-view` and `framework-default-details-tab-view` no longer log
77
+ `NG0100: ExpressionChangedAfterItHasBeenCheckedError` on every render in development mode.
78
+ Both views assigned a placeholder ribbon template from `ngAfterViewInit` — after Angular had
79
+ already checked the ribbon's `*ngTemplateOutlet` binding — which tripped the dev-mode change
80
+ detection check one to three times per load. The placeholder rendered no content, so it has
81
+ been removed and the outlet is now left empty until a view publishes its own `#ribbon`
82
+ template. The rendered output is unchanged, and ribbon buttons still appear immediately for
83
+ list and detail screens.
84
+
85
+ ### ⚠ Breaking Changes / Migration
86
+
87
+ None — nothing has to change for your app to compile against this release. Two behaviour changes to
88
+ check, and one optional cleanup:
89
+
90
+ - **Absolutely-positioned content inside a routed list view is now clipped.** The full-height layout
91
+ applied to `framework-view-list` includes `overflow: hidden`, so a popover, dropdown or tooltip that
92
+ a list screen renders with `position: absolute` inside its own host is now cut off at the host's
93
+ edges. Apps that had already written the equivalent `:host { overflow: hidden }` stylesheet by hand
94
+ are unaffected — the clipping was already in place there. Only list screens that had no such
95
+ stylesheet change. Fix by portaling the content out of the host (CDK Overlay, as `lib-catalog-select`
96
+ does) rather than relying on `position: absolute`.
97
+ - If you relied on `framework-button-export`'s first click opening the format menu rather than
98
+ exporting, set `[defaultOption]="-1"` to restore that behaviour.
99
+ - *Optional cleanup:* components extending `TabViewList` can now delete their
100
+ `:host { display: flex; flex-grow: 1; overflow: hidden }` / `lib-data-grid { flex-grow: 1 }`
101
+ stylesheets — `DefaultTabViewComponent` styles the inherited `framework-view-list` host class.
102
+
26
103
  ## [1.2.1] - 2026-07-29
27
104
 
28
105
  ### Fixed
@@ -65,7 +142,9 @@ None.
65
142
  available via [GitHub Releases](https://github.com/RicardoZambon/ZLibraries/releases) and the
66
143
  `framework-v*` tags.
67
144
 
68
- [Unreleased]: https://github.com/RicardoZambon/ZLibraries/compare/framework-v1.2.1...HEAD
145
+ [Unreleased]: https://github.com/RicardoZambon/ZLibraries/compare/framework-v1.3.1...HEAD
146
+ [1.3.1]: https://github.com/RicardoZambon/ZLibraries/releases/tag/framework-v1.3.1
147
+ [1.3.0]: https://github.com/RicardoZambon/ZLibraries/releases/tag/framework-v1.3.0
69
148
  [1.2.1]: https://github.com/RicardoZambon/ZLibraries/releases/tag/framework-v1.2.1
70
149
  [1.2.0]: https://github.com/RicardoZambon/ZLibraries/releases/tag/framework-v1.2.0
71
150
  [1.1.1]: https://github.com/RicardoZambon/ZLibraries/releases/tag/framework-v1.1.1
@@ -121,6 +121,8 @@ let CustomReuseStrategy = class CustomReuseStrategy {
121
121
  tabService;
122
122
  applicationRef = inject(ApplicationRef);
123
123
  cachedHandles = {};
124
+ componentIDs = new WeakMap();
125
+ nextComponentID = 1;
124
126
  //#endregion
125
127
  //#region Properties
126
128
  //#endregion
@@ -193,8 +195,39 @@ let CustomReuseStrategy = class CustomReuseStrategy {
193
195
  if (this.clones[url]) {
194
196
  url = this.clones[url];
195
197
  }
196
- const componentName = route.component?.name ?? '';
197
- return `${url}-${componentName}`;
198
+ // The component is identified by identity, never by name. A production build renames every
199
+ // class: esbuild wraps each component as `X = (() => { class i { } return i; })()`, so
200
+ // `component.name` is a single mangled letter that the whole chunk shares. Nested empty-path
201
+ // routes already resolve to the same URL, because an empty path contributes no segment, so a
202
+ // key built from the name collapsed a screen's tab view and its list into one entry: storing
203
+ // one overwrote the other, both levels were then handed the same detached view, and Angular
204
+ // blew the stack building a router state whose node was its own descendant. That reproduced
205
+ // only in a minified build, and only on the screens whose chunk happened to mangle to the
206
+ // same letter as the framework's.
207
+ //
208
+ // The depth is part of the key too, so two sibling routes sharing a component type under one
209
+ // URL cannot collide either.
210
+ return `${url}-${this.getRouteDepth(route)}-${this.getComponentID(route.component)}`;
211
+ }
212
+ getComponentID(component) {
213
+ if (typeof component !== 'function') {
214
+ return 0;
215
+ }
216
+ let componentID = this.componentIDs.get(component);
217
+ if (componentID === undefined) {
218
+ componentID = this.nextComponentID++;
219
+ this.componentIDs.set(component, componentID);
220
+ }
221
+ return componentID;
222
+ }
223
+ getRouteDepth(route) {
224
+ let depth = 0;
225
+ let current = route.parent;
226
+ while (current) {
227
+ depth++;
228
+ current = current.parent;
229
+ }
230
+ return depth;
198
231
  }
199
232
  getUrlFromRoute(route) {
200
233
  const segments = [];
@@ -1263,6 +1296,13 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.1.6", ngImpor
1263
1296
  const MaxExportRows = 50000;
1264
1297
  class ButtonExportComponent extends BaseButton {
1265
1298
  //#region ViewChilds, Inputs, Outputs
1299
+ /**
1300
+ * Index into `options` exported when the main button is clicked, defaulting to Excel.
1301
+ * `RibbonButtonComponent` treats -1 as "no default" and merely toggles the dropdown, which left
1302
+ * Export needing two clicks for the common case while Save (which sets 0) needed one. Set -1 to
1303
+ * restore the dropdown-only behaviour.
1304
+ */
1305
+ defaultOption = 0;
1266
1306
  fileBaseName = 'export';
1267
1307
  //#endregion
1268
1308
  //#region Variables
@@ -1337,15 +1377,17 @@ class ButtonExportComponent extends BaseButton {
1337
1377
  URL.revokeObjectURL(url);
1338
1378
  }
1339
1379
  static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "19.1.6", ngImport: i0, type: ButtonExportComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
1340
- static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "19.1.6", type: ButtonExportComponent, isStandalone: true, selector: "framework-button-export", inputs: { fileBaseName: "fileBaseName" }, providers: [{ provide: RibbonGroupChild, useExisting: forwardRef(() => ButtonExportComponent) }], usesInheritance: true, ngImport: i0, template: "<lib-ribbon-button *ngIf=\"visible\"\nlabel=\"Button-Export\"\nicon=\"fa-file-export\"\n[disabled]=\"isButtonDisabled\"\n[loading]=\"loading\"\n[iconSize]=\"iconSize\"\n[options]=\"options\"\n[tooltip]=\"tooltip\"\n(action)=\"onButtonClicked($event)\">\n</lib-ribbon-button>\n", dependencies: [{ kind: "directive", type: NgIf, selector: "[ngIf]", inputs: ["ngIf", "ngIfThen", "ngIfElse"] }, { kind: "component", type: RibbonButtonComponent, selector: "lib-ribbon-button", inputs: ["color", "defaultOption", "disabled", "icon", "iconSize", "label", "loading", "options", "tooltip"], outputs: ["action"] }] });
1380
+ static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "19.1.6", type: ButtonExportComponent, isStandalone: true, selector: "framework-button-export", inputs: { defaultOption: "defaultOption", fileBaseName: "fileBaseName" }, providers: [{ provide: RibbonGroupChild, useExisting: forwardRef(() => ButtonExportComponent) }], usesInheritance: true, ngImport: i0, template: "<lib-ribbon-button *ngIf=\"visible\"\nlabel=\"Button-Export\"\nicon=\"fa-file-export\"\n[defaultOption]=\"defaultOption\"\n[disabled]=\"isButtonDisabled\"\n[loading]=\"loading\"\n[iconSize]=\"iconSize\"\n[options]=\"options\"\n[tooltip]=\"tooltip\"\n(action)=\"onButtonClicked($event)\">\n</lib-ribbon-button>\n", dependencies: [{ kind: "directive", type: NgIf, selector: "[ngIf]", inputs: ["ngIf", "ngIfThen", "ngIfElse"] }, { kind: "component", type: RibbonButtonComponent, selector: "lib-ribbon-button", inputs: ["color", "defaultOption", "disabled", "icon", "iconSize", "label", "loading", "options", "tooltip"], outputs: ["action"] }] });
1341
1381
  }
1342
1382
  i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.1.6", ngImport: i0, type: ButtonExportComponent, decorators: [{
1343
1383
  type: Component,
1344
1384
  args: [{ selector: 'framework-button-export', imports: [
1345
1385
  NgIf,
1346
1386
  RibbonButtonComponent,
1347
- ], providers: [{ provide: RibbonGroupChild, useExisting: forwardRef(() => ButtonExportComponent) }], template: "<lib-ribbon-button *ngIf=\"visible\"\nlabel=\"Button-Export\"\nicon=\"fa-file-export\"\n[disabled]=\"isButtonDisabled\"\n[loading]=\"loading\"\n[iconSize]=\"iconSize\"\n[options]=\"options\"\n[tooltip]=\"tooltip\"\n(action)=\"onButtonClicked($event)\">\n</lib-ribbon-button>\n" }]
1348
- }], ctorParameters: () => [], propDecorators: { fileBaseName: [{
1387
+ ], providers: [{ provide: RibbonGroupChild, useExisting: forwardRef(() => ButtonExportComponent) }], template: "<lib-ribbon-button *ngIf=\"visible\"\nlabel=\"Button-Export\"\nicon=\"fa-file-export\"\n[defaultOption]=\"defaultOption\"\n[disabled]=\"isButtonDisabled\"\n[loading]=\"loading\"\n[iconSize]=\"iconSize\"\n[options]=\"options\"\n[tooltip]=\"tooltip\"\n(action)=\"onButtonClicked($event)\">\n</lib-ribbon-button>\n" }]
1388
+ }], ctorParameters: () => [], propDecorators: { defaultOption: [{
1389
+ type: Input
1390
+ }], fileBaseName: [{
1349
1391
  type: Input
1350
1392
  }] } });
1351
1393
 
@@ -2541,6 +2583,11 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.1.6", ngImpor
2541
2583
  args: [{ template: '' }]
2542
2584
  }], ctorParameters: () => [{ type: i1$2.DataGridDataset }, { type: i2.ActivatedRoute }, { type: TabService }] });
2543
2585
 
2586
+ // The host class is inherited by every subclass (Angular merges hostAttrs from a base component
2587
+ // definition), which is what lets DefaultTabViewComponent give routed list screens a full-height
2588
+ // layout without each one declaring its own stylesheet. Plain class name, NOT Tailwind utilities:
2589
+ // library SCSS resolves @apply at library-build time, whereas a utility class named here would
2590
+ // have to be generated by each consumer's own Tailwind build.
2544
2591
  class TabViewList extends TabViewBase {
2545
2592
  //#region ViewChilds, Inputs, Outputs
2546
2593
  //#endregion
@@ -2593,11 +2640,11 @@ class TabViewList extends TabViewBase {
2593
2640
  }
2594
2641
  }
2595
2642
  static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "19.1.6", ngImport: i0, type: TabViewList, deps: [], target: i0.ɵɵFactoryTarget.Component });
2596
- static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "19.1.6", type: TabViewList, isStandalone: true, selector: "ng-component", usesInheritance: true, ngImport: i0, template: '', isInline: true });
2643
+ static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "19.1.6", type: TabViewList, isStandalone: true, selector: "ng-component", host: { classAttribute: "framework-view-list" }, usesInheritance: true, ngImport: i0, template: '', isInline: true });
2597
2644
  }
2598
2645
  i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.1.6", ngImport: i0, type: TabViewList, decorators: [{
2599
2646
  type: Component,
2600
- args: [{ template: '' }]
2647
+ args: [{ host: { class: 'framework-view-list' }, template: '' }]
2601
2648
  }], ctorParameters: () => [] });
2602
2649
 
2603
2650
  class ListView extends TabViewList {
@@ -3206,7 +3253,6 @@ class DefaultTabViewComponent {
3206
3253
  changeDetectorRef;
3207
3254
  tabViewService;
3208
3255
  //#region ViewChilds, Inputs, Outputs
3209
- emptyRibbonTemplate;
3210
3256
  //#endregion
3211
3257
  //#region Variables
3212
3258
  destroy$ = new Subject();
@@ -3220,12 +3266,6 @@ class DefaultTabViewComponent {
3220
3266
  this.changeDetectorRef = changeDetectorRef;
3221
3267
  this.tabViewService = tabViewService;
3222
3268
  }
3223
- ngAfterViewInit() {
3224
- if (!this.ribbonTemplate) {
3225
- // If there are no template assigned to the ribbon, we use the empty template.
3226
- this.updateRibbonTemplate();
3227
- }
3228
- }
3229
3269
  ngOnDestroy() {
3230
3270
  this.destroy$.next(true);
3231
3271
  this.destroy$.complete();
@@ -3249,26 +3289,26 @@ class DefaultTabViewComponent {
3249
3289
  //#region Public methods
3250
3290
  //#endregion
3251
3291
  //#region Private methods
3252
- updateRibbonTemplate(template = undefined) {
3253
- const isRealTemplate = !!template;
3254
- if (!template) {
3255
- template = this.emptyRibbonTemplate;
3256
- }
3292
+ updateRibbonTemplate(template) {
3257
3293
  this.ribbonTemplate = template;
3258
- if (isRealTemplate) {
3294
+ if (template) {
3259
3295
  // Real template from a child view — render immediately so buttons appear
3260
3296
  // without waiting for the next change detection cycle (user interaction).
3261
3297
  this.changeDetectorRef.detectChanges();
3262
3298
  }
3263
3299
  else {
3264
- // Empty/fallback template — defer rendering to avoid briefly flashing
3265
- // an empty ribbon during component creation (the child view will push
3266
- // the real template moments later in the same initialization cycle).
3300
+ // No template for this view — defer clearing the ribbon to avoid tearing down
3301
+ // an already rendered one for a frame while switching views (the incoming view
3302
+ // pushes its real template moments later in the same initialization cycle).
3303
+ //
3304
+ // Never assign the ribbon template from a lifecycle hook that runs after the first
3305
+ // change detection pass (e.g. ngAfterViewInit): the outlet below has already been
3306
+ // checked by then, so mutating it there trips NG0100 in dev mode.
3267
3307
  this.changeDetectorRef.markForCheck();
3268
3308
  }
3269
3309
  }
3270
3310
  static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "19.1.6", ngImport: i0, type: DefaultTabViewComponent, deps: [{ token: i0.ChangeDetectorRef }, { token: TabViewService }], target: i0.ɵɵFactoryTarget.Component });
3271
- static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "19.1.6", type: DefaultTabViewComponent, isStandalone: true, selector: "framework-default-tab-view", providers: [{ provide: TabViewService }], viewQueries: [{ propertyName: "emptyRibbonTemplate", first: true, predicate: ["emptyRibbon"], descendants: true }], ngImport: i0, template: "<lib-ribbon>\n <ng-container *ngTemplateOutlet=\"ribbonTemplate\"></ng-container>\n\n <ng-template #emptyRibbon>\n </ng-template>\n</lib-ribbon>\n\n<router-outlet>\n</router-outlet>", styles: [":host-context{display:flex;flex-grow:1;flex-direction:column;gap:.5rem;overflow:hidden}\n"], dependencies: [{ kind: "directive", type: NgTemplateOutlet, selector: "[ngTemplateOutlet]", inputs: ["ngTemplateOutletContext", "ngTemplateOutlet", "ngTemplateOutletInjector"] }, { kind: "component", type: RibbonComponent, selector: "lib-ribbon" }, { kind: "ngmodule", type: RouterModule }, { kind: "directive", type: i2.RouterOutlet, selector: "router-outlet", inputs: ["name", "routerOutletData"], outputs: ["activate", "deactivate", "attach", "detach"], exportAs: ["outlet"] }] });
3311
+ static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "19.1.6", type: DefaultTabViewComponent, isStandalone: true, selector: "framework-default-tab-view", providers: [{ provide: TabViewService }], ngImport: i0, template: "<lib-ribbon>\n <ng-container *ngTemplateOutlet=\"ribbonTemplate ?? null\"></ng-container>\n</lib-ribbon>\n\n<router-outlet>\n</router-outlet>\n", styles: ["@charset \"UTF-8\";:host-context{display:flex;flex-grow:1;flex-direction:column;gap:.5rem;overflow:hidden}:host ::ng-deep .framework-view-list{display:flex;flex-grow:1;flex-direction:column;overflow:hidden;min-height:0}:host ::ng-deep .framework-view-list lib-data-grid{flex-grow:1}\n"], dependencies: [{ kind: "directive", type: NgTemplateOutlet, selector: "[ngTemplateOutlet]", inputs: ["ngTemplateOutletContext", "ngTemplateOutlet", "ngTemplateOutletInjector"] }, { kind: "component", type: RibbonComponent, selector: "lib-ribbon" }, { kind: "ngmodule", type: RouterModule }, { kind: "directive", type: i2.RouterOutlet, selector: "router-outlet", inputs: ["name", "routerOutletData"], outputs: ["activate", "deactivate", "attach", "detach"], exportAs: ["outlet"] }] });
3272
3312
  }
3273
3313
  i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.1.6", ngImport: i0, type: DefaultTabViewComponent, decorators: [{
3274
3314
  type: Component,
@@ -3276,11 +3316,8 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.1.6", ngImpor
3276
3316
  NgTemplateOutlet,
3277
3317
  RibbonComponent,
3278
3318
  RouterModule,
3279
- ], providers: [{ provide: TabViewService }], template: "<lib-ribbon>\n <ng-container *ngTemplateOutlet=\"ribbonTemplate\"></ng-container>\n\n <ng-template #emptyRibbon>\n </ng-template>\n</lib-ribbon>\n\n<router-outlet>\n</router-outlet>", styles: [":host-context{display:flex;flex-grow:1;flex-direction:column;gap:.5rem;overflow:hidden}\n"] }]
3280
- }], ctorParameters: () => [{ type: i0.ChangeDetectorRef }, { type: TabViewService }], propDecorators: { emptyRibbonTemplate: [{
3281
- type: ViewChild,
3282
- args: ['emptyRibbon']
3283
- }] } });
3319
+ ], providers: [{ provide: TabViewService }], template: "<lib-ribbon>\n <ng-container *ngTemplateOutlet=\"ribbonTemplate ?? null\"></ng-container>\n</lib-ribbon>\n\n<router-outlet>\n</router-outlet>\n", styles: ["@charset \"UTF-8\";:host-context{display:flex;flex-grow:1;flex-direction:column;gap:.5rem;overflow:hidden}:host ::ng-deep .framework-view-list{display:flex;flex-grow:1;flex-direction:column;overflow:hidden;min-height:0}:host ::ng-deep .framework-view-list lib-data-grid{flex-grow:1}\n"] }]
3320
+ }], ctorParameters: () => [{ type: i0.ChangeDetectorRef }, { type: TabViewService }] });
3284
3321
 
3285
3322
  function dataProviderFactory(route) {
3286
3323
  return route.snapshot.data['dataProvider']();
@@ -3372,7 +3409,7 @@ class DefaultDetailsTabViewComponent extends DefaultTabViewComponent {
3372
3409
  static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "19.1.6", type: DefaultDetailsTabViewComponent, isStandalone: true, selector: "framework-default-details-tab-view", providers: [
3373
3410
  { provide: TabViewService },
3374
3411
  { provide: DataProviderService, useFactory: dataProviderFactory, deps: [ActivatedRoute] },
3375
- ], viewQueries: [{ propertyName: "errorModal", first: true, predicate: ErrorModalComponent, descendants: true }], usesInheritance: true, ngImport: i0, template: "<lib-ribbon>\n <ng-container *ngTemplateOutlet=\"ribbonTemplate\"></ng-container>\n\n <ng-template #emptyRibbon>\n </ng-template>\n\n <div right>\n <lib-ribbon-group [label]=\"'RibbonGroup-Page' | translate\">\n <framework-button-views [detailsViewRoute]=\"detailsViewRoute\">\n </framework-button-views>\n </lib-ribbon-group>\n </div>\n</lib-ribbon>\n\n<lib-group-container\n[icon]=\"containerIcon\"\n[title]=\"containerTitle\">\n <router-outlet>\n </router-outlet>\n</lib-group-container>\n\n<framework-error-modal (closed)=\"onErrorModalClosed()\"></framework-error-modal>", styles: [":host-context{display:flex;flex-grow:1;flex-direction:column;gap:.5rem;overflow:hidden}router-outlet{display:none}\n"], dependencies: [{ kind: "component", type: ButtonViewsComponent, selector: "framework-button-views", inputs: ["detailsViewRoute"] }, { kind: "component", type: ErrorModalComponent, selector: "framework-error-modal", inputs: ["errorMessage", "size", "subtitle", "title"], outputs: ["closed"] }, { kind: "component", type: GroupContainerComponent, selector: "lib-group-container", inputs: ["title", "icon"] }, { kind: "directive", type: NgTemplateOutlet, selector: "[ngTemplateOutlet]", inputs: ["ngTemplateOutletContext", "ngTemplateOutlet", "ngTemplateOutletInjector"] }, { kind: "component", type: RibbonComponent, selector: "lib-ribbon" }, { kind: "component", type: RibbonGroupComponent, selector: "lib-ribbon-group", inputs: ["label"] }, { kind: "ngmodule", type: RouterModule }, { kind: "directive", type: i2.RouterOutlet, selector: "router-outlet", inputs: ["name", "routerOutletData"], outputs: ["activate", "deactivate", "attach", "detach"], exportAs: ["outlet"] }, { kind: "pipe", type: TranslatePipe, name: "translate" }] });
3412
+ ], viewQueries: [{ propertyName: "errorModal", first: true, predicate: ErrorModalComponent, descendants: true }], usesInheritance: true, ngImport: i0, template: "<lib-ribbon>\n <ng-container *ngTemplateOutlet=\"ribbonTemplate ?? null\"></ng-container>\n\n <div right>\n <lib-ribbon-group [label]=\"'RibbonGroup-Page' | translate\">\n <framework-button-views [detailsViewRoute]=\"detailsViewRoute\">\n </framework-button-views>\n </lib-ribbon-group>\n </div>\n</lib-ribbon>\n\n<lib-group-container\n[icon]=\"containerIcon\"\n[title]=\"containerTitle\">\n <router-outlet>\n </router-outlet>\n</lib-group-container>\n\n<framework-error-modal (closed)=\"onErrorModalClosed()\"></framework-error-modal>", styles: [":host-context{display:flex;flex-grow:1;flex-direction:column;gap:.5rem;overflow:hidden}router-outlet{display:none}\n"], dependencies: [{ kind: "component", type: ButtonViewsComponent, selector: "framework-button-views", inputs: ["detailsViewRoute"] }, { kind: "component", type: ErrorModalComponent, selector: "framework-error-modal", inputs: ["errorMessage", "size", "subtitle", "title"], outputs: ["closed"] }, { kind: "component", type: GroupContainerComponent, selector: "lib-group-container", inputs: ["title", "icon"] }, { kind: "directive", type: NgTemplateOutlet, selector: "[ngTemplateOutlet]", inputs: ["ngTemplateOutletContext", "ngTemplateOutlet", "ngTemplateOutletInjector"] }, { kind: "component", type: RibbonComponent, selector: "lib-ribbon" }, { kind: "component", type: RibbonGroupComponent, selector: "lib-ribbon-group", inputs: ["label"] }, { kind: "ngmodule", type: RouterModule }, { kind: "directive", type: i2.RouterOutlet, selector: "router-outlet", inputs: ["name", "routerOutletData"], outputs: ["activate", "deactivate", "attach", "detach"], exportAs: ["outlet"] }, { kind: "pipe", type: TranslatePipe, name: "translate" }] });
3376
3413
  }
3377
3414
  i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.1.6", ngImport: i0, type: DefaultDetailsTabViewComponent, decorators: [{
3378
3415
  type: Component,
@@ -3388,7 +3425,7 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.1.6", ngImpor
3388
3425
  ], providers: [
3389
3426
  { provide: TabViewService },
3390
3427
  { provide: DataProviderService, useFactory: dataProviderFactory, deps: [ActivatedRoute] },
3391
- ], template: "<lib-ribbon>\n <ng-container *ngTemplateOutlet=\"ribbonTemplate\"></ng-container>\n\n <ng-template #emptyRibbon>\n </ng-template>\n\n <div right>\n <lib-ribbon-group [label]=\"'RibbonGroup-Page' | translate\">\n <framework-button-views [detailsViewRoute]=\"detailsViewRoute\">\n </framework-button-views>\n </lib-ribbon-group>\n </div>\n</lib-ribbon>\n\n<lib-group-container\n[icon]=\"containerIcon\"\n[title]=\"containerTitle\">\n <router-outlet>\n </router-outlet>\n</lib-group-container>\n\n<framework-error-modal (closed)=\"onErrorModalClosed()\"></framework-error-modal>", styles: [":host-context{display:flex;flex-grow:1;flex-direction:column;gap:.5rem;overflow:hidden}router-outlet{display:none}\n"] }]
3428
+ ], template: "<lib-ribbon>\n <ng-container *ngTemplateOutlet=\"ribbonTemplate ?? null\"></ng-container>\n\n <div right>\n <lib-ribbon-group [label]=\"'RibbonGroup-Page' | translate\">\n <framework-button-views [detailsViewRoute]=\"detailsViewRoute\">\n </framework-button-views>\n </lib-ribbon-group>\n </div>\n</lib-ribbon>\n\n<lib-group-container\n[icon]=\"containerIcon\"\n[title]=\"containerTitle\">\n <router-outlet>\n </router-outlet>\n</lib-group-container>\n\n<framework-error-modal (closed)=\"onErrorModalClosed()\"></framework-error-modal>", styles: [":host-context{display:flex;flex-grow:1;flex-direction:column;gap:.5rem;overflow:hidden}router-outlet{display:none}\n"] }]
3392
3429
  }], ctorParameters: () => [], propDecorators: { errorModal: [{
3393
3430
  type: ViewChild,
3394
3431
  args: [ErrorModalComponent]