@egose/shadcn-theme-ng 0.1.0 → 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.
- package/README.md +1 -1
- package/accordion/README.md +405 -2
- package/alert/README.md +372 -2
- package/alert-dialog/README.md +471 -5
- package/aspect-ratio/README.md +272 -5
- package/autocomplete/README.md +502 -2
- package/avatar/README.md +357 -5
- package/badge/README.md +318 -2
- package/basic-alert/README.md +353 -2
- package/breadcrumb/README.md +406 -5
- package/button/README.md +482 -2
- package/button/fesm2022/button.mjs +85 -107
- package/button/types/button.d.ts +5 -8
- package/button-group/README.md +318 -5
- package/calendar/README.md +357 -2
- package/card/README.md +331 -5
- package/carousel/README.md +333 -5
- package/carousel/fesm2022/carousel.mjs +4 -1
- package/checkbox/README.md +320 -2
- package/collapsible/README.md +332 -5
- package/combobox/README.md +507 -5
- package/combobox/fesm2022/combobox.mjs +4 -1
- package/command/README.md +435 -5
- package/confirmation-dialog/README.md +301 -2
- package/context-menu/README.md +366 -5
- package/date-picker/README.md +465 -2
- package/date-picker/fesm2022/date-picker.mjs +2 -2
- package/dialog/README.md +448 -2
- package/drawer/README.md +395 -5
- package/dropdown-menu/README.md +417 -5
- package/empty/README.md +329 -5
- package/field/README.md +385 -5
- package/form-checkbox/README.md +312 -2
- package/form-date-picker/README.md +322 -2
- package/form-field/README.md +356 -2
- package/form-field-simple/README.md +340 -2
- package/form-searchable-multiselect/README.md +361 -2
- package/form-select/README.md +350 -2
- package/form-text-input/README.md +371 -2
- package/form-textarea/README.md +347 -2
- package/hover-card/README.md +256 -5
- package/icon/README.md +239 -2
- package/input/README.md +269 -2
- package/input-group/README.md +335 -5
- package/input-group/fesm2022/input-group.mjs +3 -3
- package/input-otp/README.md +375 -5
- package/item/README.md +385 -5
- package/item/fesm2022/item.mjs +3 -3
- package/kbd/README.md +291 -5
- package/label/README.md +272 -2
- package/layout-simple/README.md +193 -2
- package/layout-simple/fesm2022/layout-simple.mjs +472 -236
- package/layout-simple/types/layout-simple.d.ts +174 -137
- package/menu/README.md +417 -2
- package/menubar/README.md +343 -5
- package/native-select/README.md +323 -5
- package/navigation-menu/README.md +369 -5
- package/package.json +1 -1
- package/pagination/README.md +388 -5
- package/popover/README.md +331 -2
- package/progress/README.md +311 -5
- package/radio-group/README.md +364 -2
- package/radio-group/fesm2022/radio-group.mjs +5 -1
- package/radio-group/types/radio-group.d.ts +1 -1
- package/resizable/README.md +269 -5
- package/scroll-area/README.md +233 -5
- package/searchable-multiselect/README.md +323 -2
- package/select/README.md +437 -2
- package/separator/README.md +222 -2
- package/sheet/README.md +311 -2
- package/sidebar/README.md +457 -5
- package/skeleton/README.md +217 -5
- package/slider/README.md +273 -5
- package/slider/fesm2022/slider.mjs +3 -3
- package/sonner/README.md +346 -2
- package/spinner/README.md +284 -2
- package/switch/README.md +310 -2
- package/table/README.md +423 -5
- package/tabs/README.md +411 -2
- package/tabs/fesm2022/tabs.mjs +2 -2
- package/textarea/README.md +282 -5
- package/toggle/README.md +270 -5
- package/toggle-group/README.md +340 -5
- package/tooltip/README.md +269 -2
- package/typography/README.md +271 -5
- package/typography/types/typography.d.ts +8 -8
- package/utils/README.md +303 -2
|
@@ -1,44 +1,56 @@
|
|
|
1
1
|
import * as i0 from '@angular/core';
|
|
2
|
-
import { input,
|
|
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';
|
|
3
5
|
import { takeUntilDestroyed } from '@angular/core/rxjs-interop';
|
|
4
|
-
import { RouterLink,
|
|
6
|
+
import { RouterLink, RouterLinkActive, Router, NavigationEnd } from '@angular/router';
|
|
7
|
+
import { BreakpointObserver } from '@angular/cdk/layout';
|
|
8
|
+
import { _IdGenerator } from '@angular/cdk/a11y';
|
|
5
9
|
import { NgIcon, provideIcons } from '@ng-icons/core';
|
|
6
|
-
import { lucideUser, lucideSearch, lucideMenu } from '@ng-icons/lucide';
|
|
10
|
+
import { lucideUser, lucideSearch, lucideChevronDown, lucideX, lucideMenu, lucidePanelLeft } from '@ng-icons/lucide';
|
|
7
11
|
import { hlm } from '@egose/shadcn-theme-ng/utils';
|
|
8
|
-
import * as i4 from '@egose/shadcn-theme-ng/button';
|
|
9
|
-
import { HlmButton, HlmButtonImports } from '@egose/shadcn-theme-ng/button';
|
|
10
|
-
import * as i1 from '@angular/common';
|
|
11
|
-
import { CommonModule } from '@angular/common';
|
|
12
12
|
import { HlmDropdownMenu, HlmDropdownMenuTrigger, HlmDropdownMenuItem, HlmDropdownMenuLabel, HlmDropdownMenuSeparator, HlmDropdownMenuGroup } from '@egose/shadcn-theme-ng/dropdown-menu';
|
|
13
|
-
import * as
|
|
14
|
-
import {
|
|
13
|
+
import * as i3 from '@egose/shadcn-theme-ng/button';
|
|
14
|
+
import { HlmButton, HlmButtonImports } from '@egose/shadcn-theme-ng/button';
|
|
15
15
|
import { HlmPopover, HlmPopoverTrigger, HlmPopoverContent, HlmPopoverPortal } from '@egose/shadcn-theme-ng/popover';
|
|
16
16
|
import { HlmInput } from '@egose/shadcn-theme-ng/input';
|
|
17
|
-
import * as
|
|
17
|
+
import * as i1$1 from '@spartan-ng/brain/sheet';
|
|
18
18
|
import { BrnSheet, BrnSheetImports } from '@spartan-ng/brain/sheet';
|
|
19
|
-
import
|
|
20
|
-
import * as i3 from '@egose/shadcn-theme-ng/sheet';
|
|
19
|
+
import * as i2 from '@egose/shadcn-theme-ng/sheet';
|
|
21
20
|
import { HlmSheetImports } from '@egose/shadcn-theme-ng/sheet';
|
|
22
|
-
|
|
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
|
+
}
|
|
23
31
|
|
|
24
32
|
class EgLayoutSimpleUserMenu {
|
|
25
33
|
hlm = hlm;
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
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 */ []));
|
|
31
42
|
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "22.1.3", ngImport: i0, type: EgLayoutSimpleUserMenu, deps: [], target: i0.ɵɵFactoryTarget.Component });
|
|
32
|
-
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "22.1.3", type: EgLayoutSimpleUserMenu, isStandalone: true, selector: "eg-layout-simple-user-menu", inputs: {
|
|
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: "\n <ng-template #iconTemplate>\n <ng-icon [svg]=\"
|
|
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 });
|
|
37
48
|
}
|
|
38
49
|
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.1.3", ngImport: i0, type: EgLayoutSimpleUserMenu, decorators: [{
|
|
39
50
|
type: Component,
|
|
40
51
|
args: [{
|
|
41
52
|
selector: 'eg-layout-simple-user-menu',
|
|
53
|
+
changeDetection: ChangeDetectionStrategy.OnPush,
|
|
42
54
|
imports: [
|
|
43
55
|
CommonModule,
|
|
44
56
|
HlmDropdownMenu,
|
|
@@ -50,286 +62,506 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.1.3", ngImpor
|
|
|
50
62
|
HlmButton,
|
|
51
63
|
NgIcon,
|
|
52
64
|
RouterLink,
|
|
65
|
+
RouterLinkActive,
|
|
53
66
|
],
|
|
54
67
|
providers: [
|
|
55
68
|
provideIcons({
|
|
56
69
|
lucideUser,
|
|
57
70
|
}),
|
|
58
71
|
],
|
|
59
|
-
template: "\n <ng-template #iconTemplate>\n <ng-icon [svg]=\"
|
|
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 ",
|
|
60
73
|
}]
|
|
61
|
-
}], propDecorators: {
|
|
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 }] }] } });
|
|
62
75
|
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
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 */
|
|
67
81
|
...(ngDevMode ? [{ debugName: "emptyText" }] : /* istanbul ignore next */ []));
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
}
|
|
86
|
-
|
|
87
|
-
|
|
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 */ []));
|
|
88
112
|
constructor() {
|
|
89
|
-
|
|
90
|
-
|
|
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
|
+
});
|
|
91
145
|
}
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
}
|
|
103
|
-
catch {
|
|
104
|
-
this.options.set([]);
|
|
105
|
-
}
|
|
146
|
+
labelFor(item) {
|
|
147
|
+
return this.resultLabel()?.(item) ?? String(item);
|
|
148
|
+
}
|
|
149
|
+
setOpen(open) {
|
|
150
|
+
this.isOpen.set(open);
|
|
151
|
+
if (!open)
|
|
152
|
+
this.query.set('');
|
|
153
|
+
}
|
|
154
|
+
retry() {
|
|
155
|
+
this.retryVersion.update((version) => version + 1);
|
|
106
156
|
}
|
|
107
|
-
|
|
108
|
-
this.
|
|
109
|
-
this.
|
|
157
|
+
selectResult(item) {
|
|
158
|
+
this.setOpen(false);
|
|
159
|
+
this.resultSelected.emit(item);
|
|
110
160
|
}
|
|
111
|
-
|
|
112
|
-
|
|
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 });
|
|
113
173
|
}
|
|
114
|
-
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.1.3", ngImport: i0, type:
|
|
174
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.1.3", ngImport: i0, type: EgLayoutSearch, decorators: [{
|
|
115
175
|
type: Component,
|
|
116
176
|
args: [{
|
|
117
|
-
selector: 'eg-
|
|
118
|
-
imports: [
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
HlmPopoverTrigger,
|
|
122
|
-
HlmPopoverContent,
|
|
123
|
-
HlmPopoverPortal,
|
|
124
|
-
HlmInput,
|
|
125
|
-
HlmButton,
|
|
126
|
-
NgIcon,
|
|
127
|
-
],
|
|
128
|
-
providers: [provideIcons({ lucideSearch })],
|
|
129
|
-
template: "\n <hlm-popover>\n <button\n hlmPopoverTrigger\n hlmButton\n variant=\"secondary\"\n appearance=\"outline\"\n type=\"button\"\n class=\"w-64 justify-start gap-2 text-muted-foreground\"\n >\n <ng-icon name=\"lucideSearch\" size=\"14px\" />\n <span class=\"truncate\">{{ placeholderText() }}</span>\n </button>\n\n <hlm-popover-content *hlmPopoverPortal class=\"w-64 p-2\">\n <input\n hlmInput\n [ngModel]=\"search()\"\n (ngModelChange)=\"search.set($event)\"\n [placeholder]=\"placeholderText()\"\n class=\"mb-2\"\n />\n <div class=\"max-h-60 overflow-auto flex flex-col\">\n @if (filtered().length === 0) {\n <span class=\"text-xs text-muted-foreground px-2 py-2\">{{ emptyText() }}</span>\n } @else {\n @for (opt of filtered(); track opt.label) {\n <button\n type=\"button\"\n (click)=\"select(opt)\"\n class=\"text-left px-2 py-1.5 text-sm rounded-sm hover:bg-secondary cursor-pointer\"\n >\n {{ opt.label }}\n </button>\n }\n }\n </div>\n </hlm-popover-content>\n </hlm-popover>\n ",
|
|
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 ",
|
|
130
181
|
changeDetection: ChangeDetectionStrategy.OnPush,
|
|
131
182
|
}]
|
|
132
|
-
}], ctorParameters: () => [], propDecorators: {
|
|
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 }] }] } });
|
|
133
184
|
|
|
134
185
|
class EgLayoutSimpleSidebar {
|
|
135
|
-
|
|
136
|
-
...(ngDevMode ? [{ debugName: "
|
|
137
|
-
|
|
138
|
-
...(ngDevMode ? [{ debugName: "
|
|
139
|
-
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 */
|
|
140
191
|
...(ngDevMode ? [{ debugName: "title" }] : /* istanbul ignore next */ []));
|
|
141
192
|
content = input(/* @ts-ignore */
|
|
142
193
|
...(ngDevMode ? [undefined, { debugName: "content" }] : /* istanbul ignore next */ []));
|
|
143
194
|
contentContext = input(null, /* @ts-ignore */
|
|
144
195
|
...(ngDevMode ? [{ debugName: "contentContext" }] : /* istanbul ignore next */ []));
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
}
|
|
148
|
-
openSheet() {
|
|
149
|
-
this.viewchildSheetRef()?.open();
|
|
196
|
+
open() {
|
|
197
|
+
this.sheet()?.open();
|
|
150
198
|
}
|
|
151
|
-
|
|
152
|
-
this.
|
|
199
|
+
close() {
|
|
200
|
+
this.sheet()?.close();
|
|
153
201
|
}
|
|
154
202
|
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "22.1.3", ngImport: i0, type: EgLayoutSimpleSidebar, deps: [], target: i0.ɵɵFactoryTarget.Component });
|
|
155
|
-
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.
|
|
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 });
|
|
156
204
|
}
|
|
157
205
|
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.1.3", ngImport: i0, type: EgLayoutSimpleSidebar, decorators: [{
|
|
158
206
|
type: Component,
|
|
159
207
|
args: [{
|
|
160
208
|
selector: 'eg-layout-simple-sidebar',
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
template: "\n
|
|
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 ",
|
|
164
212
|
}]
|
|
165
|
-
}],
|
|
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 }] }] } });
|
|
214
|
+
|
|
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 ",
|
|
248
|
+
}]
|
|
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"] }] } });
|
|
166
250
|
|
|
167
251
|
class EgLayoutSimpleMobileMenuGroup {
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
...(ngDevMode ? [{ debugName: "label" }] : /* istanbul ignore next */ []));
|
|
252
|
+
label = input(/* @ts-ignore */
|
|
253
|
+
...(ngDevMode ? [undefined, { debugName: "label" }] : /* istanbul ignore next */ []));
|
|
171
254
|
items = input(/* @ts-ignore */
|
|
172
255
|
...(ngDevMode ? [undefined, { debugName: "items" }] : /* istanbul ignore next */ []));
|
|
173
|
-
|
|
174
|
-
handleClick(item) {
|
|
175
|
-
item.action?.();
|
|
176
|
-
this.itemClick.emit(item);
|
|
177
|
-
}
|
|
256
|
+
itemSelected = output();
|
|
178
257
|
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "22.1.3", ngImport: i0, type: EgLayoutSimpleMobileMenuGroup, deps: [], target: i0.ɵɵFactoryTarget.Component });
|
|
179
|
-
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: {
|
|
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 });
|
|
180
259
|
}
|
|
181
260
|
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.1.3", ngImport: i0, type: EgLayoutSimpleMobileMenuGroup, decorators: [{
|
|
182
261
|
type: Component,
|
|
183
262
|
args: [{
|
|
184
263
|
selector: 'eg-layout-simple-mobile-menu-group',
|
|
185
|
-
imports: [
|
|
186
|
-
|
|
187
|
-
|
|
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 ",
|
|
188
268
|
}]
|
|
189
|
-
}], propDecorators: { label: [{ type: i0.Input, args: [{ isSignal: true, alias: "label", required: false }] }], items: [{ type: i0.Input, args: [{ isSignal: true, alias: "items", required: false }] }],
|
|
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"] }] } });
|
|
190
270
|
|
|
191
|
-
/**
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
*/
|
|
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;
|
|
355
|
+
}
|
|
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();
|
|
380
|
+
}
|
|
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 ",
|
|
397
|
+
}]
|
|
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 }] }] } });
|
|
399
|
+
|
|
400
|
+
/** Matches Tailwind's default `md` breakpoint. */
|
|
196
401
|
const EG_LAYOUT_SIMPLE_MOBILE_BREAKPOINT = '(max-width: 767.98px)';
|
|
197
|
-
|
|
198
|
-
const commonLinkClasses = "text-left text-secondary visited:text-secondary hover:text-primary cursor-pointer no-underline";
|
|
402
|
+
/** Responsive application shell. All navigation surfaces share the same item model. */
|
|
199
403
|
class EgLayoutSimple {
|
|
200
|
-
breakpointObserver;
|
|
201
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`;
|
|
202
411
|
hlm = hlm;
|
|
412
|
+
navigationMatchOptions = navigationMatchOptions;
|
|
203
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 */ []));
|
|
204
423
|
sidebarEnabled = input(false, /* @ts-ignore */
|
|
205
424
|
...(ngDevMode ? [{ debugName: "sidebarEnabled" }] : /* istanbul ignore next */ []));
|
|
206
|
-
sidebarTitle = input('
|
|
425
|
+
sidebarTitle = input('Navigation', /* @ts-ignore */
|
|
207
426
|
...(ngDevMode ? [{ debugName: "sidebarTitle" }] : /* istanbul ignore next */ []));
|
|
208
427
|
sidebarContent = input(/* @ts-ignore */
|
|
209
428
|
...(ngDevMode ? [undefined, { debugName: "sidebarContent" }] : /* istanbul ignore next */ []));
|
|
210
|
-
/** Accessible name for the icon-only sidebar trigger. */
|
|
211
429
|
sidebarToggleLabel = input('Open navigation sidebar', /* @ts-ignore */
|
|
212
430
|
...(ngDevMode ? [{ debugName: "sidebarToggleLabel" }] : /* istanbul ignore next */ []));
|
|
213
|
-
/** Accessible name for the icon-only mobile menu trigger. */
|
|
214
431
|
mobileMenuLabel = input('Open navigation menu', /* @ts-ignore */
|
|
215
432
|
...(ngDevMode ? [{ debugName: "mobileMenuLabel" }] : /* istanbul ignore next */ []));
|
|
433
|
+
mobileMenuCloseLabel = input('Close navigation menu', /* @ts-ignore */
|
|
434
|
+
...(ngDevMode ? [{ debugName: "mobileMenuCloseLabel" }] : /* istanbul ignore next */ []));
|
|
216
435
|
userMenuTrigger = input(/* @ts-ignore */
|
|
217
436
|
...(ngDevMode ? [undefined, { debugName: "userMenuTrigger" }] : /* istanbul ignore next */ []));
|
|
218
|
-
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
...(ngDevMode ? [{ debugName: "
|
|
223
|
-
|
|
224
|
-
...(ngDevMode ? [{ debugName: "
|
|
225
|
-
|
|
226
|
-
...(ngDevMode ? [{ debugName: "
|
|
227
|
-
|
|
228
|
-
...(ngDevMode ? [{ debugName: "
|
|
229
|
-
|
|
230
|
-
...(ngDevMode ? [{ debugName: "
|
|
231
|
-
|
|
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 */
|
|
232
461
|
...(ngDevMode ? [{ debugName: "logo" }] : /* istanbul ignore next */ []));
|
|
462
|
+
brandName = input('Workspace', /* @ts-ignore */
|
|
463
|
+
...(ngDevMode ? [{ debugName: "brandName" }] : /* istanbul ignore next */ []));
|
|
233
464
|
logoLink = input('/', /* @ts-ignore */
|
|
234
465
|
...(ngDevMode ? [{ debugName: "logoLink" }] : /* istanbul ignore next */ []));
|
|
235
|
-
logoClass = input('',
|
|
236
|
-
|
|
237
|
-
|
|
238
|
-
|
|
239
|
-
|
|
240
|
-
|
|
241
|
-
|
|
242
|
-
|
|
243
|
-
|
|
244
|
-
|
|
245
|
-
|
|
246
|
-
|
|
247
|
-
|
|
248
|
-
|
|
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 */ []));
|
|
249
489
|
loading = input(false, /* @ts-ignore */
|
|
250
490
|
...(ngDevMode ? [{ debugName: "loading" }] : /* istanbul ignore next */ []));
|
|
251
|
-
|
|
252
|
-
...(ngDevMode ? [{ debugName: "
|
|
253
|
-
|
|
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 */
|
|
254
500
|
...(ngDevMode ? [{ debugName: "searchEmptyText" }] : /* istanbul ignore next */ []));
|
|
255
|
-
|
|
256
|
-
...(ngDevMode ? [
|
|
257
|
-
|
|
258
|
-
...(ngDevMode ? [undefined, { debugName: "
|
|
259
|
-
|
|
260
|
-
...(ngDevMode ? [undefined, { debugName: "
|
|
261
|
-
|
|
262
|
-
|
|
263
|
-
|
|
264
|
-
_headerClass = computed(() => hlm("px-4 py-2 flex items-center justify-between bg-gray-100 border-b border-gray-300", this.headerClass()), /* @ts-ignore */
|
|
265
|
-
...(ngDevMode ? [{ debugName: "_headerClass" }] : /* istanbul ignore next */ []));
|
|
266
|
-
_contentClass = computed(() => hlm("p-4 flex flex-col flex-1", this.contentClass()), /* @ts-ignore */
|
|
267
|
-
...(ngDevMode ? [{ debugName: "_contentClass" }] : /* istanbul ignore next */ []));
|
|
268
|
-
_contentBottomClass = computed(() => hlm("flex-1", this.contentBottomClass()), /* @ts-ignore */
|
|
269
|
-
...(ngDevMode ? [{ debugName: "_contentBottomClass" }] : /* istanbul ignore next */ []));
|
|
270
|
-
/** Computed merged classes for containers */
|
|
271
|
-
_computedLeftClass = computed(() => hlm(commonLinkGroupClasses, this.leftMenuClass()), /* @ts-ignore */
|
|
272
|
-
...(ngDevMode ? [{ debugName: "_computedLeftClass" }] : /* istanbul ignore next */ []));
|
|
273
|
-
_computedRightClass = computed(() => hlm(commonLinkGroupClasses, this.rightMenuClass()), /* @ts-ignore */
|
|
274
|
-
...(ngDevMode ? [{ debugName: "_computedRightClass" }] : /* istanbul ignore next */ []));
|
|
275
|
-
_computedTopClass = computed(() => hlm("hidden md: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 */
|
|
276
|
-
...(ngDevMode ? [{ debugName: "_computedTopClass" }] : /* istanbul ignore next */ []));
|
|
277
|
-
_computedTopSecondaryClass = computed(() => hlm("hidden md: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 */
|
|
278
|
-
...(ngDevMode ? [{ debugName: "_computedTopSecondaryClass" }] : /* istanbul ignore next */ []));
|
|
279
|
-
/** Computed merged classes for link/button elements */
|
|
280
|
-
_computedLeftLinkClass = computed(() => hlm(commonLinkClasses, this.leftLinkClass()), /* @ts-ignore */
|
|
281
|
-
...(ngDevMode ? [{ debugName: "_computedLeftLinkClass" }] : /* istanbul ignore next */ []));
|
|
282
|
-
_computedRightLinkClass = computed(() => hlm(commonLinkClasses, this.rightLinkClass()), /* @ts-ignore */
|
|
283
|
-
...(ngDevMode ? [{ debugName: "_computedRightLinkClass" }] : /* istanbul ignore next */ []));
|
|
284
|
-
_computedTopLinkClass = computed(() => hlm("text-secondary visited:text-secondary hover:text-primary cursor-pointer no-underline text-sm", this.topLinkClass()), /* @ts-ignore */
|
|
285
|
-
...(ngDevMode ? [{ debugName: "_computedTopLinkClass" }] : /* istanbul ignore next */ []));
|
|
286
|
-
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();
|
|
287
510
|
footerEnabled = input(false, /* @ts-ignore */
|
|
288
511
|
...(ngDevMode ? [{ debugName: "footerEnabled" }] : /* istanbul ignore next */ []));
|
|
289
|
-
|
|
290
|
-
...(ngDevMode ? [{ debugName: "
|
|
291
|
-
|
|
292
|
-
|
|
293
|
-
|
|
294
|
-
...(ngDevMode ? [{ debugName: "
|
|
295
|
-
|
|
296
|
-
|
|
297
|
-
|
|
298
|
-
|
|
299
|
-
|
|
300
|
-
|
|
301
|
-
|
|
302
|
-
|
|
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";
|
|
303
535
|
mobileMenuOpen = signal(false, /* @ts-ignore */
|
|
304
536
|
...(ngDevMode ? [{ debugName: "mobileMenuOpen" }] : /* istanbul ignore next */ []));
|
|
305
537
|
isMobile = signal(false, /* @ts-ignore */
|
|
306
538
|
...(ngDevMode ? [{ debugName: "isMobile" }] : /* istanbul ignore next */ []));
|
|
307
|
-
/** Expanded state of the sidebar sheet, kept in sync with BrnSheet state changes. */
|
|
308
539
|
sidebarOpen = signal(false, /* @ts-ignore */
|
|
309
540
|
...(ngDevMode ? [{ debugName: "sidebarOpen" }] : /* istanbul ignore next */ []));
|
|
310
|
-
|
|
311
|
-
|
|
541
|
+
sidebarContext = { close: () => this.closeSidebar() };
|
|
542
|
+
constructor() {
|
|
312
543
|
this.breakpointObserver
|
|
313
544
|
.observe([EG_LAYOUT_SIMPLE_MOBILE_BREAKPOINT])
|
|
314
545
|
.pipe(takeUntilDestroyed(this.destroyRef))
|
|
315
|
-
.subscribe((
|
|
316
|
-
this.isMobile.set(
|
|
317
|
-
|
|
318
|
-
effect(() => {
|
|
319
|
-
// Desktop navigation replaces the mobile menu above the breakpoint, so an
|
|
320
|
-
// open mobile menu must not cross the boundary into desktop layout.
|
|
321
|
-
if (!this.isMobile() && this.mobileMenuOpen()) {
|
|
546
|
+
.subscribe(({ matches }) => {
|
|
547
|
+
this.isMobile.set(matches);
|
|
548
|
+
if (!matches)
|
|
322
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();
|
|
323
556
|
}
|
|
324
557
|
});
|
|
325
558
|
effect((onCleanup) => {
|
|
326
|
-
const sheet = this.
|
|
559
|
+
const sheet = this.sidebar()?.sheet();
|
|
327
560
|
if (!sheet)
|
|
328
561
|
return;
|
|
329
562
|
this.sidebarOpen.set(sheet.stateComputed() === 'open');
|
|
330
563
|
const subscriptions = [
|
|
331
564
|
sheet.stateChanged.subscribe((state) => this.sidebarOpen.set(state === 'open')),
|
|
332
|
-
// Escape/backdrop closes complete the dialog without a 'closed' state emission.
|
|
333
565
|
sheet.closed.subscribe(() => this.sidebarOpen.set(false)),
|
|
334
566
|
];
|
|
335
567
|
onCleanup(() => subscriptions.forEach((subscription) => subscription.unsubscribe()));
|
|
@@ -338,43 +570,47 @@ class EgLayoutSimple {
|
|
|
338
570
|
toggleMobileMenu() {
|
|
339
571
|
this.mobileMenuOpen.update((open) => !open);
|
|
340
572
|
}
|
|
341
|
-
closeMobileMenu() {
|
|
573
|
+
closeMobileMenu(restoreFocus = false) {
|
|
342
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);
|
|
343
581
|
}
|
|
344
|
-
|
|
345
|
-
|
|
582
|
+
focusContent(event) {
|
|
583
|
+
event.preventDefault();
|
|
584
|
+
this.mainContent()?.nativeElement.focus();
|
|
346
585
|
}
|
|
347
|
-
viewchildSheetRef = viewChild(EgLayoutSimpleSidebar, /* @ts-ignore */
|
|
348
|
-
...(ngDevMode ? [{ debugName: "viewchildSheetRef" }] : /* istanbul ignore next */ []));
|
|
349
586
|
openSidebar() {
|
|
350
|
-
this.
|
|
587
|
+
this.closeMobileMenu();
|
|
588
|
+
this.sidebar()?.open();
|
|
351
589
|
}
|
|
352
590
|
closeSidebar() {
|
|
353
|
-
this.
|
|
591
|
+
this.sidebar()?.close();
|
|
354
592
|
}
|
|
355
|
-
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "22.1.3", ngImport: i0, type: EgLayoutSimple, deps: [
|
|
356
|
-
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 }, 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: [
|
|
357
|
-
provideIcons({
|
|
358
|
-
lucideMenu,
|
|
359
|
-
}),
|
|
360
|
-
], 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 [attr.aria-label]=\"sidebarToggleLabel()\"\n [attr.aria-expanded]=\"sidebarOpen()\"\n aria-controls=\"eg-layout-simple-sidebar\"\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('tw:px-3 tw:py-1.5 tw:text-sm tw:no-underline tw:hover:bg-secondary tw:cursor-pointer', item.class || '')\"\n >\n {{ item.label }}\n </a>\n } @else {\n <button\n type=\"button\"\n (click)=\"item.action?.()\"\n [class]=\"hlm('tw:px-3 tw:py-1.5 tw:text-sm tw:text-left tw:hover:bg-secondary tw:cursor-pointer tw:bg-transparent tw:border-0 tw: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 [attr.aria-label]=\"mobileMenuLabel()\"\n [attr.aria-expanded]=\"mobileMenuOpen()\"\n aria-controls=\"eg-layout-simple-mobile-menu\"\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) — 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(), 'tw:text-xs tw: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(), 'tw:text-xs tw: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 id=\"eg-layout-simple-mobile-menu\" class=\"w-full border-none\" (keydown.escape)=\"closeMobileMenu()\">\n @if (_topMenuItems.length > 0) {\n <eg-layout-simple-mobile-menu-group [items]=\"_topMenuItems\" (itemClick)=\"closeMobileMenu()\" />\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)=\"closeMobileMenu()\"\n ></eg-layout-simple-mobile-menu-group>\n } }\n\n <eg-layout-simple-mobile-menu-group [items]=\"_topMenus\" (itemClick)=\"closeMobileMenu()\" />\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)=\"closeMobileMenu()\"\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)=\"closeMobileMenu()\"\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 eg-layout-simple-main-content\">\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 });
|
|
361
595
|
}
|
|
362
596
|
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.1.3", ngImport: i0, type: EgLayoutSimple, decorators: [{
|
|
363
597
|
type: Component,
|
|
364
|
-
args: [{ selector: 'eg-layout-simple',
|
|
598
|
+
args: [{ selector: 'eg-layout-simple', imports: [
|
|
365
599
|
RouterLink,
|
|
600
|
+
RouterLinkActive,
|
|
601
|
+
NgTemplateOutlet,
|
|
602
|
+
NgIcon,
|
|
366
603
|
EgLayoutSimpleUserMenu,
|
|
367
604
|
EgLayoutSimpleSidebar,
|
|
368
605
|
EgLayoutSimpleMobileMenuGroup,
|
|
369
|
-
|
|
370
|
-
|
|
371
|
-
|
|
372
|
-
|
|
373
|
-
|
|
374
|
-
|
|
375
|
-
}),
|
|
376
|
-
|
|
377
|
-
}], 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 }] }], sidebarToggleLabel: [{ type: i0.Input, args: [{ isSignal: true, alias: "sidebarToggleLabel", required: false }] }], mobileMenuLabel: [{ type: i0.Input, args: [{ isSignal: true, alias: "mobileMenuLabel", 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 }] }] } });
|
|
378
614
|
|
|
379
615
|
/*
|
|
380
616
|
* Public API Surface of layout-simple
|
|
@@ -384,5 +620,5 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.1.3", ngImpor
|
|
|
384
620
|
* Generated bundle index. Do not edit.
|
|
385
621
|
*/
|
|
386
622
|
|
|
387
|
-
export { EG_LAYOUT_SIMPLE_MOBILE_BREAKPOINT,
|
|
623
|
+
export { EG_LAYOUT_SIMPLE_MOBILE_BREAKPOINT, EgLayoutSearch, EgLayoutSimple, EgLayoutSimpleUserMenu };
|
|
388
624
|
|