@hermes-ui/angular 0.1.7 → 0.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.
Files changed (108) hide show
  1. package/README.md +6 -6
  2. package/button/_buttons.clarity.scss +80 -2
  3. package/button/_mixins.buttons.scss +44 -2
  4. package/button/_properties.buttons.scss +209 -247
  5. package/button/_variables.buttons.scss +22 -0
  6. package/fesm2022/hermes-ui-angular-accordion.mjs +2 -2
  7. package/fesm2022/hermes-ui-angular-accordion.mjs.map +1 -1
  8. package/fesm2022/hermes-ui-angular-addons-card-container.mjs +3 -3
  9. package/fesm2022/hermes-ui-angular-addons-card-container.mjs.map +1 -1
  10. package/fesm2022/hermes-ui-angular-addons-certificate-viewer.mjs +2 -2
  11. package/fesm2022/hermes-ui-angular-addons-certificate-viewer.mjs.map +1 -1
  12. package/fesm2022/hermes-ui-angular-addons-datagrid-filters.mjs +2 -2
  13. package/fesm2022/hermes-ui-angular-addons-datagrid-filters.mjs.map +1 -1
  14. package/fesm2022/hermes-ui-angular-addons-datagrid.mjs +2 -2
  15. package/fesm2022/hermes-ui-angular-addons-datagrid.mjs.map +1 -1
  16. package/fesm2022/hermes-ui-angular-addons-property-view.mjs +2 -2
  17. package/fesm2022/hermes-ui-angular-addons-property-view.mjs.map +1 -1
  18. package/fesm2022/hermes-ui-angular-addons-theme-builder.mjs +66 -66
  19. package/fesm2022/hermes-ui-angular-addons-theme-builder.mjs.map +1 -1
  20. package/fesm2022/hermes-ui-angular-addons-var.mjs +2 -2
  21. package/fesm2022/hermes-ui-angular-addons-var.mjs.map +1 -1
  22. package/fesm2022/hermes-ui-angular-addons-wizard.mjs +2 -2
  23. package/fesm2022/hermes-ui-angular-addons-wizard.mjs.map +1 -1
  24. package/fesm2022/hermes-ui-angular-button.mjs +2 -2
  25. package/fesm2022/hermes-ui-angular-button.mjs.map +1 -1
  26. package/fesm2022/hermes-ui-angular-data-datagrid.mjs +2 -2
  27. package/fesm2022/hermes-ui-angular-data-datagrid.mjs.map +1 -1
  28. package/fesm2022/hermes-ui-angular-data-stack-view.mjs +2 -2
  29. package/fesm2022/hermes-ui-angular-data-stack-view.mjs.map +1 -1
  30. package/fesm2022/hermes-ui-angular-data-tree-view.mjs +2 -2
  31. package/fesm2022/hermes-ui-angular-data-tree-view.mjs.map +1 -1
  32. package/fesm2022/hermes-ui-angular-emphasis-alert.mjs +2 -2
  33. package/fesm2022/hermes-ui-angular-emphasis-alert.mjs.map +1 -1
  34. package/fesm2022/hermes-ui-angular-forms-checkbox.mjs +2 -2
  35. package/fesm2022/hermes-ui-angular-forms-checkbox.mjs.map +1 -1
  36. package/fesm2022/hermes-ui-angular-forms-combobox.mjs +2 -2
  37. package/fesm2022/hermes-ui-angular-forms-combobox.mjs.map +1 -1
  38. package/fesm2022/hermes-ui-angular-forms-common.mjs +2 -2
  39. package/fesm2022/hermes-ui-angular-forms-common.mjs.map +1 -1
  40. package/fesm2022/hermes-ui-angular-forms-datalist.mjs +2 -2
  41. package/fesm2022/hermes-ui-angular-forms-datalist.mjs.map +1 -1
  42. package/fesm2022/hermes-ui-angular-forms-datepicker.mjs +3 -3
  43. package/fesm2022/hermes-ui-angular-forms-datepicker.mjs.map +1 -1
  44. package/fesm2022/hermes-ui-angular-forms-file-input.mjs +2 -2
  45. package/fesm2022/hermes-ui-angular-forms-file-input.mjs.map +1 -1
  46. package/fesm2022/hermes-ui-angular-forms-input.mjs +2 -2
  47. package/fesm2022/hermes-ui-angular-forms-input.mjs.map +1 -1
  48. package/fesm2022/hermes-ui-angular-forms-native-select.mjs +2 -2
  49. package/fesm2022/hermes-ui-angular-forms-native-select.mjs.map +1 -1
  50. package/fesm2022/hermes-ui-angular-forms-number-input.mjs +2 -2
  51. package/fesm2022/hermes-ui-angular-forms-number-input.mjs.map +1 -1
  52. package/fesm2022/hermes-ui-angular-forms-password.mjs +2 -2
  53. package/fesm2022/hermes-ui-angular-forms-password.mjs.map +1 -1
  54. package/fesm2022/hermes-ui-angular-forms-radio.mjs +2 -2
  55. package/fesm2022/hermes-ui-angular-forms-radio.mjs.map +1 -1
  56. package/fesm2022/hermes-ui-angular-forms-range.mjs +2 -2
  57. package/fesm2022/hermes-ui-angular-forms-range.mjs.map +1 -1
  58. package/fesm2022/hermes-ui-angular-forms-select.mjs +2 -2
  59. package/fesm2022/hermes-ui-angular-forms-select.mjs.map +1 -1
  60. package/fesm2022/hermes-ui-angular-forms-textarea.mjs +2 -2
  61. package/fesm2022/hermes-ui-angular-forms-textarea.mjs.map +1 -1
  62. package/fesm2022/hermes-ui-angular-icon.mjs +29 -29
  63. package/fesm2022/hermes-ui-angular-icon.mjs.map +1 -1
  64. package/fesm2022/hermes-ui-angular-layout-nav.mjs +2 -2
  65. package/fesm2022/hermes-ui-angular-layout-nav.mjs.map +1 -1
  66. package/fesm2022/hermes-ui-angular-layout-tabs.mjs +2 -2
  67. package/fesm2022/hermes-ui-angular-layout-tabs.mjs.map +1 -1
  68. package/fesm2022/hermes-ui-angular-layout-vertical-nav.mjs +382 -28
  69. package/fesm2022/hermes-ui-angular-layout-vertical-nav.mjs.map +1 -1
  70. package/fesm2022/hermes-ui-angular-modal.mjs +2 -2
  71. package/fesm2022/hermes-ui-angular-modal.mjs.map +1 -1
  72. package/fesm2022/hermes-ui-angular-popover-signpost.mjs +2 -2
  73. package/fesm2022/hermes-ui-angular-popover-signpost.mjs.map +1 -1
  74. package/fesm2022/hermes-ui-angular-stepper.mjs +2 -2
  75. package/fesm2022/hermes-ui-angular-stepper.mjs.map +1 -1
  76. package/fesm2022/hermes-ui-angular-timeline.mjs +2 -2
  77. package/fesm2022/hermes-ui-angular-timeline.mjs.map +1 -1
  78. package/fesm2022/hermes-ui-angular-toast.mjs +2 -2
  79. package/fesm2022/hermes-ui-angular-toast.mjs.map +1 -1
  80. package/fesm2022/hermes-ui-angular-utils.mjs +6 -0
  81. package/fesm2022/hermes-ui-angular-utils.mjs.map +1 -1
  82. package/fesm2022/hermes-ui-angular-wizard.mjs +2 -2
  83. package/fesm2022/hermes-ui-angular-wizard.mjs.map +1 -1
  84. package/forms/combobox/_combobox.clarity.scss +18 -4
  85. package/forms/combobox/_properties.combobox.scss +5 -5
  86. package/forms/styles/_input-group.clarity.scss +7 -0
  87. package/forms/styles/_mixins.forms.scss +12 -10
  88. package/forms/styles/_native-select.clarity.scss +17 -5
  89. package/forms/styles/_properties.forms.scss +29 -18
  90. package/forms/styles/_textarea.clarity.scss +4 -4
  91. package/forms/styles/_variables.forms.scss +6 -0
  92. package/layout/main-container/_properties.header.scss +44 -6
  93. package/layout/main-container/_variables.header.scss +11 -0
  94. package/layout/nav/_header.clarity.scss +14 -0
  95. package/layout/nav/_mixins.header.scss +55 -40
  96. package/layout/nav/_responsive-nav.clarity.scss +21 -10
  97. package/layout/vertical-nav/_properties.vertical-nav.scss +77 -27
  98. package/layout/vertical-nav/_variables.vertical-nav.scss +23 -0
  99. package/layout/vertical-nav/_vertical-nav.clarity.scss +418 -277
  100. package/package.json +1 -1
  101. package/types/hermes-ui-angular-addons-theme-builder.d.ts +2 -2
  102. package/types/hermes-ui-angular-addons-theme-builder.d.ts.map +1 -1
  103. package/types/hermes-ui-angular-icon.d.ts +3 -3
  104. package/types/hermes-ui-angular-icon.d.ts.map +1 -1
  105. package/types/hermes-ui-angular-layout-vertical-nav.d.ts +134 -10
  106. package/types/hermes-ui-angular-layout-vertical-nav.d.ts.map +1 -1
  107. package/types/hermes-ui-angular-utils.d.ts +12 -0
  108. package/types/hermes-ui-angular-utils.d.ts.map +1 -1
@@ -1,13 +1,13 @@
1
1
  import * as i0 from '@angular/core';
2
- import { Component, Injectable, EventEmitter, Input, HostBinding, Output, Optional, Inject, Directive, NgModule } from '@angular/core';
2
+ import { Component, Injectable, EventEmitter, Input, HostBinding, Output, PLATFORM_ID, booleanAttribute, HostListener, Inject, Optional, Directive, NgModule } from '@angular/core';
3
3
  import { trigger, state, style, transition, animate } from '@angular/animations';
4
4
  import * as i1 from '@hermes-ui/angular/utils';
5
5
  import { IfExpandService, uniqueIdFactory, HermesConditionalModule, HermesFocusOnViewInitModule } from '@hermes-ui/angular/utils';
6
6
  import { Subject, fromEvent } from 'rxjs';
7
7
  import * as i5 from '@hermes-ui/angular/icon';
8
- import { ClarityIcons, angleIcon, angleDoubleIcon, HermesIcon } from '@hermes-ui/angular/icon';
8
+ import { HermesIcons, angleIcon, angleDoubleIcon, barsIcon, checkIcon, pinIcon, unpinIcon, twoWayArrowsIcon, HermesIcon } from '@hermes-ui/angular/icon';
9
+ import { isPlatformBrowser, CommonModule } from '@angular/common';
9
10
  import { takeUntil } from 'rxjs/operators';
10
- import { CommonModule } from '@angular/common';
11
11
 
12
12
  /*
13
13
  * Copyright (c) 2016-2026 Broadcom. All Rights Reserved.
@@ -60,12 +60,27 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.22", ngImpo
60
60
  class VerticalNavGroupRegistrationService {
61
61
  constructor() {
62
62
  this.navGroupCount = 0;
63
+ this.groups = new Set();
63
64
  }
64
- registerNavGroup() {
65
+ registerNavGroup(group) {
65
66
  this.navGroupCount++;
67
+ if (group) {
68
+ this.groups.add(group);
69
+ }
66
70
  }
67
- unregisterNavGroup() {
71
+ unregisterNavGroup(group) {
68
72
  this.navGroupCount--;
73
+ if (group) {
74
+ this.groups.delete(group);
75
+ }
76
+ }
77
+ /** Expands every group registered right now. */
78
+ expandAll() {
79
+ this.groups.forEach(group => group.expandGroup());
80
+ }
81
+ /** Collapses every group registered right now. */
82
+ collapseAll() {
83
+ this.groups.forEach(group => group.collapseGroup());
69
84
  }
70
85
  static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.22", ngImport: i0, type: VerticalNavGroupRegistrationService, deps: [], target: i0.ɵɵFactoryTarget.Injectable }); }
71
86
  static { this.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "21.2.22", ngImport: i0, type: VerticalNavGroupRegistrationService }); }
@@ -144,7 +159,7 @@ class HermesVerticalNavGroup {
144
159
  this.wasExpanded = false;
145
160
  this._subscriptions = [];
146
161
  this._expandAnimationState = COLLAPSED_STATE;
147
- _navGroupRegistrationService.registerNavGroup();
162
+ _navGroupRegistrationService.registerNavGroup(this);
148
163
  // FIXME: This subscription handles a corner case
149
164
  // Vertical Nav collapse requires the animation to run first and then
150
165
  // remove the nodes from the DOM. If the user directly sets the input
@@ -217,7 +232,7 @@ class HermesVerticalNavGroup {
217
232
  }
218
233
  ngOnDestroy() {
219
234
  this._subscriptions.forEach((sub) => sub.unsubscribe());
220
- this._navGroupRegistrationService.unregisterNavGroup();
235
+ this._navGroupRegistrationService.unregisterNavGroup(this);
221
236
  }
222
237
  expandGroup() {
223
238
  this.expanded = true;
@@ -249,7 +264,7 @@ class HermesVerticalNavGroup {
249
264
  }
250
265
  }
251
266
  static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.22", ngImport: i0, type: HermesVerticalNavGroup, deps: [{ token: i1.IfExpandService }, { token: VerticalNavGroupRegistrationService }, { token: VerticalNavGroupService }, { token: VerticalNavService }, { token: i1.HermesCommonStringsService }], target: i0.ɵɵFactoryTarget.Component }); }
252
- static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "21.2.22", type: HermesVerticalNavGroup, isStandalone: false, selector: "hermes-vertical-nav-group", inputs: { userExpandedInput: ["hermesVerticalNavGroupExpanded", "userExpandedInput"] }, outputs: { expandedChange: "hermesVerticalNavGroupExpandedChange" }, host: { properties: { "class.is-expanded": "this.expanded" }, classAttribute: "nav-group" }, providers: [IfExpandService, VerticalNavGroupService], ngImport: i0, template: "<!--\r\n ~ Copyright (c) 2016-2026 Broadcom. All Rights Reserved.\r\n ~ The term \"Broadcom\" refers to Broadcom Inc. and/or its subsidiaries.\r\n ~ This software is released under MIT license.\r\n ~ The full license information can be found in LICENSE in the root directory of this project.\r\n -->\r\n\r\n<div class=\"nav-group-content\">\r\n <ng-content select=\"[hermesVerticalNavLink]\"></ng-content>\r\n <button class=\"nav-group-trigger\" type=\"button\" [attr.aria-expanded]=\"expanded\" (click)=\"toggleExpand()\">\r\n <ng-content select=\"[hermesVerticalNavIcon]\"></ng-content>\r\n <div class=\"nav-group-text\">\r\n <ng-content></ng-content>\r\n </div>\r\n <hermes-icon shape=\"angle\" class=\"nav-group-trigger-icon\" [direction]=\"expanded ? 'down' : 'right'\"></hermes-icon>\r\n </button>\r\n</div>\r\n<!--TODO: This animation needs to be added to the hermes-vertical-nav-group-children component-->\r\n<div class=\"nav-group-children\" [@hermesExpand]=\"expandAnimationState\" (@hermesExpand.done)=\"expandAnimationDone($event)\">\r\n <ng-content select=\"[hermesIfExpanded], hermes-vertical-nav-group-children\"></ng-content>\r\n</div>\r\n", dependencies: [{ kind: "component", type: i5.HermesIcon, selector: "hermes-icon, hermes-icon", inputs: ["shape", "size", "direction", "flip", "solid", "status", "inverse", "badge"] }], animations: [
267
+ static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "21.2.22", type: HermesVerticalNavGroup, isStandalone: false, selector: "hermes-vertical-nav-group", inputs: { userExpandedInput: ["hermesVerticalNavGroupExpanded", "userExpandedInput"] }, outputs: { expandedChange: "hermesVerticalNavGroupExpandedChange" }, host: { properties: { "class.is-expanded": "this.expanded" }, classAttribute: "nav-group" }, providers: [IfExpandService, VerticalNavGroupService], ngImport: i0, template: "<!--\r\n ~ Copyright (c) 2016-2026 Broadcom. All Rights Reserved.\r\n ~ The term \"Broadcom\" refers to Broadcom Inc. and/or its subsidiaries.\r\n ~ This software is released under MIT license.\r\n ~ The full license information can be found in LICENSE in the root directory of this project.\r\n -->\r\n\r\n<div class=\"nav-group-content\">\r\n <ng-content select=\"[hermesVerticalNavLink]\"></ng-content>\r\n <button class=\"nav-group-trigger\" type=\"button\" [attr.aria-expanded]=\"expanded\" (click)=\"toggleExpand()\">\r\n <ng-content select=\"[hermesVerticalNavIcon]\"></ng-content>\r\n <div class=\"nav-group-text\">\r\n <ng-content></ng-content>\r\n </div>\r\n <hermes-icon shape=\"angle\" class=\"nav-group-trigger-icon\" [direction]=\"expanded ? 'up' : 'down'\"></hermes-icon>\r\n </button>\r\n</div>\r\n<!--TODO: This animation needs to be added to the hermes-vertical-nav-group-children component-->\r\n<div class=\"nav-group-children\" [@hermesExpand]=\"expandAnimationState\" (@hermesExpand.done)=\"expandAnimationDone($event)\">\r\n <ng-content select=\"[hermesIfExpanded], hermes-vertical-nav-group-children\"></ng-content>\r\n</div>\r\n", dependencies: [{ kind: "component", type: i5.HermesIcon, selector: "hermes-icon, hermes-icon", inputs: ["shape", "size", "direction", "flip", "solid", "status", "inverse", "badge"] }], animations: [
253
268
  trigger('hermesExpand', [
254
269
  state(EXPANDED_STATE, style({ height: '*' })),
255
270
  state(COLLAPSED_STATE, style({ height: 0, visibility: 'hidden' })),
@@ -265,7 +280,7 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.22", ngImpo
265
280
  state(COLLAPSED_STATE, style({ height: 0, visibility: 'hidden' })),
266
281
  transition(`${EXPANDED_STATE} <=> ${COLLAPSED_STATE}`, animate('0.2s ease-in-out')),
267
282
  ]),
268
- ], host: { class: 'nav-group' }, standalone: false, template: "<!--\r\n ~ Copyright (c) 2016-2026 Broadcom. All Rights Reserved.\r\n ~ The term \"Broadcom\" refers to Broadcom Inc. and/or its subsidiaries.\r\n ~ This software is released under MIT license.\r\n ~ The full license information can be found in LICENSE in the root directory of this project.\r\n -->\r\n\r\n<div class=\"nav-group-content\">\r\n <ng-content select=\"[hermesVerticalNavLink]\"></ng-content>\r\n <button class=\"nav-group-trigger\" type=\"button\" [attr.aria-expanded]=\"expanded\" (click)=\"toggleExpand()\">\r\n <ng-content select=\"[hermesVerticalNavIcon]\"></ng-content>\r\n <div class=\"nav-group-text\">\r\n <ng-content></ng-content>\r\n </div>\r\n <hermes-icon shape=\"angle\" class=\"nav-group-trigger-icon\" [direction]=\"expanded ? 'down' : 'right'\"></hermes-icon>\r\n </button>\r\n</div>\r\n<!--TODO: This animation needs to be added to the hermes-vertical-nav-group-children component-->\r\n<div class=\"nav-group-children\" [@hermesExpand]=\"expandAnimationState\" (@hermesExpand.done)=\"expandAnimationDone($event)\">\r\n <ng-content select=\"[hermesIfExpanded], hermes-vertical-nav-group-children\"></ng-content>\r\n</div>\r\n" }]
283
+ ], host: { class: 'nav-group' }, standalone: false, template: "<!--\r\n ~ Copyright (c) 2016-2026 Broadcom. All Rights Reserved.\r\n ~ The term \"Broadcom\" refers to Broadcom Inc. and/or its subsidiaries.\r\n ~ This software is released under MIT license.\r\n ~ The full license information can be found in LICENSE in the root directory of this project.\r\n -->\r\n\r\n<div class=\"nav-group-content\">\r\n <ng-content select=\"[hermesVerticalNavLink]\"></ng-content>\r\n <button class=\"nav-group-trigger\" type=\"button\" [attr.aria-expanded]=\"expanded\" (click)=\"toggleExpand()\">\r\n <ng-content select=\"[hermesVerticalNavIcon]\"></ng-content>\r\n <div class=\"nav-group-text\">\r\n <ng-content></ng-content>\r\n </div>\r\n <hermes-icon shape=\"angle\" class=\"nav-group-trigger-icon\" [direction]=\"expanded ? 'up' : 'down'\"></hermes-icon>\r\n </button>\r\n</div>\r\n<!--TODO: This animation needs to be added to the hermes-vertical-nav-group-children component-->\r\n<div class=\"nav-group-children\" [@hermesExpand]=\"expandAnimationState\" (@hermesExpand.done)=\"expandAnimationDone($event)\">\r\n <ng-content select=\"[hermesIfExpanded], hermes-vertical-nav-group-children\"></ng-content>\r\n</div>\r\n" }]
269
284
  }], ctorParameters: () => [{ type: i1.IfExpandService }, { type: VerticalNavGroupRegistrationService }, { type: VerticalNavGroupService }, { type: VerticalNavService }, { type: i1.HermesCommonStringsService }], propDecorators: { expandedChange: [{
270
285
  type: Output,
271
286
  args: ['hermesVerticalNavGroupExpandedChange']
@@ -309,39 +324,83 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.22", ngImpo
309
324
  * This software is released under MIT license.
310
325
  * The full license information can be found in LICENSE in the root directory of this project.
311
326
  */
327
+ const MODES = [
328
+ { id: 'auto', shape: 'two-way-arrows' },
329
+ { id: 'fixed', shape: 'pin' },
330
+ { id: 'compact', shape: 'bars' },
331
+ ];
332
+ // Mirrors `--hermes-vertical-nav-transition-duration` (0.2s): how long the width takes to settle.
333
+ const TRANSITION_MS = 200;
334
+ // Measuring at the exact instant the transition ends is a coin flip - the last frame lands before or
335
+ // after the timer. A small margin takes the measurement out of the race without being noticeable.
336
+ const MEASURE_MARGIN_MS = 60;
337
+ // Below this a label is not really laid out: it's the 1x1 screen-reader-only box of a collapsed nav,
338
+ // or a node that hasn't been measured yet.
339
+ const MIN_LABEL_WIDTH_PX = 8;
340
+ // Room left between the end of the longest label and the end of its box, so the hover pill and the
341
+ // selected tint don't end flush against the divider.
342
+ const LABEL_BREATHING_PX = 8;
343
+ const MEASURED_WIDTH_PROPERTY = '--hermes-vertical-nav-measured-width';
312
344
  class HermesVerticalNav {
313
- onPeekEnter() {
314
- if (this.pinnable && this.collapsed) {
315
- this.peeking = true;
316
- }
317
- }
318
- onPeekLeave() {
319
- this.peeking = false;
320
- }
321
- constructor(_navService, _navIconService, _navGroupRegistrationService, commonStrings) {
345
+ /**
346
+ * Makes the nav manage its own collapsed state from a behavior mode (see `HermesVerticalNavMode`),
347
+ * including the hover/focus reaction of `auto`. `null` (the default) leaves the collapsed state to
348
+ * `hermesVerticalNavCollapsed` and the built-in toggle button, as before.
349
+ */
350
+ get mode() {
351
+ return this._mode;
352
+ }
353
+ set mode(value) {
354
+ this._mode = value ?? null;
355
+ this.syncCollapsible();
356
+ this.applyMode();
357
+ }
358
+ constructor(_navService, _navIconService, _navGroupRegistrationService, commonStrings, host, cdr, zone, platformId) {
322
359
  this._navService = _navService;
323
360
  this._navIconService = _navIconService;
324
361
  this._navGroupRegistrationService = _navGroupRegistrationService;
325
362
  this.commonStrings = commonStrings;
363
+ this.host = host;
364
+ this.cdr = cdr;
365
+ this.zone = zone;
326
366
  /** Quando true, o toggle vira semanticamente um "fixar aberta/fechada" (ícones
327
367
  * pin/unpin em vez do chevron duplo genérico) e habilita o hover-peek: passar
328
368
  * o mouse enquanto colapsada e não fixada expande temporariamente (ver
329
- * onPeekEnter/onPeekLeave abaixo), sem persistir nem emitir o output. */
369
+ * onPointerEnter/onPointerLeave abaixo), sem persistir nem emitir o output. */
330
370
  this.pinnable = false;
371
+ /** Shows the footer with the behavior menu and the expand-all / collapse-all buttons. Needs a mode. */
372
+ this.footer = false;
373
+ /**
374
+ * Lets the width of the open nav grow (up to `--hermes-vertical-nav-max-width`) to fit the longest
375
+ * label in view. Only applies to a nav with a mode.
376
+ */
377
+ this.autoWidth = true;
378
+ this.modeChange = new EventEmitter();
379
+ this._collapsedChanged = new EventEmitter(true);
331
380
  this.contentId = uniqueIdFactory();
381
+ this.modes = MODES;
332
382
  /** true só enquanto o mouse está sobre uma nav colapsada e "pinnable" —
333
383
  * não persiste, não afeta `collapsed`/o output, é puramente visual. */
334
384
  this.peeking = false;
335
- this._collapsedChanged = new EventEmitter(true);
385
+ this.menuOpen = false;
386
+ this._mode = null;
387
+ this._collapsibleInput = false;
388
+ this.hovered = false;
389
+ this.focusedVisible = false;
390
+ this.isBrowser = isPlatformBrowser(platformId);
336
391
  this._sub = _navService.collapsedChanged.subscribe(value => {
337
392
  this._collapsedChanged.emit(value);
393
+ if (!value) {
394
+ this.scheduleMeasure();
395
+ }
338
396
  });
339
397
  }
340
398
  get collapsible() {
341
399
  return this._navService.collapsible;
342
400
  }
343
401
  set collapsible(value) {
344
- this._navService.collapsible = value;
402
+ this._collapsibleInput = !!value;
403
+ this.syncCollapsible();
345
404
  }
346
405
  get collapsed() {
347
406
  return this._navService.collapsed;
@@ -349,6 +408,17 @@ class HermesVerticalNav {
349
408
  set collapsed(value) {
350
409
  this._navService.collapsed = value;
351
410
  }
411
+ /** The nav derives its collapsed state from a mode, instead of from the collapsed input. */
412
+ get managed() {
413
+ return this._mode !== null;
414
+ }
415
+ /** In `auto` mode the nav sits on top of the content instead of pushing it. */
416
+ get overlay() {
417
+ return this._mode === 'auto';
418
+ }
419
+ get showFooter() {
420
+ return this.footer && this.managed;
421
+ }
352
422
  get hasNavGroups() {
353
423
  return this._navGroupRegistrationService.navGroupCount > 0;
354
424
  }
@@ -361,14 +431,268 @@ class HermesVerticalNav {
361
431
  }
362
432
  return !this.collapsed ? 'true' : 'false';
363
433
  }
434
+ /** The built-in top toggle is replaced by the footer once the nav manages itself. */
435
+ get showToggle() {
436
+ return !!this.collapsible && !this.managed;
437
+ }
438
+ get currentMode() {
439
+ return MODES.find(mode => mode.id === this._mode) ?? MODES[0];
440
+ }
441
+ get currentModeLabel() {
442
+ return this.label(this.currentMode.id);
443
+ }
444
+ label(key) {
445
+ const strings = this.commonStrings.keys;
446
+ const fallback = {
447
+ behavior: strings.verticalNavBehavior,
448
+ auto: strings.verticalNavModeAuto,
449
+ fixed: strings.verticalNavModeFixed,
450
+ compact: strings.verticalNavModeCompact,
451
+ expandAll: strings.verticalNavExpandAll,
452
+ collapseAll: strings.verticalNavCollapseAll,
453
+ };
454
+ return this.footerLabels?.[key] ?? fallback[key];
455
+ }
456
+ ngAfterViewInit() {
457
+ if (!this.isBrowser) {
458
+ return;
459
+ }
460
+ // The host can be created under a pointer that is already resting on it (e.g. the nav lives inside
461
+ // each routed page and is recreated on every navigation). Browsers don't always fire `mouseenter`
462
+ // for that, so ask the browser directly; it may take a frame to update `:hover`, hence two tries.
463
+ if (this.managed) {
464
+ [0, 150].forEach(delay => setTimeout(() => this.syncHoverFromDom(), delay));
465
+ }
466
+ // Anything that changes what's in view - a group opening, lazy content, translated labels -
467
+ // changes which label is the longest, so it asks for a new measurement.
468
+ this.zone.runOutsideAngular(() => {
469
+ const content = this.host.nativeElement.querySelector('.nav-content');
470
+ if (content && typeof MutationObserver !== 'undefined') {
471
+ this.observer = new MutationObserver(() => this.scheduleMeasure());
472
+ this.observer.observe(content, {
473
+ childList: true,
474
+ subtree: true,
475
+ characterData: true,
476
+ attributes: true,
477
+ attributeFilter: ['class'],
478
+ });
479
+ }
480
+ });
481
+ this.scheduleMeasure();
482
+ }
364
483
  ngOnDestroy() {
365
484
  this._sub.unsubscribe();
485
+ this.observer?.disconnect();
486
+ clearTimeout(this.measureTimer);
366
487
  }
367
488
  toggleByButton() {
368
489
  this.collapsed = !this.collapsed;
369
490
  }
370
- static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.22", ngImport: i0, type: HermesVerticalNav, deps: [{ token: VerticalNavService }, { token: VerticalNavIconService }, { token: VerticalNavGroupRegistrationService }, { token: i1.HermesCommonStringsService }], target: i0.ɵɵFactoryTarget.Component }); }
371
- static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "21.2.22", type: HermesVerticalNav, isStandalone: false, selector: "hermes-vertical-nav", inputs: { toggleLabel: ["hermesVerticalNavToggleLabel", "toggleLabel"], pinnable: ["hermesVerticalNavPinnable", "pinnable"], collapsible: ["hermesVerticalNavCollapsible", "collapsible"], collapsed: ["hermesVerticalNavCollapsed", "collapsed"] }, outputs: { _collapsedChanged: "hermesVerticalNavCollapsedChange" }, host: { listeners: { "mouseenter": "onPeekEnter()", "mouseleave": "onPeekLeave()" }, properties: { "class.is-collapsed": "collapsed && !peeking", "class.is-peeking": "peeking", "class.has-nav-groups": "hasNavGroups", "class.has-icons": "hasIcons", "class.is-pinnable": "pinnable" }, classAttribute: "hermes-vertical-nav" }, providers: [VerticalNavService, VerticalNavIconService, VerticalNavGroupRegistrationService], ngImport: i0, template: "<!--\r\n ~ Copyright (c) 2016-2026 Broadcom. All Rights Reserved.\r\n ~ The term \"Broadcom\" refers to Broadcom Inc. and/or its subsidiaries.\r\n ~ This software is released under MIT license.\r\n ~ The full license information can be found in LICENSE in the root directory of this project.\r\n -->\r\n\r\n@if (collapsible) {\r\n<button\r\n type=\"button\"\r\n class=\"nav-trigger\"\r\n [class.on-collapse]=\"collapsed\"\r\n [attr.aria-controls]=\"contentId\"\r\n [attr.aria-expanded]=\"ariaExpanded\"\r\n [attr.aria-label]=\"toggleLabel || commonStrings.keys.verticalNavToggle\"\r\n (click)=\"toggleByButton()\"\r\n>\r\n @if (pinnable) {\r\n <hermes-icon [shape]=\"collapsed ? 'pin' : 'unpin'\" class=\"nav-trigger-icon\"></hermes-icon>\r\n } @else {\r\n <hermes-icon shape=\"angle-double\" class=\"nav-trigger-icon\" [direction]=\"(collapsed) ? 'right' : 'left'\"></hermes-icon>\r\n }\r\n</button>\r\n}\r\n<div [id]=\"contentId\" class=\"nav-content\">\r\n <ng-content></ng-content>\r\n @if (collapsible && collapsed) {\r\n <button\r\n type=\"button\"\r\n (click)=\"collapsed = false\"\r\n class=\"nav-btn\"\r\n aria-hidden=\"true\"\r\n tabindex=\"-1\"\r\n [attr.aria-controls]=\"contentId\"\r\n [attr.aria-label]=\"toggleLabel || commonStrings.keys.verticalNavToggle\"\r\n ></button>\r\n }\r\n</div>\r\n", dependencies: [{ kind: "component", type: i5.HermesIcon, selector: "hermes-icon, hermes-icon", inputs: ["shape", "size", "direction", "flip", "solid", "status", "inverse", "badge"] }] }); }
491
+ onPointerEnter() {
492
+ if (this.pinnable && this.collapsed) {
493
+ this.peeking = true;
494
+ }
495
+ if (this._mode === 'auto') {
496
+ this.hovered = true;
497
+ this.applyMode();
498
+ }
499
+ }
500
+ onPointerLeave() {
501
+ this.peeking = false;
502
+ if (this._mode === 'auto') {
503
+ this.hovered = false;
504
+ this.applyMode();
505
+ }
506
+ }
507
+ /**
508
+ * Only keyboard focus (`:focus-visible`) holds the nav open. Clicking a link also focuses it, and
509
+ * click-focus alone would keep the nav open until something else was clicked - `:focus-visible` is
510
+ * exactly the browser's own pointer-vs-keyboard distinction, so pointer-triggered focus is left to
511
+ * the pointer's own enter/leave.
512
+ */
513
+ onFocusIn(event) {
514
+ if (this._mode !== 'auto') {
515
+ return;
516
+ }
517
+ const target = event.target;
518
+ if (!(target instanceof Element)) {
519
+ return;
520
+ }
521
+ try {
522
+ if (target.matches(':focus-visible')) {
523
+ this.focusedVisible = true;
524
+ this.applyMode();
525
+ }
526
+ }
527
+ catch {
528
+ // :focus-visible unsupported in this engine; the pointer alone decides.
529
+ }
530
+ }
531
+ /**
532
+ * Focus keeps the nav open only while it is still inside it. A missing `relatedTarget` counts as
533
+ * leaving: clicking a routed link can unmount the focused element, and treating that as "still
534
+ * inside" would pin the nav open for good.
535
+ */
536
+ onFocusOut(event) {
537
+ if (this._mode !== 'auto') {
538
+ return;
539
+ }
540
+ const related = event.relatedTarget;
541
+ const stillInside = related instanceof Node && this.host.nativeElement.contains(related);
542
+ if (!stillInside) {
543
+ this.focusedVisible = false;
544
+ this.applyMode();
545
+ }
546
+ }
547
+ // --- Footer ---------------------------------------------------------------------------------
548
+ toggleMenu() {
549
+ this.menuOpen = !this.menuOpen;
550
+ this.applyMode();
551
+ }
552
+ closeMenu(restoreFocus = false) {
553
+ if (!this.menuOpen) {
554
+ return;
555
+ }
556
+ this.menuOpen = false;
557
+ this.applyMode();
558
+ if (restoreFocus) {
559
+ this.host.nativeElement.querySelector('.nav-footer-mode-btn')?.focus();
560
+ }
561
+ }
562
+ selectMode(mode) {
563
+ this.menuOpen = false;
564
+ this.setMode(mode);
565
+ this.host.nativeElement.querySelector('.nav-footer-mode-btn')?.focus();
566
+ }
567
+ /** The footer's "expand all": opens every group, leaving `compact` first since it has nowhere to show them. */
568
+ expandAll() {
569
+ this.ensureExpanded();
570
+ this._navGroupRegistrationService.expandAll();
571
+ }
572
+ collapseAll() {
573
+ this._navGroupRegistrationService.collapseAll();
574
+ }
575
+ onFooterFocusOut(event) {
576
+ const related = event.relatedTarget;
577
+ const footer = event.currentTarget;
578
+ if (!(related instanceof Node && footer.contains(related))) {
579
+ this.closeMenu();
580
+ }
581
+ }
582
+ onDocumentClick(event) {
583
+ if (this.menuOpen && !this.host.nativeElement.querySelector('.nav-footer')?.contains(event.target)) {
584
+ this.closeMenu();
585
+ }
586
+ }
587
+ // --- Internals ------------------------------------------------------------------------------
588
+ syncCollapsible() {
589
+ this._navService.collapsible = this._collapsibleInput || this.managed;
590
+ }
591
+ setMode(mode) {
592
+ if (this._mode !== mode) {
593
+ this._mode = mode;
594
+ this.modeChange.emit(mode);
595
+ }
596
+ this.syncCollapsible();
597
+ this.applyMode();
598
+ }
599
+ ensureExpanded() {
600
+ if (this._mode === 'compact') {
601
+ this.setMode('fixed');
602
+ }
603
+ else if (this.collapsed) {
604
+ this.collapsed = false;
605
+ }
606
+ }
607
+ /**
608
+ * Derives the collapsed state from the mode. `auto` stays open while the pointer or the keyboard is
609
+ * on the nav, and also while its own menu is open - otherwise reaching for the menu, which sits
610
+ * over the list, could collapse the nav under the pointer.
611
+ */
612
+ applyMode() {
613
+ if (!this.managed) {
614
+ return;
615
+ }
616
+ let collapsed;
617
+ switch (this._mode) {
618
+ case 'fixed':
619
+ collapsed = false;
620
+ break;
621
+ case 'compact':
622
+ collapsed = true;
623
+ break;
624
+ default:
625
+ collapsed = !(this.hovered || this.focusedVisible || this.menuOpen);
626
+ }
627
+ this.collapsed = collapsed;
628
+ }
629
+ syncHoverFromDom() {
630
+ if (this._mode !== 'auto') {
631
+ return;
632
+ }
633
+ let hovering = false;
634
+ try {
635
+ hovering = this.host.nativeElement.matches(':hover');
636
+ }
637
+ catch {
638
+ return;
639
+ }
640
+ if (hovering !== this.hovered) {
641
+ this.hovered = hovering;
642
+ this.applyMode();
643
+ this.cdr.markForCheck();
644
+ }
645
+ }
646
+ scheduleMeasure() {
647
+ if (!this.isBrowser || !this.managed || !this.autoWidth) {
648
+ return;
649
+ }
650
+ clearTimeout(this.measureTimer);
651
+ this.zone.runOutsideAngular(() => {
652
+ this.measureTimer = setTimeout(() => this.measureWidth(), TRANSITION_MS + MEASURE_MARGIN_MS);
653
+ });
654
+ }
655
+ /**
656
+ * The smallest width at which every label in view fits whole. CSS clamps it between the nav's
657
+ * `min-width` and `max-width`, so this only reports what the labels ask for.
658
+ *
659
+ * The measurement is absolute rather than an adjustment on the current width: each label reports the
660
+ * column width it needs (everything around it plus its own text), and the largest wins. Measuring
661
+ * twice in a row gives the same number whether the column is wide or at its floor.
662
+ *
663
+ * Only labels in view count. A closed group's children stay in the DOM (that's how their height
664
+ * animates) but are `visibility: hidden`, and the nav shouldn't grow to fit text nobody sees.
665
+ */
666
+ measureWidth() {
667
+ const root = this.host.nativeElement;
668
+ const panel = root.querySelector('.nav-panel');
669
+ if (!panel || root.classList.contains('is-collapsed') || !this.managed || !this.autoWidth) {
670
+ return;
671
+ }
672
+ const panelWidth = panel.getBoundingClientRect().width;
673
+ const range = document.createRange();
674
+ let needed = 0;
675
+ root.querySelectorAll('.nav-content .nav-text, .nav-content .nav-group-text').forEach(label => {
676
+ const hiddenBy = label.closest('.nav-group-children');
677
+ if (hiddenBy && getComputedStyle(hiddenBy).visibility === 'hidden') {
678
+ return;
679
+ }
680
+ const box = label.getBoundingClientRect().width;
681
+ if (box < MIN_LABEL_WIDTH_PX) {
682
+ return;
683
+ }
684
+ range.selectNodeContents(label);
685
+ needed = Math.max(needed, panelWidth - box + range.getBoundingClientRect().width + LABEL_BREATHING_PX);
686
+ });
687
+ range.detach();
688
+ // No measurable label: the list isn't laid out yet. Leaving the width alone is right - guessing
689
+ // is what makes a column jump on its own.
690
+ if (needed > 0) {
691
+ root.style.setProperty(MEASURED_WIDTH_PROPERTY, `${Math.ceil(needed)}px`);
692
+ }
693
+ }
694
+ static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.22", ngImport: i0, type: HermesVerticalNav, deps: [{ token: VerticalNavService }, { token: VerticalNavIconService }, { token: VerticalNavGroupRegistrationService }, { token: i1.HermesCommonStringsService }, { token: i0.ElementRef }, { token: i0.ChangeDetectorRef }, { token: i0.NgZone }, { token: PLATFORM_ID }], target: i0.ɵɵFactoryTarget.Component }); }
695
+ static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "21.2.22", type: HermesVerticalNav, isStandalone: false, selector: "hermes-vertical-nav", inputs: { toggleLabel: ["hermesVerticalNavToggleLabel", "toggleLabel"], pinnable: ["hermesVerticalNavPinnable", "pinnable"], ariaLabel: ["hermesVerticalNavLabel", "ariaLabel"], mode: ["hermesVerticalNavMode", "mode"], footer: ["hermesVerticalNavFooter", "footer", booleanAttribute], autoWidth: ["hermesVerticalNavAutoWidth", "autoWidth", booleanAttribute], footerLabels: ["hermesVerticalNavFooterLabels", "footerLabels"], collapsible: ["hermesVerticalNavCollapsible", "collapsible"], collapsed: ["hermesVerticalNavCollapsed", "collapsed"] }, outputs: { modeChange: "hermesVerticalNavModeChange", _collapsedChanged: "hermesVerticalNavCollapsedChange" }, host: { listeners: { "mouseenter": "onPointerEnter()", "mouseleave": "onPointerLeave()", "focusin": "onFocusIn($event)", "focusout": "onFocusOut($event)", "document:click": "onDocumentClick($event)" }, properties: { "class.is-collapsed": "collapsed && !peeking", "class.is-peeking": "peeking", "class.has-nav-groups": "hasNavGroups", "class.has-icons": "hasIcons", "class.is-pinnable": "pinnable", "class.is-overlay": "overlay", "class.has-footer": "showFooter", "attr.role": "ariaLabel ? \"navigation\" : null", "attr.aria-label": "ariaLabel || null" }, classAttribute: "hermes-vertical-nav" }, providers: [VerticalNavService, VerticalNavIconService, VerticalNavGroupRegistrationService], ngImport: i0, template: "<!--\r\n ~ Copyright (c) 2016-2026 Broadcom. All Rights Reserved.\r\n ~ The term \"Broadcom\" refers to Broadcom Inc. and/or its subsidiaries.\r\n ~ This software is released under MIT license.\r\n ~ The full license information can be found in LICENSE in the root directory of this project.\r\n -->\r\n\r\n<div class=\"nav-panel\">\r\n @if (showToggle) {\r\n <button\r\n type=\"button\"\r\n class=\"nav-trigger\"\r\n [class.on-collapse]=\"collapsed\"\r\n [attr.aria-controls]=\"contentId\"\r\n [attr.aria-expanded]=\"ariaExpanded\"\r\n [attr.aria-label]=\"toggleLabel || commonStrings.keys.verticalNavToggle\"\r\n (click)=\"toggleByButton()\"\r\n >\r\n @if (pinnable) {\r\n <hermes-icon [shape]=\"collapsed ? 'pin' : 'unpin'\" class=\"nav-trigger-icon\"></hermes-icon>\r\n } @else {\r\n <hermes-icon shape=\"angle-double\" class=\"nav-trigger-icon\" [direction]=\"(collapsed) ? 'right' : 'left'\"></hermes-icon>\r\n }\r\n </button>\r\n }\r\n <div [id]=\"contentId\" class=\"nav-content\">\r\n <ng-content></ng-content>\r\n @if (collapsible && collapsed && !managed) {\r\n <button\r\n type=\"button\"\r\n (click)=\"collapsed = false\"\r\n class=\"nav-btn\"\r\n aria-hidden=\"true\"\r\n tabindex=\"-1\"\r\n [attr.aria-controls]=\"contentId\"\r\n [attr.aria-label]=\"toggleLabel || commonStrings.keys.verticalNavToggle\"\r\n ></button>\r\n }\r\n </div>\r\n @if (showFooter) {\r\n <div class=\"nav-footer\" (focusout)=\"onFooterFocusOut($event)\" (keydown.escape)=\"closeMenu(true)\">\r\n <button\r\n type=\"button\"\r\n class=\"nav-footer-btn nav-footer-mode-btn\"\r\n aria-haspopup=\"menu\"\r\n [attr.aria-expanded]=\"menuOpen\"\r\n [attr.aria-label]=\"label('behavior') + ': ' + currentModeLabel\"\r\n [title]=\"label('behavior') + ': ' + currentModeLabel\"\r\n (click)=\"toggleMenu()\"\r\n >\r\n <hermes-icon [shape]=\"currentMode.shape\"></hermes-icon>\r\n </button>\r\n <span class=\"nav-footer-mode\">{{ currentModeLabel }}</span>\r\n <button\r\n type=\"button\"\r\n class=\"nav-footer-btn nav-footer-batch\"\r\n [attr.aria-label]=\"label('expandAll')\"\r\n [title]=\"label('expandAll')\"\r\n (click)=\"expandAll()\"\r\n >\r\n <hermes-icon shape=\"angle-double\" direction=\"down\"></hermes-icon>\r\n </button>\r\n <button\r\n type=\"button\"\r\n class=\"nav-footer-btn nav-footer-batch\"\r\n [attr.aria-label]=\"label('collapseAll')\"\r\n [title]=\"label('collapseAll')\"\r\n (click)=\"collapseAll()\"\r\n >\r\n <hermes-icon shape=\"angle-double\" direction=\"up\"></hermes-icon>\r\n </button>\r\n @if (menuOpen) {\r\n <div class=\"nav-footer-menu\" role=\"menu\" [attr.aria-label]=\"label('behavior')\">\r\n @for (item of modes; track item.id) {\r\n <button\r\n type=\"button\"\r\n class=\"nav-footer-menu-item\"\r\n role=\"menuitemradio\"\r\n [attr.aria-checked]=\"item.id === mode\"\r\n (click)=\"selectMode(item.id)\"\r\n >\r\n <hermes-icon [shape]=\"item.shape\"></hermes-icon>\r\n <span class=\"nav-footer-menu-label\">{{ label(item.id) }}</span>\r\n @if (item.id === mode) {\r\n <hermes-icon shape=\"check\"></hermes-icon>\r\n }\r\n </button>\r\n }\r\n </div>\r\n }\r\n </div>\r\n }\r\n</div>\r\n", dependencies: [{ kind: "component", type: i5.HermesIcon, selector: "hermes-icon, hermes-icon", inputs: ["shape", "size", "direction", "flip", "solid", "status", "inverse", "badge"] }] }); }
372
696
  }
373
697
  i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.22", ngImport: i0, type: HermesVerticalNav, decorators: [{
374
698
  type: Component,
@@ -384,15 +708,42 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.22", ngImpo
384
708
  '[class.has-nav-groups]': 'hasNavGroups',
385
709
  '[class.has-icons]': 'hasIcons',
386
710
  '[class.is-pinnable]': 'pinnable',
387
- '(mouseenter)': 'onPeekEnter()',
388
- '(mouseleave)': 'onPeekLeave()',
389
- }, standalone: false, template: "<!--\r\n ~ Copyright (c) 2016-2026 Broadcom. All Rights Reserved.\r\n ~ The term \"Broadcom\" refers to Broadcom Inc. and/or its subsidiaries.\r\n ~ This software is released under MIT license.\r\n ~ The full license information can be found in LICENSE in the root directory of this project.\r\n -->\r\n\r\n@if (collapsible) {\r\n<button\r\n type=\"button\"\r\n class=\"nav-trigger\"\r\n [class.on-collapse]=\"collapsed\"\r\n [attr.aria-controls]=\"contentId\"\r\n [attr.aria-expanded]=\"ariaExpanded\"\r\n [attr.aria-label]=\"toggleLabel || commonStrings.keys.verticalNavToggle\"\r\n (click)=\"toggleByButton()\"\r\n>\r\n @if (pinnable) {\r\n <hermes-icon [shape]=\"collapsed ? 'pin' : 'unpin'\" class=\"nav-trigger-icon\"></hermes-icon>\r\n } @else {\r\n <hermes-icon shape=\"angle-double\" class=\"nav-trigger-icon\" [direction]=\"(collapsed) ? 'right' : 'left'\"></hermes-icon>\r\n }\r\n</button>\r\n}\r\n<div [id]=\"contentId\" class=\"nav-content\">\r\n <ng-content></ng-content>\r\n @if (collapsible && collapsed) {\r\n <button\r\n type=\"button\"\r\n (click)=\"collapsed = false\"\r\n class=\"nav-btn\"\r\n aria-hidden=\"true\"\r\n tabindex=\"-1\"\r\n [attr.aria-controls]=\"contentId\"\r\n [attr.aria-label]=\"toggleLabel || commonStrings.keys.verticalNavToggle\"\r\n ></button>\r\n }\r\n</div>\r\n" }]
390
- }], ctorParameters: () => [{ type: VerticalNavService }, { type: VerticalNavIconService }, { type: VerticalNavGroupRegistrationService }, { type: i1.HermesCommonStringsService }], propDecorators: { toggleLabel: [{
711
+ '[class.is-overlay]': 'overlay',
712
+ '[class.has-footer]': 'showFooter',
713
+ '[attr.role]': 'ariaLabel ? "navigation" : null',
714
+ '[attr.aria-label]': 'ariaLabel || null',
715
+ '(mouseenter)': 'onPointerEnter()',
716
+ '(mouseleave)': 'onPointerLeave()',
717
+ '(focusin)': 'onFocusIn($event)',
718
+ '(focusout)': 'onFocusOut($event)',
719
+ }, standalone: false, template: "<!--\r\n ~ Copyright (c) 2016-2026 Broadcom. All Rights Reserved.\r\n ~ The term \"Broadcom\" refers to Broadcom Inc. and/or its subsidiaries.\r\n ~ This software is released under MIT license.\r\n ~ The full license information can be found in LICENSE in the root directory of this project.\r\n -->\r\n\r\n<div class=\"nav-panel\">\r\n @if (showToggle) {\r\n <button\r\n type=\"button\"\r\n class=\"nav-trigger\"\r\n [class.on-collapse]=\"collapsed\"\r\n [attr.aria-controls]=\"contentId\"\r\n [attr.aria-expanded]=\"ariaExpanded\"\r\n [attr.aria-label]=\"toggleLabel || commonStrings.keys.verticalNavToggle\"\r\n (click)=\"toggleByButton()\"\r\n >\r\n @if (pinnable) {\r\n <hermes-icon [shape]=\"collapsed ? 'pin' : 'unpin'\" class=\"nav-trigger-icon\"></hermes-icon>\r\n } @else {\r\n <hermes-icon shape=\"angle-double\" class=\"nav-trigger-icon\" [direction]=\"(collapsed) ? 'right' : 'left'\"></hermes-icon>\r\n }\r\n </button>\r\n }\r\n <div [id]=\"contentId\" class=\"nav-content\">\r\n <ng-content></ng-content>\r\n @if (collapsible && collapsed && !managed) {\r\n <button\r\n type=\"button\"\r\n (click)=\"collapsed = false\"\r\n class=\"nav-btn\"\r\n aria-hidden=\"true\"\r\n tabindex=\"-1\"\r\n [attr.aria-controls]=\"contentId\"\r\n [attr.aria-label]=\"toggleLabel || commonStrings.keys.verticalNavToggle\"\r\n ></button>\r\n }\r\n </div>\r\n @if (showFooter) {\r\n <div class=\"nav-footer\" (focusout)=\"onFooterFocusOut($event)\" (keydown.escape)=\"closeMenu(true)\">\r\n <button\r\n type=\"button\"\r\n class=\"nav-footer-btn nav-footer-mode-btn\"\r\n aria-haspopup=\"menu\"\r\n [attr.aria-expanded]=\"menuOpen\"\r\n [attr.aria-label]=\"label('behavior') + ': ' + currentModeLabel\"\r\n [title]=\"label('behavior') + ': ' + currentModeLabel\"\r\n (click)=\"toggleMenu()\"\r\n >\r\n <hermes-icon [shape]=\"currentMode.shape\"></hermes-icon>\r\n </button>\r\n <span class=\"nav-footer-mode\">{{ currentModeLabel }}</span>\r\n <button\r\n type=\"button\"\r\n class=\"nav-footer-btn nav-footer-batch\"\r\n [attr.aria-label]=\"label('expandAll')\"\r\n [title]=\"label('expandAll')\"\r\n (click)=\"expandAll()\"\r\n >\r\n <hermes-icon shape=\"angle-double\" direction=\"down\"></hermes-icon>\r\n </button>\r\n <button\r\n type=\"button\"\r\n class=\"nav-footer-btn nav-footer-batch\"\r\n [attr.aria-label]=\"label('collapseAll')\"\r\n [title]=\"label('collapseAll')\"\r\n (click)=\"collapseAll()\"\r\n >\r\n <hermes-icon shape=\"angle-double\" direction=\"up\"></hermes-icon>\r\n </button>\r\n @if (menuOpen) {\r\n <div class=\"nav-footer-menu\" role=\"menu\" [attr.aria-label]=\"label('behavior')\">\r\n @for (item of modes; track item.id) {\r\n <button\r\n type=\"button\"\r\n class=\"nav-footer-menu-item\"\r\n role=\"menuitemradio\"\r\n [attr.aria-checked]=\"item.id === mode\"\r\n (click)=\"selectMode(item.id)\"\r\n >\r\n <hermes-icon [shape]=\"item.shape\"></hermes-icon>\r\n <span class=\"nav-footer-menu-label\">{{ label(item.id) }}</span>\r\n @if (item.id === mode) {\r\n <hermes-icon shape=\"check\"></hermes-icon>\r\n }\r\n </button>\r\n }\r\n </div>\r\n }\r\n </div>\r\n }\r\n</div>\r\n" }]
720
+ }], ctorParameters: () => [{ type: VerticalNavService }, { type: VerticalNavIconService }, { type: VerticalNavGroupRegistrationService }, { type: i1.HermesCommonStringsService }, { type: i0.ElementRef }, { type: i0.ChangeDetectorRef }, { type: i0.NgZone }, { type: undefined, decorators: [{
721
+ type: Inject,
722
+ args: [PLATFORM_ID]
723
+ }] }], propDecorators: { toggleLabel: [{
391
724
  type: Input,
392
725
  args: ['hermesVerticalNavToggleLabel']
393
726
  }], pinnable: [{
394
727
  type: Input,
395
728
  args: ['hermesVerticalNavPinnable']
729
+ }], ariaLabel: [{
730
+ type: Input,
731
+ args: ['hermesVerticalNavLabel']
732
+ }], mode: [{
733
+ type: Input,
734
+ args: ['hermesVerticalNavMode']
735
+ }], footer: [{
736
+ type: Input,
737
+ args: [{ alias: 'hermesVerticalNavFooter', transform: booleanAttribute }]
738
+ }], autoWidth: [{
739
+ type: Input,
740
+ args: [{ alias: 'hermesVerticalNavAutoWidth', transform: booleanAttribute }]
741
+ }], footerLabels: [{
742
+ type: Input,
743
+ args: ['hermesVerticalNavFooterLabels']
744
+ }], modeChange: [{
745
+ type: Output,
746
+ args: ['hermesVerticalNavModeChange']
396
747
  }], _collapsedChanged: [{
397
748
  type: Output,
398
749
  args: ['hermesVerticalNavCollapsedChange']
@@ -402,6 +753,9 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.22", ngImpo
402
753
  }], collapsed: [{
403
754
  type: Input,
404
755
  args: ['hermesVerticalNavCollapsed']
756
+ }], onDocumentClick: [{
757
+ type: HostListener,
758
+ args: ['document:click', ['$event']]
405
759
  }] } });
406
760
 
407
761
  /*
@@ -497,7 +851,7 @@ const HERMES_VERTICAL_NAV_DIRECTIVES = [
497
851
  ];
498
852
  class HermesVerticalNavModule {
499
853
  constructor() {
500
- ClarityIcons.addIcons(angleIcon, angleDoubleIcon);
854
+ HermesIcons.addIcons(angleIcon, angleDoubleIcon, barsIcon, checkIcon, pinIcon, unpinIcon, twoWayArrowsIcon);
501
855
  }
502
856
  static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.22", ngImport: i0, type: HermesVerticalNavModule, deps: [], target: i0.ɵɵFactoryTarget.NgModule }); }
503
857
  static { this.ɵmod = i0.ɵɵngDeclareNgModule({ minVersion: "14.0.0", version: "21.2.22", ngImport: i0, type: HermesVerticalNavModule, declarations: [HermesVerticalNav,