@mintplayer/ng-spark 22.5.0 → 22.8.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (36) hide show
  1. package/fesm2022/mintplayer-ng-spark-client-operations.mjs +12 -12
  2. package/fesm2022/mintplayer-ng-spark-grid.mjs +151 -70
  3. package/fesm2022/mintplayer-ng-spark-grid.mjs.map +1 -1
  4. package/fesm2022/mintplayer-ng-spark-icon.mjs +3 -3
  5. package/fesm2022/mintplayer-ng-spark-models.mjs +77 -7
  6. package/fesm2022/mintplayer-ng-spark-models.mjs.map +1 -1
  7. package/fesm2022/mintplayer-ng-spark-pipes.mjs +167 -74
  8. package/fesm2022/mintplayer-ng-spark-pipes.mjs.map +1 -1
  9. package/fesm2022/mintplayer-ng-spark-po-create.mjs +3 -3
  10. package/fesm2022/mintplayer-ng-spark-po-detail.mjs +5 -5
  11. package/fesm2022/mintplayer-ng-spark-po-detail.mjs.map +1 -1
  12. package/fesm2022/mintplayer-ng-spark-po-edit.mjs +3 -3
  13. package/fesm2022/mintplayer-ng-spark-po-form.mjs +20 -22
  14. package/fesm2022/mintplayer-ng-spark-po-form.mjs.map +1 -1
  15. package/fesm2022/mintplayer-ng-spark-query-list.mjs +23 -9
  16. package/fesm2022/mintplayer-ng-spark-query-list.mjs.map +1 -1
  17. package/fesm2022/mintplayer-ng-spark-renderers.mjs +14 -1
  18. package/fesm2022/mintplayer-ng-spark-renderers.mjs.map +1 -1
  19. package/fesm2022/mintplayer-ng-spark-retry-action-modal.mjs +3 -3
  20. package/fesm2022/mintplayer-ng-spark-services.mjs +107 -20
  21. package/fesm2022/mintplayer-ng-spark-services.mjs.map +1 -1
  22. package/fesm2022/mintplayer-ng-spark-shell.mjs +416 -0
  23. package/fesm2022/mintplayer-ng-spark-shell.mjs.map +1 -0
  24. package/fesm2022/mintplayer-ng-spark.mjs +17 -1
  25. package/fesm2022/mintplayer-ng-spark.mjs.map +1 -1
  26. package/package.json +5 -1
  27. package/types/mintplayer-ng-spark-grid.d.ts +75 -33
  28. package/types/mintplayer-ng-spark-models.d.ts +144 -7
  29. package/types/mintplayer-ng-spark-pipes.d.ts +42 -6
  30. package/types/mintplayer-ng-spark-po-detail.d.ts +2 -2
  31. package/types/mintplayer-ng-spark-po-form.d.ts +7 -7
  32. package/types/mintplayer-ng-spark-query-list.d.ts +11 -4
  33. package/types/mintplayer-ng-spark-renderers.d.ts +29 -11
  34. package/types/mintplayer-ng-spark-services.d.ts +71 -2
  35. package/types/mintplayer-ng-spark-shell.d.ts +272 -0
  36. package/types/mintplayer-ng-spark.d.ts +17 -2
@@ -1,5 +1,5 @@
1
1
  import * as _mintplayer_ng_spark_models from '@mintplayer/ng-spark/models';
2
- import { PersistentObject, CustomActionDefinition } from '@mintplayer/ng-spark/models';
2
+ import { QueryResultItem, CustomActionDefinition, QueryColumn } from '@mintplayer/ng-spark/models';
3
3
  import * as _angular_core from '@angular/core';
4
4
  import { TemplateRef } from '@angular/core';
5
5
  import { Color } from '@mintplayer/ng-bootstrap';
@@ -31,7 +31,12 @@ declare class SparkQueryListComponent {
31
31
  protected readonly lang: SparkLanguageService;
32
32
  extraActionsTemplate: _angular_core.InputSignal<TemplateRef<void> | null>;
33
33
  showCustomActions: _angular_core.InputSignal<boolean>;
34
- rowClicked: _angular_core.OutputEmitterRef<PersistentObject>;
34
+ /**
35
+ * Forwarded to the grid, so a query PAGE can replace its row links — the same reason the card
36
+ * forwards it. Without this the escape hatch existed only for a directly-embedded grid.
37
+ */
38
+ rowRoute: _angular_core.InputSignal<((row: QueryResultItem) => unknown[] | null) | null>;
39
+ rowClicked: _angular_core.OutputEmitterRef<QueryResultItem>;
35
40
  createClicked: _angular_core.OutputEmitterRef<void>;
36
41
  customActionExecuted: _angular_core.OutputEmitterRef<{
37
42
  action: CustomActionDefinition;
@@ -59,6 +64,8 @@ declare class SparkQueryListComponent {
59
64
  protected isActionEnabled(action: CustomActionDefinition): boolean;
60
65
  isStreaming: _angular_core.WritableSignal<boolean>;
61
66
  private streamingSub;
67
+ /** Columns as sent with the stream's snapshot; empty until it arrives. */
68
+ protected readonly streamColumns: _angular_core.WritableSignal<QueryColumn[]>;
62
69
  private readonly allItems;
63
70
  private readonly streamItems;
64
71
  /**
@@ -67,7 +74,7 @@ declare class SparkQueryListComponent {
67
74
  * Null for a normal query — an empty array would read as "here are no rows" and suppress the
68
75
  * fetch entirely.
69
76
  */
70
- protected readonly gridData: _angular_core.Signal<PersistentObject[] | null>;
77
+ protected readonly gridData: _angular_core.Signal<QueryResultItem[] | null>;
71
78
  constructor();
72
79
  private onParamsChange;
73
80
  /**
@@ -84,7 +91,7 @@ declare class SparkQueryListComponent {
84
91
  private handleStreamingMessage;
85
92
  private applyFilter;
86
93
  static ɵfac: _angular_core.ɵɵFactoryDeclaration<SparkQueryListComponent, never>;
87
- static ɵcmp: _angular_core.ɵɵComponentDeclaration<SparkQueryListComponent, "spark-query-list", never, { "extraActionsTemplate": { "alias": "extraActionsTemplate"; "required": false; "isSignal": true; }; "showCustomActions": { "alias": "showCustomActions"; "required": false; "isSignal": true; }; }, { "rowClicked": "rowClicked"; "createClicked": "createClicked"; "customActionExecuted": "customActionExecuted"; }, never, never, true, never>;
94
+ static ɵcmp: _angular_core.ɵɵComponentDeclaration<SparkQueryListComponent, "spark-query-list", never, { "extraActionsTemplate": { "alias": "extraActionsTemplate"; "required": false; "isSignal": true; }; "showCustomActions": { "alias": "showCustomActions"; "required": false; "isSignal": true; }; "rowRoute": { "alias": "rowRoute"; "required": false; "isSignal": true; }; }, { "rowClicked": "rowClicked"; "createClicked": "createClicked"; "customActionExecuted": "customActionExecuted"; }, never, never, true, never>;
88
95
  }
89
96
 
90
97
  export { SparkQueryListComponent };
@@ -1,5 +1,5 @@
1
1
  import { Type, InputSignal, InjectionToken, Provider } from '@angular/core';
2
- import { PersistentObjectAttribute, EntityAttributeDefinition, PersistentObject } from '@mintplayer/ng-spark/models';
2
+ import { QueryResultItemValue, PersistentObjectAttribute, SparkCellColumn, QueryResultItem, EntityAttributeDefinition, PersistentObject } from '@mintplayer/ng-spark/models';
3
3
 
4
4
  /**
5
5
  * Drops entries the component doesn't declare, so every contract member is
@@ -10,8 +10,19 @@ declare function withDeclaredInputs(component: Type<any>, inputs: Record<string,
10
10
  * The renderer-facing value of an attribute: the flat value, or for AsDetail
11
11
  * attributes (whose flat value the server nulls on purpose) the nested
12
12
  * PersistentObject (single) / PersistentObject[] (array).
13
+ *
14
+ * Used by the detail and edit paths, which still work in attributes.
13
15
  */
14
16
  declare function rendererValue(attr: PersistentObjectAttribute | undefined): any;
17
+ /**
18
+ * The renderer-facing value of a query-result cell.
19
+ *
20
+ * A grid row carries no nested objects to fall back to — a projection is flat by construction —
21
+ * so this is deliberately not the same function as {@link rendererValue}. Keeping them separate
22
+ * is what stops a renderer silently receiving `undefined` because it was written against the
23
+ * attribute shape.
24
+ */
25
+ declare function cellValue(value: QueryResultItemValue | undefined): any;
15
26
 
16
27
  /**
17
28
  * Contract for detail-page renderers (spark-po-detail).
@@ -38,21 +49,28 @@ interface SparkAttributeDetailRenderer {
38
49
  */
39
50
  interface SparkAttributeColumnRenderer {
40
51
  /**
41
- * The current attribute value. For an AsDetail attribute this is the nested
42
- * PersistentObject (single) / PersistentObject[] (array) in query-list and
43
- * sub-query grids, and the flattened value in AsDetail sub-table cells.
52
+ * The cell value. For an AsDetail column this is the nested PersistentObject (single) /
53
+ * PersistentObject[] (array) in an AsDetail sub-table, and the projected value in a query grid.
44
54
  */
45
55
  value?: InputSignal<any>;
46
- /** The attribute definition metadata */
47
- attribute?: InputSignal<EntityAttributeDefinition | undefined>;
56
+ /**
57
+ * The column being rendered.
58
+ *
59
+ * A query grid supplies a {@link SparkCellColumn} from the result own column metadata; an
60
+ * AsDetail sub-table supplies its attribute definition, which satisfies the same shape. This
61
+ * replaced an `attribute` input typed as the definition: a query result no longer carries
62
+ * attribute metadata per row, so naming it `attribute` would promise something the grid cannot
63
+ * deliver.
64
+ */
65
+ column?: InputSignal<SparkCellColumn | undefined>;
48
66
  /** Renderer-specific options from rendererOptions */
49
67
  options?: InputSignal<Record<string, any> | undefined>;
50
68
  /**
51
- * The row this cell belongs to: a PersistentObject in query-list/sub-query
52
- * grids, a plain record (possibly including the reserved '__sparkBreadcrumbs'
53
- * key) in AsDetail sub-tables. Passed only when declared.
69
+ * The row this cell belongs to: a {@link QueryResultItem} in a query grid, a plain record
70
+ * (possibly including the reserved '__sparkBreadcrumbs' key) in AsDetail sub-tables. Passed
71
+ * only when declared.
54
72
  */
55
- item?: InputSignal<PersistentObject | Record<string, any> | undefined>;
73
+ item?: InputSignal<QueryResultItem | Record<string, any> | undefined>;
56
74
  }
57
75
  /**
58
76
  * Contract for edit-form renderers (spark-po-form on create/edit pages).
@@ -94,5 +112,5 @@ declare const SPARK_ATTRIBUTE_RENDERERS: InjectionToken<SparkAttributeRendererRe
94
112
  */
95
113
  declare function provideSparkAttributeRenderers(renderers: SparkAttributeRendererRegistration[]): Provider;
96
114
 
97
- export { SPARK_ATTRIBUTE_RENDERERS, provideSparkAttributeRenderers, rendererValue, withDeclaredInputs };
115
+ export { SPARK_ATTRIBUTE_RENDERERS, cellValue, provideSparkAttributeRenderers, rendererValue, withDeclaredInputs };
98
116
  export type { SparkAttributeColumnRenderer, SparkAttributeDetailRenderer, SparkAttributeEditRenderer, SparkAttributeRendererRegistration };
@@ -83,7 +83,20 @@ declare class SparkService {
83
83
  refresh(type: string, data: Partial<PersistentObject>, triggeredBy: string): Promise<PersistentObject>;
84
84
  delete(type: string, id: string): Promise<void>;
85
85
  getCustomActions(objectTypeId: string): Promise<CustomActionDefinition[]>;
86
- executeCustomAction(objectTypeId: string, actionName: string, parent?: PersistentObject, selectedItems?: PersistentObject[]): Promise<void>;
86
+ /**
87
+ * @param parent The object of THIS type the action is operating on — the detail-page invocation.
88
+ * @param selectedItemIds Row ids from a query. Ids, never row objects: a row is a projection.
89
+ * @param queryParent When invoked from a sub-query, the object whose detail page it was rendered
90
+ * on — a DIFFERENT type (the cars listed on a company's page are Cars, the page is a Company).
91
+ * Sent as id + type, exactly as the query endpoint names it, and resolved server-side under its
92
+ * own type with its own Read gate.
93
+ * @param queryId The query the selection came from, so the server can re-run it narrowed to those
94
+ * ids and hand the action the rows the grid actually had -- index-computed columns included.
95
+ */
96
+ executeCustomAction(objectTypeId: string, actionName: string, parent?: PersistentObject, selectedItemIds?: string[], queryParent?: {
97
+ id: string;
98
+ type: string;
99
+ }, queryId?: string): Promise<void>;
87
100
  getLookupReferences(): Promise<LookupReferenceListItem[]>;
88
101
  getLookupReference(name: string): Promise<LookupReference>;
89
102
  addLookupReferenceValue(name: string, value: LookupReferenceValue): Promise<LookupReferenceValue>;
@@ -133,4 +146,60 @@ declare class SparkIconRegistry {
133
146
  static ɵprov: i0.ɵɵInjectableDeclaration<SparkIconRegistry>;
134
147
  }
135
148
 
136
- export { RetryActionService, SparkIconRegistry, SparkLanguageService, SparkService, SparkStreamingService };
149
+ /**
150
+ * A query's custom actions, reachable **without the grid that usually renders them**.
151
+ *
152
+ * ## Why this exists
153
+ *
154
+ * A query's actions were only ever obtainable by rendering `<spark-query-grid>`, which loads the
155
+ * query, resolves its entity type, fetches the actions and filters them to the ones marked for a
156
+ * query surface — all privately. A page that wanted the same buttons somewhere else (a toolbar
157
+ * above the card, the shell's topbar) had three bad options: duplicate the four-step resolution
158
+ * and let it drift, reach into the grid's internals, or put the button in the wrong place.
159
+ *
160
+ * This exposes the resolution itself. The grid keeps rendering the default placement; a host that
161
+ * wants a different one asks here and renders its own control.
162
+ *
163
+ * ## What it does not do
164
+ *
165
+ * It does not authorize. `/spark/actions/{type}` returns only the actions this caller may see —
166
+ * the server filters against `security.json`, and executing re-checks — so nothing here is a gate,
167
+ * and a host must not treat "the list came back empty" as anything other than a display fact.
168
+ *
169
+ * It also does not cache. Actions depend on the caller, and a memo keyed by type id would survive
170
+ * a sign-out.
171
+ */
172
+ declare class SparkQueryActionsService {
173
+ private readonly sparkService;
174
+ /**
175
+ * The custom actions of the query named by id or alias, already filtered to those that belong on
176
+ * a query surface.
177
+ *
178
+ * Returns an empty list — rather than throwing — when the query resolves to no entity type,
179
+ * because a caller rendering a toolbar wants "no buttons", not a broken page.
180
+ */
181
+ actionsFor(queryIdOrAlias: string): Promise<CustomActionDefinition[]>;
182
+ /**
183
+ * Runs one of those actions. `selectedItemIds` are row ids, exactly as the grid posts them —
184
+ * the server re-materializes each one through the same load path a detail page uses, so an id
185
+ * from anywhere is treated as caller input rather than as a verified row.
186
+ */
187
+ execute(queryIdOrAlias: string, actionName: string, options?: {
188
+ parent?: PersistentObject;
189
+ selectedItemIds?: string[];
190
+ /** For a sub-query: the object whose detail page it was rendered on. See SparkService. */
191
+ queryParent?: {
192
+ id: string;
193
+ type: string;
194
+ };
195
+ }): Promise<void>;
196
+ /**
197
+ * The query and the entity type its rows are mapped against — the two-step resolution both
198
+ * methods need, kept in one place so they cannot disagree about which type an action runs on.
199
+ */
200
+ private contextFor;
201
+ static ɵfac: i0.ɵɵFactoryDeclaration<SparkQueryActionsService, never>;
202
+ static ɵprov: i0.ɵɵInjectableDeclaration<SparkQueryActionsService>;
203
+ }
204
+
205
+ export { RetryActionService, SparkIconRegistry, SparkLanguageService, SparkQueryActionsService, SparkService, SparkStreamingService };
@@ -0,0 +1,272 @@
1
+ import * as _angular_core from '@angular/core';
2
+ import { TemplateRef } from '@angular/core';
3
+ import { BsShellState } from '@mintplayer/ng-bootstrap/shell';
4
+ import { Breakpoint } from '@mintplayer/ng-bootstrap';
5
+ import { ShellStateChangeEventDetail } from '@mintplayer/web-components/shell';
6
+ import { ProgramUnitGroup } from '@mintplayer/ng-spark/models';
7
+ import { SparkLanguageService } from '@mintplayer/ng-spark/services';
8
+
9
+ /**
10
+ * Region slots for `<spark-shell>`.
11
+ *
12
+ * Each directive marks a template that REPLACES one region of the shell chrome (or fills an
13
+ * empty one). An omitted slot is not an empty slot: the shell renders its default — the toggler,
14
+ * the language selector, the title heading — so a host that supplies nothing still gets a
15
+ * complete working shell, and a host that supplies one slot leaves the rest alone.
16
+ *
17
+ * The menu itself is deliberately NOT a slot. Navigation is sourced entirely from
18
+ * `programUnits.json` through the rights-filtered `/spark/program-units` endpoint and re-fetched
19
+ * on sign-in/out; a host that finds itself writing unit anchors in a slot should be adding units
20
+ * to `programUnits.json` instead. Slots exist for the content AROUND the menu: an auth bar, a
21
+ * user chip, branding, a one-off extra link, an alert strip above the routed content.
22
+ *
23
+ * Naming follows the house convention (prefix, component, slot — see `*sparkQueryIcon` in
24
+ * `@mintplayer/ng-spark/grid`): `sparkShell` + region. Every slot also exists as a `TemplateRef`
25
+ * input on `SparkShellComponent` for hosts that cannot use content projection.
26
+ *
27
+ * ```html
28
+ * <spark-shell title="My App">
29
+ * <spark-auth-bar *sparkShellTopbarEnd />
30
+ * <div *sparkShellSidebarTop>
31
+ * <a routerLink="/github-projects" class="nav-link">GitHub projects</a>
32
+ * </div>
33
+ * <router-outlet />
34
+ * </spark-shell>
35
+ * ```
36
+ */
37
+ /** Topbar, leading edge. Default: a `bs-navbar-toggler` mirroring the shell's open state. */
38
+ declare class SparkShellTopbarStartDirective {
39
+ readonly templateRef: TemplateRef<unknown>;
40
+ static ɵfac: _angular_core.ɵɵFactoryDeclaration<SparkShellTopbarStartDirective, never>;
41
+ static ɵdir: _angular_core.ɵɵDirectiveDeclaration<SparkShellTopbarStartDirective, "[sparkShellTopbarStart]", never, {}, {}, never, never, true, never>;
42
+ }
43
+ /**
44
+ * Topbar, trailing edge. Default: the language selector (which hides itself when the app has
45
+ * one language). This is where an auth bar goes — the shell cannot ship one itself, since
46
+ * `@mintplayer/ng-spark` does not (and must not) depend on `@mintplayer/ng-spark-auth`.
47
+ */
48
+ declare class SparkShellTopbarEndDirective {
49
+ readonly templateRef: TemplateRef<unknown>;
50
+ static ɵfac: _angular_core.ɵɵFactoryDeclaration<SparkShellTopbarEndDirective, never>;
51
+ static ɵdir: _angular_core.ɵɵDirectiveDeclaration<SparkShellTopbarEndDirective, "[sparkShellTopbarEnd]", never, {}, {}, never, never, true, never>;
52
+ }
53
+ /**
54
+ * Topbar, trailing edge, **beside** the default chrome rather than instead of it — rendered before
55
+ * the language selector, which stays.
56
+ *
57
+ * ## Why this is not just `*sparkShellTopbarEnd`
58
+ *
59
+ * That slot REPLACES the region, which is right for an auth bar (a host taking over the trailing
60
+ * edge wholesale) and wrong for a page-level action button. A host that only wanted to add a
61
+ * button had to re-render the language selector itself to keep it — which means importing it,
62
+ * knowing it hides itself in a single-language app, and keeping that copy in step with the shell.
63
+ * Every host that did this got it slightly differently.
64
+ *
65
+ * Pairs with `SparkQueryActionsService`: that service resolves a query's custom actions without the
66
+ * grid, and this is where a page-level one goes.
67
+ *
68
+ * ```html
69
+ * <button *sparkShellTopbarActions class="btn btn-primary" (click)="publish()">Publish</button>
70
+ * ```
71
+ *
72
+ * Supplying both slots is allowed and does what it says: `topbarEnd` replaces the default chrome,
73
+ * and these actions still render ahead of whatever it put there.
74
+ */
75
+ declare class SparkShellTopbarActionsDirective {
76
+ readonly templateRef: TemplateRef<unknown>;
77
+ static ɵfac: _angular_core.ɵɵFactoryDeclaration<SparkShellTopbarActionsDirective, never>;
78
+ static ɵdir: _angular_core.ɵɵDirectiveDeclaration<SparkShellTopbarActionsDirective, "[sparkShellTopbarActions]", never, {}, {}, never, never, true, never>;
79
+ }
80
+ /** Sidebar, above everything. Default: `<h5>{{ title }}</h5>`. */
81
+ declare class SparkShellSidebarHeaderDirective {
82
+ readonly templateRef: TemplateRef<unknown>;
83
+ static ɵfac: _angular_core.ɵɵFactoryDeclaration<SparkShellSidebarHeaderDirective, never>;
84
+ static ɵdir: _angular_core.ɵɵDirectiveDeclaration<SparkShellSidebarHeaderDirective, "[sparkShellSidebarHeader]", never, {}, {}, never, never, true, never>;
85
+ }
86
+ /** Sidebar, between the header and the program-units menu. No default. */
87
+ declare class SparkShellSidebarTopDirective {
88
+ readonly templateRef: TemplateRef<unknown>;
89
+ static ɵfac: _angular_core.ɵɵFactoryDeclaration<SparkShellSidebarTopDirective, never>;
90
+ static ɵdir: _angular_core.ɵɵDirectiveDeclaration<SparkShellSidebarTopDirective, "[sparkShellSidebarTop]", never, {}, {}, never, never, true, never>;
91
+ }
92
+ /**
93
+ * An extra accordion tab in the sidebar menu, rendered after the generated program-unit groups
94
+ * and sharing their single-open behavior.
95
+ *
96
+ * A tab is contributed as DATA (header + body template), not as markup, and that is load-bearing:
97
+ * `bs-accordion` discovers its tabs with an Angular content query, which matches by declaration
98
+ * view, so a `<bs-accordion-tab>` written in a host's template and inserted into the library's
99
+ * accordion is never registered — it would land at index -1, get no hoisted header and no slot.
100
+ * Declaring a second `<bs-accordion>` instead is what puts the tab in its own exclusivity group:
101
+ * `mp-accordion` enforces single-open per element, over children it owns and over
102
+ * `<details name>`, whose grouping cannot cross a shadow root. So the tab element must be created
103
+ * by the menu itself, from what this directive carries.
104
+ *
105
+ * ```html
106
+ * <ng-container *sparkShellTab="'Component demos'; icon: 'palette'">
107
+ * <a routerLink="/query-slots" routerLinkActive="active" class="nav-link">Query card slots</a>
108
+ * </ng-container>
109
+ * ```
110
+ *
111
+ * Navigation still belongs in `programUnits.json` — this is for pages the model cannot describe
112
+ * (client-side demos, external tools). For sidebar content that is NOT an accordion tab, use
113
+ * `*sparkShellSidebarTop` or `*sparkShellSidebarFooter`.
114
+ */
115
+ declare class SparkShellTabDirective {
116
+ readonly templateRef: TemplateRef<unknown>;
117
+ /** The tab's header label. */
118
+ readonly header: _angular_core.InputSignal<string>;
119
+ /** Bootstrap icon name for the header, as in `programUnits.json`. Defaults to a folder. */
120
+ readonly icon: _angular_core.InputSignal<string | undefined>;
121
+ /** Replaces the icon+label header entirely, for a header that needs its own markup. */
122
+ readonly headerTemplate: _angular_core.InputSignal<TemplateRef<unknown> | null>;
123
+ static ɵfac: _angular_core.ɵɵFactoryDeclaration<SparkShellTabDirective, never>;
124
+ static ɵdir: _angular_core.ɵɵDirectiveDeclaration<SparkShellTabDirective, "[sparkShellTab]", never, { "header": { "alias": "sparkShellTab"; "required": true; "isSignal": true; }; "icon": { "alias": "sparkShellTabIcon"; "required": false; "isSignal": true; }; "headerTemplate": { "alias": "sparkShellTabHeader"; "required": false; "isSignal": true; }; }, {}, never, never, true, never>;
125
+ }
126
+ /**
127
+ * A sidebar accordion tab in the shape the menu renders it. Hosts normally contribute tabs with
128
+ * `*sparkShellTab`; this is the same thing as data, for a host that computes its tabs.
129
+ */
130
+ interface SparkSidebarTab {
131
+ readonly header: string;
132
+ readonly icon?: string;
133
+ readonly headerTemplate?: TemplateRef<unknown> | null;
134
+ readonly content: TemplateRef<unknown>;
135
+ }
136
+ /** Sidebar, at the very bottom. No default. */
137
+ declare class SparkShellSidebarFooterDirective {
138
+ readonly templateRef: TemplateRef<unknown>;
139
+ static ɵfac: _angular_core.ɵɵFactoryDeclaration<SparkShellSidebarFooterDirective, never>;
140
+ static ɵdir: _angular_core.ɵɵDirectiveDeclaration<SparkShellSidebarFooterDirective, "[sparkShellSidebarFooter]", never, {}, {}, never, never, true, never>;
141
+ }
142
+ /** Main region, above the projected content (the host's `<router-outlet>`). No default. */
143
+ declare class SparkShellMainHeaderDirective {
144
+ readonly templateRef: TemplateRef<unknown>;
145
+ static ɵfac: _angular_core.ɵɵFactoryDeclaration<SparkShellMainHeaderDirective, never>;
146
+ static ɵdir: _angular_core.ɵɵDirectiveDeclaration<SparkShellMainHeaderDirective, "[sparkShellMainHeader]", never, {}, {}, never, never, true, never>;
147
+ }
148
+
149
+ /**
150
+ * The application frame: topbar + sidebar + main, wrapping ng-bootstrap's `bs-shell` (whose
151
+ * `mp-shell` web component owns ALL responsive behavior — breakpoints, the overlay drawer,
152
+ * dismiss-on-navigate — in CSS; nothing here re-derives a pixel width). The sidebar renders the
153
+ * server-driven program-units menu; the host projects its `<router-outlet>` as the default
154
+ * content and customizes the chrome through the `*sparkShell*` slots (see `spark-shell-slots.ts`
155
+ * for the doctrine: an omitted slot renders its default, and the menu itself is never a slot).
156
+ *
157
+ * ```html
158
+ * <spark-shell title="My App">
159
+ * <spark-auth-bar *sparkShellTopbarEnd />
160
+ * <router-outlet />
161
+ * </spark-shell>
162
+ * ```
163
+ *
164
+ * The one piece of state the shell keeps is the toggler↔drawer mirror: the built-in hamburger is
165
+ * hidden (`::part(hamburger)`) in favor of a `bs-navbar-toggler` in the topbar, so the shell
166
+ * listens to `statechange` to keep the toggler's icon truthful in `auto` mode and only forces
167
+ * `show`/`hide` on explicit toggles.
168
+ *
169
+ * Theming: the chrome colors are CSS custom properties with the classic dark-sidebar defaults —
170
+ * `--spark-shell-topbar-bg`, `--spark-shell-sidebar-bg`, `--spark-shell-main-bg` — overridable on
171
+ * the `<spark-shell>` element. `sidebarTheme` flips the sidebar's `data-bs-theme` (which is what
172
+ * recolors the accordion internals across the shadow boundary) together with its default palette.
173
+ */
174
+ declare class SparkShellComponent {
175
+ /** The sidebar heading. Ignored when a `*sparkShellSidebarHeader` slot is supplied. */
176
+ readonly title: _angular_core.InputSignal<string>;
177
+ /** Forwarded to `bs-shell`: below it the sidebar is an overlay drawer. */
178
+ readonly breakpoint: _angular_core.InputSignal<Breakpoint>;
179
+ /**
180
+ * `data-bs-theme` for the sidebar — what flips the accordion's shadow-DOM internals between
181
+ * palettes — plus the matching default background. `null` sets no theme (inherit the page's).
182
+ */
183
+ readonly sidebarTheme: _angular_core.InputSignal<"dark" | "light" | null>;
184
+ /** Forwarded to the menu: any changed value re-fetches the program units. */
185
+ readonly reloadToken: _angular_core.InputSignal<unknown>;
186
+ /** Extra sidebar tabs as data, for hosts that compute them; `*sparkShellTab` is the usual way. */
187
+ readonly sidebarTabs: _angular_core.InputSignal<readonly SparkSidebarTab[]>;
188
+ readonly topbarStartTemplate: _angular_core.InputSignal<TemplateRef<unknown> | null>;
189
+ readonly topbarEndTemplate: _angular_core.InputSignal<TemplateRef<unknown> | null>;
190
+ readonly topbarActionsTemplate: _angular_core.InputSignal<TemplateRef<unknown> | null>;
191
+ readonly sidebarHeaderTemplate: _angular_core.InputSignal<TemplateRef<unknown> | null>;
192
+ readonly sidebarTopTemplate: _angular_core.InputSignal<TemplateRef<unknown> | null>;
193
+ readonly sidebarFooterTemplate: _angular_core.InputSignal<TemplateRef<unknown> | null>;
194
+ readonly mainHeaderTemplate: _angular_core.InputSignal<TemplateRef<unknown> | null>;
195
+ private readonly topbarStartSlot;
196
+ private readonly topbarEndSlot;
197
+ private readonly topbarActionsSlot;
198
+ private readonly sidebarHeaderSlot;
199
+ private readonly sidebarTopSlot;
200
+ private readonly sidebarFooterSlot;
201
+ private readonly mainHeaderSlot;
202
+ protected readonly topbarStartTpl: _angular_core.Signal<TemplateRef<unknown> | null>;
203
+ protected readonly topbarEndTpl: _angular_core.Signal<TemplateRef<unknown> | null>;
204
+ protected readonly topbarActionsTpl: _angular_core.Signal<TemplateRef<unknown> | null>;
205
+ protected readonly sidebarHeaderTpl: _angular_core.Signal<TemplateRef<unknown> | null>;
206
+ protected readonly sidebarTopTpl: _angular_core.Signal<TemplateRef<unknown> | null>;
207
+ protected readonly sidebarFooterTpl: _angular_core.Signal<TemplateRef<unknown> | null>;
208
+ protected readonly mainHeaderTpl: _angular_core.Signal<TemplateRef<unknown> | null>;
209
+ /**
210
+ * Extra accordion tabs, forwarded to the menu so IT creates the `<bs-accordion-tab>` elements —
211
+ * the only way they share the generated groups' single-open behavior (see
212
+ * `SparkShellTabDirective`). Data-supplied tabs come first, then projected ones in declaration
213
+ * order.
214
+ */
215
+ private readonly tabSlots;
216
+ protected readonly tabs: _angular_core.Signal<readonly SparkSidebarTab[]>;
217
+ protected readonly shellState: _angular_core.WritableSignal<BsShellState>;
218
+ protected readonly isSidebarVisible: _angular_core.WritableSignal<boolean>;
219
+ protected toggleSidebar(open: boolean): void;
220
+ protected onShellToggle(detail: ShellStateChangeEventDetail): void;
221
+ static ɵfac: _angular_core.ɵɵFactoryDeclaration<SparkShellComponent, never>;
222
+ static ɵcmp: _angular_core.ɵɵComponentDeclaration<SparkShellComponent, "spark-shell", never, { "title": { "alias": "title"; "required": false; "isSignal": true; }; "breakpoint": { "alias": "breakpoint"; "required": false; "isSignal": true; }; "sidebarTheme": { "alias": "sidebarTheme"; "required": false; "isSignal": true; }; "reloadToken": { "alias": "reloadToken"; "required": false; "isSignal": true; }; "sidebarTabs": { "alias": "sidebarTabs"; "required": false; "isSignal": true; }; "topbarStartTemplate": { "alias": "topbarStartTemplate"; "required": false; "isSignal": true; }; "topbarEndTemplate": { "alias": "topbarEndTemplate"; "required": false; "isSignal": true; }; "topbarActionsTemplate": { "alias": "topbarActionsTemplate"; "required": false; "isSignal": true; }; "sidebarHeaderTemplate": { "alias": "sidebarHeaderTemplate"; "required": false; "isSignal": true; }; "sidebarTopTemplate": { "alias": "sidebarTopTemplate"; "required": false; "isSignal": true; }; "sidebarFooterTemplate": { "alias": "sidebarFooterTemplate"; "required": false; "isSignal": true; }; "mainHeaderTemplate": { "alias": "mainHeaderTemplate"; "required": false; "isSignal": true; }; }, {}, ["topbarStartSlot", "topbarEndSlot", "topbarActionsSlot", "sidebarHeaderSlot", "sidebarTopSlot", "sidebarFooterSlot", "mainHeaderSlot", "tabSlots"], ["*"], true, never>;
223
+ }
224
+
225
+ /**
226
+ * The server-driven navigation menu: an accordion of program-unit groups fetched from
227
+ * `GET /spark/program-units`, which the server has already filtered to what the caller's rights
228
+ * allow. Hosts write ZERO router links for navigation — every group, unit, icon, label and link
229
+ * comes from `programUnits.json`; content around the menu belongs in `<spark-shell>`'s slots,
230
+ * and a host tempted to hand-write a unit anchor should add a unit to `programUnits.json`
231
+ * instead.
232
+ *
233
+ * Because the response is caller-scoped it must be re-fetched when the caller changes: the
234
+ * component tracks the optional `SPARK_AUTH_STATE` signal (supplied by ng-spark-auth's
235
+ * `provideSparkAuth()`, or by the app's own auth stack) and reloads on every change. Without a
236
+ * provider it fetches once. `reloadToken` is the manual escape hatch (any changed value triggers
237
+ * a reload), and `reload()` the imperative one.
238
+ *
239
+ * Usually rendered by `<spark-shell>`; exported standalone for hosts that own their own layout.
240
+ */
241
+ declare class SparkProgramUnitsComponent {
242
+ private readonly sparkService;
243
+ private readonly authState;
244
+ /** Any changed value triggers a reload — for apps whose auth state isn't a provided signal. */
245
+ readonly reloadToken: _angular_core.InputSignal<unknown>;
246
+ /**
247
+ * Extra tabs to render after the generated groups, normally forwarded by `<spark-shell>` from
248
+ * its `*sparkShellTab` directives. They must be rendered by THIS template — see
249
+ * `SparkShellTabDirective` for why a host-declared `<bs-accordion-tab>` cannot work.
250
+ */
251
+ readonly extraTabs: _angular_core.InputSignal<readonly SparkSidebarTab[]>;
252
+ protected readonly groups: _angular_core.WritableSignal<ProgramUnitGroup[]>;
253
+ constructor();
254
+ /** Re-fetches the menu. The response is already rights-filtered per caller. */
255
+ reload(): Promise<void>;
256
+ static ɵfac: _angular_core.ɵɵFactoryDeclaration<SparkProgramUnitsComponent, never>;
257
+ static ɵcmp: _angular_core.ɵɵComponentDeclaration<SparkProgramUnitsComponent, "spark-program-units", never, { "reloadToken": { "alias": "reloadToken"; "required": false; "isSignal": true; }; "extraTabs": { "alias": "extraTabs"; "required": false; "isSignal": true; }; }, {}, never, never, true, never>;
258
+ }
259
+
260
+ /**
261
+ * The culture switcher: a `bs-select` over `SparkLanguageService`'s languages, persisting the
262
+ * choice. Renders nothing when the app declares one language (or none), so hosts can include it
263
+ * unconditionally — `<spark-shell>`'s topbar does exactly that as its trailing default.
264
+ */
265
+ declare class SparkLanguageSelectorComponent {
266
+ protected readonly lang: SparkLanguageService;
267
+ static ɵfac: _angular_core.ɵɵFactoryDeclaration<SparkLanguageSelectorComponent, never>;
268
+ static ɵcmp: _angular_core.ɵɵComponentDeclaration<SparkLanguageSelectorComponent, "spark-language-selector", never, {}, {}, never, never, true, never>;
269
+ }
270
+
271
+ export { SparkLanguageSelectorComponent, SparkProgramUnitsComponent, SparkShellComponent, SparkShellMainHeaderDirective, SparkShellSidebarFooterDirective, SparkShellSidebarHeaderDirective, SparkShellSidebarTopDirective, SparkShellTabDirective, SparkShellTopbarActionsDirective, SparkShellTopbarEndDirective, SparkShellTopbarStartDirective };
272
+ export type { SparkSidebarTab };
@@ -1,4 +1,4 @@
1
- import { InjectionToken, Provider } from '@angular/core';
1
+ import { InjectionToken, Signal, Provider } from '@angular/core';
2
2
 
3
3
  interface SparkConfig {
4
4
  baseUrl: string;
@@ -6,7 +6,22 @@ interface SparkConfig {
6
6
  declare const SPARK_CONFIG: InjectionToken<SparkConfig>;
7
7
  declare const defaultSparkConfig: SparkConfig;
8
8
 
9
+ /**
10
+ * A signal that changes whenever the authenticated user changes — the bridge that lets ng-spark
11
+ * components react to sign-in/out without a dependency on `@mintplayer/ng-spark-auth` (no
12
+ * dependency exists between the two packages, in either direction, on purpose).
13
+ *
14
+ * `@mintplayer/ng-spark-auth`'s `provideSparkAuth()` supplies it from `SparkAuthService.user`;
15
+ * an app with its own auth stack provides any signal that changes on sign-in/out. Consumers
16
+ * inject it `{ optional: true }` — absent, auth-sensitive data (the program-units menu) is
17
+ * fetched once and never re-fetched.
18
+ *
19
+ * The signal's VALUE is deliberately opaque (`unknown`): consumers only track it for change,
20
+ * never read it — what "the user" looks like belongs to the auth package.
21
+ */
22
+ declare const SPARK_AUTH_STATE: InjectionToken<Signal<unknown>>;
23
+
9
24
  declare function provideSpark(config?: Partial<SparkConfig>): Provider[];
10
25
 
11
- export { SPARK_CONFIG, defaultSparkConfig, provideSpark };
26
+ export { SPARK_AUTH_STATE, SPARK_CONFIG, defaultSparkConfig, provideSpark };
12
27
  export type { SparkConfig };