@caribeng/ui 22.2.0 → 22.4.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 (121) hide show
  1. package/README.md +93 -11
  2. package/fesm2022/caribeng-ui-accordion.mjs +2 -2
  3. package/fesm2022/caribeng-ui-avatar.mjs +2 -2
  4. package/fesm2022/caribeng-ui-badge.mjs +8 -2
  5. package/fesm2022/caribeng-ui-breadcrumb.mjs +13 -6
  6. package/fesm2022/caribeng-ui-chart.mjs +8 -5
  7. package/fesm2022/caribeng-ui-chat.mjs +1303 -0
  8. package/fesm2022/caribeng-ui-code-block.mjs +332 -0
  9. package/fesm2022/caribeng-ui-colorpicker.mjs +99 -5
  10. package/fesm2022/caribeng-ui-command-palette.mjs +476 -0
  11. package/fesm2022/caribeng-ui-confirmdialog.mjs +78 -13
  12. package/fesm2022/caribeng-ui-confirmpopup.mjs +91 -16
  13. package/fesm2022/caribeng-ui-contextmenu.mjs +8 -4
  14. package/fesm2022/caribeng-ui-copy-button.mjs +230 -0
  15. package/fesm2022/caribeng-ui-dataview.mjs +4 -1
  16. package/fesm2022/caribeng-ui-dock.mjs +52 -12
  17. package/fesm2022/caribeng-ui-drawer.mjs +9 -4
  18. package/fesm2022/caribeng-ui-editor.mjs +21 -0
  19. package/fesm2022/caribeng-ui-fieldset.mjs +2 -2
  20. package/fesm2022/caribeng-ui-file-card.mjs +134 -17
  21. package/fesm2022/caribeng-ui-folder-card.mjs +122 -12
  22. package/fesm2022/caribeng-ui-inlinemessage.mjs +2 -2
  23. package/fesm2022/caribeng-ui-inputmask.mjs +8 -2
  24. package/fesm2022/caribeng-ui-kanban.mjs +4612 -0
  25. package/fesm2022/caribeng-ui-kbd.mjs +122 -0
  26. package/fesm2022/caribeng-ui-megamenu.mjs +13 -9
  27. package/fesm2022/caribeng-ui-mentions.mjs +495 -0
  28. package/fesm2022/caribeng-ui-menu.mjs +8 -4
  29. package/fesm2022/caribeng-ui-menubar.mjs +9 -5
  30. package/fesm2022/caribeng-ui-message.mjs +6 -3
  31. package/fesm2022/caribeng-ui-organizationchart.mjs +6 -10
  32. package/fesm2022/caribeng-ui-panel.mjs +6 -6
  33. package/fesm2022/caribeng-ui-panelmenu.mjs +9 -6
  34. package/fesm2022/caribeng-ui-phone-input.mjs +688 -0
  35. package/fesm2022/caribeng-ui-pricing.mjs +263 -69
  36. package/fesm2022/caribeng-ui-qrcode.mjs +564 -0
  37. package/fesm2022/caribeng-ui-ripple.mjs +2 -0
  38. package/fesm2022/caribeng-ui-scrolltop.mjs +3 -1
  39. package/fesm2022/caribeng-ui-sidebar.mjs +573 -0
  40. package/fesm2022/caribeng-ui-stepper.mjs +10 -3
  41. package/fesm2022/caribeng-ui-table.mjs +10 -4
  42. package/fesm2022/caribeng-ui-tabmenu.mjs +8 -4
  43. package/fesm2022/caribeng-ui-tieredmenu.mjs +109 -19
  44. package/fesm2022/caribeng-ui.mjs +388 -1
  45. package/package.json +42 -2
  46. package/schematics/collection.json +5 -0
  47. package/schematics/migrate-from-primeng/core-icons.json +1 -0
  48. package/schematics/migrate-from-primeng/icons.js +269 -0
  49. package/schematics/migrate-from-primeng/index.js +290 -0
  50. package/schematics/migrate-from-primeng/mappings/button.js +93 -0
  51. package/schematics/migrate-from-primeng/mappings/card.js +33 -0
  52. package/schematics/migrate-from-primeng/mappings/checkbox.js +44 -0
  53. package/schematics/migrate-from-primeng/mappings/confirm.js +221 -0
  54. package/schematics/migrate-from-primeng/mappings/datepicker.js +121 -0
  55. package/schematics/migrate-from-primeng/mappings/dialog.js +84 -0
  56. package/schematics/migrate-from-primeng/mappings/index.js +88 -0
  57. package/schematics/migrate-from-primeng/mappings/inputnumber.js +62 -0
  58. package/schematics/migrate-from-primeng/mappings/inputtext.js +60 -0
  59. package/schematics/migrate-from-primeng/mappings/menu.js +468 -0
  60. package/schematics/migrate-from-primeng/mappings/multiselect.js +49 -0
  61. package/schematics/migrate-from-primeng/mappings/radiobutton.js +22 -0
  62. package/schematics/migrate-from-primeng/mappings/rules.js +206 -0
  63. package/schematics/migrate-from-primeng/mappings/select.js +97 -0
  64. package/schematics/migrate-from-primeng/mappings/service-calls.js +100 -0
  65. package/schematics/migrate-from-primeng/mappings/table.js +613 -0
  66. package/schematics/migrate-from-primeng/mappings/tabs.js +225 -0
  67. package/schematics/migrate-from-primeng/mappings/tag.js +29 -0
  68. package/schematics/migrate-from-primeng/mappings/textarea.js +44 -0
  69. package/schematics/migrate-from-primeng/mappings/toast.js +173 -0
  70. package/schematics/migrate-from-primeng/mappings/toggleswitch.js +37 -0
  71. package/schematics/migrate-from-primeng/mappings/tooltip.js +44 -0
  72. package/schematics/migrate-from-primeng/mappings/types.js +10 -0
  73. package/schematics/migrate-from-primeng/report.js +79 -0
  74. package/schematics/migrate-from-primeng/schema.js +2 -0
  75. package/schematics/migrate-from-primeng/schema.json +34 -0
  76. package/schematics/migrate-from-primeng/template.js +387 -0
  77. package/schematics/migrate-from-primeng/todo.js +5 -0
  78. package/schematics/migrate-from-primeng/typescript.js +442 -0
  79. package/schematics/migrate-from-primeng/workspace.js +117 -0
  80. package/schematics/ng-add/index.js +16 -1
  81. package/types/caribeng-ui-badge.d.ts +3 -1
  82. package/types/caribeng-ui-breadcrumb.d.ts +8 -0
  83. package/types/caribeng-ui-chart.d.ts +3 -1
  84. package/types/caribeng-ui-chat.d.ts +299 -0
  85. package/types/caribeng-ui-code-block.d.ts +65 -0
  86. package/types/caribeng-ui-colorpicker.d.ts +5 -1
  87. package/types/caribeng-ui-command-palette.d.ts +133 -0
  88. package/types/caribeng-ui-confirmdialog.d.ts +34 -2
  89. package/types/caribeng-ui-confirmpopup.d.ts +39 -2
  90. package/types/caribeng-ui-contextmenu.d.ts +7 -0
  91. package/types/caribeng-ui-copy-button.d.ts +90 -0
  92. package/types/caribeng-ui-dataview.d.ts +2 -0
  93. package/types/caribeng-ui-dock.d.ts +13 -1
  94. package/types/caribeng-ui-drawer.d.ts +3 -1
  95. package/types/caribeng-ui-file-card.d.ts +27 -2
  96. package/types/caribeng-ui-folder-card.d.ts +27 -5
  97. package/types/caribeng-ui-inputmask.d.ts +3 -1
  98. package/types/caribeng-ui-kanban.d.ts +783 -0
  99. package/types/caribeng-ui-kbd.d.ts +36 -0
  100. package/types/caribeng-ui-megamenu.d.ts +11 -0
  101. package/types/caribeng-ui-mentions.d.ts +127 -0
  102. package/types/caribeng-ui-menu.d.ts +7 -0
  103. package/types/caribeng-ui-menubar.d.ts +7 -0
  104. package/types/caribeng-ui-message.d.ts +2 -0
  105. package/types/caribeng-ui-panelmenu.d.ts +7 -0
  106. package/types/caribeng-ui-phone-input.d.ts +168 -0
  107. package/types/caribeng-ui-pricing.d.ts +41 -4
  108. package/types/caribeng-ui-qrcode.d.ts +88 -0
  109. package/types/caribeng-ui-sidebar.d.ts +167 -0
  110. package/types/caribeng-ui-stepper.d.ts +2 -0
  111. package/types/caribeng-ui-table.d.ts +1 -1
  112. package/types/caribeng-ui-tabmenu.d.ts +7 -0
  113. package/types/caribeng-ui-tieredmenu.d.ts +17 -1
  114. package/types/caribeng-ui.d.ts +276 -2
  115. package/styles/caribeng.css +0 -380
  116. package/styles/scss/_mixins.scss +0 -46
  117. package/styles/scss/_overlay.scss +0 -15
  118. package/styles/scss/_tokens.scss +0 -267
  119. package/styles/scss/_utilities.scss +0 -73
  120. package/styles/scss/_variables.scss +0 -33
  121. package/styles/scss/index.scss +0 -16
@@ -475,7 +475,7 @@ class CbTable {
475
475
  }
476
476
  // --- Helpers ---------------------------------------------------------------
477
477
  cellValue(row, col) {
478
- return row != null && typeof row === 'object' ? row[col.field] : row;
478
+ return fieldValue(row, col.field);
479
479
  }
480
480
  cellTemplate(field) {
481
481
  return this.cellTemplates().find((cell) => cell.cbTableCell() === field);
@@ -505,8 +505,8 @@ class CbTable {
505
505
  return a === b;
506
506
  }
507
507
  compare(a, b, field) {
508
- const av = a?.[field];
509
- const bv = b?.[field];
508
+ const av = fieldValue(a, field);
509
+ const bv = fieldValue(b, field);
510
510
  if (av == null)
511
511
  return bv == null ? 0 : -1;
512
512
  if (bv == null)
@@ -981,8 +981,14 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.0.5", ngImpor
981
981
  function toBoolean(value) {
982
982
  return value !== false && value != null && `${value}` !== 'false';
983
983
  }
984
+ /** Valor de `field` en la fila; admite rutas (`cliente.nombre`), como `field` en PrimeNG. */
984
985
  function fieldValue(row, field) {
985
- return row != null && typeof row === 'object' ? row[field] : row;
986
+ if (row == null || typeof row !== 'object')
987
+ return row;
988
+ const record = row;
989
+ if (field in record || !field.includes('.'))
990
+ return record[field];
991
+ return field.split('.').reduce((value, key) => (value != null && typeof value === 'object' ? value[key] : undefined), row);
986
992
  }
987
993
  /** Minúsculas y sin tildes, para que "jose" encuentre "José". */
988
994
  function normalize(text) {
@@ -1,7 +1,7 @@
1
1
  import * as i0 from '@angular/core';
2
- import { input, model, output, ViewEncapsulation, ChangeDetectionStrategy, Component } from '@angular/core';
2
+ import { input, computed, model, output, ViewEncapsulation, ChangeDetectionStrategy, Component } from '@angular/core';
3
3
  import { CbIcon } from '@caribeng/ui/icon';
4
- import { injectCbTranslation } from '@caribeng/ui';
4
+ import { injectCbTranslation, cbVisibleItems, cbRunCommand } from '@caribeng/ui';
5
5
 
6
6
  /** Horizontal navigation menu with an active item. */
7
7
  class CbTabMenu {
@@ -10,6 +10,9 @@ class CbTabMenu {
10
10
  this.t = injectCbTranslation();
11
11
  this.items = input([], /* @ts-ignore */
12
12
  ...(ngDevMode ? [{ debugName: "items" }] : /* istanbul ignore next */ []));
13
+ /** Items sin los de `visible: false`. */
14
+ this.visibleItems = computed(() => cbVisibleItems(this.items()), /* @ts-ignore */
15
+ ...(ngDevMode ? [{ debugName: "visibleItems" }] : /* istanbul ignore next */ []));
13
16
  this.activeIndex = model(0, /* @ts-ignore */
14
17
  ...(ngDevMode ? [{ debugName: "activeIndex" }] : /* istanbul ignore next */ []));
15
18
  this.ariaLabel = input(undefined, /* @ts-ignore */
@@ -20,13 +23,14 @@ class CbTabMenu {
20
23
  if (item.disabled)
21
24
  return;
22
25
  this.activeIndex.set(index);
26
+ cbRunCommand(item);
23
27
  this.itemSelect.emit(item);
24
28
  }
25
29
  static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "22.0.5", ngImport: i0, type: CbTabMenu, deps: [], target: i0.ɵɵFactoryTarget.Component }); }
26
30
  static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "22.0.5", type: CbTabMenu, isStandalone: true, selector: "cb-tabmenu", inputs: { items: { classPropertyName: "items", publicName: "items", isSignal: true, isRequired: false, transformFunction: null }, activeIndex: { classPropertyName: "activeIndex", publicName: "activeIndex", isSignal: true, isRequired: false, transformFunction: null }, ariaLabel: { classPropertyName: "ariaLabel", publicName: "ariaLabel", isSignal: true, isRequired: false, transformFunction: null } }, outputs: { activeIndex: "activeIndexChange", itemSelect: "itemSelect" }, host: { classAttribute: "cb-tabmenu" }, ngImport: i0, template: `
27
31
  <nav [attr.aria-label]="(ariaLabel() ?? t().sectionNavigation)">
28
32
  <ul class="cb-tabmenu__list">
29
- @for (item of items(); track $index; let i = $index) {
33
+ @for (item of visibleItems(); track $index; let i = $index) {
30
34
  <li class="cb-tabmenu__entry">
31
35
  @if (item.url && !item.disabled) {
32
36
  <a class="cb-tabmenu__link" [href]="item.url" [attr.aria-current]="activeIndex() === i ? 'page' : null" [attr.tabindex]="item.disabled ? -1 : 0" (click)="select(item, i)">
@@ -50,7 +54,7 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.0.5", ngImpor
50
54
  args: [{ selector: 'cb-tabmenu', changeDetection: ChangeDetectionStrategy.OnPush, encapsulation: ViewEncapsulation.Emulated, imports: [CbIcon], host: { class: 'cb-tabmenu' }, template: `
51
55
  <nav [attr.aria-label]="(ariaLabel() ?? t().sectionNavigation)">
52
56
  <ul class="cb-tabmenu__list">
53
- @for (item of items(); track $index; let i = $index) {
57
+ @for (item of visibleItems(); track $index; let i = $index) {
54
58
  <li class="cb-tabmenu__entry">
55
59
  @if (item.url && !item.disabled) {
56
60
  <a class="cb-tabmenu__link" [href]="item.url" [attr.aria-current]="activeIndex() === i ? 'page' : null" [attr.tabindex]="item.disabled ? -1 : 0" (click)="select(item, i)">
@@ -1,9 +1,9 @@
1
1
  import * as i0 from '@angular/core';
2
- import { inject, ViewContainerRef, DestroyRef, input, output, signal, viewChild, ViewEncapsulation, ChangeDetectionStrategy, Component } from '@angular/core';
2
+ import { inject, ViewContainerRef, DestroyRef, input, computed, output, signal, viewChild, Injector, afterNextRender, ViewEncapsulation, ChangeDetectionStrategy, Component } from '@angular/core';
3
3
  import { Overlay } from '@angular/cdk/overlay';
4
4
  import { TemplatePortal } from '@angular/cdk/portal';
5
5
  import { CbIcon } from '@caribeng/ui/icon';
6
- import { injectCbTranslation } from '@caribeng/ui';
6
+ import { injectCbTranslation, cbVisibleItems, cbRunCommand } from '@caribeng/ui';
7
7
 
8
8
  /** Popup menu with cascading submenus. */
9
9
  class CbTieredMenu {
@@ -15,6 +15,9 @@ class CbTieredMenu {
15
15
  this.destroyRef = inject(DestroyRef);
16
16
  this.items = input([], /* @ts-ignore */
17
17
  ...(ngDevMode ? [{ debugName: "items" }] : /* istanbul ignore next */ []));
18
+ /** Items sin los de `visible: false`. */
19
+ this.visibleItems = computed(() => cbVisibleItems(this.items()), /* @ts-ignore */
20
+ ...(ngDevMode ? [{ debugName: "visibleItems" }] : /* istanbul ignore next */ []));
18
21
  this.ariaLabel = input(undefined, /* @ts-ignore */
19
22
  ...(ngDevMode ? [{ debugName: "ariaLabel" }] : /* istanbul ignore next */ []));
20
23
  this.triggerLabel = input(undefined, /* @ts-ignore */
@@ -33,6 +36,8 @@ class CbTieredMenu {
33
36
  { originX: 'start', originY: 'top', overlayX: 'start', overlayY: 'bottom', offsetY: -4 },
34
37
  { originX: 'end', originY: 'bottom', overlayX: 'end', overlayY: 'top', offsetY: 4 },
35
38
  ];
39
+ this.injector = inject(Injector);
40
+ this.trigger = viewChild.required('trigger');
36
41
  this.destroyRef.onDestroy(() => this.overlayRef?.dispose());
37
42
  }
38
43
  toggle(event) { if (this.overlayRef)
@@ -46,26 +51,111 @@ class CbTieredMenu {
46
51
  this.overlayRef = ref;
47
52
  this.isOpen.set(true);
48
53
  ref.attach(new TemplatePortal(this.content(), this.vcr));
49
- ref.backdropClick().subscribe(() => this.hide());
54
+ ref.backdropClick().subscribe(() => this.hide(false));
50
55
  ref.keydownEvents().subscribe((event) => { if (event.key === 'Escape') {
51
56
  event.preventDefault();
52
57
  this.hide();
53
58
  } });
59
+ // Patrón WAI-ARIA menu: al abrir, el foco pasa al primer item.
60
+ afterNextRender(() => this.focusFirst(ref.overlayElement.querySelector('.cb-tieredmenu__list')), { injector: this.injector });
54
61
  }
55
62
  select(item) { if (item.disabled)
56
- return; this.itemSelect.emit(item); this.hide(); }
57
- hide() { this.overlayRef?.dispose(); this.overlayRef = null; this.isOpen.set(false); this.openIndex.set(null); this.openChildIndex.set(null); }
63
+ return; cbRunCommand(item); this.itemSelect.emit(item); this.hide(); }
64
+ /** Cierra el menú; con `restoreFocus` (por defecto) el foco vuelve al botón que lo abre. */
65
+ hide(restoreFocus = true) {
66
+ const wasOpen = !!this.overlayRef;
67
+ this.overlayRef?.dispose();
68
+ this.overlayRef = null;
69
+ this.isOpen.set(false);
70
+ this.openIndex.set(null);
71
+ this.openChildIndex.set(null);
72
+ if (wasOpen && restoreFocus)
73
+ this.trigger().nativeElement.focus();
74
+ }
75
+ onTriggerKeydown(event) {
76
+ if (event.key !== 'ArrowDown' || this.overlayRef)
77
+ return;
78
+ event.preventDefault();
79
+ this.show(event.currentTarget);
80
+ }
81
+ /** Flechas, Inicio y Fin dentro de cada nivel; derecha abre el submenú e izquierda vuelve al nivel anterior. */
82
+ onMenuKeydown(event) {
83
+ const item = event.target.closest('[role="menuitem"]');
84
+ const menu = item?.closest('[role="menu"]');
85
+ if (!item || !menu)
86
+ return;
87
+ const items = this.menuItems(menu);
88
+ const at = items.indexOf(item);
89
+ const opensSubmenu = item.getAttribute('aria-haspopup') === 'menu';
90
+ switch (event.key) {
91
+ case 'ArrowDown':
92
+ items[(at + 1) % items.length]?.focus();
93
+ break;
94
+ case 'ArrowUp':
95
+ items[(at - 1 + items.length) % items.length]?.focus();
96
+ break;
97
+ case 'Home':
98
+ items[0]?.focus();
99
+ break;
100
+ case 'End':
101
+ items[items.length - 1]?.focus();
102
+ break;
103
+ case 'ArrowRight':
104
+ case 'Enter':
105
+ case ' ':
106
+ if (!opensSubmenu)
107
+ return;
108
+ this.openSubmenu(item);
109
+ break;
110
+ case 'ArrowLeft': {
111
+ if (menu.classList.contains('cb-tieredmenu__list'))
112
+ break;
113
+ const parent = menu.parentElement?.querySelector(':scope > [role="menuitem"]');
114
+ if (parent?.dataset['level'] === '1') {
115
+ this.openIndex.set(null);
116
+ this.openChildIndex.set(null);
117
+ }
118
+ else
119
+ this.openChildIndex.set(null);
120
+ parent?.focus();
121
+ break;
122
+ }
123
+ case 'Tab':
124
+ this.hide();
125
+ break;
126
+ default: return;
127
+ }
128
+ event.preventDefault();
129
+ }
130
+ openSubmenu(item) {
131
+ const index = Number(item.dataset['index']);
132
+ if (item.dataset['level'] === '1') {
133
+ this.openIndex.set(index);
134
+ this.openChildIndex.set(null);
135
+ }
136
+ else
137
+ this.openChildIndex.set(index);
138
+ // El submenú se pinta en el siguiente render (zoneless): se enfoca después.
139
+ afterNextRender(() => this.focusFirst(item.parentElement?.querySelector(':scope > [role="menu"]') ?? null), { injector: this.injector });
140
+ }
141
+ menuItems(menu) {
142
+ return Array.from(menu.querySelectorAll(':scope > li > [role="menuitem"]')).filter((el) => !el.hasAttribute('disabled'));
143
+ }
144
+ focusFirst(menu) {
145
+ if (menu)
146
+ this.menuItems(menu)[0]?.focus();
147
+ }
58
148
  static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "22.0.5", ngImport: i0, type: CbTieredMenu, deps: [], target: i0.ɵɵFactoryTarget.Component }); }
59
- static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "22.0.5", type: CbTieredMenu, isStandalone: true, selector: "cb-tieredmenu", inputs: { items: { classPropertyName: "items", publicName: "items", isSignal: true, isRequired: false, transformFunction: null }, ariaLabel: { classPropertyName: "ariaLabel", publicName: "ariaLabel", isSignal: true, isRequired: false, transformFunction: null }, triggerLabel: { classPropertyName: "triggerLabel", publicName: "triggerLabel", isSignal: true, isRequired: false, transformFunction: null } }, outputs: { itemSelect: "itemSelect" }, viewQueries: [{ propertyName: "content", first: true, predicate: ["content"], descendants: true, isSignal: true }], ngImport: i0, template: `
60
- <button class="cb-tieredmenu__trigger" type="button" [attr.aria-expanded]="isOpen()" aria-haspopup="menu" (click)="toggle($event)">{{ (triggerLabel() ?? t().menu) }}</button>
149
+ static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "22.0.5", type: CbTieredMenu, isStandalone: true, selector: "cb-tieredmenu", inputs: { items: { classPropertyName: "items", publicName: "items", isSignal: true, isRequired: false, transformFunction: null }, ariaLabel: { classPropertyName: "ariaLabel", publicName: "ariaLabel", isSignal: true, isRequired: false, transformFunction: null }, triggerLabel: { classPropertyName: "triggerLabel", publicName: "triggerLabel", isSignal: true, isRequired: false, transformFunction: null } }, outputs: { itemSelect: "itemSelect" }, viewQueries: [{ propertyName: "content", first: true, predicate: ["content"], descendants: true, isSignal: true }, { propertyName: "trigger", first: true, predicate: ["trigger"], descendants: true, isSignal: true }], ngImport: i0, template: `
150
+ <button #trigger class="cb-tieredmenu__trigger" type="button" [attr.aria-expanded]="isOpen()" aria-haspopup="menu" (click)="toggle($event)" (keydown)="onTriggerKeydown($event)">{{ (triggerLabel() ?? t().menu) }}</button>
61
151
  <ng-template #content>
62
- <ul class="cb-tieredmenu__list" role="menu" [attr.aria-label]="(ariaLabel() ?? t().menu)">
63
- @for (item of items(); track $index; let i = $index) {
152
+ <ul class="cb-tieredmenu__list" role="menu" [attr.aria-label]="(ariaLabel() ?? t().menu)" (keydown)="onMenuKeydown($event)">
153
+ @for (item of visibleItems(); track $index; let i = $index) {
64
154
  @if (item.separator) { <li class="cb-tieredmenu__separator" role="separator"></li> }
65
155
  @else {
66
- <li class="cb-tieredmenu__entry" [class.cb-tieredmenu__entry--open]="openIndex() === i">
156
+ <li class="cb-tieredmenu__entry" role="none" [class.cb-tieredmenu__entry--open]="openIndex() === i">
67
157
  @if (item.items?.length) {
68
- <button class="cb-tieredmenu__item" type="button" role="menuitem" aria-haspopup="menu" [attr.aria-expanded]="openIndex() === i" [disabled]="item.disabled" (mouseenter)="openIndex.set(i)" (click)="openIndex.set(openIndex() === i ? null : i)">
158
+ <button class="cb-tieredmenu__item" type="button" role="menuitem" aria-haspopup="menu" [attr.aria-expanded]="openIndex() === i" data-level="1" [attr.data-index]="i" [disabled]="item.disabled" (mouseenter)="openIndex.set(i)" (click)="openIndex.set(openIndex() === i ? null : i)">
69
159
  @if (item.icon) { <cb-icon [name]="item.icon" [size]="16" aria-hidden="true" /> }<span>{{ item.label }}</span><cb-icon name="chevron-right" [size]="15" aria-hidden="true" />
70
160
  </button>
71
161
  @if (openIndex() === i) {
@@ -73,7 +163,7 @@ class CbTieredMenu {
73
163
  @for (child of item.items; track $index; let j = $index) {
74
164
  <li role="none">
75
165
  @if (child.items?.length) {
76
- <button class="cb-tieredmenu__item" type="button" role="menuitem" aria-haspopup="menu" [attr.aria-expanded]="openChildIndex() === j" [disabled]="child.disabled" (mouseenter)="openChildIndex.set(j)" (click)="openChildIndex.set(openChildIndex() === j ? null : j)">
166
+ <button class="cb-tieredmenu__item" type="button" role="menuitem" aria-haspopup="menu" [attr.aria-expanded]="openChildIndex() === j" data-level="2" [attr.data-index]="j" [disabled]="child.disabled" (mouseenter)="openChildIndex.set(j)" (click)="openChildIndex.set(openChildIndex() === j ? null : j)">
77
167
  @if (child.icon) { <cb-icon [name]="child.icon" [size]="16" aria-hidden="true" /> }<span>{{ child.label }}</span><cb-icon name="chevron-right" [size]="15" aria-hidden="true" />
78
168
  </button>
79
169
  @if (openChildIndex() === j) {
@@ -105,15 +195,15 @@ class CbTieredMenu {
105
195
  i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.0.5", ngImport: i0, type: CbTieredMenu, decorators: [{
106
196
  type: Component,
107
197
  args: [{ selector: 'cb-tieredmenu', changeDetection: ChangeDetectionStrategy.OnPush, encapsulation: ViewEncapsulation.Emulated, imports: [CbIcon], template: `
108
- <button class="cb-tieredmenu__trigger" type="button" [attr.aria-expanded]="isOpen()" aria-haspopup="menu" (click)="toggle($event)">{{ (triggerLabel() ?? t().menu) }}</button>
198
+ <button #trigger class="cb-tieredmenu__trigger" type="button" [attr.aria-expanded]="isOpen()" aria-haspopup="menu" (click)="toggle($event)" (keydown)="onTriggerKeydown($event)">{{ (triggerLabel() ?? t().menu) }}</button>
109
199
  <ng-template #content>
110
- <ul class="cb-tieredmenu__list" role="menu" [attr.aria-label]="(ariaLabel() ?? t().menu)">
111
- @for (item of items(); track $index; let i = $index) {
200
+ <ul class="cb-tieredmenu__list" role="menu" [attr.aria-label]="(ariaLabel() ?? t().menu)" (keydown)="onMenuKeydown($event)">
201
+ @for (item of visibleItems(); track $index; let i = $index) {
112
202
  @if (item.separator) { <li class="cb-tieredmenu__separator" role="separator"></li> }
113
203
  @else {
114
- <li class="cb-tieredmenu__entry" [class.cb-tieredmenu__entry--open]="openIndex() === i">
204
+ <li class="cb-tieredmenu__entry" role="none" [class.cb-tieredmenu__entry--open]="openIndex() === i">
115
205
  @if (item.items?.length) {
116
- <button class="cb-tieredmenu__item" type="button" role="menuitem" aria-haspopup="menu" [attr.aria-expanded]="openIndex() === i" [disabled]="item.disabled" (mouseenter)="openIndex.set(i)" (click)="openIndex.set(openIndex() === i ? null : i)">
206
+ <button class="cb-tieredmenu__item" type="button" role="menuitem" aria-haspopup="menu" [attr.aria-expanded]="openIndex() === i" data-level="1" [attr.data-index]="i" [disabled]="item.disabled" (mouseenter)="openIndex.set(i)" (click)="openIndex.set(openIndex() === i ? null : i)">
117
207
  @if (item.icon) { <cb-icon [name]="item.icon" [size]="16" aria-hidden="true" /> }<span>{{ item.label }}</span><cb-icon name="chevron-right" [size]="15" aria-hidden="true" />
118
208
  </button>
119
209
  @if (openIndex() === i) {
@@ -121,7 +211,7 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.0.5", ngImpor
121
211
  @for (child of item.items; track $index; let j = $index) {
122
212
  <li role="none">
123
213
  @if (child.items?.length) {
124
- <button class="cb-tieredmenu__item" type="button" role="menuitem" aria-haspopup="menu" [attr.aria-expanded]="openChildIndex() === j" [disabled]="child.disabled" (mouseenter)="openChildIndex.set(j)" (click)="openChildIndex.set(openChildIndex() === j ? null : j)">
214
+ <button class="cb-tieredmenu__item" type="button" role="menuitem" aria-haspopup="menu" [attr.aria-expanded]="openChildIndex() === j" data-level="2" [attr.data-index]="j" [disabled]="child.disabled" (mouseenter)="openChildIndex.set(j)" (click)="openChildIndex.set(openChildIndex() === j ? null : j)">
125
215
  @if (child.icon) { <cb-icon [name]="child.icon" [size]="16" aria-hidden="true" /> }<span>{{ child.label }}</span><cb-icon name="chevron-right" [size]="15" aria-hidden="true" />
126
216
  </button>
127
217
  @if (openChildIndex() === j) {
@@ -149,7 +239,7 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.0.5", ngImpor
149
239
  </ul>
150
240
  </ng-template>
151
241
  `, styles: [":host{display:inline-block;color:var(--cb-color-text);font-family:var(--cb-font-sans)}.cb-tieredmenu__trigger{min-height:2.5rem;padding:.5rem .875rem;border:1px solid var(--cb-color-border);border-radius:var(--cb-radius-md);background:var(--cb-color-surface-raised);color:inherit;font:inherit;cursor:pointer}.cb-tieredmenu__trigger:hover,.cb-tieredmenu__trigger:focus-visible{outline:none;border-color:var(--cb-color-primary)}.cb-tieredmenu__list,.cb-tieredmenu__submenu{min-width:13rem;margin:0;padding:.375rem;list-style:none;background:var(--cb-color-surface-raised);border:1px solid var(--cb-color-border);border-radius:var(--cb-radius-md);box-shadow:var(--cb-shadow-lg)}.cb-tieredmenu__entry{position:relative}.cb-tieredmenu__item{display:flex;align-items:center;gap:.625rem;width:100%;min-height:2.25rem;padding:.5rem .625rem;border:0;border-radius:var(--cb-radius-sm);background:transparent;color:inherit;font:inherit;text-align:left;cursor:pointer}.cb-tieredmenu__item span{flex:1}.cb-tieredmenu__item:hover:not(:disabled),.cb-tieredmenu__item:focus-visible,.cb-tieredmenu__entry--open>.cb-tieredmenu__item{outline:none;background:var(--cb-color-surface)}.cb-tieredmenu__item:disabled{opacity:.5;cursor:default}.cb-tieredmenu__submenu{position:absolute;z-index:2;top:-.375rem;left:calc(100% + .25rem)}.cb-tieredmenu__submenu--third{z-index:3}.cb-tieredmenu__separator{height:1px;margin:.375rem .25rem;background:var(--cb-color-border)}\n"] }]
152
- }], ctorParameters: () => [], propDecorators: { items: [{ type: i0.Input, args: [{ isSignal: true, alias: "items", required: false }] }], ariaLabel: [{ type: i0.Input, args: [{ isSignal: true, alias: "ariaLabel", required: false }] }], triggerLabel: [{ type: i0.Input, args: [{ isSignal: true, alias: "triggerLabel", required: false }] }], itemSelect: [{ type: i0.Output, args: ["itemSelect"] }], content: [{ type: i0.ViewChild, args: ['content', { isSignal: true }] }] } });
242
+ }], ctorParameters: () => [], propDecorators: { items: [{ type: i0.Input, args: [{ isSignal: true, alias: "items", required: false }] }], ariaLabel: [{ type: i0.Input, args: [{ isSignal: true, alias: "ariaLabel", required: false }] }], triggerLabel: [{ type: i0.Input, args: [{ isSignal: true, alias: "triggerLabel", required: false }] }], itemSelect: [{ type: i0.Output, args: ["itemSelect"] }], content: [{ type: i0.ViewChild, args: ['content', { isSignal: true }] }], trigger: [{ type: i0.ViewChild, args: ['trigger', { isSignal: true }] }] } });
153
243
 
154
244
  /**
155
245
  * Generated bundle index. Do not edit.