ng-hub-ui-nav 22.11.2 → 22.12.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 +16 -7
- package/fesm2022/ng-hub-ui-nav.mjs +53 -8
- package/fesm2022/ng-hub-ui-nav.mjs.map +1 -1
- package/package.json +2 -2
- package/types/ng-hub-ui-nav.d.ts +23 -3
package/README.md
CHANGED
|
@@ -8,7 +8,7 @@
|
|
|
8
8
|
A flexible, accessible, and highly customizable navigation component for Angular 21+. It supports horizontal menus, vertical sidebars, mobile collapse modes, stacked drill-down panels, projected start/end slots, and scroll-spy integration.
|
|
9
9
|
|
|
10
10
|
> [!IMPORTANT]
|
|
11
|
-
> Version `
|
|
11
|
+
> Version `22.12.0` targets Angular 21 and follows the signal-first architecture used across `ng-hub-ui`.
|
|
12
12
|
|
|
13
13
|
## Documentation and Live Examples
|
|
14
14
|
|
|
@@ -69,8 +69,8 @@ This library is part of the **ng-hub-ui** ecosystem:
|
|
|
69
69
|
- Scroll-spy helpers for documentation pages and one-page layouts.
|
|
70
70
|
- Sticky vertical navigation support.
|
|
71
71
|
- **Desktop icon rail** — the two-way `rail` input collapses a vertical nav to `--hub-nav-rail-width` (4rem) showing icons only: labels surface as tooltips, accordion groups open as click-triggered overlay flyouts, and the offcanvas behavior still wins below `collapseBreakpoint`. A built-in edge toggle ships by default (`config.railToggle: false` to bring your own) and is fully themeable through `--hub-nav-rail-toggle-*`, including a replaceable SVG arrow. The library persists nothing; `railChange` lets the app store the preference.
|
|
72
|
-
- **Tooltip on truncated labels** — long item labels are clipped with an ellipsis (the standard sidebar behaviour) and reveal their full text on hover, automatically and only when truncated (via `ng-hub-ui-utils`' `[hubOverflowTooltip]`). The tooltip is **agnostic** — it defaults to the hub-ui tooltip but is swappable with `provideHubTooltip(...)`. Requires `ng-hub-ui-utils >= 22.
|
|
73
|
-
- Semantic `
|
|
72
|
+
- **Tooltip on truncated labels** — long item labels are clipped with an ellipsis (the standard sidebar behaviour) and reveal their full text on hover, automatically and only when truncated (via `ng-hub-ui-utils`' `[hubOverflowTooltip]`). The tooltip is **agnostic** — it defaults to the hub-ui tooltip but is swappable with `provideHubTooltip(...)`. Requires `ng-hub-ui-utils >= 22.13.0` (the library's peer floor) and the tooltip styles (`@use 'ng-hub-ui-utils/styles/tooltip';`). Tip: control the sidebar width with `--hub-nav-panel-width`.
|
|
73
|
+
- Semantic `color` accent system (`primary` / `success` / `danger` / `warning` / `info`, plus any custom accent or literal colour) recolouring the hover/active affordances — mirrors `<hub-panels>`.
|
|
74
74
|
- Full CSS variable theming via `--hub-nav-*` tokens.
|
|
75
75
|
|
|
76
76
|
## Installation
|
|
@@ -187,9 +187,9 @@ A toggle button ships on the outer edge of the primary column: an arrow inside a
|
|
|
187
187
|
| `config` | `Partial<HubNavConfig>` | `{}` | Per-instance config merged with global defaults. |
|
|
188
188
|
| `navClass` | `string` | `''` | Additional class applied to the internal `<nav>`. |
|
|
189
189
|
| `itemTemplate` | `TemplateRef<unknown> \| null` | `null` | Optional custom item template. |
|
|
190
|
-
| `autoOpenFromRoute` | `boolean` | `false` | Opens matching dropdowns/panels from the current route. It also re-derives the stack when the viewport comes back above `collapseBreakpoint`; with the input off, a stack opened by hand survives that round trip. |
|
|
190
|
+
| `autoOpenFromRoute` | `boolean` | `false` | Opens matching dropdowns/panels from the current route, and leaves exactly one section open when roots expand differently: arriving at an accordion root drops the panel of the panel root you left, and the other way round. It also re-derives the stack when the viewport comes back above `collapseBreakpoint`; with the input off, a stack opened by hand survives that round trip. |
|
|
191
191
|
| `rail` | `boolean` (two-way `model`) | `false` | Desktop-only icon rail for vertical navs. Ignored below `collapseBreakpoint`. Bind with `[(rail)]`. |
|
|
192
|
-
| `
|
|
192
|
+
| `color` | `'primary' \| 'success' \| 'danger' \| 'warning' \| 'info' \| string \| undefined` | `undefined` (reads as `primary`) | Semantic accent for the hover/active affordances. A bareword — semantic name, registered accent or CSS named colour — resolves through `--hub-sys-color-<name>`; a literal `#hex` / `rgb()` / `oklch()` / `var()` is passed through unchanged. |
|
|
193
193
|
|
|
194
194
|
#### Outputs
|
|
195
195
|
|
|
@@ -219,11 +219,20 @@ interface HubNavConfig {
|
|
|
219
219
|
sidebarSide: 'left' | 'right';
|
|
220
220
|
panelWidth: string;
|
|
221
221
|
dropdownRenderMode: 'inline' | 'overlay';
|
|
222
|
+
railToggle?: boolean;
|
|
223
|
+
activeIndicator?: boolean;
|
|
224
|
+
followReplacedUrls?: boolean | number;
|
|
222
225
|
labels?: Partial<HubNavLabels>;
|
|
223
226
|
}
|
|
224
227
|
```
|
|
225
228
|
|
|
226
|
-
`
|
|
229
|
+
`railToggle` (default `true`) draws the built-in rail toggle on the outer edge of a vertical desktop nav; set it to `false` to supply your own control.
|
|
230
|
+
|
|
231
|
+
`activeIndicator` (default `false`) moves the active mark to a single element shared by the list so it travels between siblings instead of appearing in place. It is opt-in because the mark stops being painted by each item, so a rule targeting `.hub-nav-item__link--active` no longer applies. It honours `prefers-reduced-motion`.
|
|
232
|
+
|
|
233
|
+
`followReplacedUrls` (default `true`) decides how eagerly the nav follows a URL that was **replaced** rather than pushed — which is what a scroll spy does while the reader scrolls. `true` follows every report; a **number** follows only once the reports have been quiet for that many milliseconds, so the mark lands where the reader stopped instead of walking down the menu; `false` never follows, marking only where the reader chose to go. Deep links are unaffected either way.
|
|
234
|
+
|
|
235
|
+
`labels` overrides the built-in accessible strings (`toggleNavigation`, `closeNavigation`, `collapseNavigation`, `expandNavigation`, `goBack`, `closePanel`, `toggleSection` — the last one supports a `{label}` placeholder) per instance. Without an override, each label resolves from the shared `HUBUI.NAV.*` dictionary keys (`provideHubTranslationAdapter()` in `ng-hub-ui-utils`) and finally falls back to English.
|
|
227
236
|
|
|
228
237
|
|
|
229
238
|
### `HubNavItem`
|
|
@@ -285,7 +294,7 @@ The component exposes a complete set of `--hub-nav-*` tokens. See the full refer
|
|
|
285
294
|
|
|
286
295
|
### Recolour the whole nav from a single accent
|
|
287
296
|
|
|
288
|
-
The hover/active affordances and the nav surface all derive from one accent hook. Set it (or use the `
|
|
297
|
+
The hover/active affordances and the nav surface all derive from one accent hook. Set it (or use the `color` input) to re-theme the entire nav:
|
|
289
298
|
|
|
290
299
|
```css
|
|
291
300
|
.my-sidebar {
|
|
@@ -396,8 +396,17 @@ class HubNavStateService {
|
|
|
396
396
|
this.openDropdown(id);
|
|
397
397
|
return true;
|
|
398
398
|
}
|
|
399
|
-
/**
|
|
399
|
+
/**
|
|
400
|
+
* Closes all open dropdowns.
|
|
401
|
+
*
|
|
402
|
+
* Writing an empty set over an empty set is not free: the signal has no value equality, so
|
|
403
|
+
* every reader re-runs. Route synchronisation calls this on each navigation, and this nav
|
|
404
|
+
* has already been observed generating state churn by the million in a single SSR pass.
|
|
405
|
+
*/
|
|
400
406
|
closeAllDropdowns() {
|
|
407
|
+
if (this._openDropdowns().size === 0) {
|
|
408
|
+
return;
|
|
409
|
+
}
|
|
401
410
|
this._openDropdowns.set(new Set());
|
|
402
411
|
}
|
|
403
412
|
/**
|
|
@@ -519,6 +528,12 @@ class HubNavStateService {
|
|
|
519
528
|
/**
|
|
520
529
|
* Finds the ordered list of dropdown ancestor IDs for the active route.
|
|
521
530
|
*
|
|
531
|
+
* The walk commits to the first branch it accepts, so which item it accepts has to be the
|
|
532
|
+
* most specific one at each level, not merely the first that matches: a menu whose opening
|
|
533
|
+
* entry is parked on the language prefix (`/en/`) matches every URL in the site, and being
|
|
534
|
+
* childless it ended the walk with an empty trail — every section stayed shut, whichever
|
|
535
|
+
* page you were on.
|
|
536
|
+
*
|
|
522
537
|
* @param items - Items to search recursively.
|
|
523
538
|
* @param activeRoute - Current router URL.
|
|
524
539
|
* @param trail - Accumulated ancestor trail.
|
|
@@ -526,7 +541,7 @@ class HubNavStateService {
|
|
|
526
541
|
*/
|
|
527
542
|
findActiveDropdownTrail(items, activeRoute, trail = []) {
|
|
528
543
|
for (const item of items) {
|
|
529
|
-
if (!this.
|
|
544
|
+
if (!this.isItemActiveAmongSiblings(item, items, activeRoute)) {
|
|
530
545
|
continue;
|
|
531
546
|
}
|
|
532
547
|
const nextTrail = item.children?.length ? [...trail, item.id] : trail;
|
|
@@ -557,8 +572,11 @@ class HubNavStateService {
|
|
|
557
572
|
closePanelsFromIndex(index) {
|
|
558
573
|
this._panelStack.update((stack) => stack.slice(0, index));
|
|
559
574
|
}
|
|
560
|
-
/** Closes all open panels. */
|
|
575
|
+
/** Closes all open panels. Skips the write when the stack is already empty, as {@link closeAllDropdowns} does. */
|
|
561
576
|
closeAllPanels() {
|
|
577
|
+
if (this._panelStack().length === 0) {
|
|
578
|
+
return;
|
|
579
|
+
}
|
|
562
580
|
this._panelStack.set([]);
|
|
563
581
|
}
|
|
564
582
|
/**
|
|
@@ -849,8 +867,14 @@ class HubNavScrollSpySectionDirective {
|
|
|
849
867
|
/** Optional section id. When omitted, host `id` is used. */
|
|
850
868
|
sectionId = input(null, { ...(ngDevMode ? { debugName: "sectionId" } : /* istanbul ignore next */ {}), alias: 'hubNavScrollSpySection' });
|
|
851
869
|
el = inject((ElementRef));
|
|
852
|
-
/**
|
|
853
|
-
|
|
870
|
+
/**
|
|
871
|
+
* Effective section id exposed to the container directive.
|
|
872
|
+
*
|
|
873
|
+
* Falsy rather than nullish on purpose: the documented bare form, `<section id="x"
|
|
874
|
+
* hubNavScrollSpySection>`, reaches the input as the empty string, which `??` would keep —
|
|
875
|
+
* stripping the host marker attribute and leaving the container with nothing to observe.
|
|
876
|
+
*/
|
|
877
|
+
resolvedSectionId = computed(() => this.sectionId() || this.el.nativeElement.id || null, /* @ts-ignore */
|
|
854
878
|
...(ngDevMode ? [{ debugName: "resolvedSectionId" }] : /* istanbul ignore next */ []));
|
|
855
879
|
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "22.0.8", ngImport: i0, type: HubNavScrollSpySectionDirective, deps: [], target: i0.ɵɵFactoryTarget.Directive });
|
|
856
880
|
static ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "17.1.0", version: "22.0.8", type: HubNavScrollSpySectionDirective, isStandalone: true, selector: "[hubNavScrollSpySection]", inputs: { sectionId: { classPropertyName: "sectionId", publicName: "hubNavScrollSpySection", isSignal: true, isRequired: false, transformFunction: null } }, host: { properties: { "attr.data-hub-nav-scroll-spy-section": "resolvedSectionId() || null" } }, ngImport: i0 });
|
|
@@ -1325,7 +1349,7 @@ class HubNavItemComponent {
|
|
|
1325
1349
|
this.toggleDropdown.emit(item);
|
|
1326
1350
|
}
|
|
1327
1351
|
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "22.0.8", ngImport: i0, type: HubNavItemComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
|
|
1328
|
-
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "22.0.8", type: HubNavItemComponent, isStandalone: true, selector: "hub-nav-item", inputs: { item: { classPropertyName: "item", publicName: "item", isSignal: true, isRequired: true, transformFunction: null }, depth: { classPropertyName: "depth", publicName: "depth", isSignal: true, isRequired: false, transformFunction: null }, isActive: { classPropertyName: "isActive", publicName: "isActive", isSignal: true, isRequired: false, transformFunction: null }, isExpanded: { classPropertyName: "isExpanded", publicName: "isExpanded", isSignal: true, isRequired: false, transformFunction: null }, itemTemplate: { classPropertyName: "itemTemplate", publicName: "itemTemplate", isSignal: true, isRequired: false, transformFunction: null }, forceAccordionMode: { classPropertyName: "forceAccordionMode", publicName: "forceAccordionMode", isSignal: true, isRequired: false, transformFunction: null } }, outputs: { clicked: "clicked", toggleDropdown: "toggleDropdown" }, host: { attributes: { "role": "none" }, properties: { "class.hub-nav-item--active": "isActive()", "class.hub-nav-item--disabled": "item().disabled", "class.hub-nav-item--has-children": "hasChildren()", "class.hub-nav-item--expanded": "isExpanded()", "class.hub-nav-item--header": "isHeader()", "attr.data-item-id": "item().id" }, classAttribute: "hub-nav-item" }, ngImport: i0, template: "@if (itemTemplate()) {\n\t<!-- Custom template rendering -->\n\t<ng-container [ngTemplateOutlet]=\"itemTemplate()!\" [ngTemplateOutletContext]=\"templateContext()\" />\n} @else if (isHeader()) {\n\t<!-- Header item: non-interactive section label -->\n\t<span class=\"hub-nav-item__header\" role=\"presentation\">{{ item().label }}</span>\n} @else if (isLink() && resolvedRoute()) {\n\t<!-- Link item: routable anchor -->\n\t<a\n\t\tclass=\"hub-nav-item__link\"\n\t\t[class.hub-nav-item__link--active]=\"isActive()\"\n\t\trole=\"menuitem\"\n\t\t[routerLink]=\"resolvedRoute()\"\n\t\t[queryParams]=\"item().queryParams\"\n\t\t[fragment]=\"item().fragment\"\n\t\t[class.hub-nav-item__link--disabled]=\"item().disabled\"\n\t\t[attr.tabindex]=\"item().disabled ? -1 : 0\"\n\t\t[attr.aria-disabled]=\"item().disabled || null\"\n\t\t[attr.aria-current]=\"isActive() ? 'page' : null\"\n\t\t[tooltip]=\"railTooltip()\"\n\t\t[placement]=\"railTooltipPlacement()\"\n\t\t(click)=\"onItemClick($event)\"\n\t>\n\t\t@if (item().icon) {\n\t\t\t<span class=\"hub-nav-item__icon\" [class]=\"item().icon\" aria-hidden=\"true\"></span>\n\t\t} @else if (railInitial()) {\n\t\t\t<span class=\"hub-nav-item__initial\" aria-hidden=\"true\">{{ railInitial() }}</span>\n\t\t}\n\t\t<span class=\"hub-nav-item__label\" [hubOverflowTooltip]=\"item().label\">{{ item().label }}</span>\n\t\t@if (item().badge) {\n\t\t\t<span class=\"hub-nav-item__badge\" [class]=\"item().badgeClass\">{{ item().badge }}</span>\n\t\t}\n\t</a>\n} @else if ((isDropdown() || hasChildren()) && resolvedRoute()) {\n\t<!-- Routable dropdown: link area navigates, caret area toggles submenu -->\n\t<div class=\"hub-nav-item__compound\">\n\t\t<a\n\t\t\tclass=\"hub-nav-item__link\"\n\t\t\t[class.hub-nav-item__link--split]=\"showCaret()\"\n\t\t\trole=\"menuitem\"\n\t\t\t[class.hub-nav-item__link--active]=\"isActive()\"\n\t\t\t[routerLink]=\"resolvedRoute()\"\n\t\t\t[queryParams]=\"item().queryParams\"\n\t\t\t[fragment]=\"item().fragment\"\n\t\t\t[class.hub-nav-item__link--disabled]=\"item().disabled\"\n\t\t\t[attr.tabindex]=\"item().disabled ? -1 : 0\"\n\t\t\t[attr.aria-disabled]=\"item().disabled || null\"\n\t\t\t[attr.aria-current]=\"isActive() ? 'page' : null\"\n\t\t\t[attr.aria-expanded]=\"showCaret() ? null : isExpanded()\"\n\t\t\t[attr.aria-haspopup]=\"showCaret() ? null : true\"\n\t\t\t[tooltip]=\"railTooltip()\"\n\t\t\t[placement]=\"railTooltipPlacement()\"\n\t\t\t(click)=\"onRouteItemClick($event)\"\n\t\t>\n\t\t\t@if (item().icon) {\n\t\t\t\t<span class=\"hub-nav-item__icon\" [class]=\"item().icon\" aria-hidden=\"true\"></span>\n\t\t\t} @else if (railInitial()) {\n\t\t\t\t<span class=\"hub-nav-item__initial\" aria-hidden=\"true\">{{ railInitial() }}</span>\n\t\t\t}\n\t\t\t<span class=\"hub-nav-item__label\" [hubOverflowTooltip]=\"item().label\">{{ item().label }}</span>\n\t\t\t@if (item().badge) {\n\t\t\t\t<span class=\"hub-nav-item__badge\" [class]=\"item().badgeClass\">{{ item().badge }}</span>\n\t\t\t}\n\t\t</a>\n\n\t\t@if (showCaret()) {\n\t\t\t<button\n\t\t\t\ttype=\"button\"\n\t\t\t\tclass=\"hub-nav-item__caret-button\"\n\t\t\t\t[class.hub-nav-item__caret-button--active]=\"isActive()\"\n\t\t\t\t[class.hub-nav-item__caret-button--expanded]=\"isExpanded()\"\n\t\t\t\t[class.hub-nav-item__caret-button--disabled]=\"item().disabled\"\n\t\t\t\t[attr.tabindex]=\"item().disabled ? -1 : 0\"\n\t\t\t\t[attr.aria-label]=\"caretAriaLabel()\"\n\t\t\t\t[attr.aria-expanded]=\"isExpanded()\"\n\t\t\t\t[attr.aria-haspopup]=\"true\"\n\t\t\t\t[attr.aria-disabled]=\"item().disabled || null\"\n\t\t\t\t(click)=\"onCaretClick($event)\"\n\t\t\t>\n\t\t\t\t<span class=\"hub-nav-item__caret\" aria-hidden=\"true\"></span>\n\t\t\t</button>\n\t\t}\n\t</div>\n} @else if (isDropdown() || hasChildren()) {\n\t<!-- Dropdown trigger: button that toggles a submenu -->\n\t<button\n\t\ttype=\"button\"\n\t\tclass=\"hub-nav-item__link hub-nav-item__dropdown-toggle\"\n\t\trole=\"menuitem\"\n\t\t[class.hub-nav-item__link--active]=\"isActive()\"\n\t\t[class.hub-nav-item__link--disabled]=\"item().disabled\"\n\t\t[attr.aria-expanded]=\"isExpanded()\"\n\t\t[attr.aria-haspopup]=\"true\"\n\t\t[attr.tabindex]=\"item().disabled ? -1 : 0\"\n\t\t[attr.aria-disabled]=\"item().disabled || null\"\n\t\t[tooltip]=\"railTooltip()\"\n\t\t[placement]=\"railTooltipPlacement()\"\n\t\t(click)=\"onItemClick($event)\"\n\t>\n\t\t@if (item().icon) {\n\t\t\t<span class=\"hub-nav-item__icon\" [class]=\"item().icon\" aria-hidden=\"true\"></span>\n\t\t} @else if (railInitial()) {\n\t\t\t<span class=\"hub-nav-item__initial\" aria-hidden=\"true\">{{ railInitial() }}</span>\n\t\t}\n\t\t<span class=\"hub-nav-item__label\" [hubOverflowTooltip]=\"item().label\">{{ item().label }}</span>\n\t\t@if (item().badge) {\n\t\t\t<span class=\"hub-nav-item__badge\" [class]=\"item().badgeClass\">{{ item().badge }}</span>\n\t\t}\n\t\t@if (showCaret()) {\n\t\t\t<span class=\"hub-nav-item__caret\" aria-hidden=\"true\"></span>\n\t\t}\n\t</button>\n} @else {\n\t<!-- Fallback: non-routable item (custom or link without route) -->\n\t<button\n\t\ttype=\"button\"\n\t\tclass=\"hub-nav-item__link\"\n\t\trole=\"menuitem\"\n\t\t[class.hub-nav-item__link--disabled]=\"item().disabled\"\n\t\t[attr.tabindex]=\"item().disabled ? -1 : 0\"\n\t\t[attr.aria-disabled]=\"item().disabled || null\"\n\t\t[tooltip]=\"railTooltip()\"\n\t\t[placement]=\"railTooltipPlacement()\"\n\t\t(click)=\"onItemClick($event)\"\n\t>\n\t\t@if (item().icon) {\n\t\t\t<span class=\"hub-nav-item__icon\" [class]=\"item().icon\" aria-hidden=\"true\"></span>\n\t\t} @else if (railInitial()) {\n\t\t\t<span class=\"hub-nav-item__initial\" aria-hidden=\"true\">{{ railInitial() }}</span>\n\t\t}\n\t\t<span class=\"hub-nav-item__label\" [hubOverflowTooltip]=\"item().label\">{{ item().label }}</span>\n\t\t@if (item().badge) {\n\t\t\t<span class=\"hub-nav-item__badge\" [class]=\"item().badgeClass\">{{ item().badge }}</span>\n\t\t}\n\t</button>\n}\n", styles: [":host{display:block;position:relative}:host-context(.hub-nav-item-list--force-accordion){display:block;width:100%}.hub-nav-item__link{display:flex;align-items:center;gap:var(--hub-nav-icon-gap, .5rem);width:100%;padding:var(--hub-nav-item-padding-y, .5rem) var(--hub-nav-item-padding-x, 1rem);font-size:var(--hub-nav-item-font-size, 1rem);font-weight:var(--hub-nav-item-font-weight, 400);color:var(--hub-nav-item-color, #212529);text-decoration:none;background:none;border:0;border-radius:var(--hub-nav-item-border-radius, .25rem);cursor:pointer;transition:var(--hub-nav-item-transition, all .15s ease-in-out);white-space:nowrap;font-family:inherit;line-height:var(--hub-ref-line-height-base, 1.5);text-align:start}.hub-nav-item__link:hover:not(.hub-nav-item__link--disabled){background-color:var(--hub-nav-item-hover-bg, rgba(0, 0, 0, .04));color:var(--hub-nav-item-hover-color, #0d6efd)}.hub-nav-item__link--active{background-color:var(--hub-nav-item-active-bg);color:var(--hub-nav-item-active-color);font-weight:var(--hub-nav-item-active-font-weight, 600)}.hub-nav-item__link--disabled{color:var(--hub-nav-item-disabled-color, #6c757d);opacity:var(--hub-nav-item-disabled-opacity, .65);pointer-events:none;cursor:default}.hub-nav-item__link:focus-visible{outline:2px solid var(--hub-sys-focus-ring-color, rgba(13, 110, 253, .25));outline-offset:-2px}:host-context(.hub-nav--horizontal) .hub-nav-item__link--active{box-shadow:inset 0 calc(var(--hub-nav-item-active-indicator-size, 3px) * -1) 0 var(--hub-nav-item-active-indicator-color)}:host-context(.hub-nav-item-list--animated-indicator) .hub-nav-item__link--active{background-color:transparent;box-shadow:none}.hub-nav-item__compound{display:flex;align-items:stretch;width:100%}.hub-nav-item__link--split{flex:1 1 auto;min-width:0;border-start-end-radius:0;border-end-end-radius:0}.hub-nav-item__caret-button{display:inline-flex;align-items:center;justify-content:center;flex:0 0 auto;min-width:calc(var(--hub-nav-item-font-size, 1rem) * 2.5);padding:0 var(--hub-nav-item-padding-x, 1rem);color:var(--hub-nav-item-color, #212529);background:none;border:0;border-start-start-radius:0;border-end-start-radius:0;border-start-end-radius:var(--hub-nav-item-border-radius, .25rem);border-end-end-radius:var(--hub-nav-item-border-radius, .25rem);cursor:pointer;transition:var(--hub-nav-item-transition, all .15s ease-in-out)}.hub-nav-item__caret-button:hover:not(.hub-nav-item__caret-button--disabled){background-color:var(--hub-nav-item-hover-bg, rgba(0, 0, 0, .04));color:var(--hub-nav-item-hover-color, #0d6efd)}.hub-nav-item__caret-button--active{background-color:var(--hub-nav-item-active-bg, #0d6efd);color:var(--hub-nav-item-active-color, #fff)}.hub-nav-item__caret-button--disabled{color:var(--hub-nav-item-disabled-color, #6c757d);opacity:var(--hub-nav-item-disabled-opacity, .65);cursor:default}.hub-nav-item__caret-button:focus-visible{outline:2px solid var(--hub-sys-focus-ring-color, rgba(13, 110, 253, .25));outline-offset:-2px}.hub-nav-item__caret-button--expanded:not(.hub-nav-item__caret-button--active){background-color:var(--hub-nav-item-hover-bg, rgba(0, 0, 0, .04));color:var(--hub-nav-item-hover-color, #0d6efd)}.hub-nav-item__icon{display:inline-flex;align-items:center;justify-content:center;width:var(--hub-nav-icon-size, 1em);height:var(--hub-nav-icon-size, 1em);flex-shrink:0}.hub-nav-item__label{flex:1;overflow:hidden;text-overflow:ellipsis}.hub-nav-item__badge{display:inline-flex;align-items:center;justify-content:center;padding:var(--hub-nav-badge-padding-y, .25em) var(--hub-nav-badge-padding-x, .5em);font-size:var(--hub-nav-badge-font-size, .75rem);font-weight:var(--hub-ref-font-weight-semibold, 600);line-height:1;color:var(--hub-nav-badge-color, #fff);background-color:var(--hub-nav-badge-bg, #dc3545);border-radius:var(--hub-nav-badge-border-radius, 50rem);flex-shrink:0}.hub-nav-item__caret{display:inline-block;width:0;height:0;vertical-align:middle;border-top:var(--hub-nav-caret-size, .3rem) solid var(--hub-nav-caret-color, currentColor);border-right:var(--hub-nav-caret-size, .3rem) solid transparent;border-left:var(--hub-nav-caret-size, .3rem) solid transparent;transition:var(--hub-nav-item-transition, all .15s ease-in-out);flex-shrink:0}:host(.hub-nav-item--expanded) .hub-nav-item__caret{transform:rotate(180deg)}:host(.hub-nav-item--expanded) .hub-nav-item__link:not(.hub-nav-item__link--active){background-color:var(--hub-nav-item-hover-bg, rgba(0, 0, 0, .04));color:var(--hub-nav-item-hover-color, #0d6efd);font-weight:var(--hub-nav-item-active-font-weight, 600)}.hub-nav-item__header{display:block;padding:var(--hub-nav-header-padding-y, .25rem) var(--hub-nav-header-padding-x, 1rem);margin-top:var(--hub-nav-header-margin-top, .75rem);font-size:var(--hub-nav-header-font-size, .875rem);font-weight:var(--hub-nav-header-font-weight, 600);color:var(--hub-nav-header-color, #6c757d);text-transform:uppercase;letter-spacing:.05em;cursor:default;white-space:nowrap}:host-context(.hub-nav--horizontal) .hub-nav-item__header{display:inline-flex;align-items:center;margin-top:0;margin-inline-start:0;padding-block:var(--hub-nav-header-padding-y, .25rem);padding-inline-end:var(--hub-nav-header-padding-x, 1rem);padding-inline-start:var(--hub-nav-header-horizontal-padding-inline-start, 2rem)}:host-context(.hub-nav-dropdown) .hub-nav-item__header,:host-context(.hub-nav-accordion) .hub-nav-item__header,:host-context(.hub-nav-panel__body) .hub-nav-item__header,:host-context(.hub-nav-mobile-panel__body) .hub-nav-item__header{display:block;margin-top:var(--hub-nav-header-margin-top, .75rem);margin-inline-start:0}:host-context(.hub-nav--horizontal){display:inline-flex}:host-context(.hub-nav--horizontal) .hub-nav-item__link{white-space:nowrap}:host-context(.hub-nav--horizontal):host-context(.hub-nav-dropdown) .hub-nav-item__caret{border-top:var(--hub-nav-caret-size, .3rem) solid transparent;border-bottom:var(--hub-nav-caret-size, .3rem) solid transparent;border-left:var(--hub-nav-caret-size, .3rem) solid var(--hub-nav-caret-color, currentColor);border-right:0}:host-context(.hub-nav-dropdown){display:block}:host-context(.hub-nav-item-list--force-accordion) .hub-nav-item__link{width:100%}.hub-nav-item__initial{display:none}:host-context(.hub-nav-item-list--rail) .hub-nav-item__link{justify-content:center;gap:0;padding-inline:0}:host-context(.hub-nav-item-list--rail) .hub-nav-item__label{flex:0 0 auto;inline-size:0;overflow:hidden}:host-context(.hub-nav-item-list--rail) .hub-nav-item__badge,:host-context(.hub-nav-item-list--rail) .hub-nav-item__caret,:host-context(.hub-nav-item-list--rail) .hub-nav-item__header{display:none}:host-context(.hub-nav-item-list--rail) .hub-nav-item__initial{display:inline-flex;align-items:center;justify-content:center;width:var(--hub-nav-icon-size, 1em);height:var(--hub-nav-icon-size, 1em);font-weight:var(--hub-nav-item-active-font-weight, 600);text-transform:uppercase;flex-shrink:0}\n"], dependencies: [{ kind: "directive", type: NgTemplateOutlet, selector: "[ngTemplateOutlet]", inputs: ["ngTemplateOutletContext", "ngTemplateOutlet", "ngTemplateOutletInjector"] }, { kind: "directive", type: RouterLink, selector: "[routerLink]", inputs: ["target", "queryParams", "fragment", "queryParamsHandling", "state", "info", "relativeTo", "preserveFragment", "skipLocationChange", "replaceUrl", "browserUrl", "routerLink"] }, { kind: "directive", type: HubOverflowTooltipDirective, selector: "[hubOverflowTooltip]", inputs: ["hubOverflowTooltip", "placement"] }, { kind: "directive", type: TooltipDirective, selector: "[tooltip]", inputs: ["tooltip", "placement", "delay", "offset"] }], changeDetection: i0.ChangeDetectionStrategy.OnPush });
|
|
1352
|
+
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "22.0.8", type: HubNavItemComponent, isStandalone: true, selector: "hub-nav-item", inputs: { item: { classPropertyName: "item", publicName: "item", isSignal: true, isRequired: true, transformFunction: null }, depth: { classPropertyName: "depth", publicName: "depth", isSignal: true, isRequired: false, transformFunction: null }, isActive: { classPropertyName: "isActive", publicName: "isActive", isSignal: true, isRequired: false, transformFunction: null }, isExpanded: { classPropertyName: "isExpanded", publicName: "isExpanded", isSignal: true, isRequired: false, transformFunction: null }, itemTemplate: { classPropertyName: "itemTemplate", publicName: "itemTemplate", isSignal: true, isRequired: false, transformFunction: null }, forceAccordionMode: { classPropertyName: "forceAccordionMode", publicName: "forceAccordionMode", isSignal: true, isRequired: false, transformFunction: null } }, outputs: { clicked: "clicked", toggleDropdown: "toggleDropdown" }, host: { attributes: { "role": "none" }, properties: { "class.hub-nav-item--active": "isActive()", "class.hub-nav-item--disabled": "item().disabled", "class.hub-nav-item--has-children": "hasChildren()", "class.hub-nav-item--expanded": "isExpanded()", "class.hub-nav-item--header": "isHeader()", "attr.data-item-id": "item().id" }, classAttribute: "hub-nav-item" }, ngImport: i0, template: "@if (itemTemplate()) {\n\t<!-- Custom template rendering -->\n\t<ng-container [ngTemplateOutlet]=\"itemTemplate()!\" [ngTemplateOutletContext]=\"templateContext()\" />\n} @else if (isHeader()) {\n\t<!-- Header item: non-interactive section label -->\n\t<span class=\"hub-nav-item__header\" role=\"presentation\">{{ item().label }}</span>\n} @else if (isLink() && resolvedRoute()) {\n\t<!-- Link item: routable anchor -->\n\t<a\n\t\tclass=\"hub-nav-item__link\"\n\t\t[class.hub-nav-item__link--active]=\"isActive()\"\n\t\trole=\"menuitem\"\n\t\t[routerLink]=\"resolvedRoute()\"\n\t\t[queryParams]=\"item().queryParams\"\n\t\t[fragment]=\"item().fragment\"\n\t\t[class.hub-nav-item__link--disabled]=\"item().disabled\"\n\t\t[attr.tabindex]=\"item().disabled ? -1 : 0\"\n\t\t[attr.aria-disabled]=\"item().disabled || null\"\n\t\t[attr.aria-current]=\"isActive() ? 'page' : null\"\n\t\t[tooltip]=\"railTooltip()\"\n\t\t[placement]=\"railTooltipPlacement()\"\n\t\t(click)=\"onItemClick($event)\"\n\t>\n\t\t@if (item().icon) {\n\t\t\t<span class=\"hub-nav-item__icon\" [class]=\"item().icon\" aria-hidden=\"true\"></span>\n\t\t} @else if (railInitial()) {\n\t\t\t<span class=\"hub-nav-item__initial\" aria-hidden=\"true\">{{ railInitial() }}</span>\n\t\t}\n\t\t<span class=\"hub-nav-item__label\" [hubOverflowTooltip]=\"item().label\">{{ item().label }}</span>\n\t\t@if (item().badge) {\n\t\t\t<span class=\"hub-nav-item__badge\" [class]=\"item().badgeClass\">{{ item().badge }}</span>\n\t\t}\n\t</a>\n} @else if ((isDropdown() || hasChildren()) && resolvedRoute()) {\n\t<!-- Routable dropdown: link area navigates, caret area toggles submenu -->\n\t<div class=\"hub-nav-item__compound\">\n\t\t<a\n\t\t\tclass=\"hub-nav-item__link\"\n\t\t\t[class.hub-nav-item__link--split]=\"showCaret()\"\n\t\t\trole=\"menuitem\"\n\t\t\t[class.hub-nav-item__link--active]=\"isActive()\"\n\t\t\t[routerLink]=\"resolvedRoute()\"\n\t\t\t[queryParams]=\"item().queryParams\"\n\t\t\t[fragment]=\"item().fragment\"\n\t\t\t[class.hub-nav-item__link--disabled]=\"item().disabled\"\n\t\t\t[attr.tabindex]=\"item().disabled ? -1 : 0\"\n\t\t\t[attr.aria-disabled]=\"item().disabled || null\"\n\t\t\t[attr.aria-current]=\"isActive() ? 'page' : null\"\n\t\t\t[attr.aria-expanded]=\"showCaret() ? null : isExpanded()\"\n\t\t\t[attr.aria-haspopup]=\"showCaret() ? null : true\"\n\t\t\t[tooltip]=\"railTooltip()\"\n\t\t\t[placement]=\"railTooltipPlacement()\"\n\t\t\t(click)=\"onRouteItemClick($event)\"\n\t\t>\n\t\t\t@if (item().icon) {\n\t\t\t\t<span class=\"hub-nav-item__icon\" [class]=\"item().icon\" aria-hidden=\"true\"></span>\n\t\t\t} @else if (railInitial()) {\n\t\t\t\t<span class=\"hub-nav-item__initial\" aria-hidden=\"true\">{{ railInitial() }}</span>\n\t\t\t}\n\t\t\t<span class=\"hub-nav-item__label\" [hubOverflowTooltip]=\"item().label\">{{ item().label }}</span>\n\t\t\t@if (item().badge) {\n\t\t\t\t<span class=\"hub-nav-item__badge\" [class]=\"item().badgeClass\">{{ item().badge }}</span>\n\t\t\t}\n\t\t</a>\n\n\t\t@if (showCaret()) {\n\t\t\t<button\n\t\t\t\ttype=\"button\"\n\t\t\t\tclass=\"hub-nav-item__caret-button\"\n\t\t\t\t[class.hub-nav-item__caret-button--active]=\"isActive()\"\n\t\t\t\t[class.hub-nav-item__caret-button--expanded]=\"isExpanded()\"\n\t\t\t\t[class.hub-nav-item__caret-button--disabled]=\"item().disabled\"\n\t\t\t\t[attr.tabindex]=\"item().disabled ? -1 : 0\"\n\t\t\t\t[attr.aria-label]=\"caretAriaLabel()\"\n\t\t\t\t[attr.aria-expanded]=\"isExpanded()\"\n\t\t\t\t[attr.aria-haspopup]=\"true\"\n\t\t\t\t[attr.aria-disabled]=\"item().disabled || null\"\n\t\t\t\t(click)=\"onCaretClick($event)\"\n\t\t\t>\n\t\t\t\t<span class=\"hub-nav-item__caret\" aria-hidden=\"true\"></span>\n\t\t\t</button>\n\t\t}\n\t</div>\n} @else if (isDropdown() || hasChildren()) {\n\t<!-- Dropdown trigger: button that toggles a submenu -->\n\t<button\n\t\ttype=\"button\"\n\t\tclass=\"hub-nav-item__link hub-nav-item__dropdown-toggle\"\n\t\trole=\"menuitem\"\n\t\t[class.hub-nav-item__link--active]=\"isActive()\"\n\t\t[class.hub-nav-item__link--disabled]=\"item().disabled\"\n\t\t[attr.aria-expanded]=\"isExpanded()\"\n\t\t[attr.aria-haspopup]=\"true\"\n\t\t[attr.tabindex]=\"item().disabled ? -1 : 0\"\n\t\t[attr.aria-disabled]=\"item().disabled || null\"\n\t\t[tooltip]=\"railTooltip()\"\n\t\t[placement]=\"railTooltipPlacement()\"\n\t\t(click)=\"onItemClick($event)\"\n\t>\n\t\t@if (item().icon) {\n\t\t\t<span class=\"hub-nav-item__icon\" [class]=\"item().icon\" aria-hidden=\"true\"></span>\n\t\t} @else if (railInitial()) {\n\t\t\t<span class=\"hub-nav-item__initial\" aria-hidden=\"true\">{{ railInitial() }}</span>\n\t\t}\n\t\t<span class=\"hub-nav-item__label\" [hubOverflowTooltip]=\"item().label\">{{ item().label }}</span>\n\t\t@if (item().badge) {\n\t\t\t<span class=\"hub-nav-item__badge\" [class]=\"item().badgeClass\">{{ item().badge }}</span>\n\t\t}\n\t\t@if (showCaret()) {\n\t\t\t<span class=\"hub-nav-item__caret\" aria-hidden=\"true\"></span>\n\t\t}\n\t</button>\n} @else {\n\t<!-- Fallback: non-routable item (custom or link without route) -->\n\t<button\n\t\ttype=\"button\"\n\t\tclass=\"hub-nav-item__link\"\n\t\trole=\"menuitem\"\n\t\t[class.hub-nav-item__link--disabled]=\"item().disabled\"\n\t\t[attr.tabindex]=\"item().disabled ? -1 : 0\"\n\t\t[attr.aria-disabled]=\"item().disabled || null\"\n\t\t[tooltip]=\"railTooltip()\"\n\t\t[placement]=\"railTooltipPlacement()\"\n\t\t(click)=\"onItemClick($event)\"\n\t>\n\t\t@if (item().icon) {\n\t\t\t<span class=\"hub-nav-item__icon\" [class]=\"item().icon\" aria-hidden=\"true\"></span>\n\t\t} @else if (railInitial()) {\n\t\t\t<span class=\"hub-nav-item__initial\" aria-hidden=\"true\">{{ railInitial() }}</span>\n\t\t}\n\t\t<span class=\"hub-nav-item__label\" [hubOverflowTooltip]=\"item().label\">{{ item().label }}</span>\n\t\t@if (item().badge) {\n\t\t\t<span class=\"hub-nav-item__badge\" [class]=\"item().badgeClass\">{{ item().badge }}</span>\n\t\t}\n\t</button>\n}\n", styles: [":host{display:block;position:relative}:host-context(.hub-nav-item-list--force-accordion){display:block;width:100%}.hub-nav-item__link{display:flex;align-items:center;gap:var(--hub-nav-icon-gap, .5rem);width:100%;padding:var(--hub-nav-item-padding-y, .5rem) var(--hub-nav-item-padding-x, 1rem);font-size:var(--hub-nav-item-font-size, 1rem);font-weight:var(--hub-nav-item-font-weight, 400);color:var(--hub-nav-item-color, #212529);text-decoration:none;background:none;border:0;border-radius:var(--hub-nav-item-border-radius, .25rem);cursor:pointer;transition:var(--hub-nav-item-transition, all .15s ease-in-out);white-space:nowrap;font-family:inherit;line-height:var(--hub-ref-line-height-base, 1.5);text-align:start}.hub-nav-item__link:hover:not(.hub-nav-item__link--disabled){background-color:var(--hub-nav-item-hover-bg, rgba(0, 0, 0, .04));color:var(--hub-nav-item-hover-color, #0d6efd)}.hub-nav-item__link--active{background-color:var(--hub-nav-item-active-bg);color:var(--hub-nav-item-active-color);font-weight:var(--hub-nav-item-active-font-weight, 600)}.hub-nav-item__link--disabled{color:var(--hub-nav-item-disabled-color, #6c757d);opacity:var(--hub-nav-item-disabled-opacity, .65);pointer-events:none;cursor:default}.hub-nav-item__link:focus-visible{outline:2px solid var(--hub-sys-focus-ring-color, rgba(13, 110, 253, .25));outline-offset:-2px}:host-context(.hub-nav--horizontal) .hub-nav-item__link--active{box-shadow:inset 0 calc(var(--hub-nav-item-active-indicator-size, 3px) * -1) 0 var(--hub-nav-item-active-indicator-color)}:host-context(.hub-nav-item-list--animated-indicator) .hub-nav-item__link--active{background-color:transparent;box-shadow:none}.hub-nav-item__compound{display:flex;align-items:stretch;width:100%}.hub-nav-item__link--split{flex:1 1 auto;min-width:0;border-start-end-radius:0;border-end-end-radius:0}.hub-nav-item__caret-button{display:inline-flex;align-items:center;justify-content:center;flex:0 0 auto;min-width:calc(var(--hub-nav-item-font-size, 1rem) * 2.5);padding:0 var(--hub-nav-item-padding-x, 1rem);color:var(--hub-nav-item-color, #212529);background:none;border:0;border-start-start-radius:0;border-end-start-radius:0;border-start-end-radius:var(--hub-nav-item-border-radius, .25rem);border-end-end-radius:var(--hub-nav-item-border-radius, .25rem);cursor:pointer;transition:var(--hub-nav-item-transition, all .15s ease-in-out)}.hub-nav-item__caret-button:hover:not(.hub-nav-item__caret-button--disabled){background-color:var(--hub-nav-item-hover-bg, rgba(0, 0, 0, .04));color:var(--hub-nav-item-hover-color, #0d6efd)}.hub-nav-item__caret-button--active{background-color:var(--hub-nav-item-active-bg, #0d6efd);color:var(--hub-nav-item-active-color, #fff)}.hub-nav-item__caret-button--disabled{color:var(--hub-nav-item-disabled-color, #6c757d);opacity:var(--hub-nav-item-disabled-opacity, .65);cursor:default}.hub-nav-item__caret-button:focus-visible{outline:2px solid var(--hub-sys-focus-ring-color, rgba(13, 110, 253, .25));outline-offset:-2px}.hub-nav-item__caret-button--expanded:not(.hub-nav-item__caret-button--active){background-color:var(--hub-nav-item-hover-bg, rgba(0, 0, 0, .04));color:var(--hub-nav-item-hover-color, #0d6efd)}.hub-nav-item__icon{display:inline-flex;align-items:center;justify-content:center;width:var(--hub-nav-icon-size, 1em);height:var(--hub-nav-icon-size, 1em);flex-shrink:0}.hub-nav-item__label{flex:1;overflow:hidden;text-overflow:ellipsis}.hub-nav-item__badge{display:inline-flex;align-items:center;justify-content:center;padding:var(--hub-nav-badge-padding-y, .25em) var(--hub-nav-badge-padding-x, .5em);font-size:var(--hub-nav-badge-font-size, .75rem);font-weight:var(--hub-ref-font-weight-semibold, 600);line-height:1;color:var(--hub-nav-badge-color, #fff);background-color:var(--hub-nav-badge-bg, #dc3545);border-radius:var(--hub-nav-badge-border-radius, 50rem);flex-shrink:0}.hub-nav-item__caret{display:inline-block;width:0;height:0;vertical-align:middle;border-top:var(--hub-nav-caret-size, .3rem) solid var(--hub-nav-caret-color, currentColor);border-right:var(--hub-nav-caret-size, .3rem) solid transparent;border-left:var(--hub-nav-caret-size, .3rem) solid transparent;transition:var(--hub-nav-item-transition, all .15s ease-in-out);flex-shrink:0}:host(.hub-nav-item--expanded) .hub-nav-item__caret{transform:rotate(180deg)}:host(.hub-nav-item--expanded) .hub-nav-item__link:not(.hub-nav-item__link--active){background-color:var(--hub-nav-item-hover-bg, rgba(0, 0, 0, .04));color:var(--hub-nav-item-hover-color, #0d6efd);font-weight:var(--hub-nav-item-active-font-weight, 600)}.hub-nav-item__header{display:block;padding:var(--hub-nav-header-padding-y, .25rem) var(--hub-nav-header-padding-x, 1rem);margin-top:var(--hub-nav-header-margin-top, .75rem);font-size:var(--hub-nav-header-font-size, .875rem);font-weight:var(--hub-nav-header-font-weight, 600);color:var(--hub-nav-header-color, #6c757d);text-transform:uppercase;letter-spacing:.05em;cursor:default;white-space:nowrap}:host-context(.hub-nav--horizontal) .hub-nav-item__header{display:inline-flex;align-items:center;margin-top:0;margin-inline-start:0;padding-block:var(--hub-nav-header-padding-y, .25rem);padding-inline-end:var(--hub-nav-header-padding-x, 1rem);padding-inline-start:var(--hub-nav-header-horizontal-padding-inline-start, 2rem)}:host-context(.hub-nav-dropdown) .hub-nav-item__header,:host-context(.hub-nav-accordion) .hub-nav-item__header,:host-context(.hub-nav-panel__body) .hub-nav-item__header,:host-context(.hub-nav-mobile-panel__body) .hub-nav-item__header{display:block;margin-top:var(--hub-nav-header-margin-top, .75rem);margin-inline-start:0}:host-context(.hub-nav--horizontal){display:inline-flex}:host-context(.hub-nav--horizontal) .hub-nav-item__link{white-space:nowrap}:host-context(.hub-nav--horizontal):host-context(.hub-nav-dropdown) .hub-nav-item__caret{border-top:var(--hub-nav-caret-size, .3rem) solid transparent;border-bottom:var(--hub-nav-caret-size, .3rem) solid transparent;border-left:var(--hub-nav-caret-size, .3rem) solid var(--hub-nav-caret-color, currentColor);border-right:0}:host-context(.hub-nav-dropdown){display:block}:host-context(.hub-nav-item-list--force-accordion) .hub-nav-item__link{width:100%}.hub-nav-item__initial{display:none}:host-context(.hub-nav-item-list--rail) .hub-nav-item__link{justify-content:center;gap:0;padding-inline:0}:host-context(.hub-nav-item-list--rail) .hub-nav-item__label{flex:0 0 auto;inline-size:0;overflow:hidden}:host-context(.hub-nav-item-list--rail) .hub-nav-item__badge,:host-context(.hub-nav-item-list--rail) .hub-nav-item__caret,:host-context(.hub-nav-item-list--rail) .hub-nav-item__header{display:none}:host-context(.hub-nav-item-list--rail) .hub-nav-item__initial{display:inline-flex;align-items:center;justify-content:center;width:var(--hub-nav-icon-size, 1em);height:var(--hub-nav-icon-size, 1em);font-weight:var(--hub-nav-item-active-font-weight, 600);text-transform:uppercase;flex-shrink:0}\n"], dependencies: [{ kind: "directive", type: NgTemplateOutlet, selector: "[ngTemplateOutlet]", inputs: ["ngTemplateOutletContext", "ngTemplateOutlet", "ngTemplateOutletInjector"] }, { kind: "directive", type: RouterLink, selector: "[routerLink]", inputs: ["target", "queryParams", "fragment", "queryParamsHandling", "state", "info", "relativeTo", "preserveFragment", "skipLocationChange", "replaceUrl", "browserUrl", "routerLink"] }, { kind: "directive", type: HubOverflowTooltipDirective, selector: "[hubOverflowTooltip]", inputs: ["hubOverflowTooltip", "placement", "hubOverflowTooltipMeasure"] }, { kind: "directive", type: TooltipDirective, selector: "[tooltip]", inputs: ["tooltip", "placement", "delay", "offset"] }], changeDetection: i0.ChangeDetectionStrategy.OnPush });
|
|
1329
1353
|
}
|
|
1330
1354
|
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.0.8", ngImport: i0, type: HubNavItemComponent, decorators: [{
|
|
1331
1355
|
type: Component,
|
|
@@ -2895,18 +2919,39 @@ class HubNavComponent {
|
|
|
2895
2919
|
this._lastSyncedPath = currentPath;
|
|
2896
2920
|
return;
|
|
2897
2921
|
}
|
|
2922
|
+
// Which root the reader is now inside, resolved by the most specific match rather than
|
|
2923
|
+
// the first one — the same rule {@link openPanelsFromRoute} uses. A root parked on the
|
|
2924
|
+
// language prefix (`/en/`) matches every URL in the site, and taking it as the answer
|
|
2925
|
+
// handed an accordion section's navigation to the panel stack.
|
|
2926
|
+
const activeRootItem = items.find((item) => this.state.isItemActiveAmongSiblings(item, items, currentUrl));
|
|
2927
|
+
// Nowhere in the menu — a settings screen, a 404. Whatever is open describes the page
|
|
2928
|
+
// just left, so both mechanisms are cleared rather than only the panels.
|
|
2929
|
+
if (!activeRootItem) {
|
|
2930
|
+
this.state.closeAllDropdowns();
|
|
2931
|
+
this.state.closeAllPanels();
|
|
2932
|
+
this._lastSyncedPath = currentPath;
|
|
2933
|
+
return;
|
|
2934
|
+
}
|
|
2898
2935
|
// An accordion opens in place, so what the route has to open is its
|
|
2899
2936
|
// dropdown state — not the panel stack, which is the drill-down mechanism
|
|
2900
2937
|
// and is not rendered in this mode. Deciding by collapsed-or-not alone
|
|
2901
2938
|
// left an expanded accordion with nothing opened from the route: the
|
|
2902
2939
|
// section somebody had just navigated into stayed shut, while a panel
|
|
2903
2940
|
// nobody could see was opened behind the page.
|
|
2904
|
-
|
|
2905
|
-
if (activeRootItem && this.state.getEffectiveExpandMode(activeRootItem) === 'accordion') {
|
|
2941
|
+
if (this.state.getEffectiveExpandMode(activeRootItem) === 'accordion') {
|
|
2906
2942
|
this.state.syncDropdownsWithRoute(items, currentUrl);
|
|
2943
|
+
// In a mixed nav the reader can arrive here from a root that drills down into
|
|
2944
|
+
// panels, and that panel now has no owner: an accordion expands in place and
|
|
2945
|
+
// never touches the stack, so nothing else would ever close it. Two sections
|
|
2946
|
+
// stayed open at once, one of them the one just walked out of.
|
|
2947
|
+
this.state.closeAllPanels();
|
|
2907
2948
|
this._lastSyncedPath = currentPath;
|
|
2908
2949
|
return;
|
|
2909
2950
|
}
|
|
2951
|
+
// The mirror of the branch above. This root does not expand in place, so any dropdown
|
|
2952
|
+
// still open belongs to the section left behind — including the case of a root with no
|
|
2953
|
+
// children at all, which opens neither mechanism and must therefore leave neither.
|
|
2954
|
+
this.state.closeAllDropdowns();
|
|
2910
2955
|
if (currentPath === this._lastSyncedPath && this.state.panelCount() > 0) {
|
|
2911
2956
|
return;
|
|
2912
2957
|
}
|