@mintplayer/ng-spark 22.5.0 → 22.6.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.
@@ -258,10 +258,10 @@ class SparkQueryListComponent {
258
258
  }
259
259
  this.streamItems.set(items);
260
260
  }
261
- static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "22.0.0", ngImport: i0, type: SparkQueryListComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
262
- static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "22.0.0", type: SparkQueryListComponent, isStandalone: true, selector: "spark-query-list", inputs: { extraActionsTemplate: { classPropertyName: "extraActionsTemplate", publicName: "extraActionsTemplate", isSignal: true, isRequired: false, transformFunction: null }, showCustomActions: { classPropertyName: "showCustomActions", publicName: "showCustomActions", isSignal: true, isRequired: false, transformFunction: null } }, outputs: { rowClicked: "rowClicked", createClicked: "createClicked", customActionExecuted: "customActionExecuted" }, host: { properties: { "class.virtual-scrolling": "isVirtualScrolling()" } }, viewQueries: [{ propertyName: "grid", first: true, predicate: SparkQueryGridComponent, descendants: true, isSignal: true }], ngImport: i0, template: "<div class=\"d-flex flex-column h-100\">\n <div class=\"spark-actionbar py-2 flex-shrink-0\" [class.px-4]=\"isVirtualScrolling()\" [class.px-3]=\"!isVirtualScrolling()\">\n <bs-priority-nav [moreLabel]=\"lang.t('common.more')\" [collapseAt]=\"'sm'\">\n @if (canCreate()) {\n <button *bsPriorityNavItem=\"1\" class=\"btn btn-primary\" (click)=\"onCreate()\">\n <spark-icon name=\"plus-lg\" /> {{ 'common.new' | t }}\n </button>\n }\n @if (showCustomActions()) {\n @for (action of customActions(); track action.name) {\n <!-- Disabled, not hidden: hiding makes the affordance undiscoverable and reflows the\n priority nav on every selection change. The server enforces the same rule. -->\n <button *bsPriorityNavItem=\"10 + action.offset\" class=\"btn btn-outline-primary\"\n [disabled]=\"!isActionEnabled(action)\" (click)=\"onCustomAction(action)\">\n {{ action.displayName | resolveTranslation }}\n </button>\n }\n }\n @if (extraActionsTemplate(); as extraActionsTpl) {\n <ng-container *bsPriorityNavItem=\"50\">\n <ng-container *ngTemplateOutlet=\"extraActionsTpl\"></ng-container>\n </ng-container>\n }\n </bs-priority-nav>\n </div>\n\n <h2 class=\"mb-4 flex-shrink-0\" [class.px-4]=\"isVirtualScrolling()\">\n {{ (query()?.description | resolveTranslation) || query()?.name || ('common.loading' | t) }}\n @if (isStreaming()) {\n <bs-badge [type]=\"colors.success\" class=\"ms-2 align-middle spark-live-badge\">LIVE</bs-badge>\n }\n </h2>\n\n @if (errorMessage(); as err) {\n <!-- The route could not be resolved to a query at all. A failure INSIDE the grid renders in\n the grid; this is the one it cannot report, because it never got a query id. -->\n <bs-alert [type]=\"colors.danger\" class=\"m-3 d-block\">\n {{ err }}\n </bs-alert>\n } @else if (queryId(); as qId) {\n <div class=\"flex-shrink-0\" [class.px-4]=\"isVirtualScrolling()\">\n <bs-form>\n <bs-grid>\n <div bsRow class=\"mb-3\">\n <div [md]=\"12\">\n <bs-input-group>\n <span class=\"addon\">\n <spark-icon name=\"search\" />\n </span>\n <input\n type=\"text\"\n [placeholder]=\"'common.search' | t\"\n [ngModel]=\"searchTerm()\"\n (ngModelChange)=\"searchTerm.set($event)\">\n @if (searchTerm()) {\n <button\n type=\"button\"\n class=\"btn btn-outline-secondary\"\n (click)=\"clearSearch()\">\n <spark-icon name=\"x-lg\" />\n </button>\n }\n </bs-input-group>\n </div>\n <!-- Its own full-width row rather than a column beside the box: the count is\n occasional, and reserving 8 columns for it shrank the search permanently. The\n @if moved out of the column so nothing reserves vertical space when absent. -->\n @if (searchTerm() && resultCount() !== null) {\n <div [md]=\"12\" class=\"text-end mt-1\">\n <span class=\"text-muted\">\n {{ resultCount() }} {{ resultCount() === 1 ? ('common.resultFound' | t) : ('common.resultsFound' | t) }}\n </span>\n </div>\n }\n </div>\n </bs-grid>\n </bs-form>\n </div>\n\n <!--\n One grid, both transports. `data` is null for a normal query, so the grid fetches and pages\n server-side; for a streaming query this page owns the socket and hands the filtered snapshot\n in. This used to be two near-identical <bs-datatable> blocks with a shared row template.\n -->\n <spark-query-grid class=\"flex-grow-1\"\n [queryId]=\"qId\"\n [data]=\"gridData()\"\n [search]=\"searchTerm()\"\n (rowClicked)=\"rowClicked.emit($event)\"\n (customActionExecuted)=\"customActionExecuted.emit($event)\" />\n } @else {\n <div class=\"text-center p-5\">\n <bs-spinner />\n </div>\n }\n</div>\n", styles: [".spark-actionbar{position:sticky;top:0;z-index:400;background-color:var(--bs-tertiary-bg);border-bottom:1px solid var(--bs-border-color);margin-bottom:1rem}.spark-actionbar .btn{border-radius:0}:host{display:flex;flex-direction:column;flex:1;min-height:0}:host.virtual-scrolling{margin:0 -1.5rem -1.5rem}:host.virtual-scrolling spark-query-grid{display:flex;flex-direction:column;min-height:0}:host.virtual-scrolling ::ng-deep bs-datatable{display:flex;flex-direction:column;min-height:0;--mp-datatable-virtual-max-height: 100%}:host.virtual-scrolling ::ng-deep bs-datatable mp-datatable{flex:1 1 auto;min-height:0}tr:hover{background-color:#0000000d}td input[type=checkbox]:disabled{opacity:1;pointer-events:none}.spark-live-badge{font-size:.6em}\n"], dependencies: [{ kind: "component", type: BsBadgeComponent, selector: "bs-badge", inputs: ["type", "unit", "decorative"] }, { kind: "ngmodule", type: CommonModule }, { kind: "directive", type: i1.NgTemplateOutlet, selector: "[ngTemplateOutlet]", inputs: ["ngTemplateOutletContext", "ngTemplateOutlet", "ngTemplateOutletInjector"] }, { kind: "ngmodule", type: FormsModule }, { kind: "directive", type: i2.DefaultValueAccessor, selector: "input:not([type=checkbox]):not([ngNoCva])[formControlName],textarea:not([ngNoCva])[formControlName],input:not([type=checkbox]):not([ngNoCva])[formControl],textarea:not([ngNoCva])[formControl],input:not([type=checkbox]):not([ngNoCva])[ngModel],textarea:not([ngNoCva])[ngModel],[ngDefaultControl]" }, { kind: "directive", type: i2.NgControlStatus, selector: "[formControlName],[ngModel],[formControl]" }, { kind: "directive", type: i2.NgModel, selector: "[ngModel]:not([formControlName]):not([formControl])", inputs: ["name", "disabled", "ngModel", "ngModelOptions"], outputs: ["ngModelChange"], exportAs: ["ngModel"] }, { kind: "component", type: BsAlertComponent, selector: "bs-alert", inputs: ["type", "announce", "isVisible"], outputs: ["isVisibleChange", "afterOpenedOrClosed"] }, { kind: "component", type: BsFormComponent, selector: "bs-form", inputs: ["action", "method"], outputs: ["submitted"] }, { kind: "directive", type: BsFormControlDirective, selector: "bs-form input:not(.no-form-control), bs-form textarea:not(.no-form-control)" }, { kind: "component", type: BsGridComponent, selector: "bs-grid", inputs: ["stopFullWidthAt"] }, { kind: "directive", type: BsGridRowDirective, selector: "[bsRow]" }, { kind: "directive", type: BsGridColumnDirective, selector: "[xxs],[xs],[sm],[md],[lg],[xl],[xxl]", inputs: ["xxs", "xs", "sm", "md", "lg", "xl", "xxl"] }, { kind: "component", type: BsInputGroupComponent, selector: "bs-input-group", inputs: ["size"] }, { kind: "component", type: BsPriorityNavComponent, selector: "bs-priority-nav", inputs: ["moreLabel", "moreLabelTemplate", "collapseAt", "overflowFrom", "hideEmptyMore", "ariaLabel"], outputs: ["overflowChange"] }, { kind: "directive", type: BsPriorityNavItemDirective, selector: "[bsPriorityNavItem]", inputs: ["bsPriorityNavItem", "bsPriorityNavItemHideBelow"] }, { kind: "component", type: BsSpinnerComponent, selector: "bs-spinner", inputs: ["type", "color"] }, { kind: "component", type: SparkIconComponent, selector: "spark-icon", inputs: ["name"] }, { kind: "component", type: SparkQueryGridComponent, selector: "spark-query-grid", inputs: ["queryId", "parentId", "parentType", "data", "search", "reloadToken", "settings", "selection"], outputs: ["settingsChange", "selectionChange", "error", "rowClicked", "customActionExecuted"] }, { kind: "pipe", type: ResolveTranslationPipe, name: "resolveTranslation" }, { kind: "pipe", type: TranslateKeyPipe, name: "t" }], changeDetection: i0.ChangeDetectionStrategy.OnPush });
261
+ static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "22.1.3", ngImport: i0, type: SparkQueryListComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
262
+ static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "22.1.3", type: SparkQueryListComponent, isStandalone: true, selector: "spark-query-list", inputs: { extraActionsTemplate: { classPropertyName: "extraActionsTemplate", publicName: "extraActionsTemplate", isSignal: true, isRequired: false, transformFunction: null }, showCustomActions: { classPropertyName: "showCustomActions", publicName: "showCustomActions", isSignal: true, isRequired: false, transformFunction: null } }, outputs: { rowClicked: "rowClicked", createClicked: "createClicked", customActionExecuted: "customActionExecuted" }, host: { properties: { "class.virtual-scrolling": "isVirtualScrolling()" } }, viewQueries: [{ propertyName: "grid", first: true, predicate: SparkQueryGridComponent, descendants: true, isSignal: true }], ngImport: i0, template: "<div class=\"d-flex flex-column h-100\">\n <div class=\"spark-actionbar py-2 flex-shrink-0\" [class.px-4]=\"isVirtualScrolling()\" [class.px-3]=\"!isVirtualScrolling()\">\n <bs-priority-nav [moreLabel]=\"lang.t('common.more')\" [collapseAt]=\"'sm'\">\n @if (canCreate()) {\n <button *bsPriorityNavItem=\"1\" class=\"btn btn-primary\" (click)=\"onCreate()\">\n <spark-icon name=\"plus-lg\" /> {{ 'common.new' | t }}\n </button>\n }\n @if (showCustomActions()) {\n @for (action of customActions(); track action.name) {\n <!-- Disabled, not hidden: hiding makes the affordance undiscoverable and reflows the\n priority nav on every selection change. The server enforces the same rule. -->\n <button *bsPriorityNavItem=\"10 + action.offset\" class=\"btn btn-outline-primary\"\n [disabled]=\"!isActionEnabled(action)\" (click)=\"onCustomAction(action)\">\n {{ action.displayName | resolveTranslation }}\n </button>\n }\n }\n @if (extraActionsTemplate(); as extraActionsTpl) {\n <ng-container *bsPriorityNavItem=\"50\">\n <ng-container *ngTemplateOutlet=\"extraActionsTpl\"></ng-container>\n </ng-container>\n }\n </bs-priority-nav>\n </div>\n\n <h2 class=\"mb-4 flex-shrink-0\" [class.px-4]=\"isVirtualScrolling()\">\n {{ (query()?.description | resolveTranslation) || query()?.name || ('common.loading' | t) }}\n @if (isStreaming()) {\n <bs-badge [type]=\"colors.success\" class=\"ms-2 align-middle spark-live-badge\">LIVE</bs-badge>\n }\n </h2>\n\n @if (errorMessage(); as err) {\n <!-- The route could not be resolved to a query at all. A failure INSIDE the grid renders in\n the grid; this is the one it cannot report, because it never got a query id. -->\n <bs-alert [type]=\"colors.danger\" class=\"m-3 d-block\">\n {{ err }}\n </bs-alert>\n } @else if (queryId(); as qId) {\n <div class=\"flex-shrink-0\" [class.px-4]=\"isVirtualScrolling()\">\n <bs-form>\n <bs-grid>\n <div bsRow class=\"mb-3\">\n <div [md]=\"12\">\n <bs-input-group>\n <span class=\"addon\">\n <spark-icon name=\"search\" />\n </span>\n <input\n type=\"text\"\n [placeholder]=\"'common.search' | t\"\n [ngModel]=\"searchTerm()\"\n (ngModelChange)=\"searchTerm.set($event)\">\n @if (searchTerm()) {\n <button\n type=\"button\"\n class=\"btn btn-outline-secondary\"\n (click)=\"clearSearch()\">\n <spark-icon name=\"x-lg\" />\n </button>\n }\n </bs-input-group>\n </div>\n <!-- Its own full-width row rather than a column beside the box: the count is\n occasional, and reserving 8 columns for it shrank the search permanently. The\n @if moved out of the column so nothing reserves vertical space when absent. -->\n @if (searchTerm() && resultCount() !== null) {\n <div [md]=\"12\" class=\"text-end mt-1\">\n <span class=\"text-muted\">\n {{ resultCount() }} {{ resultCount() === 1 ? ('common.resultFound' | t) : ('common.resultsFound' | t) }}\n </span>\n </div>\n }\n </div>\n </bs-grid>\n </bs-form>\n </div>\n\n <!--\n One grid, both transports. `data` is null for a normal query, so the grid fetches and pages\n server-side; for a streaming query this page owns the socket and hands the filtered snapshot\n in. This used to be two near-identical <bs-datatable> blocks with a shared row template.\n -->\n <spark-query-grid class=\"flex-grow-1\"\n [queryId]=\"qId\"\n [data]=\"gridData()\"\n [search]=\"searchTerm()\"\n (rowClicked)=\"rowClicked.emit($event)\"\n (customActionExecuted)=\"customActionExecuted.emit($event)\" />\n } @else {\n <div class=\"text-center p-5\">\n <bs-spinner />\n </div>\n }\n</div>\n", styles: [".spark-actionbar{position:sticky;top:0;z-index:400;background-color:var(--bs-tertiary-bg);border-bottom:1px solid var(--bs-border-color);margin-bottom:1rem}.spark-actionbar .btn{border-radius:0}:host{display:flex;flex-direction:column;flex:1;min-height:0}:host.virtual-scrolling{margin:0 -1.5rem -1.5rem}:host.virtual-scrolling spark-query-grid{display:flex;flex-direction:column;min-height:0}:host.virtual-scrolling ::ng-deep bs-datatable{display:flex;flex-direction:column;min-height:0;--mp-datatable-virtual-max-height: 100%}:host.virtual-scrolling ::ng-deep bs-datatable mp-datatable{flex:1 1 auto;min-height:0}tr:hover{background-color:#0000000d}td input[type=checkbox]:disabled{opacity:1;pointer-events:none}.spark-live-badge{font-size:.6em}\n"], dependencies: [{ kind: "component", type: BsBadgeComponent, selector: "bs-badge", inputs: ["type", "unit", "decorative"] }, { kind: "ngmodule", type: CommonModule }, { kind: "directive", type: i1.NgTemplateOutlet, selector: "[ngTemplateOutlet]", inputs: ["ngTemplateOutletContext", "ngTemplateOutlet", "ngTemplateOutletInjector"] }, { kind: "ngmodule", type: FormsModule }, { kind: "directive", type: i2.DefaultValueAccessor, selector: "input:not([type=checkbox]):not([ngNoCva])[formControlName],textarea:not([ngNoCva])[formControlName],input:not([type=checkbox]):not([ngNoCva])[formControl],textarea:not([ngNoCva])[formControl],input:not([type=checkbox]):not([ngNoCva])[ngModel],textarea:not([ngNoCva])[ngModel],[ngDefaultControl]" }, { kind: "directive", type: i2.NgControlStatus, selector: "[formControlName],[ngModel],[formControl]" }, { kind: "directive", type: i2.NgModel, selector: "[ngModel]:not([formControlName]):not([formControl])", inputs: ["name", "disabled", "ngModel", "ngModelOptions"], outputs: ["ngModelChange"], exportAs: ["ngModel"] }, { kind: "component", type: BsAlertComponent, selector: "bs-alert", inputs: ["type", "announce", "isVisible"], outputs: ["isVisibleChange", "afterOpenedOrClosed"] }, { kind: "component", type: BsFormComponent, selector: "bs-form", inputs: ["action", "method"], outputs: ["submitted"] }, { kind: "directive", type: BsFormControlDirective, selector: "bs-form input:not(.no-form-control), bs-form textarea:not(.no-form-control)" }, { kind: "component", type: BsGridComponent, selector: "bs-grid", inputs: ["stopFullWidthAt"] }, { kind: "directive", type: BsGridRowDirective, selector: "[bsRow]" }, { kind: "directive", type: BsGridColumnDirective, selector: "[xxs],[xs],[sm],[md],[lg],[xl],[xxl]", inputs: ["xxs", "xs", "sm", "md", "lg", "xl", "xxl"] }, { kind: "component", type: BsInputGroupComponent, selector: "bs-input-group", inputs: ["size"] }, { kind: "component", type: BsPriorityNavComponent, selector: "bs-priority-nav", inputs: ["moreLabel", "moreLabelTemplate", "collapseAt", "overflowFrom", "hideEmptyMore", "ariaLabel"], outputs: ["overflowChange"] }, { kind: "directive", type: BsPriorityNavItemDirective, selector: "[bsPriorityNavItem]", inputs: ["bsPriorityNavItem", "bsPriorityNavItemHideBelow"] }, { kind: "component", type: BsSpinnerComponent, selector: "bs-spinner", inputs: ["type", "color"] }, { kind: "component", type: SparkIconComponent, selector: "spark-icon", inputs: ["name"] }, { kind: "component", type: SparkQueryGridComponent, selector: "spark-query-grid", inputs: ["queryId", "parentId", "parentType", "data", "search", "reloadToken", "settings", "selection"], outputs: ["settingsChange", "selectionChange", "error", "rowClicked", "customActionExecuted"] }, { kind: "pipe", type: ResolveTranslationPipe, name: "resolveTranslation" }, { kind: "pipe", type: TranslateKeyPipe, name: "t" }], changeDetection: i0.ChangeDetectionStrategy.OnPush });
263
263
  }
264
- i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.0.0", ngImport: i0, type: SparkQueryListComponent, decorators: [{
264
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.1.3", ngImport: i0, type: SparkQueryListComponent, decorators: [{
265
265
  type: Component,
266
266
  args: [{ selector: 'spark-query-list', imports: [BsBadgeComponent, CommonModule, NgTemplateOutlet, FormsModule, BsAlertComponent, BsFormComponent, BsFormControlDirective, BsGridComponent, BsGridRowDirective, BsGridColumnDirective, BsInputGroupComponent, BsPriorityNavComponent, BsPriorityNavItemDirective, BsSpinnerComponent, SparkIconComponent, SparkQueryGridComponent, ResolveTranslationPipe, TranslateKeyPipe], changeDetection: ChangeDetectionStrategy.OnPush, host: {
267
267
  '[class.virtual-scrolling]': 'isVirtualScrolling()'
@@ -103,8 +103,8 @@ class SparkRetryActionModalComponent {
103
103
  };
104
104
  return populated;
105
105
  }
106
- static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "22.0.0", ngImport: i0, type: SparkRetryActionModalComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
107
- static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "22.0.0", type: SparkRetryActionModalComponent, isStandalone: true, selector: "spark-retry-action-modal", ngImport: i0, template: `
106
+ static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "22.1.3", ngImport: i0, type: SparkRetryActionModalComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
107
+ static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "22.1.3", type: SparkRetryActionModalComponent, isStandalone: true, selector: "spark-retry-action-modal", ngImport: i0, template: `
108
108
  <bs-modal [isOpen]="isOpen()" (isOpenChange)="!$event && onOption('Cancel')">
109
109
  <div *bsModal>
110
110
  <div bsModalHeader>
@@ -136,7 +136,7 @@ class SparkRetryActionModalComponent {
136
136
  </bs-modal>
137
137
  `, isInline: true, dependencies: [{ kind: "ngmodule", type: CommonModule }, { kind: "component", type: BsModalHostComponent, selector: "bs-modal", inputs: ["isOpen", "closeOnEscape", "scrollable"], outputs: ["isOpenChange"] }, { kind: "directive", type: BsModalDirective, selector: "[bsModal]" }, { kind: "directive", type: BsModalHeaderDirective, selector: "[bsModalHeader]" }, { kind: "directive", type: BsModalBodyDirective, selector: "[bsModalBody]" }, { kind: "directive", type: BsModalFooterDirective, selector: "[bsModalFooter]" }, { kind: "directive", type: BsButtonTypeDirective, selector: "button[color],input[type=\"button\"][color],input[type=\"submit\"][color],a[color]", inputs: ["color"] }, { kind: "component", type: SparkPoFormComponent, selector: "spark-po-form", inputs: ["entityType", "formData", "validationErrors", "showButtons", "isSaving", "parentId", "parentType", "objectTypeId", "objectId"], outputs: ["formDataChange", "save", "cancel"] }], changeDetection: i0.ChangeDetectionStrategy.OnPush });
138
138
  }
139
- i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.0.0", ngImport: i0, type: SparkRetryActionModalComponent, decorators: [{
139
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.1.3", ngImport: i0, type: SparkRetryActionModalComponent, decorators: [{
140
140
  type: Component,
141
141
  args: [{
142
142
  selector: 'spark-retry-action-modal',
@@ -20,10 +20,10 @@ class RetryActionService {
20
20
  this.resolveRetry?.(result);
21
21
  this.resolveRetry = null;
22
22
  }
23
- static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "22.0.0", ngImport: i0, type: RetryActionService, deps: [], target: i0.ɵɵFactoryTarget.Injectable });
24
- static ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "22.0.0", ngImport: i0, type: RetryActionService, providedIn: 'root' });
23
+ static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "22.1.3", ngImport: i0, type: RetryActionService, deps: [], target: i0.ɵɵFactoryTarget.Injectable });
24
+ static ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "22.1.3", ngImport: i0, type: RetryActionService, providedIn: 'root' });
25
25
  }
26
- i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.0.0", ngImport: i0, type: RetryActionService, decorators: [{
26
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.1.3", ngImport: i0, type: RetryActionService, decorators: [{
27
27
  type: Injectable,
28
28
  args: [{ providedIn: 'root' }]
29
29
  }] });
@@ -70,10 +70,10 @@ class SparkLanguageService {
70
70
  const ts = this.translationsMap()[key];
71
71
  return this.resolve(ts) || key;
72
72
  }
73
- static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "22.0.0", ngImport: i0, type: SparkLanguageService, deps: [], target: i0.ɵɵFactoryTarget.Injectable });
74
- static ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "22.0.0", ngImport: i0, type: SparkLanguageService, providedIn: 'root' });
73
+ static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "22.1.3", ngImport: i0, type: SparkLanguageService, deps: [], target: i0.ɵɵFactoryTarget.Injectable });
74
+ static ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "22.1.3", ngImport: i0, type: SparkLanguageService, providedIn: 'root' });
75
75
  }
76
- i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.0.0", ngImport: i0, type: SparkLanguageService, decorators: [{
76
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.1.3", ngImport: i0, type: SparkLanguageService, decorators: [{
77
77
  type: Injectable,
78
78
  args: [{ providedIn: 'root' }]
79
79
  }], ctorParameters: () => [] });
@@ -156,10 +156,10 @@ class SparkStreamingService {
156
156
  const protocol = window.location.protocol === 'https:' ? 'wss:' : 'ws:';
157
157
  return `${protocol}//${window.location.host}${path}`;
158
158
  }
159
- static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "22.0.0", ngImport: i0, type: SparkStreamingService, deps: [], target: i0.ɵɵFactoryTarget.Injectable });
160
- static ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "22.0.0", ngImport: i0, type: SparkStreamingService, providedIn: 'root' });
159
+ static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "22.1.3", ngImport: i0, type: SparkStreamingService, deps: [], target: i0.ɵɵFactoryTarget.Injectable });
160
+ static ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "22.1.3", ngImport: i0, type: SparkStreamingService, providedIn: 'root' });
161
161
  }
162
- i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.0.0", ngImport: i0, type: SparkStreamingService, decorators: [{
162
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.1.3", ngImport: i0, type: SparkStreamingService, decorators: [{
163
163
  type: Injectable,
164
164
  args: [{ providedIn: 'root' }]
165
165
  }] });
@@ -333,10 +333,10 @@ class SparkService {
333
333
  body.retryResults = [...(body.retryResults || []), result];
334
334
  return retryFn();
335
335
  }
336
- static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "22.0.0", ngImport: i0, type: SparkService, deps: [], target: i0.ɵɵFactoryTarget.Injectable });
337
- static ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "22.0.0", ngImport: i0, type: SparkService, providedIn: 'root' });
336
+ static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "22.1.3", ngImport: i0, type: SparkService, deps: [], target: i0.ɵɵFactoryTarget.Injectable });
337
+ static ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "22.1.3", ngImport: i0, type: SparkService, providedIn: 'root' });
338
338
  }
339
- i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.0.0", ngImport: i0, type: SparkService, decorators: [{
339
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.1.3", ngImport: i0, type: SparkService, decorators: [{
340
340
  type: Injectable,
341
341
  args: [{ providedIn: 'root' }]
342
342
  }] });
@@ -393,10 +393,10 @@ class SparkIconRegistry {
393
393
  has(name) {
394
394
  return this.icons.has(name);
395
395
  }
396
- static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "22.0.0", ngImport: i0, type: SparkIconRegistry, deps: [], target: i0.ɵɵFactoryTarget.Injectable });
397
- static ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "22.0.0", ngImport: i0, type: SparkIconRegistry, providedIn: 'root' });
396
+ static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "22.1.3", ngImport: i0, type: SparkIconRegistry, deps: [], target: i0.ɵɵFactoryTarget.Injectable });
397
+ static ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "22.1.3", ngImport: i0, type: SparkIconRegistry, providedIn: 'root' });
398
398
  }
399
- i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.0.0", ngImport: i0, type: SparkIconRegistry, decorators: [{
399
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.1.3", ngImport: i0, type: SparkIconRegistry, decorators: [{
400
400
  type: Injectable,
401
401
  args: [{ providedIn: 'root' }]
402
402
  }], ctorParameters: () => [] });
@@ -0,0 +1,379 @@
1
+ import * as i0 from '@angular/core';
2
+ import { inject, input, signal, effect, untracked, ChangeDetectionStrategy, Component, TemplateRef, Directive, contentChild, computed, contentChildren } from '@angular/core';
3
+ import { NgTemplateOutlet, KeyValuePipe } from '@angular/common';
4
+ import { BsShellComponent, BsShellSidebarDirective } from '@mintplayer/ng-bootstrap/shell';
5
+ import { BsNavbarTogglerComponent } from '@mintplayer/ng-bootstrap/navbar-toggler';
6
+ import { RouterLink, RouterLinkActive } from '@angular/router';
7
+ import { BsAccordionComponent, BsAccordionTabComponent, BsAccordionTabHeaderDirective } from '@mintplayer/ng-bootstrap/accordion';
8
+ import { SPARK_AUTH_STATE } from '@mintplayer/ng-spark';
9
+ import { SparkService, SparkLanguageService } from '@mintplayer/ng-spark/services';
10
+ import { ResolveTranslationPipe, IconNamePipe, RouterLinkPipe } from '@mintplayer/ng-spark/pipes';
11
+ import { SparkIconComponent } from '@mintplayer/ng-spark/icon';
12
+ import * as i1 from '@angular/forms';
13
+ import { FormsModule } from '@angular/forms';
14
+ import { BsSelectComponent, BsSelectOption } from '@mintplayer/ng-bootstrap/select';
15
+
16
+ /**
17
+ * The server-driven navigation menu: an accordion of program-unit groups fetched from
18
+ * `GET /spark/program-units`, which the server has already filtered to what the caller's rights
19
+ * allow. Hosts write ZERO router links for navigation — every group, unit, icon, label and link
20
+ * comes from `programUnits.json`; content around the menu belongs in `<spark-shell>`'s slots,
21
+ * and a host tempted to hand-write a unit anchor should add a unit to `programUnits.json`
22
+ * instead.
23
+ *
24
+ * Because the response is caller-scoped it must be re-fetched when the caller changes: the
25
+ * component tracks the optional `SPARK_AUTH_STATE` signal (supplied by ng-spark-auth's
26
+ * `provideSparkAuth()`, or by the app's own auth stack) and reloads on every change. Without a
27
+ * provider it fetches once. `reloadToken` is the manual escape hatch (any changed value triggers
28
+ * a reload), and `reload()` the imperative one.
29
+ *
30
+ * Usually rendered by `<spark-shell>`; exported standalone for hosts that own their own layout.
31
+ */
32
+ class SparkProgramUnitsComponent {
33
+ sparkService = inject(SparkService);
34
+ authState = inject(SPARK_AUTH_STATE, { optional: true });
35
+ /** Any changed value triggers a reload — for apps whose auth state isn't a provided signal. */
36
+ reloadToken = input(null, /* @ts-ignore */
37
+ ...(ngDevMode ? [{ debugName: "reloadToken" }] : /* istanbul ignore next */ []));
38
+ /**
39
+ * Extra tabs to render after the generated groups, normally forwarded by `<spark-shell>` from
40
+ * its `*sparkShellTab` directives. They must be rendered by THIS template — see
41
+ * `SparkShellTabDirective` for why a host-declared `<bs-accordion-tab>` cannot work.
42
+ */
43
+ extraTabs = input([], /* @ts-ignore */
44
+ ...(ngDevMode ? [{ debugName: "extraTabs" }] : /* istanbul ignore next */ []));
45
+ groups = signal([], /* @ts-ignore */
46
+ ...(ngDevMode ? [{ debugName: "groups" }] : /* istanbul ignore next */ []));
47
+ constructor() {
48
+ effect(() => {
49
+ this.authState?.();
50
+ this.reloadToken();
51
+ untracked(() => this.reload());
52
+ });
53
+ }
54
+ /** Re-fetches the menu. The response is already rights-filtered per caller. */
55
+ async reload() {
56
+ const config = await this.sparkService.getProgramUnits();
57
+ // Order is the server file's contract, but sort both levels here so the rendered menu never
58
+ // depends on JSON array order — groups were sorted, units were not (#324 F5).
59
+ const groups = [...config.programUnitGroups]
60
+ .sort((a, b) => a.order - b.order)
61
+ .map(g => ({ ...g, programUnits: [...g.programUnits].sort((a, b) => a.order - b.order) }));
62
+ this.groups.set(groups);
63
+ }
64
+ static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "22.1.3", ngImport: i0, type: SparkProgramUnitsComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
65
+ static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "22.1.3", type: SparkProgramUnitsComponent, isStandalone: true, selector: "spark-program-units", inputs: { reloadToken: { classPropertyName: "reloadToken", publicName: "reloadToken", isSignal: true, isRequired: false, transformFunction: null }, extraTabs: { classPropertyName: "extraTabs", publicName: "extraTabs", isSignal: true, isRequired: false, transformFunction: null } }, ngImport: i0, template: "<bs-accordion class=\"d-block\">\n @for (group of groups(); track group.id) {\n <bs-accordion-tab>\n <ng-container *bsAccordionTabHeader>\n <spark-icon [name]=\"group.icon | iconName:'bi-folder'\" />\n <span class=\"ms-2\">{{ group.name | resolveTranslation }}</span>\n </ng-container>\n @for (unit of group.programUnits; track unit.id) {\n @if (unit | routerLink; as link) {\n <a [routerLink]=\"link\"\n routerLinkActive=\"active\"\n class=\"d-block px-3 py-2 text-decoration-none nav-link\">\n <spark-icon [name]=\"unit.icon | iconName:'bi-file'\" />\n <span class=\"ms-2\">{{ unit.name | resolveTranslation }}</span>\n </a>\n } @else {\n <!-- A url unit is an external address: a plain anchor, never a router link. -->\n <a [href]=\"unit.url\" target=\"_blank\" rel=\"noopener\"\n class=\"d-block px-3 py-2 text-decoration-none nav-link\">\n <spark-icon [name]=\"unit.icon | iconName:'bi-box-arrow-up-right'\" />\n <span class=\"ms-2\">{{ unit.name | resolveTranslation }}</span>\n </a>\n }\n }\n </bs-accordion-tab>\n }\n <!-- Host-contributed tabs are rendered HERE, by this template, so that the accordion's content\n query registers them and they join the generated groups' single-open group. -->\n @for (tab of extraTabs(); track tab.content) {\n <bs-accordion-tab>\n <ng-container *bsAccordionTabHeader>\n @if (tab.headerTemplate; as tpl) {\n <ng-container *ngTemplateOutlet=\"tpl\" />\n } @else {\n <spark-icon [name]=\"tab.icon | iconName:'bi-folder'\" />\n <span class=\"ms-2\">{{ tab.header }}</span>\n }\n </ng-container>\n <ng-container *ngTemplateOutlet=\"tab.content\" />\n </bs-accordion-tab>\n }\n</bs-accordion>\n", styles: [":host{display:block;--bs-primary-bg-subtle: rgba(255, 255, 255, .1);--bs-border-color: transparent}:host ::ng-deep mp-accordion::part(content){padding:0}.nav-link{color:inherit}.nav-link:hover{background-color:#ffffff1a}.nav-link.active{background-color:#fff3}\n"], dependencies: [{ kind: "directive", type: NgTemplateOutlet, selector: "[ngTemplateOutlet]", inputs: ["ngTemplateOutletContext", "ngTemplateOutlet", "ngTemplateOutletInjector"] }, { kind: "directive", type: RouterLink, selector: "[routerLink]", inputs: ["target", "queryParams", "fragment", "queryParamsHandling", "state", "info", "relativeTo", "preserveFragment", "skipLocationChange", "replaceUrl", "browserUrl", "routerLink"] }, { kind: "directive", type: RouterLinkActive, selector: "[routerLinkActive]", inputs: ["routerLinkActiveOptions", "ariaCurrentWhenActive", "routerLinkActive"], outputs: ["isActiveChange"], exportAs: ["routerLinkActive"] }, { kind: "component", type: BsAccordionComponent, selector: "bs-accordion", inputs: ["multi", "highlightActiveTab"] }, { kind: "component", type: BsAccordionTabComponent, selector: "bs-accordion-tab", inputs: ["isActive", "disabled"], outputs: ["isActiveChange"] }, { kind: "directive", type: BsAccordionTabHeaderDirective, selector: "[bsAccordionTabHeader]" }, { kind: "component", type: SparkIconComponent, selector: "spark-icon", inputs: ["name"] }, { kind: "pipe", type: ResolveTranslationPipe, name: "resolveTranslation" }, { kind: "pipe", type: IconNamePipe, name: "iconName" }, { kind: "pipe", type: RouterLinkPipe, name: "routerLink" }], changeDetection: i0.ChangeDetectionStrategy.OnPush });
66
+ }
67
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.1.3", ngImport: i0, type: SparkProgramUnitsComponent, decorators: [{
68
+ type: Component,
69
+ args: [{ selector: 'spark-program-units', standalone: true, changeDetection: ChangeDetectionStrategy.OnPush, imports: [
70
+ NgTemplateOutlet,
71
+ RouterLink, RouterLinkActive,
72
+ BsAccordionComponent, BsAccordionTabComponent, BsAccordionTabHeaderDirective,
73
+ SparkIconComponent, ResolveTranslationPipe, IconNamePipe, RouterLinkPipe,
74
+ ], template: "<bs-accordion class=\"d-block\">\n @for (group of groups(); track group.id) {\n <bs-accordion-tab>\n <ng-container *bsAccordionTabHeader>\n <spark-icon [name]=\"group.icon | iconName:'bi-folder'\" />\n <span class=\"ms-2\">{{ group.name | resolveTranslation }}</span>\n </ng-container>\n @for (unit of group.programUnits; track unit.id) {\n @if (unit | routerLink; as link) {\n <a [routerLink]=\"link\"\n routerLinkActive=\"active\"\n class=\"d-block px-3 py-2 text-decoration-none nav-link\">\n <spark-icon [name]=\"unit.icon | iconName:'bi-file'\" />\n <span class=\"ms-2\">{{ unit.name | resolveTranslation }}</span>\n </a>\n } @else {\n <!-- A url unit is an external address: a plain anchor, never a router link. -->\n <a [href]=\"unit.url\" target=\"_blank\" rel=\"noopener\"\n class=\"d-block px-3 py-2 text-decoration-none nav-link\">\n <spark-icon [name]=\"unit.icon | iconName:'bi-box-arrow-up-right'\" />\n <span class=\"ms-2\">{{ unit.name | resolveTranslation }}</span>\n </a>\n }\n }\n </bs-accordion-tab>\n }\n <!-- Host-contributed tabs are rendered HERE, by this template, so that the accordion's content\n query registers them and they join the generated groups' single-open group. -->\n @for (tab of extraTabs(); track tab.content) {\n <bs-accordion-tab>\n <ng-container *bsAccordionTabHeader>\n @if (tab.headerTemplate; as tpl) {\n <ng-container *ngTemplateOutlet=\"tpl\" />\n } @else {\n <spark-icon [name]=\"tab.icon | iconName:'bi-folder'\" />\n <span class=\"ms-2\">{{ tab.header }}</span>\n }\n </ng-container>\n <ng-container *ngTemplateOutlet=\"tab.content\" />\n </bs-accordion-tab>\n }\n</bs-accordion>\n", styles: [":host{display:block;--bs-primary-bg-subtle: rgba(255, 255, 255, .1);--bs-border-color: transparent}:host ::ng-deep mp-accordion::part(content){padding:0}.nav-link{color:inherit}.nav-link:hover{background-color:#ffffff1a}.nav-link.active{background-color:#fff3}\n"] }]
75
+ }], ctorParameters: () => [], propDecorators: { reloadToken: [{ type: i0.Input, args: [{ isSignal: true, alias: "reloadToken", required: false }] }], extraTabs: [{ type: i0.Input, args: [{ isSignal: true, alias: "extraTabs", required: false }] }] } });
76
+
77
+ /**
78
+ * The culture switcher: a `bs-select` over `SparkLanguageService`'s languages, persisting the
79
+ * choice. Renders nothing when the app declares one language (or none), so hosts can include it
80
+ * unconditionally — `<spark-shell>`'s topbar does exactly that as its trailing default.
81
+ */
82
+ class SparkLanguageSelectorComponent {
83
+ lang = inject(SparkLanguageService);
84
+ static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "22.1.3", ngImport: i0, type: SparkLanguageSelectorComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
85
+ static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "22.1.3", type: SparkLanguageSelectorComponent, isStandalone: true, selector: "spark-language-selector", ngImport: i0, template: `
86
+ @if (lang.languages() | keyvalue; as langs) {
87
+ @if (langs.length > 1) {
88
+ <bs-select [ngModel]="lang.language()" (ngModelChange)="lang.setLanguage($event)">
89
+ @for (l of langs; track l.key) {
90
+ <option [ngValue]="l.key">{{ l.value | resolveTranslation }}</option>
91
+ }
92
+ </bs-select>
93
+ }
94
+ }
95
+ `, isInline: true, dependencies: [{ kind: "ngmodule", type: FormsModule }, { kind: "directive", type: i1.NgSelectOption, selector: "option", inputs: ["ngValue", "value"] }, { kind: "directive", type: i1.ɵNgSelectMultipleOption, selector: "option", inputs: ["ngValue", "value"] }, { kind: "directive", type: i1.NgControlStatus, selector: "[formControlName],[ngModel],[formControl]" }, { kind: "directive", type: i1.NgModel, selector: "[ngModel]:not([formControlName]):not([formControl])", inputs: ["name", "disabled", "ngModel", "ngModelOptions"], outputs: ["ngModelChange"], exportAs: ["ngModel"] }, { kind: "component", type: BsSelectComponent, selector: "bs-select", inputs: ["identifier", "size", "multiple", "numberVisible", "disabled"] }, { kind: "directive", type: BsSelectOption, selector: "option", inputs: ["ngValue", "value"] }, { kind: "pipe", type: KeyValuePipe, name: "keyvalue" }, { kind: "pipe", type: ResolveTranslationPipe, name: "resolveTranslation" }], changeDetection: i0.ChangeDetectionStrategy.OnPush });
96
+ }
97
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.1.3", ngImport: i0, type: SparkLanguageSelectorComponent, decorators: [{
98
+ type: Component,
99
+ args: [{
100
+ selector: 'spark-language-selector',
101
+ standalone: true,
102
+ changeDetection: ChangeDetectionStrategy.OnPush,
103
+ imports: [KeyValuePipe, FormsModule, BsSelectComponent, BsSelectOption, ResolveTranslationPipe],
104
+ template: `
105
+ @if (lang.languages() | keyvalue; as langs) {
106
+ @if (langs.length > 1) {
107
+ <bs-select [ngModel]="lang.language()" (ngModelChange)="lang.setLanguage($event)">
108
+ @for (l of langs; track l.key) {
109
+ <option [ngValue]="l.key">{{ l.value | resolveTranslation }}</option>
110
+ }
111
+ </bs-select>
112
+ }
113
+ }
114
+ `,
115
+ }]
116
+ }] });
117
+
118
+ /**
119
+ * Region slots for `<spark-shell>`.
120
+ *
121
+ * Each directive marks a template that REPLACES one region of the shell chrome (or fills an
122
+ * empty one). An omitted slot is not an empty slot: the shell renders its default — the toggler,
123
+ * the language selector, the title heading — so a host that supplies nothing still gets a
124
+ * complete working shell, and a host that supplies one slot leaves the rest alone.
125
+ *
126
+ * The menu itself is deliberately NOT a slot. Navigation is sourced entirely from
127
+ * `programUnits.json` through the rights-filtered `/spark/program-units` endpoint and re-fetched
128
+ * on sign-in/out; a host that finds itself writing unit anchors in a slot should be adding units
129
+ * to `programUnits.json` instead. Slots exist for the content AROUND the menu: an auth bar, a
130
+ * user chip, branding, a one-off extra link, an alert strip above the routed content.
131
+ *
132
+ * Naming follows the house convention (prefix, component, slot — see `*sparkQueryIcon` in
133
+ * `@mintplayer/ng-spark/grid`): `sparkShell` + region. Every slot also exists as a `TemplateRef`
134
+ * input on `SparkShellComponent` for hosts that cannot use content projection.
135
+ *
136
+ * ```html
137
+ * <spark-shell title="My App">
138
+ * <spark-auth-bar *sparkShellTopbarEnd />
139
+ * <div *sparkShellSidebarTop>
140
+ * <a routerLink="/github-projects" class="nav-link">GitHub projects</a>
141
+ * </div>
142
+ * <router-outlet />
143
+ * </spark-shell>
144
+ * ```
145
+ */
146
+ /** Topbar, leading edge. Default: a `bs-navbar-toggler` mirroring the shell's open state. */
147
+ class SparkShellTopbarStartDirective {
148
+ templateRef = inject(TemplateRef);
149
+ static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "22.1.3", ngImport: i0, type: SparkShellTopbarStartDirective, deps: [], target: i0.ɵɵFactoryTarget.Directive });
150
+ static ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "14.0.0", version: "22.1.3", type: SparkShellTopbarStartDirective, isStandalone: true, selector: "[sparkShellTopbarStart]", ngImport: i0 });
151
+ }
152
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.1.3", ngImport: i0, type: SparkShellTopbarStartDirective, decorators: [{
153
+ type: Directive,
154
+ args: [{ selector: '[sparkShellTopbarStart]' }]
155
+ }] });
156
+ /**
157
+ * Topbar, trailing edge. Default: the language selector (which hides itself when the app has
158
+ * one language). This is where an auth bar goes — the shell cannot ship one itself, since
159
+ * `@mintplayer/ng-spark` does not (and must not) depend on `@mintplayer/ng-spark-auth`.
160
+ */
161
+ class SparkShellTopbarEndDirective {
162
+ templateRef = inject(TemplateRef);
163
+ static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "22.1.3", ngImport: i0, type: SparkShellTopbarEndDirective, deps: [], target: i0.ɵɵFactoryTarget.Directive });
164
+ static ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "14.0.0", version: "22.1.3", type: SparkShellTopbarEndDirective, isStandalone: true, selector: "[sparkShellTopbarEnd]", ngImport: i0 });
165
+ }
166
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.1.3", ngImport: i0, type: SparkShellTopbarEndDirective, decorators: [{
167
+ type: Directive,
168
+ args: [{ selector: '[sparkShellTopbarEnd]' }]
169
+ }] });
170
+ /** Sidebar, above everything. Default: `<h5>{{ title }}</h5>`. */
171
+ class SparkShellSidebarHeaderDirective {
172
+ templateRef = inject(TemplateRef);
173
+ static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "22.1.3", ngImport: i0, type: SparkShellSidebarHeaderDirective, deps: [], target: i0.ɵɵFactoryTarget.Directive });
174
+ static ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "14.0.0", version: "22.1.3", type: SparkShellSidebarHeaderDirective, isStandalone: true, selector: "[sparkShellSidebarHeader]", ngImport: i0 });
175
+ }
176
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.1.3", ngImport: i0, type: SparkShellSidebarHeaderDirective, decorators: [{
177
+ type: Directive,
178
+ args: [{ selector: '[sparkShellSidebarHeader]' }]
179
+ }] });
180
+ /** Sidebar, between the header and the program-units menu. No default. */
181
+ class SparkShellSidebarTopDirective {
182
+ templateRef = inject(TemplateRef);
183
+ static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "22.1.3", ngImport: i0, type: SparkShellSidebarTopDirective, deps: [], target: i0.ɵɵFactoryTarget.Directive });
184
+ static ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "14.0.0", version: "22.1.3", type: SparkShellSidebarTopDirective, isStandalone: true, selector: "[sparkShellSidebarTop]", ngImport: i0 });
185
+ }
186
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.1.3", ngImport: i0, type: SparkShellSidebarTopDirective, decorators: [{
187
+ type: Directive,
188
+ args: [{ selector: '[sparkShellSidebarTop]' }]
189
+ }] });
190
+ /**
191
+ * An extra accordion tab in the sidebar menu, rendered after the generated program-unit groups
192
+ * and sharing their single-open behavior.
193
+ *
194
+ * A tab is contributed as DATA (header + body template), not as markup, and that is load-bearing:
195
+ * `bs-accordion` discovers its tabs with an Angular content query, which matches by declaration
196
+ * view, so a `<bs-accordion-tab>` written in a host's template and inserted into the library's
197
+ * accordion is never registered — it would land at index -1, get no hoisted header and no slot.
198
+ * Declaring a second `<bs-accordion>` instead is what puts the tab in its own exclusivity group:
199
+ * `mp-accordion` enforces single-open per element, over children it owns and over
200
+ * `<details name>`, whose grouping cannot cross a shadow root. So the tab element must be created
201
+ * by the menu itself, from what this directive carries.
202
+ *
203
+ * ```html
204
+ * <ng-container *sparkShellTab="'Component demos'; icon: 'palette'">
205
+ * <a routerLink="/query-slots" routerLinkActive="active" class="nav-link">Query card slots</a>
206
+ * </ng-container>
207
+ * ```
208
+ *
209
+ * Navigation still belongs in `programUnits.json` — this is for pages the model cannot describe
210
+ * (client-side demos, external tools). For sidebar content that is NOT an accordion tab, use
211
+ * `*sparkShellSidebarTop` or `*sparkShellSidebarFooter`.
212
+ */
213
+ class SparkShellTabDirective {
214
+ templateRef = inject(TemplateRef);
215
+ /** The tab's header label. */
216
+ header = input.required({ ...(ngDevMode ? { debugName: "header" } : /* istanbul ignore next */ {}), alias: 'sparkShellTab' });
217
+ /** Bootstrap icon name for the header, as in `programUnits.json`. Defaults to a folder. */
218
+ icon = input(undefined, { ...(ngDevMode ? { debugName: "icon" } : /* istanbul ignore next */ {}), alias: 'sparkShellTabIcon' });
219
+ /** Replaces the icon+label header entirely, for a header that needs its own markup. */
220
+ headerTemplate = input(null, { ...(ngDevMode ? { debugName: "headerTemplate" } : /* istanbul ignore next */ {}), alias: 'sparkShellTabHeader' });
221
+ static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "22.1.3", ngImport: i0, type: SparkShellTabDirective, deps: [], target: i0.ɵɵFactoryTarget.Directive });
222
+ static ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "17.1.0", version: "22.1.3", type: SparkShellTabDirective, isStandalone: true, selector: "[sparkShellTab]", inputs: { header: { classPropertyName: "header", publicName: "sparkShellTab", isSignal: true, isRequired: true, transformFunction: null }, icon: { classPropertyName: "icon", publicName: "sparkShellTabIcon", isSignal: true, isRequired: false, transformFunction: null }, headerTemplate: { classPropertyName: "headerTemplate", publicName: "sparkShellTabHeader", isSignal: true, isRequired: false, transformFunction: null } }, ngImport: i0 });
223
+ }
224
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.1.3", ngImport: i0, type: SparkShellTabDirective, decorators: [{
225
+ type: Directive,
226
+ args: [{ selector: '[sparkShellTab]' }]
227
+ }], propDecorators: { header: [{ type: i0.Input, args: [{ isSignal: true, alias: "sparkShellTab", required: true }] }], icon: [{ type: i0.Input, args: [{ isSignal: true, alias: "sparkShellTabIcon", required: false }] }], headerTemplate: [{ type: i0.Input, args: [{ isSignal: true, alias: "sparkShellTabHeader", required: false }] }] } });
228
+ /** Sidebar, at the very bottom. No default. */
229
+ class SparkShellSidebarFooterDirective {
230
+ templateRef = inject(TemplateRef);
231
+ static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "22.1.3", ngImport: i0, type: SparkShellSidebarFooterDirective, deps: [], target: i0.ɵɵFactoryTarget.Directive });
232
+ static ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "14.0.0", version: "22.1.3", type: SparkShellSidebarFooterDirective, isStandalone: true, selector: "[sparkShellSidebarFooter]", ngImport: i0 });
233
+ }
234
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.1.3", ngImport: i0, type: SparkShellSidebarFooterDirective, decorators: [{
235
+ type: Directive,
236
+ args: [{ selector: '[sparkShellSidebarFooter]' }]
237
+ }] });
238
+ /** Main region, above the projected content (the host's `<router-outlet>`). No default. */
239
+ class SparkShellMainHeaderDirective {
240
+ templateRef = inject(TemplateRef);
241
+ static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "22.1.3", ngImport: i0, type: SparkShellMainHeaderDirective, deps: [], target: i0.ɵɵFactoryTarget.Directive });
242
+ static ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "14.0.0", version: "22.1.3", type: SparkShellMainHeaderDirective, isStandalone: true, selector: "[sparkShellMainHeader]", ngImport: i0 });
243
+ }
244
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.1.3", ngImport: i0, type: SparkShellMainHeaderDirective, decorators: [{
245
+ type: Directive,
246
+ args: [{ selector: '[sparkShellMainHeader]' }]
247
+ }] });
248
+
249
+ /**
250
+ * The application frame: topbar + sidebar + main, wrapping ng-bootstrap's `bs-shell` (whose
251
+ * `mp-shell` web component owns ALL responsive behavior — breakpoints, the overlay drawer,
252
+ * dismiss-on-navigate — in CSS; nothing here re-derives a pixel width). The sidebar renders the
253
+ * server-driven program-units menu; the host projects its `<router-outlet>` as the default
254
+ * content and customizes the chrome through the `*sparkShell*` slots (see `spark-shell-slots.ts`
255
+ * for the doctrine: an omitted slot renders its default, and the menu itself is never a slot).
256
+ *
257
+ * ```html
258
+ * <spark-shell title="My App">
259
+ * <spark-auth-bar *sparkShellTopbarEnd />
260
+ * <router-outlet />
261
+ * </spark-shell>
262
+ * ```
263
+ *
264
+ * The one piece of state the shell keeps is the toggler↔drawer mirror: the built-in hamburger is
265
+ * hidden (`::part(hamburger)`) in favor of a `bs-navbar-toggler` in the topbar, so the shell
266
+ * listens to `statechange` to keep the toggler's icon truthful in `auto` mode and only forces
267
+ * `show`/`hide` on explicit toggles.
268
+ *
269
+ * Theming: the chrome colors are CSS custom properties with the classic dark-sidebar defaults —
270
+ * `--spark-shell-topbar-bg`, `--spark-shell-sidebar-bg`, `--spark-shell-main-bg` — overridable on
271
+ * the `<spark-shell>` element. `sidebarTheme` flips the sidebar's `data-bs-theme` (which is what
272
+ * recolors the accordion internals across the shadow boundary) together with its default palette.
273
+ */
274
+ class SparkShellComponent {
275
+ /** The sidebar heading. Ignored when a `*sparkShellSidebarHeader` slot is supplied. */
276
+ title = input('', /* @ts-ignore */
277
+ ...(ngDevMode ? [{ debugName: "title" }] : /* istanbul ignore next */ []));
278
+ /** Forwarded to `bs-shell`: below it the sidebar is an overlay drawer. */
279
+ breakpoint = input('md', /* @ts-ignore */
280
+ ...(ngDevMode ? [{ debugName: "breakpoint" }] : /* istanbul ignore next */ []));
281
+ /**
282
+ * `data-bs-theme` for the sidebar — what flips the accordion's shadow-DOM internals between
283
+ * palettes — plus the matching default background. `null` sets no theme (inherit the page's).
284
+ */
285
+ sidebarTheme = input('dark', /* @ts-ignore */
286
+ ...(ngDevMode ? [{ debugName: "sidebarTheme" }] : /* istanbul ignore next */ []));
287
+ /** Forwarded to the menu: any changed value re-fetches the program units. */
288
+ reloadToken = input(null, /* @ts-ignore */
289
+ ...(ngDevMode ? [{ debugName: "reloadToken" }] : /* istanbul ignore next */ []));
290
+ /** Extra sidebar tabs as data, for hosts that compute them; `*sparkShellTab` is the usual way. */
291
+ sidebarTabs = input([], /* @ts-ignore */
292
+ ...(ngDevMode ? [{ debugName: "sidebarTabs" }] : /* istanbul ignore next */ []));
293
+ // One TemplateRef input per slot, for hosts that cannot use content projection
294
+ // (the spark-query-card precedent). The projected directive wins when both are present.
295
+ topbarStartTemplate = input(null, /* @ts-ignore */
296
+ ...(ngDevMode ? [{ debugName: "topbarStartTemplate" }] : /* istanbul ignore next */ []));
297
+ topbarEndTemplate = input(null, /* @ts-ignore */
298
+ ...(ngDevMode ? [{ debugName: "topbarEndTemplate" }] : /* istanbul ignore next */ []));
299
+ sidebarHeaderTemplate = input(null, /* @ts-ignore */
300
+ ...(ngDevMode ? [{ debugName: "sidebarHeaderTemplate" }] : /* istanbul ignore next */ []));
301
+ sidebarTopTemplate = input(null, /* @ts-ignore */
302
+ ...(ngDevMode ? [{ debugName: "sidebarTopTemplate" }] : /* istanbul ignore next */ []));
303
+ sidebarFooterTemplate = input(null, /* @ts-ignore */
304
+ ...(ngDevMode ? [{ debugName: "sidebarFooterTemplate" }] : /* istanbul ignore next */ []));
305
+ mainHeaderTemplate = input(null, /* @ts-ignore */
306
+ ...(ngDevMode ? [{ debugName: "mainHeaderTemplate" }] : /* istanbul ignore next */ []));
307
+ topbarStartSlot = contentChild(SparkShellTopbarStartDirective, /* @ts-ignore */
308
+ ...(ngDevMode ? [{ debugName: "topbarStartSlot" }] : /* istanbul ignore next */ []));
309
+ topbarEndSlot = contentChild(SparkShellTopbarEndDirective, /* @ts-ignore */
310
+ ...(ngDevMode ? [{ debugName: "topbarEndSlot" }] : /* istanbul ignore next */ []));
311
+ sidebarHeaderSlot = contentChild(SparkShellSidebarHeaderDirective, /* @ts-ignore */
312
+ ...(ngDevMode ? [{ debugName: "sidebarHeaderSlot" }] : /* istanbul ignore next */ []));
313
+ sidebarTopSlot = contentChild(SparkShellSidebarTopDirective, /* @ts-ignore */
314
+ ...(ngDevMode ? [{ debugName: "sidebarTopSlot" }] : /* istanbul ignore next */ []));
315
+ sidebarFooterSlot = contentChild(SparkShellSidebarFooterDirective, /* @ts-ignore */
316
+ ...(ngDevMode ? [{ debugName: "sidebarFooterSlot" }] : /* istanbul ignore next */ []));
317
+ mainHeaderSlot = contentChild(SparkShellMainHeaderDirective, /* @ts-ignore */
318
+ ...(ngDevMode ? [{ debugName: "mainHeaderSlot" }] : /* istanbul ignore next */ []));
319
+ topbarStartTpl = computed(() => this.topbarStartSlot()?.templateRef ?? this.topbarStartTemplate(), /* @ts-ignore */
320
+ ...(ngDevMode ? [{ debugName: "topbarStartTpl" }] : /* istanbul ignore next */ []));
321
+ topbarEndTpl = computed(() => this.topbarEndSlot()?.templateRef ?? this.topbarEndTemplate(), /* @ts-ignore */
322
+ ...(ngDevMode ? [{ debugName: "topbarEndTpl" }] : /* istanbul ignore next */ []));
323
+ sidebarHeaderTpl = computed(() => this.sidebarHeaderSlot()?.templateRef ?? this.sidebarHeaderTemplate(), /* @ts-ignore */
324
+ ...(ngDevMode ? [{ debugName: "sidebarHeaderTpl" }] : /* istanbul ignore next */ []));
325
+ sidebarTopTpl = computed(() => this.sidebarTopSlot()?.templateRef ?? this.sidebarTopTemplate(), /* @ts-ignore */
326
+ ...(ngDevMode ? [{ debugName: "sidebarTopTpl" }] : /* istanbul ignore next */ []));
327
+ sidebarFooterTpl = computed(() => this.sidebarFooterSlot()?.templateRef ?? this.sidebarFooterTemplate(), /* @ts-ignore */
328
+ ...(ngDevMode ? [{ debugName: "sidebarFooterTpl" }] : /* istanbul ignore next */ []));
329
+ mainHeaderTpl = computed(() => this.mainHeaderSlot()?.templateRef ?? this.mainHeaderTemplate(), /* @ts-ignore */
330
+ ...(ngDevMode ? [{ debugName: "mainHeaderTpl" }] : /* istanbul ignore next */ []));
331
+ /**
332
+ * Extra accordion tabs, forwarded to the menu so IT creates the `<bs-accordion-tab>` elements —
333
+ * the only way they share the generated groups' single-open behavior (see
334
+ * `SparkShellTabDirective`). Data-supplied tabs come first, then projected ones in declaration
335
+ * order.
336
+ */
337
+ tabSlots = contentChildren(SparkShellTabDirective, /* @ts-ignore */
338
+ ...(ngDevMode ? [{ debugName: "tabSlots" }] : /* istanbul ignore next */ []));
339
+ tabs = computed(() => [
340
+ ...this.sidebarTabs(),
341
+ ...this.tabSlots().map(slot => ({
342
+ header: slot.header(),
343
+ icon: slot.icon(),
344
+ headerTemplate: slot.headerTemplate(),
345
+ content: slot.templateRef,
346
+ })),
347
+ ], /* @ts-ignore */
348
+ ...(ngDevMode ? [{ debugName: "tabs" }] : /* istanbul ignore next */ []));
349
+ shellState = signal('auto', /* @ts-ignore */
350
+ ...(ngDevMode ? [{ debugName: "shellState" }] : /* istanbul ignore next */ []));
351
+ isSidebarVisible = signal(false, /* @ts-ignore */
352
+ ...(ngDevMode ? [{ debugName: "isSidebarVisible" }] : /* istanbul ignore next */ []));
353
+ // Explicit toggles force show/hide; 'auto' responsive behavior is otherwise preserved by
354
+ // never writing state on our own. The mirror below keeps the toggler icon truthful when the
355
+ // shell opens/closes itself at the breakpoint.
356
+ toggleSidebar(open) {
357
+ this.shellState.set(open ? 'show' : 'hide');
358
+ }
359
+ onShellToggle(detail) {
360
+ this.isSidebarVisible.set(detail.open);
361
+ }
362
+ static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "22.1.3", ngImport: i0, type: SparkShellComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
363
+ static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "22.1.3", type: SparkShellComponent, isStandalone: true, selector: "spark-shell", inputs: { title: { classPropertyName: "title", publicName: "title", isSignal: true, isRequired: false, transformFunction: null }, breakpoint: { classPropertyName: "breakpoint", publicName: "breakpoint", isSignal: true, isRequired: false, transformFunction: null }, sidebarTheme: { classPropertyName: "sidebarTheme", publicName: "sidebarTheme", isSignal: true, isRequired: false, transformFunction: null }, reloadToken: { classPropertyName: "reloadToken", publicName: "reloadToken", isSignal: true, isRequired: false, transformFunction: null }, sidebarTabs: { classPropertyName: "sidebarTabs", publicName: "sidebarTabs", isSignal: true, isRequired: false, transformFunction: null }, topbarStartTemplate: { classPropertyName: "topbarStartTemplate", publicName: "topbarStartTemplate", isSignal: true, isRequired: false, transformFunction: null }, topbarEndTemplate: { classPropertyName: "topbarEndTemplate", publicName: "topbarEndTemplate", isSignal: true, isRequired: false, transformFunction: null }, sidebarHeaderTemplate: { classPropertyName: "sidebarHeaderTemplate", publicName: "sidebarHeaderTemplate", isSignal: true, isRequired: false, transformFunction: null }, sidebarTopTemplate: { classPropertyName: "sidebarTopTemplate", publicName: "sidebarTopTemplate", isSignal: true, isRequired: false, transformFunction: null }, sidebarFooterTemplate: { classPropertyName: "sidebarFooterTemplate", publicName: "sidebarFooterTemplate", isSignal: true, isRequired: false, transformFunction: null }, mainHeaderTemplate: { classPropertyName: "mainHeaderTemplate", publicName: "mainHeaderTemplate", isSignal: true, isRequired: false, transformFunction: null } }, queries: [{ propertyName: "topbarStartSlot", first: true, predicate: SparkShellTopbarStartDirective, descendants: true, isSignal: true }, { propertyName: "topbarEndSlot", first: true, predicate: SparkShellTopbarEndDirective, descendants: true, isSignal: true }, { propertyName: "sidebarHeaderSlot", first: true, predicate: SparkShellSidebarHeaderDirective, descendants: true, isSignal: true }, { propertyName: "sidebarTopSlot", first: true, predicate: SparkShellSidebarTopDirective, descendants: true, isSignal: true }, { propertyName: "sidebarFooterSlot", first: true, predicate: SparkShellSidebarFooterDirective, descendants: true, isSignal: true }, { propertyName: "mainHeaderSlot", first: true, predicate: SparkShellMainHeaderDirective, descendants: true, isSignal: true }, { propertyName: "tabSlots", predicate: SparkShellTabDirective, isSignal: true }], ngImport: i0, template: "<bs-shell [state]=\"shellState()\" [breakpoint]=\"breakpoint()\" [dismissOnNavigate]=\"true\"\n (statechange)=\"onShellToggle($event)\">\n <div slot=\"topbar\" class=\"spark-topbar w-100 d-flex align-items-center\">\n @if (topbarStartTpl(); as tpl) {\n <ng-container *ngTemplateOutlet=\"tpl\" />\n } @else {\n <bs-navbar-toggler [state]=\"isSidebarVisible()\" (stateChange)=\"toggleSidebar($event)\" />\n }\n <div class=\"ms-auto me-3 d-flex align-items-center gap-2\">\n @if (topbarEndTpl(); as tpl) {\n <ng-container *ngTemplateOutlet=\"tpl\" />\n } @else {\n <spark-language-selector />\n }\n </div>\n </div>\n\n <nav bsShellSidebar class=\"spark-sidebar p-2\"\n [class.spark-sidebar-dark]=\"sidebarTheme() === 'dark'\"\n [attr.data-bs-theme]=\"sidebarTheme()\">\n @if (sidebarHeaderTpl(); as tpl) {\n <ng-container *ngTemplateOutlet=\"tpl\" />\n } @else {\n <h5 class=\"p-3 border-bottom\">{{ title() }}</h5>\n }\n @if (sidebarTopTpl(); as tpl) {\n <ng-container *ngTemplateOutlet=\"tpl\" />\n }\n <spark-program-units [reloadToken]=\"reloadToken()\" [extraTabs]=\"tabs()\" />\n @if (sidebarFooterTpl(); as tpl) {\n <ng-container *ngTemplateOutlet=\"tpl\" />\n }\n </nav>\n\n <main class=\"p-4\">\n @if (mainHeaderTpl(); as tpl) {\n <ng-container *ngTemplateOutlet=\"tpl\" />\n }\n <ng-content />\n </main>\n</bs-shell>\n", styles: [":host{display:flex;flex-direction:column;height:100vh}bs-shell{flex:1 1 auto;min-height:0}.spark-topbar{background-color:var(--spark-shell-topbar-bg, var(--bs-dark, #212529))}::ng-deep spark-shell mp-shell::part(hamburger){display:none}bs-navbar-toggler{--bs-secondary-color: rgba(255, 255, 255, .85)}main{height:100%;background-color:var(--spark-shell-main-bg, #f8f9fa);display:flex;flex-direction:column;overflow:auto}nav.spark-sidebar{min-height:100%;background:var(--spark-shell-sidebar-bg, #f8f9fa)}nav.spark-sidebar.spark-sidebar-dark{background:var(--spark-shell-sidebar-bg, #333);color:#fff}:host ::ng-deep nav.spark-sidebar{--bs-primary-bg-subtle: rgba(255, 255, 255, .1);--bs-border-color: transparent}:host ::ng-deep nav.spark-sidebar mp-accordion::part(content){padding:0}:host ::ng-deep nav.spark-sidebar .nav-link{color:inherit}:host ::ng-deep nav.spark-sidebar .nav-link:hover{background-color:#ffffff1a}:host ::ng-deep nav.spark-sidebar .nav-link.active{background-color:#fff3}\n"], dependencies: [{ kind: "directive", type: NgTemplateOutlet, selector: "[ngTemplateOutlet]", inputs: ["ngTemplateOutletContext", "ngTemplateOutlet", "ngTemplateOutletInjector"] }, { kind: "component", type: BsShellComponent, selector: "bs-shell", inputs: ["state", "breakpoint", "dismissOnNavigate"], outputs: ["statechange"] }, { kind: "directive", type: BsShellSidebarDirective, selector: "[bsShellSidebar]" }, { kind: "component", type: BsNavbarTogglerComponent, selector: "bs-navbar-toggler", inputs: ["state", "toggleOnClick", "ariaLabel", "controls"], outputs: ["stateChange"] }, { kind: "component", type: SparkProgramUnitsComponent, selector: "spark-program-units", inputs: ["reloadToken", "extraTabs"] }, { kind: "component", type: SparkLanguageSelectorComponent, selector: "spark-language-selector" }], changeDetection: i0.ChangeDetectionStrategy.OnPush });
364
+ }
365
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.1.3", ngImport: i0, type: SparkShellComponent, decorators: [{
366
+ type: Component,
367
+ args: [{ selector: 'spark-shell', standalone: true, changeDetection: ChangeDetectionStrategy.OnPush, imports: [
368
+ NgTemplateOutlet,
369
+ BsShellComponent, BsShellSidebarDirective, BsNavbarTogglerComponent,
370
+ SparkProgramUnitsComponent, SparkLanguageSelectorComponent,
371
+ ], template: "<bs-shell [state]=\"shellState()\" [breakpoint]=\"breakpoint()\" [dismissOnNavigate]=\"true\"\n (statechange)=\"onShellToggle($event)\">\n <div slot=\"topbar\" class=\"spark-topbar w-100 d-flex align-items-center\">\n @if (topbarStartTpl(); as tpl) {\n <ng-container *ngTemplateOutlet=\"tpl\" />\n } @else {\n <bs-navbar-toggler [state]=\"isSidebarVisible()\" (stateChange)=\"toggleSidebar($event)\" />\n }\n <div class=\"ms-auto me-3 d-flex align-items-center gap-2\">\n @if (topbarEndTpl(); as tpl) {\n <ng-container *ngTemplateOutlet=\"tpl\" />\n } @else {\n <spark-language-selector />\n }\n </div>\n </div>\n\n <nav bsShellSidebar class=\"spark-sidebar p-2\"\n [class.spark-sidebar-dark]=\"sidebarTheme() === 'dark'\"\n [attr.data-bs-theme]=\"sidebarTheme()\">\n @if (sidebarHeaderTpl(); as tpl) {\n <ng-container *ngTemplateOutlet=\"tpl\" />\n } @else {\n <h5 class=\"p-3 border-bottom\">{{ title() }}</h5>\n }\n @if (sidebarTopTpl(); as tpl) {\n <ng-container *ngTemplateOutlet=\"tpl\" />\n }\n <spark-program-units [reloadToken]=\"reloadToken()\" [extraTabs]=\"tabs()\" />\n @if (sidebarFooterTpl(); as tpl) {\n <ng-container *ngTemplateOutlet=\"tpl\" />\n }\n </nav>\n\n <main class=\"p-4\">\n @if (mainHeaderTpl(); as tpl) {\n <ng-container *ngTemplateOutlet=\"tpl\" />\n }\n <ng-content />\n </main>\n</bs-shell>\n", styles: [":host{display:flex;flex-direction:column;height:100vh}bs-shell{flex:1 1 auto;min-height:0}.spark-topbar{background-color:var(--spark-shell-topbar-bg, var(--bs-dark, #212529))}::ng-deep spark-shell mp-shell::part(hamburger){display:none}bs-navbar-toggler{--bs-secondary-color: rgba(255, 255, 255, .85)}main{height:100%;background-color:var(--spark-shell-main-bg, #f8f9fa);display:flex;flex-direction:column;overflow:auto}nav.spark-sidebar{min-height:100%;background:var(--spark-shell-sidebar-bg, #f8f9fa)}nav.spark-sidebar.spark-sidebar-dark{background:var(--spark-shell-sidebar-bg, #333);color:#fff}:host ::ng-deep nav.spark-sidebar{--bs-primary-bg-subtle: rgba(255, 255, 255, .1);--bs-border-color: transparent}:host ::ng-deep nav.spark-sidebar mp-accordion::part(content){padding:0}:host ::ng-deep nav.spark-sidebar .nav-link{color:inherit}:host ::ng-deep nav.spark-sidebar .nav-link:hover{background-color:#ffffff1a}:host ::ng-deep nav.spark-sidebar .nav-link.active{background-color:#fff3}\n"] }]
372
+ }], propDecorators: { title: [{ type: i0.Input, args: [{ isSignal: true, alias: "title", required: false }] }], breakpoint: [{ type: i0.Input, args: [{ isSignal: true, alias: "breakpoint", required: false }] }], sidebarTheme: [{ type: i0.Input, args: [{ isSignal: true, alias: "sidebarTheme", required: false }] }], reloadToken: [{ type: i0.Input, args: [{ isSignal: true, alias: "reloadToken", required: false }] }], sidebarTabs: [{ type: i0.Input, args: [{ isSignal: true, alias: "sidebarTabs", required: false }] }], topbarStartTemplate: [{ type: i0.Input, args: [{ isSignal: true, alias: "topbarStartTemplate", required: false }] }], topbarEndTemplate: [{ type: i0.Input, args: [{ isSignal: true, alias: "topbarEndTemplate", required: false }] }], sidebarHeaderTemplate: [{ type: i0.Input, args: [{ isSignal: true, alias: "sidebarHeaderTemplate", required: false }] }], sidebarTopTemplate: [{ type: i0.Input, args: [{ isSignal: true, alias: "sidebarTopTemplate", required: false }] }], sidebarFooterTemplate: [{ type: i0.Input, args: [{ isSignal: true, alias: "sidebarFooterTemplate", required: false }] }], mainHeaderTemplate: [{ type: i0.Input, args: [{ isSignal: true, alias: "mainHeaderTemplate", required: false }] }], topbarStartSlot: [{ type: i0.ContentChild, args: [i0.forwardRef(() => SparkShellTopbarStartDirective), { isSignal: true }] }], topbarEndSlot: [{ type: i0.ContentChild, args: [i0.forwardRef(() => SparkShellTopbarEndDirective), { isSignal: true }] }], sidebarHeaderSlot: [{ type: i0.ContentChild, args: [i0.forwardRef(() => SparkShellSidebarHeaderDirective), { isSignal: true }] }], sidebarTopSlot: [{ type: i0.ContentChild, args: [i0.forwardRef(() => SparkShellSidebarTopDirective), { isSignal: true }] }], sidebarFooterSlot: [{ type: i0.ContentChild, args: [i0.forwardRef(() => SparkShellSidebarFooterDirective), { isSignal: true }] }], mainHeaderSlot: [{ type: i0.ContentChild, args: [i0.forwardRef(() => SparkShellMainHeaderDirective), { isSignal: true }] }], tabSlots: [{ type: i0.ContentChildren, args: [i0.forwardRef(() => SparkShellTabDirective), { isSignal: true }] }] } });
373
+
374
+ /**
375
+ * Generated bundle index. Do not edit.
376
+ */
377
+
378
+ export { SparkLanguageSelectorComponent, SparkProgramUnitsComponent, SparkShellComponent, SparkShellMainHeaderDirective, SparkShellSidebarFooterDirective, SparkShellSidebarHeaderDirective, SparkShellSidebarTopDirective, SparkShellTabDirective, SparkShellTopbarEndDirective, SparkShellTopbarStartDirective };
379
+ //# sourceMappingURL=mintplayer-ng-spark-shell.mjs.map