ng-hub-ui-panels 21.2.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +378 -0
- package/fesm2022/ng-hub-ui-panels.mjs +1080 -0
- package/fesm2022/ng-hub-ui-panels.mjs.map +1 -0
- package/ng-hub-ui-panels-21.2.0.tgz +0 -0
- package/package.json +48 -0
- package/types/ng-hub-ui-panels.d.ts +399 -0
|
@@ -0,0 +1,1080 @@
|
|
|
1
|
+
import * as i0 from '@angular/core';
|
|
2
|
+
import { Injectable, inject, Renderer2, ElementRef, DestroyRef, viewChild, viewChildren, output, input, booleanAttribute, signal, computed, afterNextRender, RendererStyleFlags2, forwardRef, ChangeDetectionStrategy, ViewEncapsulation, Component, model, effect, TemplateRef, Directive } from '@angular/core';
|
|
3
|
+
import { NgTemplateOutlet } from '@angular/common';
|
|
4
|
+
import { Router, NavigationEnd, RouterOutlet } from '@angular/router';
|
|
5
|
+
import { takeUntilDestroyed } from '@angular/core/rxjs-interop';
|
|
6
|
+
import { NG_VALUE_ACCESSOR } from '@angular/forms';
|
|
7
|
+
import { filter } from 'rxjs';
|
|
8
|
+
|
|
9
|
+
/**
|
|
10
|
+
* Injectable defaults for every `<hub-panels>` in the application.
|
|
11
|
+
*
|
|
12
|
+
* Override at any injector level to change the defaults globally or for a
|
|
13
|
+
* feature subtree:
|
|
14
|
+
*
|
|
15
|
+
* ```ts
|
|
16
|
+
* providers: [{ provide: PanelsConfig, useValue: { ...new PanelsConfig(), type: 'pills' } }]
|
|
17
|
+
* ```
|
|
18
|
+
*/
|
|
19
|
+
class PanelsConfig {
|
|
20
|
+
/** Default navigation style — `'tabs'`, `'pills'` or `'accordion'`. */
|
|
21
|
+
type = 'tabs';
|
|
22
|
+
/** Whether keyboard navigation (arrows / Home / End / Delete) is enabled. */
|
|
23
|
+
isKeysAllowed = true;
|
|
24
|
+
/** Accessible label announced for the panel list. */
|
|
25
|
+
ariaLabel = 'Tabs';
|
|
26
|
+
/** Accessible label for the backward scroll button (scrollable mode). */
|
|
27
|
+
scrollBackwardAriaLabel = 'Scroll tabs backward';
|
|
28
|
+
/** Accessible label for the forward scroll button (scrollable mode). */
|
|
29
|
+
scrollForwardAriaLabel = 'Scroll tabs forward';
|
|
30
|
+
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "22.0.1", ngImport: i0, type: PanelsConfig, deps: [], target: i0.ɵɵFactoryTarget.Injectable });
|
|
31
|
+
static ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "22.0.1", ngImport: i0, type: PanelsConfig, providedIn: 'root' });
|
|
32
|
+
}
|
|
33
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.0.1", ngImport: i0, type: PanelsConfig, decorators: [{
|
|
34
|
+
type: Injectable,
|
|
35
|
+
args: [{ providedIn: 'root' }]
|
|
36
|
+
}] });
|
|
37
|
+
|
|
38
|
+
/**
|
|
39
|
+
* Usable inner width of an element: `offsetWidth` minus horizontal paddings
|
|
40
|
+
* and borders. Used by the scrollable strip to size its scroll steps.
|
|
41
|
+
*/
|
|
42
|
+
function contentBoxWidth(element) {
|
|
43
|
+
const style = getComputedStyle(element);
|
|
44
|
+
return (element.offsetWidth -
|
|
45
|
+
parseFloat(style.paddingLeft) -
|
|
46
|
+
parseFloat(style.paddingRight) -
|
|
47
|
+
parseFloat(style.borderLeftWidth) -
|
|
48
|
+
parseFloat(style.borderRightWidth));
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
/**
|
|
52
|
+
* Reads a nested value from an object using dot-notation path syntax
|
|
53
|
+
* (e.g. `id`, `meta.key`). Returns `undefined` when the path cannot be
|
|
54
|
+
* resolved. Used by the panels' `bindValue` form-value mapping.
|
|
55
|
+
*/
|
|
56
|
+
function readByPath(source, path) {
|
|
57
|
+
if (source == null || !path) {
|
|
58
|
+
return undefined;
|
|
59
|
+
}
|
|
60
|
+
return path.split('.').reduce((currentValue, segment) => {
|
|
61
|
+
if (currentValue == null) {
|
|
62
|
+
return undefined;
|
|
63
|
+
}
|
|
64
|
+
return currentValue[segment];
|
|
65
|
+
}, source);
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
/**
|
|
69
|
+
* Content-panels container — the hub `panels` primitive.
|
|
70
|
+
*
|
|
71
|
+
* Projects `<hub-panel>` panes and renders them in one of three views:
|
|
72
|
+
*
|
|
73
|
+
* - **`tabs` / `pills`** — an accessible `tablist` of clickable headers
|
|
74
|
+
* (roving tabindex, arrow/Home/End/Delete keys) above the active pane.
|
|
75
|
+
* Panels with a `routerLink` switch the content area to a `<router-outlet>`
|
|
76
|
+
* and the active panel follows the URL. With `scrollable`, overflowing
|
|
77
|
+
* headers get backward/forward scroll buttons.
|
|
78
|
+
* - **`accordion`** — each panel renders as a stacked disclosure panel with an
|
|
79
|
+
* animated collapse: clicking an open header closes it, `multiple` allows
|
|
80
|
+
* several panels open at once and `flush` removes the outer chrome. All
|
|
81
|
+
* panels start collapsed unless a panel is marked `[active]` or a form value
|
|
82
|
+
* is bound. Routed panels are not supported in this view.
|
|
83
|
+
*
|
|
84
|
+
* The container implements `ControlValueAccessor`, so the active panel(s) can
|
|
85
|
+
* be bound as a form value (`ngModel` / `formControl`): each panel contributes
|
|
86
|
+
* its `value` (or its `id` by default), optionally narrowed with `bindValue`
|
|
87
|
+
* and compared with `compareWith`. With `multiple` the form value is an array.
|
|
88
|
+
*
|
|
89
|
+
* Theming is driven entirely by the `--hub-panels-*` CSS custom properties
|
|
90
|
+
* (see `panels.variables.scss`); the accordion view also honours the
|
|
91
|
+
* `--hub-accordion-*` ng-hub-ui contract as a compatibility fallback.
|
|
92
|
+
*
|
|
93
|
+
* @example
|
|
94
|
+
* ```html
|
|
95
|
+
* <hub-panels type="accordion" multiple [formControl]="openPanels">
|
|
96
|
+
* <hub-panel heading="Fields" value="fields">…</hub-panel>
|
|
97
|
+
* <hub-panel heading="Validations" value="validations">…</hub-panel>
|
|
98
|
+
* </hub-panels>
|
|
99
|
+
* ```
|
|
100
|
+
*/
|
|
101
|
+
class PanelsComponent {
|
|
102
|
+
#router = inject(Router);
|
|
103
|
+
#renderer = inject(Renderer2);
|
|
104
|
+
#elementRef = inject(ElementRef);
|
|
105
|
+
#destroyRef = inject(DestroyRef);
|
|
106
|
+
/** Container-wide defaults (aria labels, default type, keyboard toggle). */
|
|
107
|
+
config = inject(PanelsConfig);
|
|
108
|
+
/** Scrollable container hosting the panel headers (`tabs` / `pills` views). */
|
|
109
|
+
navScroller = viewChild('navScroller', /* @ts-ignore */
|
|
110
|
+
...(ngDevMode ? [{ debugName: "navScroller" }] : /* istanbul ignore next */ []));
|
|
111
|
+
/** Backward scroll button (only rendered while it can scroll back). */
|
|
112
|
+
prevBtn = viewChild('prevBtn', /* @ts-ignore */
|
|
113
|
+
...(ngDevMode ? [{ debugName: "prevBtn" }] : /* istanbul ignore next */ []));
|
|
114
|
+
/** Forward scroll button (only rendered while it can scroll forward). */
|
|
115
|
+
nextBtn = viewChild('nextBtn', /* @ts-ignore */
|
|
116
|
+
...(ngDevMode ? [{ debugName: "nextBtn" }] : /* istanbul ignore next */ []));
|
|
117
|
+
/** Parking lot that owns the projected panel hosts before they are placed. */
|
|
118
|
+
contentRoot = viewChild('contentRoot', /* @ts-ignore */
|
|
119
|
+
...(ngDevMode ? [{ debugName: "contentRoot" }] : /* istanbul ignore next */ []));
|
|
120
|
+
/** Visible block hosts used by `multiple` tabs / pills. */
|
|
121
|
+
multiplePaneHosts = viewChildren('multiplePaneHost', /* @ts-ignore */
|
|
122
|
+
...(ngDevMode ? [{ debugName: "multiplePaneHosts" }] : /* istanbul ignore next */ []));
|
|
123
|
+
/** Visible grouped blocks used by `multiple` tabs / pills. */
|
|
124
|
+
multipleBlocks = viewChildren('multipleBlock', /* @ts-ignore */
|
|
125
|
+
...(ngDevMode ? [{ debugName: "multipleBlocks" }] : /* istanbul ignore next */ []));
|
|
126
|
+
/** Emitted when the user activates (opens) a different panel. */
|
|
127
|
+
panelChange = output();
|
|
128
|
+
/** Whether the panel list is stacked beside the content (`tabs` / `pills`). */
|
|
129
|
+
vertical = input(false, { ...(ngDevMode ? { debugName: "vertical" } : /* istanbul ignore next */ {}), transform: booleanAttribute });
|
|
130
|
+
/** Whether panel headers stretch to share the available width equally. */
|
|
131
|
+
justified = input(false, { ...(ngDevMode ? { debugName: "justified" } : /* istanbul ignore next */ {}), transform: booleanAttribute });
|
|
132
|
+
/** Visualization — `'tabs'` (default), `'pills'` or `'accordion'`. */
|
|
133
|
+
type = input(this.config.type, /* @ts-ignore */
|
|
134
|
+
...(ngDevMode ? [{ debugName: "type" }] : /* istanbul ignore next */ []));
|
|
135
|
+
/** Whether keyboard navigation is enabled. */
|
|
136
|
+
isKeysAllowed = input(this.config.isKeysAllowed, { ...(ngDevMode ? { debugName: "isKeysAllowed" } : /* istanbul ignore next */ {}), transform: booleanAttribute });
|
|
137
|
+
/** Whether overflowing headers get backward/forward scroll buttons. */
|
|
138
|
+
scrollable = input(false, { ...(ngDevMode ? { debugName: "scrollable" } : /* istanbul ignore next */ {}), transform: booleanAttribute });
|
|
139
|
+
/** Accordion view: whether several panels may be expanded at once. */
|
|
140
|
+
multiple = input(false, { ...(ngDevMode ? { debugName: "multiple" } : /* istanbul ignore next */ {}), transform: booleanAttribute });
|
|
141
|
+
/** Accordion view: edge-to-edge panels without outer borders or radius. */
|
|
142
|
+
flush = input(false, { ...(ngDevMode ? { debugName: "flush" } : /* istanbul ignore next */ {}), transform: booleanAttribute });
|
|
143
|
+
/**
|
|
144
|
+
* Dot-notation path applied to each panel's `value` to obtain the emitted
|
|
145
|
+
* form value (e.g. `'meta.key'`). Empty by default — the raw value is used.
|
|
146
|
+
*/
|
|
147
|
+
bindValue = input(undefined, /* @ts-ignore */
|
|
148
|
+
...(ngDevMode ? [{ debugName: "bindValue" }] : /* istanbul ignore next */ []));
|
|
149
|
+
/** Equality used to match form values against panel values. `===` by default. */
|
|
150
|
+
compareWith = input((a, b) => a === b, /* @ts-ignore */
|
|
151
|
+
...(ngDevMode ? [{ debugName: "compareWith" }] : /* istanbul ignore next */ []));
|
|
152
|
+
/** Registered panels, in projection order. */
|
|
153
|
+
panels = signal([], /* @ts-ignore */
|
|
154
|
+
...(ngDevMode ? [{ debugName: "panels" }] : /* istanbul ignore next */ []));
|
|
155
|
+
/** Currently active panel, if any (the first one, under `multiple`). */
|
|
156
|
+
activePanel = computed(() => this.panels().find((panel) => panel.active()), /* @ts-ignore */
|
|
157
|
+
...(ngDevMode ? [{ debugName: "activePanel" }] : /* istanbul ignore next */ []));
|
|
158
|
+
/** Panel index lookup used by the strip templates and keyboard navigation. */
|
|
159
|
+
panelIndexMap = computed(() => new Map(this.panels().map((panel, index) => [panel, index])), /* @ts-ignore */
|
|
160
|
+
...(ngDevMode ? [{ debugName: "panelIndexMap" }] : /* istanbul ignore next */ []));
|
|
161
|
+
/** Whether the container renders the accordion visualization. */
|
|
162
|
+
isAccordionView = computed(() => this.type() === 'accordion', /* @ts-ignore */
|
|
163
|
+
...(ngDevMode ? [{ debugName: "isAccordionView" }] : /* istanbul ignore next */ []));
|
|
164
|
+
/**
|
|
165
|
+
* Whether the container renders the chromeless `card` visualization: no
|
|
166
|
+
* navigation strip and every panel always visible, each styled as a card.
|
|
167
|
+
*/
|
|
168
|
+
isCardView = computed(() => this.type() === 'card', /* @ts-ignore */
|
|
169
|
+
...(ngDevMode ? [{ debugName: "isCardView" }] : /* istanbul ignore next */ []));
|
|
170
|
+
/**
|
|
171
|
+
* Whether more than one panel may be active at once. Driven by `multiple`
|
|
172
|
+
* for every view, and always enabled in the `card` view, where all panels
|
|
173
|
+
* stay visible at once and must not deactivate one another.
|
|
174
|
+
*/
|
|
175
|
+
allowsMultipleActive = computed(() => this.multiple() || this.isCardView(), /* @ts-ignore */
|
|
176
|
+
...(ngDevMode ? [{ debugName: "allowsMultipleActive" }] : /* istanbul ignore next */ []));
|
|
177
|
+
/** Whether the bound form control disabled the whole container. */
|
|
178
|
+
formDisabled = signal(false, /* @ts-ignore */
|
|
179
|
+
...(ngDevMode ? [{ debugName: "formDisabled" }] : /* istanbul ignore next */ []));
|
|
180
|
+
/**
|
|
181
|
+
* Whether the active panel routes its content through a `<router-outlet>`.
|
|
182
|
+
* Never true in the accordion view, where routed panels are not supported.
|
|
183
|
+
*/
|
|
184
|
+
activePanelHasRouter = computed(() => !this.isAccordionView() && !this.allowsMultipleActive() && !!this.activePanel()?.routerUrl(), /* @ts-ignore */
|
|
185
|
+
...(ngDevMode ? [{ debugName: "activePanelHasRouter" }] : /* istanbul ignore next */ []));
|
|
186
|
+
/**
|
|
187
|
+
* In `multiple` tabs/pills, headers are partitioned into blocks. Every
|
|
188
|
+
* active panel starts a block; following inactive headers stay visible in
|
|
189
|
+
* that same block until the next active panel starts a new one.
|
|
190
|
+
*/
|
|
191
|
+
multipleHeaderGroups = computed(() => {
|
|
192
|
+
if (!this.allowsMultipleActive() || this.isAccordionView()) {
|
|
193
|
+
return [];
|
|
194
|
+
}
|
|
195
|
+
const panels = this.panels();
|
|
196
|
+
if (!panels.length) {
|
|
197
|
+
return [];
|
|
198
|
+
}
|
|
199
|
+
const activeIndices = panels
|
|
200
|
+
.map((panel, index) => (panel.active() ? index : -1))
|
|
201
|
+
.filter((index) => index !== -1);
|
|
202
|
+
if (!activeIndices.length) {
|
|
203
|
+
return [{ headers: panels }];
|
|
204
|
+
}
|
|
205
|
+
return activeIndices.map((activeIndex, groupIndex) => {
|
|
206
|
+
const startIndex = groupIndex === 0 ? 0 : activeIndex;
|
|
207
|
+
const endIndex = activeIndices[groupIndex + 1] ?? panels.length;
|
|
208
|
+
return {
|
|
209
|
+
activePanel: panels[activeIndex],
|
|
210
|
+
headers: panels.slice(startIndex, endIndex)
|
|
211
|
+
};
|
|
212
|
+
});
|
|
213
|
+
}, /* @ts-ignore */
|
|
214
|
+
...(ngDevMode ? [{ debugName: "multipleHeaderGroups" }] : /* istanbul ignore next */ []));
|
|
215
|
+
/** Whether the strip cannot scroll further backward. */
|
|
216
|
+
backwardIsDisabled = signal(true, /* @ts-ignore */
|
|
217
|
+
...(ngDevMode ? [{ debugName: "backwardIsDisabled" }] : /* istanbul ignore next */ []));
|
|
218
|
+
/** Whether the strip cannot scroll further forward. */
|
|
219
|
+
forwardIsDisabled = signal(false, /* @ts-ignore */
|
|
220
|
+
...(ngDevMode ? [{ debugName: "forwardIsDisabled" }] : /* istanbul ignore next */ []));
|
|
221
|
+
#isDestroyed = false;
|
|
222
|
+
#syncScheduled = false;
|
|
223
|
+
#viewInitialised = false;
|
|
224
|
+
#placementScheduled = false;
|
|
225
|
+
#multipleBlockSizingScheduled = false;
|
|
226
|
+
/** Last value written by the bound form control; `null` when no form. */
|
|
227
|
+
#formValue = null;
|
|
228
|
+
#onChange = () => undefined;
|
|
229
|
+
#onTouched = () => undefined;
|
|
230
|
+
constructor() {
|
|
231
|
+
this.#destroyRef.onDestroy(() => {
|
|
232
|
+
this.#isDestroyed = true;
|
|
233
|
+
});
|
|
234
|
+
afterNextRender(() => {
|
|
235
|
+
this.#viewInitialised = true;
|
|
236
|
+
this.updateScrollButtons();
|
|
237
|
+
this.setActivePanel();
|
|
238
|
+
// Re-apply any form value written before the panels' inputs were bound.
|
|
239
|
+
this.#applyFormValue();
|
|
240
|
+
this.#ensureActivePanel();
|
|
241
|
+
this.#schedulePanelPlacement();
|
|
242
|
+
this.#scheduleMultipleBlockSizing();
|
|
243
|
+
this.#router.events
|
|
244
|
+
.pipe(filter((event) => event instanceof NavigationEnd), takeUntilDestroyed(this.#destroyRef))
|
|
245
|
+
.subscribe(() => this.setActivePanel());
|
|
246
|
+
});
|
|
247
|
+
}
|
|
248
|
+
/**
|
|
249
|
+
* Registers a panel in the container. Called by `PanelComponent` on
|
|
250
|
+
* construction — not meant for manual use.
|
|
251
|
+
*/
|
|
252
|
+
registerPanel(panel) {
|
|
253
|
+
this.panels.update((panels) => [...panels, panel]);
|
|
254
|
+
this.#scheduleSync();
|
|
255
|
+
}
|
|
256
|
+
/**
|
|
257
|
+
* Removes a panel from the container. `reselect` activates the closest
|
|
258
|
+
* enabled neighbour when the removed panel was active; `emit` fires the
|
|
259
|
+
* panel's `removed` output.
|
|
260
|
+
*/
|
|
261
|
+
removePanel(panel, options = {}) {
|
|
262
|
+
const { reselect = true, emit = true } = options;
|
|
263
|
+
const panels = this.panels();
|
|
264
|
+
const index = panels.indexOf(panel);
|
|
265
|
+
if (index === -1 || this.#isDestroyed) {
|
|
266
|
+
return;
|
|
267
|
+
}
|
|
268
|
+
if (reselect && panel.active() && !this.isAccordionView()) {
|
|
269
|
+
const closestIndex = this.#closestEnabledIndex(index);
|
|
270
|
+
if (closestIndex !== -1) {
|
|
271
|
+
panels[closestIndex].active.set(true);
|
|
272
|
+
}
|
|
273
|
+
}
|
|
274
|
+
if (emit) {
|
|
275
|
+
panel.removed.emit(panel);
|
|
276
|
+
}
|
|
277
|
+
this.panels.update((currentPanels) => currentPanels.filter((candidate) => candidate !== panel));
|
|
278
|
+
// Detach the projected pane: the consumer template still owns the node,
|
|
279
|
+
// so removing the header alone would leave the pane content behind.
|
|
280
|
+
const paneElement = panel.elementRef.nativeElement;
|
|
281
|
+
if (paneElement.parentNode) {
|
|
282
|
+
this.#renderer.removeChild(paneElement.parentNode, paneElement);
|
|
283
|
+
}
|
|
284
|
+
if (panel.active()) {
|
|
285
|
+
panel.active.set(false);
|
|
286
|
+
this.#emitFormValue();
|
|
287
|
+
}
|
|
288
|
+
this.#scheduleSync();
|
|
289
|
+
}
|
|
290
|
+
/**
|
|
291
|
+
* Activates a panel on behalf of the user (`tabs` / `pills` views): marks it
|
|
292
|
+
* active, navigates when routed, and emits `panelChange`. In `multiple` mode
|
|
293
|
+
* clicking an active panel toggles it off (the panes render side by side);
|
|
294
|
+
* otherwise an already-active panel no-ops. Disabled panels always no-op.
|
|
295
|
+
*/
|
|
296
|
+
selectPanel(panel) {
|
|
297
|
+
if (panel.disabled() || this.formDisabled()) {
|
|
298
|
+
return;
|
|
299
|
+
}
|
|
300
|
+
if (this.allowsMultipleActive()) {
|
|
301
|
+
if (panel.active()) {
|
|
302
|
+
panel.active.set(false);
|
|
303
|
+
}
|
|
304
|
+
else {
|
|
305
|
+
panel.active.set(true);
|
|
306
|
+
panel.navigate();
|
|
307
|
+
this.panelChange.emit({ prev: undefined, current: panel });
|
|
308
|
+
}
|
|
309
|
+
this.#emitFormValue();
|
|
310
|
+
this.#onTouched();
|
|
311
|
+
this.#schedulePanelPlacement();
|
|
312
|
+
return;
|
|
313
|
+
}
|
|
314
|
+
if (panel.active()) {
|
|
315
|
+
return;
|
|
316
|
+
}
|
|
317
|
+
const previousPanel = this.activePanel();
|
|
318
|
+
// Deactivate the previously active panel up front so the emitted form
|
|
319
|
+
// value reflects only the newly selected panel. The per-panel effect that
|
|
320
|
+
// enforces single-active runs asynchronously, so relying on it here would
|
|
321
|
+
// emit a stale value that still includes the previous panel.
|
|
322
|
+
if (previousPanel && previousPanel !== panel) {
|
|
323
|
+
previousPanel.active.set(false);
|
|
324
|
+
}
|
|
325
|
+
panel.active.set(true);
|
|
326
|
+
panel.navigate();
|
|
327
|
+
this.panelChange.emit({ prev: previousPanel, current: panel });
|
|
328
|
+
this.#emitFormValue();
|
|
329
|
+
this.#onTouched();
|
|
330
|
+
this.#schedulePanelPlacement();
|
|
331
|
+
}
|
|
332
|
+
/**
|
|
333
|
+
* Toggles a panel on behalf of the user (accordion view): an open panel
|
|
334
|
+
* closes, a closed one opens — closing the others unless `multiple`.
|
|
335
|
+
* Emits `panelChange` when a panel opens.
|
|
336
|
+
*/
|
|
337
|
+
togglePanel(panel) {
|
|
338
|
+
if (panel.disabled() || this.formDisabled()) {
|
|
339
|
+
return;
|
|
340
|
+
}
|
|
341
|
+
if (panel.active()) {
|
|
342
|
+
panel.active.set(false);
|
|
343
|
+
}
|
|
344
|
+
else {
|
|
345
|
+
const previousPanel = this.allowsMultipleActive() ? undefined : this.activePanel();
|
|
346
|
+
panel.active.set(true);
|
|
347
|
+
this.panelChange.emit({ prev: previousPanel, current: panel });
|
|
348
|
+
}
|
|
349
|
+
this.#emitFormValue();
|
|
350
|
+
this.#onTouched();
|
|
351
|
+
this.#schedulePanelPlacement();
|
|
352
|
+
}
|
|
353
|
+
/**
|
|
354
|
+
* Marks the routed panel matching the current URL as active. Does not
|
|
355
|
+
* navigate — activation through this path is URL-driven. No-op in the
|
|
356
|
+
* accordion view, where routed panels are not supported.
|
|
357
|
+
*/
|
|
358
|
+
setActivePanel() {
|
|
359
|
+
if (this.isAccordionView()) {
|
|
360
|
+
return;
|
|
361
|
+
}
|
|
362
|
+
const [route, queryString] = this.#router.url.split('?');
|
|
363
|
+
for (const panel of this.panels()) {
|
|
364
|
+
if (!panel.routerUrl()) {
|
|
365
|
+
continue;
|
|
366
|
+
}
|
|
367
|
+
let matches;
|
|
368
|
+
if (panel.pathMatch() === 'full') {
|
|
369
|
+
const currentUrl = queryString?.trim() ? `${route}?${queryString.trim()}` : route;
|
|
370
|
+
matches = currentUrl === panel.getFullRoute();
|
|
371
|
+
}
|
|
372
|
+
else {
|
|
373
|
+
matches = route === panel.getRoute();
|
|
374
|
+
}
|
|
375
|
+
if (matches) {
|
|
376
|
+
if (!panel.active()) {
|
|
377
|
+
panel.active.set(true);
|
|
378
|
+
}
|
|
379
|
+
break;
|
|
380
|
+
}
|
|
381
|
+
}
|
|
382
|
+
}
|
|
383
|
+
// ── ControlValueAccessor ────────────────────────────────────────────────
|
|
384
|
+
/**
|
|
385
|
+
* Writes the form value into the container: panels whose (`bindValue`-mapped)
|
|
386
|
+
* value matches are activated, the rest are deactivated. With `multiple` an
|
|
387
|
+
* array is expected; otherwise a single value.
|
|
388
|
+
*/
|
|
389
|
+
writeValue(value) {
|
|
390
|
+
if (value == null) {
|
|
391
|
+
this.#formValue = [];
|
|
392
|
+
}
|
|
393
|
+
else if (this.multiple()) {
|
|
394
|
+
this.#formValue = Array.isArray(value) ? [...value] : [value];
|
|
395
|
+
}
|
|
396
|
+
else {
|
|
397
|
+
this.#formValue = Array.isArray(value) ? value.slice(0, 1) : [value];
|
|
398
|
+
}
|
|
399
|
+
this.#applyFormValue();
|
|
400
|
+
}
|
|
401
|
+
/** Registers the form-control change callback. */
|
|
402
|
+
registerOnChange(onChange) {
|
|
403
|
+
this.#onChange = onChange;
|
|
404
|
+
}
|
|
405
|
+
/** Registers the form-control touched callback. */
|
|
406
|
+
registerOnTouched(onTouched) {
|
|
407
|
+
this.#onTouched = onTouched;
|
|
408
|
+
}
|
|
409
|
+
/** Enables/disables every panel header on behalf of the form control. */
|
|
410
|
+
setDisabledState(isDisabled) {
|
|
411
|
+
this.formDisabled.set(isDisabled);
|
|
412
|
+
}
|
|
413
|
+
/** Keyboard navigation for the panel strip (arrows / Home / End / Delete). */
|
|
414
|
+
onPanelKeydown(event, index) {
|
|
415
|
+
if (!this.isKeysAllowed()) {
|
|
416
|
+
return;
|
|
417
|
+
}
|
|
418
|
+
switch (event.key) {
|
|
419
|
+
case 'ArrowRight':
|
|
420
|
+
case 'ArrowDown':
|
|
421
|
+
if (event.key === 'ArrowDown' && !this.vertical()) {
|
|
422
|
+
return;
|
|
423
|
+
}
|
|
424
|
+
event.preventDefault();
|
|
425
|
+
this.#focusPanelAt(this.#stepEnabledIndex(index, 1));
|
|
426
|
+
return;
|
|
427
|
+
case 'ArrowLeft':
|
|
428
|
+
case 'ArrowUp':
|
|
429
|
+
if (event.key === 'ArrowUp' && !this.vertical()) {
|
|
430
|
+
return;
|
|
431
|
+
}
|
|
432
|
+
event.preventDefault();
|
|
433
|
+
this.#focusPanelAt(this.#stepEnabledIndex(index, -1));
|
|
434
|
+
return;
|
|
435
|
+
case 'Home':
|
|
436
|
+
event.preventDefault();
|
|
437
|
+
this.#focusPanelAt(this.panels().findIndex((panel) => !panel.disabled()));
|
|
438
|
+
return;
|
|
439
|
+
case 'End': {
|
|
440
|
+
event.preventDefault();
|
|
441
|
+
const panels = this.panels();
|
|
442
|
+
this.#focusPanelAt(panels.length - 1 - [...panels].reverse().findIndex((panel) => !panel.disabled()));
|
|
443
|
+
return;
|
|
444
|
+
}
|
|
445
|
+
case 'Delete': {
|
|
446
|
+
const panel = this.panels()[index];
|
|
447
|
+
if (panel?.removable()) {
|
|
448
|
+
this.removePanel(panel);
|
|
449
|
+
queueMicrotask(() => this.#focusPanelAt(Math.min(index, this.panels().length - 1)));
|
|
450
|
+
}
|
|
451
|
+
}
|
|
452
|
+
}
|
|
453
|
+
}
|
|
454
|
+
/**
|
|
455
|
+
* Keyboard navigation between accordion headers (arrows / Home / End /
|
|
456
|
+
* Delete). Enter and Space toggle natively through the button click.
|
|
457
|
+
*/
|
|
458
|
+
onAccordionKeydown(event, panel) {
|
|
459
|
+
if (!this.isKeysAllowed()) {
|
|
460
|
+
return;
|
|
461
|
+
}
|
|
462
|
+
const index = this.panels().indexOf(panel);
|
|
463
|
+
switch (event.key) {
|
|
464
|
+
case 'ArrowDown':
|
|
465
|
+
event.preventDefault();
|
|
466
|
+
this.#focusPanelAt(this.#stepEnabledIndex(index, 1));
|
|
467
|
+
return;
|
|
468
|
+
case 'ArrowUp':
|
|
469
|
+
event.preventDefault();
|
|
470
|
+
this.#focusPanelAt(this.#stepEnabledIndex(index, -1));
|
|
471
|
+
return;
|
|
472
|
+
case 'Home':
|
|
473
|
+
event.preventDefault();
|
|
474
|
+
this.#focusPanelAt(this.panels().findIndex((candidate) => !candidate.disabled()));
|
|
475
|
+
return;
|
|
476
|
+
case 'End': {
|
|
477
|
+
event.preventDefault();
|
|
478
|
+
const panels = this.panels();
|
|
479
|
+
this.#focusPanelAt(panels.length - 1 - [...panels].reverse().findIndex((candidate) => !candidate.disabled()));
|
|
480
|
+
return;
|
|
481
|
+
}
|
|
482
|
+
case 'Delete': {
|
|
483
|
+
if (panel.removable()) {
|
|
484
|
+
this.removePanel(panel);
|
|
485
|
+
queueMicrotask(() => this.#focusPanelAt(Math.min(index, this.panels().length - 1)));
|
|
486
|
+
}
|
|
487
|
+
}
|
|
488
|
+
}
|
|
489
|
+
}
|
|
490
|
+
/** Recomputes the enabled/disabled state of the scroll buttons. */
|
|
491
|
+
updateScrollButtons() {
|
|
492
|
+
if (!this.scrollable() || this.isAccordionView()) {
|
|
493
|
+
return;
|
|
494
|
+
}
|
|
495
|
+
const scroller = this.navScroller()?.nativeElement;
|
|
496
|
+
if (!scroller) {
|
|
497
|
+
return;
|
|
498
|
+
}
|
|
499
|
+
const { scrollLeft, scrollWidth } = scroller;
|
|
500
|
+
this.backwardIsDisabled.set(scrollLeft <= 0);
|
|
501
|
+
this.forwardIsDisabled.set(scrollLeft + contentBoxWidth(scroller) + 1 >= scrollWidth);
|
|
502
|
+
}
|
|
503
|
+
/** Re-syncs scroll controls and multiple-block sizing on window resize. */
|
|
504
|
+
onWindowResize() {
|
|
505
|
+
this.updateScrollButtons();
|
|
506
|
+
this.#scheduleMultipleBlockSizing();
|
|
507
|
+
}
|
|
508
|
+
/** Updates the scroll buttons as the strip scrolls. */
|
|
509
|
+
onScroll() {
|
|
510
|
+
this.updateScrollButtons();
|
|
511
|
+
}
|
|
512
|
+
/** Global index of a panel within the projected strip order. */
|
|
513
|
+
panelIndex(panel) {
|
|
514
|
+
return this.panelIndexMap().get(panel) ?? -1;
|
|
515
|
+
}
|
|
516
|
+
/** Scrolls the panel headers one viewport backward. */
|
|
517
|
+
navBackward() {
|
|
518
|
+
const scroller = this.navScroller()?.nativeElement;
|
|
519
|
+
if (!scroller) {
|
|
520
|
+
return;
|
|
521
|
+
}
|
|
522
|
+
const step = contentBoxWidth(scroller) - this.#visibleScrollButtonsWidth();
|
|
523
|
+
scroller.scrollLeft = Math.max(scroller.scrollLeft - step, 0);
|
|
524
|
+
}
|
|
525
|
+
/** Scrolls the panel headers one viewport forward. */
|
|
526
|
+
navForward() {
|
|
527
|
+
const scroller = this.navScroller()?.nativeElement;
|
|
528
|
+
if (!scroller) {
|
|
529
|
+
return;
|
|
530
|
+
}
|
|
531
|
+
const step = contentBoxWidth(scroller) - this.#visibleScrollButtonsWidth();
|
|
532
|
+
const lastPosition = scroller.scrollWidth - step;
|
|
533
|
+
scroller.scrollLeft = Math.min(scroller.scrollLeft + step, lastPosition);
|
|
534
|
+
}
|
|
535
|
+
/** Width currently taken by the visible scroll buttons. */
|
|
536
|
+
#visibleScrollButtonsWidth() {
|
|
537
|
+
return [this.prevBtn()?.nativeElement, this.nextBtn()?.nativeElement].reduce((total, button) => (button ? total + contentBoxWidth(button) : total), 0);
|
|
538
|
+
}
|
|
539
|
+
/** Index of the enabled panel closest to `index`, or `-1` when none exists. */
|
|
540
|
+
#closestEnabledIndex(index) {
|
|
541
|
+
const panels = this.panels();
|
|
542
|
+
for (let step = 1; step <= panels.length; step += 1) {
|
|
543
|
+
const previous = panels[index - step];
|
|
544
|
+
if (previous && !previous.disabled()) {
|
|
545
|
+
return index - step;
|
|
546
|
+
}
|
|
547
|
+
const next = panels[index + step];
|
|
548
|
+
if (next && !next.disabled()) {
|
|
549
|
+
return index + step;
|
|
550
|
+
}
|
|
551
|
+
}
|
|
552
|
+
return -1;
|
|
553
|
+
}
|
|
554
|
+
/** Next enabled panel index from `index` in `direction`, wrapping around. */
|
|
555
|
+
#stepEnabledIndex(index, direction) {
|
|
556
|
+
const panels = this.panels();
|
|
557
|
+
for (let step = 1; step <= panels.length; step += 1) {
|
|
558
|
+
const candidate = (index + direction * step + panels.length * step) % panels.length;
|
|
559
|
+
if (!panels[candidate].disabled()) {
|
|
560
|
+
return candidate;
|
|
561
|
+
}
|
|
562
|
+
}
|
|
563
|
+
return index;
|
|
564
|
+
}
|
|
565
|
+
/** Moves DOM focus to the panel header at `index` (strip link or accordion button). */
|
|
566
|
+
#focusPanelAt(index) {
|
|
567
|
+
if (index < 0) {
|
|
568
|
+
return;
|
|
569
|
+
}
|
|
570
|
+
const selector = this.isAccordionView() ? '.hub-panels__accordion-btn' : '.hub-panels__nav-link';
|
|
571
|
+
const headers = this.#elementRef.nativeElement.querySelectorAll(selector);
|
|
572
|
+
headers[index]?.focus();
|
|
573
|
+
}
|
|
574
|
+
/**
|
|
575
|
+
* Coalesces post-registration/removal housekeeping into one microtask:
|
|
576
|
+
* re-applies the bound form value to the current panels, guarantees an
|
|
577
|
+
* active panel (non-routed `tabs` / `pills` containers without a bound
|
|
578
|
+
* form) and refreshes the scroll buttons after the strip changed size.
|
|
579
|
+
* Skipped until the first render — before it the projected panels' inputs
|
|
580
|
+
* are not bound yet, and the constructor's `afterNextRender` performs the
|
|
581
|
+
* initial pass instead.
|
|
582
|
+
*/
|
|
583
|
+
#scheduleSync() {
|
|
584
|
+
if (this.#syncScheduled || this.#isDestroyed) {
|
|
585
|
+
return;
|
|
586
|
+
}
|
|
587
|
+
this.#syncScheduled = true;
|
|
588
|
+
queueMicrotask(() => {
|
|
589
|
+
this.#syncScheduled = false;
|
|
590
|
+
if (this.#isDestroyed || !this.#viewInitialised) {
|
|
591
|
+
return;
|
|
592
|
+
}
|
|
593
|
+
this.#applyFormValue();
|
|
594
|
+
this.#ensureActivePanel();
|
|
595
|
+
this.#schedulePanelPlacement();
|
|
596
|
+
this.updateScrollButtons();
|
|
597
|
+
});
|
|
598
|
+
}
|
|
599
|
+
/** Coalesces DOM moves for the projected `hub-panel` hosts. */
|
|
600
|
+
#schedulePanelPlacement() {
|
|
601
|
+
if (this.#placementScheduled || this.#isDestroyed) {
|
|
602
|
+
return;
|
|
603
|
+
}
|
|
604
|
+
this.#placementScheduled = true;
|
|
605
|
+
requestAnimationFrame(() => {
|
|
606
|
+
this.#placementScheduled = false;
|
|
607
|
+
if (this.#isDestroyed || !this.#viewInitialised) {
|
|
608
|
+
return;
|
|
609
|
+
}
|
|
610
|
+
this.#runPanelPlacementPass();
|
|
611
|
+
requestAnimationFrame(() => {
|
|
612
|
+
if (this.#isDestroyed || !this.#viewInitialised) {
|
|
613
|
+
return;
|
|
614
|
+
}
|
|
615
|
+
this.#runPanelPlacementPass();
|
|
616
|
+
});
|
|
617
|
+
});
|
|
618
|
+
}
|
|
619
|
+
/** Performs one projected-panel placement pass plus dependent sizing. */
|
|
620
|
+
#runPanelPlacementPass() {
|
|
621
|
+
this.#placeProjectedPanels();
|
|
622
|
+
this.#scheduleMultipleBlockSizing();
|
|
623
|
+
}
|
|
624
|
+
/** Coalesces the DOM measurements needed by `multiple + vertical`. */
|
|
625
|
+
#scheduleMultipleBlockSizing() {
|
|
626
|
+
if (this.#multipleBlockSizingScheduled || this.#isDestroyed) {
|
|
627
|
+
return;
|
|
628
|
+
}
|
|
629
|
+
this.#multipleBlockSizingScheduled = true;
|
|
630
|
+
requestAnimationFrame(() => {
|
|
631
|
+
this.#multipleBlockSizingScheduled = false;
|
|
632
|
+
if (this.#isDestroyed || !this.#viewInitialised) {
|
|
633
|
+
return;
|
|
634
|
+
}
|
|
635
|
+
this.#syncMultipleBlockSizing();
|
|
636
|
+
});
|
|
637
|
+
}
|
|
638
|
+
/** Moves projected panel hosts into their visible multiple-block container. */
|
|
639
|
+
#placeProjectedPanels() {
|
|
640
|
+
const contentRoot = this.contentRoot()?.nativeElement;
|
|
641
|
+
if (!contentRoot) {
|
|
642
|
+
return;
|
|
643
|
+
}
|
|
644
|
+
if (!this.allowsMultipleActive() || this.isAccordionView()) {
|
|
645
|
+
for (const panel of this.panels()) {
|
|
646
|
+
const panelElement = panel.elementRef.nativeElement;
|
|
647
|
+
if (panelElement.parentElement !== contentRoot) {
|
|
648
|
+
this.#renderer.appendChild(contentRoot, panelElement);
|
|
649
|
+
}
|
|
650
|
+
}
|
|
651
|
+
return;
|
|
652
|
+
}
|
|
653
|
+
const hostMap = new Map(Array.from(this.#elementRef.nativeElement.querySelectorAll('.hub-panels__multiple-layout .hub-panels__multiple-pane-host'))
|
|
654
|
+
.map((host) => [host.dataset['panelId'] ?? '', host]));
|
|
655
|
+
for (const panel of this.panels()) {
|
|
656
|
+
const panelElement = panel.elementRef.nativeElement;
|
|
657
|
+
const targetHost = hostMap.get(panel.id()) ?? contentRoot;
|
|
658
|
+
if (panelElement.parentElement !== targetHost) {
|
|
659
|
+
this.#renderer.appendChild(targetHost, panelElement);
|
|
660
|
+
}
|
|
661
|
+
}
|
|
662
|
+
}
|
|
663
|
+
/** Updates the minimum content width for each `multiple + vertical` block. */
|
|
664
|
+
#syncMultipleBlockSizing() {
|
|
665
|
+
for (const blockRef of this.multipleBlocks()) {
|
|
666
|
+
const block = blockRef.nativeElement;
|
|
667
|
+
this.#renderer.removeStyle(block, '--hub-panels-multiple-vertical-panel-min-width', RendererStyleFlags2.DashCase);
|
|
668
|
+
if (!this.vertical() || !this.allowsMultipleActive() || this.isAccordionView()) {
|
|
669
|
+
continue;
|
|
670
|
+
}
|
|
671
|
+
const header = block.querySelector(':scope > .hub-panels__header');
|
|
672
|
+
if (!(header instanceof HTMLElement)) {
|
|
673
|
+
continue;
|
|
674
|
+
}
|
|
675
|
+
const headerStackHeight = Math.ceil(header.getBoundingClientRect().height);
|
|
676
|
+
this.#renderer.setStyle(block, '--hub-panels-multiple-vertical-panel-min-width', `${headerStackHeight}px`, RendererStyleFlags2.DashCase);
|
|
677
|
+
}
|
|
678
|
+
}
|
|
679
|
+
/**
|
|
680
|
+
* Activates the first enabled panel when none is active. Skipped for the
|
|
681
|
+
* accordion view (panels start collapsed), for routed containers (the URL
|
|
682
|
+
* is the single source of truth) and when a form value is bound (the form
|
|
683
|
+
* is).
|
|
684
|
+
*/
|
|
685
|
+
#ensureActivePanel() {
|
|
686
|
+
if (this.isAccordionView() || this.#formValue !== null) {
|
|
687
|
+
return;
|
|
688
|
+
}
|
|
689
|
+
if (this.allowsMultipleActive()) {
|
|
690
|
+
return;
|
|
691
|
+
}
|
|
692
|
+
const panels = this.panels();
|
|
693
|
+
if (!panels.length || panels.some((panel) => panel.active())) {
|
|
694
|
+
return;
|
|
695
|
+
}
|
|
696
|
+
if (panels.some((panel) => !!panel.routerUrl())) {
|
|
697
|
+
return;
|
|
698
|
+
}
|
|
699
|
+
panels.find((panel) => !panel.disabled())?.active.set(true);
|
|
700
|
+
}
|
|
701
|
+
/** Activates/deactivates panels so they mirror the bound form value. */
|
|
702
|
+
#applyFormValue() {
|
|
703
|
+
if (this.#formValue === null) {
|
|
704
|
+
return;
|
|
705
|
+
}
|
|
706
|
+
const compare = this.compareWith();
|
|
707
|
+
for (const panel of this.panels()) {
|
|
708
|
+
const panelValue = this.#comparableValue(panel);
|
|
709
|
+
const matches = this.#formValue.some((selectedValue) => compare(selectedValue, panelValue));
|
|
710
|
+
if (panel.active() !== matches) {
|
|
711
|
+
panel.active.set(matches);
|
|
712
|
+
}
|
|
713
|
+
}
|
|
714
|
+
}
|
|
715
|
+
/** Emits the current selection through the form-control callback. */
|
|
716
|
+
#emitFormValue() {
|
|
717
|
+
const compare = this.compareWith();
|
|
718
|
+
const activeValues = this.panels()
|
|
719
|
+
.filter((panel) => panel.active())
|
|
720
|
+
.map((panel) => this.#comparableValue(panel));
|
|
721
|
+
if (this.#formValue !== null) {
|
|
722
|
+
this.#formValue = [...activeValues];
|
|
723
|
+
}
|
|
724
|
+
// Deduplicate defensively when several panels share the same value.
|
|
725
|
+
const uniqueValues = activeValues.filter((value, index) => activeValues.findIndex((candidate) => compare(candidate, value)) === index);
|
|
726
|
+
this.#onChange(this.multiple() ? uniqueValues : (uniqueValues[0] ?? null));
|
|
727
|
+
}
|
|
728
|
+
/** Form value of a panel with the `bindValue` path applied. */
|
|
729
|
+
#comparableValue(panel) {
|
|
730
|
+
const rawValue = panel.formValue();
|
|
731
|
+
const bindPath = this.bindValue();
|
|
732
|
+
return bindPath ? readByPath(rawValue, bindPath) : rawValue;
|
|
733
|
+
}
|
|
734
|
+
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "22.0.1", ngImport: i0, type: PanelsComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
|
|
735
|
+
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "22.0.1", type: PanelsComponent, isStandalone: true, selector: "hub-panels", inputs: { vertical: { classPropertyName: "vertical", publicName: "vertical", isSignal: true, isRequired: false, transformFunction: null }, justified: { classPropertyName: "justified", publicName: "justified", isSignal: true, isRequired: false, transformFunction: null }, type: { classPropertyName: "type", publicName: "type", isSignal: true, isRequired: false, transformFunction: null }, isKeysAllowed: { classPropertyName: "isKeysAllowed", publicName: "isKeysAllowed", isSignal: true, isRequired: false, transformFunction: null }, scrollable: { classPropertyName: "scrollable", publicName: "scrollable", isSignal: true, isRequired: false, transformFunction: null }, multiple: { classPropertyName: "multiple", publicName: "multiple", isSignal: true, isRequired: false, transformFunction: null }, flush: { classPropertyName: "flush", publicName: "flush", isSignal: true, isRequired: false, transformFunction: null }, bindValue: { classPropertyName: "bindValue", publicName: "bindValue", isSignal: true, isRequired: false, transformFunction: null }, compareWith: { classPropertyName: "compareWith", publicName: "compareWith", isSignal: true, isRequired: false, transformFunction: null } }, outputs: { panelChange: "panelChange" }, host: { listeners: { "window:resize": "onWindowResize()" }, properties: { "class.hub-panels--tabs": "type() === 'tabs'", "class.hub-panels--pills": "type() === 'pills'", "class.hub-panels--card": "isCardView()", "class.hub-panels--vertical": "vertical() && !isAccordionView() && !isCardView()", "class.hub-panels--accordion": "isAccordionView()", "class.hub-panels--flush": "isAccordionView() && flush()", "class.hub-panels--multiple": "multiple()" }, classAttribute: "hub-panels" }, providers: [
|
|
736
|
+
{
|
|
737
|
+
provide: NG_VALUE_ACCESSOR,
|
|
738
|
+
useExisting: forwardRef(() => PanelsComponent),
|
|
739
|
+
multi: true
|
|
740
|
+
}
|
|
741
|
+
], viewQueries: [{ propertyName: "navScroller", first: true, predicate: ["navScroller"], descendants: true, isSignal: true }, { propertyName: "prevBtn", first: true, predicate: ["prevBtn"], descendants: true, isSignal: true }, { propertyName: "nextBtn", first: true, predicate: ["nextBtn"], descendants: true, isSignal: true }, { propertyName: "contentRoot", first: true, predicate: ["contentRoot"], descendants: true, isSignal: true }, { propertyName: "multiplePaneHosts", predicate: ["multiplePaneHost"], descendants: true, isSignal: true }, { propertyName: "multipleBlocks", predicate: ["multipleBlock"], descendants: true, isSignal: true }], ngImport: i0, template: "@if (!isAccordionView() && !isCardView()) {\n\t@if (multiple()) {\n\t\t<div class=\"hub-panels__multiple-layout\">\n\t\t\t@for (group of multipleHeaderGroups(); track group.activePanel ?? group.headers[0]) {\n\t\t\t\t<div\n\t\t\t\t\t#multipleBlock\n\t\t\t\t\tclass=\"hub-panels hub-panels__multiple-block\"\n\t\t\t\t\t[class.hub-panels--tabs]=\"type() === 'tabs'\"\n\t\t\t\t\t[class.hub-panels--pills]=\"type() === 'pills'\"\n\t\t\t\t\t[class.hub-panels--vertical]=\"vertical()\"\n\t\t\t\t>\n\t\t\t\t\t<div class=\"hub-panels__header\">\n\t\t\t\t\t\t<ul\n\t\t\t\t\t\t\tclass=\"hub-panels__nav\"\n\t\t\t\t\t\t\trole=\"tablist\"\n\t\t\t\t\t\t\t[attr.aria-label]=\"config.ariaLabel\"\n\t\t\t\t\t\t\t[attr.aria-orientation]=\"vertical() ? 'vertical' : null\"\n\t\t\t\t\t\t\t[class.hub-panels__nav--tabs]=\"type() === 'tabs'\"\n\t\t\t\t\t\t\t[class.hub-panels__nav--pills]=\"type() === 'pills'\"\n\t\t\t\t\t\t\t[class.hub-panels__nav--vertical]=\"vertical()\"\n\t\t\t\t\t\t\t[class.hub-panels__nav--justified]=\"justified()\"\n\t\t\t\t\t\t>\n\t\t\t\t\t\t\t@for (panel of group.headers; track panel) {\n\t\t\t\t\t\t\t\t<li\n\t\t\t\t\t\t\t\t\tclass=\"hub-panels__nav-item\"\n\t\t\t\t\t\t\t\t\t[class]=\"panel.customClass()\"\n\t\t\t\t\t\t\t\t\t[class.hub-panels__nav-item--active]=\"panel.active()\"\n\t\t\t\t\t\t\t\t\t[class.hub-panels__nav-item--disabled]=\"panel.disabled()\"\n\t\t\t\t\t\t\t\t>\n\t\t\t\t\t\t\t\t\t<button\n\t\t\t\t\t\t\t\t\t\ttype=\"button\"\n\t\t\t\t\t\t\t\t\t\tclass=\"hub-panels__nav-link\"\n\t\t\t\t\t\t\t\t\t\trole=\"tab\"\n\t\t\t\t\t\t\t\t\t\t[id]=\"panel.id() + '-link'\"\n\t\t\t\t\t\t\t\t\t\t[class.hub-panels__nav-link--active]=\"panel.active()\"\n\t\t\t\t\t\t\t\t\t\t[class.hub-panels__nav-link--disabled]=\"panel.disabled()\"\n\t\t\t\t\t\t\t\t\t\t[disabled]=\"panel.disabled() || formDisabled()\"\n\t\t\t\t\t\t\t\t\t\t[attr.aria-controls]=\"panel.id()\"\n\t\t\t\t\t\t\t\t\t\t[attr.aria-selected]=\"panel.active()\"\n\t\t\t\t\t\t\t\t\t\t[attr.tabindex]=\"panel.active() || (!activePanel() && panelIndex(panel) === 0) ? null : -1\"\n\t\t\t\t\t\t\t\t\t\t(click)=\"selectPanel(panel)\"\n\t\t\t\t\t\t\t\t\t\t(keydown)=\"onPanelKeydown($event, panelIndex(panel))\"\n\t\t\t\t\t\t\t\t\t>\n\t\t\t\t\t\t\t\t\t\t@if (panel.headingRef(); as headingRef) {\n\t\t\t\t\t\t\t\t\t\t\t<ng-container [ngTemplateOutlet]=\"headingRef\" />\n\t\t\t\t\t\t\t\t\t\t} @else {\n\t\t\t\t\t\t\t\t\t\t\t{{ panel.heading() }}\n\t\t\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t\t\t\t@if (panel.removable()) {\n\t\t\t\t\t\t\t\t\t\t\t<span\n\t\t\t\t\t\t\t\t\t\t\t\tclass=\"hub-panels__remove-btn\"\n\t\t\t\t\t\t\t\t\t\t\t\taria-hidden=\"true\"\n\t\t\t\t\t\t\t\t\t\t\t\t(click)=\"$event.stopPropagation(); removePanel(panel)\"\n\t\t\t\t\t\t\t\t\t\t\t\t>×</span\n\t\t\t\t\t\t\t\t\t\t\t>\n\t\t\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t\t\t</button>\n\t\t\t\t\t\t\t\t</li>\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t</ul>\n\t\t\t\t\t\t@if (!justified() && type() !== 'pills' && !vertical()) {\n\t\t\t\t\t\t\t<div class=\"hub-panels__spacer\"></div>\n\t\t\t\t\t\t}\n\t\t\t\t\t</div>\n\n\t\t\t\t\t@if (group.activePanel) {\n\t\t\t\t\t\t<div\n\t\t\t\t\t\t\tclass=\"hub-panels__content\"\n\t\t\t\t\t\t\t[class.hub-panels__content--pills]=\"type() === 'pills'\"\n\t\t\t\t\t\t>\n\t\t\t\t\t\t\t<div\n\t\t\t\t\t\t\t\t#multiplePaneHost\n\t\t\t\t\t\t\t\tclass=\"hub-panels__multiple-pane-host\"\n\t\t\t\t\t\t\t\t[attr.data-panel-id]=\"group.activePanel.id()\"\n\t\t\t\t\t\t\t></div>\n\t\t\t\t\t\t</div>\n\t\t\t\t\t}\n\t\t\t\t</div>\n\t\t\t}\n\t\t</div>\n\t} @else {\n\t\t<div class=\"hub-panels__header\">\n\t\t\t@if (scrollable() && !backwardIsDisabled()) {\n\t\t\t\t<button\n\t\t\t\t\t#prevBtn\n\t\t\t\t\ttype=\"button\"\n\t\t\t\t\tclass=\"hub-panels__scroll-btn hub-panels__scroll-btn--backward\"\n\t\t\t\t\t[attr.aria-label]=\"config.scrollBackwardAriaLabel\"\n\t\t\t\t\t(click)=\"navBackward()\"\n\t\t\t\t></button>\n\t\t\t}\n\n\t\t\t<div #navScroller class=\"hub-panels__nav-scroller\" (scroll)=\"onScroll()\">\n\t\t\t\t<ul\n\t\t\t\t\tclass=\"hub-panels__nav\"\n\t\t\t\t\trole=\"tablist\"\n\t\t\t\t\t[attr.aria-label]=\"config.ariaLabel\"\n\t\t\t\t\t[attr.aria-orientation]=\"vertical() ? 'vertical' : null\"\n\t\t\t\t\t[class.hub-panels__nav--tabs]=\"type() === 'tabs'\"\n\t\t\t\t\t[class.hub-panels__nav--pills]=\"type() === 'pills'\"\n\t\t\t\t\t[class.hub-panels__nav--vertical]=\"vertical()\"\n\t\t\t\t\t[class.hub-panels__nav--justified]=\"justified()\"\n\t\t\t\t>\n\t\t\t\t\t@for (panel of panels(); track panel; let index = $index) {\n\t\t\t\t\t\t<li\n\t\t\t\t\t\t\tclass=\"hub-panels__nav-item\"\n\t\t\t\t\t\t\t[class]=\"panel.customClass()\"\n\t\t\t\t\t\t\t[class.hub-panels__nav-item--active]=\"panel.active()\"\n\t\t\t\t\t\t\t[class.hub-panels__nav-item--disabled]=\"panel.disabled()\"\n\t\t\t\t\t\t>\n\t\t\t\t\t\t\t<button\n\t\t\t\t\t\t\t\ttype=\"button\"\n\t\t\t\t\t\t\t\tclass=\"hub-panels__nav-link\"\n\t\t\t\t\t\t\t\trole=\"tab\"\n\t\t\t\t\t\t\t\t[id]=\"panel.id() + '-link'\"\n\t\t\t\t\t\t\t\t[class.hub-panels__nav-link--active]=\"panel.active()\"\n\t\t\t\t\t\t\t\t[class.hub-panels__nav-link--disabled]=\"panel.disabled()\"\n\t\t\t\t\t\t\t\t[disabled]=\"panel.disabled() || formDisabled()\"\n\t\t\t\t\t\t\t\t[attr.aria-controls]=\"panel.id()\"\n\t\t\t\t\t\t\t\t[attr.aria-selected]=\"panel.active()\"\n\t\t\t\t\t\t\t\t[attr.tabindex]=\"panel.active() || (!activePanel() && index === 0) ? null : -1\"\n\t\t\t\t\t\t\t\t(click)=\"selectPanel(panel)\"\n\t\t\t\t\t\t\t\t(keydown)=\"onPanelKeydown($event, index)\"\n\t\t\t\t\t\t\t>\n\t\t\t\t\t\t\t\t@if (panel.headingRef(); as headingRef) {\n\t\t\t\t\t\t\t\t\t<ng-container [ngTemplateOutlet]=\"headingRef\" />\n\t\t\t\t\t\t\t\t} @else {\n\t\t\t\t\t\t\t\t\t{{ panel.heading() }}\n\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t\t@if (panel.removable()) {\n\t\t\t\t\t\t\t\t\t<span\n\t\t\t\t\t\t\t\t\t\tclass=\"hub-panels__remove-btn\"\n\t\t\t\t\t\t\t\t\t\taria-hidden=\"true\"\n\t\t\t\t\t\t\t\t\t\t(click)=\"$event.stopPropagation(); removePanel(panel)\"\n\t\t\t\t\t\t\t\t\t\t>×</span\n\t\t\t\t\t\t\t\t\t>\n\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t</button>\n\t\t\t\t\t\t</li>\n\t\t\t\t\t}\n\t\t\t\t</ul>\n\t\t\t\t@if (!justified() && type() !== 'pills') {\n\t\t\t\t\t<div class=\"hub-panels__spacer\"></div>\n\t\t\t\t}\n\t\t\t</div>\n\n\t\t\t@if (scrollable() && !forwardIsDisabled()) {\n\t\t\t\t<button\n\t\t\t\t\t#nextBtn\n\t\t\t\t\ttype=\"button\"\n\t\t\t\t\tclass=\"hub-panels__scroll-btn hub-panels__scroll-btn--forward\"\n\t\t\t\t\t[attr.aria-label]=\"config.scrollForwardAriaLabel\"\n\t\t\t\t\t(click)=\"navForward()\"\n\t\t\t\t></button>\n\t\t\t}\n\t\t</div>\n\t}\n}\n\n<div\n\t#contentRoot\n\tclass=\"hub-panels__content\"\n\t[class.hub-panels__content--pills]=\"type() === 'pills'\"\n\t[class.hub-panels__content--accordion]=\"isAccordionView()\"\n\t[class.hub-panels__content--multiple-parking]=\"!isAccordionView() && multiple()\"\n>\n\t@if (activePanelHasRouter()) {\n\t\t<router-outlet />\n\t} @else {\n\t\t<ng-content />\n\t}\n</div>\n", styles: [":where(.hub-panels){--hub-panels-flex-direction: row;--hub-panels-border-width: var(--hub-ref-border-width, 1px);--hub-panels-border-color: var(--hub-sys-border-color-default, #dee2e6);--hub-panels-border-radius: var(--hub-ref-radius-md, .375rem);--hub-panels-content-bg: var(--hub-sys-surface-page, #fff);--hub-panels-header-bg: var(--hub-panels-content-bg);--hub-panels-content-box-shadow: none;--hub-panels-content-padding-x: var(--hub-ref-space-3, 1rem);--hub-panels-content-padding-y: var(--hub-ref-space-3, 1rem);--hub-panels-nav-btn-width: 1.5rem;--hub-panels-nav-btn-height: 1.5rem;--hub-panels-backward-btn-bg: url(\"data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 16 16'%3E%3Cpath fill='%23212529' d='M11.354 1.646a.5.5 0 0 1 0 .708L5.707 8l5.647 5.646a.5.5 0 0 1-.708.708l-6-6a.5.5 0 0 1 0-.708l6-6a.5.5 0 0 1 .708 0z'/%3E%3C/svg%3E\");--hub-panels-forward-btn-bg: url(\"data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 16 16'%3E%3Cpath fill='%23212529' d='M4.646 1.646a.5.5 0 0 1 .708 0l6 6a.5.5 0 0 1 0 .708l-6 6a.5.5 0 0 1-.708-.708L10.293 8 4.646 2.354a.5.5 0 0 1 0-.708z'/%3E%3C/svg%3E\");--hub-panels-nav-link-padding-x: var(--hub-ref-space-3, 1rem);--hub-panels-nav-link-padding-y: var(--hub-ref-space-2, .5rem);--hub-panels-nav-link-color: var(--hub-sys-text-primary, #212529);--hub-panels-nav-link-hover-color: var(--hub-sys-color-primary-emphasis, #0a58ca);--hub-panels-nav-link-active-color: var(--hub-sys-color-primary, #0d6efd);--hub-panels-nav-link-active-bg: var(--hub-panels-content-bg);--hub-panels-nav-link-disabled-color: var(--hub-sys-text-muted, #6c757d);--hub-panels-tab-font-family: var(--hub-container-font-family, var(--hub-ref-font-family-base));--hub-panels-tab-font-size: var(--hub-container-font-size, var(--hub-ref-font-size-base, 1rem));--hub-panels-tab-font-weight: 500;--hub-panels-tab-line-height: var(--hub-ref-line-height-base, 1.5);--hub-panels-tab-padding-x: var(--hub-panels-nav-link-padding-x);--hub-panels-tab-padding-y: var(--hub-panels-nav-link-padding-y);--hub-panels-tab-gap: var(--hub-ref-space-2, .5rem);--hub-panels-tab-bg: transparent;--hub-panels-tab-color: var(--hub-panels-nav-link-color);--hub-panels-tab-border-width: var(--hub-panels-border-width);--hub-panels-tab-border-style: solid;--hub-panels-tab-border-color: transparent;--hub-panels-tab-border-radius: var(--hub-panels-border-radius);--hub-panels-tab-bg-hover: var(--hub-ref-surface-2, #f8f9fa);--hub-panels-tab-color-hover: var(--hub-panels-nav-link-hover-color);--hub-panels-tab-bg-active: var(--hub-panels-nav-link-active-bg);--hub-panels-tab-color-active: var(--hub-panels-nav-link-active-color);--hub-panels-tab-border-color-active: var(--hub-sys-color-primary, #0d6efd);--hub-panels-tab-bg-disabled: transparent;--hub-panels-tab-color-disabled: var(--hub-panels-nav-link-disabled-color);--hub-panels-tab-focus-ring-width: var(--hub-sys-focus-ring-width, .25rem);--hub-panels-tab-focus-ring-color: var(--hub-sys-focus-ring-color, rgba(13, 110, 253, .25));--hub-panels-tab-transition: var(--hub-sys-transition-base, all .2s ease-in-out);--hub-panels-tab-active-shadow: 0 -.25rem .5rem rgba(0, 0, 0, .06);--hub-panels-tab-active-shadow-vertical: -.25rem 0 .5rem rgba(0, 0, 0, .06);--hub-panels-strip-margin-top: var(--hub-ref-space-2, .5rem);--hub-panels-nav-gap: 0;--hub-panels-pill-border-radius: 50rem;--hub-panels-pill-bg-active: var(--hub-sys-color-primary, #0d6efd);--hub-panels-pill-color-active: var(--hub-ref-color-white, #fff);--hub-panels-pill-gap: var(--hub-ref-space-2, .5rem);--hub-panels-pill-content-border-width: 0;--hub-panels-remove-btn-opacity: .6;--hub-panels-remove-btn-opacity-hover: 1;--hub-panels-nav-content-gap: var(--hub-ref-space-2, .5rem);--hub-panels-pane-min-width: 16rem;--hub-panels-pane-min-height: 8rem;--hub-panels-pane-gap: 0;--hub-panels-card-gap: var(--hub-ref-space-3, 1rem);--hub-panels-accordion-color: var(--hub-accordion-color, var(--hub-sys-text-primary, #212529));--hub-panels-accordion-bg: var(--hub-accordion-bg, var(--hub-sys-surface-page, #fff));--hub-panels-accordion-border-width: var(--hub-accordion-border-width, var(--hub-ref-border-width, 1px));--hub-panels-accordion-border-color: var(--hub-accordion-border-color, var(--hub-sys-border-color-default, #dee2e6));--hub-panels-accordion-border-radius: var(--hub-accordion-border-radius, var(--hub-ref-radius-sm, .25rem));--hub-panels-accordion-inner-border-radius: var( --hub-accordion-inner-border-radius, calc(var(--hub-panels-accordion-border-radius) - var(--hub-panels-accordion-border-width)) );--hub-panels-accordion-btn-padding-x: var(--hub-accordion-btn-padding-x, 1.25rem);--hub-panels-accordion-btn-padding-y: var(--hub-accordion-btn-padding-y, var(--hub-ref-space-3, 1rem));--hub-panels-accordion-btn-color: var(--hub-accordion-btn-color, var(--hub-sys-text-primary, #212529));--hub-panels-accordion-btn-bg: var(--hub-accordion-btn-bg, var(--hub-sys-surface-page, #fff));--hub-panels-accordion-active-color: var(--hub-accordion-active-color, var(--hub-sys-color-primary, #0c63e4));--hub-panels-accordion-active-bg: var(--hub-accordion-active-bg, var(--hub-sys-color-primary-subtle, #e7f1ff));--hub-panels-accordion-icon-color: var(--hub-accordion-icon-color, var(--hub-panels-accordion-btn-color));--hub-panels-accordion-icon-active-color: var(--hub-accordion-icon-active-color, var(--hub-panels-accordion-active-color));--hub-panels-accordion-btn-icon-mask: var(--hub-accordion-btn-icon-mask, url(\"data:image/svg+xml;charset=UTF-8,%3Csvg viewBox='0 0 16 16' xmlns='http://www.w3.org/2000/svg'%3E%3Cpath fill='%23000' fill-rule='evenodd' d='M1.646 4.646a.5.5 0 0 1 .708 0L8 10.293l5.646-5.647a.5.5 0 0 1 .708.708l-6 6a.5.5 0 0 1-.708 0l-6-6a.5.5 0 0 1 0-.708z'/%3E%3C/svg%3E\"));--hub-panels-accordion-btn-icon-width: var(--hub-accordion-btn-icon-width, 1.25rem);--hub-panels-accordion-btn-icon-transform: var(--hub-accordion-btn-icon-transform, rotate(-180deg));--hub-panels-accordion-btn-icon-transition: var(--hub-accordion-btn-icon-transition, transform .2s ease-in-out);--hub-panels-accordion-btn-focus-box-shadow: var( --hub-accordion-btn-focus-box-shadow, 0 0 0 var(--hub-sys-focus-ring-width, .25rem) var(--hub-sys-focus-ring-color, rgba(13, 110, 253, .25)) );--hub-panels-accordion-transition: var( --hub-accordion-transition, color .15s ease-in-out, background-color .15s ease-in-out, border-color .15s ease-in-out, box-shadow .15s ease-in-out, border-radius .15s ease );--hub-panels-accordion-collapse-transition-duration: var(--hub-accordion-collapse-transition-duration, .25s);--hub-panels-accordion-collapse-transition-easing: var( --hub-accordion-collapse-transition-easing, cubic-bezier(.4, 0, .2, 1) );--hub-panels-accordion-body-padding-x: var(--hub-accordion-body-padding-x, 1.25rem);--hub-panels-accordion-body-padding-y: var(--hub-accordion-body-padding-y, var(--hub-ref-space-3, 1rem))}\n", ".hub-panels{display:block;width:100%;box-sizing:border-box}.hub-panels,.hub-panels *,.hub-panels *:before,.hub-panels *:after{box-sizing:border-box}.hub-panels__header{display:flex;flex-direction:var(--hub-panels-flex-direction);align-items:stretch;background:var(--hub-panels-header-bg)}.hub-panels__scroll-btn{flex:0 0 auto;align-self:center;width:var(--hub-panels-nav-btn-width);height:var(--hub-panels-nav-btn-height);padding:0;border:0;cursor:pointer;background-color:transparent;background-position:center;background-repeat:no-repeat;background-size:1rem 1rem}.hub-panels__scroll-btn--backward{background-image:var(--hub-panels-backward-btn-bg)}.hub-panels__scroll-btn--forward{background-image:var(--hub-panels-forward-btn-bg)}.hub-panels__nav-scroller{display:flex;flex:1 1 auto;overflow-x:auto;background:var(--hub-panels-header-bg);scroll-behavior:smooth;scrollbar-width:none}.hub-panels__nav-scroller::-webkit-scrollbar{display:none}.hub-panels__nav{display:flex;flex:0 0 auto;flex-wrap:nowrap;gap:var(--hub-panels-nav-gap);margin:0;padding:0;list-style:none}.hub-panels__nav--tabs{border-bottom:var(--hub-panels-border-width) solid var(--hub-panels-border-color)}.hub-panels__nav--tabs .hub-panels__nav-link{margin-bottom:calc(-1 * var(--hub-panels-border-width))}.hub-panels__nav--pills{gap:var(--hub-panels-pill-gap)}.hub-panels__nav--pills .hub-panels__nav-link{border-radius:var(--hub-panels-pill-border-radius)}.hub-panels__nav--pills .hub-panels__nav-link--active{color:var(--hub-panels-pill-color-active);background:var(--hub-panels-pill-bg-active);border-color:transparent}.hub-panels__nav--justified{flex:1 1 auto}.hub-panels__nav--justified .hub-panels__nav-item{flex:1 1 0}.hub-panels__nav--justified .hub-panels__nav-link{width:100%;justify-content:center}.hub-panels__nav--vertical{flex-direction:column}.hub-panels__nav--vertical.hub-panels__nav--tabs{border-bottom:0;border-inline-end:var(--hub-panels-border-width) solid var(--hub-panels-border-color)}.hub-panels__nav--vertical.hub-panels__nav--tabs .hub-panels__nav-link{margin-bottom:0;margin-inline-end:calc(-1 * var(--hub-panels-border-width))}.hub-panels__nav-item{display:flex;flex:0 0 auto}.hub-panels__nav-link{position:relative;display:inline-flex;align-items:center;gap:var(--hub-panels-tab-gap);padding:var(--hub-panels-tab-padding-y) var(--hub-panels-tab-padding-x);font-family:var(--hub-panels-tab-font-family);font-size:var(--hub-panels-tab-font-size);font-weight:var(--hub-panels-tab-font-weight);line-height:var(--hub-panels-tab-line-height);white-space:nowrap;color:var(--hub-panels-tab-color);background:var(--hub-panels-tab-bg);border-style:var(--hub-panels-tab-border-style);border-width:var(--hub-panels-tab-border-width);border-color:var(--hub-panels-tab-border-color);border-start-start-radius:var(--hub-panels-tab-border-radius);border-start-end-radius:var(--hub-panels-tab-border-radius);cursor:pointer;transition:var(--hub-panels-tab-transition)}.hub-panels__nav-link:hover:not(:disabled):not(.hub-panels__nav-link--active){color:var(--hub-panels-tab-color-hover);background:var(--hub-panels-tab-bg-hover)}.hub-panels__nav-link:focus-visible{z-index:1;outline:0;box-shadow:0 0 0 var(--hub-panels-tab-focus-ring-width) var(--hub-panels-tab-focus-ring-color)}.hub-panels__nav-link--active{color:var(--hub-panels-tab-color-active);background:var(--hub-panels-tab-bg-active);border-color:var(--hub-panels-tab-border-color-active)}.hub-panels__nav-link:disabled{color:var(--hub-panels-tab-color-disabled);background:var(--hub-panels-tab-bg-disabled);cursor:not-allowed}.hub-panels__remove-btn{display:inline-flex;align-items:center;line-height:1;opacity:var(--hub-panels-remove-btn-opacity)}.hub-panels__remove-btn:hover{opacity:var(--hub-panels-remove-btn-opacity-hover)}.hub-panels__spacer{flex:1 1 auto;background:var(--hub-panels-header-bg);border-bottom:var(--hub-panels-border-width) solid var(--hub-panels-border-color)}.hub-panels__content{padding:var(--hub-panels-content-padding-y) var(--hub-panels-content-padding-x);background:var(--hub-panels-content-bg);box-shadow:var(--hub-panels-content-box-shadow)}.hub-panels__content--accordion{padding:0;background:transparent;box-shadow:none}.hub-panels__content--multiple-parking{display:none}.hub-panels__multiple-layout{display:flex;align-items:stretch;gap:var(--hub-panels-pane-gap);overflow-x:auto;overflow-y:hidden;scroll-behavior:smooth}.hub-panels__multiple-block{display:flex;flex-direction:column;flex:1 0 var(--hub-panels-pane-min-width);align-self:stretch;min-width:var(--hub-panels-pane-min-width);min-height:100%}.hub-panels__multiple-block.hub-panels--vertical{flex-direction:row;flex:1 1 auto;width:100%;min-width:100%;min-height:var(--hub-panels-pane-min-height)}.hub-panels__multiple-block>.hub-panels__content{display:flex;flex:1 1 auto;min-height:0}.hub-panels__multiple-block.hub-panels--vertical>.hub-panels__content{flex:1 1 auto;width:auto;min-width:max(var(--hub-panels-pane-min-width),var(--hub-panels-multiple-vertical-panel-min-width, 0px))}.hub-panels__multiple-pane-host{display:flex;flex:1 1 auto;width:100%;min-height:0}.hub-panels__multiple-pane-host>.hub-panels__panel{flex:1 1 auto;width:100%;height:100%}.hub-panels__multiple-pane-host>.hub-panels__panel.hub-panels__panel--active{display:flex;flex-direction:column}.hub-panels__multiple-pane-host>.hub-panels__panel.hub-panels__panel--active>div{flex:1 1 auto;min-height:0}.hub-panels--vertical.hub-panels--multiple>.hub-panels__multiple-layout{flex-direction:column;align-items:stretch;width:100%}.hub-panels--pills.hub-panels--multiple.hub-panels--vertical>.hub-panels__multiple-layout>.hub-panels__multiple-block+.hub-panels__multiple-block{padding-top:var(--hub-panels-nav-content-gap);border-top:var(--hub-panels-border-width) solid var(--hub-panels-border-color)}.hub-panels__panel{display:none}.hub-panels__panel--active{display:block}.hub-panels--tabs:not(.hub-panels--vertical):not(.hub-panels--multiple)>.hub-panels__header{margin-top:var(--hub-panels-strip-margin-top)}.hub-panels--tabs:not(.hub-panels--vertical):not(.hub-panels--multiple)>.hub-panels__content{border:var(--hub-panels-border-width) solid var(--hub-panels-border-color);border-top:0;border-end-start-radius:var(--hub-panels-border-radius);border-end-end-radius:var(--hub-panels-border-radius)}.hub-panels--tabs:not(.hub-panels--vertical):not(.hub-panels--multiple) .hub-panels__nav--tabs .hub-panels__nav-link--active{border-color:var(--hub-panels-border-color);border-bottom-color:var(--hub-panels-tab-bg-active);box-shadow:var(--hub-panels-tab-active-shadow)}.hub-panels--pills>.hub-panels__header{margin-bottom:var(--hub-panels-nav-content-gap)}.hub-panels--pills>.hub-panels__content{border:var(--hub-panels-pill-content-border-width) solid var(--hub-panels-border-color);border-radius:var(--hub-panels-border-radius)}.hub-panels--vertical{display:flex;align-items:stretch}.hub-panels--vertical .hub-panels__header{flex-direction:column}.hub-panels--vertical .hub-panels__nav-scroller{overflow:visible}.hub-panels--vertical .hub-panels__content{flex:1 1 auto;min-width:0}.hub-panels--tabs.hub-panels--vertical:not(.hub-panels--multiple)>.hub-panels__header{margin-inline-start:var(--hub-panels-strip-margin-top);align-self:stretch;min-height:0}.hub-panels--tabs.hub-panels--vertical:not(.hub-panels--multiple) .hub-panels__spacer{display:none}.hub-panels--tabs.hub-panels--vertical:not(.hub-panels--multiple) .hub-panels__nav-scroller{flex:1 1 auto;align-self:stretch;min-height:100%}.hub-panels--tabs.hub-panels--vertical:not(.hub-panels--multiple) .hub-panels__nav--vertical{flex:1 1 auto;align-self:stretch;min-height:100%}.hub-panels--tabs.hub-panels--vertical:not(.hub-panels--multiple) .hub-panels__nav--vertical .hub-panels__nav-item{width:100%}.hub-panels--tabs.hub-panels--vertical:not(.hub-panels--multiple) .hub-panels__nav--vertical .hub-panels__nav-link{width:calc(100% + var(--hub-panels-border-width));justify-content:flex-start;margin-bottom:0;border-start-start-radius:var(--hub-panels-tab-border-radius);border-start-end-radius:0;border-end-start-radius:var(--hub-panels-tab-border-radius);border-end-end-radius:0;margin-inline-end:calc(-1 * var(--hub-panels-border-width))}.hub-panels--tabs.hub-panels--vertical:not(.hub-panels--multiple)>.hub-panels__content{border:var(--hub-panels-border-width) solid var(--hub-panels-border-color);border-inline-start:0;border-start-end-radius:var(--hub-panels-border-radius);border-end-end-radius:var(--hub-panels-border-radius)}.hub-panels--tabs.hub-panels--vertical:not(.hub-panels--multiple) .hub-panels__nav--tabs .hub-panels__nav-link--active{z-index:1;border-color:var(--hub-panels-border-color);border-inline-end-color:var(--hub-panels-tab-bg-active);box-shadow:var(--hub-panels-tab-active-shadow-vertical)}.hub-panels--pills.hub-panels--vertical>.hub-panels__header{margin-bottom:0;margin-inline-end:var(--hub-panels-nav-content-gap)}.hub-panels--card{display:flex}.hub-panels--card>.hub-panels__content{display:flex;flex-direction:column;gap:var(--hub-panels-card-gap, var(--hub-ref-space-3, 1rem));width:100%;padding:0;background:transparent;box-shadow:none}\n", ".hub-panels__panel--accordion{display:block;color:var(--hub-panels-accordion-color);background-color:var(--hub-panels-accordion-bg);border:var(--hub-panels-accordion-border-width) solid var(--hub-panels-accordion-border-color)}.hub-panels__panel--accordion:not(:first-of-type){border-top:0}.hub-panels__panel--accordion:first-of-type{border-start-start-radius:var(--hub-panels-accordion-border-radius);border-start-end-radius:var(--hub-panels-accordion-border-radius)}.hub-panels__panel--accordion:first-of-type>.hub-panels__accordion-header .hub-panels__accordion-btn{border-start-start-radius:var(--hub-panels-accordion-inner-border-radius);border-start-end-radius:var(--hub-panels-accordion-inner-border-radius)}.hub-panels__panel--accordion:last-of-type{border-end-start-radius:var(--hub-panels-accordion-border-radius);border-end-end-radius:var(--hub-panels-accordion-border-radius)}.hub-panels__panel--accordion:last-of-type>.hub-panels__accordion-header .hub-panels__accordion-btn--collapsed{border-end-start-radius:var(--hub-panels-accordion-inner-border-radius);border-end-end-radius:var(--hub-panels-accordion-inner-border-radius)}.hub-panels__panel--accordion:last-of-type>.hub-panels__accordion-collapse{border-end-start-radius:var(--hub-panels-accordion-border-radius);border-end-end-radius:var(--hub-panels-accordion-border-radius)}.hub-panels__accordion-header{margin:0}.hub-panels__accordion-btn{position:relative;display:flex;align-items:center;width:100%;gap:var(--hub-panels-tab-gap);padding:var(--hub-panels-accordion-btn-padding-y) var(--hub-panels-accordion-btn-padding-x);font-family:var(--hub-panels-tab-font-family);font-size:var(--hub-panels-tab-font-size);line-height:var(--hub-panels-tab-line-height);text-align:left;color:var(--hub-panels-accordion-btn-color);background-color:var(--hub-panels-accordion-btn-bg);border:0;border-radius:0;overflow-anchor:none;transition:var(--hub-panels-accordion-transition);cursor:pointer}.hub-panels__accordion-btn:after{flex-shrink:0;width:var(--hub-panels-accordion-btn-icon-width);height:var(--hub-panels-accordion-btn-icon-width);margin-left:auto;content:\"\";background-color:var(--hub-panels-accordion-icon-active-color);-webkit-mask-image:var(--hub-panels-accordion-btn-icon-mask);mask-image:var(--hub-panels-accordion-btn-icon-mask);-webkit-mask-repeat:no-repeat;mask-repeat:no-repeat;-webkit-mask-size:contain;mask-size:contain;-webkit-mask-position:center;mask-position:center;transform:var(--hub-panels-accordion-btn-icon-transform);transition:var(--hub-panels-accordion-btn-icon-transition)}.hub-panels__accordion-btn:not(.hub-panels__accordion-btn--collapsed){color:var(--hub-panels-accordion-active-color);background-color:var(--hub-panels-accordion-active-bg);box-shadow:inset 0 calc(-1 * var(--hub-panels-accordion-border-width)) 0 var(--hub-panels-accordion-border-color)}.hub-panels__accordion-btn--collapsed:after{background-color:var(--hub-panels-accordion-icon-color);transform:none}.hub-panels__accordion-btn:hover:not(:disabled){z-index:2}.hub-panels__accordion-btn:focus-visible{z-index:3;outline:0;box-shadow:var(--hub-panels-accordion-btn-focus-box-shadow)}.hub-panels__accordion-btn:disabled{color:var(--hub-panels-tab-color-disabled);cursor:not-allowed}.hub-panels__accordion-collapse{display:grid;grid-template-rows:1fr;transition:grid-template-rows var(--hub-panels-accordion-collapse-transition-duration) var(--hub-panels-accordion-collapse-transition-easing)}.hub-panels__accordion-collapse--collapsed{grid-template-rows:0fr}.hub-panels__accordion-collapse>.hub-panels__accordion-body{min-height:0;overflow:hidden;opacity:1;padding:var(--hub-panels-accordion-body-padding-y) var(--hub-panels-accordion-body-padding-x);transition:opacity var(--hub-panels-accordion-collapse-transition-duration) var(--hub-panels-accordion-collapse-transition-easing),padding var(--hub-panels-accordion-collapse-transition-duration) var(--hub-panels-accordion-collapse-transition-easing)}.hub-panels__accordion-collapse--collapsed>.hub-panels__accordion-body{opacity:0;padding-top:0;padding-bottom:0}.hub-panels--flush .hub-panels__panel--accordion{border-right:0;border-left:0;border-radius:0}.hub-panels--flush .hub-panels__panel--accordion:first-of-type{border-top:0}.hub-panels--flush .hub-panels__panel--accordion:last-of-type{border-bottom:0}.hub-panels--flush .hub-panels__panel--accordion>.hub-panels__accordion-collapse,.hub-panels--flush .hub-panels__panel--accordion>.hub-panels__accordion-header .hub-panels__accordion-btn{border-radius:0}\n"], dependencies: [{ kind: "directive", type: NgTemplateOutlet, selector: "[ngTemplateOutlet]", inputs: ["ngTemplateOutletContext", "ngTemplateOutlet", "ngTemplateOutletInjector"] }, { kind: "directive", type: RouterOutlet, selector: "router-outlet", inputs: ["name", "routerOutletData"], outputs: ["activate", "deactivate", "attach", "detach"], exportAs: ["outlet"] }], changeDetection: i0.ChangeDetectionStrategy.OnPush, encapsulation: i0.ViewEncapsulation.None });
|
|
742
|
+
}
|
|
743
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.0.1", ngImport: i0, type: PanelsComponent, decorators: [{
|
|
744
|
+
type: Component,
|
|
745
|
+
args: [{ selector: 'hub-panels', imports: [NgTemplateOutlet, RouterOutlet], encapsulation: ViewEncapsulation.None, changeDetection: ChangeDetectionStrategy.OnPush, providers: [
|
|
746
|
+
{
|
|
747
|
+
provide: NG_VALUE_ACCESSOR,
|
|
748
|
+
useExisting: forwardRef(() => PanelsComponent),
|
|
749
|
+
multi: true
|
|
750
|
+
}
|
|
751
|
+
], host: {
|
|
752
|
+
class: 'hub-panels',
|
|
753
|
+
'[class.hub-panels--tabs]': "type() === 'tabs'",
|
|
754
|
+
'[class.hub-panels--pills]': "type() === 'pills'",
|
|
755
|
+
'[class.hub-panels--card]': 'isCardView()',
|
|
756
|
+
'[class.hub-panels--vertical]': 'vertical() && !isAccordionView() && !isCardView()',
|
|
757
|
+
'[class.hub-panels--accordion]': 'isAccordionView()',
|
|
758
|
+
'[class.hub-panels--flush]': 'isAccordionView() && flush()',
|
|
759
|
+
'[class.hub-panels--multiple]': 'multiple()',
|
|
760
|
+
'(window:resize)': 'onWindowResize()'
|
|
761
|
+
}, template: "@if (!isAccordionView() && !isCardView()) {\n\t@if (multiple()) {\n\t\t<div class=\"hub-panels__multiple-layout\">\n\t\t\t@for (group of multipleHeaderGroups(); track group.activePanel ?? group.headers[0]) {\n\t\t\t\t<div\n\t\t\t\t\t#multipleBlock\n\t\t\t\t\tclass=\"hub-panels hub-panels__multiple-block\"\n\t\t\t\t\t[class.hub-panels--tabs]=\"type() === 'tabs'\"\n\t\t\t\t\t[class.hub-panels--pills]=\"type() === 'pills'\"\n\t\t\t\t\t[class.hub-panels--vertical]=\"vertical()\"\n\t\t\t\t>\n\t\t\t\t\t<div class=\"hub-panels__header\">\n\t\t\t\t\t\t<ul\n\t\t\t\t\t\t\tclass=\"hub-panels__nav\"\n\t\t\t\t\t\t\trole=\"tablist\"\n\t\t\t\t\t\t\t[attr.aria-label]=\"config.ariaLabel\"\n\t\t\t\t\t\t\t[attr.aria-orientation]=\"vertical() ? 'vertical' : null\"\n\t\t\t\t\t\t\t[class.hub-panels__nav--tabs]=\"type() === 'tabs'\"\n\t\t\t\t\t\t\t[class.hub-panels__nav--pills]=\"type() === 'pills'\"\n\t\t\t\t\t\t\t[class.hub-panels__nav--vertical]=\"vertical()\"\n\t\t\t\t\t\t\t[class.hub-panels__nav--justified]=\"justified()\"\n\t\t\t\t\t\t>\n\t\t\t\t\t\t\t@for (panel of group.headers; track panel) {\n\t\t\t\t\t\t\t\t<li\n\t\t\t\t\t\t\t\t\tclass=\"hub-panels__nav-item\"\n\t\t\t\t\t\t\t\t\t[class]=\"panel.customClass()\"\n\t\t\t\t\t\t\t\t\t[class.hub-panels__nav-item--active]=\"panel.active()\"\n\t\t\t\t\t\t\t\t\t[class.hub-panels__nav-item--disabled]=\"panel.disabled()\"\n\t\t\t\t\t\t\t\t>\n\t\t\t\t\t\t\t\t\t<button\n\t\t\t\t\t\t\t\t\t\ttype=\"button\"\n\t\t\t\t\t\t\t\t\t\tclass=\"hub-panels__nav-link\"\n\t\t\t\t\t\t\t\t\t\trole=\"tab\"\n\t\t\t\t\t\t\t\t\t\t[id]=\"panel.id() + '-link'\"\n\t\t\t\t\t\t\t\t\t\t[class.hub-panels__nav-link--active]=\"panel.active()\"\n\t\t\t\t\t\t\t\t\t\t[class.hub-panels__nav-link--disabled]=\"panel.disabled()\"\n\t\t\t\t\t\t\t\t\t\t[disabled]=\"panel.disabled() || formDisabled()\"\n\t\t\t\t\t\t\t\t\t\t[attr.aria-controls]=\"panel.id()\"\n\t\t\t\t\t\t\t\t\t\t[attr.aria-selected]=\"panel.active()\"\n\t\t\t\t\t\t\t\t\t\t[attr.tabindex]=\"panel.active() || (!activePanel() && panelIndex(panel) === 0) ? null : -1\"\n\t\t\t\t\t\t\t\t\t\t(click)=\"selectPanel(panel)\"\n\t\t\t\t\t\t\t\t\t\t(keydown)=\"onPanelKeydown($event, panelIndex(panel))\"\n\t\t\t\t\t\t\t\t\t>\n\t\t\t\t\t\t\t\t\t\t@if (panel.headingRef(); as headingRef) {\n\t\t\t\t\t\t\t\t\t\t\t<ng-container [ngTemplateOutlet]=\"headingRef\" />\n\t\t\t\t\t\t\t\t\t\t} @else {\n\t\t\t\t\t\t\t\t\t\t\t{{ panel.heading() }}\n\t\t\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t\t\t\t@if (panel.removable()) {\n\t\t\t\t\t\t\t\t\t\t\t<span\n\t\t\t\t\t\t\t\t\t\t\t\tclass=\"hub-panels__remove-btn\"\n\t\t\t\t\t\t\t\t\t\t\t\taria-hidden=\"true\"\n\t\t\t\t\t\t\t\t\t\t\t\t(click)=\"$event.stopPropagation(); removePanel(panel)\"\n\t\t\t\t\t\t\t\t\t\t\t\t>×</span\n\t\t\t\t\t\t\t\t\t\t\t>\n\t\t\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t\t\t</button>\n\t\t\t\t\t\t\t\t</li>\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t</ul>\n\t\t\t\t\t\t@if (!justified() && type() !== 'pills' && !vertical()) {\n\t\t\t\t\t\t\t<div class=\"hub-panels__spacer\"></div>\n\t\t\t\t\t\t}\n\t\t\t\t\t</div>\n\n\t\t\t\t\t@if (group.activePanel) {\n\t\t\t\t\t\t<div\n\t\t\t\t\t\t\tclass=\"hub-panels__content\"\n\t\t\t\t\t\t\t[class.hub-panels__content--pills]=\"type() === 'pills'\"\n\t\t\t\t\t\t>\n\t\t\t\t\t\t\t<div\n\t\t\t\t\t\t\t\t#multiplePaneHost\n\t\t\t\t\t\t\t\tclass=\"hub-panels__multiple-pane-host\"\n\t\t\t\t\t\t\t\t[attr.data-panel-id]=\"group.activePanel.id()\"\n\t\t\t\t\t\t\t></div>\n\t\t\t\t\t\t</div>\n\t\t\t\t\t}\n\t\t\t\t</div>\n\t\t\t}\n\t\t</div>\n\t} @else {\n\t\t<div class=\"hub-panels__header\">\n\t\t\t@if (scrollable() && !backwardIsDisabled()) {\n\t\t\t\t<button\n\t\t\t\t\t#prevBtn\n\t\t\t\t\ttype=\"button\"\n\t\t\t\t\tclass=\"hub-panels__scroll-btn hub-panels__scroll-btn--backward\"\n\t\t\t\t\t[attr.aria-label]=\"config.scrollBackwardAriaLabel\"\n\t\t\t\t\t(click)=\"navBackward()\"\n\t\t\t\t></button>\n\t\t\t}\n\n\t\t\t<div #navScroller class=\"hub-panels__nav-scroller\" (scroll)=\"onScroll()\">\n\t\t\t\t<ul\n\t\t\t\t\tclass=\"hub-panels__nav\"\n\t\t\t\t\trole=\"tablist\"\n\t\t\t\t\t[attr.aria-label]=\"config.ariaLabel\"\n\t\t\t\t\t[attr.aria-orientation]=\"vertical() ? 'vertical' : null\"\n\t\t\t\t\t[class.hub-panels__nav--tabs]=\"type() === 'tabs'\"\n\t\t\t\t\t[class.hub-panels__nav--pills]=\"type() === 'pills'\"\n\t\t\t\t\t[class.hub-panels__nav--vertical]=\"vertical()\"\n\t\t\t\t\t[class.hub-panels__nav--justified]=\"justified()\"\n\t\t\t\t>\n\t\t\t\t\t@for (panel of panels(); track panel; let index = $index) {\n\t\t\t\t\t\t<li\n\t\t\t\t\t\t\tclass=\"hub-panels__nav-item\"\n\t\t\t\t\t\t\t[class]=\"panel.customClass()\"\n\t\t\t\t\t\t\t[class.hub-panels__nav-item--active]=\"panel.active()\"\n\t\t\t\t\t\t\t[class.hub-panels__nav-item--disabled]=\"panel.disabled()\"\n\t\t\t\t\t\t>\n\t\t\t\t\t\t\t<button\n\t\t\t\t\t\t\t\ttype=\"button\"\n\t\t\t\t\t\t\t\tclass=\"hub-panels__nav-link\"\n\t\t\t\t\t\t\t\trole=\"tab\"\n\t\t\t\t\t\t\t\t[id]=\"panel.id() + '-link'\"\n\t\t\t\t\t\t\t\t[class.hub-panels__nav-link--active]=\"panel.active()\"\n\t\t\t\t\t\t\t\t[class.hub-panels__nav-link--disabled]=\"panel.disabled()\"\n\t\t\t\t\t\t\t\t[disabled]=\"panel.disabled() || formDisabled()\"\n\t\t\t\t\t\t\t\t[attr.aria-controls]=\"panel.id()\"\n\t\t\t\t\t\t\t\t[attr.aria-selected]=\"panel.active()\"\n\t\t\t\t\t\t\t\t[attr.tabindex]=\"panel.active() || (!activePanel() && index === 0) ? null : -1\"\n\t\t\t\t\t\t\t\t(click)=\"selectPanel(panel)\"\n\t\t\t\t\t\t\t\t(keydown)=\"onPanelKeydown($event, index)\"\n\t\t\t\t\t\t\t>\n\t\t\t\t\t\t\t\t@if (panel.headingRef(); as headingRef) {\n\t\t\t\t\t\t\t\t\t<ng-container [ngTemplateOutlet]=\"headingRef\" />\n\t\t\t\t\t\t\t\t} @else {\n\t\t\t\t\t\t\t\t\t{{ panel.heading() }}\n\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t\t@if (panel.removable()) {\n\t\t\t\t\t\t\t\t\t<span\n\t\t\t\t\t\t\t\t\t\tclass=\"hub-panels__remove-btn\"\n\t\t\t\t\t\t\t\t\t\taria-hidden=\"true\"\n\t\t\t\t\t\t\t\t\t\t(click)=\"$event.stopPropagation(); removePanel(panel)\"\n\t\t\t\t\t\t\t\t\t\t>×</span\n\t\t\t\t\t\t\t\t\t>\n\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t</button>\n\t\t\t\t\t\t</li>\n\t\t\t\t\t}\n\t\t\t\t</ul>\n\t\t\t\t@if (!justified() && type() !== 'pills') {\n\t\t\t\t\t<div class=\"hub-panels__spacer\"></div>\n\t\t\t\t}\n\t\t\t</div>\n\n\t\t\t@if (scrollable() && !forwardIsDisabled()) {\n\t\t\t\t<button\n\t\t\t\t\t#nextBtn\n\t\t\t\t\ttype=\"button\"\n\t\t\t\t\tclass=\"hub-panels__scroll-btn hub-panels__scroll-btn--forward\"\n\t\t\t\t\t[attr.aria-label]=\"config.scrollForwardAriaLabel\"\n\t\t\t\t\t(click)=\"navForward()\"\n\t\t\t\t></button>\n\t\t\t}\n\t\t</div>\n\t}\n}\n\n<div\n\t#contentRoot\n\tclass=\"hub-panels__content\"\n\t[class.hub-panels__content--pills]=\"type() === 'pills'\"\n\t[class.hub-panels__content--accordion]=\"isAccordionView()\"\n\t[class.hub-panels__content--multiple-parking]=\"!isAccordionView() && multiple()\"\n>\n\t@if (activePanelHasRouter()) {\n\t\t<router-outlet />\n\t} @else {\n\t\t<ng-content />\n\t}\n</div>\n", styles: [":where(.hub-panels){--hub-panels-flex-direction: row;--hub-panels-border-width: var(--hub-ref-border-width, 1px);--hub-panels-border-color: var(--hub-sys-border-color-default, #dee2e6);--hub-panels-border-radius: var(--hub-ref-radius-md, .375rem);--hub-panels-content-bg: var(--hub-sys-surface-page, #fff);--hub-panels-header-bg: var(--hub-panels-content-bg);--hub-panels-content-box-shadow: none;--hub-panels-content-padding-x: var(--hub-ref-space-3, 1rem);--hub-panels-content-padding-y: var(--hub-ref-space-3, 1rem);--hub-panels-nav-btn-width: 1.5rem;--hub-panels-nav-btn-height: 1.5rem;--hub-panels-backward-btn-bg: url(\"data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 16 16'%3E%3Cpath fill='%23212529' d='M11.354 1.646a.5.5 0 0 1 0 .708L5.707 8l5.647 5.646a.5.5 0 0 1-.708.708l-6-6a.5.5 0 0 1 0-.708l6-6a.5.5 0 0 1 .708 0z'/%3E%3C/svg%3E\");--hub-panels-forward-btn-bg: url(\"data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 16 16'%3E%3Cpath fill='%23212529' d='M4.646 1.646a.5.5 0 0 1 .708 0l6 6a.5.5 0 0 1 0 .708l-6 6a.5.5 0 0 1-.708-.708L10.293 8 4.646 2.354a.5.5 0 0 1 0-.708z'/%3E%3C/svg%3E\");--hub-panels-nav-link-padding-x: var(--hub-ref-space-3, 1rem);--hub-panels-nav-link-padding-y: var(--hub-ref-space-2, .5rem);--hub-panels-nav-link-color: var(--hub-sys-text-primary, #212529);--hub-panels-nav-link-hover-color: var(--hub-sys-color-primary-emphasis, #0a58ca);--hub-panels-nav-link-active-color: var(--hub-sys-color-primary, #0d6efd);--hub-panels-nav-link-active-bg: var(--hub-panels-content-bg);--hub-panels-nav-link-disabled-color: var(--hub-sys-text-muted, #6c757d);--hub-panels-tab-font-family: var(--hub-container-font-family, var(--hub-ref-font-family-base));--hub-panels-tab-font-size: var(--hub-container-font-size, var(--hub-ref-font-size-base, 1rem));--hub-panels-tab-font-weight: 500;--hub-panels-tab-line-height: var(--hub-ref-line-height-base, 1.5);--hub-panels-tab-padding-x: var(--hub-panels-nav-link-padding-x);--hub-panels-tab-padding-y: var(--hub-panels-nav-link-padding-y);--hub-panels-tab-gap: var(--hub-ref-space-2, .5rem);--hub-panels-tab-bg: transparent;--hub-panels-tab-color: var(--hub-panels-nav-link-color);--hub-panels-tab-border-width: var(--hub-panels-border-width);--hub-panels-tab-border-style: solid;--hub-panels-tab-border-color: transparent;--hub-panels-tab-border-radius: var(--hub-panels-border-radius);--hub-panels-tab-bg-hover: var(--hub-ref-surface-2, #f8f9fa);--hub-panels-tab-color-hover: var(--hub-panels-nav-link-hover-color);--hub-panels-tab-bg-active: var(--hub-panels-nav-link-active-bg);--hub-panels-tab-color-active: var(--hub-panels-nav-link-active-color);--hub-panels-tab-border-color-active: var(--hub-sys-color-primary, #0d6efd);--hub-panels-tab-bg-disabled: transparent;--hub-panels-tab-color-disabled: var(--hub-panels-nav-link-disabled-color);--hub-panels-tab-focus-ring-width: var(--hub-sys-focus-ring-width, .25rem);--hub-panels-tab-focus-ring-color: var(--hub-sys-focus-ring-color, rgba(13, 110, 253, .25));--hub-panels-tab-transition: var(--hub-sys-transition-base, all .2s ease-in-out);--hub-panels-tab-active-shadow: 0 -.25rem .5rem rgba(0, 0, 0, .06);--hub-panels-tab-active-shadow-vertical: -.25rem 0 .5rem rgba(0, 0, 0, .06);--hub-panels-strip-margin-top: var(--hub-ref-space-2, .5rem);--hub-panels-nav-gap: 0;--hub-panels-pill-border-radius: 50rem;--hub-panels-pill-bg-active: var(--hub-sys-color-primary, #0d6efd);--hub-panels-pill-color-active: var(--hub-ref-color-white, #fff);--hub-panels-pill-gap: var(--hub-ref-space-2, .5rem);--hub-panels-pill-content-border-width: 0;--hub-panels-remove-btn-opacity: .6;--hub-panels-remove-btn-opacity-hover: 1;--hub-panels-nav-content-gap: var(--hub-ref-space-2, .5rem);--hub-panels-pane-min-width: 16rem;--hub-panels-pane-min-height: 8rem;--hub-panels-pane-gap: 0;--hub-panels-card-gap: var(--hub-ref-space-3, 1rem);--hub-panels-accordion-color: var(--hub-accordion-color, var(--hub-sys-text-primary, #212529));--hub-panels-accordion-bg: var(--hub-accordion-bg, var(--hub-sys-surface-page, #fff));--hub-panels-accordion-border-width: var(--hub-accordion-border-width, var(--hub-ref-border-width, 1px));--hub-panels-accordion-border-color: var(--hub-accordion-border-color, var(--hub-sys-border-color-default, #dee2e6));--hub-panels-accordion-border-radius: var(--hub-accordion-border-radius, var(--hub-ref-radius-sm, .25rem));--hub-panels-accordion-inner-border-radius: var( --hub-accordion-inner-border-radius, calc(var(--hub-panels-accordion-border-radius) - var(--hub-panels-accordion-border-width)) );--hub-panels-accordion-btn-padding-x: var(--hub-accordion-btn-padding-x, 1.25rem);--hub-panels-accordion-btn-padding-y: var(--hub-accordion-btn-padding-y, var(--hub-ref-space-3, 1rem));--hub-panels-accordion-btn-color: var(--hub-accordion-btn-color, var(--hub-sys-text-primary, #212529));--hub-panels-accordion-btn-bg: var(--hub-accordion-btn-bg, var(--hub-sys-surface-page, #fff));--hub-panels-accordion-active-color: var(--hub-accordion-active-color, var(--hub-sys-color-primary, #0c63e4));--hub-panels-accordion-active-bg: var(--hub-accordion-active-bg, var(--hub-sys-color-primary-subtle, #e7f1ff));--hub-panels-accordion-icon-color: var(--hub-accordion-icon-color, var(--hub-panels-accordion-btn-color));--hub-panels-accordion-icon-active-color: var(--hub-accordion-icon-active-color, var(--hub-panels-accordion-active-color));--hub-panels-accordion-btn-icon-mask: var(--hub-accordion-btn-icon-mask, url(\"data:image/svg+xml;charset=UTF-8,%3Csvg viewBox='0 0 16 16' xmlns='http://www.w3.org/2000/svg'%3E%3Cpath fill='%23000' fill-rule='evenodd' d='M1.646 4.646a.5.5 0 0 1 .708 0L8 10.293l5.646-5.647a.5.5 0 0 1 .708.708l-6 6a.5.5 0 0 1-.708 0l-6-6a.5.5 0 0 1 0-.708z'/%3E%3C/svg%3E\"));--hub-panels-accordion-btn-icon-width: var(--hub-accordion-btn-icon-width, 1.25rem);--hub-panels-accordion-btn-icon-transform: var(--hub-accordion-btn-icon-transform, rotate(-180deg));--hub-panels-accordion-btn-icon-transition: var(--hub-accordion-btn-icon-transition, transform .2s ease-in-out);--hub-panels-accordion-btn-focus-box-shadow: var( --hub-accordion-btn-focus-box-shadow, 0 0 0 var(--hub-sys-focus-ring-width, .25rem) var(--hub-sys-focus-ring-color, rgba(13, 110, 253, .25)) );--hub-panels-accordion-transition: var( --hub-accordion-transition, color .15s ease-in-out, background-color .15s ease-in-out, border-color .15s ease-in-out, box-shadow .15s ease-in-out, border-radius .15s ease );--hub-panels-accordion-collapse-transition-duration: var(--hub-accordion-collapse-transition-duration, .25s);--hub-panels-accordion-collapse-transition-easing: var( --hub-accordion-collapse-transition-easing, cubic-bezier(.4, 0, .2, 1) );--hub-panels-accordion-body-padding-x: var(--hub-accordion-body-padding-x, 1.25rem);--hub-panels-accordion-body-padding-y: var(--hub-accordion-body-padding-y, var(--hub-ref-space-3, 1rem))}\n", ".hub-panels{display:block;width:100%;box-sizing:border-box}.hub-panels,.hub-panels *,.hub-panels *:before,.hub-panels *:after{box-sizing:border-box}.hub-panels__header{display:flex;flex-direction:var(--hub-panels-flex-direction);align-items:stretch;background:var(--hub-panels-header-bg)}.hub-panels__scroll-btn{flex:0 0 auto;align-self:center;width:var(--hub-panels-nav-btn-width);height:var(--hub-panels-nav-btn-height);padding:0;border:0;cursor:pointer;background-color:transparent;background-position:center;background-repeat:no-repeat;background-size:1rem 1rem}.hub-panels__scroll-btn--backward{background-image:var(--hub-panels-backward-btn-bg)}.hub-panels__scroll-btn--forward{background-image:var(--hub-panels-forward-btn-bg)}.hub-panels__nav-scroller{display:flex;flex:1 1 auto;overflow-x:auto;background:var(--hub-panels-header-bg);scroll-behavior:smooth;scrollbar-width:none}.hub-panels__nav-scroller::-webkit-scrollbar{display:none}.hub-panels__nav{display:flex;flex:0 0 auto;flex-wrap:nowrap;gap:var(--hub-panels-nav-gap);margin:0;padding:0;list-style:none}.hub-panels__nav--tabs{border-bottom:var(--hub-panels-border-width) solid var(--hub-panels-border-color)}.hub-panels__nav--tabs .hub-panels__nav-link{margin-bottom:calc(-1 * var(--hub-panels-border-width))}.hub-panels__nav--pills{gap:var(--hub-panels-pill-gap)}.hub-panels__nav--pills .hub-panels__nav-link{border-radius:var(--hub-panels-pill-border-radius)}.hub-panels__nav--pills .hub-panels__nav-link--active{color:var(--hub-panels-pill-color-active);background:var(--hub-panels-pill-bg-active);border-color:transparent}.hub-panels__nav--justified{flex:1 1 auto}.hub-panels__nav--justified .hub-panels__nav-item{flex:1 1 0}.hub-panels__nav--justified .hub-panels__nav-link{width:100%;justify-content:center}.hub-panels__nav--vertical{flex-direction:column}.hub-panels__nav--vertical.hub-panels__nav--tabs{border-bottom:0;border-inline-end:var(--hub-panels-border-width) solid var(--hub-panels-border-color)}.hub-panels__nav--vertical.hub-panels__nav--tabs .hub-panels__nav-link{margin-bottom:0;margin-inline-end:calc(-1 * var(--hub-panels-border-width))}.hub-panels__nav-item{display:flex;flex:0 0 auto}.hub-panels__nav-link{position:relative;display:inline-flex;align-items:center;gap:var(--hub-panels-tab-gap);padding:var(--hub-panels-tab-padding-y) var(--hub-panels-tab-padding-x);font-family:var(--hub-panels-tab-font-family);font-size:var(--hub-panels-tab-font-size);font-weight:var(--hub-panels-tab-font-weight);line-height:var(--hub-panels-tab-line-height);white-space:nowrap;color:var(--hub-panels-tab-color);background:var(--hub-panels-tab-bg);border-style:var(--hub-panels-tab-border-style);border-width:var(--hub-panels-tab-border-width);border-color:var(--hub-panels-tab-border-color);border-start-start-radius:var(--hub-panels-tab-border-radius);border-start-end-radius:var(--hub-panels-tab-border-radius);cursor:pointer;transition:var(--hub-panels-tab-transition)}.hub-panels__nav-link:hover:not(:disabled):not(.hub-panels__nav-link--active){color:var(--hub-panels-tab-color-hover);background:var(--hub-panels-tab-bg-hover)}.hub-panels__nav-link:focus-visible{z-index:1;outline:0;box-shadow:0 0 0 var(--hub-panels-tab-focus-ring-width) var(--hub-panels-tab-focus-ring-color)}.hub-panels__nav-link--active{color:var(--hub-panels-tab-color-active);background:var(--hub-panels-tab-bg-active);border-color:var(--hub-panels-tab-border-color-active)}.hub-panels__nav-link:disabled{color:var(--hub-panels-tab-color-disabled);background:var(--hub-panels-tab-bg-disabled);cursor:not-allowed}.hub-panels__remove-btn{display:inline-flex;align-items:center;line-height:1;opacity:var(--hub-panels-remove-btn-opacity)}.hub-panels__remove-btn:hover{opacity:var(--hub-panels-remove-btn-opacity-hover)}.hub-panels__spacer{flex:1 1 auto;background:var(--hub-panels-header-bg);border-bottom:var(--hub-panels-border-width) solid var(--hub-panels-border-color)}.hub-panels__content{padding:var(--hub-panels-content-padding-y) var(--hub-panels-content-padding-x);background:var(--hub-panels-content-bg);box-shadow:var(--hub-panels-content-box-shadow)}.hub-panels__content--accordion{padding:0;background:transparent;box-shadow:none}.hub-panels__content--multiple-parking{display:none}.hub-panels__multiple-layout{display:flex;align-items:stretch;gap:var(--hub-panels-pane-gap);overflow-x:auto;overflow-y:hidden;scroll-behavior:smooth}.hub-panels__multiple-block{display:flex;flex-direction:column;flex:1 0 var(--hub-panels-pane-min-width);align-self:stretch;min-width:var(--hub-panels-pane-min-width);min-height:100%}.hub-panels__multiple-block.hub-panels--vertical{flex-direction:row;flex:1 1 auto;width:100%;min-width:100%;min-height:var(--hub-panels-pane-min-height)}.hub-panels__multiple-block>.hub-panels__content{display:flex;flex:1 1 auto;min-height:0}.hub-panels__multiple-block.hub-panels--vertical>.hub-panels__content{flex:1 1 auto;width:auto;min-width:max(var(--hub-panels-pane-min-width),var(--hub-panels-multiple-vertical-panel-min-width, 0px))}.hub-panels__multiple-pane-host{display:flex;flex:1 1 auto;width:100%;min-height:0}.hub-panels__multiple-pane-host>.hub-panels__panel{flex:1 1 auto;width:100%;height:100%}.hub-panels__multiple-pane-host>.hub-panels__panel.hub-panels__panel--active{display:flex;flex-direction:column}.hub-panels__multiple-pane-host>.hub-panels__panel.hub-panels__panel--active>div{flex:1 1 auto;min-height:0}.hub-panels--vertical.hub-panels--multiple>.hub-panels__multiple-layout{flex-direction:column;align-items:stretch;width:100%}.hub-panels--pills.hub-panels--multiple.hub-panels--vertical>.hub-panels__multiple-layout>.hub-panels__multiple-block+.hub-panels__multiple-block{padding-top:var(--hub-panels-nav-content-gap);border-top:var(--hub-panels-border-width) solid var(--hub-panels-border-color)}.hub-panels__panel{display:none}.hub-panels__panel--active{display:block}.hub-panels--tabs:not(.hub-panels--vertical):not(.hub-panels--multiple)>.hub-panels__header{margin-top:var(--hub-panels-strip-margin-top)}.hub-panels--tabs:not(.hub-panels--vertical):not(.hub-panels--multiple)>.hub-panels__content{border:var(--hub-panels-border-width) solid var(--hub-panels-border-color);border-top:0;border-end-start-radius:var(--hub-panels-border-radius);border-end-end-radius:var(--hub-panels-border-radius)}.hub-panels--tabs:not(.hub-panels--vertical):not(.hub-panels--multiple) .hub-panels__nav--tabs .hub-panels__nav-link--active{border-color:var(--hub-panels-border-color);border-bottom-color:var(--hub-panels-tab-bg-active);box-shadow:var(--hub-panels-tab-active-shadow)}.hub-panels--pills>.hub-panels__header{margin-bottom:var(--hub-panels-nav-content-gap)}.hub-panels--pills>.hub-panels__content{border:var(--hub-panels-pill-content-border-width) solid var(--hub-panels-border-color);border-radius:var(--hub-panels-border-radius)}.hub-panels--vertical{display:flex;align-items:stretch}.hub-panels--vertical .hub-panels__header{flex-direction:column}.hub-panels--vertical .hub-panels__nav-scroller{overflow:visible}.hub-panels--vertical .hub-panels__content{flex:1 1 auto;min-width:0}.hub-panels--tabs.hub-panels--vertical:not(.hub-panels--multiple)>.hub-panels__header{margin-inline-start:var(--hub-panels-strip-margin-top);align-self:stretch;min-height:0}.hub-panels--tabs.hub-panels--vertical:not(.hub-panels--multiple) .hub-panels__spacer{display:none}.hub-panels--tabs.hub-panels--vertical:not(.hub-panels--multiple) .hub-panels__nav-scroller{flex:1 1 auto;align-self:stretch;min-height:100%}.hub-panels--tabs.hub-panels--vertical:not(.hub-panels--multiple) .hub-panels__nav--vertical{flex:1 1 auto;align-self:stretch;min-height:100%}.hub-panels--tabs.hub-panels--vertical:not(.hub-panels--multiple) .hub-panels__nav--vertical .hub-panels__nav-item{width:100%}.hub-panels--tabs.hub-panels--vertical:not(.hub-panels--multiple) .hub-panels__nav--vertical .hub-panels__nav-link{width:calc(100% + var(--hub-panels-border-width));justify-content:flex-start;margin-bottom:0;border-start-start-radius:var(--hub-panels-tab-border-radius);border-start-end-radius:0;border-end-start-radius:var(--hub-panels-tab-border-radius);border-end-end-radius:0;margin-inline-end:calc(-1 * var(--hub-panels-border-width))}.hub-panels--tabs.hub-panels--vertical:not(.hub-panels--multiple)>.hub-panels__content{border:var(--hub-panels-border-width) solid var(--hub-panels-border-color);border-inline-start:0;border-start-end-radius:var(--hub-panels-border-radius);border-end-end-radius:var(--hub-panels-border-radius)}.hub-panels--tabs.hub-panels--vertical:not(.hub-panels--multiple) .hub-panels__nav--tabs .hub-panels__nav-link--active{z-index:1;border-color:var(--hub-panels-border-color);border-inline-end-color:var(--hub-panels-tab-bg-active);box-shadow:var(--hub-panels-tab-active-shadow-vertical)}.hub-panels--pills.hub-panels--vertical>.hub-panels__header{margin-bottom:0;margin-inline-end:var(--hub-panels-nav-content-gap)}.hub-panels--card{display:flex}.hub-panels--card>.hub-panels__content{display:flex;flex-direction:column;gap:var(--hub-panels-card-gap, var(--hub-ref-space-3, 1rem));width:100%;padding:0;background:transparent;box-shadow:none}\n", ".hub-panels__panel--accordion{display:block;color:var(--hub-panels-accordion-color);background-color:var(--hub-panels-accordion-bg);border:var(--hub-panels-accordion-border-width) solid var(--hub-panels-accordion-border-color)}.hub-panels__panel--accordion:not(:first-of-type){border-top:0}.hub-panels__panel--accordion:first-of-type{border-start-start-radius:var(--hub-panels-accordion-border-radius);border-start-end-radius:var(--hub-panels-accordion-border-radius)}.hub-panels__panel--accordion:first-of-type>.hub-panels__accordion-header .hub-panels__accordion-btn{border-start-start-radius:var(--hub-panels-accordion-inner-border-radius);border-start-end-radius:var(--hub-panels-accordion-inner-border-radius)}.hub-panels__panel--accordion:last-of-type{border-end-start-radius:var(--hub-panels-accordion-border-radius);border-end-end-radius:var(--hub-panels-accordion-border-radius)}.hub-panels__panel--accordion:last-of-type>.hub-panels__accordion-header .hub-panels__accordion-btn--collapsed{border-end-start-radius:var(--hub-panels-accordion-inner-border-radius);border-end-end-radius:var(--hub-panels-accordion-inner-border-radius)}.hub-panels__panel--accordion:last-of-type>.hub-panels__accordion-collapse{border-end-start-radius:var(--hub-panels-accordion-border-radius);border-end-end-radius:var(--hub-panels-accordion-border-radius)}.hub-panels__accordion-header{margin:0}.hub-panels__accordion-btn{position:relative;display:flex;align-items:center;width:100%;gap:var(--hub-panels-tab-gap);padding:var(--hub-panels-accordion-btn-padding-y) var(--hub-panels-accordion-btn-padding-x);font-family:var(--hub-panels-tab-font-family);font-size:var(--hub-panels-tab-font-size);line-height:var(--hub-panels-tab-line-height);text-align:left;color:var(--hub-panels-accordion-btn-color);background-color:var(--hub-panels-accordion-btn-bg);border:0;border-radius:0;overflow-anchor:none;transition:var(--hub-panels-accordion-transition);cursor:pointer}.hub-panels__accordion-btn:after{flex-shrink:0;width:var(--hub-panels-accordion-btn-icon-width);height:var(--hub-panels-accordion-btn-icon-width);margin-left:auto;content:\"\";background-color:var(--hub-panels-accordion-icon-active-color);-webkit-mask-image:var(--hub-panels-accordion-btn-icon-mask);mask-image:var(--hub-panels-accordion-btn-icon-mask);-webkit-mask-repeat:no-repeat;mask-repeat:no-repeat;-webkit-mask-size:contain;mask-size:contain;-webkit-mask-position:center;mask-position:center;transform:var(--hub-panels-accordion-btn-icon-transform);transition:var(--hub-panels-accordion-btn-icon-transition)}.hub-panels__accordion-btn:not(.hub-panels__accordion-btn--collapsed){color:var(--hub-panels-accordion-active-color);background-color:var(--hub-panels-accordion-active-bg);box-shadow:inset 0 calc(-1 * var(--hub-panels-accordion-border-width)) 0 var(--hub-panels-accordion-border-color)}.hub-panels__accordion-btn--collapsed:after{background-color:var(--hub-panels-accordion-icon-color);transform:none}.hub-panels__accordion-btn:hover:not(:disabled){z-index:2}.hub-panels__accordion-btn:focus-visible{z-index:3;outline:0;box-shadow:var(--hub-panels-accordion-btn-focus-box-shadow)}.hub-panels__accordion-btn:disabled{color:var(--hub-panels-tab-color-disabled);cursor:not-allowed}.hub-panels__accordion-collapse{display:grid;grid-template-rows:1fr;transition:grid-template-rows var(--hub-panels-accordion-collapse-transition-duration) var(--hub-panels-accordion-collapse-transition-easing)}.hub-panels__accordion-collapse--collapsed{grid-template-rows:0fr}.hub-panels__accordion-collapse>.hub-panels__accordion-body{min-height:0;overflow:hidden;opacity:1;padding:var(--hub-panels-accordion-body-padding-y) var(--hub-panels-accordion-body-padding-x);transition:opacity var(--hub-panels-accordion-collapse-transition-duration) var(--hub-panels-accordion-collapse-transition-easing),padding var(--hub-panels-accordion-collapse-transition-duration) var(--hub-panels-accordion-collapse-transition-easing)}.hub-panels__accordion-collapse--collapsed>.hub-panels__accordion-body{opacity:0;padding-top:0;padding-bottom:0}.hub-panels--flush .hub-panels__panel--accordion{border-right:0;border-left:0;border-radius:0}.hub-panels--flush .hub-panels__panel--accordion:first-of-type{border-top:0}.hub-panels--flush .hub-panels__panel--accordion:last-of-type{border-bottom:0}.hub-panels--flush .hub-panels__panel--accordion>.hub-panels__accordion-collapse,.hub-panels--flush .hub-panels__panel--accordion>.hub-panels__accordion-header .hub-panels__accordion-btn{border-radius:0}\n"] }]
|
|
762
|
+
}], ctorParameters: () => [], propDecorators: { navScroller: [{ type: i0.ViewChild, args: ['navScroller', { isSignal: true }] }], prevBtn: [{ type: i0.ViewChild, args: ['prevBtn', { isSignal: true }] }], nextBtn: [{ type: i0.ViewChild, args: ['nextBtn', { isSignal: true }] }], contentRoot: [{ type: i0.ViewChild, args: ['contentRoot', { isSignal: true }] }], multiplePaneHosts: [{ type: i0.ViewChildren, args: ['multiplePaneHost', { isSignal: true }] }], multipleBlocks: [{ type: i0.ViewChildren, args: ['multipleBlock', { isSignal: true }] }], panelChange: [{ type: i0.Output, args: ["panelChange"] }], vertical: [{ type: i0.Input, args: [{ isSignal: true, alias: "vertical", required: false }] }], justified: [{ type: i0.Input, args: [{ isSignal: true, alias: "justified", required: false }] }], type: [{ type: i0.Input, args: [{ isSignal: true, alias: "type", required: false }] }], isKeysAllowed: [{ type: i0.Input, args: [{ isSignal: true, alias: "isKeysAllowed", required: false }] }], scrollable: [{ type: i0.Input, args: [{ isSignal: true, alias: "scrollable", required: false }] }], multiple: [{ type: i0.Input, args: [{ isSignal: true, alias: "multiple", required: false }] }], flush: [{ type: i0.Input, args: [{ isSignal: true, alias: "flush", required: false }] }], bindValue: [{ type: i0.Input, args: [{ isSignal: true, alias: "bindValue", required: false }] }], compareWith: [{ type: i0.Input, args: [{ isSignal: true, alias: "compareWith", required: false }] }] } });
|
|
763
|
+
|
|
764
|
+
/** Monotonic counter backing the auto-generated accessibility ids. */
|
|
765
|
+
let nextPanelId = 0;
|
|
766
|
+
/**
|
|
767
|
+
* One content panel inside a `<hub-panels>` container.
|
|
768
|
+
*
|
|
769
|
+
* In the `tabs` / `pills` views the host element is the tab *panel*
|
|
770
|
+
* (`role="tabpanel"`) and the clickable header is rendered by
|
|
771
|
+
* {@link PanelsComponent} in the strip. In the `accordion` view this component
|
|
772
|
+
* renders its own disclosure header plus an animated collapse wrapper around
|
|
773
|
+
* the projected content. In every view the header comes from `heading` or from
|
|
774
|
+
* a `<ng-template hubPanelHeading>` projected inside this element.
|
|
775
|
+
*
|
|
776
|
+
* Panels can be plain content panes or routed: when `routerLink` is set, the
|
|
777
|
+
* container renders a `<router-outlet>` instead of the projected panels and
|
|
778
|
+
* the active panel follows the current URL (`tabs` / `pills` views only).
|
|
779
|
+
*
|
|
780
|
+
* @example
|
|
781
|
+
* ```html
|
|
782
|
+
* <hub-panels>
|
|
783
|
+
* <hub-panel heading="Fields">…</hub-panel>
|
|
784
|
+
* <hub-panel>
|
|
785
|
+
* <ng-template hubPanelHeading>Validations <span class="badge">3</span></ng-template>
|
|
786
|
+
* …
|
|
787
|
+
* </hub-panel>
|
|
788
|
+
* </hub-panels>
|
|
789
|
+
* ```
|
|
790
|
+
*/
|
|
791
|
+
class PanelComponent {
|
|
792
|
+
/** Host element reference — exposed so the container can detach removed panes. */
|
|
793
|
+
elementRef = inject(ElementRef);
|
|
794
|
+
#renderer = inject(Renderer2);
|
|
795
|
+
#router = inject(Router);
|
|
796
|
+
/**
|
|
797
|
+
* Owning panels container, or `null` when the panel is used standalone
|
|
798
|
+
* (outside any `<hub-panels>`), in which case it renders as a card.
|
|
799
|
+
* Exposed to the template for the accordion header.
|
|
800
|
+
*/
|
|
801
|
+
tabset = inject(PanelsComponent, { optional: true });
|
|
802
|
+
/** Plain-text panel header. Ignored when a `hubPanelHeading` template exists. */
|
|
803
|
+
heading = input(undefined, /* @ts-ignore */
|
|
804
|
+
...(ngDevMode ? [{ debugName: "heading" }] : /* istanbul ignore next */ []));
|
|
805
|
+
/**
|
|
806
|
+
* Unique id used for the `tab` / `tabpanel` (or accordion header / region)
|
|
807
|
+
* ARIA pairing. Auto-generated (`hub-panel-<n>`) when not provided.
|
|
808
|
+
*/
|
|
809
|
+
id = input(`hub-panel-${nextPanelId++}`, /* @ts-ignore */
|
|
810
|
+
...(ngDevMode ? [{ debugName: "id" }] : /* istanbul ignore next */ []));
|
|
811
|
+
/** Whether the panel cannot be activated. */
|
|
812
|
+
disabled = input(false, { ...(ngDevMode ? { debugName: "disabled" } : /* istanbul ignore next */ {}), transform: booleanAttribute });
|
|
813
|
+
/** Whether the panel shows a remove affordance (✕ and the Delete key). */
|
|
814
|
+
removable = input(false, { ...(ngDevMode ? { debugName: "removable" } : /* istanbul ignore next */ {}), transform: booleanAttribute });
|
|
815
|
+
/**
|
|
816
|
+
* URL comparison used to mark routed panels active: `'route'` compares the
|
|
817
|
+
* path only, `'full'` also compares query params.
|
|
818
|
+
*/
|
|
819
|
+
pathMatch = input('route', /* @ts-ignore */
|
|
820
|
+
...(ngDevMode ? [{ debugName: "pathMatch" }] : /* istanbul ignore next */ []));
|
|
821
|
+
/** Navigation target that turns this panel into a routed panel. */
|
|
822
|
+
routerLink = input(undefined, /* @ts-ignore */
|
|
823
|
+
...(ngDevMode ? [{ debugName: "routerLink" }] : /* istanbul ignore next */ []));
|
|
824
|
+
/** Query params appended when navigating to `routerLink`. */
|
|
825
|
+
queryParams = input(undefined, /* @ts-ignore */
|
|
826
|
+
...(ngDevMode ? [{ debugName: "queryParams" }] : /* istanbul ignore next */ []));
|
|
827
|
+
/** Extra CSS classes applied to both the nav item and this pane. */
|
|
828
|
+
customClass = input(undefined, /* @ts-ignore */
|
|
829
|
+
...(ngDevMode ? [{ debugName: "customClass" }] : /* istanbul ignore next */ []));
|
|
830
|
+
/**
|
|
831
|
+
* Value this panel contributes when the container is used as a form control
|
|
832
|
+
* (see {@link PanelsComponent} `ControlValueAccessor`). Defaults to `id`.
|
|
833
|
+
*/
|
|
834
|
+
value = input(undefined, /* @ts-ignore */
|
|
835
|
+
...(ngDevMode ? [{ debugName: "value" }] : /* istanbul ignore next */ []));
|
|
836
|
+
/** Whether the panel is currently active (expanded, in the accordion view). */
|
|
837
|
+
active = model(false, /* @ts-ignore */
|
|
838
|
+
...(ngDevMode ? [{ debugName: "active" }] : /* istanbul ignore next */ []));
|
|
839
|
+
/** Emitted when the panel becomes active. */
|
|
840
|
+
selectPanel = output();
|
|
841
|
+
/** Emitted when the panel stops being active. */
|
|
842
|
+
deselectPanel = output();
|
|
843
|
+
/** Emitted when the panel is removed through the ✕ button or the Delete key. */
|
|
844
|
+
removed = output();
|
|
845
|
+
/** Custom header template registered by `PanelHeadingDirective`. */
|
|
846
|
+
headingRef = signal(undefined, /* @ts-ignore */
|
|
847
|
+
...(ngDevMode ? [{ debugName: "headingRef" }] : /* istanbul ignore next */ []));
|
|
848
|
+
/** Whether the owning container renders the accordion visualization. */
|
|
849
|
+
accordionView = computed(() => this.tabset?.isAccordionView() ?? false, /* @ts-ignore */
|
|
850
|
+
...(ngDevMode ? [{ debugName: "accordionView" }] : /* istanbul ignore next */ []));
|
|
851
|
+
/**
|
|
852
|
+
* Whether this panel renders as a card: either inside a `<hub-panels
|
|
853
|
+
* type="card">` container or standalone (no owning container at all).
|
|
854
|
+
*/
|
|
855
|
+
cardView = computed(() => !this.tabset || this.tabset.isCardView(), /* @ts-ignore */
|
|
856
|
+
...(ngDevMode ? [{ debugName: "cardView" }] : /* istanbul ignore next */ []));
|
|
857
|
+
/** Form value resolved for this panel: the explicit `value` or the panel id. */
|
|
858
|
+
formValue = computed(() => (this.value() !== undefined ? this.value() : this.id()), /* @ts-ignore */
|
|
859
|
+
...(ngDevMode ? [{ debugName: "formValue" }] : /* istanbul ignore next */ []));
|
|
860
|
+
/** `routerLink` normalised to a segments array, or `null` when not routed. */
|
|
861
|
+
routerUrl = computed(() => {
|
|
862
|
+
const link = this.routerLink();
|
|
863
|
+
if (!link) {
|
|
864
|
+
return null;
|
|
865
|
+
}
|
|
866
|
+
return Array.isArray(link) ? link : [link];
|
|
867
|
+
}, /* @ts-ignore */
|
|
868
|
+
...(ngDevMode ? [{ debugName: "routerUrl" }] : /* istanbul ignore next */ []));
|
|
869
|
+
/** Last activation state seen by the effect — avoids emitting on init. */
|
|
870
|
+
#wasActive = false;
|
|
871
|
+
constructor() {
|
|
872
|
+
// Standalone panels (no container) render as a card and skip registration.
|
|
873
|
+
this.tabset?.registerPanel(this);
|
|
874
|
+
// Mirror `customClass` onto the pane host element.
|
|
875
|
+
effect((onCleanup) => {
|
|
876
|
+
const classes = (this.customClass() ?? '')
|
|
877
|
+
.split(' ')
|
|
878
|
+
.map((cssClass) => cssClass.trim())
|
|
879
|
+
.filter((cssClass) => cssClass.length > 0);
|
|
880
|
+
for (const cssClass of classes) {
|
|
881
|
+
this.#renderer.addClass(this.elementRef.nativeElement, cssClass);
|
|
882
|
+
}
|
|
883
|
+
onCleanup(() => {
|
|
884
|
+
for (const cssClass of classes) {
|
|
885
|
+
this.#renderer.removeClass(this.elementRef.nativeElement, cssClass);
|
|
886
|
+
}
|
|
887
|
+
});
|
|
888
|
+
});
|
|
889
|
+
// Activation side effects: emit outputs and enforce single-active-panel
|
|
890
|
+
// (unless the container allows multiple expanded panels — accordion mode).
|
|
891
|
+
effect(() => {
|
|
892
|
+
const isActive = this.active();
|
|
893
|
+
if (isActive && this.disabled()) {
|
|
894
|
+
this.active.set(false);
|
|
895
|
+
return;
|
|
896
|
+
}
|
|
897
|
+
if (isActive === this.#wasActive) {
|
|
898
|
+
return;
|
|
899
|
+
}
|
|
900
|
+
this.#wasActive = isActive;
|
|
901
|
+
if (isActive) {
|
|
902
|
+
this.selectPanel.emit(this);
|
|
903
|
+
if (this.tabset && !this.tabset.allowsMultipleActive()) {
|
|
904
|
+
for (const panel of this.tabset.panels()) {
|
|
905
|
+
if (panel !== this) {
|
|
906
|
+
panel.active.set(false);
|
|
907
|
+
}
|
|
908
|
+
}
|
|
909
|
+
}
|
|
910
|
+
}
|
|
911
|
+
else {
|
|
912
|
+
this.deselectPanel.emit(this);
|
|
913
|
+
}
|
|
914
|
+
});
|
|
915
|
+
}
|
|
916
|
+
ngOnDestroy() {
|
|
917
|
+
this.tabset?.removePanel(this, { reselect: false, emit: false });
|
|
918
|
+
}
|
|
919
|
+
/** Route path plus query string, or `null` when the panel is not routed. */
|
|
920
|
+
getFullRoute() {
|
|
921
|
+
const route = this.getRoute();
|
|
922
|
+
if (!route) {
|
|
923
|
+
return null;
|
|
924
|
+
}
|
|
925
|
+
const queryString = this.getQueryParamsString();
|
|
926
|
+
return queryString ? `${route}?${queryString}` : route;
|
|
927
|
+
}
|
|
928
|
+
/** Normalised absolute route path, or `null` when the panel is not routed. */
|
|
929
|
+
getRoute() {
|
|
930
|
+
const routerUrl = this.routerUrl();
|
|
931
|
+
if (!routerUrl) {
|
|
932
|
+
return null;
|
|
933
|
+
}
|
|
934
|
+
let route = routerUrl.join('/').replace(/\/\/+/g, '/');
|
|
935
|
+
if (route.charAt(0) === '.') {
|
|
936
|
+
route = route.substring(1);
|
|
937
|
+
}
|
|
938
|
+
if (route.charAt(0) !== '/') {
|
|
939
|
+
route = `/${route}`;
|
|
940
|
+
}
|
|
941
|
+
return route;
|
|
942
|
+
}
|
|
943
|
+
/** `queryParams` serialised as `key=value&…`, or `null` when empty. */
|
|
944
|
+
getQueryParamsString() {
|
|
945
|
+
const params = this.queryParams();
|
|
946
|
+
if (!params || !Object.keys(params).length) {
|
|
947
|
+
return null;
|
|
948
|
+
}
|
|
949
|
+
return Object.entries(params)
|
|
950
|
+
.map(([key, value]) => `${key}=${value}`)
|
|
951
|
+
.join('&');
|
|
952
|
+
}
|
|
953
|
+
/** Navigates to the panel's route. No-op for non-routed panels. */
|
|
954
|
+
navigate() {
|
|
955
|
+
const routerUrl = this.routerUrl();
|
|
956
|
+
if (routerUrl) {
|
|
957
|
+
this.#router.navigate(routerUrl, { queryParams: this.queryParams() ?? {} });
|
|
958
|
+
}
|
|
959
|
+
}
|
|
960
|
+
/** Accordion header click — toggles this panel through the container. */
|
|
961
|
+
onAccordionHeaderClick() {
|
|
962
|
+
this.tabset?.togglePanel(this);
|
|
963
|
+
}
|
|
964
|
+
/** Accordion header keyboard navigation, delegated to the container. */
|
|
965
|
+
onAccordionHeaderKeydown(event) {
|
|
966
|
+
this.tabset?.onAccordionKeydown(event, this);
|
|
967
|
+
}
|
|
968
|
+
/** Removes this panel through the accordion header's ✕ affordance. */
|
|
969
|
+
removeSelf() {
|
|
970
|
+
this.tabset?.removePanel(this);
|
|
971
|
+
}
|
|
972
|
+
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "22.0.1", ngImport: i0, type: PanelComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
|
|
973
|
+
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "22.0.1", type: PanelComponent, isStandalone: true, selector: "hub-panel, [hub-panel]", inputs: { heading: { classPropertyName: "heading", publicName: "heading", isSignal: true, isRequired: false, transformFunction: null }, id: { classPropertyName: "id", publicName: "id", isSignal: true, isRequired: false, transformFunction: null }, disabled: { classPropertyName: "disabled", publicName: "disabled", isSignal: true, isRequired: false, transformFunction: null }, removable: { classPropertyName: "removable", publicName: "removable", isSignal: true, isRequired: false, transformFunction: null }, pathMatch: { classPropertyName: "pathMatch", publicName: "pathMatch", isSignal: true, isRequired: false, transformFunction: null }, routerLink: { classPropertyName: "routerLink", publicName: "routerLink", isSignal: true, isRequired: false, transformFunction: null }, queryParams: { classPropertyName: "queryParams", publicName: "queryParams", isSignal: true, isRequired: false, transformFunction: null }, customClass: { classPropertyName: "customClass", publicName: "customClass", isSignal: true, isRequired: false, transformFunction: null }, value: { classPropertyName: "value", publicName: "value", isSignal: true, isRequired: false, transformFunction: null }, active: { classPropertyName: "active", publicName: "active", isSignal: true, isRequired: false, transformFunction: null } }, outputs: { active: "activeChange", selectPanel: "selectPanel", deselectPanel: "deselectPanel", removed: "removed" }, host: { properties: { "attr.id": "accordionView() || cardView() ? null : id()", "attr.role": "accordionView() || cardView() ? null : 'tabpanel'", "attr.aria-labelledby": "accordionView() || cardView() ? null : id() + '-link'", "class.hub-panels__panel--active": "active()", "class.hub-panels__panel--accordion": "accordionView()", "class.hub-panels__panel--card": "cardView()" }, classAttribute: "hub-panels__panel" }, exportAs: ["hubPanel"], ngImport: i0, template: "@if (accordionView()) {\n\t<h2 class=\"hub-panels__accordion-header\">\n\t\t<button\n\t\t\ttype=\"button\"\n\t\t\tclass=\"hub-panels__accordion-btn\"\n\t\t\t[class.hub-panels__accordion-btn--collapsed]=\"!active()\"\n\t\t\t[id]=\"id() + '-link'\"\n\t\t\t[disabled]=\"disabled() || tabset?.formDisabled()\"\n\t\t\t[attr.aria-expanded]=\"active()\"\n\t\t\t[attr.aria-controls]=\"id()\"\n\t\t\t(click)=\"onAccordionHeaderClick()\"\n\t\t\t(keydown)=\"onAccordionHeaderKeydown($event)\"\n\t\t>\n\t\t\t@if (headingRef(); as headingTemplate) {\n\t\t\t\t<ng-container [ngTemplateOutlet]=\"headingTemplate\" />\n\t\t\t} @else {\n\t\t\t\t{{ heading() }}\n\t\t\t}\n\t\t\t@if (removable()) {\n\t\t\t\t<span class=\"hub-panels__remove-btn\" aria-hidden=\"true\" (click)=\"$event.stopPropagation(); removeSelf()\">×</span>\n\t\t\t}\n\t\t</button>\n\t</h2>\n}\n\n<!-- Projection slots for every view. In the strip views the wrappers are plain\n\t pass-throughs; in the accordion view they become the animated collapse\n\t region. The header/footer `select` slots and the default `<ng-content>` are\n\t all UNCONDITIONAL \u2014 never wrapped in `@if` \u2014 to avoid the lost-projection\n\t bug that conditional slots cause. Header/footer render in every view; the\n\t `card` view styles them as the card's header and footer bands. -->\n<div\n\t[class.hub-panels__accordion-collapse]=\"accordionView()\"\n\t[class.hub-panels__accordion-collapse--collapsed]=\"accordionView() && !active()\"\n\t[attr.role]=\"accordionView() ? 'region' : null\"\n\t[attr.id]=\"accordionView() ? id() : null\"\n\t[attr.aria-labelledby]=\"accordionView() ? id() + '-link' : null\"\n\t[attr.aria-hidden]=\"accordionView() ? !active() : null\"\n\t[attr.inert]=\"accordionView() && !active() ? '' : null\"\n>\n\t<div [class.hub-panels__accordion-body]=\"accordionView()\">\n\t\t<ng-content select=\"[hubPanelHeader]\" />\n\t\t<div class=\"hub-panels__panel-body\">\n\t\t\t<ng-content />\n\t\t</div>\n\t\t<ng-content select=\"[hubPanelFooter]\" />\n\t</div>\n</div>\n", styles: [":where(.hub-panels__panel--card){--hub-panels-card-bg: var(--hub-sys-surface-page, #fff);--hub-panels-card-color: var(--hub-sys-text-primary, #212529);--hub-panels-card-border-width: var(--hub-ref-border-width, 1px);--hub-panels-card-border-color: var(--hub-sys-border-color-default, #dee2e6);--hub-panels-card-border-radius: var(--hub-ref-radius-md, .375rem);--hub-panels-card-box-shadow: var(--hub-sys-shadow-sm, 0 .125rem .25rem rgba(0, 0, 0, .075));--hub-panels-card-padding-x: var(--hub-ref-space-4, 1.25rem);--hub-panels-card-padding-y: var(--hub-ref-space-3, 1rem)}:where(.hub-panels__panel-header,.hub-panels__panel-footer){--hub-panels-panel-header-bg: var(--hub-ref-surface-2, #f8f9fa);--hub-panels-panel-header-color: var(--hub-sys-text-primary, #212529);--hub-panels-panel-header-padding-x: var(--hub-ref-space-4, 1.25rem);--hub-panels-panel-header-padding-y: var(--hub-ref-space-3, 1rem);--hub-panels-panel-header-font-weight: 600;--hub-panels-panel-header-border-width: var(--hub-ref-border-width, 1px);--hub-panels-panel-header-border-color: var(--hub-sys-border-color-default, #dee2e6)}.hub-panels__panel-header{display:block;padding:var(--hub-panels-panel-header-padding-y) var(--hub-panels-panel-header-padding-x);color:var(--hub-panels-panel-header-color);background:var(--hub-panels-panel-header-bg);font-weight:var(--hub-panels-panel-header-font-weight);border-bottom:var(--hub-panels-panel-header-border-width) solid var(--hub-panels-panel-header-border-color)}.hub-panels__panel-footer{display:block;padding:var(--hub-panels-panel-header-padding-y) var(--hub-panels-panel-header-padding-x);color:var(--hub-panels-panel-header-color);background:var(--hub-panels-panel-header-bg);border-top:var(--hub-panels-panel-header-border-width) solid var(--hub-panels-panel-header-border-color)}.hub-panels__panel.hub-panels__panel--card{display:flex;flex-direction:column;color:var(--hub-panels-card-color);background:var(--hub-panels-card-bg);border:var(--hub-panels-card-border-width) solid var(--hub-panels-card-border-color);border-radius:var(--hub-panels-card-border-radius);box-shadow:var(--hub-panels-card-box-shadow);overflow:hidden}.hub-panels__panel.hub-panels__panel--card .hub-panels__panel-body{padding:var(--hub-panels-card-padding-y) var(--hub-panels-card-padding-x)}\n"], dependencies: [{ kind: "directive", type: NgTemplateOutlet, selector: "[ngTemplateOutlet]", inputs: ["ngTemplateOutletContext", "ngTemplateOutlet", "ngTemplateOutletInjector"] }], changeDetection: i0.ChangeDetectionStrategy.OnPush, encapsulation: i0.ViewEncapsulation.None });
|
|
974
|
+
}
|
|
975
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.0.1", ngImport: i0, type: PanelComponent, decorators: [{
|
|
976
|
+
type: Component,
|
|
977
|
+
args: [{ selector: 'hub-panel, [hub-panel]', exportAs: 'hubPanel', imports: [NgTemplateOutlet], encapsulation: ViewEncapsulation.None, changeDetection: ChangeDetectionStrategy.OnPush, host: {
|
|
978
|
+
class: 'hub-panels__panel',
|
|
979
|
+
'[attr.id]': 'accordionView() || cardView() ? null : id()',
|
|
980
|
+
'[attr.role]': "accordionView() || cardView() ? null : 'tabpanel'",
|
|
981
|
+
'[attr.aria-labelledby]': "accordionView() || cardView() ? null : id() + '-link'",
|
|
982
|
+
'[class.hub-panels__panel--active]': 'active()',
|
|
983
|
+
'[class.hub-panels__panel--accordion]': 'accordionView()',
|
|
984
|
+
'[class.hub-panels__panel--card]': 'cardView()'
|
|
985
|
+
}, template: "@if (accordionView()) {\n\t<h2 class=\"hub-panels__accordion-header\">\n\t\t<button\n\t\t\ttype=\"button\"\n\t\t\tclass=\"hub-panels__accordion-btn\"\n\t\t\t[class.hub-panels__accordion-btn--collapsed]=\"!active()\"\n\t\t\t[id]=\"id() + '-link'\"\n\t\t\t[disabled]=\"disabled() || tabset?.formDisabled()\"\n\t\t\t[attr.aria-expanded]=\"active()\"\n\t\t\t[attr.aria-controls]=\"id()\"\n\t\t\t(click)=\"onAccordionHeaderClick()\"\n\t\t\t(keydown)=\"onAccordionHeaderKeydown($event)\"\n\t\t>\n\t\t\t@if (headingRef(); as headingTemplate) {\n\t\t\t\t<ng-container [ngTemplateOutlet]=\"headingTemplate\" />\n\t\t\t} @else {\n\t\t\t\t{{ heading() }}\n\t\t\t}\n\t\t\t@if (removable()) {\n\t\t\t\t<span class=\"hub-panels__remove-btn\" aria-hidden=\"true\" (click)=\"$event.stopPropagation(); removeSelf()\">×</span>\n\t\t\t}\n\t\t</button>\n\t</h2>\n}\n\n<!-- Projection slots for every view. In the strip views the wrappers are plain\n\t pass-throughs; in the accordion view they become the animated collapse\n\t region. The header/footer `select` slots and the default `<ng-content>` are\n\t all UNCONDITIONAL \u2014 never wrapped in `@if` \u2014 to avoid the lost-projection\n\t bug that conditional slots cause. Header/footer render in every view; the\n\t `card` view styles them as the card's header and footer bands. -->\n<div\n\t[class.hub-panels__accordion-collapse]=\"accordionView()\"\n\t[class.hub-panels__accordion-collapse--collapsed]=\"accordionView() && !active()\"\n\t[attr.role]=\"accordionView() ? 'region' : null\"\n\t[attr.id]=\"accordionView() ? id() : null\"\n\t[attr.aria-labelledby]=\"accordionView() ? id() + '-link' : null\"\n\t[attr.aria-hidden]=\"accordionView() ? !active() : null\"\n\t[attr.inert]=\"accordionView() && !active() ? '' : null\"\n>\n\t<div [class.hub-panels__accordion-body]=\"accordionView()\">\n\t\t<ng-content select=\"[hubPanelHeader]\" />\n\t\t<div class=\"hub-panels__panel-body\">\n\t\t\t<ng-content />\n\t\t</div>\n\t\t<ng-content select=\"[hubPanelFooter]\" />\n\t</div>\n</div>\n", styles: [":where(.hub-panels__panel--card){--hub-panels-card-bg: var(--hub-sys-surface-page, #fff);--hub-panels-card-color: var(--hub-sys-text-primary, #212529);--hub-panels-card-border-width: var(--hub-ref-border-width, 1px);--hub-panels-card-border-color: var(--hub-sys-border-color-default, #dee2e6);--hub-panels-card-border-radius: var(--hub-ref-radius-md, .375rem);--hub-panels-card-box-shadow: var(--hub-sys-shadow-sm, 0 .125rem .25rem rgba(0, 0, 0, .075));--hub-panels-card-padding-x: var(--hub-ref-space-4, 1.25rem);--hub-panels-card-padding-y: var(--hub-ref-space-3, 1rem)}:where(.hub-panels__panel-header,.hub-panels__panel-footer){--hub-panels-panel-header-bg: var(--hub-ref-surface-2, #f8f9fa);--hub-panels-panel-header-color: var(--hub-sys-text-primary, #212529);--hub-panels-panel-header-padding-x: var(--hub-ref-space-4, 1.25rem);--hub-panels-panel-header-padding-y: var(--hub-ref-space-3, 1rem);--hub-panels-panel-header-font-weight: 600;--hub-panels-panel-header-border-width: var(--hub-ref-border-width, 1px);--hub-panels-panel-header-border-color: var(--hub-sys-border-color-default, #dee2e6)}.hub-panels__panel-header{display:block;padding:var(--hub-panels-panel-header-padding-y) var(--hub-panels-panel-header-padding-x);color:var(--hub-panels-panel-header-color);background:var(--hub-panels-panel-header-bg);font-weight:var(--hub-panels-panel-header-font-weight);border-bottom:var(--hub-panels-panel-header-border-width) solid var(--hub-panels-panel-header-border-color)}.hub-panels__panel-footer{display:block;padding:var(--hub-panels-panel-header-padding-y) var(--hub-panels-panel-header-padding-x);color:var(--hub-panels-panel-header-color);background:var(--hub-panels-panel-header-bg);border-top:var(--hub-panels-panel-header-border-width) solid var(--hub-panels-panel-header-border-color)}.hub-panels__panel.hub-panels__panel--card{display:flex;flex-direction:column;color:var(--hub-panels-card-color);background:var(--hub-panels-card-bg);border:var(--hub-panels-card-border-width) solid var(--hub-panels-card-border-color);border-radius:var(--hub-panels-card-border-radius);box-shadow:var(--hub-panels-card-box-shadow);overflow:hidden}.hub-panels__panel.hub-panels__panel--card .hub-panels__panel-body{padding:var(--hub-panels-card-padding-y) var(--hub-panels-card-padding-x)}\n"] }]
|
|
986
|
+
}], ctorParameters: () => [], propDecorators: { heading: [{ type: i0.Input, args: [{ isSignal: true, alias: "heading", required: false }] }], id: [{ type: i0.Input, args: [{ isSignal: true, alias: "id", required: false }] }], disabled: [{ type: i0.Input, args: [{ isSignal: true, alias: "disabled", required: false }] }], removable: [{ type: i0.Input, args: [{ isSignal: true, alias: "removable", required: false }] }], pathMatch: [{ type: i0.Input, args: [{ isSignal: true, alias: "pathMatch", required: false }] }], routerLink: [{ type: i0.Input, args: [{ isSignal: true, alias: "routerLink", required: false }] }], queryParams: [{ type: i0.Input, args: [{ isSignal: true, alias: "queryParams", required: false }] }], customClass: [{ type: i0.Input, args: [{ isSignal: true, alias: "customClass", required: false }] }], value: [{ type: i0.Input, args: [{ isSignal: true, alias: "value", required: false }] }], active: [{ type: i0.Input, args: [{ isSignal: true, alias: "active", required: false }] }, { type: i0.Output, args: ["activeChange"] }], selectPanel: [{ type: i0.Output, args: ["selectPanel"] }], deselectPanel: [{ type: i0.Output, args: ["deselectPanel"] }], removed: [{ type: i0.Output, args: ["removed"] }] } });
|
|
987
|
+
|
|
988
|
+
/**
|
|
989
|
+
* Marks an `<ng-template>` inside a `hub-panel` as that panel's custom header
|
|
990
|
+
* (strip link in `tabs`/`pills` view, disclosure button in `accordion` view),
|
|
991
|
+
* replacing the plain-text `heading` input.
|
|
992
|
+
*
|
|
993
|
+
* @example
|
|
994
|
+
* ```html
|
|
995
|
+
* <hub-panel>
|
|
996
|
+
* <ng-template hubPanelHeading><em>Rich</em> heading</ng-template>
|
|
997
|
+
* Panel content
|
|
998
|
+
* </hub-panel>
|
|
999
|
+
* ```
|
|
1000
|
+
*/
|
|
1001
|
+
class PanelHeadingDirective {
|
|
1002
|
+
constructor() {
|
|
1003
|
+
inject(PanelComponent).headingRef.set(inject(TemplateRef));
|
|
1004
|
+
}
|
|
1005
|
+
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "22.0.1", ngImport: i0, type: PanelHeadingDirective, deps: [], target: i0.ɵɵFactoryTarget.Directive });
|
|
1006
|
+
static ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "14.0.0", version: "22.0.1", type: PanelHeadingDirective, isStandalone: true, selector: "[hubPanelHeading]", ngImport: i0 });
|
|
1007
|
+
}
|
|
1008
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.0.1", ngImport: i0, type: PanelHeadingDirective, decorators: [{
|
|
1009
|
+
type: Directive,
|
|
1010
|
+
args: [{ selector: '[hubPanelHeading]' }]
|
|
1011
|
+
}], ctorParameters: () => [] });
|
|
1012
|
+
|
|
1013
|
+
/**
|
|
1014
|
+
* Marks an element inside a `hub-panel` as the panel's content **header** band,
|
|
1015
|
+
* projected at the top of the panel body (above `<ng-content>`).
|
|
1016
|
+
*
|
|
1017
|
+
* Unlike `hubPanelHeading` — which renders the navigational label in the
|
|
1018
|
+
* `tabs`/`pills` strip or the `accordion` disclosure button — this header lives
|
|
1019
|
+
* inside the panel body and renders in **every** view (`tabs`, `pills`,
|
|
1020
|
+
* `accordion`, `card`). It is the natural title slot for the `card` format.
|
|
1021
|
+
*
|
|
1022
|
+
* @example
|
|
1023
|
+
* ```html
|
|
1024
|
+
* <hub-panel>
|
|
1025
|
+
* <div hubPanelHeader>Card title</div>
|
|
1026
|
+
* Card content
|
|
1027
|
+
* <div hubPanelFooter>Actions</div>
|
|
1028
|
+
* </hub-panel>
|
|
1029
|
+
* ```
|
|
1030
|
+
*/
|
|
1031
|
+
class PanelHeaderDirective {
|
|
1032
|
+
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "22.0.1", ngImport: i0, type: PanelHeaderDirective, deps: [], target: i0.ɵɵFactoryTarget.Directive });
|
|
1033
|
+
static ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "14.0.0", version: "22.0.1", type: PanelHeaderDirective, isStandalone: true, selector: "[hubPanelHeader]", host: { classAttribute: "hub-panels__panel-header" }, ngImport: i0 });
|
|
1034
|
+
}
|
|
1035
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.0.1", ngImport: i0, type: PanelHeaderDirective, decorators: [{
|
|
1036
|
+
type: Directive,
|
|
1037
|
+
args: [{
|
|
1038
|
+
selector: '[hubPanelHeader]',
|
|
1039
|
+
host: { class: 'hub-panels__panel-header' }
|
|
1040
|
+
}]
|
|
1041
|
+
}] });
|
|
1042
|
+
|
|
1043
|
+
/**
|
|
1044
|
+
* Marks an element inside a `hub-panel` as the panel's content **footer** band,
|
|
1045
|
+
* projected at the bottom of the panel body (below `<ng-content>`).
|
|
1046
|
+
*
|
|
1047
|
+
* Renders in **every** view (`tabs`, `pills`, `accordion`, `card`); it is the
|
|
1048
|
+
* natural actions/footer slot for the `card` format.
|
|
1049
|
+
*
|
|
1050
|
+
* @example
|
|
1051
|
+
* ```html
|
|
1052
|
+
* <hub-panel>
|
|
1053
|
+
* <div hubPanelHeader>Card title</div>
|
|
1054
|
+
* Card content
|
|
1055
|
+
* <div hubPanelFooter>Actions</div>
|
|
1056
|
+
* </hub-panel>
|
|
1057
|
+
* ```
|
|
1058
|
+
*/
|
|
1059
|
+
class PanelFooterDirective {
|
|
1060
|
+
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "22.0.1", ngImport: i0, type: PanelFooterDirective, deps: [], target: i0.ɵɵFactoryTarget.Directive });
|
|
1061
|
+
static ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "14.0.0", version: "22.0.1", type: PanelFooterDirective, isStandalone: true, selector: "[hubPanelFooter]", host: { classAttribute: "hub-panels__panel-footer" }, ngImport: i0 });
|
|
1062
|
+
}
|
|
1063
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.0.1", ngImport: i0, type: PanelFooterDirective, decorators: [{
|
|
1064
|
+
type: Directive,
|
|
1065
|
+
args: [{
|
|
1066
|
+
selector: '[hubPanelFooter]',
|
|
1067
|
+
host: { class: 'hub-panels__panel-footer' }
|
|
1068
|
+
}]
|
|
1069
|
+
}] });
|
|
1070
|
+
|
|
1071
|
+
/*
|
|
1072
|
+
* Public API Surface of ng-hub-ui-panels
|
|
1073
|
+
*/
|
|
1074
|
+
|
|
1075
|
+
/**
|
|
1076
|
+
* Generated bundle index. Do not edit.
|
|
1077
|
+
*/
|
|
1078
|
+
|
|
1079
|
+
export { PanelComponent, PanelFooterDirective, PanelHeaderDirective, PanelHeadingDirective, PanelsComponent, PanelsConfig };
|
|
1080
|
+
//# sourceMappingURL=ng-hub-ui-panels.mjs.map
|