@neuravision/ng-construct 0.3.2 → 0.3.6

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.
@@ -1,5 +1,5 @@
1
1
  import * as i0 from '@angular/core';
2
- import { input, output, signal, computed, ChangeDetectionStrategy, Component, inject, forwardRef, model, booleanAttribute, viewChild, contentChildren, effect, contentChild, ElementRef, TemplateRef, Directive, Injectable, viewChildren, Renderer2, InjectionToken, DOCUMENT, numberAttribute, Pipe } from '@angular/core';
2
+ import { input, output, signal, computed, ChangeDetectionStrategy, Component, inject, forwardRef, model, booleanAttribute, viewChild, contentChildren, effect, DOCUMENT, contentChild, ElementRef, TemplateRef, Directive, Injectable, viewChildren, Renderer2, InjectionToken, numberAttribute, Pipe } from '@angular/core';
3
3
  import { NG_VALUE_ACCESSOR } from '@angular/forms';
4
4
  import { NgTemplateOutlet } from '@angular/common';
5
5
  import { RouterLink, RouterLinkActive } from '@angular/router';
@@ -354,6 +354,464 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.1.2", ngImpor
354
354
  `, styles: [":host{display:block}\n"] }]
355
355
  }], propDecorators: { multi: [{ type: i0.Input, args: [{ isSignal: true, alias: "multi", required: false }] }], bordered: [{ type: i0.Input, args: [{ isSignal: true, alias: "bordered", required: false }] }], items: [{ type: i0.ContentChildren, args: [i0.forwardRef(() => AfAccordionItemComponent), { isSignal: true }] }] } });
356
356
 
357
+ /**
358
+ * Skip-link component for keyboard-only navigation bypass.
359
+ *
360
+ * Renders an anchor that is visually hidden off-screen and slides into view
361
+ * when focused. On activation it moves focus to the target element, allowing
362
+ * keyboard users to skip repetitive navigation blocks.
363
+ *
364
+ * Must be placed as the first focusable element in the document.
365
+ *
366
+ * @example
367
+ * <af-skip-link target="main-content" />
368
+ * <nav>…</nav>
369
+ * <main id="main-content" tabindex="-1">…</main>
370
+ */
371
+ class AfSkipLinkComponent {
372
+ /** ID of the element to skip to (without the leading `#`). */
373
+ target = input.required(...(ngDevMode ? [{ debugName: "target" }] : []));
374
+ /** Visible label text shown when the link receives focus. */
375
+ label = input('Skip to main content', ...(ngDevMode ? [{ debugName: "label" }] : []));
376
+ document = inject(DOCUMENT);
377
+ /**
378
+ * Moves focus to the target element so keyboard navigation
379
+ * continues from there instead of the top of the page.
380
+ */
381
+ focusTarget(event) {
382
+ event.preventDefault();
383
+ const el = this.document.getElementById(this.target());
384
+ if (!el) {
385
+ return;
386
+ }
387
+ if (!el.hasAttribute('tabindex')) {
388
+ el.setAttribute('tabindex', '-1');
389
+ }
390
+ el.focus();
391
+ }
392
+ static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.1.2", ngImport: i0, type: AfSkipLinkComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
393
+ static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.1.0", version: "21.1.2", type: AfSkipLinkComponent, isStandalone: true, selector: "af-skip-link", inputs: { target: { classPropertyName: "target", publicName: "target", isSignal: true, isRequired: true, transformFunction: null }, label: { classPropertyName: "label", publicName: "label", isSignal: true, isRequired: false, transformFunction: null } }, ngImport: i0, template: `
394
+ <a
395
+ class="ct-skip-link"
396
+ [attr.href]="'#' + target()"
397
+ (click)="focusTarget($event)"
398
+ >
399
+ {{ label() }}
400
+ </a>
401
+ `, isInline: true, styles: [":host{display:contents}\n"], changeDetection: i0.ChangeDetectionStrategy.OnPush });
402
+ }
403
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.1.2", ngImport: i0, type: AfSkipLinkComponent, decorators: [{
404
+ type: Component,
405
+ args: [{ selector: 'af-skip-link', changeDetection: ChangeDetectionStrategy.OnPush, template: `
406
+ <a
407
+ class="ct-skip-link"
408
+ [attr.href]="'#' + target()"
409
+ (click)="focusTarget($event)"
410
+ >
411
+ {{ label() }}
412
+ </a>
413
+ `, styles: [":host{display:contents}\n"] }]
414
+ }], propDecorators: { target: [{ type: i0.Input, args: [{ isSignal: true, alias: "target", required: true }] }], label: [{ type: i0.Input, args: [{ isSignal: true, alias: "label", required: false }] }] } });
415
+
416
+ /**
417
+ * Page header rendered inside the main content area of an App Shell.
418
+ *
419
+ * Displays breadcrumbs, page title, and actions in a flex row.
420
+ * Place inside `<af-app-shell>` without any slot attribute so it
421
+ * projects into the main area.
422
+ *
423
+ * @example
424
+ * <af-app-shell>
425
+ * <af-app-shell-page-header sticky>
426
+ * <nav aria-label="Breadcrumb">Home / Dashboard</nav>
427
+ * <h1>Dashboard</h1>
428
+ * <button class="ct-button">New Item</button>
429
+ * </af-app-shell-page-header>
430
+ * <p>Main content…</p>
431
+ * </af-app-shell>
432
+ */
433
+ class AfAppShellPageHeaderComponent {
434
+ /** Pin the page header to the top of the scrollable main area. */
435
+ sticky = input(false, { ...(ngDevMode ? { debugName: "sticky" } : {}), transform: booleanAttribute });
436
+ classes = computed(() => {
437
+ const c = ['ct-app-shell__page-header'];
438
+ if (this.sticky()) {
439
+ c.push('ct-app-shell__page-header--sticky');
440
+ }
441
+ return c.join(' ');
442
+ }, ...(ngDevMode ? [{ debugName: "classes" }] : []));
443
+ static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.1.2", ngImport: i0, type: AfAppShellPageHeaderComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
444
+ static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.1.0", version: "21.1.2", type: AfAppShellPageHeaderComponent, isStandalone: true, selector: "af-app-shell-page-header", inputs: { sticky: { classPropertyName: "sticky", publicName: "sticky", isSignal: true, isRequired: false, transformFunction: null } }, ngImport: i0, template: `
445
+ <div [class]="classes()">
446
+ <ng-content />
447
+ </div>
448
+ `, isInline: true, styles: [":host{display:contents}\n"], changeDetection: i0.ChangeDetectionStrategy.OnPush });
449
+ }
450
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.1.2", ngImport: i0, type: AfAppShellPageHeaderComponent, decorators: [{
451
+ type: Component,
452
+ args: [{ selector: 'af-app-shell-page-header', changeDetection: ChangeDetectionStrategy.OnPush, template: `
453
+ <div [class]="classes()">
454
+ <ng-content />
455
+ </div>
456
+ `, styles: [":host{display:contents}\n"] }]
457
+ }], propDecorators: { sticky: [{ type: i0.Input, args: [{ isSignal: true, alias: "sticky", required: false }] }] } });
458
+ /**
459
+ * Classic CSS-Grid App Shell that orchestrates header, sidebar,
460
+ * main content, optional panel, and footer.
461
+ *
462
+ * Wraps the `ct-app-shell` CSS component from the Construct Design System.
463
+ * Sidebar and panel states are two-way bindable via `model()` signals.
464
+ *
465
+ * Content projection slots:
466
+ * - `[header]` — Navbar / top bar
467
+ * - `[sidebar]` — Navigation sidebar
468
+ * - `[panel]` — Right-side contextual panel
469
+ * - `[footer]` — Footer area
470
+ * - `[bottomNav]` — Mobile bottom navigation (requires `bottomNav` modifier)
471
+ * - *(default)* — Main content (including `<af-app-shell-page-header>`)
472
+ *
473
+ * @example
474
+ * <af-app-shell [(sidebarState)]="sidebarState" [(panelState)]="panelState" sidebarFullHeight>
475
+ * <af-navbar header ariaLabel="Main">…</af-navbar>
476
+ * <af-sidebar sidebar ariaLabel="Navigation">…</af-sidebar>
477
+ * <af-app-shell-page-header sticky>
478
+ * <h1>Dashboard</h1>
479
+ * </af-app-shell-page-header>
480
+ * <p>Content goes here</p>
481
+ * <div panel>Inspector</div>
482
+ * <footer footer>&copy; 2026</footer>
483
+ * </af-app-shell>
484
+ */
485
+ class AfAppShellComponent {
486
+ /** Current sidebar state — two-way bindable. */
487
+ sidebarState = model('expanded', ...(ngDevMode ? [{ debugName: "sidebarState" }] : []));
488
+ /** Current panel state — two-way bindable. */
489
+ panelState = model('closed', ...(ngDevMode ? [{ debugName: "panelState" }] : []));
490
+ /** Remove the sidebar column entirely. */
491
+ noSidebar = input(false, { ...(ngDevMode ? { debugName: "noSidebar" } : {}), transform: booleanAttribute });
492
+ /** Place the sidebar on the right side. */
493
+ sidebarRight = input(false, { ...(ngDevMode ? { debugName: "sidebarRight" } : {}), transform: booleanAttribute });
494
+ /** Sidebar spans the full viewport height (header sits beside it). */
495
+ sidebarFullHeight = input(false, { ...(ngDevMode ? { debugName: "sidebarFullHeight" } : {}), transform: booleanAttribute });
496
+ /** Stick the footer to the bottom with a top border. */
497
+ footerSticky = input(false, { ...(ngDevMode ? { debugName: "footerSticky" } : {}), transform: booleanAttribute });
498
+ /** Enable bottom navigation on mobile (hides sidebar and footer). */
499
+ bottomNav = input(false, { ...(ngDevMode ? { debugName: "bottomNav" } : {}), transform: booleanAttribute });
500
+ /** Accessible label for the sidebar landmark. */
501
+ sidebarLabel = input('Site navigation', ...(ngDevMode ? [{ debugName: "sidebarLabel" }] : []));
502
+ /** Accessible label for the panel landmark. */
503
+ panelLabel = input('Details', ...(ngDevMode ? [{ debugName: "panelLabel" }] : []));
504
+ /** ID of the main content element (used by skip-link). */
505
+ mainId = input('main-content', ...(ngDevMode ? [{ debugName: "mainId" }] : []));
506
+ /** Visible text of the skip-link. */
507
+ skipLinkLabel = input('Skip to content', ...(ngDevMode ? [{ debugName: "skipLinkLabel" }] : []));
508
+ shellClasses = computed(() => {
509
+ const classes = ['ct-app-shell'];
510
+ if (this.noSidebar()) {
511
+ classes.push('ct-app-shell--no-sidebar');
512
+ }
513
+ if (this.sidebarRight()) {
514
+ classes.push('ct-app-shell--sidebar-right');
515
+ }
516
+ if (this.sidebarFullHeight()) {
517
+ classes.push('ct-app-shell--sidebar-full-height');
518
+ }
519
+ if (this.footerSticky()) {
520
+ classes.push('ct-app-shell--footer-sticky');
521
+ }
522
+ if (this.bottomNav()) {
523
+ classes.push('ct-app-shell--bottom-nav');
524
+ }
525
+ return classes.join(' ');
526
+ }, ...(ngDevMode ? [{ debugName: "shellClasses" }] : []));
527
+ /** Dismiss the mobile sidebar overlay. */
528
+ onBackdropClick() {
529
+ this.sidebarState.set('hidden');
530
+ }
531
+ static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.1.2", ngImport: i0, type: AfAppShellComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
532
+ static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.1.0", version: "21.1.2", type: AfAppShellComponent, isStandalone: true, selector: "af-app-shell", inputs: { sidebarState: { classPropertyName: "sidebarState", publicName: "sidebarState", isSignal: true, isRequired: false, transformFunction: null }, panelState: { classPropertyName: "panelState", publicName: "panelState", isSignal: true, isRequired: false, transformFunction: null }, noSidebar: { classPropertyName: "noSidebar", publicName: "noSidebar", isSignal: true, isRequired: false, transformFunction: null }, sidebarRight: { classPropertyName: "sidebarRight", publicName: "sidebarRight", isSignal: true, isRequired: false, transformFunction: null }, sidebarFullHeight: { classPropertyName: "sidebarFullHeight", publicName: "sidebarFullHeight", isSignal: true, isRequired: false, transformFunction: null }, footerSticky: { classPropertyName: "footerSticky", publicName: "footerSticky", isSignal: true, isRequired: false, transformFunction: null }, bottomNav: { classPropertyName: "bottomNav", publicName: "bottomNav", isSignal: true, isRequired: false, transformFunction: null }, sidebarLabel: { classPropertyName: "sidebarLabel", publicName: "sidebarLabel", isSignal: true, isRequired: false, transformFunction: null }, panelLabel: { classPropertyName: "panelLabel", publicName: "panelLabel", isSignal: true, isRequired: false, transformFunction: null }, mainId: { classPropertyName: "mainId", publicName: "mainId", isSignal: true, isRequired: false, transformFunction: null }, skipLinkLabel: { classPropertyName: "skipLinkLabel", publicName: "skipLinkLabel", isSignal: true, isRequired: false, transformFunction: null } }, outputs: { sidebarState: "sidebarStateChange", panelState: "panelStateChange" }, ngImport: i0, template: `
533
+ <div
534
+ [class]="shellClasses()"
535
+ [attr.data-sidebar-state]="sidebarState()"
536
+ [attr.data-panel-state]="panelState()">
537
+ <af-skip-link [target]="mainId()" [label]="skipLinkLabel()" />
538
+
539
+ <header class="ct-app-shell__header">
540
+ <ng-content select="[header]" />
541
+ </header>
542
+
543
+ <aside class="ct-app-shell__sidebar" [attr.aria-label]="sidebarLabel()">
544
+ <ng-content select="[sidebar]" />
545
+ </aside>
546
+
547
+ <main class="ct-app-shell__main" [id]="mainId()" tabindex="0">
548
+ <ng-content />
549
+ </main>
550
+
551
+ <aside class="ct-app-shell__panel" [attr.aria-label]="panelLabel()">
552
+ <ng-content select="[panel]" />
553
+ </aside>
554
+
555
+ <footer class="ct-app-shell__footer">
556
+ <ng-content select="[footer]" />
557
+ </footer>
558
+
559
+ <div class="ct-app-shell__bottom-nav">
560
+ <ng-content select="[bottomNav]" />
561
+ </div>
562
+
563
+ <div
564
+ class="ct-app-shell__backdrop"
565
+ (click)="onBackdropClick()"
566
+ aria-hidden="true"></div>
567
+ </div>
568
+ `, isInline: true, styles: [":host{display:contents}\n"], dependencies: [{ kind: "component", type: AfSkipLinkComponent, selector: "af-skip-link", inputs: ["target", "label"] }], changeDetection: i0.ChangeDetectionStrategy.OnPush });
569
+ }
570
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.1.2", ngImport: i0, type: AfAppShellComponent, decorators: [{
571
+ type: Component,
572
+ args: [{ selector: 'af-app-shell', changeDetection: ChangeDetectionStrategy.OnPush, imports: [AfSkipLinkComponent], template: `
573
+ <div
574
+ [class]="shellClasses()"
575
+ [attr.data-sidebar-state]="sidebarState()"
576
+ [attr.data-panel-state]="panelState()">
577
+ <af-skip-link [target]="mainId()" [label]="skipLinkLabel()" />
578
+
579
+ <header class="ct-app-shell__header">
580
+ <ng-content select="[header]" />
581
+ </header>
582
+
583
+ <aside class="ct-app-shell__sidebar" [attr.aria-label]="sidebarLabel()">
584
+ <ng-content select="[sidebar]" />
585
+ </aside>
586
+
587
+ <main class="ct-app-shell__main" [id]="mainId()" tabindex="0">
588
+ <ng-content />
589
+ </main>
590
+
591
+ <aside class="ct-app-shell__panel" [attr.aria-label]="panelLabel()">
592
+ <ng-content select="[panel]" />
593
+ </aside>
594
+
595
+ <footer class="ct-app-shell__footer">
596
+ <ng-content select="[footer]" />
597
+ </footer>
598
+
599
+ <div class="ct-app-shell__bottom-nav">
600
+ <ng-content select="[bottomNav]" />
601
+ </div>
602
+
603
+ <div
604
+ class="ct-app-shell__backdrop"
605
+ (click)="onBackdropClick()"
606
+ aria-hidden="true"></div>
607
+ </div>
608
+ `, styles: [":host{display:contents}\n"] }]
609
+ }], propDecorators: { sidebarState: [{ type: i0.Input, args: [{ isSignal: true, alias: "sidebarState", required: false }] }, { type: i0.Output, args: ["sidebarStateChange"] }], panelState: [{ type: i0.Input, args: [{ isSignal: true, alias: "panelState", required: false }] }, { type: i0.Output, args: ["panelStateChange"] }], noSidebar: [{ type: i0.Input, args: [{ isSignal: true, alias: "noSidebar", required: false }] }], sidebarRight: [{ type: i0.Input, args: [{ isSignal: true, alias: "sidebarRight", required: false }] }], sidebarFullHeight: [{ type: i0.Input, args: [{ isSignal: true, alias: "sidebarFullHeight", required: false }] }], footerSticky: [{ type: i0.Input, args: [{ isSignal: true, alias: "footerSticky", required: false }] }], bottomNav: [{ type: i0.Input, args: [{ isSignal: true, alias: "bottomNav", required: false }] }], sidebarLabel: [{ type: i0.Input, args: [{ isSignal: true, alias: "sidebarLabel", required: false }] }], panelLabel: [{ type: i0.Input, args: [{ isSignal: true, alias: "panelLabel", required: false }] }], mainId: [{ type: i0.Input, args: [{ isSignal: true, alias: "mainId", required: false }] }], skipLinkLabel: [{ type: i0.Input, args: [{ isSignal: true, alias: "skipLinkLabel", required: false }] }] } });
610
+
611
+ /**
612
+ * Toolbar rendered inside the main content area of an App Shell V2.
613
+ *
614
+ * Replaces the classic full-width page header with a toolbar row
615
+ * for breadcrumbs, page title, and actions. Place inside
616
+ * `<af-app-shell-v2>` without any slot attribute so it projects
617
+ * into the main area.
618
+ *
619
+ * @example
620
+ * <af-app-shell-v2>
621
+ * <af-app-shell-v2-toolbar sticky>
622
+ * <nav aria-label="Breadcrumb">Home / Dashboard</nav>
623
+ * <div>
624
+ * <button class="ct-button">Export</button>
625
+ * </div>
626
+ * </af-app-shell-v2-toolbar>
627
+ * <p>Main content…</p>
628
+ * </af-app-shell-v2>
629
+ */
630
+ class AfAppShellV2ToolbarComponent {
631
+ /** Pin the toolbar to the top of the scrollable main area. */
632
+ sticky = input(false, { ...(ngDevMode ? { debugName: "sticky" } : {}), transform: booleanAttribute });
633
+ classes = computed(() => {
634
+ const c = ['ct-app-shell-v2__toolbar'];
635
+ if (this.sticky()) {
636
+ c.push('ct-app-shell-v2__toolbar--sticky');
637
+ }
638
+ return c.join(' ');
639
+ }, ...(ngDevMode ? [{ debugName: "classes" }] : []));
640
+ static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.1.2", ngImport: i0, type: AfAppShellV2ToolbarComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
641
+ static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.1.0", version: "21.1.2", type: AfAppShellV2ToolbarComponent, isStandalone: true, selector: "af-app-shell-v2-toolbar", inputs: { sticky: { classPropertyName: "sticky", publicName: "sticky", isSignal: true, isRequired: false, transformFunction: null } }, ngImport: i0, template: `
642
+ <div [class]="classes()">
643
+ <ng-content />
644
+ </div>
645
+ `, isInline: true, styles: [":host{display:contents}\n"], changeDetection: i0.ChangeDetectionStrategy.OnPush });
646
+ }
647
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.1.2", ngImport: i0, type: AfAppShellV2ToolbarComponent, decorators: [{
648
+ type: Component,
649
+ args: [{ selector: 'af-app-shell-v2-toolbar', changeDetection: ChangeDetectionStrategy.OnPush, template: `
650
+ <div [class]="classes()">
651
+ <ng-content />
652
+ </div>
653
+ `, styles: [":host{display:contents}\n"] }]
654
+ }], propDecorators: { sticky: [{ type: i0.Input, args: [{ isSignal: true, alias: "sticky", required: false }] }] } });
655
+ /**
656
+ * Floating-canvas App Shell with elevated surfaces, rounded corners,
657
+ * and optional glass/branded modifiers.
658
+ *
659
+ * Wraps the `ct-app-shell-v2` CSS component from the Construct Design System.
660
+ * Sidebar and panel states are two-way bindable via `model()` signals.
661
+ *
662
+ * Content projection slots:
663
+ * - `[header]` — Optional floating header bar (requires `withHeader` input)
664
+ * - `[sidebar]` — Floating sidebar surface
665
+ * - `[panel]` — Right-side contextual panel (inside body flex container)
666
+ * - `[footer]` — Footer inside the main area
667
+ * - *(default)* — Main content (including `<af-app-shell-v2-toolbar>`)
668
+ *
669
+ * @example
670
+ * <af-app-shell-v2
671
+ * [(sidebarState)]="sidebarState"
672
+ * [(panelState)]="panelState"
673
+ * withHeader
674
+ * sidebarBranded
675
+ * glass>
676
+ * <af-navbar header ariaLabel="Main">…</af-navbar>
677
+ * <af-sidebar sidebar ariaLabel="Navigation">…</af-sidebar>
678
+ * <af-app-shell-v2-toolbar sticky>
679
+ * <h1>Dashboard</h1>
680
+ * </af-app-shell-v2-toolbar>
681
+ * <p>Content goes here</p>
682
+ * <div panel>Inspector</div>
683
+ * <footer footer>&copy; 2026</footer>
684
+ * </af-app-shell-v2>
685
+ */
686
+ class AfAppShellV2Component {
687
+ /** Current sidebar state — two-way bindable. */
688
+ sidebarState = model('expanded', ...(ngDevMode ? [{ debugName: "sidebarState" }] : []));
689
+ /** Current panel state — two-way bindable. */
690
+ panelState = model('closed', ...(ngDevMode ? [{ debugName: "panelState" }] : []));
691
+ /** Remove the sidebar entirely. */
692
+ noSidebar = input(false, { ...(ngDevMode ? { debugName: "noSidebar" } : {}), transform: booleanAttribute });
693
+ /** Place the sidebar on the right side. */
694
+ sidebarRight = input(false, { ...(ngDevMode ? { debugName: "sidebarRight" } : {}), transform: booleanAttribute });
695
+ /** Sidebar spans the full viewport height (header sits beside it). */
696
+ sidebarFullHeight = input(false, { ...(ngDevMode ? { debugName: "sidebarFullHeight" } : {}), transform: booleanAttribute });
697
+ /** Show the optional floating header bar. */
698
+ withHeader = input(false, { ...(ngDevMode ? { debugName: "withHeader" } : {}), transform: booleanAttribute });
699
+ /** Dark-branded sidebar (Slack / Linear / Discord aesthetic). */
700
+ sidebarBranded = input(false, { ...(ngDevMode ? { debugName: "sidebarBranded" } : {}), transform: booleanAttribute });
701
+ /** Frosted glass morphism effect on all floating surfaces. */
702
+ glass = input(false, { ...(ngDevMode ? { debugName: "glass" } : {}), transform: booleanAttribute });
703
+ /** Accessible label for the sidebar landmark. */
704
+ sidebarLabel = input('Site navigation', ...(ngDevMode ? [{ debugName: "sidebarLabel" }] : []));
705
+ /** Accessible label for the panel landmark. */
706
+ panelLabel = input('Details', ...(ngDevMode ? [{ debugName: "panelLabel" }] : []));
707
+ /** ID of the main content element (used by skip-link). */
708
+ mainId = input('main-content', ...(ngDevMode ? [{ debugName: "mainId" }] : []));
709
+ /** Visible text of the skip-link. */
710
+ skipLinkLabel = input('Skip to content', ...(ngDevMode ? [{ debugName: "skipLinkLabel" }] : []));
711
+ shellClasses = computed(() => {
712
+ const classes = ['ct-app-shell-v2'];
713
+ if (this.noSidebar()) {
714
+ classes.push('ct-app-shell-v2--no-sidebar');
715
+ }
716
+ if (this.sidebarRight()) {
717
+ classes.push('ct-app-shell-v2--sidebar-right');
718
+ }
719
+ if (this.sidebarFullHeight()) {
720
+ classes.push('ct-app-shell-v2--sidebar-full-height');
721
+ }
722
+ if (this.withHeader()) {
723
+ classes.push('ct-app-shell-v2--with-header');
724
+ }
725
+ if (this.sidebarBranded()) {
726
+ classes.push('ct-app-shell-v2--sidebar-branded');
727
+ }
728
+ if (this.glass()) {
729
+ classes.push('ct-app-shell-v2--glass');
730
+ }
731
+ return classes.join(' ');
732
+ }, ...(ngDevMode ? [{ debugName: "shellClasses" }] : []));
733
+ /** Dismiss the mobile sidebar overlay. */
734
+ onBackdropClick() {
735
+ this.sidebarState.set('hidden');
736
+ }
737
+ static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.1.2", ngImport: i0, type: AfAppShellV2Component, deps: [], target: i0.ɵɵFactoryTarget.Component });
738
+ static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "21.1.2", type: AfAppShellV2Component, isStandalone: true, selector: "af-app-shell-v2", inputs: { sidebarState: { classPropertyName: "sidebarState", publicName: "sidebarState", isSignal: true, isRequired: false, transformFunction: null }, panelState: { classPropertyName: "panelState", publicName: "panelState", isSignal: true, isRequired: false, transformFunction: null }, noSidebar: { classPropertyName: "noSidebar", publicName: "noSidebar", isSignal: true, isRequired: false, transformFunction: null }, sidebarRight: { classPropertyName: "sidebarRight", publicName: "sidebarRight", isSignal: true, isRequired: false, transformFunction: null }, sidebarFullHeight: { classPropertyName: "sidebarFullHeight", publicName: "sidebarFullHeight", isSignal: true, isRequired: false, transformFunction: null }, withHeader: { classPropertyName: "withHeader", publicName: "withHeader", isSignal: true, isRequired: false, transformFunction: null }, sidebarBranded: { classPropertyName: "sidebarBranded", publicName: "sidebarBranded", isSignal: true, isRequired: false, transformFunction: null }, glass: { classPropertyName: "glass", publicName: "glass", isSignal: true, isRequired: false, transformFunction: null }, sidebarLabel: { classPropertyName: "sidebarLabel", publicName: "sidebarLabel", isSignal: true, isRequired: false, transformFunction: null }, panelLabel: { classPropertyName: "panelLabel", publicName: "panelLabel", isSignal: true, isRequired: false, transformFunction: null }, mainId: { classPropertyName: "mainId", publicName: "mainId", isSignal: true, isRequired: false, transformFunction: null }, skipLinkLabel: { classPropertyName: "skipLinkLabel", publicName: "skipLinkLabel", isSignal: true, isRequired: false, transformFunction: null } }, outputs: { sidebarState: "sidebarStateChange", panelState: "panelStateChange" }, ngImport: i0, template: `
739
+ <div
740
+ [class]="shellClasses()"
741
+ [attr.data-sidebar-state]="sidebarState()"
742
+ [attr.data-panel-state]="panelState()">
743
+ <af-skip-link [target]="mainId()" [label]="skipLinkLabel()" />
744
+
745
+ @if (withHeader()) {
746
+ <header class="ct-app-shell-v2__header">
747
+ <ng-content select="[header]" />
748
+ </header>
749
+ }
750
+
751
+ <aside class="ct-app-shell-v2__sidebar" [attr.aria-label]="sidebarLabel()">
752
+ <ng-content select="[sidebar]" />
753
+ </aside>
754
+
755
+ <div class="ct-app-shell-v2__body">
756
+ <main class="ct-app-shell-v2__main" [id]="mainId()" tabindex="0">
757
+ <ng-content />
758
+ <div class="ct-app-shell-v2__footer">
759
+ <ng-content select="[footer]" />
760
+ </div>
761
+ </main>
762
+
763
+ <aside class="ct-app-shell-v2__panel" [attr.aria-label]="panelLabel()">
764
+ <ng-content select="[panel]" />
765
+ </aside>
766
+ </div>
767
+
768
+ <div
769
+ class="ct-app-shell-v2__backdrop"
770
+ (click)="onBackdropClick()"
771
+ aria-hidden="true"></div>
772
+ </div>
773
+ `, isInline: true, styles: [":host{display:contents}\n"], dependencies: [{ kind: "component", type: AfSkipLinkComponent, selector: "af-skip-link", inputs: ["target", "label"] }], changeDetection: i0.ChangeDetectionStrategy.OnPush });
774
+ }
775
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.1.2", ngImport: i0, type: AfAppShellV2Component, decorators: [{
776
+ type: Component,
777
+ args: [{ selector: 'af-app-shell-v2', changeDetection: ChangeDetectionStrategy.OnPush, imports: [AfSkipLinkComponent], template: `
778
+ <div
779
+ [class]="shellClasses()"
780
+ [attr.data-sidebar-state]="sidebarState()"
781
+ [attr.data-panel-state]="panelState()">
782
+ <af-skip-link [target]="mainId()" [label]="skipLinkLabel()" />
783
+
784
+ @if (withHeader()) {
785
+ <header class="ct-app-shell-v2__header">
786
+ <ng-content select="[header]" />
787
+ </header>
788
+ }
789
+
790
+ <aside class="ct-app-shell-v2__sidebar" [attr.aria-label]="sidebarLabel()">
791
+ <ng-content select="[sidebar]" />
792
+ </aside>
793
+
794
+ <div class="ct-app-shell-v2__body">
795
+ <main class="ct-app-shell-v2__main" [id]="mainId()" tabindex="0">
796
+ <ng-content />
797
+ <div class="ct-app-shell-v2__footer">
798
+ <ng-content select="[footer]" />
799
+ </div>
800
+ </main>
801
+
802
+ <aside class="ct-app-shell-v2__panel" [attr.aria-label]="panelLabel()">
803
+ <ng-content select="[panel]" />
804
+ </aside>
805
+ </div>
806
+
807
+ <div
808
+ class="ct-app-shell-v2__backdrop"
809
+ (click)="onBackdropClick()"
810
+ aria-hidden="true"></div>
811
+ </div>
812
+ `, styles: [":host{display:contents}\n"] }]
813
+ }], propDecorators: { sidebarState: [{ type: i0.Input, args: [{ isSignal: true, alias: "sidebarState", required: false }] }, { type: i0.Output, args: ["sidebarStateChange"] }], panelState: [{ type: i0.Input, args: [{ isSignal: true, alias: "panelState", required: false }] }, { type: i0.Output, args: ["panelStateChange"] }], noSidebar: [{ type: i0.Input, args: [{ isSignal: true, alias: "noSidebar", required: false }] }], sidebarRight: [{ type: i0.Input, args: [{ isSignal: true, alias: "sidebarRight", required: false }] }], sidebarFullHeight: [{ type: i0.Input, args: [{ isSignal: true, alias: "sidebarFullHeight", required: false }] }], withHeader: [{ type: i0.Input, args: [{ isSignal: true, alias: "withHeader", required: false }] }], sidebarBranded: [{ type: i0.Input, args: [{ isSignal: true, alias: "sidebarBranded", required: false }] }], glass: [{ type: i0.Input, args: [{ isSignal: true, alias: "glass", required: false }] }], sidebarLabel: [{ type: i0.Input, args: [{ isSignal: true, alias: "sidebarLabel", required: false }] }], panelLabel: [{ type: i0.Input, args: [{ isSignal: true, alias: "panelLabel", required: false }] }], mainId: [{ type: i0.Input, args: [{ isSignal: true, alias: "mainId", required: false }] }], skipLinkLabel: [{ type: i0.Input, args: [{ isSignal: true, alias: "skipLinkLabel", required: false }] }] } });
814
+
357
815
  /**
358
816
  * Avatar component displaying a user image with fallback to initials.
359
817
  *
@@ -2521,15 +2979,32 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.1.2", ngImpor
2521
2979
  */
2522
2980
  class AfDropdownComponent {
2523
2981
  static nextId = 0;
2982
+ hostRef = inject(ElementRef);
2524
2983
  /** Dropdown button label. */
2525
2984
  label = input('Actions', ...(ngDevMode ? [{ debugName: "label" }] : []));
2985
+ /** Trigger button size. */
2986
+ size = input('md', ...(ngDevMode ? [{ debugName: "size" }] : []));
2987
+ /** Horizontal alignment of the menu relative to the trigger. */
2988
+ align = input('start', ...(ngDevMode ? [{ debugName: "align" }] : []));
2989
+ /** Which side of the trigger the menu opens on. */
2990
+ side = input('bottom', ...(ngDevMode ? [{ debugName: "side" }] : []));
2526
2991
  /** Menu items. */
2527
2992
  items = input([], ...(ngDevMode ? [{ debugName: "items" }] : []));
2528
2993
  /** Emits the selected item's value. */
2529
2994
  itemSelected = output();
2995
+ /** Computed CSS classes for the trigger button. */
2996
+ triggerClasses = computed(() => {
2997
+ const classes = ['ct-button', 'ct-button--secondary', 'ct-dropdown__trigger'];
2998
+ if (this.size() !== 'md') {
2999
+ classes.push(`ct-button--${this.size()}`);
3000
+ }
3001
+ return classes.join(' ');
3002
+ }, ...(ngDevMode ? [{ debugName: "triggerClasses" }] : []));
2530
3003
  triggerRef = viewChild('trigger', ...(ngDevMode ? [{ debugName: "triggerRef" }] : []));
2531
3004
  menuRef = viewChild('menu', ...(ngDevMode ? [{ debugName: "menuRef" }] : []));
2532
3005
  itemButtons = viewChildren('itemButton', ...(ngDevMode ? [{ debugName: "itemButtons" }] : []));
3006
+ /** Non-separator items that can receive focus and be selected. */
3007
+ actionableItems = computed(() => this.items().filter((item) => !item.separator), ...(ngDevMode ? [{ debugName: "actionableItems" }] : []));
2533
3008
  isOpen = signal(false, ...(ngDevMode ? [{ debugName: "isOpen" }] : []));
2534
3009
  focusedItemIndex = signal(0, ...(ngDevMode ? [{ debugName: "focusedItemIndex" }] : []));
2535
3010
  instanceId = AfDropdownComponent.nextId++;
@@ -2572,7 +3047,7 @@ class AfDropdownComponent {
2572
3047
  }
2573
3048
  /** Handles keyboard events within the open menu. */
2574
3049
  onMenuKeydown(event) {
2575
- const actionableItems = this.getActionableItems();
3050
+ const actionableItems = this.actionableItems();
2576
3051
  if (actionableItems.length === 0)
2577
3052
  return;
2578
3053
  switch (event.key) {
@@ -2623,8 +3098,7 @@ class AfDropdownComponent {
2623
3098
  }
2624
3099
  }
2625
3100
  onDocumentClick(event) {
2626
- const target = event.target;
2627
- if (!target.closest('.ct-dropdown')) {
3101
+ if (!this.hostRef.nativeElement.contains(event.target)) {
2628
3102
  this.close(false);
2629
3103
  }
2630
3104
  }
@@ -2633,11 +3107,11 @@ class AfDropdownComponent {
2633
3107
  * actionable (non-separator) items.
2634
3108
  */
2635
3109
  getActionableIndex(item) {
2636
- return this.getActionableItems().indexOf(item);
3110
+ return this.actionableItems().indexOf(item);
2637
3111
  }
2638
3112
  open(focusLast = false) {
2639
3113
  this.isOpen.set(true);
2640
- const actionableItems = this.getActionableItems();
3114
+ const actionableItems = this.actionableItems();
2641
3115
  const startIndex = focusLast
2642
3116
  ? this.nextEnabledIndex(actionableItems.length, -1)
2643
3117
  : this.nextEnabledIndex(-1, 1);
@@ -2663,7 +3137,7 @@ class AfDropdownComponent {
2663
3137
  buttons[idx]?.nativeElement.focus();
2664
3138
  }
2665
3139
  nextEnabledIndex(from, direction) {
2666
- const actionableItems = this.getActionableItems();
3140
+ const actionableItems = this.actionableItems();
2667
3141
  const len = actionableItems.length;
2668
3142
  if (len === 0)
2669
3143
  return 0;
@@ -2679,9 +3153,6 @@ class AfDropdownComponent {
2679
3153
  }
2680
3154
  return from;
2681
3155
  }
2682
- getActionableItems() {
2683
- return this.items().filter((item) => !item.separator);
2684
- }
2685
3156
  handleTypeAhead(char) {
2686
3157
  if (this.typeAheadTimer) {
2687
3158
  clearTimeout(this.typeAheadTimer);
@@ -2691,7 +3162,7 @@ class AfDropdownComponent {
2691
3162
  this.typeAheadBuffer = '';
2692
3163
  this.typeAheadTimer = null;
2693
3164
  }, 500);
2694
- const actionableItems = this.getActionableItems();
3165
+ const actionableItems = this.actionableItems();
2695
3166
  const startIndex = this.focusedItemIndex() + 1;
2696
3167
  for (let i = 0; i < actionableItems.length; i++) {
2697
3168
  const idx = (startIndex + i) % actionableItems.length;
@@ -2703,11 +3174,12 @@ class AfDropdownComponent {
2703
3174
  }
2704
3175
  }
2705
3176
  static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.1.2", ngImport: i0, type: AfDropdownComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
2706
- static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "21.1.2", type: AfDropdownComponent, isStandalone: true, selector: "af-dropdown", 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: { listeners: { "document:click": "onDocumentClick($event)" } }, viewQueries: [{ propertyName: "triggerRef", first: true, predicate: ["trigger"], descendants: true, isSignal: true }, { propertyName: "menuRef", first: true, predicate: ["menu"], descendants: true, isSignal: true }, { propertyName: "itemButtons", predicate: ["itemButton"], descendants: true, isSignal: true }], ngImport: i0, template: `
2707
- <div class="ct-dropdown" [attr.data-state]="isOpen() ? 'open' : 'closed'">
3177
+ static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "21.1.2", type: AfDropdownComponent, isStandalone: true, selector: "af-dropdown", inputs: { label: { classPropertyName: "label", publicName: "label", isSignal: true, isRequired: false, transformFunction: null }, size: { classPropertyName: "size", publicName: "size", isSignal: true, isRequired: false, transformFunction: null }, align: { classPropertyName: "align", publicName: "align", isSignal: true, isRequired: false, transformFunction: null }, side: { classPropertyName: "side", publicName: "side", isSignal: true, isRequired: false, transformFunction: null }, items: { classPropertyName: "items", publicName: "items", isSignal: true, isRequired: false, transformFunction: null } }, outputs: { itemSelected: "itemSelected" }, host: { listeners: { "document:click": "onDocumentClick($event)" } }, viewQueries: [{ propertyName: "triggerRef", first: true, predicate: ["trigger"], descendants: true, isSignal: true }, { propertyName: "menuRef", first: true, predicate: ["menu"], descendants: true, isSignal: true }, { propertyName: "itemButtons", predicate: ["itemButton"], descendants: true, isSignal: true }], ngImport: i0, template: `
3178
+ <div class="ct-dropdown" [attr.data-state]="isOpen() ? 'open' : 'closed'" [attr.data-align]="align()" [attr.data-side]="side()">
2708
3179
  <button
2709
3180
  #trigger
2710
- class="ct-button ct-button--secondary ct-dropdown__trigger"
3181
+ [id]="triggerId"
3182
+ [class]="triggerClasses()"
2711
3183
  [attr.aria-expanded]="isOpen()"
2712
3184
  [attr.aria-controls]="menuId"
2713
3185
  aria-haspopup="menu"
@@ -2751,10 +3223,11 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.1.2", ngImpor
2751
3223
  args: [{ selector: 'af-dropdown', changeDetection: ChangeDetectionStrategy.OnPush, host: {
2752
3224
  '(document:click)': 'onDocumentClick($event)',
2753
3225
  }, template: `
2754
- <div class="ct-dropdown" [attr.data-state]="isOpen() ? 'open' : 'closed'">
3226
+ <div class="ct-dropdown" [attr.data-state]="isOpen() ? 'open' : 'closed'" [attr.data-align]="align()" [attr.data-side]="side()">
2755
3227
  <button
2756
3228
  #trigger
2757
- class="ct-button ct-button--secondary ct-dropdown__trigger"
3229
+ [id]="triggerId"
3230
+ [class]="triggerClasses()"
2758
3231
  [attr.aria-expanded]="isOpen()"
2759
3232
  [attr.aria-controls]="menuId"
2760
3233
  aria-haspopup="menu"
@@ -2792,7 +3265,7 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.1.2", ngImpor
2792
3265
  }
2793
3266
  </div>
2794
3267
  `, styles: [":host{display:inline-block}\n"] }]
2795
- }], 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"] }], triggerRef: [{ type: i0.ViewChild, args: ['trigger', { isSignal: true }] }], menuRef: [{ type: i0.ViewChild, args: ['menu', { isSignal: true }] }], itemButtons: [{ type: i0.ViewChildren, args: ['itemButton', { isSignal: true }] }] } });
3268
+ }], propDecorators: { label: [{ type: i0.Input, args: [{ isSignal: true, alias: "label", required: false }] }], size: [{ type: i0.Input, args: [{ isSignal: true, alias: "size", required: false }] }], align: [{ type: i0.Input, args: [{ isSignal: true, alias: "align", required: false }] }], side: [{ type: i0.Input, args: [{ isSignal: true, alias: "side", required: false }] }], items: [{ type: i0.Input, args: [{ isSignal: true, alias: "items", required: false }] }], itemSelected: [{ type: i0.Output, args: ["itemSelected"] }], triggerRef: [{ type: i0.ViewChild, args: ['trigger', { isSignal: true }] }], menuRef: [{ type: i0.ViewChild, args: ['menu', { isSignal: true }] }], itemButtons: [{ type: i0.ViewChildren, args: ['itemButton', { isSignal: true }] }] } });
2796
3269
 
2797
3270
  /**
2798
3271
  * Pagination component
@@ -6242,6 +6715,10 @@ class AfNavItemComponent {
6242
6715
  static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.1.2", ngImport: i0, type: AfNavItemComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
6243
6716
  static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "21.1.2", type: AfNavItemComponent, isStandalone: true, selector: "af-nav-item", inputs: { label: { classPropertyName: "label", publicName: "label", isSignal: true, isRequired: true, transformFunction: null }, href: { classPropertyName: "href", publicName: "href", isSignal: true, isRequired: false, transformFunction: null }, routerLink: { classPropertyName: "routerLink", publicName: "routerLink", isSignal: true, isRequired: false, transformFunction: null }, active: { classPropertyName: "active", publicName: "active", isSignal: true, isRequired: false, transformFunction: null }, disabled: { classPropertyName: "disabled", publicName: "disabled", isSignal: true, isRequired: false, transformFunction: null } }, outputs: { clicked: "clicked" }, viewQueries: [{ propertyName: "linkRef", first: true, predicate: ["linkEl"], descendants: true, isSignal: true }], ngImport: i0, template: `
6244
6717
  <li class="ct-navbar__item" role="none">
6718
+ <ng-template #contentTpl>
6719
+ <ng-content>{{ label() }}</ng-content>
6720
+ </ng-template>
6721
+
6245
6722
  @if (routerLink()) {
6246
6723
  <a
6247
6724
  #linkEl
@@ -6252,7 +6729,7 @@ class AfNavItemComponent {
6252
6729
  [attr.aria-disabled]="disabled() || null"
6253
6730
  [attr.tabindex]="rovingTabindex()"
6254
6731
  (click)="onClick($event)">
6255
- <ng-content>{{ label() }}</ng-content>
6732
+ <ng-container [ngTemplateOutlet]="contentTpl" />
6256
6733
  </a>
6257
6734
  } @else if (href()) {
6258
6735
  <a
@@ -6265,7 +6742,7 @@ class AfNavItemComponent {
6265
6742
  [attr.aria-disabled]="disabled() || null"
6266
6743
  [attr.tabindex]="rovingTabindex()"
6267
6744
  (click)="onClick($event)">
6268
- <ng-content>{{ label() }}</ng-content>
6745
+ <ng-container [ngTemplateOutlet]="contentTpl" />
6269
6746
  </a>
6270
6747
  } @else {
6271
6748
  <button
@@ -6278,16 +6755,20 @@ class AfNavItemComponent {
6278
6755
  [attr.aria-disabled]="disabled() || null"
6279
6756
  [attr.tabindex]="rovingTabindex()"
6280
6757
  (click)="onClick($event)">
6281
- <ng-content>{{ label() }}</ng-content>
6758
+ <ng-container [ngTemplateOutlet]="contentTpl" />
6282
6759
  </button>
6283
6760
  }
6284
6761
  </li>
6285
- `, isInline: true, styles: [":host{display:contents}\n"], dependencies: [{ kind: "directive", type: RouterLink, selector: "[routerLink]", inputs: ["target", "queryParams", "fragment", "queryParamsHandling", "state", "info", "relativeTo", "preserveFragment", "skipLocationChange", "replaceUrl", "routerLink"] }, { kind: "directive", type: RouterLinkActive, selector: "[routerLinkActive]", inputs: ["routerLinkActiveOptions", "ariaCurrentWhenActive", "routerLinkActive"], outputs: ["isActiveChange"], exportAs: ["routerLinkActive"] }], changeDetection: i0.ChangeDetectionStrategy.OnPush });
6762
+ `, isInline: true, styles: [":host{display:contents}\n"], dependencies: [{ kind: "directive", type: RouterLink, selector: "[routerLink]", inputs: ["target", "queryParams", "fragment", "queryParamsHandling", "state", "info", "relativeTo", "preserveFragment", "skipLocationChange", "replaceUrl", "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"] }], changeDetection: i0.ChangeDetectionStrategy.OnPush });
6286
6763
  }
6287
6764
  i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.1.2", ngImport: i0, type: AfNavItemComponent, decorators: [{
6288
6765
  type: Component,
6289
- args: [{ selector: 'af-nav-item', changeDetection: ChangeDetectionStrategy.OnPush, imports: [RouterLink, RouterLinkActive], template: `
6766
+ args: [{ selector: 'af-nav-item', changeDetection: ChangeDetectionStrategy.OnPush, imports: [RouterLink, RouterLinkActive, NgTemplateOutlet], template: `
6290
6767
  <li class="ct-navbar__item" role="none">
6768
+ <ng-template #contentTpl>
6769
+ <ng-content>{{ label() }}</ng-content>
6770
+ </ng-template>
6771
+
6291
6772
  @if (routerLink()) {
6292
6773
  <a
6293
6774
  #linkEl
@@ -6298,7 +6779,7 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.1.2", ngImpor
6298
6779
  [attr.aria-disabled]="disabled() || null"
6299
6780
  [attr.tabindex]="rovingTabindex()"
6300
6781
  (click)="onClick($event)">
6301
- <ng-content>{{ label() }}</ng-content>
6782
+ <ng-container [ngTemplateOutlet]="contentTpl" />
6302
6783
  </a>
6303
6784
  } @else if (href()) {
6304
6785
  <a
@@ -6311,7 +6792,7 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.1.2", ngImpor
6311
6792
  [attr.aria-disabled]="disabled() || null"
6312
6793
  [attr.tabindex]="rovingTabindex()"
6313
6794
  (click)="onClick($event)">
6314
- <ng-content>{{ label() }}</ng-content>
6795
+ <ng-container [ngTemplateOutlet]="contentTpl" />
6315
6796
  </a>
6316
6797
  } @else {
6317
6798
  <button
@@ -6324,7 +6805,7 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.1.2", ngImpor
6324
6805
  [attr.aria-disabled]="disabled() || null"
6325
6806
  [attr.tabindex]="rovingTabindex()"
6326
6807
  (click)="onClick($event)">
6327
- <ng-content>{{ label() }}</ng-content>
6808
+ <ng-container [ngTemplateOutlet]="contentTpl" />
6328
6809
  </button>
6329
6810
  }
6330
6811
  </li>
@@ -6526,7 +7007,9 @@ class AfNavbarComponent {
6526
7007
  static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.1.2", ngImport: i0, type: AfNavbarComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
6527
7008
  static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "21.1.2", type: AfNavbarComponent, isStandalone: true, selector: "af-navbar", inputs: { size: { classPropertyName: "size", publicName: "size", isSignal: true, isRequired: false, transformFunction: null }, variant: { classPropertyName: "variant", publicName: "variant", isSignal: true, isRequired: false, transformFunction: null }, center: { classPropertyName: "center", publicName: "center", isSignal: true, isRequired: false, transformFunction: null }, ariaLabel: { classPropertyName: "ariaLabel", publicName: "ariaLabel", isSignal: true, isRequired: false, transformFunction: null } }, host: { listeners: { "keydown": "handleKeydown($event)", "document:click": "onDocumentClick($event)" } }, queries: [{ propertyName: "items", predicate: AfNavItemComponent, isSignal: true }], viewQueries: [{ propertyName: "toggleRef", first: true, predicate: ["toggleBtn"], descendants: true, isSignal: true }, { propertyName: "mobileLinks", predicate: ["mobileLink"], descendants: true, isSignal: true }], ngImport: i0, template: `
6528
7009
  <header [class]="navbarClasses()">
6529
- <ng-content select="[brand]" />
7010
+ <div class="ct-navbar__brand-wrapper">
7011
+ <ng-content select="[brand]" />
7012
+ </div>
6530
7013
 
6531
7014
  <button
6532
7015
  #toggleBtn
@@ -6611,7 +7094,9 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.1.2", ngImpor
6611
7094
  '(document:click)': 'onDocumentClick($event)',
6612
7095
  }, template: `
6613
7096
  <header [class]="navbarClasses()">
6614
- <ng-content select="[brand]" />
7097
+ <div class="ct-navbar__brand-wrapper">
7098
+ <ng-content select="[brand]" />
7099
+ </div>
6615
7100
 
6616
7101
  <button
6617
7102
  #toggleBtn
@@ -7106,65 +7591,6 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.1.2", ngImpor
7106
7591
  `, styles: [":host{display:contents}\n"] }]
7107
7592
  }], propDecorators: { variant: [{ type: i0.Input, args: [{ isSignal: true, alias: "variant", required: false }] }], appearance: [{ type: i0.Input, args: [{ isSignal: true, alias: "appearance", required: false }] }], position: [{ type: i0.Input, args: [{ isSignal: true, alias: "position", required: false }] }], dismissible: [{ type: i0.Input, args: [{ isSignal: true, alias: "dismissible", required: false }] }], compact: [{ type: i0.Input, args: [{ isSignal: true, alias: "compact", required: false }] }], full: [{ type: i0.Input, args: [{ isSignal: true, alias: "full", required: false }] }], autoClose: [{ type: i0.Input, args: [{ isSignal: true, alias: "autoClose", required: false }] }], closeAriaLabel: [{ type: i0.Input, args: [{ isSignal: true, alias: "closeAriaLabel", required: false }] }], dismissed: [{ type: i0.Output, args: ["dismissed"] }] } });
7108
7593
 
7109
- /**
7110
- * Skip-link component for keyboard-only navigation bypass.
7111
- *
7112
- * Renders an anchor that is visually hidden off-screen and slides into view
7113
- * when focused. On activation it moves focus to the target element, allowing
7114
- * keyboard users to skip repetitive navigation blocks.
7115
- *
7116
- * Must be placed as the first focusable element in the document.
7117
- *
7118
- * @example
7119
- * <af-skip-link target="main-content" />
7120
- * <nav>…</nav>
7121
- * <main id="main-content" tabindex="-1">…</main>
7122
- */
7123
- class AfSkipLinkComponent {
7124
- /** ID of the element to skip to (without the leading `#`). */
7125
- target = input.required(...(ngDevMode ? [{ debugName: "target" }] : []));
7126
- /** Visible label text shown when the link receives focus. */
7127
- label = input('Skip to main content', ...(ngDevMode ? [{ debugName: "label" }] : []));
7128
- document = inject(DOCUMENT);
7129
- /**
7130
- * Moves focus to the target element so keyboard navigation
7131
- * continues from there instead of the top of the page.
7132
- */
7133
- focusTarget(event) {
7134
- event.preventDefault();
7135
- const el = this.document.getElementById(this.target());
7136
- if (!el) {
7137
- return;
7138
- }
7139
- if (!el.hasAttribute('tabindex')) {
7140
- el.setAttribute('tabindex', '-1');
7141
- }
7142
- el.focus();
7143
- }
7144
- static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.1.2", ngImport: i0, type: AfSkipLinkComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
7145
- static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.1.0", version: "21.1.2", type: AfSkipLinkComponent, isStandalone: true, selector: "af-skip-link", inputs: { target: { classPropertyName: "target", publicName: "target", isSignal: true, isRequired: true, transformFunction: null }, label: { classPropertyName: "label", publicName: "label", isSignal: true, isRequired: false, transformFunction: null } }, ngImport: i0, template: `
7146
- <a
7147
- class="ct-skip-link"
7148
- [attr.href]="'#' + target()"
7149
- (click)="focusTarget($event)"
7150
- >
7151
- {{ label() }}
7152
- </a>
7153
- `, isInline: true, styles: [":host{display:contents}\n"], changeDetection: i0.ChangeDetectionStrategy.OnPush });
7154
- }
7155
- i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.1.2", ngImport: i0, type: AfSkipLinkComponent, decorators: [{
7156
- type: Component,
7157
- args: [{ selector: 'af-skip-link', changeDetection: ChangeDetectionStrategy.OnPush, template: `
7158
- <a
7159
- class="ct-skip-link"
7160
- [attr.href]="'#' + target()"
7161
- (click)="focusTarget($event)"
7162
- >
7163
- {{ label() }}
7164
- </a>
7165
- `, styles: [":host{display:contents}\n"] }]
7166
- }], propDecorators: { target: [{ type: i0.Input, args: [{ isSignal: true, alias: "target", required: true }] }], label: [{ type: i0.Input, args: [{ isSignal: true, alias: "label", required: false }] }] } });
7167
-
7168
7594
  /**
7169
7595
  * Empty state component for displaying placeholder content when no data is available.
7170
7596
  *
@@ -7727,5 +8153,5 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.1.2", ngImpor
7727
8153
  * Generated bundle index. Do not edit.
7728
8154
  */
7729
8155
 
7730
- export { AfAccordionComponent, AfAccordionItemComponent, AfAlertComponent, AfAvatarComponent, AfBadgeComponent, AfBannerComponent, AfBreadcrumbsComponent, AfButtonComponent, AfCardComponent, AfCellDefDirective, AfCheckboxComponent, AfChipInputComponent, AfComboboxComponent, AfDataTableComponent, AfDatepickerComponent, AfDividerComponent, AfDrawerComponent, AfDropdownComponent, AfEmptyStateComponent, AfFieldComponent, AfFileUploadComponent, AfFormatLabelPipe, AfIconComponent, AfInputComponent, AfModalComponent, AfNavItemComponent, AfNavbarComponent, AfPaginationComponent, AfPopoverComponent, AfPopoverTriggerDirective, AfProgressBarComponent, AfRadioComponent, AfRadioGroupComponent, AfSelectComponent, AfSelectMenuComponent, AfSidebarComponent, AfSkeletonComponent, AfSkipLinkComponent, AfSliderComponent, AfSpinnerComponent, AfSwitchComponent, AfTabPanelComponent, AfTableBodyComponent, AfTableCellComponent, AfTableComponent, AfTableHeaderCellComponent, AfTableHeaderComponent, AfTableRowComponent, AfTabsComponent, AfTextareaComponent, AfToastContainerComponent, AfToastService, AfToggleGroupComponent, AfToolbarComponent, AfTooltipDirective };
8156
+ export { AfAccordionComponent, AfAccordionItemComponent, AfAlertComponent, AfAppShellComponent, AfAppShellPageHeaderComponent, AfAppShellV2Component, AfAppShellV2ToolbarComponent, AfAvatarComponent, AfBadgeComponent, AfBannerComponent, AfBreadcrumbsComponent, AfButtonComponent, AfCardComponent, AfCellDefDirective, AfCheckboxComponent, AfChipInputComponent, AfComboboxComponent, AfDataTableComponent, AfDatepickerComponent, AfDividerComponent, AfDrawerComponent, AfDropdownComponent, AfEmptyStateComponent, AfFieldComponent, AfFileUploadComponent, AfFormatLabelPipe, AfIconComponent, AfInputComponent, AfModalComponent, AfNavItemComponent, AfNavbarComponent, AfPaginationComponent, AfPopoverComponent, AfPopoverTriggerDirective, AfProgressBarComponent, AfRadioComponent, AfRadioGroupComponent, AfSelectComponent, AfSelectMenuComponent, AfSidebarComponent, AfSkeletonComponent, AfSkipLinkComponent, AfSliderComponent, AfSpinnerComponent, AfSwitchComponent, AfTabPanelComponent, AfTableBodyComponent, AfTableCellComponent, AfTableComponent, AfTableHeaderCellComponent, AfTableHeaderComponent, AfTableRowComponent, AfTabsComponent, AfTextareaComponent, AfToastContainerComponent, AfToastService, AfToggleGroupComponent, AfToolbarComponent, AfTooltipDirective };
7731
8157
  //# sourceMappingURL=neuravision-ng-construct.mjs.map