@elasticias/ui 1.0.36 → 1.0.38

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.
@@ -7243,11 +7243,11 @@ class EfModuleRailComponent {
7243
7243
  return row.kind === 'module' ? `m:${row.module.id}` : `d:${index}`;
7244
7244
  }
7245
7245
  static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.11", ngImport: i0, type: EfModuleRailComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
7246
- static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "21.2.11", type: EfModuleRailComponent, isStandalone: true, selector: "ef-module-rail", inputs: { badges: "badges" }, ngImport: i0, template: "<nav class=\"ef-module-rail\" aria-label=\"Modules\">\n <div class=\"ef-module-rail__logo-slot\">\n <ng-content select=\"[logo]\"></ng-content>\n </div>\n\n @for (row of rows(); track trackRow($index, row)) {\n @if (row.kind === 'divider') {\n <span class=\"ef-module-rail__divider\" aria-hidden=\"true\"></span>\n } @else {\n <button\n type=\"button\"\n class=\"ef-module-rail__btn\"\n [class.is-active]=\"activeId() === row.module.id\"\n [attr.data-module]=\"row.module.id\"\n [attr.aria-current]=\"activeId() === row.module.id ? 'page' : null\"\n [style.--m-color]=\"'var(--' + row.module.accent + ')'\"\n [pTooltip]=\"row.module.labelKey | translate\"\n tooltipPosition=\"right\"\n (click)=\"onSelect(row.module)\"\n >\n <i class=\"ef-module-rail__icon\" [class]=\"row.module.icon\" aria-hidden=\"true\"></i>\n\n @if (badgeFor(row.module.id); as badge) {\n <span class=\"ef-module-rail__badge\">{{ badge }}</span>\n }\n\n <span class=\"ef-module-rail__sr\">{{ row.module.labelKey | translate }}</span>\n </button>\n }\n }\n</nav>\n", styles: ["@charset \"UTF-8\";:host{display:block;flex:0 0 64px;width:64px;background:var(--rail-bg);color:var(--rail-fg)}.ef-module-rail{display:flex;flex-direction:column;align-items:center;height:100%;padding:12px 0;gap:4px}.ef-module-rail__logo-slot{display:flex;align-items:center;justify-content:center;min-height:40px;width:40px;margin-bottom:4px}.ef-module-rail__logo-slot:empty{display:none}.ef-module-rail__logo-slot:not(:empty)+.ef-module-rail__divider,.ef-module-rail__logo-slot:has(*)+.ef-module-rail__divider{display:block}.ef-module-rail__divider{height:1px;width:32px;background:var(--rail-rule);margin:4px 0;flex-shrink:0}.ef-module-rail__btn{position:relative;display:grid;place-items:center;width:44px;height:44px;padding:0;border:0;background:transparent;color:var(--rail-fg-mute);border-radius:var(--r-md);cursor:pointer;transition:color var(--t-fast) var(--ease-out),background-color var(--t-fast) var(--ease-out)}.ef-module-rail__btn:hover{color:#fff;background:var(--rail-hover)}.ef-module-rail__btn:focus-visible{outline:2px solid color-mix(in srgb,var(--tenant-300, #b87a99) 80%,transparent);outline-offset:2px}.ef-module-rail__btn.is-active{color:#fff;background:var(--rail-active)}.ef-module-rail__btn.is-active:before{content:\"\";position:absolute;inset-inline-end:-10px;top:8px;bottom:8px;width:3px;border-radius:var(--r-sm) 0 0 var(--r-sm);background:var(--m-color, var(--tenant-300, #b87a99))}.ef-module-rail__icon{font-size:20px;line-height:1}.ef-module-rail__badge{position:absolute;top:4px;right:4px;min-width:16px;height:16px;padding:0 4px;display:inline-flex;align-items:center;justify-content:center;background:var(--tenant-500);color:#fff;border-radius:var(--r-pill);font-family:var(--font-mono);font-size:10px;font-weight:700;line-height:1}:host-context([dir=rtl]) .ef-module-rail__badge{right:auto;left:4px}.ef-module-rail__sr{position:absolute;width:1px;height:1px;padding:0;margin:-1px;overflow:hidden;clip:rect(0,0,0,0);white-space:nowrap;border:0}\n"], dependencies: [{ kind: "ngmodule", type: CommonModule }, { kind: "ngmodule", type: TooltipModule }, { kind: "directive", type: i1$5.Tooltip, selector: "[pTooltip]", inputs: ["tooltipPosition", "tooltipEvent", "positionStyle", "tooltipStyleClass", "tooltipZIndex", "escape", "showDelay", "hideDelay", "life", "positionTop", "positionLeft", "autoHide", "fitContent", "hideOnEscape", "showOnEllipsis", "pTooltip", "tooltipDisabled", "tooltipOptions", "appendTo", "ptTooltip", "pTooltipPT", "pTooltipUnstyled"] }, { kind: "ngmodule", type: TranslateModule }, { kind: "pipe", type: i1$1.TranslatePipe, name: "translate" }], changeDetection: i0.ChangeDetectionStrategy.OnPush });
7246
+ static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "21.2.11", type: EfModuleRailComponent, isStandalone: true, selector: "ef-module-rail", inputs: { badges: "badges" }, ngImport: i0, template: "<nav class=\"ef-module-rail\" aria-label=\"Modules\">\n <div class=\"ef-module-rail__logo-slot\">\n <ng-content select=\"[logo]\"></ng-content>\n </div>\n\n @for (row of rows(); track trackRow($index, row)) {\n @if (row.kind === 'divider') {\n <span class=\"ef-module-rail__divider\" aria-hidden=\"true\"></span>\n } @else {\n <button\n type=\"button\"\n class=\"ef-module-rail__btn\"\n [class.is-active]=\"activeId() === row.module.id\"\n [attr.data-module]=\"row.module.id\"\n [attr.aria-current]=\"activeId() === row.module.id ? 'page' : null\"\n [style.--m-color]=\"'var(--' + row.module.accent + ')'\"\n [pTooltip]=\"row.module.labelKey | translate\"\n tooltipPosition=\"right\"\n (click)=\"onSelect(row.module)\"\n >\n <i class=\"ef-module-rail__icon\" [class]=\"row.module.icon\" aria-hidden=\"true\"></i>\n\n @if (badgeFor(row.module.id); as badge) {\n <span class=\"ef-module-rail__badge\">{{ badge }}</span>\n }\n\n <span class=\"ef-module-rail__sr\">{{ row.module.labelKey | translate }}</span>\n </button>\n }\n }\n\n <!-- Pinned to the foot of the rail: controls that belong to the chrome\n rather than to a module (the side-panel toggle). Collapses when empty. -->\n <div class=\"ef-module-rail__footer\">\n <ng-content select=\"[rail-footer]\"></ng-content>\n </div>\n</nav>\n", styles: ["@charset \"UTF-8\";:host{display:block;flex:0 0 64px;width:64px;background:var(--rail-bg);color:var(--rail-fg)}.ef-module-rail{display:flex;flex-direction:column;align-items:center;height:100%;padding:12px 0;gap:4px}.ef-module-rail__logo-slot{display:flex;align-items:center;justify-content:center;min-height:40px;width:40px;margin-bottom:4px}.ef-module-rail__logo-slot:empty{display:none}.ef-module-rail__logo-slot:not(:empty)+.ef-module-rail__divider,.ef-module-rail__logo-slot:has(*)+.ef-module-rail__divider{display:block}.ef-module-rail__divider{height:1px;width:32px;background:var(--rail-rule);margin:4px 0;flex-shrink:0}.ef-module-rail__footer{display:flex;flex-direction:column;align-items:center;gap:4px;margin-top:auto}.ef-module-rail__footer:empty{display:none}.ef-module-rail__btn{position:relative;display:grid;place-items:center;width:44px;height:44px;padding:0;border:0;background:transparent;color:var(--rail-fg-mute);border-radius:var(--r-md);cursor:pointer;transition:color var(--t-fast) var(--ease-out),background-color var(--t-fast) var(--ease-out)}.ef-module-rail__btn:hover{color:#fff;background:var(--rail-hover)}.ef-module-rail__btn:focus-visible{outline:2px solid color-mix(in srgb,var(--tenant-300, #b87a99) 80%,transparent);outline-offset:2px}.ef-module-rail__btn.is-active{color:#fff;background:var(--rail-active)}.ef-module-rail__btn.is-active:before{content:\"\";position:absolute;inset-inline-end:-10px;top:8px;bottom:8px;width:3px;border-radius:var(--r-sm) 0 0 var(--r-sm);background:var(--m-color, var(--tenant-300, #b87a99))}.ef-module-rail__icon{font-size:20px;line-height:1}.ef-module-rail__badge{position:absolute;top:4px;right:4px;min-width:16px;height:16px;padding:0 4px;display:inline-flex;align-items:center;justify-content:center;background:var(--tenant-500);color:#fff;border-radius:var(--r-pill);font-family:var(--font-mono);font-size:10px;font-weight:700;line-height:1}:host-context([dir=rtl]) .ef-module-rail__badge{right:auto;left:4px}.ef-module-rail__sr{position:absolute;width:1px;height:1px;padding:0;margin:-1px;overflow:hidden;clip:rect(0,0,0,0);white-space:nowrap;border:0}\n"], dependencies: [{ kind: "ngmodule", type: CommonModule }, { kind: "ngmodule", type: TooltipModule }, { kind: "directive", type: i1$5.Tooltip, selector: "[pTooltip]", inputs: ["tooltipPosition", "tooltipEvent", "positionStyle", "tooltipStyleClass", "tooltipZIndex", "escape", "showDelay", "hideDelay", "life", "positionTop", "positionLeft", "autoHide", "fitContent", "hideOnEscape", "showOnEllipsis", "pTooltip", "tooltipDisabled", "tooltipOptions", "appendTo", "ptTooltip", "pTooltipPT", "pTooltipUnstyled"] }, { kind: "ngmodule", type: TranslateModule }, { kind: "pipe", type: i1$1.TranslatePipe, name: "translate" }], changeDetection: i0.ChangeDetectionStrategy.OnPush });
7247
7247
  }
7248
7248
  i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.11", ngImport: i0, type: EfModuleRailComponent, decorators: [{
7249
7249
  type: Component,
7250
- args: [{ selector: 'ef-module-rail', standalone: true, changeDetection: ChangeDetectionStrategy.OnPush, imports: [CommonModule, TooltipModule, TranslateModule], template: "<nav class=\"ef-module-rail\" aria-label=\"Modules\">\n <div class=\"ef-module-rail__logo-slot\">\n <ng-content select=\"[logo]\"></ng-content>\n </div>\n\n @for (row of rows(); track trackRow($index, row)) {\n @if (row.kind === 'divider') {\n <span class=\"ef-module-rail__divider\" aria-hidden=\"true\"></span>\n } @else {\n <button\n type=\"button\"\n class=\"ef-module-rail__btn\"\n [class.is-active]=\"activeId() === row.module.id\"\n [attr.data-module]=\"row.module.id\"\n [attr.aria-current]=\"activeId() === row.module.id ? 'page' : null\"\n [style.--m-color]=\"'var(--' + row.module.accent + ')'\"\n [pTooltip]=\"row.module.labelKey | translate\"\n tooltipPosition=\"right\"\n (click)=\"onSelect(row.module)\"\n >\n <i class=\"ef-module-rail__icon\" [class]=\"row.module.icon\" aria-hidden=\"true\"></i>\n\n @if (badgeFor(row.module.id); as badge) {\n <span class=\"ef-module-rail__badge\">{{ badge }}</span>\n }\n\n <span class=\"ef-module-rail__sr\">{{ row.module.labelKey | translate }}</span>\n </button>\n }\n }\n</nav>\n", styles: ["@charset \"UTF-8\";:host{display:block;flex:0 0 64px;width:64px;background:var(--rail-bg);color:var(--rail-fg)}.ef-module-rail{display:flex;flex-direction:column;align-items:center;height:100%;padding:12px 0;gap:4px}.ef-module-rail__logo-slot{display:flex;align-items:center;justify-content:center;min-height:40px;width:40px;margin-bottom:4px}.ef-module-rail__logo-slot:empty{display:none}.ef-module-rail__logo-slot:not(:empty)+.ef-module-rail__divider,.ef-module-rail__logo-slot:has(*)+.ef-module-rail__divider{display:block}.ef-module-rail__divider{height:1px;width:32px;background:var(--rail-rule);margin:4px 0;flex-shrink:0}.ef-module-rail__btn{position:relative;display:grid;place-items:center;width:44px;height:44px;padding:0;border:0;background:transparent;color:var(--rail-fg-mute);border-radius:var(--r-md);cursor:pointer;transition:color var(--t-fast) var(--ease-out),background-color var(--t-fast) var(--ease-out)}.ef-module-rail__btn:hover{color:#fff;background:var(--rail-hover)}.ef-module-rail__btn:focus-visible{outline:2px solid color-mix(in srgb,var(--tenant-300, #b87a99) 80%,transparent);outline-offset:2px}.ef-module-rail__btn.is-active{color:#fff;background:var(--rail-active)}.ef-module-rail__btn.is-active:before{content:\"\";position:absolute;inset-inline-end:-10px;top:8px;bottom:8px;width:3px;border-radius:var(--r-sm) 0 0 var(--r-sm);background:var(--m-color, var(--tenant-300, #b87a99))}.ef-module-rail__icon{font-size:20px;line-height:1}.ef-module-rail__badge{position:absolute;top:4px;right:4px;min-width:16px;height:16px;padding:0 4px;display:inline-flex;align-items:center;justify-content:center;background:var(--tenant-500);color:#fff;border-radius:var(--r-pill);font-family:var(--font-mono);font-size:10px;font-weight:700;line-height:1}:host-context([dir=rtl]) .ef-module-rail__badge{right:auto;left:4px}.ef-module-rail__sr{position:absolute;width:1px;height:1px;padding:0;margin:-1px;overflow:hidden;clip:rect(0,0,0,0);white-space:nowrap;border:0}\n"] }]
7250
+ args: [{ selector: 'ef-module-rail', standalone: true, changeDetection: ChangeDetectionStrategy.OnPush, imports: [CommonModule, TooltipModule, TranslateModule], template: "<nav class=\"ef-module-rail\" aria-label=\"Modules\">\n <div class=\"ef-module-rail__logo-slot\">\n <ng-content select=\"[logo]\"></ng-content>\n </div>\n\n @for (row of rows(); track trackRow($index, row)) {\n @if (row.kind === 'divider') {\n <span class=\"ef-module-rail__divider\" aria-hidden=\"true\"></span>\n } @else {\n <button\n type=\"button\"\n class=\"ef-module-rail__btn\"\n [class.is-active]=\"activeId() === row.module.id\"\n [attr.data-module]=\"row.module.id\"\n [attr.aria-current]=\"activeId() === row.module.id ? 'page' : null\"\n [style.--m-color]=\"'var(--' + row.module.accent + ')'\"\n [pTooltip]=\"row.module.labelKey | translate\"\n tooltipPosition=\"right\"\n (click)=\"onSelect(row.module)\"\n >\n <i class=\"ef-module-rail__icon\" [class]=\"row.module.icon\" aria-hidden=\"true\"></i>\n\n @if (badgeFor(row.module.id); as badge) {\n <span class=\"ef-module-rail__badge\">{{ badge }}</span>\n }\n\n <span class=\"ef-module-rail__sr\">{{ row.module.labelKey | translate }}</span>\n </button>\n }\n }\n\n <!-- Pinned to the foot of the rail: controls that belong to the chrome\n rather than to a module (the side-panel toggle). Collapses when empty. -->\n <div class=\"ef-module-rail__footer\">\n <ng-content select=\"[rail-footer]\"></ng-content>\n </div>\n</nav>\n", styles: ["@charset \"UTF-8\";:host{display:block;flex:0 0 64px;width:64px;background:var(--rail-bg);color:var(--rail-fg)}.ef-module-rail{display:flex;flex-direction:column;align-items:center;height:100%;padding:12px 0;gap:4px}.ef-module-rail__logo-slot{display:flex;align-items:center;justify-content:center;min-height:40px;width:40px;margin-bottom:4px}.ef-module-rail__logo-slot:empty{display:none}.ef-module-rail__logo-slot:not(:empty)+.ef-module-rail__divider,.ef-module-rail__logo-slot:has(*)+.ef-module-rail__divider{display:block}.ef-module-rail__divider{height:1px;width:32px;background:var(--rail-rule);margin:4px 0;flex-shrink:0}.ef-module-rail__footer{display:flex;flex-direction:column;align-items:center;gap:4px;margin-top:auto}.ef-module-rail__footer:empty{display:none}.ef-module-rail__btn{position:relative;display:grid;place-items:center;width:44px;height:44px;padding:0;border:0;background:transparent;color:var(--rail-fg-mute);border-radius:var(--r-md);cursor:pointer;transition:color var(--t-fast) var(--ease-out),background-color var(--t-fast) var(--ease-out)}.ef-module-rail__btn:hover{color:#fff;background:var(--rail-hover)}.ef-module-rail__btn:focus-visible{outline:2px solid color-mix(in srgb,var(--tenant-300, #b87a99) 80%,transparent);outline-offset:2px}.ef-module-rail__btn.is-active{color:#fff;background:var(--rail-active)}.ef-module-rail__btn.is-active:before{content:\"\";position:absolute;inset-inline-end:-10px;top:8px;bottom:8px;width:3px;border-radius:var(--r-sm) 0 0 var(--r-sm);background:var(--m-color, var(--tenant-300, #b87a99))}.ef-module-rail__icon{font-size:20px;line-height:1}.ef-module-rail__badge{position:absolute;top:4px;right:4px;min-width:16px;height:16px;padding:0 4px;display:inline-flex;align-items:center;justify-content:center;background:var(--tenant-500);color:#fff;border-radius:var(--r-pill);font-family:var(--font-mono);font-size:10px;font-weight:700;line-height:1}:host-context([dir=rtl]) .ef-module-rail__badge{right:auto;left:4px}.ef-module-rail__sr{position:absolute;width:1px;height:1px;padding:0;margin:-1px;overflow:hidden;clip:rect(0,0,0,0);white-space:nowrap;border:0}\n"] }]
7251
7251
  }], propDecorators: { badges: [{
7252
7252
  type: Input
7253
7253
  }] } });
@@ -7425,6 +7425,15 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.11", ngImpo
7425
7425
  args: ['document:keydown.escape']
7426
7426
  }] } });
7427
7427
 
7428
+ const SIDE_COLLAPSED_KEY = 'ef.shell.side-collapsed';
7429
+ function readSideCollapsed() {
7430
+ try {
7431
+ return localStorage.getItem(SIDE_COLLAPSED_KEY) === '1';
7432
+ }
7433
+ catch {
7434
+ return false;
7435
+ }
7436
+ }
7428
7437
  /**
7429
7438
  * Top-level Comptoir shell.
7430
7439
  *
@@ -7442,7 +7451,9 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.11", ngImpo
7442
7451
  * - `EfPermissionService` (via the rail / mobile tabs) for visible modules
7443
7452
  * - `EfActiveModuleService` for the active module accent
7444
7453
  *
7445
- * **Desktop / tablet:** rail (64px) + side (240px) + (top + main).
7454
+ * **Desktop / tablet:** rail (64px) + side (240px) + (top + main). The
7455
+ * side folds away from a toggle at the foot of the rail (or mod+B); the
7456
+ * rail never does.
7446
7457
  * **Mobile:** delegates to `<ef-app-shell-mobile>` — top bar + scrollable
7447
7458
  * body + 5-tab bottom bar + FAB slot.
7448
7459
  *
@@ -7463,6 +7474,38 @@ class EfAppShellComponent {
7463
7474
  viewport = this.vp.current;
7464
7475
  isMobile = this.vp.isMobile;
7465
7476
  showSide = computed(() => !this.vp.isMobile(), ...(ngDevMode ? [{ debugName: "showSide" }] : /* istanbul ignore next */ []));
7477
+ /* ── Side panel toggle ───────────────────────────────────────
7478
+ The rail stays; only the 240px module side folds away, for
7479
+ the screens that want the width (a wide grid, the order
7480
+ builder). The toggle sits at the foot of the rail rather than
7481
+ inside the side, so it is still there to bring the side back
7482
+ once it is gone, and in the same spot. Remembered per browser:
7483
+ it is a reading preference, not something worth a round trip. */
7484
+ sideCollapsed = signal(readSideCollapsed(), ...(ngDevMode ? [{ debugName: "sideCollapsed" }] : /* istanbul ignore next */ []));
7485
+ /** Shown in the toggle's tooltip: the button is far from the content, the shortcut is not. */
7486
+ shortcutHint = formatShortcut('mod+b');
7487
+ toggleSide() {
7488
+ const collapsed = !this.sideCollapsed();
7489
+ this.sideCollapsed.set(collapsed);
7490
+ try {
7491
+ localStorage.setItem(SIDE_COLLAPSED_KEY, collapsed ? '1' : '0');
7492
+ }
7493
+ catch {
7494
+ /* private window or blocked storage: the toggle still works for this visit */
7495
+ }
7496
+ }
7497
+ constructor() {
7498
+ inject(EfShortcutService).register({
7499
+ id: 'shell.toggle-side',
7500
+ keys: 'mod+b',
7501
+ labelKey: 'common_sidebar_toggle',
7502
+ group: 'shortcut_group_general',
7503
+ handler: () => {
7504
+ if (!this.isMobile())
7505
+ this.toggleSide();
7506
+ },
7507
+ });
7508
+ }
7466
7509
  /* ── Mobile chrome ───────────────────────────────────────────
7467
7510
  Tabs and the module sheet live here rather than in a child
7468
7511
  component: content has to be declared once, in one template,
@@ -7519,7 +7562,7 @@ class EfAppShellComponent {
7519
7562
  this.switcherOpen.set(false);
7520
7563
  }
7521
7564
  static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.11", ngImport: i0, type: EfAppShellComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
7522
- static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "21.2.11", type: EfAppShellComponent, isStandalone: true, selector: "ef-app-shell", inputs: { stripe: "stripe" }, host: { properties: { "attr.data-viewport": "viewport()" } }, ngImport: i0, template: "<!-- One layout, one declaration per slot.\n Angular binds projected content to the LAST matching <ng-content> in a\n template, so declaring the same selector once per viewport branch meant the\n branch that was actually rendered on a phone received nothing \u2014 every\n screen came up blank inside working chrome. The layouts differ by CSS and\n by which chrome is rendered, never by where the content is declared. -->\n\n<ef-module-rail class=\"ef-app-shell__rail\">\n <ng-content select=\"[logo]\" logo></ng-content>\n</ef-module-rail>\n\n@if (showSide()) {\n <ef-module-side class=\"ef-app-shell__side\">\n <ng-content select=\"[side-header-meta]\" side-header-meta></ng-content>\n <ng-content select=\"[side-footer]\" side-footer></ng-content>\n </ef-module-side>\n}\n\n<div class=\"ef-app-shell__column\">\n <ef-app-top>\n <!-- The menu takes the breadcrumb's slot on a phone: the breadcrumb is\n hidden there (ef-app-top), so this is the leading position, which is\n where a menu button belongs and where a thumb reaches. -->\n @if (isMobile()) {\n <button\n breadcrumb\n type=\"button\"\n class=\"ef-app-shell__menu\"\n (click)=\"openSwitcher()\"\n [attr.aria-label]=\"'common_modules' | translate\"\n >\n <i class=\"pi pi-bars\" aria-hidden=\"true\"></i>\n </button>\n }\n <ng-content select=\"[breadcrumb]\" breadcrumb></ng-content>\n <ng-content select=\"[search]\" search></ng-content>\n <ng-content select=\"[actions]\" actions></ng-content>\n </ef-app-top>\n\n <ef-app-main [stripe]=\"stripe\">\n <ng-content></ng-content>\n </ef-app-main>\n\n @if (isMobile()) {\n <nav class=\"ef-app-shell__tabs\" [attr.aria-label]=\"'common_modules' | translate\">\n @for (module of tabs(); track module.id) {\n <button\n type=\"button\"\n class=\"ef-app-shell__tab\"\n [class.is-active]=\"activeId() === module.id\"\n [attr.data-module]=\"module.id\"\n [attr.aria-current]=\"activeId() === module.id ? 'page' : null\"\n (click)=\"onSelect(module)\"\n >\n <i class=\"ef-app-shell__tab-icon\" [class]=\"module.icon\" aria-hidden=\"true\"></i>\n <span class=\"ef-app-shell__tab-label\">{{ module.labelKey | translate }}</span>\n </button>\n }\n </nav>\n }\n</div>\n\n<ng-content select=\"[fab]\"></ng-content>\n\n@if (isMobile()) {\n <ef-bottom-sheet [open]=\"switcherOpen()\" (openChange)=\"onSwitcherChange($event)\">\n <!-- The screens first: the tab bar already switches modules, so this is\n the only way to reach anything but a module's default screen. -->\n @for (section of moduleSections(); track section.id) {\n @if (section.labelKey) {\n <h2 class=\"ef-app-shell__sheet-title\">{{ section.labelKey | translate }}</h2>\n }\n <ul class=\"ef-app-shell__sheet-list\">\n @for (item of section.items; track item.id) {\n <li>\n <a\n class=\"ef-app-shell__sheet-item\"\n [routerLink]=\"item.route\"\n routerLinkActive=\"is-active\"\n (click)=\"onNavigate(item)\"\n >\n @if (item.icon) {\n <i [class]=\"item.icon\" aria-hidden=\"true\"></i>\n }\n <span>{{ item.labelKey | translate }}</span>\n @if (item.badge !== undefined && item.badge !== null) {\n <span class=\"ef-app-shell__sheet-badge\">{{ item.badge }}</span>\n }\n </a>\n </li>\n }\n </ul>\n }\n\n <h2 class=\"ef-app-shell__sheet-title\">{{ 'common_modules' | translate }}</h2>\n <ul class=\"ef-app-shell__sheet-list\">\n @for (module of allVisible(); track module.id) {\n <li>\n <button\n type=\"button\"\n class=\"ef-app-shell__sheet-item\"\n [class.is-active]=\"activeId() === module.id\"\n [attr.data-module]=\"module.id\"\n (click)=\"onSelect(module)\"\n >\n <i [class]=\"module.icon\" aria-hidden=\"true\"></i>\n <span>{{ module.labelKey | translate }}</span>\n </button>\n </li>\n }\n </ul>\n\n <!-- App-level entries that live in the rail on a desktop and have nowhere\n else to go on a phone: this sheet is the phone's menu. Declared only\n in the mobile branch, so a desktop simply drops what is projected. -->\n <div class=\"ef-app-shell__sheet-footer\">\n <ng-content select=\"[sheet-footer]\" sheet-footer></ng-content>\n </div>\n </ef-bottom-sheet>\n}\n", styles: ["@charset \"UTF-8\";:host{display:flex;flex-direction:row;width:100%;height:100vh;background:var(--paper);color:var(--text);overflow:hidden}.ef-app-shell__column{display:flex;flex-direction:column;flex:1 1 auto;min-width:0;min-height:0;overflow:hidden}.ef-app-shell__menu{display:inline-flex;align-items:center;justify-content:center;width:var(--hit-touch);height:var(--hit-touch);background:transparent;border:0;border-radius:var(--r-md);color:var(--text);cursor:pointer;font-size:18px}.ef-app-shell__menu:hover{background:var(--paper-alt)}.ef-app-shell__tabs{flex:0 0 auto;display:flex;align-items:stretch;height:64px;padding-bottom:env(safe-area-inset-bottom);background:var(--paper);border-top:1px solid var(--rule)}.ef-app-shell__tab{position:relative;flex:1 1 0;min-width:0;display:inline-flex;flex-direction:column;align-items:center;justify-content:center;gap:2px;background:transparent;border:0;color:var(--text-mute);cursor:pointer;padding:6px 4px;transition:color var(--t-fast) var(--ease-out)}.ef-app-shell__tab.is-active{color:var(--text)}.ef-app-shell__tab.is-active:after{content:\"\";position:absolute;top:0;left:50%;transform:translate(-50%);width:28px;height:3px;background:var(--module);border-radius:0 0 var(--r-sm) var(--r-sm)}.ef-app-shell__tab-icon{font-size:18px;line-height:1}.ef-app-shell__tab-label{font-family:var(--font-ui);font-size:10.5px;font-weight:600;letter-spacing:-.005em;white-space:nowrap;overflow:hidden;text-overflow:ellipsis;max-width:100%}.ef-app-shell__sheet-title{font-size:11.5px;font-weight:700;letter-spacing:.1em;text-transform:uppercase;color:var(--text-mute);margin:0 0 10px;padding-top:16px;border-top:1px solid var(--rule)}.ef-app-shell__sheet-title:first-child{padding-top:0;border-top:0}.ef-app-shell__sheet-list{list-style:none;margin:0 0 4px;padding:0;display:grid;grid-template-columns:repeat(2,1fr);gap:8px}.ef-app-shell__sheet-list+.ef-app-shell__sheet-title{margin-top:8px}.ef-app-shell__sheet-item{display:flex;align-items:center;gap:12px;width:100%;height:var(--hit-touch);padding:0 16px;background:var(--paper-alt);border:0;border-radius:var(--r-md);text-decoration:none;color:var(--text);cursor:pointer;font-family:var(--font-ui);font-size:14px;font-weight:500;text-align:left;transition:background-color var(--t-fast) var(--ease-out)}.ef-app-shell__sheet-item:hover{background:var(--rule)}.ef-app-shell__sheet-item.is-active{border-left:3px solid var(--module);padding-left:13px}@media(max-width:767px){.ef-app-shell__rail{display:none}}.ef-app-shell__sheet-badge{margin-inline-start:auto;font-size:11px;font-weight:700;color:var(--text-mute)}.ef-app-shell__sheet-item.is-active{background:var(--paper);color:var(--text);font-weight:700}.ef-app-shell__sheet-footer{display:grid;gap:8px;margin-top:16px;padding-top:16px;border-top:1px solid var(--rule)}.ef-app-shell__sheet-footer:empty{display:none}\n"], dependencies: [{ kind: "ngmodule", type: CommonModule }, { kind: "component", type: EfModuleRailComponent, selector: "ef-module-rail", inputs: ["badges"] }, { kind: "component", type: EfModuleSideComponent, selector: "ef-module-side" }, { kind: "component", type: EfAppTopComponent, selector: "ef-app-top", inputs: ["themeToggle", "logout"] }, { kind: "component", type: EfAppMainComponent, selector: "ef-app-main", inputs: ["stripe"] }, { kind: "component", type: EfBottomSheetComponent, selector: "ef-bottom-sheet", inputs: ["open", "dismissOnBackdrop"], outputs: ["openChange"] }, { kind: "ngmodule", type: TranslateModule }, { kind: "directive", type: RouterLink, selector: "[routerLink]", inputs: ["target", "queryParams", "fragment", "queryParamsHandling", "state", "info", "relativeTo", "preserveFragment", "skipLocationChange", "replaceUrl", "routerLink"] }, { kind: "pipe", type: i1$1.TranslatePipe, name: "translate" }], changeDetection: i0.ChangeDetectionStrategy.OnPush });
7565
+ static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "21.2.11", type: EfAppShellComponent, isStandalone: true, selector: "ef-app-shell", inputs: { stripe: "stripe" }, host: { properties: { "attr.data-viewport": "viewport()" } }, ngImport: i0, template: "<!-- One layout, one declaration per slot.\n Angular binds projected content to the LAST matching <ng-content> in a\n template, so declaring the same selector once per viewport branch meant the\n branch that was actually rendered on a phone received nothing \u2014 every\n screen came up blank inside working chrome. The layouts differ by CSS and\n by which chrome is rendered, never by where the content is declared. -->\n\n<ef-module-rail class=\"ef-app-shell__rail\">\n <ng-content select=\"[logo]\" logo></ng-content>\n\n <!-- Shows or hides the side panel. In the rail rather than the top bar\n because the rail never folds: the button keeps one position whether\n the panel is open or closed, so a second click needs no search.\n Drawn inline because PrimeIcons has no panel glyph; the divider\n marks the panel, so it is there while the panel is. -->\n @if (showSide()) {\n <button\n rail-footer\n type=\"button\"\n class=\"ef-app-shell__side-toggle\"\n aria-controls=\"ef-app-shell-side\"\n [attr.aria-expanded]=\"!sideCollapsed()\"\n [attr.aria-label]=\"(sideCollapsed() ? 'common_sidebar_show' : 'common_sidebar_hide') | translate\"\n [pTooltip]=\"((sideCollapsed() ? 'common_sidebar_show' : 'common_sidebar_hide') | translate) + ' \u00B7 ' + shortcutHint\"\n tooltipPosition=\"right\"\n (click)=\"toggleSide()\"\n >\n <svg width=\"20\" height=\"20\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\"\n stroke-width=\"1.8\" stroke-linecap=\"round\" stroke-linejoin=\"round\" aria-hidden=\"true\">\n <rect x=\"3\" y=\"4\" width=\"18\" height=\"16\" rx=\"3.5\" />\n @if (!sideCollapsed()) {\n <path d=\"M12 4v16\" />\n }\n </svg>\n </button>\n }\n</ef-module-rail>\n\n@if (showSide()) {\n <!-- Folded by class rather than by @if: the side-footer slot (identity\n menu) is projected into it, and the panel animates closed. `inert`\n takes the hidden links out of the tab order and the a11y tree. -->\n <ef-module-side\n id=\"ef-app-shell-side\"\n class=\"ef-app-shell__side\"\n [class.is-collapsed]=\"sideCollapsed()\"\n [attr.inert]=\"sideCollapsed() ? '' : null\"\n >\n <ng-content select=\"[side-header-meta]\" side-header-meta></ng-content>\n <ng-content select=\"[side-footer]\" side-footer></ng-content>\n </ef-module-side>\n}\n\n<div class=\"ef-app-shell__column\">\n <ef-app-top>\n <!-- The menu takes the breadcrumb's slot on a phone: the breadcrumb is\n hidden there (ef-app-top), so this is the leading position, which is\n where a menu button belongs and where a thumb reaches. -->\n @if (isMobile()) {\n <button\n breadcrumb\n type=\"button\"\n class=\"ef-app-shell__menu\"\n (click)=\"openSwitcher()\"\n [attr.aria-label]=\"'common_modules' | translate\"\n >\n <i class=\"pi pi-bars\" aria-hidden=\"true\"></i>\n </button>\n }\n <ng-content select=\"[breadcrumb]\" breadcrumb></ng-content>\n <ng-content select=\"[search]\" search></ng-content>\n <ng-content select=\"[actions]\" actions></ng-content>\n </ef-app-top>\n\n <ef-app-main [stripe]=\"stripe\">\n <ng-content></ng-content>\n </ef-app-main>\n\n @if (isMobile()) {\n <nav class=\"ef-app-shell__tabs\" [attr.aria-label]=\"'common_modules' | translate\">\n @for (module of tabs(); track module.id) {\n <button\n type=\"button\"\n class=\"ef-app-shell__tab\"\n [class.is-active]=\"activeId() === module.id\"\n [attr.data-module]=\"module.id\"\n [attr.aria-current]=\"activeId() === module.id ? 'page' : null\"\n (click)=\"onSelect(module)\"\n >\n <i class=\"ef-app-shell__tab-icon\" [class]=\"module.icon\" aria-hidden=\"true\"></i>\n <span class=\"ef-app-shell__tab-label\">{{ module.labelKey | translate }}</span>\n </button>\n }\n </nav>\n }\n</div>\n\n<ng-content select=\"[fab]\"></ng-content>\n\n@if (isMobile()) {\n <ef-bottom-sheet [open]=\"switcherOpen()\" (openChange)=\"onSwitcherChange($event)\">\n <!-- The screens first: the tab bar already switches modules, so this is\n the only way to reach anything but a module's default screen. -->\n @for (section of moduleSections(); track section.id) {\n @if (section.labelKey) {\n <h2 class=\"ef-app-shell__sheet-title\">{{ section.labelKey | translate }}</h2>\n }\n <ul class=\"ef-app-shell__sheet-list\">\n @for (item of section.items; track item.id) {\n <li>\n <a\n class=\"ef-app-shell__sheet-item\"\n [routerLink]=\"item.route\"\n routerLinkActive=\"is-active\"\n (click)=\"onNavigate(item)\"\n >\n @if (item.icon) {\n <i [class]=\"item.icon\" aria-hidden=\"true\"></i>\n }\n <span>{{ item.labelKey | translate }}</span>\n @if (item.badge !== undefined && item.badge !== null) {\n <span class=\"ef-app-shell__sheet-badge\">{{ item.badge }}</span>\n }\n </a>\n </li>\n }\n </ul>\n }\n\n <h2 class=\"ef-app-shell__sheet-title\">{{ 'common_modules' | translate }}</h2>\n <ul class=\"ef-app-shell__sheet-list\">\n @for (module of allVisible(); track module.id) {\n <li>\n <button\n type=\"button\"\n class=\"ef-app-shell__sheet-item\"\n [class.is-active]=\"activeId() === module.id\"\n [attr.data-module]=\"module.id\"\n (click)=\"onSelect(module)\"\n >\n <i [class]=\"module.icon\" aria-hidden=\"true\"></i>\n <span>{{ module.labelKey | translate }}</span>\n </button>\n </li>\n }\n </ul>\n\n <!-- App-level entries that live in the rail on a desktop and have nowhere\n else to go on a phone: this sheet is the phone's menu. Declared only\n in the mobile branch, so a desktop simply drops what is projected. -->\n <div class=\"ef-app-shell__sheet-footer\">\n <ng-content select=\"[sheet-footer]\" sheet-footer></ng-content>\n </div>\n </ef-bottom-sheet>\n}\n", styles: ["@charset \"UTF-8\";:host{display:flex;flex-direction:row;width:100%;height:100vh;background:var(--paper);color:var(--text);overflow:hidden}.ef-app-shell__column{display:flex;flex-direction:column;flex:1 1 auto;min-width:0;min-height:0;overflow:hidden}.ef-app-shell__side{overflow:hidden;transition:flex-basis var(--t-fast) var(--ease-out),width var(--t-fast) var(--ease-out)}.ef-app-shell__side.is-collapsed{flex-basis:0;width:0;border-right-width:0}.ef-app-shell__side-toggle{display:grid;place-items:center;flex:0 0 auto;width:44px;height:44px;padding:0;background:transparent;border:0;border-radius:var(--r-md);color:var(--rail-fg-mute);cursor:pointer;transition:background-color var(--t-fast) var(--ease-out),color var(--t-fast) var(--ease-out)}.ef-app-shell__side-toggle:hover{background:var(--rail-hover);color:#fff}.ef-app-shell__side-toggle:focus-visible{outline:2px solid color-mix(in srgb,var(--tenant-300, #b87a99) 80%,transparent);outline-offset:2px}@media(prefers-reduced-motion:reduce){.ef-app-shell__side{transition:none}}.ef-app-shell__menu{display:inline-flex;align-items:center;justify-content:center;width:var(--hit-touch);height:var(--hit-touch);background:transparent;border:0;border-radius:var(--r-md);color:var(--text);cursor:pointer;font-size:18px}.ef-app-shell__menu:hover{background:var(--paper-alt)}.ef-app-shell__tabs{flex:0 0 auto;display:flex;align-items:stretch;height:64px;padding-bottom:env(safe-area-inset-bottom);background:var(--paper);border-top:1px solid var(--rule)}.ef-app-shell__tab{position:relative;flex:1 1 0;min-width:0;display:inline-flex;flex-direction:column;align-items:center;justify-content:center;gap:2px;background:transparent;border:0;color:var(--text-mute);cursor:pointer;padding:6px 4px;transition:color var(--t-fast) var(--ease-out)}.ef-app-shell__tab.is-active{color:var(--text)}.ef-app-shell__tab.is-active:after{content:\"\";position:absolute;top:0;left:50%;transform:translate(-50%);width:28px;height:3px;background:var(--module);border-radius:0 0 var(--r-sm) var(--r-sm)}.ef-app-shell__tab-icon{font-size:18px;line-height:1}.ef-app-shell__tab-label{font-family:var(--font-ui);font-size:10.5px;font-weight:600;letter-spacing:-.005em;white-space:nowrap;overflow:hidden;text-overflow:ellipsis;max-width:100%}.ef-app-shell__sheet-title{font-size:11.5px;font-weight:700;letter-spacing:.1em;text-transform:uppercase;color:var(--text-mute);margin:0 0 10px;padding-top:16px;border-top:1px solid var(--rule)}.ef-app-shell__sheet-title:first-child{padding-top:0;border-top:0}.ef-app-shell__sheet-list{list-style:none;margin:0 0 4px;padding:0;display:grid;grid-template-columns:repeat(2,1fr);gap:8px}.ef-app-shell__sheet-list+.ef-app-shell__sheet-title{margin-top:8px}.ef-app-shell__sheet-item{display:flex;align-items:center;gap:12px;width:100%;height:var(--hit-touch);padding:0 16px;background:var(--paper-alt);border:0;border-radius:var(--r-md);text-decoration:none;color:var(--text);cursor:pointer;font-family:var(--font-ui);font-size:14px;font-weight:500;text-align:left;transition:background-color var(--t-fast) var(--ease-out)}.ef-app-shell__sheet-item:hover{background:var(--rule)}.ef-app-shell__sheet-item.is-active{border-left:3px solid var(--module);padding-left:13px}@media(max-width:767px){.ef-app-shell__rail{display:none}}.ef-app-shell__sheet-badge{margin-inline-start:auto;font-size:11px;font-weight:700;color:var(--text-mute)}.ef-app-shell__sheet-item.is-active{background:var(--paper);color:var(--text);font-weight:700}.ef-app-shell__sheet-footer{display:grid;gap:8px;margin-top:16px;padding-top:16px;border-top:1px solid var(--rule)}.ef-app-shell__sheet-footer:empty{display:none}\n"], dependencies: [{ kind: "ngmodule", type: CommonModule }, { kind: "component", type: EfModuleRailComponent, selector: "ef-module-rail", inputs: ["badges"] }, { kind: "component", type: EfModuleSideComponent, selector: "ef-module-side" }, { kind: "component", type: EfAppTopComponent, selector: "ef-app-top", inputs: ["themeToggle", "logout"] }, { kind: "component", type: EfAppMainComponent, selector: "ef-app-main", inputs: ["stripe"] }, { kind: "component", type: EfBottomSheetComponent, selector: "ef-bottom-sheet", inputs: ["open", "dismissOnBackdrop"], outputs: ["openChange"] }, { kind: "ngmodule", type: TooltipModule }, { kind: "directive", type: i1$5.Tooltip, selector: "[pTooltip]", inputs: ["tooltipPosition", "tooltipEvent", "positionStyle", "tooltipStyleClass", "tooltipZIndex", "escape", "showDelay", "hideDelay", "life", "positionTop", "positionLeft", "autoHide", "fitContent", "hideOnEscape", "showOnEllipsis", "pTooltip", "tooltipDisabled", "tooltipOptions", "appendTo", "ptTooltip", "pTooltipPT", "pTooltipUnstyled"] }, { kind: "ngmodule", type: TranslateModule }, { kind: "directive", type: RouterLink, selector: "[routerLink]", inputs: ["target", "queryParams", "fragment", "queryParamsHandling", "state", "info", "relativeTo", "preserveFragment", "skipLocationChange", "replaceUrl", "routerLink"] }, { kind: "pipe", type: i1$1.TranslatePipe, name: "translate" }], changeDetection: i0.ChangeDetectionStrategy.OnPush });
7523
7566
  }
7524
7567
  i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.11", ngImport: i0, type: EfAppShellComponent, decorators: [{
7525
7568
  type: Component,
@@ -7530,12 +7573,13 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.11", ngImpo
7530
7573
  EfAppTopComponent,
7531
7574
  EfAppMainComponent,
7532
7575
  EfBottomSheetComponent,
7576
+ TooltipModule,
7533
7577
  TranslateModule,
7534
7578
  RouterLink,
7535
7579
  ], host: {
7536
7580
  '[attr.data-viewport]': 'viewport()',
7537
- }, template: "<!-- One layout, one declaration per slot.\n Angular binds projected content to the LAST matching <ng-content> in a\n template, so declaring the same selector once per viewport branch meant the\n branch that was actually rendered on a phone received nothing \u2014 every\n screen came up blank inside working chrome. The layouts differ by CSS and\n by which chrome is rendered, never by where the content is declared. -->\n\n<ef-module-rail class=\"ef-app-shell__rail\">\n <ng-content select=\"[logo]\" logo></ng-content>\n</ef-module-rail>\n\n@if (showSide()) {\n <ef-module-side class=\"ef-app-shell__side\">\n <ng-content select=\"[side-header-meta]\" side-header-meta></ng-content>\n <ng-content select=\"[side-footer]\" side-footer></ng-content>\n </ef-module-side>\n}\n\n<div class=\"ef-app-shell__column\">\n <ef-app-top>\n <!-- The menu takes the breadcrumb's slot on a phone: the breadcrumb is\n hidden there (ef-app-top), so this is the leading position, which is\n where a menu button belongs and where a thumb reaches. -->\n @if (isMobile()) {\n <button\n breadcrumb\n type=\"button\"\n class=\"ef-app-shell__menu\"\n (click)=\"openSwitcher()\"\n [attr.aria-label]=\"'common_modules' | translate\"\n >\n <i class=\"pi pi-bars\" aria-hidden=\"true\"></i>\n </button>\n }\n <ng-content select=\"[breadcrumb]\" breadcrumb></ng-content>\n <ng-content select=\"[search]\" search></ng-content>\n <ng-content select=\"[actions]\" actions></ng-content>\n </ef-app-top>\n\n <ef-app-main [stripe]=\"stripe\">\n <ng-content></ng-content>\n </ef-app-main>\n\n @if (isMobile()) {\n <nav class=\"ef-app-shell__tabs\" [attr.aria-label]=\"'common_modules' | translate\">\n @for (module of tabs(); track module.id) {\n <button\n type=\"button\"\n class=\"ef-app-shell__tab\"\n [class.is-active]=\"activeId() === module.id\"\n [attr.data-module]=\"module.id\"\n [attr.aria-current]=\"activeId() === module.id ? 'page' : null\"\n (click)=\"onSelect(module)\"\n >\n <i class=\"ef-app-shell__tab-icon\" [class]=\"module.icon\" aria-hidden=\"true\"></i>\n <span class=\"ef-app-shell__tab-label\">{{ module.labelKey | translate }}</span>\n </button>\n }\n </nav>\n }\n</div>\n\n<ng-content select=\"[fab]\"></ng-content>\n\n@if (isMobile()) {\n <ef-bottom-sheet [open]=\"switcherOpen()\" (openChange)=\"onSwitcherChange($event)\">\n <!-- The screens first: the tab bar already switches modules, so this is\n the only way to reach anything but a module's default screen. -->\n @for (section of moduleSections(); track section.id) {\n @if (section.labelKey) {\n <h2 class=\"ef-app-shell__sheet-title\">{{ section.labelKey | translate }}</h2>\n }\n <ul class=\"ef-app-shell__sheet-list\">\n @for (item of section.items; track item.id) {\n <li>\n <a\n class=\"ef-app-shell__sheet-item\"\n [routerLink]=\"item.route\"\n routerLinkActive=\"is-active\"\n (click)=\"onNavigate(item)\"\n >\n @if (item.icon) {\n <i [class]=\"item.icon\" aria-hidden=\"true\"></i>\n }\n <span>{{ item.labelKey | translate }}</span>\n @if (item.badge !== undefined && item.badge !== null) {\n <span class=\"ef-app-shell__sheet-badge\">{{ item.badge }}</span>\n }\n </a>\n </li>\n }\n </ul>\n }\n\n <h2 class=\"ef-app-shell__sheet-title\">{{ 'common_modules' | translate }}</h2>\n <ul class=\"ef-app-shell__sheet-list\">\n @for (module of allVisible(); track module.id) {\n <li>\n <button\n type=\"button\"\n class=\"ef-app-shell__sheet-item\"\n [class.is-active]=\"activeId() === module.id\"\n [attr.data-module]=\"module.id\"\n (click)=\"onSelect(module)\"\n >\n <i [class]=\"module.icon\" aria-hidden=\"true\"></i>\n <span>{{ module.labelKey | translate }}</span>\n </button>\n </li>\n }\n </ul>\n\n <!-- App-level entries that live in the rail on a desktop and have nowhere\n else to go on a phone: this sheet is the phone's menu. Declared only\n in the mobile branch, so a desktop simply drops what is projected. -->\n <div class=\"ef-app-shell__sheet-footer\">\n <ng-content select=\"[sheet-footer]\" sheet-footer></ng-content>\n </div>\n </ef-bottom-sheet>\n}\n", styles: ["@charset \"UTF-8\";:host{display:flex;flex-direction:row;width:100%;height:100vh;background:var(--paper);color:var(--text);overflow:hidden}.ef-app-shell__column{display:flex;flex-direction:column;flex:1 1 auto;min-width:0;min-height:0;overflow:hidden}.ef-app-shell__menu{display:inline-flex;align-items:center;justify-content:center;width:var(--hit-touch);height:var(--hit-touch);background:transparent;border:0;border-radius:var(--r-md);color:var(--text);cursor:pointer;font-size:18px}.ef-app-shell__menu:hover{background:var(--paper-alt)}.ef-app-shell__tabs{flex:0 0 auto;display:flex;align-items:stretch;height:64px;padding-bottom:env(safe-area-inset-bottom);background:var(--paper);border-top:1px solid var(--rule)}.ef-app-shell__tab{position:relative;flex:1 1 0;min-width:0;display:inline-flex;flex-direction:column;align-items:center;justify-content:center;gap:2px;background:transparent;border:0;color:var(--text-mute);cursor:pointer;padding:6px 4px;transition:color var(--t-fast) var(--ease-out)}.ef-app-shell__tab.is-active{color:var(--text)}.ef-app-shell__tab.is-active:after{content:\"\";position:absolute;top:0;left:50%;transform:translate(-50%);width:28px;height:3px;background:var(--module);border-radius:0 0 var(--r-sm) var(--r-sm)}.ef-app-shell__tab-icon{font-size:18px;line-height:1}.ef-app-shell__tab-label{font-family:var(--font-ui);font-size:10.5px;font-weight:600;letter-spacing:-.005em;white-space:nowrap;overflow:hidden;text-overflow:ellipsis;max-width:100%}.ef-app-shell__sheet-title{font-size:11.5px;font-weight:700;letter-spacing:.1em;text-transform:uppercase;color:var(--text-mute);margin:0 0 10px;padding-top:16px;border-top:1px solid var(--rule)}.ef-app-shell__sheet-title:first-child{padding-top:0;border-top:0}.ef-app-shell__sheet-list{list-style:none;margin:0 0 4px;padding:0;display:grid;grid-template-columns:repeat(2,1fr);gap:8px}.ef-app-shell__sheet-list+.ef-app-shell__sheet-title{margin-top:8px}.ef-app-shell__sheet-item{display:flex;align-items:center;gap:12px;width:100%;height:var(--hit-touch);padding:0 16px;background:var(--paper-alt);border:0;border-radius:var(--r-md);text-decoration:none;color:var(--text);cursor:pointer;font-family:var(--font-ui);font-size:14px;font-weight:500;text-align:left;transition:background-color var(--t-fast) var(--ease-out)}.ef-app-shell__sheet-item:hover{background:var(--rule)}.ef-app-shell__sheet-item.is-active{border-left:3px solid var(--module);padding-left:13px}@media(max-width:767px){.ef-app-shell__rail{display:none}}.ef-app-shell__sheet-badge{margin-inline-start:auto;font-size:11px;font-weight:700;color:var(--text-mute)}.ef-app-shell__sheet-item.is-active{background:var(--paper);color:var(--text);font-weight:700}.ef-app-shell__sheet-footer{display:grid;gap:8px;margin-top:16px;padding-top:16px;border-top:1px solid var(--rule)}.ef-app-shell__sheet-footer:empty{display:none}\n"] }]
7538
- }], propDecorators: { stripe: [{
7581
+ }, template: "<!-- One layout, one declaration per slot.\n Angular binds projected content to the LAST matching <ng-content> in a\n template, so declaring the same selector once per viewport branch meant the\n branch that was actually rendered on a phone received nothing \u2014 every\n screen came up blank inside working chrome. The layouts differ by CSS and\n by which chrome is rendered, never by where the content is declared. -->\n\n<ef-module-rail class=\"ef-app-shell__rail\">\n <ng-content select=\"[logo]\" logo></ng-content>\n\n <!-- Shows or hides the side panel. In the rail rather than the top bar\n because the rail never folds: the button keeps one position whether\n the panel is open or closed, so a second click needs no search.\n Drawn inline because PrimeIcons has no panel glyph; the divider\n marks the panel, so it is there while the panel is. -->\n @if (showSide()) {\n <button\n rail-footer\n type=\"button\"\n class=\"ef-app-shell__side-toggle\"\n aria-controls=\"ef-app-shell-side\"\n [attr.aria-expanded]=\"!sideCollapsed()\"\n [attr.aria-label]=\"(sideCollapsed() ? 'common_sidebar_show' : 'common_sidebar_hide') | translate\"\n [pTooltip]=\"((sideCollapsed() ? 'common_sidebar_show' : 'common_sidebar_hide') | translate) + ' \u00B7 ' + shortcutHint\"\n tooltipPosition=\"right\"\n (click)=\"toggleSide()\"\n >\n <svg width=\"20\" height=\"20\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\"\n stroke-width=\"1.8\" stroke-linecap=\"round\" stroke-linejoin=\"round\" aria-hidden=\"true\">\n <rect x=\"3\" y=\"4\" width=\"18\" height=\"16\" rx=\"3.5\" />\n @if (!sideCollapsed()) {\n <path d=\"M12 4v16\" />\n }\n </svg>\n </button>\n }\n</ef-module-rail>\n\n@if (showSide()) {\n <!-- Folded by class rather than by @if: the side-footer slot (identity\n menu) is projected into it, and the panel animates closed. `inert`\n takes the hidden links out of the tab order and the a11y tree. -->\n <ef-module-side\n id=\"ef-app-shell-side\"\n class=\"ef-app-shell__side\"\n [class.is-collapsed]=\"sideCollapsed()\"\n [attr.inert]=\"sideCollapsed() ? '' : null\"\n >\n <ng-content select=\"[side-header-meta]\" side-header-meta></ng-content>\n <ng-content select=\"[side-footer]\" side-footer></ng-content>\n </ef-module-side>\n}\n\n<div class=\"ef-app-shell__column\">\n <ef-app-top>\n <!-- The menu takes the breadcrumb's slot on a phone: the breadcrumb is\n hidden there (ef-app-top), so this is the leading position, which is\n where a menu button belongs and where a thumb reaches. -->\n @if (isMobile()) {\n <button\n breadcrumb\n type=\"button\"\n class=\"ef-app-shell__menu\"\n (click)=\"openSwitcher()\"\n [attr.aria-label]=\"'common_modules' | translate\"\n >\n <i class=\"pi pi-bars\" aria-hidden=\"true\"></i>\n </button>\n }\n <ng-content select=\"[breadcrumb]\" breadcrumb></ng-content>\n <ng-content select=\"[search]\" search></ng-content>\n <ng-content select=\"[actions]\" actions></ng-content>\n </ef-app-top>\n\n <ef-app-main [stripe]=\"stripe\">\n <ng-content></ng-content>\n </ef-app-main>\n\n @if (isMobile()) {\n <nav class=\"ef-app-shell__tabs\" [attr.aria-label]=\"'common_modules' | translate\">\n @for (module of tabs(); track module.id) {\n <button\n type=\"button\"\n class=\"ef-app-shell__tab\"\n [class.is-active]=\"activeId() === module.id\"\n [attr.data-module]=\"module.id\"\n [attr.aria-current]=\"activeId() === module.id ? 'page' : null\"\n (click)=\"onSelect(module)\"\n >\n <i class=\"ef-app-shell__tab-icon\" [class]=\"module.icon\" aria-hidden=\"true\"></i>\n <span class=\"ef-app-shell__tab-label\">{{ module.labelKey | translate }}</span>\n </button>\n }\n </nav>\n }\n</div>\n\n<ng-content select=\"[fab]\"></ng-content>\n\n@if (isMobile()) {\n <ef-bottom-sheet [open]=\"switcherOpen()\" (openChange)=\"onSwitcherChange($event)\">\n <!-- The screens first: the tab bar already switches modules, so this is\n the only way to reach anything but a module's default screen. -->\n @for (section of moduleSections(); track section.id) {\n @if (section.labelKey) {\n <h2 class=\"ef-app-shell__sheet-title\">{{ section.labelKey | translate }}</h2>\n }\n <ul class=\"ef-app-shell__sheet-list\">\n @for (item of section.items; track item.id) {\n <li>\n <a\n class=\"ef-app-shell__sheet-item\"\n [routerLink]=\"item.route\"\n routerLinkActive=\"is-active\"\n (click)=\"onNavigate(item)\"\n >\n @if (item.icon) {\n <i [class]=\"item.icon\" aria-hidden=\"true\"></i>\n }\n <span>{{ item.labelKey | translate }}</span>\n @if (item.badge !== undefined && item.badge !== null) {\n <span class=\"ef-app-shell__sheet-badge\">{{ item.badge }}</span>\n }\n </a>\n </li>\n }\n </ul>\n }\n\n <h2 class=\"ef-app-shell__sheet-title\">{{ 'common_modules' | translate }}</h2>\n <ul class=\"ef-app-shell__sheet-list\">\n @for (module of allVisible(); track module.id) {\n <li>\n <button\n type=\"button\"\n class=\"ef-app-shell__sheet-item\"\n [class.is-active]=\"activeId() === module.id\"\n [attr.data-module]=\"module.id\"\n (click)=\"onSelect(module)\"\n >\n <i [class]=\"module.icon\" aria-hidden=\"true\"></i>\n <span>{{ module.labelKey | translate }}</span>\n </button>\n </li>\n }\n </ul>\n\n <!-- App-level entries that live in the rail on a desktop and have nowhere\n else to go on a phone: this sheet is the phone's menu. Declared only\n in the mobile branch, so a desktop simply drops what is projected. -->\n <div class=\"ef-app-shell__sheet-footer\">\n <ng-content select=\"[sheet-footer]\" sheet-footer></ng-content>\n </div>\n </ef-bottom-sheet>\n}\n", styles: ["@charset \"UTF-8\";:host{display:flex;flex-direction:row;width:100%;height:100vh;background:var(--paper);color:var(--text);overflow:hidden}.ef-app-shell__column{display:flex;flex-direction:column;flex:1 1 auto;min-width:0;min-height:0;overflow:hidden}.ef-app-shell__side{overflow:hidden;transition:flex-basis var(--t-fast) var(--ease-out),width var(--t-fast) var(--ease-out)}.ef-app-shell__side.is-collapsed{flex-basis:0;width:0;border-right-width:0}.ef-app-shell__side-toggle{display:grid;place-items:center;flex:0 0 auto;width:44px;height:44px;padding:0;background:transparent;border:0;border-radius:var(--r-md);color:var(--rail-fg-mute);cursor:pointer;transition:background-color var(--t-fast) var(--ease-out),color var(--t-fast) var(--ease-out)}.ef-app-shell__side-toggle:hover{background:var(--rail-hover);color:#fff}.ef-app-shell__side-toggle:focus-visible{outline:2px solid color-mix(in srgb,var(--tenant-300, #b87a99) 80%,transparent);outline-offset:2px}@media(prefers-reduced-motion:reduce){.ef-app-shell__side{transition:none}}.ef-app-shell__menu{display:inline-flex;align-items:center;justify-content:center;width:var(--hit-touch);height:var(--hit-touch);background:transparent;border:0;border-radius:var(--r-md);color:var(--text);cursor:pointer;font-size:18px}.ef-app-shell__menu:hover{background:var(--paper-alt)}.ef-app-shell__tabs{flex:0 0 auto;display:flex;align-items:stretch;height:64px;padding-bottom:env(safe-area-inset-bottom);background:var(--paper);border-top:1px solid var(--rule)}.ef-app-shell__tab{position:relative;flex:1 1 0;min-width:0;display:inline-flex;flex-direction:column;align-items:center;justify-content:center;gap:2px;background:transparent;border:0;color:var(--text-mute);cursor:pointer;padding:6px 4px;transition:color var(--t-fast) var(--ease-out)}.ef-app-shell__tab.is-active{color:var(--text)}.ef-app-shell__tab.is-active:after{content:\"\";position:absolute;top:0;left:50%;transform:translate(-50%);width:28px;height:3px;background:var(--module);border-radius:0 0 var(--r-sm) var(--r-sm)}.ef-app-shell__tab-icon{font-size:18px;line-height:1}.ef-app-shell__tab-label{font-family:var(--font-ui);font-size:10.5px;font-weight:600;letter-spacing:-.005em;white-space:nowrap;overflow:hidden;text-overflow:ellipsis;max-width:100%}.ef-app-shell__sheet-title{font-size:11.5px;font-weight:700;letter-spacing:.1em;text-transform:uppercase;color:var(--text-mute);margin:0 0 10px;padding-top:16px;border-top:1px solid var(--rule)}.ef-app-shell__sheet-title:first-child{padding-top:0;border-top:0}.ef-app-shell__sheet-list{list-style:none;margin:0 0 4px;padding:0;display:grid;grid-template-columns:repeat(2,1fr);gap:8px}.ef-app-shell__sheet-list+.ef-app-shell__sheet-title{margin-top:8px}.ef-app-shell__sheet-item{display:flex;align-items:center;gap:12px;width:100%;height:var(--hit-touch);padding:0 16px;background:var(--paper-alt);border:0;border-radius:var(--r-md);text-decoration:none;color:var(--text);cursor:pointer;font-family:var(--font-ui);font-size:14px;font-weight:500;text-align:left;transition:background-color var(--t-fast) var(--ease-out)}.ef-app-shell__sheet-item:hover{background:var(--rule)}.ef-app-shell__sheet-item.is-active{border-left:3px solid var(--module);padding-left:13px}@media(max-width:767px){.ef-app-shell__rail{display:none}}.ef-app-shell__sheet-badge{margin-inline-start:auto;font-size:11px;font-weight:700;color:var(--text-mute)}.ef-app-shell__sheet-item.is-active{background:var(--paper);color:var(--text);font-weight:700}.ef-app-shell__sheet-footer{display:grid;gap:8px;margin-top:16px;padding-top:16px;border-top:1px solid var(--rule)}.ef-app-shell__sheet-footer:empty{display:none}\n"] }]
7582
+ }], ctorParameters: () => [], propDecorators: { stripe: [{
7539
7583
  type: Input
7540
7584
  }] } });
7541
7585
 
@@ -7980,6 +8024,8 @@ class EfProfileChipComponent {
7980
8024
  tone = 'tenant';
7981
8025
  /** Render as a non-interactive container (no hover/focus, no click). */
7982
8026
  readonly = false;
8027
+ /** Avatar only, no name or role: for a trigger that sits in a toolbar. */
8028
+ compact = false;
7983
8029
  clickEvent = new EventEmitter();
7984
8030
  get computedInitial() {
7985
8031
  /* An explicit `initial` is taken verbatim — callers pass real initials
@@ -7998,11 +8044,11 @@ class EfProfileChipComponent {
7998
8044
  }
7999
8045
  }
8000
8046
  static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.11", ngImport: i0, type: EfProfileChipComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
8001
- static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "21.2.11", type: EfProfileChipComponent, isStandalone: true, selector: "ef-profile-chip", inputs: { name: "name", role: "role", roleKey: "roleKey", initial: "initial", tone: "tone", readonly: ["readonly", "readonly", booleanAttribute] }, outputs: { clickEvent: "clickEvent" }, ngImport: i0, template: "<button\n type=\"button\"\n class=\"ef-profile-chip\"\n [class.is-tenant]=\"tone === 'tenant'\"\n [class.is-readonly]=\"readonly\"\n [attr.aria-label]=\"name || null\"\n [attr.tabindex]=\"readonly ? -1 : null\"\n (click)=\"handleClick($event)\"\n>\n <span class=\"ef-profile-chip__avatar\" aria-hidden=\"true\">{{ computedInitial }}</span>\n <span class=\"ef-profile-chip__text\">\n @if (name) {\n <span class=\"ef-profile-chip__name\">{{ name }}</span>\n }\n @if (roleKey || role) {\n <span class=\"ef-profile-chip__role\">\n @if (roleKey) {\n {{ roleKey | translate }}\n } @else {\n {{ role }}\n }\n </span>\n }\n </span>\n</button>\n", styles: ["@charset \"UTF-8\";:host{display:block}.ef-profile-chip{display:inline-flex;align-items:center;gap:8px;width:100%;padding:8px 10px;background:transparent;border:0;border-radius:var(--r-md, 8px);color:var(--text);cursor:pointer;text-align:start;font-family:inherit;transition:background var(--t-fast, .14s) var(--ease-out, ease-out)}.ef-profile-chip:hover:not(.is-readonly){background:color-mix(in srgb,var(--ink-active, #0f1115) 6%,transparent)}.ef-profile-chip:focus-visible{outline:2px solid color-mix(in srgb,var(--tenant-400, #6b7280) 60%,transparent);outline-offset:1px}.ef-profile-chip.is-readonly{cursor:default}.ef-profile-chip__avatar{display:inline-flex;align-items:center;justify-content:center;flex:0 0 32px;width:32px;height:32px;border-radius:var(--r-pill, 999px);background:var(--ink-active, #0f1115);color:var(--paper, #fff);font-family:var(--font-display);font-variation-settings:\"opsz\" 12,\"wght\" 700,\"wdth\" 80;font-size:12px;line-height:1;letter-spacing:-.01em}.is-tenant .ef-profile-chip__avatar{background:var(--tenant-500);color:var(--on-tenant)}.ef-profile-chip__text{display:flex;flex-direction:column;min-width:0;font-size:12px;line-height:1.3}.ef-profile-chip__name{font-weight:700;color:var(--text);overflow:hidden;text-overflow:ellipsis;white-space:nowrap}.ef-profile-chip__role{color:var(--text-mute);overflow:hidden;text-overflow:ellipsis;white-space:nowrap}\n"], dependencies: [{ kind: "ngmodule", type: CommonModule }, { kind: "ngmodule", type: TranslateModule }, { kind: "pipe", type: i1$1.TranslatePipe, name: "translate" }], changeDetection: i0.ChangeDetectionStrategy.OnPush });
8047
+ static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "21.2.11", type: EfProfileChipComponent, isStandalone: true, selector: "ef-profile-chip", inputs: { name: "name", role: "role", roleKey: "roleKey", initial: "initial", tone: "tone", readonly: ["readonly", "readonly", booleanAttribute], compact: ["compact", "compact", booleanAttribute] }, outputs: { clickEvent: "clickEvent" }, ngImport: i0, template: "<button\n type=\"button\"\n class=\"ef-profile-chip\"\n [class.is-tenant]=\"tone === 'tenant'\"\n [class.is-readonly]=\"readonly\"\n [class.is-compact]=\"compact\"\n [attr.aria-label]=\"name || null\"\n [attr.tabindex]=\"readonly ? -1 : null\"\n (click)=\"handleClick($event)\"\n>\n <span class=\"ef-profile-chip__avatar\" aria-hidden=\"true\">{{ computedInitial }}</span>\n @if (!compact) {\n <span class=\"ef-profile-chip__text\">\n @if (name) {\n <span class=\"ef-profile-chip__name\">{{ name }}</span>\n }\n @if (roleKey || role) {\n <span class=\"ef-profile-chip__role\">\n @if (roleKey) {\n {{ roleKey | translate }}\n } @else {\n {{ role }}\n }\n </span>\n }\n </span>\n }\n</button>\n", styles: ["@charset \"UTF-8\";:host{display:block}.ef-profile-chip{display:inline-flex;align-items:center;gap:8px;width:100%;padding:8px 10px;background:transparent;border:0;border-radius:var(--r-md, 8px);color:var(--text);cursor:pointer;text-align:start;font-family:inherit;transition:background var(--t-fast, .14s) var(--ease-out, ease-out)}.ef-profile-chip:hover:not(.is-readonly){background:color-mix(in srgb,var(--ink-active, #0f1115) 6%,transparent)}.ef-profile-chip:focus-visible{outline:2px solid color-mix(in srgb,var(--tenant-400, #6b7280) 60%,transparent);outline-offset:1px}.ef-profile-chip.is-readonly{cursor:default}.ef-profile-chip.is-compact{width:auto;padding:2px;border-radius:var(--r-pill, 999px)}.ef-profile-chip__avatar{display:inline-flex;align-items:center;justify-content:center;flex:0 0 32px;width:32px;height:32px;border-radius:var(--r-pill, 999px);background:var(--ink-active, #0f1115);color:var(--paper, #fff);font-family:var(--font-display);font-variation-settings:\"opsz\" 12,\"wght\" 700,\"wdth\" 80;font-size:12px;line-height:1;letter-spacing:-.01em}.is-tenant .ef-profile-chip__avatar{background:var(--tenant-500);color:var(--on-tenant)}.ef-profile-chip__text{display:flex;flex-direction:column;min-width:0;font-size:12px;line-height:1.3}.ef-profile-chip__name{font-weight:700;color:var(--text);overflow:hidden;text-overflow:ellipsis;white-space:nowrap}.ef-profile-chip__role{color:var(--text-mute);overflow:hidden;text-overflow:ellipsis;white-space:nowrap}\n"], dependencies: [{ kind: "ngmodule", type: CommonModule }, { kind: "ngmodule", type: TranslateModule }, { kind: "pipe", type: i1$1.TranslatePipe, name: "translate" }], changeDetection: i0.ChangeDetectionStrategy.OnPush });
8002
8048
  }
8003
8049
  i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.11", ngImport: i0, type: EfProfileChipComponent, decorators: [{
8004
8050
  type: Component,
8005
- args: [{ selector: 'ef-profile-chip', standalone: true, changeDetection: ChangeDetectionStrategy.OnPush, imports: [CommonModule, TranslateModule], template: "<button\n type=\"button\"\n class=\"ef-profile-chip\"\n [class.is-tenant]=\"tone === 'tenant'\"\n [class.is-readonly]=\"readonly\"\n [attr.aria-label]=\"name || null\"\n [attr.tabindex]=\"readonly ? -1 : null\"\n (click)=\"handleClick($event)\"\n>\n <span class=\"ef-profile-chip__avatar\" aria-hidden=\"true\">{{ computedInitial }}</span>\n <span class=\"ef-profile-chip__text\">\n @if (name) {\n <span class=\"ef-profile-chip__name\">{{ name }}</span>\n }\n @if (roleKey || role) {\n <span class=\"ef-profile-chip__role\">\n @if (roleKey) {\n {{ roleKey | translate }}\n } @else {\n {{ role }}\n }\n </span>\n }\n </span>\n</button>\n", styles: ["@charset \"UTF-8\";:host{display:block}.ef-profile-chip{display:inline-flex;align-items:center;gap:8px;width:100%;padding:8px 10px;background:transparent;border:0;border-radius:var(--r-md, 8px);color:var(--text);cursor:pointer;text-align:start;font-family:inherit;transition:background var(--t-fast, .14s) var(--ease-out, ease-out)}.ef-profile-chip:hover:not(.is-readonly){background:color-mix(in srgb,var(--ink-active, #0f1115) 6%,transparent)}.ef-profile-chip:focus-visible{outline:2px solid color-mix(in srgb,var(--tenant-400, #6b7280) 60%,transparent);outline-offset:1px}.ef-profile-chip.is-readonly{cursor:default}.ef-profile-chip__avatar{display:inline-flex;align-items:center;justify-content:center;flex:0 0 32px;width:32px;height:32px;border-radius:var(--r-pill, 999px);background:var(--ink-active, #0f1115);color:var(--paper, #fff);font-family:var(--font-display);font-variation-settings:\"opsz\" 12,\"wght\" 700,\"wdth\" 80;font-size:12px;line-height:1;letter-spacing:-.01em}.is-tenant .ef-profile-chip__avatar{background:var(--tenant-500);color:var(--on-tenant)}.ef-profile-chip__text{display:flex;flex-direction:column;min-width:0;font-size:12px;line-height:1.3}.ef-profile-chip__name{font-weight:700;color:var(--text);overflow:hidden;text-overflow:ellipsis;white-space:nowrap}.ef-profile-chip__role{color:var(--text-mute);overflow:hidden;text-overflow:ellipsis;white-space:nowrap}\n"] }]
8051
+ args: [{ selector: 'ef-profile-chip', standalone: true, changeDetection: ChangeDetectionStrategy.OnPush, imports: [CommonModule, TranslateModule], template: "<button\n type=\"button\"\n class=\"ef-profile-chip\"\n [class.is-tenant]=\"tone === 'tenant'\"\n [class.is-readonly]=\"readonly\"\n [class.is-compact]=\"compact\"\n [attr.aria-label]=\"name || null\"\n [attr.tabindex]=\"readonly ? -1 : null\"\n (click)=\"handleClick($event)\"\n>\n <span class=\"ef-profile-chip__avatar\" aria-hidden=\"true\">{{ computedInitial }}</span>\n @if (!compact) {\n <span class=\"ef-profile-chip__text\">\n @if (name) {\n <span class=\"ef-profile-chip__name\">{{ name }}</span>\n }\n @if (roleKey || role) {\n <span class=\"ef-profile-chip__role\">\n @if (roleKey) {\n {{ roleKey | translate }}\n } @else {\n {{ role }}\n }\n </span>\n }\n </span>\n }\n</button>\n", styles: ["@charset \"UTF-8\";:host{display:block}.ef-profile-chip{display:inline-flex;align-items:center;gap:8px;width:100%;padding:8px 10px;background:transparent;border:0;border-radius:var(--r-md, 8px);color:var(--text);cursor:pointer;text-align:start;font-family:inherit;transition:background var(--t-fast, .14s) var(--ease-out, ease-out)}.ef-profile-chip:hover:not(.is-readonly){background:color-mix(in srgb,var(--ink-active, #0f1115) 6%,transparent)}.ef-profile-chip:focus-visible{outline:2px solid color-mix(in srgb,var(--tenant-400, #6b7280) 60%,transparent);outline-offset:1px}.ef-profile-chip.is-readonly{cursor:default}.ef-profile-chip.is-compact{width:auto;padding:2px;border-radius:var(--r-pill, 999px)}.ef-profile-chip__avatar{display:inline-flex;align-items:center;justify-content:center;flex:0 0 32px;width:32px;height:32px;border-radius:var(--r-pill, 999px);background:var(--ink-active, #0f1115);color:var(--paper, #fff);font-family:var(--font-display);font-variation-settings:\"opsz\" 12,\"wght\" 700,\"wdth\" 80;font-size:12px;line-height:1;letter-spacing:-.01em}.is-tenant .ef-profile-chip__avatar{background:var(--tenant-500);color:var(--on-tenant)}.ef-profile-chip__text{display:flex;flex-direction:column;min-width:0;font-size:12px;line-height:1.3}.ef-profile-chip__name{font-weight:700;color:var(--text);overflow:hidden;text-overflow:ellipsis;white-space:nowrap}.ef-profile-chip__role{color:var(--text-mute);overflow:hidden;text-overflow:ellipsis;white-space:nowrap}\n"] }]
8006
8052
  }], propDecorators: { name: [{
8007
8053
  type: Input
8008
8054
  }], role: [{
@@ -8016,6 +8062,9 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.11", ngImpo
8016
8062
  }], readonly: [{
8017
8063
  type: Input,
8018
8064
  args: [{ transform: booleanAttribute }]
8065
+ }], compact: [{
8066
+ type: Input,
8067
+ args: [{ transform: booleanAttribute }]
8019
8068
  }], clickEvent: [{
8020
8069
  type: Output
8021
8070
  }] } });
@@ -8051,6 +8100,8 @@ class EfProfileMenuComponent {
8051
8100
  initial = input('', ...(ngDevMode ? [{ debugName: "initial" }] : /* istanbul ignore next */ []));
8052
8101
  tone = input('tenant', ...(ngDevMode ? [{ debugName: "tone" }] : /* istanbul ignore next */ []));
8053
8102
  items = input([], ...(ngDevMode ? [{ debugName: "items" }] : /* istanbul ignore next */ []));
8103
+ /** `avatar` is the chip without its text, for the top bar while the
8104
+ * side panel (and the full chip in its footer) is folded away. */
8054
8105
  variant = input('chip', ...(ngDevMode ? [{ debugName: "variant" }] : /* istanbul ignore next */ []));
8055
8106
  itemSelected = output();
8056
8107
  /** Id of the one expanded group, or null. One at a time: a menu that
@@ -8079,11 +8130,11 @@ class EfProfileMenuComponent {
8079
8130
  popover?.hide();
8080
8131
  }
8081
8132
  static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.11", ngImport: i0, type: EfProfileMenuComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
8082
- static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "21.2.11", type: EfProfileMenuComponent, isStandalone: true, selector: "ef-profile-menu", inputs: { name: { classPropertyName: "name", publicName: "name", isSignal: true, isRequired: false, transformFunction: null }, secondary: { classPropertyName: "secondary", publicName: "secondary", isSignal: true, isRequired: false, transformFunction: null }, role: { classPropertyName: "role", publicName: "role", isSignal: true, isRequired: false, transformFunction: null }, initial: { classPropertyName: "initial", publicName: "initial", isSignal: true, isRequired: false, transformFunction: null }, tone: { classPropertyName: "tone", publicName: "tone", isSignal: true, isRequired: false, transformFunction: null }, items: { classPropertyName: "items", publicName: "items", isSignal: true, isRequired: false, transformFunction: null }, variant: { classPropertyName: "variant", publicName: "variant", isSignal: true, isRequired: false, transformFunction: null } }, outputs: { itemSelected: "itemSelected" }, ngImport: i0, template: "@if (variant() === 'chip') {\n <ef-profile-chip\n [name]=\"name()\"\n [role]=\"chipRole()\"\n [initial]=\"initial()\"\n [tone]=\"tone()\"\n (clickEvent)=\"op.toggle($event)\"\n />\n <!-- The popover is reduced to a placement mechanism: `.ef-menu` inside it\n draws the surface, so `ef-menu-popover` strips PrimeNG's own panel and\n arrow rather than letting two panels stack. -->\n <p-popover #op styleClass=\"ef-menu-popover\" appendTo=\"body\">\n <ng-container *ngTemplateOutlet=\"panel; context: { $implicit: op }\" />\n </p-popover>\n} @else {\n <ng-container *ngTemplateOutlet=\"panel\" />\n}\n\n<ng-template #panel let-op>\n <div class=\"ef-menu\" role=\"menu\" [attr.aria-label]=\"name() || null\">\n @if (name() || secondary()) {\n <div class=\"ef-menu__head\">\n @if (name()) {\n <span class=\"ef-menu__head-name\">{{ name() }}</span>\n }\n @if (secondary()) {\n <span class=\"ef-menu__head-sub\">{{ secondary() }}</span>\n }\n </div>\n }\n\n @for (item of items(); track item.id) {\n @if (item.groupStart) {\n <div class=\"ef-menu__divider\" role=\"separator\"></div>\n }\n\n <button\n type=\"button\"\n class=\"ef-menu__item\"\n role=\"menuitem\"\n [class.danger]=\"item.severity === 'danger'\"\n [attr.aria-expanded]=\"item.children?.length ? isExpanded(item.id) : null\"\n (click)=\"select(item, op)\"\n >\n @if (item.icon) {\n <i [class]=\"'ico ' + item.icon\" aria-hidden=\"true\"></i>\n }\n <span class=\"ef-menu__label\">{{ item.labelKey | translate }}</span>\n @if (item.badge !== undefined && item.badge !== null) {\n <span class=\"ef-menu__badge\">{{ item.badge }}</span>\n }\n @if (item.children?.length) {\n <i\n class=\"ef-menu__caret pi\"\n [class.pi-chevron-down]=\"!isExpanded(item.id)\"\n [class.pi-chevron-up]=\"isExpanded(item.id)\"\n aria-hidden=\"true\"\n ></i>\n }\n </button>\n\n @if (item.children?.length && isExpanded(item.id)) {\n <div class=\"ef-menu__sublist\" role=\"group\">\n @for (child of item.children; track child.id) {\n <button\n type=\"button\"\n class=\"ef-menu__item\"\n role=\"menuitem\"\n (click)=\"select(child, op)\"\n >\n @if (child.icon) {\n <i [class]=\"'ico ' + child.icon\" aria-hidden=\"true\"></i>\n }\n <span class=\"ef-menu__label\">{{ child.labelKey | translate }}</span>\n </button>\n }\n </div>\n }\n }\n </div>\n</ng-template>\n", styles: [":host{display:block;min-width:0}.ef-menu{min-width:232px;max-width:288px;max-height:calc(100vh - 32px);overflow-y:auto}@media(max-width:767px){.ef-menu{min-width:0}.ef-menu__item{min-height:var(--hit-touch);padding-block:0;font-size:14px}}\n"], dependencies: [{ kind: "ngmodule", type: CommonModule }, { kind: "directive", type: i1$3.NgTemplateOutlet, selector: "[ngTemplateOutlet]", inputs: ["ngTemplateOutletContext", "ngTemplateOutlet", "ngTemplateOutletInjector"] }, { kind: "ngmodule", type: TranslateModule }, { kind: "ngmodule", type: PopoverModule }, { kind: "component", type: i2$4.Popover, selector: "p-popover", inputs: ["ariaLabel", "ariaLabelledBy", "dismissable", "style", "styleClass", "appendTo", "autoZIndex", "ariaCloseLabel", "baseZIndex", "focusOnShow", "showTransitionOptions", "hideTransitionOptions", "motionOptions"], outputs: ["onShow", "onHide"] }, { kind: "component", type: EfProfileChipComponent, selector: "ef-profile-chip", inputs: ["name", "role", "roleKey", "initial", "tone", "readonly"], outputs: ["clickEvent"] }, { kind: "pipe", type: i1$1.TranslatePipe, name: "translate" }], changeDetection: i0.ChangeDetectionStrategy.OnPush });
8133
+ static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "21.2.11", type: EfProfileMenuComponent, isStandalone: true, selector: "ef-profile-menu", inputs: { name: { classPropertyName: "name", publicName: "name", isSignal: true, isRequired: false, transformFunction: null }, secondary: { classPropertyName: "secondary", publicName: "secondary", isSignal: true, isRequired: false, transformFunction: null }, role: { classPropertyName: "role", publicName: "role", isSignal: true, isRequired: false, transformFunction: null }, initial: { classPropertyName: "initial", publicName: "initial", isSignal: true, isRequired: false, transformFunction: null }, tone: { classPropertyName: "tone", publicName: "tone", isSignal: true, isRequired: false, transformFunction: null }, items: { classPropertyName: "items", publicName: "items", isSignal: true, isRequired: false, transformFunction: null }, variant: { classPropertyName: "variant", publicName: "variant", isSignal: true, isRequired: false, transformFunction: null } }, outputs: { itemSelected: "itemSelected" }, ngImport: i0, template: "@if (variant() !== 'list') {\n <ef-profile-chip\n [name]=\"name()\"\n [role]=\"chipRole()\"\n [initial]=\"initial()\"\n [tone]=\"tone()\"\n [compact]=\"variant() === 'avatar'\"\n (clickEvent)=\"op.toggle($event)\"\n />\n <!-- The popover is reduced to a placement mechanism: `.ef-menu` inside it\n draws the surface, so `ef-menu-popover` strips PrimeNG's own panel and\n arrow rather than letting two panels stack. -->\n <p-popover #op styleClass=\"ef-menu-popover\" appendTo=\"body\">\n <ng-container *ngTemplateOutlet=\"panel; context: { $implicit: op }\" />\n </p-popover>\n} @else {\n <ng-container *ngTemplateOutlet=\"panel\" />\n}\n\n<ng-template #panel let-op>\n <div class=\"ef-menu\" role=\"menu\" [attr.aria-label]=\"name() || null\">\n @if (name() || secondary()) {\n <div class=\"ef-menu__head\">\n @if (name()) {\n <span class=\"ef-menu__head-name\">{{ name() }}</span>\n }\n @if (secondary()) {\n <span class=\"ef-menu__head-sub\">{{ secondary() }}</span>\n }\n </div>\n }\n\n @for (item of items(); track item.id) {\n @if (item.groupStart) {\n <div class=\"ef-menu__divider\" role=\"separator\"></div>\n }\n\n <button\n type=\"button\"\n class=\"ef-menu__item\"\n role=\"menuitem\"\n [class.danger]=\"item.severity === 'danger'\"\n [attr.aria-expanded]=\"item.children?.length ? isExpanded(item.id) : null\"\n (click)=\"select(item, op)\"\n >\n @if (item.icon) {\n <i [class]=\"'ico ' + item.icon\" aria-hidden=\"true\"></i>\n }\n <span class=\"ef-menu__label\">{{ item.labelKey | translate }}</span>\n @if (item.badge !== undefined && item.badge !== null) {\n <span class=\"ef-menu__badge\">{{ item.badge }}</span>\n }\n @if (item.children?.length) {\n <i\n class=\"ef-menu__caret pi\"\n [class.pi-chevron-down]=\"!isExpanded(item.id)\"\n [class.pi-chevron-up]=\"isExpanded(item.id)\"\n aria-hidden=\"true\"\n ></i>\n }\n </button>\n\n @if (item.children?.length && isExpanded(item.id)) {\n <div class=\"ef-menu__sublist\" role=\"group\">\n @for (child of item.children; track child.id) {\n <button\n type=\"button\"\n class=\"ef-menu__item\"\n role=\"menuitem\"\n (click)=\"select(child, op)\"\n >\n @if (child.icon) {\n <i [class]=\"'ico ' + child.icon\" aria-hidden=\"true\"></i>\n }\n <span class=\"ef-menu__label\">{{ child.labelKey | translate }}</span>\n </button>\n }\n </div>\n }\n }\n </div>\n</ng-template>\n", styles: [":host{display:block;min-width:0}.ef-menu{min-width:232px;max-width:288px;max-height:calc(100vh - 32px);overflow-y:auto}@media(max-width:767px){.ef-menu{min-width:0}.ef-menu__item{min-height:var(--hit-touch);padding-block:0;font-size:14px}}\n"], dependencies: [{ kind: "ngmodule", type: CommonModule }, { kind: "directive", type: i1$3.NgTemplateOutlet, selector: "[ngTemplateOutlet]", inputs: ["ngTemplateOutletContext", "ngTemplateOutlet", "ngTemplateOutletInjector"] }, { kind: "ngmodule", type: TranslateModule }, { kind: "ngmodule", type: PopoverModule }, { kind: "component", type: i2$4.Popover, selector: "p-popover", inputs: ["ariaLabel", "ariaLabelledBy", "dismissable", "style", "styleClass", "appendTo", "autoZIndex", "ariaCloseLabel", "baseZIndex", "focusOnShow", "showTransitionOptions", "hideTransitionOptions", "motionOptions"], outputs: ["onShow", "onHide"] }, { kind: "component", type: EfProfileChipComponent, selector: "ef-profile-chip", inputs: ["name", "role", "roleKey", "initial", "tone", "readonly", "compact"], outputs: ["clickEvent"] }, { kind: "pipe", type: i1$1.TranslatePipe, name: "translate" }], changeDetection: i0.ChangeDetectionStrategy.OnPush });
8083
8134
  }
8084
8135
  i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.11", ngImport: i0, type: EfProfileMenuComponent, decorators: [{
8085
8136
  type: Component,
8086
- args: [{ selector: 'ef-profile-menu', standalone: true, imports: [CommonModule, TranslateModule, PopoverModule, EfProfileChipComponent], changeDetection: ChangeDetectionStrategy.OnPush, template: "@if (variant() === 'chip') {\n <ef-profile-chip\n [name]=\"name()\"\n [role]=\"chipRole()\"\n [initial]=\"initial()\"\n [tone]=\"tone()\"\n (clickEvent)=\"op.toggle($event)\"\n />\n <!-- The popover is reduced to a placement mechanism: `.ef-menu` inside it\n draws the surface, so `ef-menu-popover` strips PrimeNG's own panel and\n arrow rather than letting two panels stack. -->\n <p-popover #op styleClass=\"ef-menu-popover\" appendTo=\"body\">\n <ng-container *ngTemplateOutlet=\"panel; context: { $implicit: op }\" />\n </p-popover>\n} @else {\n <ng-container *ngTemplateOutlet=\"panel\" />\n}\n\n<ng-template #panel let-op>\n <div class=\"ef-menu\" role=\"menu\" [attr.aria-label]=\"name() || null\">\n @if (name() || secondary()) {\n <div class=\"ef-menu__head\">\n @if (name()) {\n <span class=\"ef-menu__head-name\">{{ name() }}</span>\n }\n @if (secondary()) {\n <span class=\"ef-menu__head-sub\">{{ secondary() }}</span>\n }\n </div>\n }\n\n @for (item of items(); track item.id) {\n @if (item.groupStart) {\n <div class=\"ef-menu__divider\" role=\"separator\"></div>\n }\n\n <button\n type=\"button\"\n class=\"ef-menu__item\"\n role=\"menuitem\"\n [class.danger]=\"item.severity === 'danger'\"\n [attr.aria-expanded]=\"item.children?.length ? isExpanded(item.id) : null\"\n (click)=\"select(item, op)\"\n >\n @if (item.icon) {\n <i [class]=\"'ico ' + item.icon\" aria-hidden=\"true\"></i>\n }\n <span class=\"ef-menu__label\">{{ item.labelKey | translate }}</span>\n @if (item.badge !== undefined && item.badge !== null) {\n <span class=\"ef-menu__badge\">{{ item.badge }}</span>\n }\n @if (item.children?.length) {\n <i\n class=\"ef-menu__caret pi\"\n [class.pi-chevron-down]=\"!isExpanded(item.id)\"\n [class.pi-chevron-up]=\"isExpanded(item.id)\"\n aria-hidden=\"true\"\n ></i>\n }\n </button>\n\n @if (item.children?.length && isExpanded(item.id)) {\n <div class=\"ef-menu__sublist\" role=\"group\">\n @for (child of item.children; track child.id) {\n <button\n type=\"button\"\n class=\"ef-menu__item\"\n role=\"menuitem\"\n (click)=\"select(child, op)\"\n >\n @if (child.icon) {\n <i [class]=\"'ico ' + child.icon\" aria-hidden=\"true\"></i>\n }\n <span class=\"ef-menu__label\">{{ child.labelKey | translate }}</span>\n </button>\n }\n </div>\n }\n }\n </div>\n</ng-template>\n", styles: [":host{display:block;min-width:0}.ef-menu{min-width:232px;max-width:288px;max-height:calc(100vh - 32px);overflow-y:auto}@media(max-width:767px){.ef-menu{min-width:0}.ef-menu__item{min-height:var(--hit-touch);padding-block:0;font-size:14px}}\n"] }]
8137
+ args: [{ selector: 'ef-profile-menu', standalone: true, imports: [CommonModule, TranslateModule, PopoverModule, EfProfileChipComponent], changeDetection: ChangeDetectionStrategy.OnPush, template: "@if (variant() !== 'list') {\n <ef-profile-chip\n [name]=\"name()\"\n [role]=\"chipRole()\"\n [initial]=\"initial()\"\n [tone]=\"tone()\"\n [compact]=\"variant() === 'avatar'\"\n (clickEvent)=\"op.toggle($event)\"\n />\n <!-- The popover is reduced to a placement mechanism: `.ef-menu` inside it\n draws the surface, so `ef-menu-popover` strips PrimeNG's own panel and\n arrow rather than letting two panels stack. -->\n <p-popover #op styleClass=\"ef-menu-popover\" appendTo=\"body\">\n <ng-container *ngTemplateOutlet=\"panel; context: { $implicit: op }\" />\n </p-popover>\n} @else {\n <ng-container *ngTemplateOutlet=\"panel\" />\n}\n\n<ng-template #panel let-op>\n <div class=\"ef-menu\" role=\"menu\" [attr.aria-label]=\"name() || null\">\n @if (name() || secondary()) {\n <div class=\"ef-menu__head\">\n @if (name()) {\n <span class=\"ef-menu__head-name\">{{ name() }}</span>\n }\n @if (secondary()) {\n <span class=\"ef-menu__head-sub\">{{ secondary() }}</span>\n }\n </div>\n }\n\n @for (item of items(); track item.id) {\n @if (item.groupStart) {\n <div class=\"ef-menu__divider\" role=\"separator\"></div>\n }\n\n <button\n type=\"button\"\n class=\"ef-menu__item\"\n role=\"menuitem\"\n [class.danger]=\"item.severity === 'danger'\"\n [attr.aria-expanded]=\"item.children?.length ? isExpanded(item.id) : null\"\n (click)=\"select(item, op)\"\n >\n @if (item.icon) {\n <i [class]=\"'ico ' + item.icon\" aria-hidden=\"true\"></i>\n }\n <span class=\"ef-menu__label\">{{ item.labelKey | translate }}</span>\n @if (item.badge !== undefined && item.badge !== null) {\n <span class=\"ef-menu__badge\">{{ item.badge }}</span>\n }\n @if (item.children?.length) {\n <i\n class=\"ef-menu__caret pi\"\n [class.pi-chevron-down]=\"!isExpanded(item.id)\"\n [class.pi-chevron-up]=\"isExpanded(item.id)\"\n aria-hidden=\"true\"\n ></i>\n }\n </button>\n\n @if (item.children?.length && isExpanded(item.id)) {\n <div class=\"ef-menu__sublist\" role=\"group\">\n @for (child of item.children; track child.id) {\n <button\n type=\"button\"\n class=\"ef-menu__item\"\n role=\"menuitem\"\n (click)=\"select(child, op)\"\n >\n @if (child.icon) {\n <i [class]=\"'ico ' + child.icon\" aria-hidden=\"true\"></i>\n }\n <span class=\"ef-menu__label\">{{ child.labelKey | translate }}</span>\n </button>\n }\n </div>\n }\n }\n </div>\n</ng-template>\n", styles: [":host{display:block;min-width:0}.ef-menu{min-width:232px;max-width:288px;max-height:calc(100vh - 32px);overflow-y:auto}@media(max-width:767px){.ef-menu{min-width:0}.ef-menu__item{min-height:var(--hit-touch);padding-block:0;font-size:14px}}\n"] }]
8087
8138
  }], propDecorators: { name: [{ type: i0.Input, args: [{ isSignal: true, alias: "name", required: false }] }], secondary: [{ type: i0.Input, args: [{ isSignal: true, alias: "secondary", required: false }] }], role: [{ type: i0.Input, args: [{ isSignal: true, alias: "role", required: false }] }], initial: [{ type: i0.Input, args: [{ isSignal: true, alias: "initial", required: false }] }], tone: [{ type: i0.Input, args: [{ isSignal: true, alias: "tone", required: false }] }], items: [{ type: i0.Input, args: [{ isSignal: true, alias: "items", required: false }] }], variant: [{ type: i0.Input, args: [{ isSignal: true, alias: "variant", required: false }] }], itemSelected: [{ type: i0.Output, args: ["itemSelected"] }] } });
8088
8139
 
8089
8140
  class EfBlockUiComponent {