@egose/shadcn-theme-ng 0.0.28 → 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 (237) hide show
  1. package/README.md +130 -13
  2. package/accordion/README.md +376 -34
  3. package/accordion/fesm2022/accordion.mjs +27 -39
  4. package/alert/README.md +343 -34
  5. package/alert/fesm2022/alert.mjs +47 -47
  6. package/alert-dialog/README.md +471 -5
  7. package/alert-dialog/fesm2022/alert-dialog.mjs +47 -47
  8. package/aspect-ratio/README.md +272 -5
  9. package/aspect-ratio/fesm2022/aspect-ratio.mjs +9 -9
  10. package/autocomplete/README.md +473 -34
  11. package/autocomplete/fesm2022/autocomplete.mjs +53 -71
  12. package/avatar/README.md +357 -5
  13. package/avatar/fesm2022/avatar.mjs +32 -32
  14. package/badge/README.md +289 -34
  15. package/badge/fesm2022/badge.mjs +57 -57
  16. package/basic-alert/README.md +324 -34
  17. package/basic-alert/fesm2022/basic-alert.mjs +6 -18
  18. package/breadcrumb/README.md +406 -5
  19. package/breadcrumb/fesm2022/breadcrumb.mjs +33 -39
  20. package/button/README.md +453 -34
  21. package/button/fesm2022/button.mjs +147 -219
  22. package/button/types/button.d.ts +7 -10
  23. package/button-group/README.md +318 -5
  24. package/button-group/fesm2022/button-group.mjs +20 -20
  25. package/calendar/README.md +328 -34
  26. package/calendar/fesm2022/calendar.mjs +29 -743
  27. package/card/README.md +331 -5
  28. package/card/fesm2022/card.mjs +33 -33
  29. package/carousel/README.md +333 -5
  30. package/carousel/fesm2022/carousel.mjs +39 -78
  31. package/checkbox/README.md +291 -34
  32. package/checkbox/fesm2022/checkbox.mjs +20 -58
  33. package/checkbox/types/checkbox.d.ts +5 -4
  34. package/collapsible/README.md +332 -5
  35. package/collapsible/fesm2022/collapsible.mjs +15 -15
  36. package/combobox/README.md +507 -5
  37. package/combobox/fesm2022/combobox.mjs +91 -224
  38. package/command/README.md +435 -5
  39. package/command/fesm2022/command.mjs +49 -109
  40. package/confirmation-dialog/README.md +272 -34
  41. package/confirmation-dialog/fesm2022/confirmation-dialog.mjs +15 -40
  42. package/confirmation-dialog/types/confirmation-dialog.d.ts +8 -4
  43. package/context-menu/README.md +366 -5
  44. package/context-menu/fesm2022/context-menu.mjs +9 -9
  45. package/date-picker/README.md +436 -34
  46. package/date-picker/fesm2022/date-picker.mjs +64 -267
  47. package/date-picker/types/date-picker.d.ts +7 -3
  48. package/dialog/README.md +419 -34
  49. package/dialog/fesm2022/dialog.mjs +45 -71
  50. package/drawer/README.md +395 -5
  51. package/drawer/fesm2022/drawer.mjs +44 -54
  52. package/dropdown-menu/README.md +417 -5
  53. package/dropdown-menu/fesm2022/dropdown-menu.mjs +82 -70
  54. package/dropdown-menu/types/dropdown-menu.d.ts +4 -0
  55. package/empty/README.md +329 -5
  56. package/empty/fesm2022/empty.mjs +30 -30
  57. package/field/README.md +385 -5
  58. package/field/fesm2022/field.mjs +56 -72
  59. package/form-checkbox/README.md +283 -34
  60. package/form-checkbox/fesm2022/form-checkbox.mjs +25 -85
  61. package/form-checkbox/types/form-checkbox.d.ts +7 -1
  62. package/form-date-picker/README.md +293 -34
  63. package/form-date-picker/fesm2022/form-date-picker.mjs +31 -84
  64. package/form-date-picker/types/form-date-picker.d.ts +7 -1
  65. package/form-field/README.md +327 -34
  66. package/form-field/fesm2022/form-field.mjs +33 -19
  67. package/form-field/types/form-field.d.ts +28 -20
  68. package/form-field-simple/README.md +311 -34
  69. package/form-field-simple/fesm2022/form-field-simple.mjs +4 -4
  70. package/form-searchable-multiselect/README.md +332 -34
  71. package/form-searchable-multiselect/fesm2022/form-searchable-multiselect.mjs +31 -91
  72. package/form-searchable-multiselect/types/form-searchable-multiselect.d.ts +7 -1
  73. package/form-select/README.md +321 -34
  74. package/form-select/fesm2022/form-select.mjs +32 -149
  75. package/form-select/types/form-select.d.ts +7 -1
  76. package/form-text-input/README.md +342 -34
  77. package/form-text-input/fesm2022/form-text-input.mjs +35 -149
  78. package/form-text-input/types/form-text-input.d.ts +9 -12
  79. package/form-textarea/README.md +318 -34
  80. package/form-textarea/fesm2022/form-textarea.mjs +34 -109
  81. package/form-textarea/types/form-textarea.d.ts +8 -1
  82. package/hover-card/README.md +256 -5
  83. package/hover-card/fesm2022/hover-card.mjs +19 -19
  84. package/icon/README.md +210 -34
  85. package/icon/fesm2022/icon.mjs +8 -8
  86. package/input/README.md +240 -34
  87. package/input/fesm2022/input.mjs +17 -12
  88. package/input/types/input.d.ts +2 -1
  89. package/input-group/README.md +335 -5
  90. package/input-group/fesm2022/input-group.mjs +34 -34
  91. package/input-otp/README.md +375 -5
  92. package/input-otp/fesm2022/input-otp.mjs +26 -26
  93. package/item/README.md +385 -5
  94. package/item/fesm2022/item.mjs +53 -53
  95. package/kbd/README.md +291 -5
  96. package/kbd/fesm2022/kbd.mjs +12 -12
  97. package/label/README.md +243 -34
  98. package/label/fesm2022/label.mjs +10 -10
  99. package/label/types/label.d.ts +1 -1
  100. package/layout-simple/README.md +174 -44
  101. package/layout-simple/fesm2022/layout-simple.mjs +508 -603
  102. package/layout-simple/types/layout-simple.d.ts +179 -128
  103. package/menu/README.md +418 -0
  104. package/menu/fesm2022/menu.mjs +455 -0
  105. package/menu/package.json +24 -0
  106. package/menu/types/menu.d.ts +137 -0
  107. package/menubar/README.md +343 -5
  108. package/menubar/fesm2022/menubar.mjs +13 -13
  109. package/native-select/README.md +323 -5
  110. package/native-select/fesm2022/native-select.mjs +19 -19
  111. package/navigation-menu/README.md +369 -5
  112. package/navigation-menu/fesm2022/navigation-menu.mjs +35 -47
  113. package/package.json +183 -154
  114. package/pagination/README.md +388 -5
  115. package/pagination/fesm2022/pagination.mjs +45 -331
  116. package/popover/README.md +302 -34
  117. package/popover/fesm2022/popover.mjs +30 -30
  118. package/progress/README.md +311 -5
  119. package/progress/fesm2022/progress.mjs +13 -13
  120. package/radio-group/README.md +335 -34
  121. package/radio-group/fesm2022/radio-group.mjs +26 -19
  122. package/radio-group/types/radio-group.d.ts +1 -1
  123. package/resizable/README.md +269 -5
  124. package/resizable/fesm2022/resizable.mjs +18 -26
  125. package/scroll-area/README.md +233 -5
  126. package/scroll-area/fesm2022/scroll-area.mjs +9 -9
  127. package/searchable-multiselect/README.md +294 -34
  128. package/searchable-multiselect/fesm2022/searchable-multiselect.mjs +28 -117
  129. package/searchable-multiselect/types/searchable-multiselect.d.ts +8 -2
  130. package/select/README.md +408 -34
  131. package/select/fesm2022/select.mjs +71 -111
  132. package/select/types/select.d.ts +3 -1
  133. package/separator/README.md +193 -34
  134. package/separator/fesm2022/separator.mjs +9 -9
  135. package/separator/types/separator.d.ts +1 -1
  136. package/sheet/README.md +282 -34
  137. package/sheet/fesm2022/sheet.mjs +41 -53
  138. package/sidebar/README.md +457 -5
  139. package/sidebar/fesm2022/sidebar.mjs +125 -227
  140. package/skeleton/README.md +217 -5
  141. package/skeleton/fesm2022/skeleton.mjs +9 -9
  142. package/slider/README.md +273 -5
  143. package/slider/fesm2022/slider.mjs +10 -80
  144. package/sonner/README.md +317 -34
  145. package/sonner/fesm2022/sonner.mjs +13 -13
  146. package/spinner/README.md +255 -34
  147. package/spinner/fesm2022/spinner.mjs +11 -11
  148. package/switch/README.md +281 -34
  149. package/switch/fesm2022/switch.mjs +13 -15
  150. package/table/README.md +423 -5
  151. package/table/fesm2022/table.mjs +41 -41
  152. package/tabs/README.md +382 -34
  153. package/tabs/fesm2022/tabs.mjs +35 -111
  154. package/textarea/README.md +282 -5
  155. package/textarea/fesm2022/textarea.mjs +9 -9
  156. package/toggle/README.md +270 -5
  157. package/toggle/fesm2022/toggle.mjs +13 -13
  158. package/toggle-group/README.md +340 -5
  159. package/toggle-group/fesm2022/toggle-group.mjs +13 -13
  160. package/toggle-group/types/toggle-group.d.ts +13 -7
  161. package/tooltip/README.md +240 -34
  162. package/tooltip/fesm2022/tooltip.mjs +14 -14
  163. package/typography/README.md +271 -5
  164. package/typography/fesm2022/typography.mjs +53 -53
  165. package/typography/types/typography.d.ts +19 -19
  166. package/utils/README.md +274 -34
  167. package/utils/fesm2022/utils.mjs +68 -44
  168. package/accordion/fesm2022/accordion.mjs.map +0 -1
  169. package/alert/fesm2022/alert.mjs.map +0 -1
  170. package/alert-dialog/fesm2022/alert-dialog.mjs.map +0 -1
  171. package/aspect-ratio/fesm2022/aspect-ratio.mjs.map +0 -1
  172. package/autocomplete/fesm2022/autocomplete.mjs.map +0 -1
  173. package/avatar/fesm2022/avatar.mjs.map +0 -1
  174. package/badge/fesm2022/badge.mjs.map +0 -1
  175. package/basic-alert/fesm2022/basic-alert.mjs.map +0 -1
  176. package/breadcrumb/fesm2022/breadcrumb.mjs.map +0 -1
  177. package/button/fesm2022/button.mjs.map +0 -1
  178. package/button-group/fesm2022/button-group.mjs.map +0 -1
  179. package/calendar/fesm2022/calendar.mjs.map +0 -1
  180. package/card/fesm2022/card.mjs.map +0 -1
  181. package/carousel/fesm2022/carousel.mjs.map +0 -1
  182. package/checkbox/fesm2022/checkbox.mjs.map +0 -1
  183. package/collapsible/fesm2022/collapsible.mjs.map +0 -1
  184. package/combobox/fesm2022/combobox.mjs.map +0 -1
  185. package/command/fesm2022/command.mjs.map +0 -1
  186. package/confirmation-dialog/fesm2022/confirmation-dialog.mjs.map +0 -1
  187. package/context-menu/fesm2022/context-menu.mjs.map +0 -1
  188. package/date-picker/fesm2022/date-picker.mjs.map +0 -1
  189. package/dialog/fesm2022/dialog.mjs.map +0 -1
  190. package/drawer/fesm2022/drawer.mjs.map +0 -1
  191. package/dropdown-menu/fesm2022/dropdown-menu.mjs.map +0 -1
  192. package/empty/fesm2022/empty.mjs.map +0 -1
  193. package/field/fesm2022/field.mjs.map +0 -1
  194. package/form-checkbox/fesm2022/form-checkbox.mjs.map +0 -1
  195. package/form-date-picker/fesm2022/form-date-picker.mjs.map +0 -1
  196. package/form-field/fesm2022/form-field.mjs.map +0 -1
  197. package/form-field-simple/fesm2022/form-field-simple.mjs.map +0 -1
  198. package/form-searchable-multiselect/fesm2022/form-searchable-multiselect.mjs.map +0 -1
  199. package/form-select/fesm2022/form-select.mjs.map +0 -1
  200. package/form-text-input/fesm2022/form-text-input.mjs.map +0 -1
  201. package/form-textarea/fesm2022/form-textarea.mjs.map +0 -1
  202. package/hover-card/fesm2022/hover-card.mjs.map +0 -1
  203. package/icon/fesm2022/icon.mjs.map +0 -1
  204. package/input/fesm2022/input.mjs.map +0 -1
  205. package/input-group/fesm2022/input-group.mjs.map +0 -1
  206. package/input-otp/fesm2022/input-otp.mjs.map +0 -1
  207. package/item/fesm2022/item.mjs.map +0 -1
  208. package/kbd/fesm2022/kbd.mjs.map +0 -1
  209. package/label/fesm2022/label.mjs.map +0 -1
  210. package/layout-simple/fesm2022/layout-simple.mjs.map +0 -1
  211. package/menubar/fesm2022/menubar.mjs.map +0 -1
  212. package/native-select/fesm2022/native-select.mjs.map +0 -1
  213. package/navigation-menu/fesm2022/navigation-menu.mjs.map +0 -1
  214. package/pagination/fesm2022/pagination.mjs.map +0 -1
  215. package/popover/fesm2022/popover.mjs.map +0 -1
  216. package/progress/fesm2022/progress.mjs.map +0 -1
  217. package/radio-group/fesm2022/radio-group.mjs.map +0 -1
  218. package/resizable/fesm2022/resizable.mjs.map +0 -1
  219. package/scroll-area/fesm2022/scroll-area.mjs.map +0 -1
  220. package/searchable-multiselect/fesm2022/searchable-multiselect.mjs.map +0 -1
  221. package/select/fesm2022/select.mjs.map +0 -1
  222. package/separator/fesm2022/separator.mjs.map +0 -1
  223. package/sheet/fesm2022/sheet.mjs.map +0 -1
  224. package/sidebar/fesm2022/sidebar.mjs.map +0 -1
  225. package/skeleton/fesm2022/skeleton.mjs.map +0 -1
  226. package/slider/fesm2022/slider.mjs.map +0 -1
  227. package/sonner/fesm2022/sonner.mjs.map +0 -1
  228. package/spinner/fesm2022/spinner.mjs.map +0 -1
  229. package/switch/fesm2022/switch.mjs.map +0 -1
  230. package/table/fesm2022/table.mjs.map +0 -1
  231. package/tabs/fesm2022/tabs.mjs.map +0 -1
  232. package/textarea/fesm2022/textarea.mjs.map +0 -1
  233. package/toggle/fesm2022/toggle.mjs.map +0 -1
  234. package/toggle-group/fesm2022/toggle-group.mjs.map +0 -1
  235. package/tooltip/fesm2022/tooltip.mjs.map +0 -1
  236. package/typography/fesm2022/typography.mjs.map +0 -1
  237. package/utils/fesm2022/utils.mjs.map +0 -1
@@ -1,131 +1,56 @@
1
1
  import * as i0 from '@angular/core';
2
- import { input, Component, signal, computed, output, ChangeDetectionStrategy, viewChild, effect } from '@angular/core';
3
- import { RouterLink, RouterModule } from '@angular/router';
4
- import * as i1$2 from '@angular/cdk/layout';
5
- import { Breakpoints } from '@angular/cdk/layout';
2
+ import { input, ChangeDetectionStrategy, Component, output, signal, viewChild, viewChildren, effect, computed, inject, ElementRef, Injector, afterNextRender, DestroyRef } from '@angular/core';
3
+ import * as i1 from '@angular/common';
4
+ import { CommonModule, NgTemplateOutlet } from '@angular/common';
5
+ import { takeUntilDestroyed } from '@angular/core/rxjs-interop';
6
+ import { RouterLink, RouterLinkActive, Router, NavigationEnd } from '@angular/router';
7
+ import { BreakpointObserver } from '@angular/cdk/layout';
8
+ import { _IdGenerator } from '@angular/cdk/a11y';
6
9
  import { NgIcon, provideIcons } from '@ng-icons/core';
7
- import { lucideUser, lucideSearch, lucideMenu } from '@ng-icons/lucide';
10
+ import { lucideUser, lucideSearch, lucideChevronDown, lucideX, lucideMenu, lucidePanelLeft } from '@ng-icons/lucide';
8
11
  import { hlm } from '@egose/shadcn-theme-ng/utils';
9
- import * as i4 from '@egose/shadcn-theme-ng/button';
10
- import { HlmButton, HlmButtonImports } from '@egose/shadcn-theme-ng/button';
11
- import * as i1 from '@angular/common';
12
- import { CommonModule } from '@angular/common';
13
12
  import { HlmDropdownMenu, HlmDropdownMenuTrigger, HlmDropdownMenuItem, HlmDropdownMenuLabel, HlmDropdownMenuSeparator, HlmDropdownMenuGroup } from '@egose/shadcn-theme-ng/dropdown-menu';
14
- import * as i1$1 from '@angular/forms';
15
- import { FormsModule } from '@angular/forms';
16
- import { HlmPopover, HlmPopoverTrigger, HlmPopoverContent } from '@egose/shadcn-theme-ng/popover';
13
+ import * as i3 from '@egose/shadcn-theme-ng/button';
14
+ import { HlmButton, HlmButtonImports } from '@egose/shadcn-theme-ng/button';
15
+ import { HlmPopover, HlmPopoverTrigger, HlmPopoverContent, HlmPopoverPortal } from '@egose/shadcn-theme-ng/popover';
17
16
  import { HlmInput } from '@egose/shadcn-theme-ng/input';
18
- import * as i2 from '@spartan-ng/brain/sheet';
17
+ import * as i1$1 from '@spartan-ng/brain/sheet';
19
18
  import { BrnSheet, BrnSheetImports } from '@spartan-ng/brain/sheet';
20
- import { HlmLabelImports } from '@egose/shadcn-theme-ng/label';
21
- import * as i3 from '@egose/shadcn-theme-ng/sheet';
19
+ import * as i2 from '@egose/shadcn-theme-ng/sheet';
22
20
  import { HlmSheetImports } from '@egose/shadcn-theme-ng/sheet';
23
21
 
22
+ /** Internal matching contract shared by links and dropdown destinations. */
23
+ function navigationMatchOptions(item) {
24
+ return {
25
+ paths: item.activeMatch === 'prefix' ? 'subset' : 'exact',
26
+ queryParams: 'ignored',
27
+ fragment: 'ignored',
28
+ matrixParams: 'ignored',
29
+ };
30
+ }
31
+
24
32
  class EgLayoutSimpleUserMenu {
25
33
  hlm = hlm;
26
- lucideUser = lucideUser;
27
- menus = input([], /* @ts-ignore */
28
- ...(ngDevMode ? [{ debugName: "menus" }] : /* istanbul ignore next */ []));
29
- menuTrigger = input(/* @ts-ignore */
30
- ...(ngDevMode ? [undefined, { debugName: "menuTrigger" }] : /* istanbul ignore next */ []));
31
- static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "22.0.7", ngImport: i0, type: EgLayoutSimpleUserMenu, deps: [], target: i0.ɵɵFactoryTarget.Component });
32
- static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "22.0.7", type: EgLayoutSimpleUserMenu, isStandalone: true, selector: "eg-layout-simple-user-menu", inputs: { menus: { classPropertyName: "menus", publicName: "menus", isSignal: true, isRequired: false, transformFunction: null }, menuTrigger: { classPropertyName: "menuTrigger", publicName: "menuTrigger", isSignal: true, isRequired: false, transformFunction: null } }, providers: [
34
+ navigationMatchOptions = navigationMatchOptions;
35
+ userIcon = lucideUser;
36
+ sections = input([], /* @ts-ignore */
37
+ ...(ngDevMode ? [{ debugName: "sections" }] : /* istanbul ignore next */ []));
38
+ triggerTemplate = input(/* @ts-ignore */
39
+ ...(ngDevMode ? [undefined, { debugName: "triggerTemplate" }] : /* istanbul ignore next */ []));
40
+ triggerLabel = input('Open account menu', /* @ts-ignore */
41
+ ...(ngDevMode ? [{ debugName: "triggerLabel" }] : /* istanbul ignore next */ []));
42
+ static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "22.1.3", ngImport: i0, type: EgLayoutSimpleUserMenu, deps: [], target: i0.ɵɵFactoryTarget.Component });
43
+ static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "22.1.3", type: EgLayoutSimpleUserMenu, isStandalone: true, selector: "eg-layout-simple-user-menu", inputs: { sections: { classPropertyName: "sections", publicName: "sections", isSignal: true, isRequired: false, transformFunction: null }, triggerTemplate: { classPropertyName: "triggerTemplate", publicName: "triggerTemplate", isSignal: true, isRequired: false, transformFunction: null }, triggerLabel: { classPropertyName: "triggerLabel", publicName: "triggerLabel", isSignal: true, isRequired: false, transformFunction: null } }, providers: [
33
44
  provideIcons({
34
45
  lucideUser,
35
46
  }),
36
- ], ngImport: i0, template: `
37
- <ng-template #iconTemplate>
38
- <ng-icon [svg]="lucideUser" size="1.5rem" class="[&_svg]:w-[inherit]! [&_svg]:h-[inherit]!" />
39
- </ng-template>
40
-
41
- @let _menuTrigger = menuTrigger();
42
-
43
- <div class="flex w-full items-center justify-center">
44
- @if (_menuTrigger) {
45
- <button
46
- type="button"
47
- [hlmDropdownMenuTrigger]="menu"
48
- class="cursor-pointer bg-transparent border-0 p-0"
49
- >
50
- <ng-container *ngTemplateOutlet="_menuTrigger" />
51
- </button>
52
- } @else {
53
- <button
54
- hlmButton
55
- variant="primary"
56
- size="icon"
57
- [hlmDropdownMenuTrigger]="menu"
58
- [icon]="iconTemplate"
59
- class="rounded-full border border-gray-400"
60
- ></button>
61
- }
62
-
63
- <ng-template #menu>
64
- <div hlmDropdownMenu class="w-56">
65
- @for (section of menus(); track section) {
66
- @if (section.label) {
67
- <div hlmDropdownMenuLabel>{{ section.label }}</div>
68
- }
69
- @if (section.items?.length) {
70
- <div hlmDropdownMenuGroup>
71
- @for (item of section.items; track item) {
72
- @if (item.link) {
73
- <a
74
- hlmDropdownMenuItem
75
- [routerLink]="item.link"
76
- [class]="hlm('cursor-pointer no-underline', item.class)"
77
- >
78
- @if (item.icon) {
79
- <ng-icon
80
- [svg]="item.icon"
81
- size="1rem"
82
- [class]="
83
- hlm(
84
- '[_svg]:text-[inherit]! [_svg]:bg-[inherit]! cursor-pointer mr-2',
85
- item.class
86
- )
87
- "
88
- />
89
- }
90
- <span>{{ item.label }}</span>
91
- </a>
92
- } @else {
93
- <button
94
- hlmDropdownMenuItem
95
- (click)="item.action?.()"
96
- [class]="hlm('cursor-pointer no-underline', item.class)"
97
- >
98
- @if (item.icon) {
99
- <ng-icon
100
- [svg]="item.icon"
101
- size="1rem"
102
- [class]="
103
- hlm(
104
- '[_svg]:text-[inherit]! [_svg]:bg-[inherit]! cursor-pointer mr-2',
105
- item.class
106
- )
107
- "
108
- />
109
- }
110
- <span>{{ item.label }}</span>
111
- </button>
112
- }
113
- }
114
- </div>
115
- }
116
- @if (section.separator) {
117
- <div hlmDropdownMenuSeparator></div>
118
- }
119
- }
120
- </div>
121
- </ng-template>
122
- </div>
123
- `, isInline: true, dependencies: [{ kind: "ngmodule", type: CommonModule }, { kind: "directive", type: i1.NgTemplateOutlet, selector: "[ngTemplateOutlet]", inputs: ["ngTemplateOutletContext", "ngTemplateOutlet", "ngTemplateOutletInjector"] }, { kind: "directive", type: HlmDropdownMenu, selector: "[hlmDropdownMenu],hlm-dropdown-menu", inputs: ["sideOffset"] }, { kind: "directive", type: HlmDropdownMenuTrigger, selector: "[hlmDropdownMenuTrigger]", inputs: ["align", "side"] }, { kind: "directive", type: HlmDropdownMenuItem, selector: "[hlmDropdownMenuItem],hlm-dropdown-menu-item", inputs: ["disabled", "variant", "inset"] }, { kind: "directive", type: HlmDropdownMenuLabel, selector: "[hlmDropdownMenuLabel],hlm-dropdown-menu-label", inputs: ["inset"] }, { kind: "directive", type: HlmDropdownMenuSeparator, selector: "[hlmDropdownMenuSeparator],hlm-dropdown-menu-separator" }, { kind: "directive", type: HlmDropdownMenuGroup, selector: "[hlmDropdownMenuGroup],hlm-dropdown-menu-group" }, { kind: "component", type: HlmButton, selector: "button[hlmButton], a[hlmButton]", inputs: ["variant", "size", "appearance", "loading", "icon", "iconPosition", "class", "spinnerUserClass", "disabled", "type"] }, { kind: "component", type: NgIcon, selector: "ng-icon", inputs: ["name", "svg", "size", "strokeWidth", "color"] }, { kind: "directive", type: RouterLink, selector: "[routerLink]", inputs: ["target", "queryParams", "fragment", "queryParamsHandling", "state", "info", "relativeTo", "preserveFragment", "skipLocationChange", "replaceUrl", "browserUrl", "routerLink"] }] });
47
+ ], ngImport: i0, template: "\n <ng-template #iconTemplate>\n <ng-icon [svg]=\"userIcon\" size=\"1.25rem\" aria-hidden=\"true\" />\n </ng-template>\n\n @let customTrigger = triggerTemplate();\n\n <div class=\"flex w-full items-center justify-center\">\n @if (customTrigger) {\n <button\n type=\"button\"\n [hlmDropdownMenuTrigger]=\"menu\"\n [attr.aria-label]=\"triggerLabel()\"\n class=\"min-h-11 min-w-11 rounded-full cursor-pointer bg-transparent border-0 p-0 focus-visible:outline-2 focus-visible:outline-offset-2 focus-visible:outline-ring\"\n >\n <ng-container *ngTemplateOutlet=\"customTrigger\" />\n </button>\n } @else {\n <button\n hlmButton\n type=\"button\"\n variant=\"secondary\"\n appearance=\"outline\"\n size=\"icon\"\n [hlmDropdownMenuTrigger]=\"menu\"\n [icon]=\"iconTemplate\"\n [attr.aria-label]=\"triggerLabel()\"\n class=\"size-11 rounded-full border border-border text-foreground\"\n ></button>\n }\n\n <ng-template #menu>\n <div hlmDropdownMenu class=\"w-56\">\n @for (section of sections(); track $index) {\n @if (section.label) {\n <div hlmDropdownMenuLabel>{{ section.label }}</div>\n }\n @if (section.items?.length) {\n <div hlmDropdownMenuGroup>\n @for (item of section.items; track item) {\n @if (item.link && !item.disabled) {\n <a\n hlmDropdownMenuItem\n [routerLink]=\"item.link\"\n routerLinkActive=\"tw:bg-foreground/10 tw:font-semibold\"\n [routerLinkActiveOptions]=\"navigationMatchOptions(item)\"\n ariaCurrentWhenActive=\"page\"\n [class]=\"hlm('tw:min-h-11 tw:cursor-pointer tw:no-underline', item.class)\"\n >\n @if (item.icon) {\n <ng-icon\n [svg]=\"item.icon\"\n aria-hidden=\"true\"\n size=\"1rem\"\n [class]=\"\n hlm(\n 'tw:[_svg]:text-[inherit]! tw:[_svg]:bg-[inherit]! tw:cursor-pointer tw:mr-2',\n item.class\n )\n \"\n />\n }\n <span>{{ item.label }}</span>\n </a>\n } @else {\n <button\n hlmDropdownMenuItem\n type=\"button\"\n [disabled]=\"item.disabled || !item.action\"\n (click)=\"item.action?.()\"\n [class]=\"hlm('tw:min-h-11 tw:cursor-pointer tw:no-underline', item.class)\"\n >\n @if (item.icon) {\n <ng-icon\n [svg]=\"item.icon\"\n aria-hidden=\"true\"\n size=\"1rem\"\n [class]=\"\n hlm(\n 'tw:[_svg]:text-[inherit]! tw:[_svg]:bg-[inherit]! tw:cursor-pointer tw:mr-2',\n item.class\n )\n \"\n />\n }\n <span>{{ item.label }}</span>\n </button>\n }\n }\n </div>\n }\n @if (section.separator) {\n <div hlmDropdownMenuSeparator></div>\n }\n }\n </div>\n </ng-template>\n </div>\n ", isInline: true, dependencies: [{ kind: "ngmodule", type: CommonModule }, { kind: "directive", type: i1.NgTemplateOutlet, selector: "[ngTemplateOutlet]", inputs: ["ngTemplateOutletContext", "ngTemplateOutlet", "ngTemplateOutletInjector"] }, { kind: "directive", type: HlmDropdownMenu, selector: "[hlmDropdownMenu],hlm-dropdown-menu", inputs: ["sideOffset"] }, { kind: "directive", type: HlmDropdownMenuTrigger, selector: "[hlmDropdownMenuTrigger]", inputs: ["align", "side"] }, { kind: "directive", type: HlmDropdownMenuItem, selector: "[hlmDropdownMenuItem],hlm-dropdown-menu-item", inputs: ["disabled", "variant", "inset"] }, { kind: "directive", type: HlmDropdownMenuLabel, selector: "[hlmDropdownMenuLabel],hlm-dropdown-menu-label", inputs: ["inset"] }, { kind: "directive", type: HlmDropdownMenuSeparator, selector: "[hlmDropdownMenuSeparator],hlm-dropdown-menu-separator" }, { kind: "directive", type: HlmDropdownMenuGroup, selector: "[hlmDropdownMenuGroup],hlm-dropdown-menu-group" }, { kind: "component", type: HlmButton, selector: "button[hlmButton], a[hlmButton]", inputs: ["variant", "size", "appearance", "loading", "icon", "iconPosition", "class", "spinnerUserClass", "disabled", "type"] }, { kind: "component", type: NgIcon, selector: "ng-icon", inputs: ["name", "svg", "size", "strokeWidth", "color"] }, { kind: "directive", type: RouterLink, selector: "[routerLink]", inputs: ["target", "queryParams", "fragment", "queryParamsHandling", "state", "info", "relativeTo", "preserveFragment", "skipLocationChange", "replaceUrl", "browserUrl", "routerLink"] }, { kind: "directive", type: RouterLinkActive, selector: "[routerLinkActive]", inputs: ["routerLinkActiveOptions", "ariaCurrentWhenActive", "routerLinkActive"], outputs: ["isActiveChange"], exportAs: ["routerLinkActive"] }], changeDetection: i0.ChangeDetectionStrategy.OnPush });
124
48
  }
125
- i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.0.7", ngImport: i0, type: EgLayoutSimpleUserMenu, decorators: [{
49
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.1.3", ngImport: i0, type: EgLayoutSimpleUserMenu, decorators: [{
126
50
  type: Component,
127
51
  args: [{
128
52
  selector: 'eg-layout-simple-user-menu',
53
+ changeDetection: ChangeDetectionStrategy.OnPush,
129
54
  imports: [
130
55
  CommonModule,
131
56
  HlmDropdownMenu,
@@ -137,575 +62,555 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.0.7", ngImpor
137
62
  HlmButton,
138
63
  NgIcon,
139
64
  RouterLink,
65
+ RouterLinkActive,
140
66
  ],
141
67
  providers: [
142
68
  provideIcons({
143
69
  lucideUser,
144
70
  }),
145
71
  ],
146
- template: `
147
- <ng-template #iconTemplate>
148
- <ng-icon [svg]="lucideUser" size="1.5rem" class="[&_svg]:w-[inherit]! [&_svg]:h-[inherit]!" />
149
- </ng-template>
150
-
151
- @let _menuTrigger = menuTrigger();
152
-
153
- <div class="flex w-full items-center justify-center">
154
- @if (_menuTrigger) {
155
- <button
156
- type="button"
157
- [hlmDropdownMenuTrigger]="menu"
158
- class="cursor-pointer bg-transparent border-0 p-0"
159
- >
160
- <ng-container *ngTemplateOutlet="_menuTrigger" />
161
- </button>
162
- } @else {
163
- <button
164
- hlmButton
165
- variant="primary"
166
- size="icon"
167
- [hlmDropdownMenuTrigger]="menu"
168
- [icon]="iconTemplate"
169
- class="rounded-full border border-gray-400"
170
- ></button>
171
- }
172
-
173
- <ng-template #menu>
174
- <div hlmDropdownMenu class="w-56">
175
- @for (section of menus(); track section) {
176
- @if (section.label) {
177
- <div hlmDropdownMenuLabel>{{ section.label }}</div>
178
- }
179
- @if (section.items?.length) {
180
- <div hlmDropdownMenuGroup>
181
- @for (item of section.items; track item) {
182
- @if (item.link) {
183
- <a
184
- hlmDropdownMenuItem
185
- [routerLink]="item.link"
186
- [class]="hlm('cursor-pointer no-underline', item.class)"
187
- >
188
- @if (item.icon) {
189
- <ng-icon
190
- [svg]="item.icon"
191
- size="1rem"
192
- [class]="
193
- hlm(
194
- '[_svg]:text-[inherit]! [_svg]:bg-[inherit]! cursor-pointer mr-2',
195
- item.class
196
- )
197
- "
198
- />
199
- }
200
- <span>{{ item.label }}</span>
201
- </a>
202
- } @else {
203
- <button
204
- hlmDropdownMenuItem
205
- (click)="item.action?.()"
206
- [class]="hlm('cursor-pointer no-underline', item.class)"
207
- >
208
- @if (item.icon) {
209
- <ng-icon
210
- [svg]="item.icon"
211
- size="1rem"
212
- [class]="
213
- hlm(
214
- '[_svg]:text-[inherit]! [_svg]:bg-[inherit]! cursor-pointer mr-2',
215
- item.class
216
- )
217
- "
218
- />
219
- }
220
- <span>{{ item.label }}</span>
221
- </button>
222
- }
223
- }
224
- </div>
225
- }
226
- @if (section.separator) {
227
- <div hlmDropdownMenuSeparator></div>
228
- }
229
- }
230
- </div>
231
- </ng-template>
232
- </div>
233
- `,
72
+ template: "\n <ng-template #iconTemplate>\n <ng-icon [svg]=\"userIcon\" size=\"1.25rem\" aria-hidden=\"true\" />\n </ng-template>\n\n @let customTrigger = triggerTemplate();\n\n <div class=\"flex w-full items-center justify-center\">\n @if (customTrigger) {\n <button\n type=\"button\"\n [hlmDropdownMenuTrigger]=\"menu\"\n [attr.aria-label]=\"triggerLabel()\"\n class=\"min-h-11 min-w-11 rounded-full cursor-pointer bg-transparent border-0 p-0 focus-visible:outline-2 focus-visible:outline-offset-2 focus-visible:outline-ring\"\n >\n <ng-container *ngTemplateOutlet=\"customTrigger\" />\n </button>\n } @else {\n <button\n hlmButton\n type=\"button\"\n variant=\"secondary\"\n appearance=\"outline\"\n size=\"icon\"\n [hlmDropdownMenuTrigger]=\"menu\"\n [icon]=\"iconTemplate\"\n [attr.aria-label]=\"triggerLabel()\"\n class=\"size-11 rounded-full border border-border text-foreground\"\n ></button>\n }\n\n <ng-template #menu>\n <div hlmDropdownMenu class=\"w-56\">\n @for (section of sections(); track $index) {\n @if (section.label) {\n <div hlmDropdownMenuLabel>{{ section.label }}</div>\n }\n @if (section.items?.length) {\n <div hlmDropdownMenuGroup>\n @for (item of section.items; track item) {\n @if (item.link && !item.disabled) {\n <a\n hlmDropdownMenuItem\n [routerLink]=\"item.link\"\n routerLinkActive=\"tw:bg-foreground/10 tw:font-semibold\"\n [routerLinkActiveOptions]=\"navigationMatchOptions(item)\"\n ariaCurrentWhenActive=\"page\"\n [class]=\"hlm('tw:min-h-11 tw:cursor-pointer tw:no-underline', item.class)\"\n >\n @if (item.icon) {\n <ng-icon\n [svg]=\"item.icon\"\n aria-hidden=\"true\"\n size=\"1rem\"\n [class]=\"\n hlm(\n 'tw:[_svg]:text-[inherit]! tw:[_svg]:bg-[inherit]! tw:cursor-pointer tw:mr-2',\n item.class\n )\n \"\n />\n }\n <span>{{ item.label }}</span>\n </a>\n } @else {\n <button\n hlmDropdownMenuItem\n type=\"button\"\n [disabled]=\"item.disabled || !item.action\"\n (click)=\"item.action?.()\"\n [class]=\"hlm('tw:min-h-11 tw:cursor-pointer tw:no-underline', item.class)\"\n >\n @if (item.icon) {\n <ng-icon\n [svg]=\"item.icon\"\n aria-hidden=\"true\"\n size=\"1rem\"\n [class]=\"\n hlm(\n 'tw:[_svg]:text-[inherit]! tw:[_svg]:bg-[inherit]! tw:cursor-pointer tw:mr-2',\n item.class\n )\n \"\n />\n }\n <span>{{ item.label }}</span>\n </button>\n }\n }\n </div>\n }\n @if (section.separator) {\n <div hlmDropdownMenuSeparator></div>\n }\n }\n </div>\n </ng-template>\n </div>\n ",
234
73
  }]
235
- }], propDecorators: { menus: [{ type: i0.Input, args: [{ isSignal: true, alias: "menus", required: false }] }], menuTrigger: [{ type: i0.Input, args: [{ isSignal: true, alias: "menuTrigger", required: false }] }] } });
74
+ }], propDecorators: { sections: [{ type: i0.Input, args: [{ isSignal: true, alias: "sections", required: false }] }], triggerTemplate: [{ type: i0.Input, args: [{ isSignal: true, alias: "triggerTemplate", required: false }] }], triggerLabel: [{ type: i0.Input, args: [{ isSignal: true, alias: "triggerLabel", required: false }] }] } });
236
75
 
237
- class EgGenericAutocomplete {
238
- placeholderText = input('Select an option', /* @ts-ignore */
239
- ...(ngDevMode ? [{ debugName: "placeholderText" }] : /* istanbul ignore next */ []));
240
- emptyText = input('No options found', /* @ts-ignore */
76
+ /** Async page search with debouncing, stale-response protection, and keyboard navigation. */
77
+ class EgLayoutSearch {
78
+ placeholder = input('Search pages…', /* @ts-ignore */
79
+ ...(ngDevMode ? [{ debugName: "placeholder" }] : /* istanbul ignore next */ []));
80
+ emptyText = input('No matching pages found.', /* @ts-ignore */
241
81
  ...(ngDevMode ? [{ debugName: "emptyText" }] : /* istanbul ignore next */ []));
242
- /** Loader function: takes search string, returns options. */
243
- loaderFn = input(async () => [], /* @ts-ignore */
244
- ...(ngDevMode ? [{ debugName: "loaderFn" }] : /* istanbul ignore next */ []));
245
- transformValueToSearch = input((value) => String(value), /* @ts-ignore */
246
- ...(ngDevMode ? [{ debugName: "transformValueToSearch" }] : /* istanbul ignore next */ []));
247
- search = signal('', /* @ts-ignore */
248
- ...(ngDevMode ? [{ debugName: "search" }] : /* istanbul ignore next */ []));
249
- options = signal([], /* @ts-ignore */
250
- ...(ngDevMode ? [{ debugName: "options" }] : /* istanbul ignore next */ []));
251
- filtered = computed(() => {
252
- const opts = this.options();
253
- const search = this.search().toLowerCase();
254
- const transform = this.transformValueToSearch() ?? ((value) => String(value));
255
- const mapped = opts.map((o) => ({ label: transform(o), value: o, raw: o }));
256
- if (!search)
257
- return mapped;
258
- return mapped.filter((o) => o.label.toLowerCase().includes(search));
259
- }, /* @ts-ignore */
260
- ...(ngDevMode ? [{ debugName: "filtered" }] : /* istanbul ignore next */ []));
261
- optionChange = output();
82
+ errorText = input('Search is unavailable. Please try again.', /* @ts-ignore */
83
+ ...(ngDevMode ? [{ debugName: "errorText" }] : /* istanbul ignore next */ []));
84
+ loadingText = input('Searching…', /* @ts-ignore */
85
+ ...(ngDevMode ? [{ debugName: "loadingText" }] : /* istanbul ignore next */ []));
86
+ retryText = input('Try again', /* @ts-ignore */
87
+ ...(ngDevMode ? [{ debugName: "retryText" }] : /* istanbul ignore next */ []));
88
+ loader = input(/* @ts-ignore */
89
+ ...(ngDevMode ? [undefined, { debugName: "loader" }] : /* istanbul ignore next */ []));
90
+ resultLabel = input(/* @ts-ignore */
91
+ ...(ngDevMode ? [undefined, { debugName: "resultLabel" }] : /* istanbul ignore next */ []));
92
+ resultTemplate = input(/* @ts-ignore */
93
+ ...(ngDevMode ? [undefined, { debugName: "resultTemplate" }] : /* istanbul ignore next */ []));
94
+ resultSelected = output();
95
+ searchIcon = lucideSearch;
96
+ query = signal('', /* @ts-ignore */
97
+ ...(ngDevMode ? [{ debugName: "query" }] : /* istanbul ignore next */ []));
98
+ results = signal([], /* @ts-ignore */
99
+ ...(ngDevMode ? [{ debugName: "results" }] : /* istanbul ignore next */ []));
100
+ isOpen = signal(false, /* @ts-ignore */
101
+ ...(ngDevMode ? [{ debugName: "isOpen" }] : /* istanbul ignore next */ []));
102
+ isLoading = signal(false, /* @ts-ignore */
103
+ ...(ngDevMode ? [{ debugName: "isLoading" }] : /* istanbul ignore next */ []));
104
+ hasError = signal(false, /* @ts-ignore */
105
+ ...(ngDevMode ? [{ debugName: "hasError" }] : /* istanbul ignore next */ []));
106
+ retryVersion = signal(0, /* @ts-ignore */
107
+ ...(ngDevMode ? [{ debugName: "retryVersion" }] : /* istanbul ignore next */ []));
108
+ searchInput = viewChild('searchInput', /* @ts-ignore */
109
+ ...(ngDevMode ? [{ debugName: "searchInput" }] : /* istanbul ignore next */ []));
110
+ resultButtons = viewChildren('resultButton', /* @ts-ignore */
111
+ ...(ngDevMode ? [{ debugName: "resultButtons" }] : /* istanbul ignore next */ []));
262
112
  constructor() {
263
- // Trigger initial load
264
- this.loadOptions();
113
+ effect((onCleanup) => {
114
+ const open = this.isOpen();
115
+ const search = this.query().trim();
116
+ const loader = this.loader();
117
+ this.retryVersion();
118
+ this.results.set([]);
119
+ this.hasError.set(false);
120
+ this.isLoading.set(open && !!loader);
121
+ if (!open || !loader)
122
+ return;
123
+ // Cleanup also invalidates an in-flight request when the component is destroyed.
124
+ let cancelled = false;
125
+ const timeout = setTimeout(async () => {
126
+ try {
127
+ const results = await loader({ search });
128
+ if (!cancelled)
129
+ this.results.set(results);
130
+ }
131
+ catch {
132
+ if (!cancelled)
133
+ this.hasError.set(true);
134
+ }
135
+ finally {
136
+ if (!cancelled)
137
+ this.isLoading.set(false);
138
+ }
139
+ }, search ? 180 : 0);
140
+ onCleanup(() => {
141
+ cancelled = true;
142
+ clearTimeout(timeout);
143
+ });
144
+ });
265
145
  }
266
- async loadOptions() {
267
- const fn = this.loaderFn();
268
- if (!fn) {
269
- this.options.set([]);
270
- return;
271
- }
272
- try {
273
- const params = { search: this.search() };
274
- const result = await fn(params);
275
- this.options.set(result ?? []);
276
- }
277
- catch {
278
- this.options.set([]);
279
- }
146
+ labelFor(item) {
147
+ return this.resultLabel()?.(item) ?? String(item);
280
148
  }
281
- select(opt) {
282
- this.optionChange.emit(opt.value);
283
- this.search.set('');
149
+ setOpen(open) {
150
+ this.isOpen.set(open);
151
+ if (!open)
152
+ this.query.set('');
284
153
  }
285
- static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "22.0.7", ngImport: i0, type: EgGenericAutocomplete, deps: [], target: i0.ɵɵFactoryTarget.Component });
286
- static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "22.0.7", type: EgGenericAutocomplete, isStandalone: true, selector: "eg-generic-autocomplete", inputs: { placeholderText: { classPropertyName: "placeholderText", publicName: "placeholderText", isSignal: true, isRequired: false, transformFunction: null }, emptyText: { classPropertyName: "emptyText", publicName: "emptyText", isSignal: true, isRequired: false, transformFunction: null }, loaderFn: { classPropertyName: "loaderFn", publicName: "loaderFn", isSignal: true, isRequired: false, transformFunction: null }, transformValueToSearch: { classPropertyName: "transformValueToSearch", publicName: "transformValueToSearch", isSignal: true, isRequired: false, transformFunction: null } }, outputs: { optionChange: "optionChange" }, providers: [provideIcons({ lucideSearch })], ngImport: i0, template: `
287
- <hlm-popover>
288
- <button
289
- hlmPopoverTrigger
290
- hlmButton
291
- variant="secondary"
292
- appearance="outline"
293
- type="button"
294
- class="w-64 justify-start gap-2 text-muted-foreground"
295
- >
296
- <ng-icon name="lucideSearch" size="14px" />
297
- <span class="truncate">{{ placeholderText() }}</span>
298
- </button>
299
-
300
- <hlm-popover-content class="w-64 p-2">
301
- <input
302
- hlmInput
303
- [ngModel]="search()"
304
- (ngModelChange)="search.set($event)"
305
- [placeholder]="placeholderText()"
306
- class="mb-2"
307
- />
308
- <div class="max-h-60 overflow-auto flex flex-col">
309
- @if (filtered().length === 0) {
310
- <span class="text-xs text-muted-foreground px-2 py-2">{{ emptyText() }}</span>
311
- } @else {
312
- @for (opt of filtered(); track opt.label) {
313
- <button
314
- type="button"
315
- (click)="select(opt)"
316
- class="text-left px-2 py-1.5 text-sm rounded-sm hover:bg-secondary cursor-pointer"
317
- >
318
- {{ opt.label }}
319
- </button>
320
- }
321
- }
322
- </div>
323
- </hlm-popover-content>
324
- </hlm-popover>
325
- `, isInline: true, dependencies: [{ kind: "ngmodule", type: FormsModule }, { kind: "directive", type: i1$1.DefaultValueAccessor, selector: "input:not([type=checkbox]):not([ngNoCva])[formControlName],textarea:not([ngNoCva])[formControlName],input:not([type=checkbox]):not([ngNoCva])[formControl],textarea:not([ngNoCva])[formControl],input:not([type=checkbox]):not([ngNoCva])[ngModel],textarea:not([ngNoCva])[ngModel],[ngDefaultControl]" }, { kind: "directive", type: i1$1.NgControlStatus, selector: "[formControlName],[ngModel],[formControl]" }, { kind: "directive", type: i1$1.NgModel, selector: "[ngModel]:not([formControlName]):not([formControl])", inputs: ["name", "disabled", "ngModel", "ngModelOptions"], outputs: ["ngModelChange"], exportAs: ["ngModel"] }, { kind: "directive", type: HlmPopover, selector: "[hlmPopover],hlm-popover" }, { kind: "directive", type: HlmPopoverTrigger, selector: "button[hlmPopoverTrigger],button[hlmPopoverTriggerFor]" }, { kind: "directive", type: HlmPopoverContent, selector: "[hlmPopoverContent],hlm-popover-content" }, { kind: "directive", type: HlmInput, selector: "[hlmInput]" }, { kind: "component", type: HlmButton, selector: "button[hlmButton], a[hlmButton]", inputs: ["variant", "size", "appearance", "loading", "icon", "iconPosition", "class", "spinnerUserClass", "disabled", "type"] }, { kind: "component", type: NgIcon, selector: "ng-icon", inputs: ["name", "svg", "size", "strokeWidth", "color"] }], changeDetection: i0.ChangeDetectionStrategy.OnPush });
154
+ retry() {
155
+ this.retryVersion.update((version) => version + 1);
156
+ }
157
+ selectResult(item) {
158
+ this.setOpen(false);
159
+ this.resultSelected.emit(item);
160
+ }
161
+ focusResult(index, event) {
162
+ const buttons = this.resultButtons();
163
+ if (!buttons.length)
164
+ return;
165
+ event.preventDefault();
166
+ if (index < 0)
167
+ this.searchInput()?.nativeElement.focus();
168
+ else
169
+ buttons[Math.min(index, buttons.length - 1)]?.nativeElement.focus();
170
+ }
171
+ static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "22.1.3", ngImport: i0, type: EgLayoutSearch, deps: [], target: i0.ɵɵFactoryTarget.Component });
172
+ static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "22.1.3", type: EgLayoutSearch, isStandalone: true, selector: "eg-layout-search", inputs: { placeholder: { classPropertyName: "placeholder", publicName: "placeholder", isSignal: true, isRequired: false, transformFunction: null }, emptyText: { classPropertyName: "emptyText", publicName: "emptyText", isSignal: true, isRequired: false, transformFunction: null }, errorText: { classPropertyName: "errorText", publicName: "errorText", isSignal: true, isRequired: false, transformFunction: null }, loadingText: { classPropertyName: "loadingText", publicName: "loadingText", isSignal: true, isRequired: false, transformFunction: null }, retryText: { classPropertyName: "retryText", publicName: "retryText", isSignal: true, isRequired: false, transformFunction: null }, loader: { classPropertyName: "loader", publicName: "loader", isSignal: true, isRequired: false, transformFunction: null }, resultLabel: { classPropertyName: "resultLabel", publicName: "resultLabel", isSignal: true, isRequired: false, transformFunction: null }, resultTemplate: { classPropertyName: "resultTemplate", publicName: "resultTemplate", isSignal: true, isRequired: false, transformFunction: null } }, outputs: { resultSelected: "resultSelected" }, host: { classAttribute: "block min-w-0" }, viewQueries: [{ propertyName: "searchInput", first: true, predicate: ["searchInput"], descendants: true, isSignal: true }, { propertyName: "resultButtons", predicate: ["resultButton"], descendants: true, isSignal: true }], ngImport: i0, template: "\n <hlm-popover\n [state]=\"isOpen() ? 'open' : 'closed'\"\n (stateChanged)=\"setOpen($event === 'open')\"\n (closed)=\"setOpen(false)\"\n >\n <button\n hlmPopoverTrigger\n type=\"button\"\n class=\"flex min-h-11 w-full items-center gap-2 rounded-lg border border-border bg-foreground/3 px-3 text-left text-sm text-foreground/75 cursor-pointer hover:bg-foreground/5 focus-visible:outline-2 focus-visible:outline-offset-2 focus-visible:outline-ring md:w-56\"\n >\n <ng-icon [svg]=\"searchIcon\" size=\"16px\" aria-hidden=\"true\" class=\"shrink-0\" />\n <span class=\"truncate\">{{ placeholder() }}</span>\n </button>\n <hlm-popover-content *hlmPopoverPortal class=\"w-80 max-w-[calc(100vw-2rem)] p-2\">\n <input\n #searchInput\n hlmInput\n type=\"search\"\n autocomplete=\"off\"\n [value]=\"query()\"\n (input)=\"query.set($any($event.target).value)\"\n [placeholder]=\"placeholder()\"\n [attr.aria-label]=\"placeholder()\"\n (keydown.arrowdown)=\"focusResult(0, $event)\"\n class=\"mb-2 min-h-11\"\n />\n <div [attr.aria-busy]=\"isLoading()\" class=\"max-h-72 overflow-y-auto overscroll-contain\">\n @if (isLoading()) {\n <p role=\"status\" class=\"px-3 py-6 text-center text-sm text-foreground/75\">\n {{ loadingText() }}\n </p>\n } @else if (hasError()) {\n <div role=\"status\" class=\"space-y-3 px-3 py-4 text-sm\">\n <p>{{ errorText() }}</p>\n <button\n type=\"button\"\n (click)=\"retry()\"\n class=\"min-h-11 rounded-md border border-border px-3 font-medium cursor-pointer focus-visible:outline-2 focus-visible:outline-ring\"\n >\n {{ retryText() }}\n </button>\n </div>\n } @else if (!results().length) {\n <p role=\"status\" class=\"px-3 py-6 text-center text-sm text-foreground/75\">\n {{ emptyText() }}\n </p>\n } @else {\n @for (result of results(); track $index; let index = $index) {\n <button\n #resultButton\n type=\"button\"\n (click)=\"selectResult(result)\"\n (keydown.arrowdown)=\"focusResult(index + 1, $event)\"\n (keydown.arrowup)=\"focusResult(index - 1, $event)\"\n (keydown.home)=\"focusResult(0, $event)\"\n (keydown.end)=\"focusResult(results().length - 1, $event)\"\n class=\"flex min-h-11 w-full items-center rounded-md px-3 py-2 text-left text-sm cursor-pointer hover:bg-foreground/5 focus-visible:bg-foreground/10 focus-visible:outline-2 focus-visible:-outline-offset-2 focus-visible:outline-ring\"\n >\n @if (resultTemplate(); as template) {\n <ng-container [ngTemplateOutlet]=\"template\" [ngTemplateOutletContext]=\"{ $implicit: result }\" />\n } @else {\n {{ labelFor(result) }}\n }\n </button>\n }\n }\n </div>\n </hlm-popover-content>\n </hlm-popover>\n ", isInline: true, dependencies: [{ kind: "directive", type: NgTemplateOutlet, selector: "[ngTemplateOutlet]", inputs: ["ngTemplateOutletContext", "ngTemplateOutlet", "ngTemplateOutletInjector"] }, { kind: "directive", type: HlmPopover, selector: "[hlmPopover],hlm-popover" }, { kind: "directive", type: HlmPopoverTrigger, selector: "button[hlmPopoverTrigger],button[hlmPopoverTriggerFor]" }, { kind: "directive", type: HlmPopoverContent, selector: "[hlmPopoverContent],hlm-popover-content" }, { kind: "directive", type: HlmPopoverPortal, selector: "[hlmPopoverPortal]" }, { kind: "directive", type: HlmInput, selector: "[hlmInput]", inputs: ["ariaDescribedby"] }, { kind: "component", type: NgIcon, selector: "ng-icon", inputs: ["name", "svg", "size", "strokeWidth", "color"] }], changeDetection: i0.ChangeDetectionStrategy.OnPush });
326
173
  }
327
- i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.0.7", ngImport: i0, type: EgGenericAutocomplete, decorators: [{
174
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.1.3", ngImport: i0, type: EgLayoutSearch, decorators: [{
328
175
  type: Component,
329
176
  args: [{
330
- selector: 'eg-generic-autocomplete',
331
- imports: [FormsModule, HlmPopover, HlmPopoverTrigger, HlmPopoverContent, HlmInput, HlmButton, NgIcon],
332
- providers: [provideIcons({ lucideSearch })],
333
- template: `
334
- <hlm-popover>
335
- <button
336
- hlmPopoverTrigger
337
- hlmButton
338
- variant="secondary"
339
- appearance="outline"
340
- type="button"
341
- class="w-64 justify-start gap-2 text-muted-foreground"
342
- >
343
- <ng-icon name="lucideSearch" size="14px" />
344
- <span class="truncate">{{ placeholderText() }}</span>
345
- </button>
346
-
347
- <hlm-popover-content class="w-64 p-2">
348
- <input
349
- hlmInput
350
- [ngModel]="search()"
351
- (ngModelChange)="search.set($event)"
352
- [placeholder]="placeholderText()"
353
- class="mb-2"
354
- />
355
- <div class="max-h-60 overflow-auto flex flex-col">
356
- @if (filtered().length === 0) {
357
- <span class="text-xs text-muted-foreground px-2 py-2">{{ emptyText() }}</span>
358
- } @else {
359
- @for (opt of filtered(); track opt.label) {
360
- <button
361
- type="button"
362
- (click)="select(opt)"
363
- class="text-left px-2 py-1.5 text-sm rounded-sm hover:bg-secondary cursor-pointer"
364
- >
365
- {{ opt.label }}
366
- </button>
367
- }
368
- }
369
- </div>
370
- </hlm-popover-content>
371
- </hlm-popover>
372
- `,
177
+ selector: 'eg-layout-search',
178
+ imports: [NgTemplateOutlet, HlmPopover, HlmPopoverTrigger, HlmPopoverContent, HlmPopoverPortal, HlmInput, NgIcon],
179
+ host: { class: "block min-w-0" },
180
+ template: "\n <hlm-popover\n [state]=\"isOpen() ? 'open' : 'closed'\"\n (stateChanged)=\"setOpen($event === 'open')\"\n (closed)=\"setOpen(false)\"\n >\n <button\n hlmPopoverTrigger\n type=\"button\"\n class=\"flex min-h-11 w-full items-center gap-2 rounded-lg border border-border bg-foreground/3 px-3 text-left text-sm text-foreground/75 cursor-pointer hover:bg-foreground/5 focus-visible:outline-2 focus-visible:outline-offset-2 focus-visible:outline-ring md:w-56\"\n >\n <ng-icon [svg]=\"searchIcon\" size=\"16px\" aria-hidden=\"true\" class=\"shrink-0\" />\n <span class=\"truncate\">{{ placeholder() }}</span>\n </button>\n <hlm-popover-content *hlmPopoverPortal class=\"w-80 max-w-[calc(100vw-2rem)] p-2\">\n <input\n #searchInput\n hlmInput\n type=\"search\"\n autocomplete=\"off\"\n [value]=\"query()\"\n (input)=\"query.set($any($event.target).value)\"\n [placeholder]=\"placeholder()\"\n [attr.aria-label]=\"placeholder()\"\n (keydown.arrowdown)=\"focusResult(0, $event)\"\n class=\"mb-2 min-h-11\"\n />\n <div [attr.aria-busy]=\"isLoading()\" class=\"max-h-72 overflow-y-auto overscroll-contain\">\n @if (isLoading()) {\n <p role=\"status\" class=\"px-3 py-6 text-center text-sm text-foreground/75\">\n {{ loadingText() }}\n </p>\n } @else if (hasError()) {\n <div role=\"status\" class=\"space-y-3 px-3 py-4 text-sm\">\n <p>{{ errorText() }}</p>\n <button\n type=\"button\"\n (click)=\"retry()\"\n class=\"min-h-11 rounded-md border border-border px-3 font-medium cursor-pointer focus-visible:outline-2 focus-visible:outline-ring\"\n >\n {{ retryText() }}\n </button>\n </div>\n } @else if (!results().length) {\n <p role=\"status\" class=\"px-3 py-6 text-center text-sm text-foreground/75\">\n {{ emptyText() }}\n </p>\n } @else {\n @for (result of results(); track $index; let index = $index) {\n <button\n #resultButton\n type=\"button\"\n (click)=\"selectResult(result)\"\n (keydown.arrowdown)=\"focusResult(index + 1, $event)\"\n (keydown.arrowup)=\"focusResult(index - 1, $event)\"\n (keydown.home)=\"focusResult(0, $event)\"\n (keydown.end)=\"focusResult(results().length - 1, $event)\"\n class=\"flex min-h-11 w-full items-center rounded-md px-3 py-2 text-left text-sm cursor-pointer hover:bg-foreground/5 focus-visible:bg-foreground/10 focus-visible:outline-2 focus-visible:-outline-offset-2 focus-visible:outline-ring\"\n >\n @if (resultTemplate(); as template) {\n <ng-container [ngTemplateOutlet]=\"template\" [ngTemplateOutletContext]=\"{ $implicit: result }\" />\n } @else {\n {{ labelFor(result) }}\n }\n </button>\n }\n }\n </div>\n </hlm-popover-content>\n </hlm-popover>\n ",
373
181
  changeDetection: ChangeDetectionStrategy.OnPush,
374
182
  }]
375
- }], ctorParameters: () => [], propDecorators: { placeholderText: [{ type: i0.Input, args: [{ isSignal: true, alias: "placeholderText", required: false }] }], emptyText: [{ type: i0.Input, args: [{ isSignal: true, alias: "emptyText", required: false }] }], loaderFn: [{ type: i0.Input, args: [{ isSignal: true, alias: "loaderFn", required: false }] }], transformValueToSearch: [{ type: i0.Input, args: [{ isSignal: true, alias: "transformValueToSearch", required: false }] }], optionChange: [{ type: i0.Output, args: ["optionChange"] }] } });
183
+ }], ctorParameters: () => [], propDecorators: { placeholder: [{ type: i0.Input, args: [{ isSignal: true, alias: "placeholder", required: false }] }], emptyText: [{ type: i0.Input, args: [{ isSignal: true, alias: "emptyText", required: false }] }], errorText: [{ type: i0.Input, args: [{ isSignal: true, alias: "errorText", required: false }] }], loadingText: [{ type: i0.Input, args: [{ isSignal: true, alias: "loadingText", required: false }] }], retryText: [{ type: i0.Input, args: [{ isSignal: true, alias: "retryText", required: false }] }], loader: [{ type: i0.Input, args: [{ isSignal: true, alias: "loader", required: false }] }], resultLabel: [{ type: i0.Input, args: [{ isSignal: true, alias: "resultLabel", required: false }] }], resultTemplate: [{ type: i0.Input, args: [{ isSignal: true, alias: "resultTemplate", required: false }] }], resultSelected: [{ type: i0.Output, args: ["resultSelected"] }], searchInput: [{ type: i0.ViewChild, args: ['searchInput', { isSignal: true }] }], resultButtons: [{ type: i0.ViewChildren, args: ['resultButton', { isSignal: true }] }] } });
376
184
 
377
185
  class EgLayoutSimpleSidebar {
378
- viewchildSheetRef = viewChild(BrnSheet, /* @ts-ignore */
379
- ...(ngDevMode ? [{ debugName: "viewchildSheetRef" }] : /* istanbul ignore next */ []));
380
- side = input('left', /* @ts-ignore */
381
- ...(ngDevMode ? [{ debugName: "side" }] : /* istanbul ignore next */ []));
382
- title = input('', /* @ts-ignore */
186
+ sheet = viewChild(BrnSheet, /* @ts-ignore */
187
+ ...(ngDevMode ? [{ debugName: "sheet" }] : /* istanbul ignore next */ []));
188
+ panelId = input.required(/* @ts-ignore */
189
+ ...(ngDevMode ? [{ debugName: "panelId" }] : /* istanbul ignore next */ []));
190
+ title = input('Navigation', /* @ts-ignore */
383
191
  ...(ngDevMode ? [{ debugName: "title" }] : /* istanbul ignore next */ []));
384
192
  content = input(/* @ts-ignore */
385
193
  ...(ngDevMode ? [undefined, { debugName: "content" }] : /* istanbul ignore next */ []));
386
- contentContext = input(/* @ts-ignore */
387
- ...(ngDevMode ? [undefined, { debugName: "contentContext" }] : /* istanbul ignore next */ []));
388
- constructor() {
389
- effect(() => { });
390
- }
391
- openSheet() {
392
- this.viewchildSheetRef()?.open();
194
+ contentContext = input(null, /* @ts-ignore */
195
+ ...(ngDevMode ? [{ debugName: "contentContext" }] : /* istanbul ignore next */ []));
196
+ open() {
197
+ this.sheet()?.open();
393
198
  }
394
- closeSheet() {
395
- this.viewchildSheetRef()?.close();
199
+ close() {
200
+ this.sheet()?.close();
396
201
  }
397
- static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "22.0.7", ngImport: i0, type: EgLayoutSimpleSidebar, deps: [], target: i0.ɵɵFactoryTarget.Component });
398
- static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "22.0.7", type: EgLayoutSimpleSidebar, isStandalone: true, selector: "eg-layout-simple-sidebar", inputs: { side: { classPropertyName: "side", publicName: "side", isSignal: true, isRequired: false, transformFunction: null }, title: { classPropertyName: "title", publicName: "title", isSignal: true, isRequired: false, transformFunction: null }, content: { classPropertyName: "content", publicName: "content", isSignal: true, isRequired: false, transformFunction: null }, contentContext: { classPropertyName: "contentContext", publicName: "contentContext", isSignal: true, isRequired: false, transformFunction: null } }, viewQueries: [{ propertyName: "viewchildSheetRef", first: true, predicate: BrnSheet, descendants: true, isSignal: true }], ngImport: i0, template: `
399
- @let _title = title();
400
- @let _content = content();
401
-
402
- <hlm-sheet [side]="side() ?? 'left'">
403
- <hlm-sheet-content *brnSheetContent="let ctx" class="gap-0">
404
- @if (_title) {
405
- <hlm-sheet-header>
406
- <h3 hlmSheetTitle>{{ _title }}</h3>
407
- </hlm-sheet-header>
408
- }
409
-
410
- @if (_content) {
411
- <ng-container *ngTemplateOutlet="_content; context: contentContext()"></ng-container>
412
- }
413
-
414
- <hlm-sheet-footer>
415
- <button brnSheetClose hlmButton variant="secondary" appearance="outline-filled">Close</button>
416
- </hlm-sheet-footer>
417
- </hlm-sheet-content>
418
- </hlm-sheet>
419
- `, isInline: true, dependencies: [{ kind: "ngmodule", type: CommonModule }, { kind: "directive", type: i1.NgTemplateOutlet, selector: "[ngTemplateOutlet]", inputs: ["ngTemplateOutletContext", "ngTemplateOutlet", "ngTemplateOutletInjector"] }, { kind: "ngmodule", type: RouterModule }, { kind: "directive", type: i2.BrnSheetClose, selector: "button[brnSheetClose]" }, { kind: "directive", type: i2.BrnSheetContent, selector: "[brnSheetContent]" }, { kind: "component", type: i3.HlmSheet, selector: "hlm-sheet", exportAs: ["hlmSheet"] }, { kind: "component", type: i3.HlmSheetContent, selector: "hlm-sheet-content", inputs: ["class"] }, { kind: "component", type: i3.HlmSheetFooter, selector: "hlm-sheet-footer", inputs: ["class"] }, { kind: "component", type: i3.HlmSheetHeader, selector: "hlm-sheet-header", inputs: ["class"] }, { kind: "directive", type: i3.HlmSheetTitle, selector: "[hlmSheetTitle]", inputs: ["class"] }, { kind: "component", type: i4.HlmButton, selector: "button[hlmButton], a[hlmButton]", inputs: ["variant", "size", "appearance", "loading", "icon", "iconPosition", "class", "spinnerUserClass", "disabled", "type"] }] });
202
+ static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "22.1.3", ngImport: i0, type: EgLayoutSimpleSidebar, deps: [], target: i0.ɵɵFactoryTarget.Component });
203
+ static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.2.0", version: "22.1.3", type: EgLayoutSimpleSidebar, isStandalone: true, selector: "eg-layout-simple-sidebar", inputs: { panelId: { classPropertyName: "panelId", publicName: "panelId", isSignal: true, isRequired: true, transformFunction: null }, title: { classPropertyName: "title", publicName: "title", isSignal: true, isRequired: false, transformFunction: null }, content: { classPropertyName: "content", publicName: "content", isSignal: true, isRequired: false, transformFunction: null }, contentContext: { classPropertyName: "contentContext", publicName: "contentContext", isSignal: true, isRequired: false, transformFunction: null } }, viewQueries: [{ propertyName: "sheet", first: true, predicate: BrnSheet, descendants: true, isSignal: true }], ngImport: i0, template: "\n <hlm-sheet [id]=\"panelId()\" side=\"left\">\n <hlm-sheet-content\n *brnSheetContent=\"let context\"\n class=\"flex h-full max-w-[calc(100vw-2rem)] flex-col gap-0\"\n >\n <hlm-sheet-header class=\"shrink-0 border-b border-border pr-12\">\n <h2 hlmSheetTitle>{{ title() }}</h2>\n </hlm-sheet-header>\n <div class=\"min-h-0 flex-1 overflow-y-auto overscroll-contain p-4\">\n <ng-container [ngTemplateOutlet]=\"content() ?? null\" [ngTemplateOutletContext]=\"contentContext()\" />\n </div>\n <hlm-sheet-footer class=\"shrink-0 border-t border-border\">\n <button type=\"button\" brnSheetClose hlmButton variant=\"secondary\" appearance=\"outline\">\n Close navigation\n </button>\n </hlm-sheet-footer>\n </hlm-sheet-content>\n </hlm-sheet>\n ", isInline: true, dependencies: [{ kind: "directive", type: NgTemplateOutlet, selector: "[ngTemplateOutlet]", inputs: ["ngTemplateOutletContext", "ngTemplateOutlet", "ngTemplateOutletInjector"] }, { kind: "directive", type: i1$1.BrnSheetClose, selector: "button[brnSheetClose]" }, { kind: "directive", type: i1$1.BrnSheetContent, selector: "[brnSheetContent]" }, { kind: "component", type: i2.HlmSheet, selector: "hlm-sheet", exportAs: ["hlmSheet"] }, { kind: "component", type: i2.HlmSheetContent, selector: "hlm-sheet-content", inputs: ["class"] }, { kind: "component", type: i2.HlmSheetFooter, selector: "hlm-sheet-footer", inputs: ["class"] }, { kind: "component", type: i2.HlmSheetHeader, selector: "hlm-sheet-header", inputs: ["class"] }, { kind: "directive", type: i2.HlmSheetTitle, selector: "[hlmSheetTitle]", inputs: ["class"] }, { kind: "component", type: i3.HlmButton, selector: "button[hlmButton], a[hlmButton]", inputs: ["variant", "size", "appearance", "loading", "icon", "iconPosition", "class", "spinnerUserClass", "disabled", "type"] }], changeDetection: i0.ChangeDetectionStrategy.OnPush });
420
204
  }
421
- i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.0.7", ngImport: i0, type: EgLayoutSimpleSidebar, decorators: [{
205
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.1.3", ngImport: i0, type: EgLayoutSimpleSidebar, decorators: [{
422
206
  type: Component,
423
207
  args: [{
424
208
  selector: 'eg-layout-simple-sidebar',
425
- standalone: true,
426
- imports: [CommonModule, RouterModule, BrnSheetImports, HlmSheetImports, HlmButtonImports, HlmLabelImports],
427
- template: `
428
- @let _title = title();
429
- @let _content = content();
430
-
431
- <hlm-sheet [side]="side() ?? 'left'">
432
- <hlm-sheet-content *brnSheetContent="let ctx" class="gap-0">
433
- @if (_title) {
434
- <hlm-sheet-header>
435
- <h3 hlmSheetTitle>{{ _title }}</h3>
436
- </hlm-sheet-header>
437
- }
438
-
439
- @if (_content) {
440
- <ng-container *ngTemplateOutlet="_content; context: contentContext()"></ng-container>
441
- }
209
+ imports: [NgTemplateOutlet, BrnSheetImports, HlmSheetImports, HlmButtonImports],
210
+ changeDetection: ChangeDetectionStrategy.OnPush,
211
+ template: "\n <hlm-sheet [id]=\"panelId()\" side=\"left\">\n <hlm-sheet-content\n *brnSheetContent=\"let context\"\n class=\"flex h-full max-w-[calc(100vw-2rem)] flex-col gap-0\"\n >\n <hlm-sheet-header class=\"shrink-0 border-b border-border pr-12\">\n <h2 hlmSheetTitle>{{ title() }}</h2>\n </hlm-sheet-header>\n <div class=\"min-h-0 flex-1 overflow-y-auto overscroll-contain p-4\">\n <ng-container [ngTemplateOutlet]=\"content() ?? null\" [ngTemplateOutletContext]=\"contentContext()\" />\n </div>\n <hlm-sheet-footer class=\"shrink-0 border-t border-border\">\n <button type=\"button\" brnSheetClose hlmButton variant=\"secondary\" appearance=\"outline\">\n Close navigation\n </button>\n </hlm-sheet-footer>\n </hlm-sheet-content>\n </hlm-sheet>\n ",
212
+ }]
213
+ }], propDecorators: { sheet: [{ type: i0.ViewChild, args: [i0.forwardRef(() => BrnSheet), { isSignal: true }] }], panelId: [{ type: i0.Input, args: [{ isSignal: true, alias: "panelId", required: true }] }], title: [{ type: i0.Input, args: [{ isSignal: true, alias: "title", required: false }] }], content: [{ type: i0.Input, args: [{ isSignal: true, alias: "content", required: false }] }], contentContext: [{ type: i0.Input, args: [{ isSignal: true, alias: "contentContext", required: false }] }] } });
442
214
 
443
- <hlm-sheet-footer>
444
- <button brnSheetClose hlmButton variant="secondary" appearance="outline-filled">Close</button>
445
- </hlm-sheet-footer>
446
- </hlm-sheet-content>
447
- </hlm-sheet>
448
- `,
215
+ /** Internal shared renderer keeps desktop, mobile, and footer navigation consistent. */
216
+ class EgLayoutNavigationItem {
217
+ item = input.required(/* @ts-ignore */
218
+ ...(ngDevMode ? [{ debugName: "item" }] : /* istanbul ignore next */ []));
219
+ itemClass = input('', /* @ts-ignore */
220
+ ...(ngDevMode ? [{ debugName: "itemClass" }] : /* istanbul ignore next */ []));
221
+ appearance = input('link', /* @ts-ignore */
222
+ ...(ngDevMode ? [{ debugName: "appearance" }] : /* istanbul ignore next */ []));
223
+ selected = output();
224
+ activeClasses = "bg-foreground/10 font-semibold underline decoration-2 underline-offset-4";
225
+ classes = computed(() => hlm("flex min-h-11 w-full items-center gap-2 rounded-lg px-3 py-2 text-left text-sm font-medium text-foreground no-underline cursor-pointer motion-safe:transition-colors hover:bg-foreground/5 focus-visible:outline-2 focus-visible:outline-offset-2 focus-visible:outline-ring disabled:cursor-not-allowed disabled:opacity-50", this.appearance() === 'card' &&
226
+ "h-full min-h-11 md:min-h-24 flex-col items-start justify-between gap-5 rounded-xl border border-transparent bg-foreground/3 p-4 font-semibold break-words hover:border-border hover:bg-foreground/7", this.itemClass(), this.item().class), /* @ts-ignore */
227
+ ...(ngDevMode ? [{ debugName: "classes" }] : /* istanbul ignore next */ []));
228
+ matchOptions = computed(() => navigationMatchOptions(this.item()), /* @ts-ignore */
229
+ ...(ngDevMode ? [{ debugName: "matchOptions" }] : /* istanbul ignore next */ []));
230
+ activate() {
231
+ const item = this.item();
232
+ if (item.disabled || !item.action)
233
+ return;
234
+ item.action();
235
+ this.selected.emit(item);
236
+ }
237
+ static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "22.1.3", ngImport: i0, type: EgLayoutNavigationItem, deps: [], target: i0.ɵɵFactoryTarget.Component });
238
+ static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "22.1.3", type: EgLayoutNavigationItem, isStandalone: true, selector: "eg-layout-navigation-item", inputs: { item: { classPropertyName: "item", publicName: "item", isSignal: true, isRequired: true, transformFunction: null }, itemClass: { classPropertyName: "itemClass", publicName: "itemClass", isSignal: true, isRequired: false, transformFunction: null }, appearance: { classPropertyName: "appearance", publicName: "appearance", isSignal: true, isRequired: false, transformFunction: null } }, outputs: { selected: "selected" }, host: { classAttribute: "block min-w-0 shrink-0" }, ngImport: i0, template: "\n @let entry = item();\n @if (entry.link && !entry.disabled) {\n <a\n [routerLink]=\"entry.link\"\n [routerLinkActive]=\"activeClasses\"\n [routerLinkActiveOptions]=\"matchOptions()\"\n ariaCurrentWhenActive=\"page\"\n [class]=\"classes()\"\n (click)=\"selected.emit(entry)\"\n >\n <ng-container [ngTemplateOutlet]=\"content\" />\n </a>\n } @else {\n <button type=\"button\" [class]=\"classes()\" [disabled]=\"entry.disabled || !entry.action\" (click)=\"activate()\">\n <ng-container [ngTemplateOutlet]=\"content\" />\n </button>\n }\n <ng-template #content>\n @if (entry.icon) {\n <ng-icon\n [svg]=\"entry.icon\"\n [size]=\"appearance() === 'card' ? '1.25rem' : '1rem'\"\n aria-hidden=\"true\"\n class=\"shrink-0\"\n />\n }\n <span class=\"min-w-0\">\n <span class=\"block\">{{ entry.label }}</span>\n @if (appearance() === 'card' && entry.description) {\n <span class=\"mt-1.5 block text-sm font-normal leading-relaxed text-foreground/75\">{{\n entry.description\n }}</span>\n }\n </span>\n </ng-template>\n ", isInline: true, dependencies: [{ kind: "directive", type: RouterLink, selector: "[routerLink]", inputs: ["target", "queryParams", "fragment", "queryParamsHandling", "state", "info", "relativeTo", "preserveFragment", "skipLocationChange", "replaceUrl", "browserUrl", "routerLink"] }, { kind: "directive", type: RouterLinkActive, selector: "[routerLinkActive]", inputs: ["routerLinkActiveOptions", "ariaCurrentWhenActive", "routerLinkActive"], outputs: ["isActiveChange"], exportAs: ["routerLinkActive"] }, { kind: "component", type: NgIcon, selector: "ng-icon", inputs: ["name", "svg", "size", "strokeWidth", "color"] }, { kind: "directive", type: NgTemplateOutlet, selector: "[ngTemplateOutlet]", inputs: ["ngTemplateOutletContext", "ngTemplateOutlet", "ngTemplateOutletInjector"] }], changeDetection: i0.ChangeDetectionStrategy.OnPush });
239
+ }
240
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.1.3", ngImport: i0, type: EgLayoutNavigationItem, decorators: [{
241
+ type: Component,
242
+ args: [{
243
+ selector: 'eg-layout-navigation-item',
244
+ imports: [RouterLink, RouterLinkActive, NgIcon, NgTemplateOutlet],
245
+ changeDetection: ChangeDetectionStrategy.OnPush,
246
+ host: { class: "block min-w-0 shrink-0" },
247
+ template: "\n @let entry = item();\n @if (entry.link && !entry.disabled) {\n <a\n [routerLink]=\"entry.link\"\n [routerLinkActive]=\"activeClasses\"\n [routerLinkActiveOptions]=\"matchOptions()\"\n ariaCurrentWhenActive=\"page\"\n [class]=\"classes()\"\n (click)=\"selected.emit(entry)\"\n >\n <ng-container [ngTemplateOutlet]=\"content\" />\n </a>\n } @else {\n <button type=\"button\" [class]=\"classes()\" [disabled]=\"entry.disabled || !entry.action\" (click)=\"activate()\">\n <ng-container [ngTemplateOutlet]=\"content\" />\n </button>\n }\n <ng-template #content>\n @if (entry.icon) {\n <ng-icon\n [svg]=\"entry.icon\"\n [size]=\"appearance() === 'card' ? '1.25rem' : '1rem'\"\n aria-hidden=\"true\"\n class=\"shrink-0\"\n />\n }\n <span class=\"min-w-0\">\n <span class=\"block\">{{ entry.label }}</span>\n @if (appearance() === 'card' && entry.description) {\n <span class=\"mt-1.5 block text-sm font-normal leading-relaxed text-foreground/75\">{{\n entry.description\n }}</span>\n }\n </span>\n </ng-template>\n ",
449
248
  }]
450
- }], ctorParameters: () => [], propDecorators: { viewchildSheetRef: [{ type: i0.ViewChild, args: [i0.forwardRef(() => BrnSheet), { isSignal: true }] }], side: [{ type: i0.Input, args: [{ isSignal: true, alias: "side", required: false }] }], title: [{ type: i0.Input, args: [{ isSignal: true, alias: "title", required: false }] }], content: [{ type: i0.Input, args: [{ isSignal: true, alias: "content", required: false }] }], contentContext: [{ type: i0.Input, args: [{ isSignal: true, alias: "contentContext", required: false }] }] } });
249
+ }], propDecorators: { item: [{ type: i0.Input, args: [{ isSignal: true, alias: "item", required: true }] }], itemClass: [{ type: i0.Input, args: [{ isSignal: true, alias: "itemClass", required: false }] }], appearance: [{ type: i0.Input, args: [{ isSignal: true, alias: "appearance", required: false }] }], selected: [{ type: i0.Output, args: ["selected"] }] } });
451
250
 
452
251
  class EgLayoutSimpleMobileMenuGroup {
453
- hlm = hlm;
454
- label = input('', /* @ts-ignore */
455
- ...(ngDevMode ? [{ debugName: "label" }] : /* istanbul ignore next */ []));
252
+ label = input(/* @ts-ignore */
253
+ ...(ngDevMode ? [undefined, { debugName: "label" }] : /* istanbul ignore next */ []));
456
254
  items = input(/* @ts-ignore */
457
255
  ...(ngDevMode ? [undefined, { debugName: "items" }] : /* istanbul ignore next */ []));
458
- itemClick = output();
459
- handleClick(item) {
460
- item.action?.();
461
- this.itemClick.emit(item);
462
- }
463
- static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "22.0.7", ngImport: i0, type: EgLayoutSimpleMobileMenuGroup, deps: [], target: i0.ɵɵFactoryTarget.Component });
464
- static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "22.0.7", type: EgLayoutSimpleMobileMenuGroup, isStandalone: true, selector: "eg-layout-simple-mobile-menu-group", inputs: { label: { classPropertyName: "label", publicName: "label", isSignal: true, isRequired: false, transformFunction: null }, items: { classPropertyName: "items", publicName: "items", isSignal: true, isRequired: false, transformFunction: null } }, outputs: { itemClick: "itemClick" }, providers: [], ngImport: i0, template: `
465
- @let _label = label();
466
- @let _items = items();
467
-
468
- @if (_items && _items.length > 0) {
469
- @if (_label) {
470
- <div class="px-3 py-1 text-xs font-semibold text-muted-foreground">{{ _label }}</div>
471
- }
472
- <div class="flex flex-col">
473
- @for (item of _items; track item.label) {
474
- @if (item.link) {
475
- <a
476
- [routerLink]="item.link"
477
- [class]="
478
- hlm(
479
- 'cursor-pointer no-underline px-3 py-2 text-sm hover:bg-secondary rounded-sm flex items-center gap-2'
480
- )
481
- "
482
- (click)="handleClick(item)"
483
- >
484
- @if (item.icon) {
485
- <ng-icon [svg]="item.icon" size="1rem" [class]="hlm('cursor-pointer mr-2')"> </ng-icon>
486
- }
487
- <span>{{ item.label }}</span>
488
- </a>
489
- } @else {
490
- <button
491
- type="button"
492
- (click)="handleClick(item)"
493
- [class]="
494
- hlm(
495
- 'cursor-pointer no-underline px-3 py-2 text-sm hover:bg-secondary rounded-sm flex items-center gap-2 bg-transparent border-0 text-left w-full'
496
- )
497
- "
498
- >
499
- @if (item.icon) {
500
- <ng-icon [svg]="item.icon" size="1rem" [class]="hlm('cursor-pointer mr-2')"> </ng-icon>
501
- }
502
- <span>{{ item.label }}</span>
503
- </button>
504
- }
505
- }
506
- </div>
507
- }
508
- `, isInline: true, dependencies: [{ kind: "component", type: NgIcon, selector: "ng-icon", inputs: ["name", "svg", "size", "strokeWidth", "color"] }, { kind: "directive", type: RouterLink, selector: "[routerLink]", inputs: ["target", "queryParams", "fragment", "queryParamsHandling", "state", "info", "relativeTo", "preserveFragment", "skipLocationChange", "replaceUrl", "browserUrl", "routerLink"] }] });
256
+ itemSelected = output();
257
+ static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "22.1.3", ngImport: i0, type: EgLayoutSimpleMobileMenuGroup, deps: [], target: i0.ɵɵFactoryTarget.Component });
258
+ static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "22.1.3", type: EgLayoutSimpleMobileMenuGroup, isStandalone: true, selector: "eg-layout-simple-mobile-menu-group", inputs: { label: { classPropertyName: "label", publicName: "label", isSignal: true, isRequired: false, transformFunction: null }, items: { classPropertyName: "items", publicName: "items", isSignal: true, isRequired: false, transformFunction: null } }, outputs: { itemSelected: "itemSelected" }, host: { classAttribute: "block empty:hidden" }, ngImport: i0, template: "\n @if (items()?.length) {\n @if (label()) {\n <div class=\"px-3 pb-2 text-xs font-semibold text-foreground/75\">{{ label() }}</div>\n }\n <div class=\"grid gap-1\">\n @for (item of items(); track $index) {\n <eg-layout-navigation-item [item]=\"item\" (selected)=\"itemSelected.emit($event)\" />\n }\n </div>\n }\n ", isInline: true, dependencies: [{ kind: "component", type: EgLayoutNavigationItem, selector: "eg-layout-navigation-item", inputs: ["item", "itemClass", "appearance"], outputs: ["selected"] }], changeDetection: i0.ChangeDetectionStrategy.OnPush });
509
259
  }
510
- i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.0.7", ngImport: i0, type: EgLayoutSimpleMobileMenuGroup, decorators: [{
260
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.1.3", ngImport: i0, type: EgLayoutSimpleMobileMenuGroup, decorators: [{
511
261
  type: Component,
512
262
  args: [{
513
263
  selector: 'eg-layout-simple-mobile-menu-group',
514
- imports: [NgIcon, RouterLink],
515
- providers: [],
516
- template: `
517
- @let _label = label();
518
- @let _items = items();
264
+ imports: [EgLayoutNavigationItem],
265
+ changeDetection: ChangeDetectionStrategy.OnPush,
266
+ host: { class: "block empty:hidden" },
267
+ template: "\n @if (items()?.length) {\n @if (label()) {\n <div class=\"px-3 pb-2 text-xs font-semibold text-foreground/75\">{{ label() }}</div>\n }\n <div class=\"grid gap-1\">\n @for (item of items(); track $index) {\n <eg-layout-navigation-item [item]=\"item\" (selected)=\"itemSelected.emit($event)\" />\n }\n </div>\n }\n ",
268
+ }]
269
+ }], propDecorators: { label: [{ type: i0.Input, args: [{ isSignal: true, alias: "label", required: false }] }], items: [{ type: i0.Input, args: [{ isSignal: true, alias: "items", required: false }] }], itemSelected: [{ type: i0.Output, args: ["itemSelected"] }] } });
519
270
 
520
- @if (_items && _items.length > 0) {
521
- @if (_label) {
522
- <div class="px-3 py-1 text-xs font-semibold text-muted-foreground">{{ _label }}</div>
523
- }
524
- <div class="flex flex-col">
525
- @for (item of _items; track item.label) {
526
- @if (item.link) {
527
- <a
528
- [routerLink]="item.link"
529
- [class]="
530
- hlm(
531
- 'cursor-pointer no-underline px-3 py-2 text-sm hover:bg-secondary rounded-sm flex items-center gap-2'
532
- )
533
- "
534
- (click)="handleClick(item)"
535
- >
536
- @if (item.icon) {
537
- <ng-icon [svg]="item.icon" size="1rem" [class]="hlm('cursor-pointer mr-2')"> </ng-icon>
538
- }
539
- <span>{{ item.label }}</span>
540
- </a>
541
- } @else {
542
- <button
543
- type="button"
544
- (click)="handleClick(item)"
545
- [class]="
546
- hlm(
547
- 'cursor-pointer no-underline px-3 py-2 text-sm hover:bg-secondary rounded-sm flex items-center gap-2 bg-transparent border-0 text-left w-full'
548
- )
549
- "
550
- >
551
- @if (item.icon) {
552
- <ng-icon [svg]="item.icon" size="1rem" [class]="hlm('cursor-pointer mr-2')"> </ng-icon>
553
- }
554
- <span>{{ item.label }}</span>
555
- </button>
556
- }
271
+ /** Internal disclosure navigation: native links, normal Tab order, no application-menu roles. */
272
+ class EgLayoutFlyoutNavbar {
273
+ groups = input.required(/* @ts-ignore */
274
+ ...(ngDevMode ? [{ debugName: "groups" }] : /* istanbul ignore next */ []));
275
+ label = input('Fly-out navigation', /* @ts-ignore */
276
+ ...(ngDevMode ? [{ debugName: "label" }] : /* istanbul ignore next */ []));
277
+ closeLabel = input('Close navigation panel', /* @ts-ignore */
278
+ ...(ngDevMode ? [{ debugName: "closeLabel" }] : /* istanbul ignore next */ []));
279
+ navbarClass = input('', /* @ts-ignore */
280
+ ...(ngDevMode ? [{ debugName: "navbarClass" }] : /* istanbul ignore next */ []));
281
+ panelClass = input('', /* @ts-ignore */
282
+ ...(ngDevMode ? [{ debugName: "panelClass" }] : /* istanbul ignore next */ []));
283
+ itemClass = input('', /* @ts-ignore */
284
+ ...(ngDevMode ? [{ debugName: "itemClass" }] : /* istanbul ignore next */ []));
285
+ host = inject(ElementRef);
286
+ injector = inject(Injector);
287
+ router = inject(Router);
288
+ currentUrl = signal(this.router.url, /* @ts-ignore */
289
+ ...(ngDevMode ? [{ debugName: "currentUrl" }] : /* istanbul ignore next */ []));
290
+ triggers = viewChildren('trigger', /* @ts-ignore */
291
+ ...(ngDevMode ? [{ debugName: "triggers" }] : /* istanbul ignore next */ []));
292
+ panel = viewChild('panel', /* @ts-ignore */
293
+ ...(ngDevMode ? [{ debugName: "panel" }] : /* istanbul ignore next */ []));
294
+ id = inject(_IdGenerator).getId('eg-layout-flyout-');
295
+ hlm = hlm;
296
+ chevronIcon = lucideChevronDown;
297
+ closeIcon = lucideX;
298
+ openIndex = signal(null, /* @ts-ignore */
299
+ ...(ngDevMode ? [{ debugName: "openIndex" }] : /* istanbul ignore next */ []));
300
+ navbarClasses = computed(() => hlm("flex flex-wrap items-center gap-1 border-b border-border bg-background px-4 py-2 sm:px-6", this.navbarClass()), /* @ts-ignore */
301
+ ...(ngDevMode ? [{ debugName: "navbarClasses" }] : /* istanbul ignore next */ []));
302
+ panelClasses = computed(() => hlm("absolute inset-x-0 top-full max-h-[min(70dvh,36rem)] overflow-y-auto overscroll-contain rounded-b-2xl border border-t-0 border-border bg-background p-5 text-foreground shadow-xl sm:p-6", this.panelClass()), /* @ts-ignore */
303
+ ...(ngDevMode ? [{ debugName: "panelClasses" }] : /* istanbul ignore next */ []));
304
+ activeGroups = computed(() => {
305
+ this.currentUrl();
306
+ return this.groups().map((group) => group.items.some((item) => item.link && !item.disabled && this.router.isActive(item.link, navigationMatchOptions(item))));
307
+ }, /* @ts-ignore */
308
+ ...(ngDevMode ? [{ debugName: "activeGroups" }] : /* istanbul ignore next */ []));
309
+ constructor() {
310
+ this.router.events.pipe(takeUntilDestroyed()).subscribe((event) => {
311
+ if (event instanceof NavigationEnd) {
312
+ this.currentUrl.set(event.urlAfterRedirects);
313
+ this.close();
314
+ }
315
+ });
316
+ effect(() => {
317
+ this.groups();
318
+ this.close();
319
+ });
320
+ }
321
+ toggle(index) {
322
+ this.openIndex.update((open) => (open === index ? null : index));
323
+ }
324
+ close(restoreFocus = false) {
325
+ const index = restoreFocus ? this.openIndex() : null;
326
+ this.openIndex.set(null);
327
+ if (restoreFocus && index !== null)
328
+ this.triggers()[index]?.nativeElement.focus();
329
+ }
330
+ closeOnOutsidePointer(event) {
331
+ if (!this.host.nativeElement.contains(event.target))
332
+ this.close();
333
+ }
334
+ closeOnFocusOut(event) {
335
+ if (!this.host.nativeElement.contains(event.relatedTarget))
336
+ this.close();
337
+ }
338
+ onEscape(event) {
339
+ if (this.openIndex() === null)
340
+ return;
341
+ event.preventDefault();
342
+ event.stopPropagation();
343
+ this.close(true);
344
+ }
345
+ onTriggerKeydown(event, index) {
346
+ if (event.key === 'ArrowDown' || event.key === 'ArrowUp') {
347
+ event.preventDefault();
348
+ this.openIndex.set(index);
349
+ afterNextRender(() => {
350
+ const items = this.panel()?.nativeElement.querySelectorAll('eg-layout-navigation-item a, eg-layout-navigation-item button:not(:disabled)');
351
+ const position = event.key === 'ArrowUp' ? (items?.length ?? 0) - 1 : 0;
352
+ items?.[position]?.focus();
353
+ }, { injector: this.injector });
354
+ return;
557
355
  }
558
- </div>
356
+ const triggers = this.triggers()
357
+ .map((trigger) => trigger.nativeElement)
358
+ .filter((trigger) => !trigger.disabled);
359
+ const current = triggers.indexOf(event.currentTarget);
360
+ let next;
361
+ switch (event.key) {
362
+ case 'ArrowRight':
363
+ next = (current + 1) % triggers.length;
364
+ break;
365
+ case 'ArrowLeft':
366
+ next = (current - 1 + triggers.length) % triggers.length;
367
+ break;
368
+ case 'Home':
369
+ next = 0;
370
+ break;
371
+ case 'End':
372
+ next = triggers.length - 1;
373
+ break;
374
+ default:
375
+ return;
376
+ }
377
+ event.preventDefault();
378
+ this.close();
379
+ triggers[next]?.focus();
559
380
  }
560
- `,
381
+ static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "22.1.3", ngImport: i0, type: EgLayoutFlyoutNavbar, deps: [], target: i0.ɵɵFactoryTarget.Component });
382
+ static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "22.1.3", type: EgLayoutFlyoutNavbar, isStandalone: true, selector: "eg-layout-flyout-navbar", inputs: { groups: { classPropertyName: "groups", publicName: "groups", isSignal: true, isRequired: true, transformFunction: null }, label: { classPropertyName: "label", publicName: "label", isSignal: true, isRequired: false, transformFunction: null }, closeLabel: { classPropertyName: "closeLabel", publicName: "closeLabel", isSignal: true, isRequired: false, transformFunction: null }, navbarClass: { classPropertyName: "navbarClass", publicName: "navbarClass", isSignal: true, isRequired: false, transformFunction: null }, panelClass: { classPropertyName: "panelClass", publicName: "panelClass", isSignal: true, isRequired: false, transformFunction: null }, itemClass: { classPropertyName: "itemClass", publicName: "itemClass", isSignal: true, isRequired: false, transformFunction: null } }, host: { listeners: { "document:pointerdown": "closeOnOutsidePointer($event)", "focusout": "closeOnFocusOut($event)", "keydown.escape": "onEscape($event)" }, classAttribute: "relative z-20 block min-w-0" }, viewQueries: [{ propertyName: "triggers", predicate: ["trigger"], descendants: true, isSignal: true }, { propertyName: "panel", first: true, predicate: ["panel"], descendants: true, isSignal: true }], ngImport: i0, template: "\n <nav [attr.aria-label]=\"label()\" [class]=\"navbarClasses()\">\n @for (group of groups(); track $index; let index = $index) {\n <button\n #trigger\n type=\"button\"\n [id]=\"id + '-trigger-' + index\"\n [attr.aria-controls]=\"id + '-panel-' + index\"\n [attr.aria-expanded]=\"openIndex() === index\"\n [disabled]=\"!group.items.length\"\n (click)=\"toggle(index)\"\n (keydown)=\"onTriggerKeydown($event, index)\"\n [attr.data-active]=\"activeGroups()[index] ? '' : null\"\n [class]=\"\n hlm(\n 'tw:flex tw:min-h-11 tw:items-center tw:gap-2 tw:rounded-lg tw:px-3 tw:py-2 tw:text-left tw:text-sm tw:font-medium tw:text-foreground tw:cursor-pointer tw:hover:bg-foreground/5 tw:focus-visible:outline-2 tw:focus-visible:outline-offset-2 tw:focus-visible:outline-ring tw:disabled:cursor-not-allowed tw:disabled:opacity-50',\n (openIndex() === index || activeGroups()[index]) && 'tw:bg-foreground/7 tw:font-semibold'\n )\n \"\n >\n @if (group.icon) {\n <ng-icon [svg]=\"group.icon\" size=\"1rem\" aria-hidden=\"true\" />\n }\n {{ group.label }}\n <ng-icon\n [svg]=\"chevronIcon\"\n size=\"14px\"\n aria-hidden=\"true\"\n [class]=\"hlm('tw:shrink-0 tw:motion-safe:transition-transform', openIndex() === index && 'tw:rotate-180')\"\n />\n </button>\n @if (openIndex() === index) {\n <section\n #panel\n [id]=\"id + '-panel-' + index\"\n [attr.aria-labelledby]=\"id + '-trigger-' + index\"\n data-slot=\"flyout-panel\"\n [class]=\"panelClasses()\"\n >\n <div class=\"mb-4 flex items-start justify-between gap-4\">\n <div class=\"space-y-1\">\n <p class=\"text-xs font-semibold uppercase tracking-wider text-foreground/75\">\n {{ group.label }}\n </p>\n @if (group.description) {\n <p class=\"max-w-2xl text-sm leading-relaxed text-foreground/75\">\n {{ group.description }}\n </p>\n }\n </div>\n <button\n type=\"button\"\n [attr.aria-label]=\"closeLabel()\"\n (click)=\"close(true)\"\n class=\"inline-flex size-11 shrink-0 items-center justify-center rounded-lg text-foreground/75 cursor-pointer hover:bg-foreground/5 focus-visible:outline-2 focus-visible:outline-ring\"\n >\n <ng-icon [svg]=\"closeIcon\" size=\"18px\" aria-hidden=\"true\" />\n </button>\n </div>\n <div class=\"grid grid-cols-2 gap-3 lg:grid-cols-3\">\n @for (item of group.items; track $index) {\n <eg-layout-navigation-item\n [item]=\"item\"\n appearance=\"card\"\n [itemClass]=\"itemClass()\"\n (selected)=\"close(true)\"\n />\n }\n </div>\n </section>\n }\n }\n </nav>\n ", isInline: true, dependencies: [{ kind: "component", type: NgIcon, selector: "ng-icon", inputs: ["name", "svg", "size", "strokeWidth", "color"] }, { kind: "component", type: EgLayoutNavigationItem, selector: "eg-layout-navigation-item", inputs: ["item", "itemClass", "appearance"], outputs: ["selected"] }], changeDetection: i0.ChangeDetectionStrategy.OnPush });
383
+ }
384
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.1.3", ngImport: i0, type: EgLayoutFlyoutNavbar, decorators: [{
385
+ type: Component,
386
+ args: [{
387
+ selector: 'eg-layout-flyout-navbar',
388
+ imports: [NgIcon, EgLayoutNavigationItem],
389
+ changeDetection: ChangeDetectionStrategy.OnPush,
390
+ host: {
391
+ class: "relative z-20 block min-w-0",
392
+ '(document:pointerdown)': 'closeOnOutsidePointer($event)',
393
+ '(focusout)': 'closeOnFocusOut($event)',
394
+ '(keydown.escape)': 'onEscape($event)',
395
+ },
396
+ template: "\n <nav [attr.aria-label]=\"label()\" [class]=\"navbarClasses()\">\n @for (group of groups(); track $index; let index = $index) {\n <button\n #trigger\n type=\"button\"\n [id]=\"id + '-trigger-' + index\"\n [attr.aria-controls]=\"id + '-panel-' + index\"\n [attr.aria-expanded]=\"openIndex() === index\"\n [disabled]=\"!group.items.length\"\n (click)=\"toggle(index)\"\n (keydown)=\"onTriggerKeydown($event, index)\"\n [attr.data-active]=\"activeGroups()[index] ? '' : null\"\n [class]=\"\n hlm(\n 'tw:flex tw:min-h-11 tw:items-center tw:gap-2 tw:rounded-lg tw:px-3 tw:py-2 tw:text-left tw:text-sm tw:font-medium tw:text-foreground tw:cursor-pointer tw:hover:bg-foreground/5 tw:focus-visible:outline-2 tw:focus-visible:outline-offset-2 tw:focus-visible:outline-ring tw:disabled:cursor-not-allowed tw:disabled:opacity-50',\n (openIndex() === index || activeGroups()[index]) && 'tw:bg-foreground/7 tw:font-semibold'\n )\n \"\n >\n @if (group.icon) {\n <ng-icon [svg]=\"group.icon\" size=\"1rem\" aria-hidden=\"true\" />\n }\n {{ group.label }}\n <ng-icon\n [svg]=\"chevronIcon\"\n size=\"14px\"\n aria-hidden=\"true\"\n [class]=\"hlm('tw:shrink-0 tw:motion-safe:transition-transform', openIndex() === index && 'tw:rotate-180')\"\n />\n </button>\n @if (openIndex() === index) {\n <section\n #panel\n [id]=\"id + '-panel-' + index\"\n [attr.aria-labelledby]=\"id + '-trigger-' + index\"\n data-slot=\"flyout-panel\"\n [class]=\"panelClasses()\"\n >\n <div class=\"mb-4 flex items-start justify-between gap-4\">\n <div class=\"space-y-1\">\n <p class=\"text-xs font-semibold uppercase tracking-wider text-foreground/75\">\n {{ group.label }}\n </p>\n @if (group.description) {\n <p class=\"max-w-2xl text-sm leading-relaxed text-foreground/75\">\n {{ group.description }}\n </p>\n }\n </div>\n <button\n type=\"button\"\n [attr.aria-label]=\"closeLabel()\"\n (click)=\"close(true)\"\n class=\"inline-flex size-11 shrink-0 items-center justify-center rounded-lg text-foreground/75 cursor-pointer hover:bg-foreground/5 focus-visible:outline-2 focus-visible:outline-ring\"\n >\n <ng-icon [svg]=\"closeIcon\" size=\"18px\" aria-hidden=\"true\" />\n </button>\n </div>\n <div class=\"grid grid-cols-2 gap-3 lg:grid-cols-3\">\n @for (item of group.items; track $index) {\n <eg-layout-navigation-item\n [item]=\"item\"\n appearance=\"card\"\n [itemClass]=\"itemClass()\"\n (selected)=\"close(true)\"\n />\n }\n </div>\n </section>\n }\n }\n </nav>\n ",
561
397
  }]
562
- }], propDecorators: { label: [{ type: i0.Input, args: [{ isSignal: true, alias: "label", required: false }] }], items: [{ type: i0.Input, args: [{ isSignal: true, alias: "items", required: false }] }], itemClick: [{ type: i0.Output, args: ["itemClick"] }] } });
398
+ }], ctorParameters: () => [], propDecorators: { groups: [{ type: i0.Input, args: [{ isSignal: true, alias: "groups", required: true }] }], label: [{ type: i0.Input, args: [{ isSignal: true, alias: "label", required: false }] }], closeLabel: [{ type: i0.Input, args: [{ isSignal: true, alias: "closeLabel", required: false }] }], navbarClass: [{ type: i0.Input, args: [{ isSignal: true, alias: "navbarClass", required: false }] }], panelClass: [{ type: i0.Input, args: [{ isSignal: true, alias: "panelClass", required: false }] }], itemClass: [{ type: i0.Input, args: [{ isSignal: true, alias: "itemClass", required: false }] }], triggers: [{ type: i0.ViewChildren, args: ['trigger', { isSignal: true }] }], panel: [{ type: i0.ViewChild, args: ['panel', { isSignal: true }] }] } });
563
399
 
564
- const commonLinkGroupClasses = 'hidden md:flex space-x-4 items-center';
565
- const commonLinkClasses = 'text-left text-secondary visited:text-secondary hover:text-primary cursor-pointer no-underline';
400
+ /** Matches Tailwind's default `md` breakpoint. */
401
+ const EG_LAYOUT_SIMPLE_MOBILE_BREAKPOINT = '(max-width: 767.98px)';
402
+ /** Responsive application shell. All navigation surfaces share the same item model. */
566
403
  class EgLayoutSimple {
567
- breakpointObserver;
404
+ destroyRef = inject(DestroyRef);
405
+ breakpointObserver = inject(BreakpointObserver);
406
+ router = inject(Router);
407
+ instanceId = inject(_IdGenerator).getId('eg-layout-simple-');
408
+ mainId = `${this.instanceId}-main`;
409
+ mobileMenuId = `${this.instanceId}-mobile-menu`;
410
+ sidebarId = `${this.instanceId}-sidebar`;
568
411
  hlm = hlm;
412
+ navigationMatchOptions = navigationMatchOptions;
569
413
  menuIcon = lucideMenu;
414
+ sidebarIcon = lucidePanelLeft;
415
+ closeIcon = lucideX;
416
+ chevronIcon = lucideChevronDown;
417
+ mobileMenuTrigger = viewChild('mobileMenuTrigger', /* @ts-ignore */
418
+ ...(ngDevMode ? [{ debugName: "mobileMenuTrigger" }] : /* istanbul ignore next */ []));
419
+ mainContent = viewChild('mainContent', /* @ts-ignore */
420
+ ...(ngDevMode ? [{ debugName: "mainContent" }] : /* istanbul ignore next */ []));
421
+ sidebar = viewChild(EgLayoutSimpleSidebar, /* @ts-ignore */
422
+ ...(ngDevMode ? [{ debugName: "sidebar" }] : /* istanbul ignore next */ []));
570
423
  sidebarEnabled = input(false, /* @ts-ignore */
571
424
  ...(ngDevMode ? [{ debugName: "sidebarEnabled" }] : /* istanbul ignore next */ []));
572
- sidebarTitle = input('Menu', /* @ts-ignore */
425
+ sidebarTitle = input('Navigation', /* @ts-ignore */
573
426
  ...(ngDevMode ? [{ debugName: "sidebarTitle" }] : /* istanbul ignore next */ []));
574
427
  sidebarContent = input(/* @ts-ignore */
575
428
  ...(ngDevMode ? [undefined, { debugName: "sidebarContent" }] : /* istanbul ignore next */ []));
429
+ sidebarToggleLabel = input('Open navigation sidebar', /* @ts-ignore */
430
+ ...(ngDevMode ? [{ debugName: "sidebarToggleLabel" }] : /* istanbul ignore next */ []));
431
+ mobileMenuLabel = input('Open navigation menu', /* @ts-ignore */
432
+ ...(ngDevMode ? [{ debugName: "mobileMenuLabel" }] : /* istanbul ignore next */ []));
433
+ mobileMenuCloseLabel = input('Close navigation menu', /* @ts-ignore */
434
+ ...(ngDevMode ? [{ debugName: "mobileMenuCloseLabel" }] : /* istanbul ignore next */ []));
576
435
  userMenuTrigger = input(/* @ts-ignore */
577
436
  ...(ngDevMode ? [undefined, { debugName: "userMenuTrigger" }] : /* istanbul ignore next */ []));
578
- /** Menu data inputs */
579
- leftMenus = input([], /* @ts-ignore */
580
- ...(ngDevMode ? [{ debugName: "leftMenus" }] : /* istanbul ignore next */ []));
581
- leftMenuGroups = input([], /* @ts-ignore */
582
- ...(ngDevMode ? [{ debugName: "leftMenuGroups" }] : /* istanbul ignore next */ []));
583
- rightMenus = input([], /* @ts-ignore */
584
- ...(ngDevMode ? [{ debugName: "rightMenus" }] : /* istanbul ignore next */ []));
585
- topMenus = input([], /* @ts-ignore */
586
- ...(ngDevMode ? [{ debugName: "topMenus" }] : /* istanbul ignore next */ []));
587
- topSecondaryMenus = input([], /* @ts-ignore */
588
- ...(ngDevMode ? [{ debugName: "topSecondaryMenus" }] : /* istanbul ignore next */ []));
589
- userMenus = input([], /* @ts-ignore */
590
- ...(ngDevMode ? [{ debugName: "userMenus" }] : /* istanbul ignore next */ []));
591
- logo = input('assets/logo.png', /* @ts-ignore */
437
+ userMenuLabel = input('Open account menu', /* @ts-ignore */
438
+ ...(ngDevMode ? [{ debugName: "userMenuLabel" }] : /* istanbul ignore next */ []));
439
+ /** Main header destinations; use `activeMatch: 'prefix'` for whole sections. */
440
+ primaryNavigation = input([], /* @ts-ignore */
441
+ ...(ngDevMode ? [{ debugName: "primaryNavigation" }] : /* istanbul ignore next */ []));
442
+ navigationGroups = input([], /* @ts-ignore */
443
+ ...(ngDevMode ? [{ debugName: "navigationGroups" }] : /* istanbul ignore next */ []));
444
+ utilityNavigation = input([], /* @ts-ignore */
445
+ ...(ngDevMode ? [{ debugName: "utilityNavigation" }] : /* istanbul ignore next */ []));
446
+ sectionNavigation = input([], /* @ts-ignore */
447
+ ...(ngDevMode ? [{ debugName: "sectionNavigation" }] : /* istanbul ignore next */ []));
448
+ secondaryNavigationGroups = input([], /* @ts-ignore */
449
+ ...(ngDevMode ? [{ debugName: "secondaryNavigationGroups" }] : /* istanbul ignore next */ []));
450
+ /** Category navbar with wide card panels; mobile renders expandable groups. */
451
+ flyoutNavigationGroups = input([], /* @ts-ignore */
452
+ ...(ngDevMode ? [{ debugName: "flyoutNavigationGroups" }] : /* istanbul ignore next */ []));
453
+ flyoutNavigationLabel = input('Fly-out navigation', /* @ts-ignore */
454
+ ...(ngDevMode ? [{ debugName: "flyoutNavigationLabel" }] : /* istanbul ignore next */ []));
455
+ flyoutCloseLabel = input('Close navigation panel', /* @ts-ignore */
456
+ ...(ngDevMode ? [{ debugName: "flyoutCloseLabel" }] : /* istanbul ignore next */ []));
457
+ userMenuSections = input([], /* @ts-ignore */
458
+ ...(ngDevMode ? [{ debugName: "userMenuSections" }] : /* istanbul ignore next */ []));
459
+ /** Optional image. Without it, the brand name is shown instead of a broken image. */
460
+ logo = input('', /* @ts-ignore */
592
461
  ...(ngDevMode ? [{ debugName: "logo" }] : /* istanbul ignore next */ []));
462
+ brandName = input('Workspace', /* @ts-ignore */
463
+ ...(ngDevMode ? [{ debugName: "brandName" }] : /* istanbul ignore next */ []));
593
464
  logoLink = input('/', /* @ts-ignore */
594
465
  ...(ngDevMode ? [{ debugName: "logoLink" }] : /* istanbul ignore next */ []));
595
- logoClass = input('', { ...(ngDevMode ? { debugName: "logoClass" } : /* istanbul ignore next */ {}), alias: 'logoClass' });
596
- headerClass = input('', { ...(ngDevMode ? { debugName: "headerClass" } : /* istanbul ignore next */ {}), alias: 'headerClass' });
597
- contentClass = input('', { ...(ngDevMode ? { debugName: "contentClass" } : /* istanbul ignore next */ {}), alias: 'contentClass' });
598
- contentBottomClass = input('', { ...(ngDevMode ? { debugName: "contentBottomClass" } : /* istanbul ignore next */ {}), alias: 'contentBottomClass' });
599
- /** Container class inputs */
600
- leftMenuClass = input('', { ...(ngDevMode ? { debugName: "leftMenuClass" } : /* istanbul ignore next */ {}), alias: 'leftClass' });
601
- rightMenuClass = input('', { ...(ngDevMode ? { debugName: "rightMenuClass" } : /* istanbul ignore next */ {}), alias: 'rightClass' });
602
- topMenuClass = input('', { ...(ngDevMode ? { debugName: "topMenuClass" } : /* istanbul ignore next */ {}), alias: 'topClass' });
603
- /** Link/button base class inputs */
604
- leftLinkClass = input('', { ...(ngDevMode ? { debugName: "leftLinkClass" } : /* istanbul ignore next */ {}), alias: 'leftLinkClass' });
605
- rightLinkClass = input('', { ...(ngDevMode ? { debugName: "rightLinkClass" } : /* istanbul ignore next */ {}), alias: 'rightLinkClass' });
606
- topLinkClass = input('', { ...(ngDevMode ? { debugName: "topLinkClass" } : /* istanbul ignore next */ {}), alias: 'topLinkClass' });
607
- searchEnabled = input(false, /* @ts-ignore */
608
- ...(ngDevMode ? [{ debugName: "searchEnabled" }] : /* istanbul ignore next */ []));
466
+ logoClass = input('', /* @ts-ignore */
467
+ ...(ngDevMode ? [{ debugName: "logoClass" }] : /* istanbul ignore next */ []));
468
+ /** Disable for a shell preview embedded inside another page. */
469
+ fullHeight = input(true, /* @ts-ignore */
470
+ ...(ngDevMode ? [{ debugName: "fullHeight" }] : /* istanbul ignore next */ []));
471
+ headerClass = input('', /* @ts-ignore */
472
+ ...(ngDevMode ? [{ debugName: "headerClass" }] : /* istanbul ignore next */ []));
473
+ contentClass = input('', /* @ts-ignore */
474
+ ...(ngDevMode ? [{ debugName: "contentClass" }] : /* istanbul ignore next */ []));
475
+ primaryNavigationClass = input('', /* @ts-ignore */
476
+ ...(ngDevMode ? [{ debugName: "primaryNavigationClass" }] : /* istanbul ignore next */ []));
477
+ utilityNavigationClass = input('', /* @ts-ignore */
478
+ ...(ngDevMode ? [{ debugName: "utilityNavigationClass" }] : /* istanbul ignore next */ []));
479
+ sectionNavigationClass = input('', /* @ts-ignore */
480
+ ...(ngDevMode ? [{ debugName: "sectionNavigationClass" }] : /* istanbul ignore next */ []));
481
+ secondaryNavigationClass = input('', /* @ts-ignore */
482
+ ...(ngDevMode ? [{ debugName: "secondaryNavigationClass" }] : /* istanbul ignore next */ []));
483
+ flyoutNavigationClass = input('', /* @ts-ignore */
484
+ ...(ngDevMode ? [{ debugName: "flyoutNavigationClass" }] : /* istanbul ignore next */ []));
485
+ flyoutPanelClass = input('', /* @ts-ignore */
486
+ ...(ngDevMode ? [{ debugName: "flyoutPanelClass" }] : /* istanbul ignore next */ []));
487
+ navigationItemClass = input('', /* @ts-ignore */
488
+ ...(ngDevMode ? [{ debugName: "navigationItemClass" }] : /* istanbul ignore next */ []));
609
489
  loading = input(false, /* @ts-ignore */
610
490
  ...(ngDevMode ? [{ debugName: "loading" }] : /* istanbul ignore next */ []));
611
- searchPlaceholderText = input('Select an page', /* @ts-ignore */
612
- ...(ngDevMode ? [{ debugName: "searchPlaceholderText" }] : /* istanbul ignore next */ []));
613
- searchEmptyText = input('No pages found', /* @ts-ignore */
491
+ loadingText = input('Loading content…', /* @ts-ignore */
492
+ ...(ngDevMode ? [{ debugName: "loadingText" }] : /* istanbul ignore next */ []));
493
+ skipLinkText = input('Skip to content', /* @ts-ignore */
494
+ ...(ngDevMode ? [{ debugName: "skipLinkText" }] : /* istanbul ignore next */ []));
495
+ searchEnabled = input(false, /* @ts-ignore */
496
+ ...(ngDevMode ? [{ debugName: "searchEnabled" }] : /* istanbul ignore next */ []));
497
+ searchPlaceholder = input('Search pages…', /* @ts-ignore */
498
+ ...(ngDevMode ? [{ debugName: "searchPlaceholder" }] : /* istanbul ignore next */ []));
499
+ searchEmptyText = input('No matching pages found.', /* @ts-ignore */
614
500
  ...(ngDevMode ? [{ debugName: "searchEmptyText" }] : /* istanbul ignore next */ []));
615
- searchOptionTemplate = input(/* @ts-ignore */
616
- ...(ngDevMode ? [undefined, { debugName: "searchOptionTemplate" }] : /* istanbul ignore next */ []));
617
- searchLoaderFn = input(/* @ts-ignore */
618
- ...(ngDevMode ? [undefined, { debugName: "searchLoaderFn" }] : /* istanbul ignore next */ []));
619
- searchTransformValueToSearch = input(/* @ts-ignore */
620
- ...(ngDevMode ? [undefined, { debugName: "searchTransformValueToSearch" }] : /* istanbul ignore next */ []));
621
- searchOptionChange = output();
622
- _logoClass = computed(() => hlm('h-10', this.logoClass()), /* @ts-ignore */
623
- ...(ngDevMode ? [{ debugName: "_logoClass" }] : /* istanbul ignore next */ []));
624
- _headerClass = computed(() => hlm('px-4 py-2 flex items-center justify-between bg-gray-100 border-b border-gray-300', this.headerClass()), /* @ts-ignore */
625
- ...(ngDevMode ? [{ debugName: "_headerClass" }] : /* istanbul ignore next */ []));
626
- _contentClass = computed(() => hlm('p-4 flex flex-col flex-1', this.contentClass()), /* @ts-ignore */
627
- ...(ngDevMode ? [{ debugName: "_contentClass" }] : /* istanbul ignore next */ []));
628
- _contentBottomClass = computed(() => hlm('flex-1', this.contentBottomClass()), /* @ts-ignore */
629
- ...(ngDevMode ? [{ debugName: "_contentBottomClass" }] : /* istanbul ignore next */ []));
630
- /** Computed merged classes for containers */
631
- _computedLeftClass = computed(() => hlm(commonLinkGroupClasses, this.leftMenuClass()), /* @ts-ignore */
632
- ...(ngDevMode ? [{ debugName: "_computedLeftClass" }] : /* istanbul ignore next */ []));
633
- _computedRightClass = computed(() => hlm(commonLinkGroupClasses, this.rightMenuClass()), /* @ts-ignore */
634
- ...(ngDevMode ? [{ debugName: "_computedRightClass" }] : /* istanbul ignore next */ []));
635
- _computedTopClass = computed(() => hlm('flex flex-wrap items-center gap-x-4 gap-y-1 px-4 py-2 bg-gray-50 border-b border-gray-200', this.topMenuClass()), /* @ts-ignore */
636
- ...(ngDevMode ? [{ debugName: "_computedTopClass" }] : /* istanbul ignore next */ []));
637
- _computedTopSecondaryClass = computed(() => hlm('flex flex-wrap items-center gap-x-4 gap-y-1 px-4 py-1.5 bg-gray-100/60 border-b border-gray-200', this.topMenuClass()), /* @ts-ignore */
638
- ...(ngDevMode ? [{ debugName: "_computedTopSecondaryClass" }] : /* istanbul ignore next */ []));
639
- /** Computed merged classes for link/button elements */
640
- _computedLeftLinkClass = computed(() => hlm(commonLinkClasses, this.leftLinkClass()), /* @ts-ignore */
641
- ...(ngDevMode ? [{ debugName: "_computedLeftLinkClass" }] : /* istanbul ignore next */ []));
642
- _computedRightLinkClass = computed(() => hlm(commonLinkClasses, this.rightLinkClass()), /* @ts-ignore */
643
- ...(ngDevMode ? [{ debugName: "_computedRightLinkClass" }] : /* istanbul ignore next */ []));
644
- _computedTopLinkClass = computed(() => hlm('text-secondary visited:text-secondary hover:text-primary cursor-pointer no-underline text-sm', this.topLinkClass()), /* @ts-ignore */
645
- ...(ngDevMode ? [{ debugName: "_computedTopLinkClass" }] : /* istanbul ignore next */ []));
646
- mobileMenuItemClass = commonLinkClasses;
501
+ searchErrorText = input('Search is unavailable. Please try again.', /* @ts-ignore */
502
+ ...(ngDevMode ? [{ debugName: "searchErrorText" }] : /* istanbul ignore next */ []));
503
+ searchResultTemplate = input(/* @ts-ignore */
504
+ ...(ngDevMode ? [undefined, { debugName: "searchResultTemplate" }] : /* istanbul ignore next */ []));
505
+ searchLoader = input(/* @ts-ignore */
506
+ ...(ngDevMode ? [undefined, { debugName: "searchLoader" }] : /* istanbul ignore next */ []));
507
+ searchResultLabel = input(/* @ts-ignore */
508
+ ...(ngDevMode ? [undefined, { debugName: "searchResultLabel" }] : /* istanbul ignore next */ []));
509
+ searchResultSelected = output();
647
510
  footerEnabled = input(false, /* @ts-ignore */
648
511
  ...(ngDevMode ? [{ debugName: "footerEnabled" }] : /* istanbul ignore next */ []));
649
- footerMenus = input([], /* @ts-ignore */
650
- ...(ngDevMode ? [{ debugName: "footerMenus" }] : /* istanbul ignore next */ []));
651
- footerMenuClass = input('', { ...(ngDevMode ? { debugName: "footerMenuClass" } : /* istanbul ignore next */ {}), alias: 'footerMenuClass' });
652
- footerLinkClass = input('', { ...(ngDevMode ? { debugName: "footerLinkClass" } : /* istanbul ignore next */ {}), alias: 'footerLinkClass' });
653
- footerContent = input('© 2024 My Company', /* @ts-ignore */
654
- ...(ngDevMode ? [{ debugName: "footerContent" }] : /* istanbul ignore next */ []));
655
- footerClass = input('', { ...(ngDevMode ? { debugName: "footerClass" } : /* istanbul ignore next */ {}), alias: 'footerClass' });
656
- _footerClass = computed(() => hlm('px-4 py-4 bg-gray-100 border-t border-gray-300 text-sm text-gray-600', this.footerClass()), /* @ts-ignore */
657
- ...(ngDevMode ? [{ debugName: "_footerClass" }] : /* istanbul ignore next */ []));
658
- _computedFooterMenuClass = computed(() => hlm('flex flex-wrap justify-center space-x-4', this.footerMenuClass()), /* @ts-ignore */
659
- ...(ngDevMode ? [{ debugName: "_computedFooterMenuClass" }] : /* istanbul ignore next */ []));
660
- _computedFooterLinkClass = computed(() => hlm('text-secondary hover:text-primary cursor-pointer no-underline', this.footerLinkClass()), /* @ts-ignore */
661
- ...(ngDevMode ? [{ debugName: "_computedFooterLinkClass" }] : /* istanbul ignore next */ []));
662
- /** Mobile menu state */
663
- mobileMenuOpen = false;
512
+ footerNavigation = input([], /* @ts-ignore */
513
+ ...(ngDevMode ? [{ debugName: "footerNavigation" }] : /* istanbul ignore next */ []));
514
+ footerText = input('', /* @ts-ignore */
515
+ ...(ngDevMode ? [{ debugName: "footerText" }] : /* istanbul ignore next */ []));
516
+ footerClass = input('', /* @ts-ignore */
517
+ ...(ngDevMode ? [{ debugName: "footerClass" }] : /* istanbul ignore next */ []));
518
+ logoClasses = computed(() => hlm("h-8 w-auto max-w-40 object-contain", this.logoClass()), /* @ts-ignore */
519
+ ...(ngDevMode ? [{ debugName: "logoClasses" }] : /* istanbul ignore next */ []));
520
+ headerClasses = computed(() => hlm("flex min-h-16 flex-wrap items-center justify-between gap-3 border-b border-border bg-background px-4 py-3 sm:px-6", this.headerClass()), /* @ts-ignore */
521
+ ...(ngDevMode ? [{ debugName: "headerClasses" }] : /* istanbul ignore next */ []));
522
+ contentClasses = computed(() => hlm("flex min-w-0 flex-1 flex-col p-4 outline-none sm:p-6", this.contentClass()), /* @ts-ignore */
523
+ ...(ngDevMode ? [{ debugName: "contentClasses" }] : /* istanbul ignore next */ []));
524
+ primaryNavigationClasses = computed(() => hlm("hidden md:flex flex-wrap items-center gap-1", this.primaryNavigationClass()), /* @ts-ignore */
525
+ ...(ngDevMode ? [{ debugName: "primaryNavigationClasses" }] : /* istanbul ignore next */ []));
526
+ utilityNavigationClasses = computed(() => hlm("hidden md:flex flex-wrap items-center gap-1", this.utilityNavigationClass()), /* @ts-ignore */
527
+ ...(ngDevMode ? [{ debugName: "utilityNavigationClasses" }] : /* istanbul ignore next */ []));
528
+ sectionNavigationClasses = computed(() => hlm("hidden md:flex items-center gap-1 overflow-x-auto border-b border-border bg-background px-4 py-2 sm:px-6", this.sectionNavigationClass()), /* @ts-ignore */
529
+ ...(ngDevMode ? [{ debugName: "sectionNavigationClasses" }] : /* istanbul ignore next */ []));
530
+ secondaryNavigationClasses = computed(() => hlm("hidden md:flex items-center gap-5 overflow-x-auto border-b border-border bg-foreground/3 px-4 py-2 sm:px-6", this.secondaryNavigationClass()), /* @ts-ignore */
531
+ ...(ngDevMode ? [{ debugName: "secondaryNavigationClasses" }] : /* istanbul ignore next */ []));
532
+ footerClasses = computed(() => hlm("flex flex-wrap items-center justify-between gap-x-6 gap-y-2 border-t border-border bg-background px-4 py-4 text-sm text-foreground/75 sm:px-6", this.footerClass()), /* @ts-ignore */
533
+ ...(ngDevMode ? [{ debugName: "footerClasses" }] : /* istanbul ignore next */ []));
534
+ iconButtonClasses = "inline-flex size-11 shrink-0 items-center justify-center rounded-lg border border-border bg-background text-foreground cursor-pointer hover:bg-foreground/5 focus-visible:outline-2 focus-visible:outline-offset-2 focus-visible:outline-ring";
535
+ mobileMenuOpen = signal(false, /* @ts-ignore */
536
+ ...(ngDevMode ? [{ debugName: "mobileMenuOpen" }] : /* istanbul ignore next */ []));
664
537
  isMobile = signal(false, /* @ts-ignore */
665
538
  ...(ngDevMode ? [{ debugName: "isMobile" }] : /* istanbul ignore next */ []));
666
- constructor(breakpointObserver) {
667
- this.breakpointObserver = breakpointObserver;
668
- this.breakpointObserver.observe([Breakpoints.Handset]).subscribe((result) => {
669
- this.isMobile.set(result.matches);
539
+ sidebarOpen = signal(false, /* @ts-ignore */
540
+ ...(ngDevMode ? [{ debugName: "sidebarOpen" }] : /* istanbul ignore next */ []));
541
+ sidebarContext = { close: () => this.closeSidebar() };
542
+ constructor() {
543
+ this.breakpointObserver
544
+ .observe([EG_LAYOUT_SIMPLE_MOBILE_BREAKPOINT])
545
+ .pipe(takeUntilDestroyed(this.destroyRef))
546
+ .subscribe(({ matches }) => {
547
+ this.isMobile.set(matches);
548
+ if (!matches)
549
+ this.mobileMenuOpen.set(false);
550
+ });
551
+ this.router.events.pipe(takeUntilDestroyed(this.destroyRef)).subscribe((event) => {
552
+ if (event instanceof NavigationEnd) {
553
+ if (this.mobileMenuOpen())
554
+ this.closeMobileMenu(true);
555
+ this.closeSidebar();
556
+ }
557
+ });
558
+ effect((onCleanup) => {
559
+ const sheet = this.sidebar()?.sheet();
560
+ if (!sheet)
561
+ return;
562
+ this.sidebarOpen.set(sheet.stateComputed() === 'open');
563
+ const subscriptions = [
564
+ sheet.stateChanged.subscribe((state) => this.sidebarOpen.set(state === 'open')),
565
+ sheet.closed.subscribe(() => this.sidebarOpen.set(false)),
566
+ ];
567
+ onCleanup(() => subscriptions.forEach((subscription) => subscription.unsubscribe()));
670
568
  });
671
569
  }
672
570
  toggleMobileMenu() {
673
- this.mobileMenuOpen = !this.mobileMenuOpen;
571
+ this.mobileMenuOpen.update((open) => !open);
674
572
  }
675
- onSearchOptionChange(value) {
676
- this.searchOptionChange.emit(value);
573
+ closeMobileMenu(restoreFocus = false) {
574
+ this.mobileMenuOpen.set(false);
575
+ if (restoreFocus)
576
+ this.mobileMenuTrigger()?.nativeElement.focus();
577
+ }
578
+ selectSearchResult(item) {
579
+ this.closeMobileMenu(true);
580
+ this.searchResultSelected.emit(item);
581
+ }
582
+ focusContent(event) {
583
+ event.preventDefault();
584
+ this.mainContent()?.nativeElement.focus();
677
585
  }
678
- viewchildSheetRef = viewChild(EgLayoutSimpleSidebar, /* @ts-ignore */
679
- ...(ngDevMode ? [{ debugName: "viewchildSheetRef" }] : /* istanbul ignore next */ []));
680
586
  openSidebar() {
681
- this.viewchildSheetRef()?.openSheet();
587
+ this.closeMobileMenu();
588
+ this.sidebar()?.open();
682
589
  }
683
590
  closeSidebar() {
684
- this.viewchildSheetRef()?.closeSheet();
591
+ this.sidebar()?.close();
685
592
  }
686
- static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "22.0.7", ngImport: i0, type: EgLayoutSimple, deps: [{ token: i1$2.BreakpointObserver }], target: i0.ɵɵFactoryTarget.Component });
687
- static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "22.0.7", type: EgLayoutSimple, isStandalone: true, selector: "eg-layout-simple", inputs: { sidebarEnabled: { classPropertyName: "sidebarEnabled", publicName: "sidebarEnabled", isSignal: true, isRequired: false, transformFunction: null }, sidebarTitle: { classPropertyName: "sidebarTitle", publicName: "sidebarTitle", isSignal: true, isRequired: false, transformFunction: null }, sidebarContent: { classPropertyName: "sidebarContent", publicName: "sidebarContent", isSignal: true, isRequired: false, transformFunction: null }, userMenuTrigger: { classPropertyName: "userMenuTrigger", publicName: "userMenuTrigger", isSignal: true, isRequired: false, transformFunction: null }, leftMenus: { classPropertyName: "leftMenus", publicName: "leftMenus", isSignal: true, isRequired: false, transformFunction: null }, leftMenuGroups: { classPropertyName: "leftMenuGroups", publicName: "leftMenuGroups", isSignal: true, isRequired: false, transformFunction: null }, rightMenus: { classPropertyName: "rightMenus", publicName: "rightMenus", isSignal: true, isRequired: false, transformFunction: null }, topMenus: { classPropertyName: "topMenus", publicName: "topMenus", isSignal: true, isRequired: false, transformFunction: null }, topSecondaryMenus: { classPropertyName: "topSecondaryMenus", publicName: "topSecondaryMenus", isSignal: true, isRequired: false, transformFunction: null }, userMenus: { classPropertyName: "userMenus", publicName: "userMenus", isSignal: true, isRequired: false, transformFunction: null }, logo: { classPropertyName: "logo", publicName: "logo", isSignal: true, isRequired: false, transformFunction: null }, logoLink: { classPropertyName: "logoLink", publicName: "logoLink", isSignal: true, isRequired: false, transformFunction: null }, logoClass: { classPropertyName: "logoClass", publicName: "logoClass", isSignal: true, isRequired: false, transformFunction: null }, headerClass: { classPropertyName: "headerClass", publicName: "headerClass", isSignal: true, isRequired: false, transformFunction: null }, contentClass: { classPropertyName: "contentClass", publicName: "contentClass", isSignal: true, isRequired: false, transformFunction: null }, contentBottomClass: { classPropertyName: "contentBottomClass", publicName: "contentBottomClass", isSignal: true, isRequired: false, transformFunction: null }, leftMenuClass: { classPropertyName: "leftMenuClass", publicName: "leftClass", isSignal: true, isRequired: false, transformFunction: null }, rightMenuClass: { classPropertyName: "rightMenuClass", publicName: "rightClass", isSignal: true, isRequired: false, transformFunction: null }, topMenuClass: { classPropertyName: "topMenuClass", publicName: "topClass", isSignal: true, isRequired: false, transformFunction: null }, leftLinkClass: { classPropertyName: "leftLinkClass", publicName: "leftLinkClass", isSignal: true, isRequired: false, transformFunction: null }, rightLinkClass: { classPropertyName: "rightLinkClass", publicName: "rightLinkClass", isSignal: true, isRequired: false, transformFunction: null }, topLinkClass: { classPropertyName: "topLinkClass", publicName: "topLinkClass", isSignal: true, isRequired: false, transformFunction: null }, searchEnabled: { classPropertyName: "searchEnabled", publicName: "searchEnabled", isSignal: true, isRequired: false, transformFunction: null }, loading: { classPropertyName: "loading", publicName: "loading", isSignal: true, isRequired: false, transformFunction: null }, searchPlaceholderText: { classPropertyName: "searchPlaceholderText", publicName: "searchPlaceholderText", isSignal: true, isRequired: false, transformFunction: null }, searchEmptyText: { classPropertyName: "searchEmptyText", publicName: "searchEmptyText", isSignal: true, isRequired: false, transformFunction: null }, searchOptionTemplate: { classPropertyName: "searchOptionTemplate", publicName: "searchOptionTemplate", isSignal: true, isRequired: false, transformFunction: null }, searchLoaderFn: { classPropertyName: "searchLoaderFn", publicName: "searchLoaderFn", isSignal: true, isRequired: false, transformFunction: null }, searchTransformValueToSearch: { classPropertyName: "searchTransformValueToSearch", publicName: "searchTransformValueToSearch", isSignal: true, isRequired: false, transformFunction: null }, footerEnabled: { classPropertyName: "footerEnabled", publicName: "footerEnabled", isSignal: true, isRequired: false, transformFunction: null }, footerMenus: { classPropertyName: "footerMenus", publicName: "footerMenus", isSignal: true, isRequired: false, transformFunction: null }, footerMenuClass: { classPropertyName: "footerMenuClass", publicName: "footerMenuClass", isSignal: true, isRequired: false, transformFunction: null }, footerLinkClass: { classPropertyName: "footerLinkClass", publicName: "footerLinkClass", isSignal: true, isRequired: false, transformFunction: null }, footerContent: { classPropertyName: "footerContent", publicName: "footerContent", isSignal: true, isRequired: false, transformFunction: null }, footerClass: { classPropertyName: "footerClass", publicName: "footerClass", isSignal: true, isRequired: false, transformFunction: null } }, outputs: { searchOptionChange: "searchOptionChange" }, providers: [
688
- provideIcons({
689
- lucideMenu,
690
- }),
691
- ], viewQueries: [{ propertyName: "viewchildSheetRef", first: true, predicate: EgLayoutSimpleSidebar, descendants: true, isSignal: true }], ngImport: i0, template: "<ng-template #menuIconTemplate>\n <ng-icon [svg]=\"menuIcon\" size=\"20px\" class=\"[&_svg]:w-[inherit]! [&_svg]:h-[inherit]!\" />\n</ng-template>\n\n<eg-layout-simple-sidebar\n [title]=\"sidebarTitle()\"\n [content]=\"sidebarContent()\"\n [contentContext]=\"{ close: closeSidebar.bind(this) }\"\n/>\n\n<div class=\"flex flex-col min-h-screen\">\n <!-- Header -->\n <header [class]=\"_headerClass()\">\n <div class=\"flex items-center space-x-4\">\n @if (sidebarEnabled()) {\n <button\n hlmButton\n variant=\"secondary\"\n appearance=\"outline\"\n size=\"icon\"\n [icon]=\"menuIconTemplate\"\n iconPosition=\"left\"\n class=\"bg-transparent! border-gray-400! hover:border-gray-500!\"\n (click)=\"openSidebar()\"\n ></button>\n }\n\n <div class=\"logo\">\n <a [routerLink]=\"logoLink()\">\n <img [src]=\"logo()\" alt=\"Logo\" [class]=\"_logoClass()\" />\n </a>\n </div>\n <!-- Left menus (desktop) -->\n <nav [class]=\"_computedLeftClass()\">\n @for (item of leftMenus(); track item.label) { @if (item.link) {\n <a [routerLink]=\"item.link\" [class]=\"hlm(_computedLeftLinkClass(), item.class || '')\"> {{ item.label }} </a>\n } @else {\n <button type=\"button\" (click)=\"item.action?.()\" [class]=\"hlm(_computedLeftLinkClass(), item.class || '')\">\n {{ item.label }}\n </button>\n } } @for (group of leftMenuGroups(); track $index) {\n <div class=\"relative group\">\n <button\n type=\"button\"\n class=\"text-left text-secondary hover:text-primary cursor-pointer no-underline py-1 flex items-center gap-1\"\n >\n {{ group.label ?? 'Menu' }}\n <svg\n xmlns=\"http://www.w3.org/2000/svg\"\n class=\"h-3 w-3\"\n viewBox=\"0 0 24 24\"\n fill=\"none\"\n stroke=\"currentColor\"\n >\n <path stroke-linecap=\"round\" stroke-linejoin=\"round\" stroke-width=\"2\" d=\"M19 9l-7 7-7-7\" />\n </svg>\n </button>\n <div\n class=\"absolute left-0 top-full mt-1 hidden group-hover:flex flex-col min-w-[12rem] bg-popover text-popover-foreground border border-gray-200 rounded-md shadow-md py-1 z-50\"\n >\n @if (group.label) {\n <div class=\"px-3 py-1 text-xs font-semibold text-muted-foreground\">{{ group.label }}</div>\n } @for (item of group.items; track item.label) { @if (item.link) {\n <a\n [routerLink]=\"item.link\"\n [class]=\"hlm('px-3 py-1.5 text-sm no-underline hover:bg-secondary cursor-pointer', item.class || '')\"\n >\n {{ item.label }}\n </a>\n } @else {\n <button\n type=\"button\"\n (click)=\"item.action?.()\"\n [class]=\"hlm('px-3 py-1.5 text-sm text-left hover:bg-secondary cursor-pointer bg-transparent border-0 w-full', item.class || '')\"\n >\n {{ item.label }}\n </button>\n } }\n </div>\n </div>\n }\n </nav>\n </div>\n\n <!-- Right menus (desktop) -->\n <nav [class]=\"_computedRightClass()\">\n @if (searchEnabled()) {\n <eg-generic-autocomplete\n [loaderFn]=\"searchLoaderFn()\"\n [transformValueToSearch]=\"searchTransformValueToSearch()\"\n [placeholderText]=\"searchPlaceholderText()\"\n [emptyText]=\"searchEmptyText()\"\n (optionChange)=\"onSearchOptionChange($event)\"\n ></eg-generic-autocomplete>\n } @for (item of rightMenus(); track item.label) { @if (item.link) {\n <a [routerLink]=\"item.link\" [class]=\"hlm(_computedRightLinkClass(), item.class || '')\"> {{ item.label }} </a>\n } @else {\n <button type=\"button\" (click)=\"item.action?.()\" [class]=\"hlm(_computedRightLinkClass(), item.class || '')\">\n {{ item.label }}\n </button>\n } } @let uMenus = userMenus(); @if (uMenus && uMenus.length > 0) {\n <eg-layout-simple-user-menu [menus]=\"uMenus\" [menuTrigger]=\"userMenuTrigger()\" />\n }\n </nav>\n\n <!-- Mobile menu button -->\n <button\n (click)=\"toggleMobileMenu()\"\n class=\"md:hidden p-2 text-gray-700 hover:text-primary focus:outline-none cursor-pointer\"\n >\n <svg\n xmlns=\"http://www.w3.org/2000/svg\"\n class=\"h-6 w-6\"\n fill=\"none\"\n viewBox=\"0 0 24 24\"\n stroke=\"currentColor\"\n >\n <path stroke-linecap=\"round\" stroke-linejoin=\"round\" stroke-width=\"2\" d=\"M4 6h16M4 12h16M4 18h16\" />\n </svg>\n </button>\n </header>\n\n @let _topMenus = leftMenus().concat(rightMenus()); @let _userMenus = userMenus(); @let _leftMenuGroups =\n leftMenuGroups(); @let _topMenuItems = topMenus(); @let _topSecondaryGroups = topSecondaryMenus();\n\n <!-- Top menus (desktop) -->\n @if (_topMenuItems.length > 0) {\n <nav [class]=\"_computedTopClass()\">\n @for (item of _topMenuItems; track item.label) { @if (item.link) {\n <a [routerLink]=\"item.link\" [class]=\"hlm(_computedTopLinkClass(), item.class || '')\"> {{ item.label }} </a>\n } @else {\n <span [class]=\"hlm(_computedTopLinkClass(), item.class || '')\">{{ item.label }}</span>\n } }\n </nav>\n }\n\n <!-- Top secondary menus (desktop) \u2014 second row showing items grouped by parent label -->\n @if (_topSecondaryGroups.length > 0) {\n <nav [class]=\"_computedTopSecondaryClass()\">\n @for (group of _topSecondaryGroups; track group.label) {\n <span class=\"flex flex-wrap items-center gap-x-3\">\n @if (group.label) {\n <span class=\"text-xs font-semibold uppercase text-muted-foreground\">{{ group.label }}</span>\n } @for (item of group.items; track item.label) { @if (item.link) {\n <a\n [routerLink]=\"item.link\"\n [class]=\"hlm(_computedTopLinkClass(), 'text-xs hover:underline', item.class || '')\"\n >\n {{ item.label }}\n </a>\n } @else {\n <button\n type=\"button\"\n (click)=\"item.action?.()\"\n [class]=\"hlm(_computedTopLinkClass(), 'text-xs hover:underline', item.class || '')\"\n >\n {{ item.label }}\n </button>\n } }\n </span>\n }\n </nav>\n }\n\n <!-- Mobile menu -->\n @if (isMobile() && mobileMenuOpen) {\n <div class=\"w-full border-none\">\n @if (_topMenuItems.length > 0) {\n <eg-layout-simple-mobile-menu-group [items]=\"_topMenuItems\" (itemClick)=\"toggleMobileMenu()\" />\n }\n\n @for (group of _topSecondaryGroups; track group.label) { @if (group.items && group.items.length > 0) {\n <eg-layout-simple-mobile-menu-group\n [items]=\"group.items\"\n [label]=\"group.label\"\n (itemClick)=\"toggleMobileMenu()\"\n ></eg-layout-simple-mobile-menu-group>\n } }\n\n <eg-layout-simple-mobile-menu-group [items]=\"_topMenus\" (itemClick)=\"toggleMobileMenu()\" />\n\n @for (group of _leftMenuGroups; track $index) { @if (group.items && group.items.length > 0) {\n <eg-layout-simple-mobile-menu-group\n [items]=\"group.items\"\n [label]=\"group.label\"\n (itemClick)=\"toggleMobileMenu()\"\n ></eg-layout-simple-mobile-menu-group>\n } } @if ((_topMenus.length > 0 || _leftMenuGroups.length > 0) && _userMenus.length > 0) {\n <hr class=\"border-gray-300 my-2\" />\n } @for (section of userMenus(); track section.label) {\n <eg-layout-simple-mobile-menu-group\n [items]=\"section.items\"\n [label]=\"section.label\"\n (itemClick)=\"toggleMobileMenu()\"\n ></eg-layout-simple-mobile-menu-group>\n\n @if (section.separator) {\n <hr class=\"border-gray-300 my-2\" />\n } }\n </div>\n }\n\n <!-- Main content -->\n <main [class]=\"_contentClass()\">\n @if (!loading()) {\n <div class=\"flex items-center justify-center h-full\">\n <ng-content />\n </div>\n }\n <div [class]=\"_contentBottomClass()\"></div>\n </main>\n\n @if (footerEnabled()) {\n <footer [class]=\"_footerClass()\">\n <nav [class]=\"_computedFooterMenuClass()\">\n @for (item of footerMenus(); track item.label) { @if (item.link) {\n <a [routerLink]=\"item.link\" [class]=\"hlm(_computedFooterLinkClass(), item.class || '')\"> {{ item.label }} </a>\n } @else {\n <button type=\"button\" (click)=\"item.action?.()\" [class]=\"hlm(_computedFooterLinkClass(), item.class || '')\">\n {{ item.label }}\n </button>\n } }\n </nav>\n\n <div class=\"mt-2 text-center\">{{ footerContent() }}</div>\n </footer>\n }\n</div>\n", dependencies: [{ kind: "directive", type: RouterLink, selector: "[routerLink]", inputs: ["target", "queryParams", "fragment", "queryParamsHandling", "state", "info", "relativeTo", "preserveFragment", "skipLocationChange", "replaceUrl", "browserUrl", "routerLink"] }, { kind: "component", type: EgLayoutSimpleUserMenu, selector: "eg-layout-simple-user-menu", inputs: ["menus", "menuTrigger"] }, { kind: "component", type: EgLayoutSimpleSidebar, selector: "eg-layout-simple-sidebar", inputs: ["side", "title", "content", "contentContext"] }, { kind: "component", type: EgLayoutSimpleMobileMenuGroup, selector: "eg-layout-simple-mobile-menu-group", inputs: ["label", "items"], outputs: ["itemClick"] }, { kind: "component", type: EgGenericAutocomplete, selector: "eg-generic-autocomplete", inputs: ["placeholderText", "emptyText", "loaderFn", "transformValueToSearch"], outputs: ["optionChange"] }, { kind: "component", type: HlmButton, selector: "button[hlmButton], a[hlmButton]", inputs: ["variant", "size", "appearance", "loading", "icon", "iconPosition", "class", "spinnerUserClass", "disabled", "type"] }, { kind: "component", type: NgIcon, selector: "ng-icon", inputs: ["name", "svg", "size", "strokeWidth", "color"] }] });
593
+ static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "22.1.3", ngImport: i0, type: EgLayoutSimple, deps: [], target: i0.ɵɵFactoryTarget.Component });
594
+ static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "22.1.3", type: EgLayoutSimple, isStandalone: true, selector: "eg-layout-simple", inputs: { sidebarEnabled: { classPropertyName: "sidebarEnabled", publicName: "sidebarEnabled", isSignal: true, isRequired: false, transformFunction: null }, sidebarTitle: { classPropertyName: "sidebarTitle", publicName: "sidebarTitle", isSignal: true, isRequired: false, transformFunction: null }, sidebarContent: { classPropertyName: "sidebarContent", publicName: "sidebarContent", isSignal: true, isRequired: false, transformFunction: null }, sidebarToggleLabel: { classPropertyName: "sidebarToggleLabel", publicName: "sidebarToggleLabel", isSignal: true, isRequired: false, transformFunction: null }, mobileMenuLabel: { classPropertyName: "mobileMenuLabel", publicName: "mobileMenuLabel", isSignal: true, isRequired: false, transformFunction: null }, mobileMenuCloseLabel: { classPropertyName: "mobileMenuCloseLabel", publicName: "mobileMenuCloseLabel", isSignal: true, isRequired: false, transformFunction: null }, userMenuTrigger: { classPropertyName: "userMenuTrigger", publicName: "userMenuTrigger", isSignal: true, isRequired: false, transformFunction: null }, userMenuLabel: { classPropertyName: "userMenuLabel", publicName: "userMenuLabel", isSignal: true, isRequired: false, transformFunction: null }, primaryNavigation: { classPropertyName: "primaryNavigation", publicName: "primaryNavigation", isSignal: true, isRequired: false, transformFunction: null }, navigationGroups: { classPropertyName: "navigationGroups", publicName: "navigationGroups", isSignal: true, isRequired: false, transformFunction: null }, utilityNavigation: { classPropertyName: "utilityNavigation", publicName: "utilityNavigation", isSignal: true, isRequired: false, transformFunction: null }, sectionNavigation: { classPropertyName: "sectionNavigation", publicName: "sectionNavigation", isSignal: true, isRequired: false, transformFunction: null }, secondaryNavigationGroups: { classPropertyName: "secondaryNavigationGroups", publicName: "secondaryNavigationGroups", isSignal: true, isRequired: false, transformFunction: null }, flyoutNavigationGroups: { classPropertyName: "flyoutNavigationGroups", publicName: "flyoutNavigationGroups", isSignal: true, isRequired: false, transformFunction: null }, flyoutNavigationLabel: { classPropertyName: "flyoutNavigationLabel", publicName: "flyoutNavigationLabel", isSignal: true, isRequired: false, transformFunction: null }, flyoutCloseLabel: { classPropertyName: "flyoutCloseLabel", publicName: "flyoutCloseLabel", isSignal: true, isRequired: false, transformFunction: null }, userMenuSections: { classPropertyName: "userMenuSections", publicName: "userMenuSections", isSignal: true, isRequired: false, transformFunction: null }, logo: { classPropertyName: "logo", publicName: "logo", isSignal: true, isRequired: false, transformFunction: null }, brandName: { classPropertyName: "brandName", publicName: "brandName", isSignal: true, isRequired: false, transformFunction: null }, logoLink: { classPropertyName: "logoLink", publicName: "logoLink", isSignal: true, isRequired: false, transformFunction: null }, logoClass: { classPropertyName: "logoClass", publicName: "logoClass", isSignal: true, isRequired: false, transformFunction: null }, fullHeight: { classPropertyName: "fullHeight", publicName: "fullHeight", isSignal: true, isRequired: false, transformFunction: null }, headerClass: { classPropertyName: "headerClass", publicName: "headerClass", isSignal: true, isRequired: false, transformFunction: null }, contentClass: { classPropertyName: "contentClass", publicName: "contentClass", isSignal: true, isRequired: false, transformFunction: null }, primaryNavigationClass: { classPropertyName: "primaryNavigationClass", publicName: "primaryNavigationClass", isSignal: true, isRequired: false, transformFunction: null }, utilityNavigationClass: { classPropertyName: "utilityNavigationClass", publicName: "utilityNavigationClass", isSignal: true, isRequired: false, transformFunction: null }, sectionNavigationClass: { classPropertyName: "sectionNavigationClass", publicName: "sectionNavigationClass", isSignal: true, isRequired: false, transformFunction: null }, secondaryNavigationClass: { classPropertyName: "secondaryNavigationClass", publicName: "secondaryNavigationClass", isSignal: true, isRequired: false, transformFunction: null }, flyoutNavigationClass: { classPropertyName: "flyoutNavigationClass", publicName: "flyoutNavigationClass", isSignal: true, isRequired: false, transformFunction: null }, flyoutPanelClass: { classPropertyName: "flyoutPanelClass", publicName: "flyoutPanelClass", isSignal: true, isRequired: false, transformFunction: null }, navigationItemClass: { classPropertyName: "navigationItemClass", publicName: "navigationItemClass", isSignal: true, isRequired: false, transformFunction: null }, loading: { classPropertyName: "loading", publicName: "loading", isSignal: true, isRequired: false, transformFunction: null }, loadingText: { classPropertyName: "loadingText", publicName: "loadingText", isSignal: true, isRequired: false, transformFunction: null }, skipLinkText: { classPropertyName: "skipLinkText", publicName: "skipLinkText", isSignal: true, isRequired: false, transformFunction: null }, searchEnabled: { classPropertyName: "searchEnabled", publicName: "searchEnabled", isSignal: true, isRequired: false, transformFunction: null }, searchPlaceholder: { classPropertyName: "searchPlaceholder", publicName: "searchPlaceholder", isSignal: true, isRequired: false, transformFunction: null }, searchEmptyText: { classPropertyName: "searchEmptyText", publicName: "searchEmptyText", isSignal: true, isRequired: false, transformFunction: null }, searchErrorText: { classPropertyName: "searchErrorText", publicName: "searchErrorText", isSignal: true, isRequired: false, transformFunction: null }, searchResultTemplate: { classPropertyName: "searchResultTemplate", publicName: "searchResultTemplate", isSignal: true, isRequired: false, transformFunction: null }, searchLoader: { classPropertyName: "searchLoader", publicName: "searchLoader", isSignal: true, isRequired: false, transformFunction: null }, searchResultLabel: { classPropertyName: "searchResultLabel", publicName: "searchResultLabel", isSignal: true, isRequired: false, transformFunction: null }, footerEnabled: { classPropertyName: "footerEnabled", publicName: "footerEnabled", isSignal: true, isRequired: false, transformFunction: null }, footerNavigation: { classPropertyName: "footerNavigation", publicName: "footerNavigation", isSignal: true, isRequired: false, transformFunction: null }, footerText: { classPropertyName: "footerText", publicName: "footerText", isSignal: true, isRequired: false, transformFunction: null }, footerClass: { classPropertyName: "footerClass", publicName: "footerClass", isSignal: true, isRequired: false, transformFunction: null } }, outputs: { searchResultSelected: "searchResultSelected" }, host: { classAttribute: "block min-w-0" }, viewQueries: [{ propertyName: "mobileMenuTrigger", first: true, predicate: ["mobileMenuTrigger"], descendants: true, isSignal: true }, { propertyName: "mainContent", first: true, predicate: ["mainContent"], descendants: true, isSignal: true }, { propertyName: "sidebar", first: true, predicate: EgLayoutSimpleSidebar, descendants: true, isSignal: true }], ngImport: i0, template: "@if (sidebarEnabled()) {\n<eg-layout-simple-sidebar\n [panelId]=\"sidebarId\"\n [title]=\"sidebarTitle()\"\n [content]=\"sidebarContent()\"\n [contentContext]=\"sidebarContext\"\n/>\n}\n\n<div\n [class]=\"hlm('tw:relative tw:isolate tw:flex tw:min-w-0 tw:flex-col tw:bg-background tw:text-foreground', fullHeight() && 'tw:min-h-dvh')\"\n>\n <a\n [href]=\"'#' + mainId\"\n (click)=\"focusContent($event)\"\n class=\"sr-only focus:not-sr-only focus:absolute focus:left-4 focus:top-2 focus:z-50 focus:rounded-lg focus:bg-background focus:px-4 focus:py-3 focus:text-foreground focus:outline-2 focus:outline-ring\"\n >{{ skipLinkText() }}</a\n >\n\n <header [class]=\"headerClasses()\">\n <div class=\"flex min-w-0 flex-1 items-center gap-3 md:flex-none md:flex-wrap\">\n @if (sidebarEnabled()) {\n <button\n type=\"button\"\n [class]=\"iconButtonClasses\"\n [attr.aria-label]=\"sidebarToggleLabel()\"\n [attr.aria-expanded]=\"sidebarOpen()\"\n [attr.aria-controls]=\"sidebarId\"\n (click)=\"openSidebar()\"\n >\n <ng-icon [svg]=\"sidebarIcon\" size=\"20px\" aria-hidden=\"true\" />\n </button>\n }\n <a\n [routerLink]=\"logoLink()\"\n [attr.aria-label]=\"brandName() + ' home'\"\n class=\"flex min-h-11 min-w-0 items-center gap-2.5 rounded-lg pr-2 text-foreground no-underline focus-visible:outline-2 focus-visible:outline-offset-2 focus-visible:outline-ring\"\n >\n @if (logo()) { <img [src]=\"logo()\" alt=\"\" [class]=\"logoClasses()\" /> }\n <span class=\"truncate text-base font-semibold tracking-tight\">{{ brandName() }}</span>\n </a>\n <nav aria-label=\"Primary navigation\" [class]=\"primaryNavigationClasses()\">\n @for (item of primaryNavigation(); track $index) {\n <eg-layout-navigation-item [item]=\"item\" [itemClass]=\"navigationItemClass()\" />\n } @for (group of navigationGroups(); track $index) {\n <button\n type=\"button\"\n [hlmDropdownMenuTrigger]=\"groupMenu\"\n class=\"flex min-h-11 items-center gap-2 rounded-lg px-3 text-sm font-medium cursor-pointer hover:bg-foreground/5 focus-visible:outline-2 focus-visible:outline-ring\"\n >\n {{ group.label || 'More' }} <ng-icon [svg]=\"chevronIcon\" size=\"14px\" aria-hidden=\"true\" />\n </button>\n <ng-template #groupMenu>\n <div hlmDropdownMenu class=\"w-60\">\n @for (item of group.items; track $index) { @if (item.link && !item.disabled) {\n <a\n hlmDropdownMenuItem\n [routerLink]=\"item.link\"\n routerLinkActive=\"tw:bg-foreground/10 tw:font-semibold\"\n [routerLinkActiveOptions]=\"navigationMatchOptions(item)\"\n ariaCurrentWhenActive=\"page\"\n [class]=\"hlm('tw:min-h-11 tw:gap-2 tw:no-underline', item.class)\"\n >\n @if (item.icon) { <ng-icon [svg]=\"item.icon\" size=\"1rem\" aria-hidden=\"true\" /> } {{ item.label }}\n </a>\n } @else {\n <button\n type=\"button\"\n hlmDropdownMenuItem\n [disabled]=\"item.disabled || !item.action\"\n [class]=\"hlm('tw:min-h-11 tw:gap-2', item.class)\"\n (click)=\"item.action?.()\"\n >\n @if (item.icon) { <ng-icon [svg]=\"item.icon\" size=\"1rem\" aria-hidden=\"true\" /> } {{ item.label }}\n </button>\n } }\n </div>\n </ng-template>\n }\n </nav>\n </div>\n\n <div class=\"hidden md:flex flex-wrap items-center gap-3\">\n @if (searchEnabled() && !isMobile()) { <ng-container [ngTemplateOutlet]=\"searchTemplate\" /> } @if\n (utilityNavigation().length) {\n <nav aria-label=\"Utility navigation\" [class]=\"utilityNavigationClasses()\">\n @for (item of utilityNavigation(); track $index) {\n <eg-layout-navigation-item [item]=\"item\" [itemClass]=\"navigationItemClass()\" />\n }\n </nav>\n } @if (userMenuSections().length) {\n <eg-layout-simple-user-menu\n [sections]=\"userMenuSections()\"\n [triggerTemplate]=\"userMenuTrigger()\"\n [triggerLabel]=\"userMenuLabel()\"\n />\n }\n </div>\n\n <button\n #mobileMenuTrigger\n type=\"button\"\n (click)=\"toggleMobileMenu()\"\n [class]=\"hlm(iconButtonClasses, 'tw:md:hidden')\"\n [attr.aria-label]=\"mobileMenuOpen() ? mobileMenuCloseLabel() : mobileMenuLabel()\"\n [attr.aria-expanded]=\"mobileMenuOpen()\"\n [attr.aria-controls]=\"mobileMenuId\"\n >\n <ng-icon [svg]=\"mobileMenuOpen() ? closeIcon : menuIcon\" size=\"20px\" aria-hidden=\"true\" />\n </button>\n </header>\n\n @if (sectionNavigation().length) {\n <nav aria-label=\"Section navigation\" [class]=\"sectionNavigationClasses()\">\n @for (item of sectionNavigation(); track $index) {\n <eg-layout-navigation-item [item]=\"item\" [itemClass]=\"navigationItemClass()\" />\n }\n </nav>\n } @if (flyoutNavigationGroups().length && !isMobile()) {\n <eg-layout-flyout-navbar\n class=\"hidden md:block\"\n [groups]=\"flyoutNavigationGroups()\"\n [label]=\"flyoutNavigationLabel()\"\n [closeLabel]=\"flyoutCloseLabel()\"\n [navbarClass]=\"flyoutNavigationClass()\"\n [panelClass]=\"flyoutPanelClass()\"\n [itemClass]=\"navigationItemClass()\"\n />\n } @if (secondaryNavigationGroups().length) {\n <nav aria-label=\"Secondary navigation\" [class]=\"secondaryNavigationClasses()\" tabindex=\"0\">\n @for (group of secondaryNavigationGroups(); track $index; let first = $first) {\n <div\n [class]=\"hlm('tw:flex tw:shrink-0 tw:items-center tw:gap-1', !first && 'tw:border-l tw:border-border tw:pl-5')\"\n >\n @if (group.label) {\n <span class=\"mr-2 text-xs font-semibold text-foreground/75 whitespace-nowrap\"\n >{{ group.label }}</span\n >\n } @for (item of group.items; track $index) {\n <eg-layout-navigation-item\n [item]=\"item\"\n [itemClass]=\"hlm('tw:rounded-full tw:whitespace-nowrap', navigationItemClass())\"\n />\n }\n </div>\n }\n </nav>\n } @if (isMobile() && mobileMenuOpen()) {\n <nav\n [id]=\"mobileMenuId\"\n aria-label=\"Mobile navigation\"\n (keydown.escape)=\"closeMobileMenu(true); $event.stopPropagation()\"\n class=\"md:hidden max-h-[70dvh] overflow-y-auto overscroll-contain space-y-4 border-b border-border bg-background p-4\"\n >\n @if (searchEnabled()) { <ng-container [ngTemplateOutlet]=\"searchTemplate\" /> }\n <eg-layout-simple-mobile-menu-group [items]=\"primaryNavigation()\" (itemSelected)=\"closeMobileMenu(true)\" />\n @for (group of navigationGroups(); track $index) {\n <eg-layout-simple-mobile-menu-group\n [items]=\"group.items\"\n [label]=\"group.label\"\n (itemSelected)=\"closeMobileMenu(true)\"\n />\n }\n <eg-layout-simple-mobile-menu-group [items]=\"sectionNavigation()\" (itemSelected)=\"closeMobileMenu(true)\" />\n @for (group of flyoutNavigationGroups(); track $index) {\n <details class=\"group/flyout rounded-xl border border-border bg-foreground/3\">\n <summary\n class=\"flex min-h-11 list-none items-center justify-between gap-2 rounded-xl px-3 py-3 text-sm font-semibold cursor-pointer focus-visible:outline-2 focus-visible:outline-ring [&::-webkit-details-marker]:hidden\"\n >\n <span class=\"flex items-center gap-2\">\n @if (group.icon) { <ng-icon [svg]=\"group.icon\" size=\"1rem\" aria-hidden=\"true\" /> } {{ group.label }}\n </span>\n <ng-icon\n [svg]=\"chevronIcon\"\n size=\"14px\"\n aria-hidden=\"true\"\n class=\"shrink-0 group-open/flyout:rotate-180\"\n />\n </summary>\n <div class=\"space-y-2 border-t border-border p-2\">\n @if (group.description) {\n <p class=\"px-3 py-2 text-sm text-foreground/75\">{{ group.description }}</p>\n } @for (item of group.items; track $index) {\n <eg-layout-navigation-item\n [item]=\"item\"\n appearance=\"card\"\n [itemClass]=\"navigationItemClass()\"\n (selected)=\"closeMobileMenu(true)\"\n />\n }\n </div>\n </details>\n } @for (group of secondaryNavigationGroups(); track $index) {\n <eg-layout-simple-mobile-menu-group\n [items]=\"group.items\"\n [label]=\"group.label\"\n (itemSelected)=\"closeMobileMenu(true)\"\n />\n }\n <eg-layout-simple-mobile-menu-group [items]=\"utilityNavigation()\" (itemSelected)=\"closeMobileMenu(true)\" />\n @if (userMenuSections().length) {\n <div class=\"space-y-4 border-t border-border pt-4\">\n @for (section of userMenuSections(); track $index) {\n <eg-layout-simple-mobile-menu-group\n [items]=\"section.items\"\n [label]=\"section.label\"\n (itemSelected)=\"closeMobileMenu(true)\"\n />\n }\n </div>\n }\n </nav>\n }\n\n <main #mainContent [id]=\"mainId\" tabindex=\"-1\" [attr.aria-busy]=\"loading()\" [class]=\"contentClasses()\">\n @if (loading()) {\n <div\n role=\"status\"\n class=\"flex min-h-48 flex-1 items-center justify-center gap-3 text-sm text-foreground/75\"\n >\n <span\n aria-hidden=\"true\"\n class=\"size-5 rounded-full border-2 border-border border-t-foreground motion-safe:animate-spin\"\n ></span>\n {{ loadingText() }}\n </div>\n }\n <div\n [hidden]=\"loading()\"\n [style.display]=\"loading() ? 'none' : null\"\n class=\"w-full min-w-0 eg-layout-simple-main-content\"\n >\n <ng-content />\n </div>\n </main>\n\n @if (footerEnabled()) {\n <footer [class]=\"footerClasses()\">\n @if (footerText()) {\n <p>{{ footerText() }}</p>\n } @if (footerNavigation().length) {\n <nav aria-label=\"Footer navigation\" class=\"flex flex-wrap items-center gap-1\">\n @for (item of footerNavigation(); track $index) { <eg-layout-navigation-item [item]=\"item\" /> }\n </nav>\n }\n </footer>\n }\n</div>\n\n<ng-template #searchTemplate>\n <eg-layout-search\n [loader]=\"searchLoader()\"\n [resultLabel]=\"searchResultLabel()\"\n [placeholder]=\"searchPlaceholder()\"\n [emptyText]=\"searchEmptyText()\"\n [errorText]=\"searchErrorText()\"\n [resultTemplate]=\"searchResultTemplate()\"\n (resultSelected)=\"selectSearchResult($event)\"\n />\n</ng-template>\n", dependencies: [{ kind: "directive", type: RouterLink, selector: "[routerLink]", inputs: ["target", "queryParams", "fragment", "queryParamsHandling", "state", "info", "relativeTo", "preserveFragment", "skipLocationChange", "replaceUrl", "browserUrl", "routerLink"] }, { kind: "directive", type: RouterLinkActive, selector: "[routerLinkActive]", inputs: ["routerLinkActiveOptions", "ariaCurrentWhenActive", "routerLinkActive"], outputs: ["isActiveChange"], exportAs: ["routerLinkActive"] }, { kind: "directive", type: NgTemplateOutlet, selector: "[ngTemplateOutlet]", inputs: ["ngTemplateOutletContext", "ngTemplateOutlet", "ngTemplateOutletInjector"] }, { kind: "component", type: NgIcon, selector: "ng-icon", inputs: ["name", "svg", "size", "strokeWidth", "color"] }, { kind: "component", type: EgLayoutSimpleUserMenu, selector: "eg-layout-simple-user-menu", inputs: ["sections", "triggerTemplate", "triggerLabel"] }, { kind: "component", type: EgLayoutSimpleSidebar, selector: "eg-layout-simple-sidebar", inputs: ["panelId", "title", "content", "contentContext"] }, { kind: "component", type: EgLayoutSimpleMobileMenuGroup, selector: "eg-layout-simple-mobile-menu-group", inputs: ["label", "items"], outputs: ["itemSelected"] }, { kind: "component", type: EgLayoutSearch, selector: "eg-layout-search", inputs: ["placeholder", "emptyText", "errorText", "loadingText", "retryText", "loader", "resultLabel", "resultTemplate"], outputs: ["resultSelected"] }, { kind: "component", type: EgLayoutNavigationItem, selector: "eg-layout-navigation-item", inputs: ["item", "itemClass", "appearance"], outputs: ["selected"] }, { kind: "component", type: EgLayoutFlyoutNavbar, selector: "eg-layout-flyout-navbar", inputs: ["groups", "label", "closeLabel", "navbarClass", "panelClass", "itemClass"] }, { kind: "directive", type: HlmDropdownMenu, selector: "[hlmDropdownMenu],hlm-dropdown-menu", inputs: ["sideOffset"] }, { kind: "directive", type: HlmDropdownMenuItem, selector: "[hlmDropdownMenuItem],hlm-dropdown-menu-item", inputs: ["disabled", "variant", "inset"] }, { kind: "directive", type: HlmDropdownMenuTrigger, selector: "[hlmDropdownMenuTrigger]", inputs: ["align", "side"] }], changeDetection: i0.ChangeDetectionStrategy.OnPush });
692
595
  }
693
- i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.0.7", ngImport: i0, type: EgLayoutSimple, decorators: [{
596
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.1.3", ngImport: i0, type: EgLayoutSimple, decorators: [{
694
597
  type: Component,
695
- args: [{ selector: 'eg-layout-simple', standalone: true, imports: [
598
+ args: [{ selector: 'eg-layout-simple', imports: [
696
599
  RouterLink,
600
+ RouterLinkActive,
601
+ NgTemplateOutlet,
602
+ NgIcon,
697
603
  EgLayoutSimpleUserMenu,
698
604
  EgLayoutSimpleSidebar,
699
605
  EgLayoutSimpleMobileMenuGroup,
700
- EgGenericAutocomplete,
701
- HlmButton,
702
- NgIcon,
703
- ], providers: [
704
- provideIcons({
705
- lucideMenu,
706
- }),
707
- ], template: "<ng-template #menuIconTemplate>\n <ng-icon [svg]=\"menuIcon\" size=\"20px\" class=\"[&_svg]:w-[inherit]! [&_svg]:h-[inherit]!\" />\n</ng-template>\n\n<eg-layout-simple-sidebar\n [title]=\"sidebarTitle()\"\n [content]=\"sidebarContent()\"\n [contentContext]=\"{ close: closeSidebar.bind(this) }\"\n/>\n\n<div class=\"flex flex-col min-h-screen\">\n <!-- Header -->\n <header [class]=\"_headerClass()\">\n <div class=\"flex items-center space-x-4\">\n @if (sidebarEnabled()) {\n <button\n hlmButton\n variant=\"secondary\"\n appearance=\"outline\"\n size=\"icon\"\n [icon]=\"menuIconTemplate\"\n iconPosition=\"left\"\n class=\"bg-transparent! border-gray-400! hover:border-gray-500!\"\n (click)=\"openSidebar()\"\n ></button>\n }\n\n <div class=\"logo\">\n <a [routerLink]=\"logoLink()\">\n <img [src]=\"logo()\" alt=\"Logo\" [class]=\"_logoClass()\" />\n </a>\n </div>\n <!-- Left menus (desktop) -->\n <nav [class]=\"_computedLeftClass()\">\n @for (item of leftMenus(); track item.label) { @if (item.link) {\n <a [routerLink]=\"item.link\" [class]=\"hlm(_computedLeftLinkClass(), item.class || '')\"> {{ item.label }} </a>\n } @else {\n <button type=\"button\" (click)=\"item.action?.()\" [class]=\"hlm(_computedLeftLinkClass(), item.class || '')\">\n {{ item.label }}\n </button>\n } } @for (group of leftMenuGroups(); track $index) {\n <div class=\"relative group\">\n <button\n type=\"button\"\n class=\"text-left text-secondary hover:text-primary cursor-pointer no-underline py-1 flex items-center gap-1\"\n >\n {{ group.label ?? 'Menu' }}\n <svg\n xmlns=\"http://www.w3.org/2000/svg\"\n class=\"h-3 w-3\"\n viewBox=\"0 0 24 24\"\n fill=\"none\"\n stroke=\"currentColor\"\n >\n <path stroke-linecap=\"round\" stroke-linejoin=\"round\" stroke-width=\"2\" d=\"M19 9l-7 7-7-7\" />\n </svg>\n </button>\n <div\n class=\"absolute left-0 top-full mt-1 hidden group-hover:flex flex-col min-w-[12rem] bg-popover text-popover-foreground border border-gray-200 rounded-md shadow-md py-1 z-50\"\n >\n @if (group.label) {\n <div class=\"px-3 py-1 text-xs font-semibold text-muted-foreground\">{{ group.label }}</div>\n } @for (item of group.items; track item.label) { @if (item.link) {\n <a\n [routerLink]=\"item.link\"\n [class]=\"hlm('px-3 py-1.5 text-sm no-underline hover:bg-secondary cursor-pointer', item.class || '')\"\n >\n {{ item.label }}\n </a>\n } @else {\n <button\n type=\"button\"\n (click)=\"item.action?.()\"\n [class]=\"hlm('px-3 py-1.5 text-sm text-left hover:bg-secondary cursor-pointer bg-transparent border-0 w-full', item.class || '')\"\n >\n {{ item.label }}\n </button>\n } }\n </div>\n </div>\n }\n </nav>\n </div>\n\n <!-- Right menus (desktop) -->\n <nav [class]=\"_computedRightClass()\">\n @if (searchEnabled()) {\n <eg-generic-autocomplete\n [loaderFn]=\"searchLoaderFn()\"\n [transformValueToSearch]=\"searchTransformValueToSearch()\"\n [placeholderText]=\"searchPlaceholderText()\"\n [emptyText]=\"searchEmptyText()\"\n (optionChange)=\"onSearchOptionChange($event)\"\n ></eg-generic-autocomplete>\n } @for (item of rightMenus(); track item.label) { @if (item.link) {\n <a [routerLink]=\"item.link\" [class]=\"hlm(_computedRightLinkClass(), item.class || '')\"> {{ item.label }} </a>\n } @else {\n <button type=\"button\" (click)=\"item.action?.()\" [class]=\"hlm(_computedRightLinkClass(), item.class || '')\">\n {{ item.label }}\n </button>\n } } @let uMenus = userMenus(); @if (uMenus && uMenus.length > 0) {\n <eg-layout-simple-user-menu [menus]=\"uMenus\" [menuTrigger]=\"userMenuTrigger()\" />\n }\n </nav>\n\n <!-- Mobile menu button -->\n <button\n (click)=\"toggleMobileMenu()\"\n class=\"md:hidden p-2 text-gray-700 hover:text-primary focus:outline-none cursor-pointer\"\n >\n <svg\n xmlns=\"http://www.w3.org/2000/svg\"\n class=\"h-6 w-6\"\n fill=\"none\"\n viewBox=\"0 0 24 24\"\n stroke=\"currentColor\"\n >\n <path stroke-linecap=\"round\" stroke-linejoin=\"round\" stroke-width=\"2\" d=\"M4 6h16M4 12h16M4 18h16\" />\n </svg>\n </button>\n </header>\n\n @let _topMenus = leftMenus().concat(rightMenus()); @let _userMenus = userMenus(); @let _leftMenuGroups =\n leftMenuGroups(); @let _topMenuItems = topMenus(); @let _topSecondaryGroups = topSecondaryMenus();\n\n <!-- Top menus (desktop) -->\n @if (_topMenuItems.length > 0) {\n <nav [class]=\"_computedTopClass()\">\n @for (item of _topMenuItems; track item.label) { @if (item.link) {\n <a [routerLink]=\"item.link\" [class]=\"hlm(_computedTopLinkClass(), item.class || '')\"> {{ item.label }} </a>\n } @else {\n <span [class]=\"hlm(_computedTopLinkClass(), item.class || '')\">{{ item.label }}</span>\n } }\n </nav>\n }\n\n <!-- Top secondary menus (desktop) \u2014 second row showing items grouped by parent label -->\n @if (_topSecondaryGroups.length > 0) {\n <nav [class]=\"_computedTopSecondaryClass()\">\n @for (group of _topSecondaryGroups; track group.label) {\n <span class=\"flex flex-wrap items-center gap-x-3\">\n @if (group.label) {\n <span class=\"text-xs font-semibold uppercase text-muted-foreground\">{{ group.label }}</span>\n } @for (item of group.items; track item.label) { @if (item.link) {\n <a\n [routerLink]=\"item.link\"\n [class]=\"hlm(_computedTopLinkClass(), 'text-xs hover:underline', item.class || '')\"\n >\n {{ item.label }}\n </a>\n } @else {\n <button\n type=\"button\"\n (click)=\"item.action?.()\"\n [class]=\"hlm(_computedTopLinkClass(), 'text-xs hover:underline', item.class || '')\"\n >\n {{ item.label }}\n </button>\n } }\n </span>\n }\n </nav>\n }\n\n <!-- Mobile menu -->\n @if (isMobile() && mobileMenuOpen) {\n <div class=\"w-full border-none\">\n @if (_topMenuItems.length > 0) {\n <eg-layout-simple-mobile-menu-group [items]=\"_topMenuItems\" (itemClick)=\"toggleMobileMenu()\" />\n }\n\n @for (group of _topSecondaryGroups; track group.label) { @if (group.items && group.items.length > 0) {\n <eg-layout-simple-mobile-menu-group\n [items]=\"group.items\"\n [label]=\"group.label\"\n (itemClick)=\"toggleMobileMenu()\"\n ></eg-layout-simple-mobile-menu-group>\n } }\n\n <eg-layout-simple-mobile-menu-group [items]=\"_topMenus\" (itemClick)=\"toggleMobileMenu()\" />\n\n @for (group of _leftMenuGroups; track $index) { @if (group.items && group.items.length > 0) {\n <eg-layout-simple-mobile-menu-group\n [items]=\"group.items\"\n [label]=\"group.label\"\n (itemClick)=\"toggleMobileMenu()\"\n ></eg-layout-simple-mobile-menu-group>\n } } @if ((_topMenus.length > 0 || _leftMenuGroups.length > 0) && _userMenus.length > 0) {\n <hr class=\"border-gray-300 my-2\" />\n } @for (section of userMenus(); track section.label) {\n <eg-layout-simple-mobile-menu-group\n [items]=\"section.items\"\n [label]=\"section.label\"\n (itemClick)=\"toggleMobileMenu()\"\n ></eg-layout-simple-mobile-menu-group>\n\n @if (section.separator) {\n <hr class=\"border-gray-300 my-2\" />\n } }\n </div>\n }\n\n <!-- Main content -->\n <main [class]=\"_contentClass()\">\n @if (!loading()) {\n <div class=\"flex items-center justify-center h-full\">\n <ng-content />\n </div>\n }\n <div [class]=\"_contentBottomClass()\"></div>\n </main>\n\n @if (footerEnabled()) {\n <footer [class]=\"_footerClass()\">\n <nav [class]=\"_computedFooterMenuClass()\">\n @for (item of footerMenus(); track item.label) { @if (item.link) {\n <a [routerLink]=\"item.link\" [class]=\"hlm(_computedFooterLinkClass(), item.class || '')\"> {{ item.label }} </a>\n } @else {\n <button type=\"button\" (click)=\"item.action?.()\" [class]=\"hlm(_computedFooterLinkClass(), item.class || '')\">\n {{ item.label }}\n </button>\n } }\n </nav>\n\n <div class=\"mt-2 text-center\">{{ footerContent() }}</div>\n </footer>\n }\n</div>\n" }]
708
- }], ctorParameters: () => [{ type: i1$2.BreakpointObserver }], propDecorators: { sidebarEnabled: [{ type: i0.Input, args: [{ isSignal: true, alias: "sidebarEnabled", required: false }] }], sidebarTitle: [{ type: i0.Input, args: [{ isSignal: true, alias: "sidebarTitle", required: false }] }], sidebarContent: [{ type: i0.Input, args: [{ isSignal: true, alias: "sidebarContent", required: false }] }], userMenuTrigger: [{ type: i0.Input, args: [{ isSignal: true, alias: "userMenuTrigger", required: false }] }], leftMenus: [{ type: i0.Input, args: [{ isSignal: true, alias: "leftMenus", required: false }] }], leftMenuGroups: [{ type: i0.Input, args: [{ isSignal: true, alias: "leftMenuGroups", required: false }] }], rightMenus: [{ type: i0.Input, args: [{ isSignal: true, alias: "rightMenus", required: false }] }], topMenus: [{ type: i0.Input, args: [{ isSignal: true, alias: "topMenus", required: false }] }], topSecondaryMenus: [{ type: i0.Input, args: [{ isSignal: true, alias: "topSecondaryMenus", required: false }] }], userMenus: [{ type: i0.Input, args: [{ isSignal: true, alias: "userMenus", required: false }] }], logo: [{ type: i0.Input, args: [{ isSignal: true, alias: "logo", required: false }] }], logoLink: [{ type: i0.Input, args: [{ isSignal: true, alias: "logoLink", required: false }] }], logoClass: [{ type: i0.Input, args: [{ isSignal: true, alias: "logoClass", required: false }] }], headerClass: [{ type: i0.Input, args: [{ isSignal: true, alias: "headerClass", required: false }] }], contentClass: [{ type: i0.Input, args: [{ isSignal: true, alias: "contentClass", required: false }] }], contentBottomClass: [{ type: i0.Input, args: [{ isSignal: true, alias: "contentBottomClass", required: false }] }], leftMenuClass: [{ type: i0.Input, args: [{ isSignal: true, alias: "leftClass", required: false }] }], rightMenuClass: [{ type: i0.Input, args: [{ isSignal: true, alias: "rightClass", required: false }] }], topMenuClass: [{ type: i0.Input, args: [{ isSignal: true, alias: "topClass", required: false }] }], leftLinkClass: [{ type: i0.Input, args: [{ isSignal: true, alias: "leftLinkClass", required: false }] }], rightLinkClass: [{ type: i0.Input, args: [{ isSignal: true, alias: "rightLinkClass", required: false }] }], topLinkClass: [{ type: i0.Input, args: [{ isSignal: true, alias: "topLinkClass", required: false }] }], searchEnabled: [{ type: i0.Input, args: [{ isSignal: true, alias: "searchEnabled", required: false }] }], loading: [{ type: i0.Input, args: [{ isSignal: true, alias: "loading", required: false }] }], searchPlaceholderText: [{ type: i0.Input, args: [{ isSignal: true, alias: "searchPlaceholderText", required: false }] }], searchEmptyText: [{ type: i0.Input, args: [{ isSignal: true, alias: "searchEmptyText", required: false }] }], searchOptionTemplate: [{ type: i0.Input, args: [{ isSignal: true, alias: "searchOptionTemplate", required: false }] }], searchLoaderFn: [{ type: i0.Input, args: [{ isSignal: true, alias: "searchLoaderFn", required: false }] }], searchTransformValueToSearch: [{ type: i0.Input, args: [{ isSignal: true, alias: "searchTransformValueToSearch", required: false }] }], searchOptionChange: [{ type: i0.Output, args: ["searchOptionChange"] }], footerEnabled: [{ type: i0.Input, args: [{ isSignal: true, alias: "footerEnabled", required: false }] }], footerMenus: [{ type: i0.Input, args: [{ isSignal: true, alias: "footerMenus", required: false }] }], footerMenuClass: [{ type: i0.Input, args: [{ isSignal: true, alias: "footerMenuClass", required: false }] }], footerLinkClass: [{ type: i0.Input, args: [{ isSignal: true, alias: "footerLinkClass", required: false }] }], footerContent: [{ type: i0.Input, args: [{ isSignal: true, alias: "footerContent", required: false }] }], footerClass: [{ type: i0.Input, args: [{ isSignal: true, alias: "footerClass", required: false }] }], viewchildSheetRef: [{ type: i0.ViewChild, args: [i0.forwardRef(() => EgLayoutSimpleSidebar), { isSignal: true }] }] } });
606
+ EgLayoutSearch,
607
+ EgLayoutNavigationItem,
608
+ EgLayoutFlyoutNavbar,
609
+ HlmDropdownMenu,
610
+ HlmDropdownMenuItem,
611
+ HlmDropdownMenuTrigger,
612
+ ], changeDetection: ChangeDetectionStrategy.OnPush, host: { class: "block min-w-0" }, template: "@if (sidebarEnabled()) {\n<eg-layout-simple-sidebar\n [panelId]=\"sidebarId\"\n [title]=\"sidebarTitle()\"\n [content]=\"sidebarContent()\"\n [contentContext]=\"sidebarContext\"\n/>\n}\n\n<div\n [class]=\"hlm('tw:relative tw:isolate tw:flex tw:min-w-0 tw:flex-col tw:bg-background tw:text-foreground', fullHeight() && 'tw:min-h-dvh')\"\n>\n <a\n [href]=\"'#' + mainId\"\n (click)=\"focusContent($event)\"\n class=\"sr-only focus:not-sr-only focus:absolute focus:left-4 focus:top-2 focus:z-50 focus:rounded-lg focus:bg-background focus:px-4 focus:py-3 focus:text-foreground focus:outline-2 focus:outline-ring\"\n >{{ skipLinkText() }}</a\n >\n\n <header [class]=\"headerClasses()\">\n <div class=\"flex min-w-0 flex-1 items-center gap-3 md:flex-none md:flex-wrap\">\n @if (sidebarEnabled()) {\n <button\n type=\"button\"\n [class]=\"iconButtonClasses\"\n [attr.aria-label]=\"sidebarToggleLabel()\"\n [attr.aria-expanded]=\"sidebarOpen()\"\n [attr.aria-controls]=\"sidebarId\"\n (click)=\"openSidebar()\"\n >\n <ng-icon [svg]=\"sidebarIcon\" size=\"20px\" aria-hidden=\"true\" />\n </button>\n }\n <a\n [routerLink]=\"logoLink()\"\n [attr.aria-label]=\"brandName() + ' home'\"\n class=\"flex min-h-11 min-w-0 items-center gap-2.5 rounded-lg pr-2 text-foreground no-underline focus-visible:outline-2 focus-visible:outline-offset-2 focus-visible:outline-ring\"\n >\n @if (logo()) { <img [src]=\"logo()\" alt=\"\" [class]=\"logoClasses()\" /> }\n <span class=\"truncate text-base font-semibold tracking-tight\">{{ brandName() }}</span>\n </a>\n <nav aria-label=\"Primary navigation\" [class]=\"primaryNavigationClasses()\">\n @for (item of primaryNavigation(); track $index) {\n <eg-layout-navigation-item [item]=\"item\" [itemClass]=\"navigationItemClass()\" />\n } @for (group of navigationGroups(); track $index) {\n <button\n type=\"button\"\n [hlmDropdownMenuTrigger]=\"groupMenu\"\n class=\"flex min-h-11 items-center gap-2 rounded-lg px-3 text-sm font-medium cursor-pointer hover:bg-foreground/5 focus-visible:outline-2 focus-visible:outline-ring\"\n >\n {{ group.label || 'More' }} <ng-icon [svg]=\"chevronIcon\" size=\"14px\" aria-hidden=\"true\" />\n </button>\n <ng-template #groupMenu>\n <div hlmDropdownMenu class=\"w-60\">\n @for (item of group.items; track $index) { @if (item.link && !item.disabled) {\n <a\n hlmDropdownMenuItem\n [routerLink]=\"item.link\"\n routerLinkActive=\"tw:bg-foreground/10 tw:font-semibold\"\n [routerLinkActiveOptions]=\"navigationMatchOptions(item)\"\n ariaCurrentWhenActive=\"page\"\n [class]=\"hlm('tw:min-h-11 tw:gap-2 tw:no-underline', item.class)\"\n >\n @if (item.icon) { <ng-icon [svg]=\"item.icon\" size=\"1rem\" aria-hidden=\"true\" /> } {{ item.label }}\n </a>\n } @else {\n <button\n type=\"button\"\n hlmDropdownMenuItem\n [disabled]=\"item.disabled || !item.action\"\n [class]=\"hlm('tw:min-h-11 tw:gap-2', item.class)\"\n (click)=\"item.action?.()\"\n >\n @if (item.icon) { <ng-icon [svg]=\"item.icon\" size=\"1rem\" aria-hidden=\"true\" /> } {{ item.label }}\n </button>\n } }\n </div>\n </ng-template>\n }\n </nav>\n </div>\n\n <div class=\"hidden md:flex flex-wrap items-center gap-3\">\n @if (searchEnabled() && !isMobile()) { <ng-container [ngTemplateOutlet]=\"searchTemplate\" /> } @if\n (utilityNavigation().length) {\n <nav aria-label=\"Utility navigation\" [class]=\"utilityNavigationClasses()\">\n @for (item of utilityNavigation(); track $index) {\n <eg-layout-navigation-item [item]=\"item\" [itemClass]=\"navigationItemClass()\" />\n }\n </nav>\n } @if (userMenuSections().length) {\n <eg-layout-simple-user-menu\n [sections]=\"userMenuSections()\"\n [triggerTemplate]=\"userMenuTrigger()\"\n [triggerLabel]=\"userMenuLabel()\"\n />\n }\n </div>\n\n <button\n #mobileMenuTrigger\n type=\"button\"\n (click)=\"toggleMobileMenu()\"\n [class]=\"hlm(iconButtonClasses, 'tw:md:hidden')\"\n [attr.aria-label]=\"mobileMenuOpen() ? mobileMenuCloseLabel() : mobileMenuLabel()\"\n [attr.aria-expanded]=\"mobileMenuOpen()\"\n [attr.aria-controls]=\"mobileMenuId\"\n >\n <ng-icon [svg]=\"mobileMenuOpen() ? closeIcon : menuIcon\" size=\"20px\" aria-hidden=\"true\" />\n </button>\n </header>\n\n @if (sectionNavigation().length) {\n <nav aria-label=\"Section navigation\" [class]=\"sectionNavigationClasses()\">\n @for (item of sectionNavigation(); track $index) {\n <eg-layout-navigation-item [item]=\"item\" [itemClass]=\"navigationItemClass()\" />\n }\n </nav>\n } @if (flyoutNavigationGroups().length && !isMobile()) {\n <eg-layout-flyout-navbar\n class=\"hidden md:block\"\n [groups]=\"flyoutNavigationGroups()\"\n [label]=\"flyoutNavigationLabel()\"\n [closeLabel]=\"flyoutCloseLabel()\"\n [navbarClass]=\"flyoutNavigationClass()\"\n [panelClass]=\"flyoutPanelClass()\"\n [itemClass]=\"navigationItemClass()\"\n />\n } @if (secondaryNavigationGroups().length) {\n <nav aria-label=\"Secondary navigation\" [class]=\"secondaryNavigationClasses()\" tabindex=\"0\">\n @for (group of secondaryNavigationGroups(); track $index; let first = $first) {\n <div\n [class]=\"hlm('tw:flex tw:shrink-0 tw:items-center tw:gap-1', !first && 'tw:border-l tw:border-border tw:pl-5')\"\n >\n @if (group.label) {\n <span class=\"mr-2 text-xs font-semibold text-foreground/75 whitespace-nowrap\"\n >{{ group.label }}</span\n >\n } @for (item of group.items; track $index) {\n <eg-layout-navigation-item\n [item]=\"item\"\n [itemClass]=\"hlm('tw:rounded-full tw:whitespace-nowrap', navigationItemClass())\"\n />\n }\n </div>\n }\n </nav>\n } @if (isMobile() && mobileMenuOpen()) {\n <nav\n [id]=\"mobileMenuId\"\n aria-label=\"Mobile navigation\"\n (keydown.escape)=\"closeMobileMenu(true); $event.stopPropagation()\"\n class=\"md:hidden max-h-[70dvh] overflow-y-auto overscroll-contain space-y-4 border-b border-border bg-background p-4\"\n >\n @if (searchEnabled()) { <ng-container [ngTemplateOutlet]=\"searchTemplate\" /> }\n <eg-layout-simple-mobile-menu-group [items]=\"primaryNavigation()\" (itemSelected)=\"closeMobileMenu(true)\" />\n @for (group of navigationGroups(); track $index) {\n <eg-layout-simple-mobile-menu-group\n [items]=\"group.items\"\n [label]=\"group.label\"\n (itemSelected)=\"closeMobileMenu(true)\"\n />\n }\n <eg-layout-simple-mobile-menu-group [items]=\"sectionNavigation()\" (itemSelected)=\"closeMobileMenu(true)\" />\n @for (group of flyoutNavigationGroups(); track $index) {\n <details class=\"group/flyout rounded-xl border border-border bg-foreground/3\">\n <summary\n class=\"flex min-h-11 list-none items-center justify-between gap-2 rounded-xl px-3 py-3 text-sm font-semibold cursor-pointer focus-visible:outline-2 focus-visible:outline-ring [&::-webkit-details-marker]:hidden\"\n >\n <span class=\"flex items-center gap-2\">\n @if (group.icon) { <ng-icon [svg]=\"group.icon\" size=\"1rem\" aria-hidden=\"true\" /> } {{ group.label }}\n </span>\n <ng-icon\n [svg]=\"chevronIcon\"\n size=\"14px\"\n aria-hidden=\"true\"\n class=\"shrink-0 group-open/flyout:rotate-180\"\n />\n </summary>\n <div class=\"space-y-2 border-t border-border p-2\">\n @if (group.description) {\n <p class=\"px-3 py-2 text-sm text-foreground/75\">{{ group.description }}</p>\n } @for (item of group.items; track $index) {\n <eg-layout-navigation-item\n [item]=\"item\"\n appearance=\"card\"\n [itemClass]=\"navigationItemClass()\"\n (selected)=\"closeMobileMenu(true)\"\n />\n }\n </div>\n </details>\n } @for (group of secondaryNavigationGroups(); track $index) {\n <eg-layout-simple-mobile-menu-group\n [items]=\"group.items\"\n [label]=\"group.label\"\n (itemSelected)=\"closeMobileMenu(true)\"\n />\n }\n <eg-layout-simple-mobile-menu-group [items]=\"utilityNavigation()\" (itemSelected)=\"closeMobileMenu(true)\" />\n @if (userMenuSections().length) {\n <div class=\"space-y-4 border-t border-border pt-4\">\n @for (section of userMenuSections(); track $index) {\n <eg-layout-simple-mobile-menu-group\n [items]=\"section.items\"\n [label]=\"section.label\"\n (itemSelected)=\"closeMobileMenu(true)\"\n />\n }\n </div>\n }\n </nav>\n }\n\n <main #mainContent [id]=\"mainId\" tabindex=\"-1\" [attr.aria-busy]=\"loading()\" [class]=\"contentClasses()\">\n @if (loading()) {\n <div\n role=\"status\"\n class=\"flex min-h-48 flex-1 items-center justify-center gap-3 text-sm text-foreground/75\"\n >\n <span\n aria-hidden=\"true\"\n class=\"size-5 rounded-full border-2 border-border border-t-foreground motion-safe:animate-spin\"\n ></span>\n {{ loadingText() }}\n </div>\n }\n <div\n [hidden]=\"loading()\"\n [style.display]=\"loading() ? 'none' : null\"\n class=\"w-full min-w-0 eg-layout-simple-main-content\"\n >\n <ng-content />\n </div>\n </main>\n\n @if (footerEnabled()) {\n <footer [class]=\"footerClasses()\">\n @if (footerText()) {\n <p>{{ footerText() }}</p>\n } @if (footerNavigation().length) {\n <nav aria-label=\"Footer navigation\" class=\"flex flex-wrap items-center gap-1\">\n @for (item of footerNavigation(); track $index) { <eg-layout-navigation-item [item]=\"item\" /> }\n </nav>\n }\n </footer>\n }\n</div>\n\n<ng-template #searchTemplate>\n <eg-layout-search\n [loader]=\"searchLoader()\"\n [resultLabel]=\"searchResultLabel()\"\n [placeholder]=\"searchPlaceholder()\"\n [emptyText]=\"searchEmptyText()\"\n [errorText]=\"searchErrorText()\"\n [resultTemplate]=\"searchResultTemplate()\"\n (resultSelected)=\"selectSearchResult($event)\"\n />\n</ng-template>\n" }]
613
+ }], ctorParameters: () => [], propDecorators: { mobileMenuTrigger: [{ type: i0.ViewChild, args: ['mobileMenuTrigger', { isSignal: true }] }], mainContent: [{ type: i0.ViewChild, args: ['mainContent', { isSignal: true }] }], sidebar: [{ type: i0.ViewChild, args: [i0.forwardRef(() => EgLayoutSimpleSidebar), { isSignal: true }] }], sidebarEnabled: [{ type: i0.Input, args: [{ isSignal: true, alias: "sidebarEnabled", required: false }] }], sidebarTitle: [{ type: i0.Input, args: [{ isSignal: true, alias: "sidebarTitle", required: false }] }], sidebarContent: [{ type: i0.Input, args: [{ isSignal: true, alias: "sidebarContent", required: false }] }], sidebarToggleLabel: [{ type: i0.Input, args: [{ isSignal: true, alias: "sidebarToggleLabel", required: false }] }], mobileMenuLabel: [{ type: i0.Input, args: [{ isSignal: true, alias: "mobileMenuLabel", required: false }] }], mobileMenuCloseLabel: [{ type: i0.Input, args: [{ isSignal: true, alias: "mobileMenuCloseLabel", required: false }] }], userMenuTrigger: [{ type: i0.Input, args: [{ isSignal: true, alias: "userMenuTrigger", required: false }] }], userMenuLabel: [{ type: i0.Input, args: [{ isSignal: true, alias: "userMenuLabel", required: false }] }], primaryNavigation: [{ type: i0.Input, args: [{ isSignal: true, alias: "primaryNavigation", required: false }] }], navigationGroups: [{ type: i0.Input, args: [{ isSignal: true, alias: "navigationGroups", required: false }] }], utilityNavigation: [{ type: i0.Input, args: [{ isSignal: true, alias: "utilityNavigation", required: false }] }], sectionNavigation: [{ type: i0.Input, args: [{ isSignal: true, alias: "sectionNavigation", required: false }] }], secondaryNavigationGroups: [{ type: i0.Input, args: [{ isSignal: true, alias: "secondaryNavigationGroups", required: false }] }], flyoutNavigationGroups: [{ type: i0.Input, args: [{ isSignal: true, alias: "flyoutNavigationGroups", required: false }] }], flyoutNavigationLabel: [{ type: i0.Input, args: [{ isSignal: true, alias: "flyoutNavigationLabel", required: false }] }], flyoutCloseLabel: [{ type: i0.Input, args: [{ isSignal: true, alias: "flyoutCloseLabel", required: false }] }], userMenuSections: [{ type: i0.Input, args: [{ isSignal: true, alias: "userMenuSections", required: false }] }], logo: [{ type: i0.Input, args: [{ isSignal: true, alias: "logo", required: false }] }], brandName: [{ type: i0.Input, args: [{ isSignal: true, alias: "brandName", required: false }] }], logoLink: [{ type: i0.Input, args: [{ isSignal: true, alias: "logoLink", required: false }] }], logoClass: [{ type: i0.Input, args: [{ isSignal: true, alias: "logoClass", required: false }] }], fullHeight: [{ type: i0.Input, args: [{ isSignal: true, alias: "fullHeight", required: false }] }], headerClass: [{ type: i0.Input, args: [{ isSignal: true, alias: "headerClass", required: false }] }], contentClass: [{ type: i0.Input, args: [{ isSignal: true, alias: "contentClass", required: false }] }], primaryNavigationClass: [{ type: i0.Input, args: [{ isSignal: true, alias: "primaryNavigationClass", required: false }] }], utilityNavigationClass: [{ type: i0.Input, args: [{ isSignal: true, alias: "utilityNavigationClass", required: false }] }], sectionNavigationClass: [{ type: i0.Input, args: [{ isSignal: true, alias: "sectionNavigationClass", required: false }] }], secondaryNavigationClass: [{ type: i0.Input, args: [{ isSignal: true, alias: "secondaryNavigationClass", required: false }] }], flyoutNavigationClass: [{ type: i0.Input, args: [{ isSignal: true, alias: "flyoutNavigationClass", required: false }] }], flyoutPanelClass: [{ type: i0.Input, args: [{ isSignal: true, alias: "flyoutPanelClass", required: false }] }], navigationItemClass: [{ type: i0.Input, args: [{ isSignal: true, alias: "navigationItemClass", required: false }] }], loading: [{ type: i0.Input, args: [{ isSignal: true, alias: "loading", required: false }] }], loadingText: [{ type: i0.Input, args: [{ isSignal: true, alias: "loadingText", required: false }] }], skipLinkText: [{ type: i0.Input, args: [{ isSignal: true, alias: "skipLinkText", required: false }] }], searchEnabled: [{ type: i0.Input, args: [{ isSignal: true, alias: "searchEnabled", required: false }] }], searchPlaceholder: [{ type: i0.Input, args: [{ isSignal: true, alias: "searchPlaceholder", required: false }] }], searchEmptyText: [{ type: i0.Input, args: [{ isSignal: true, alias: "searchEmptyText", required: false }] }], searchErrorText: [{ type: i0.Input, args: [{ isSignal: true, alias: "searchErrorText", required: false }] }], searchResultTemplate: [{ type: i0.Input, args: [{ isSignal: true, alias: "searchResultTemplate", required: false }] }], searchLoader: [{ type: i0.Input, args: [{ isSignal: true, alias: "searchLoader", required: false }] }], searchResultLabel: [{ type: i0.Input, args: [{ isSignal: true, alias: "searchResultLabel", required: false }] }], searchResultSelected: [{ type: i0.Output, args: ["searchResultSelected"] }], footerEnabled: [{ type: i0.Input, args: [{ isSignal: true, alias: "footerEnabled", required: false }] }], footerNavigation: [{ type: i0.Input, args: [{ isSignal: true, alias: "footerNavigation", required: false }] }], footerText: [{ type: i0.Input, args: [{ isSignal: true, alias: "footerText", required: false }] }], footerClass: [{ type: i0.Input, args: [{ isSignal: true, alias: "footerClass", required: false }] }] } });
709
614
 
710
615
  /*
711
616
  * Public API Surface of layout-simple
@@ -715,5 +620,5 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.0.7", ngImpor
715
620
  * Generated bundle index. Do not edit.
716
621
  */
717
622
 
718
- export { EgGenericAutocomplete, EgLayoutSimple, EgLayoutSimpleUserMenu };
719
- //# sourceMappingURL=layout-simple.mjs.map
623
+ export { EG_LAYOUT_SIMPLE_MOBILE_BREAKPOINT, EgLayoutSearch, EgLayoutSimple, EgLayoutSimpleUserMenu };
624
+