yukit-web 0.0.6 → 0.0.8

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,7 +1,7 @@
1
1
  import { clsx } from 'clsx';
2
2
  import { twMerge } from 'tailwind-merge';
3
3
  import * as i0 from '@angular/core';
4
- import { forwardRef, signal, Directive, input, inject, TemplateRef, ElementRef, booleanAttribute, output, computed, contentChildren, ChangeDetectionStrategy, Component, model, contentChild, viewChild, Injector, afterNextRender, effect, numberAttribute, linkedSignal } from '@angular/core';
4
+ import { forwardRef, signal, Directive, input, inject, TemplateRef, ElementRef, booleanAttribute, output, computed, contentChildren, ChangeDetectionStrategy, Component, model, contentChild, viewChild, Injector, afterNextRender, effect, numberAttribute, linkedSignal, Injectable, ViewContainerRef, runInInjectionContext } from '@angular/core';
5
5
  import { NG_VALUE_ACCESSOR } from '@angular/forms';
6
6
  import { NgTemplateOutlet } from '@angular/common';
7
7
  import { HlmButton, provideBrnButtonConfig } from 'yukit-web/helm/button';
@@ -39,7 +39,7 @@ import { HlmCard, HlmCardHeader, HlmCardTitle, HlmCardDescription, HlmCardAction
39
39
  import * as i1$9 from 'yukit-web/helm/empty';
40
40
  import { HlmEmpty, HlmEmptyHeader, HlmEmptyMedia, HlmEmptyTitle, HlmEmptyDescription, HlmEmptyContent } from 'yukit-web/helm/empty';
41
41
  import { CdkContextMenuTrigger, CdkMenuItem, CdkMenuItemCheckbox, CdkMenuItemRadio, CdkMenuTrigger } from '@angular/cdk/menu';
42
- import { outputFromObservable, toObservable } from '@angular/core/rxjs-interop';
42
+ import { outputFromObservable, toObservable, toSignal } from '@angular/core/rxjs-interop';
43
43
  import * as i1$a from 'yukit-web/helm/context-menu';
44
44
  import { HlmContextMenuTrigger } from 'yukit-web/helm/context-menu';
45
45
  import * as i1$b from 'yukit-web/helm/date-picker';
@@ -48,7 +48,7 @@ import * as i1$c from 'yukit-web/helm/table';
48
48
  import { HlmTableContainer, HlmTable, HlmTHead, HlmTBody, HlmTFoot, HlmTr, HlmTh, HlmTd, HlmCaption } from 'yukit-web/helm/table';
49
49
  import { injectTable, FlexRenderDirective } from '@tanstack/angular-table';
50
50
  import { rowSortingFeature, rowSelectionFeature, rowPaginationFeature, columnVisibilityFeature, columnFilteringFeature, sortFns, createPaginatedRowModel, createSortedRowModel, createFilteredRowModel, createCoreRowModel } from '@tanstack/table-core';
51
- import { skip } from 'rxjs';
51
+ import { skip, switchMap, timer, of, merge, fromEvent } from 'rxjs';
52
52
  import * as i1$d from 'yukit-web/helm/avatar';
53
53
  import { HlmAvatarImports } from 'yukit-web/helm/avatar';
54
54
  import * as i1$e from 'yukit-web/helm/item';
@@ -81,10 +81,14 @@ import * as i1$o from 'yukit-web/helm/tabs';
81
81
  import { HlmTabsImports } from 'yukit-web/helm/tabs';
82
82
  import * as i1$p from 'yukit-web/helm/attachment';
83
83
  import { HlmAttachment, HlmAttachmentGroup, HlmAttachmentMedia, HlmAttachmentContent, HlmAttachmentTitle, HlmAttachmentDescription, HlmAttachmentActions, HlmAttachmentAction, HlmAttachmentTrigger } from 'yukit-web/helm/attachment';
84
+ import { map, distinctUntilChanged, switchMap as switchMap$1 } from 'rxjs/operators';
84
85
  import * as i1$q from 'yukit-web/helm/sidebar';
85
- import { HlmSidebarWrapper, HlmSidebarHeader, HlmSidebarContent, HlmSidebarFooter, HlmSidebarGroup, HlmSidebarGroupLabel, HlmSidebarGroupContent, HlmSidebarMenu, HlmSidebarMenuItem, HlmSidebarMenuButton, HlmSidebarMenuBadge, HlmSidebarMenuSub, HlmSidebarMenuSubItem, HlmSidebarMenuSubButton, HlmSidebarSeparator, HlmSidebarRail, HlmSidebarInset, injectHlmSidebarConfig, HlmSidebar, HlmSidebarTrigger } from 'yukit-web/helm/sidebar';
86
+ import { HlmSidebarService, HlmSidebarWrapper, HlmSidebarHeader, HlmSidebarContent, HlmSidebarFooter, HlmSidebarGroup, HlmSidebarGroupLabel, HlmSidebarGroupContent, HlmSidebarMenu, HlmSidebarMenuItem, HlmSidebarMenuButton, HlmSidebarMenuBadge, HlmSidebarMenuSub, HlmSidebarMenuSubItem, HlmSidebarMenuSubButton, HlmSidebarSeparator, HlmSidebarRail, HlmSidebarInset, injectHlmSidebarConfig, HlmSidebar, HlmSidebarTrigger } from 'yukit-web/helm/sidebar';
86
87
  export { HlmSidebarService as YuwSidebarService, provideHlmSidebarConfig as provideYuwSidebarConfig } from 'yukit-web/helm/sidebar';
87
- import { RouterLink, RouterLinkActive } from '@angular/router';
88
+ import { Router, isActive, RouterLink, RouterLinkActive } from '@angular/router';
89
+ import * as i2$1 from 'yukit-web/helm/hover-card';
90
+ import { HlmHoverCardPortal, HlmHoverCardContent } from 'yukit-web/helm/hover-card';
91
+ import { BrnHoverCardContentService } from '@spartan-ng/brain/hover-card';
88
92
 
89
93
  /**
90
94
  * Merges class lists the shadcn/Spartan way: `clsx` resolves conditionals/arrays, `twMerge`
@@ -2826,8 +2830,36 @@ class YuwDatatableComponent {
2826
2830
  this.columnVisibility = model({}, ...(ngDevMode ? [{ debugName: "columnVisibility" }] : /* istanbul ignore next */ []));
2827
2831
  this.rowSelection = model({}, ...(ngDevMode ? [{ debugName: "rowSelection" }] : /* istanbul ignore next */ []));
2828
2832
  this.pagination = model({ pageIndex: 0, pageSize: 10 }, ...(ngDevMode ? [{ debugName: "pagination" }] : /* istanbul ignore next */ []));
2833
+ this.rowClicked = output();
2834
+ this._ariaSort = {
2835
+ asc: 'ascending',
2836
+ desc: 'descending',
2837
+ };
2838
+ this._sortIcon = {
2839
+ asc: 'lucideChevronUp',
2840
+ desc: 'lucideChevronDown',
2841
+ none: 'lucideChevronsUpDown',
2842
+ };
2829
2843
  this.currentPage = linkedSignal({ ...(ngDevMode ? { debugName: "currentPage" } : /* istanbul ignore next */ {}), source: () => this.pagination().pageIndex,
2830
2844
  computation: (pageIndex) => pageIndex + 1 });
2845
+ this._isEmpty = computed(() => !this.loading() && this.table.getRowModel().rows.length === 0, ...(ngDevMode ? [{ debugName: "_isEmpty" }] : /* istanbul ignore next */ []));
2846
+ this._columnCount = computed(() => this.table.getVisibleLeafColumns().length, ...(ngDevMode ? [{ debugName: "_columnCount" }] : /* istanbul ignore next */ []));
2847
+ this._skeletonRows = computed(() => Array.from({ length: this.loadingRows() }, (_, i) => i), ...(ngDevMode ? [{ debugName: "_skeletonRows" }] : /* istanbul ignore next */ []));
2848
+ this._tableClass = computed(() => cn(this.tableClass()), ...(ngDevMode ? [{ debugName: "_tableClass" }] : /* istanbul ignore next */ []));
2849
+ this._containerClass = computed(() => datatableContainerVariants({ appearance: this.appearance() }), ...(ngDevMode ? [{ debugName: "_containerClass" }] : /* istanbul ignore next */ []));
2850
+ this._headClass = computed(() => datatableHeadVariants({ appearance: this.appearance() }), ...(ngDevMode ? [{ debugName: "_headClass" }] : /* istanbul ignore next */ []));
2851
+ this._rowClass = computed(() => datatableRowVariants({ appearance: this.appearance() }), ...(ngDevMode ? [{ debugName: "_rowClass" }] : /* istanbul ignore next */ []));
2852
+ this._cellClasses = computed(() => {
2853
+ const header = datatableHeaderCellVariants({ appearance: this.appearance() });
2854
+ const cell = datatableCellVariants({ appearance: this.appearance() });
2855
+ return new Map(this.columns().map((column, index) => {
2856
+ const align = DATATABLE_ALIGN_CLASS[column.meta?.align ?? 'start'];
2857
+ return [
2858
+ column.id ?? ('accessorKey' in column ? String(column.accessorKey) : String(index)),
2859
+ { header: cn(header, align), cell: cn(cell, align) },
2860
+ ];
2861
+ }));
2862
+ }, ...(ngDevMode ? [{ debugName: "_cellClasses" }] : /* istanbul ignore next */ []));
2831
2863
  this._options = () => ({
2832
2864
  features: {
2833
2865
  ...YUW_DATATABLE_FEATURES,
@@ -2858,37 +2890,6 @@ class YuwDatatableComponent {
2858
2890
  return this.table.getSelectedRowModel().rows.map((row) => row.original);
2859
2891
  }, ...(ngDevMode ? [{ debugName: "_selectedRows" }] : /* istanbul ignore next */ []));
2860
2892
  this.selectedRowsChange = outputFromObservable(toObservable(this._selectedRows).pipe(skip(1)));
2861
- this._isEmpty = computed(() => !this.loading() && this.table.getRowModel().rows.length === 0, ...(ngDevMode ? [{ debugName: "_isEmpty" }] : /* istanbul ignore next */ []));
2862
- this._columnCount = computed(() => this.table.getVisibleLeafColumns().length, ...(ngDevMode ? [{ debugName: "_columnCount" }] : /* istanbul ignore next */ []));
2863
- this._skeletonRows = computed(() => Array.from({ length: this.loadingRows() }, (_, i) => i), ...(ngDevMode ? [{ debugName: "_skeletonRows" }] : /* istanbul ignore next */ []));
2864
- this._tableClass = computed(() => cn(this.tableClass()), ...(ngDevMode ? [{ debugName: "_tableClass" }] : /* istanbul ignore next */ []));
2865
- this._containerClass = computed(() => datatableContainerVariants({ appearance: this.appearance() }), ...(ngDevMode ? [{ debugName: "_containerClass" }] : /* istanbul ignore next */ []));
2866
- this._headClass = computed(() => datatableHeadVariants({ appearance: this.appearance() }), ...(ngDevMode ? [{ debugName: "_headClass" }] : /* istanbul ignore next */ []));
2867
- this._rowClass = computed(() => datatableRowVariants({ appearance: this.appearance() }), ...(ngDevMode ? [{ debugName: "_rowClass" }] : /* istanbul ignore next */ []));
2868
- this._cellClasses = computed(() => {
2869
- const header = datatableHeaderCellVariants({ appearance: this.appearance() });
2870
- const cell = datatableCellVariants({ appearance: this.appearance() });
2871
- return new Map(this.columns().map((column, index) => {
2872
- const align = DATATABLE_ALIGN_CLASS[column.meta?.align ?? 'start'];
2873
- return [
2874
- column.id ?? ('accessorKey' in column ? String(column.accessorKey) : String(index)),
2875
- { header: cn(header, align), cell: cn(cell, align) },
2876
- ];
2877
- }));
2878
- }, ...(ngDevMode ? [{ debugName: "_cellClasses" }] : /* istanbul ignore next */ []));
2879
- this._ariaSort = {
2880
- asc: 'ascending',
2881
- desc: 'descending',
2882
- };
2883
- this._sortIcon = {
2884
- asc: 'lucideChevronUp',
2885
- desc: 'lucideChevronDown',
2886
- none: 'lucideChevronsUpDown',
2887
- };
2888
- }
2889
- /** Translates a 1-based page from `<yuw-pagination>` back into TanStack's zero-based state. */
2890
- onPageChange(page) {
2891
- this.pagination.update((current) => ({ ...current, pageIndex: page - 1 }));
2892
2893
  }
2893
2894
  /**
2894
2895
  * Applies the real options once, after inputs are set.
@@ -2908,15 +2909,61 @@ class YuwDatatableComponent {
2908
2909
  const options = this._options();
2909
2910
  this.table.setOptions((previous) => ({ ...previous, ...options }));
2910
2911
  }
2912
+ onPageChange(page) {
2913
+ this.pagination.update((current) => ({ ...current, pageIndex: page - 1 }));
2914
+ }
2915
+ onRowClick(row) {
2916
+ this.rowClicked.emit(row);
2917
+ }
2911
2918
  static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.8", ngImport: i0, type: YuwDatatableComponent, deps: [], target: i0.ɵɵFactoryTarget.Component }); }
2912
- static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "21.2.8", type: YuwDatatableComponent, isStandalone: true, selector: "yuw-datatable", inputs: { columns: { classPropertyName: "columns", publicName: "columns", isSignal: true, isRequired: false, transformFunction: null }, data: { classPropertyName: "data", publicName: "data", isSignal: true, isRequired: false, transformFunction: null }, sortable: { classPropertyName: "sortable", publicName: "sortable", isSignal: true, isRequired: false, transformFunction: null }, paginated: { classPropertyName: "paginated", publicName: "paginated", isSignal: true, isRequired: false, transformFunction: null }, selectable: { classPropertyName: "selectable", publicName: "selectable", isSignal: true, isRequired: false, transformFunction: null }, emptyText: { classPropertyName: "emptyText", publicName: "emptyText", isSignal: true, isRequired: false, transformFunction: null }, loading: { classPropertyName: "loading", publicName: "loading", isSignal: true, isRequired: false, transformFunction: null }, loadingRows: { classPropertyName: "loadingRows", publicName: "loadingRows", isSignal: true, isRequired: false, transformFunction: null }, previousPageLabel: { classPropertyName: "previousPageLabel", publicName: "previousPageLabel", isSignal: true, isRequired: true, transformFunction: null }, nextPageLabel: { classPropertyName: "nextPageLabel", publicName: "nextPageLabel", isSignal: true, isRequired: true, transformFunction: null }, paginationEllipsisSrText: { classPropertyName: "paginationEllipsisSrText", publicName: "paginationEllipsisSrText", isSignal: true, isRequired: true, transformFunction: null }, paginationAriaLabel: { classPropertyName: "paginationAriaLabel", publicName: "paginationAriaLabel", isSignal: true, isRequired: true, transformFunction: null }, caption: { classPropertyName: "caption", publicName: "caption", isSignal: true, isRequired: false, transformFunction: null }, tableClass: { classPropertyName: "tableClass", publicName: "tableClass", isSignal: true, isRequired: false, transformFunction: null }, appearance: { classPropertyName: "appearance", publicName: "appearance", isSignal: true, isRequired: false, transformFunction: null }, sorting: { classPropertyName: "sorting", publicName: "sorting", isSignal: true, isRequired: false, transformFunction: null }, columnFilters: { classPropertyName: "columnFilters", publicName: "columnFilters", isSignal: true, isRequired: false, transformFunction: null }, columnVisibility: { classPropertyName: "columnVisibility", publicName: "columnVisibility", isSignal: true, isRequired: false, transformFunction: null }, rowSelection: { classPropertyName: "rowSelection", publicName: "rowSelection", isSignal: true, isRequired: false, transformFunction: null }, pagination: { classPropertyName: "pagination", publicName: "pagination", isSignal: true, isRequired: false, transformFunction: null } }, outputs: { sorting: "sortingChange", columnFilters: "columnFiltersChange", columnVisibility: "columnVisibilityChange", rowSelection: "rowSelectionChange", pagination: "paginationChange", selectedRowsChange: "selectedRowsChange" }, host: { classAttribute: "contents" }, providers: [provideIcons({ lucideChevronDown, lucideChevronUp, lucideChevronsUpDown })], ngImport: i0, template: "<div yuwTableContainer [class]=\"_containerClass()\">\n <table yuwTable [class]=\"_tableClass()\">\n @if (caption()) {\n <caption yuwCaption>{{ caption() }}</caption>\n }\n\n <thead yuwTHead [class]=\"_headClass()\">\n @for (headerGroup of table.getHeaderGroups(); track headerGroup.id) {\n <tr yuwTr [class]=\"_rowClass()\">\n @for (header of headerGroup.headers; track header.id) {\n @let sorted = header.column.getIsSorted();\n <th\n yuwTh\n scope=\"col\"\n [attr.colspan]=\"header.colSpan\"\n [attr.aria-sort]=\"sorted ? _ariaSort[sorted] : null\"\n [class]=\"_cellClasses().get(header.column.id)?.header\"\n >\n @if (!header.isPlaceholder) {\n @if (sortable() && header.column.getCanSort()) {\n <button\n type=\"button\"\n class=\"inline-flex items-center gap-1 select-none hover:text-foreground/80\"\n (click)=\"header.column.toggleSorting()\"\n >\n <ng-container\n *flexRender=\"header.column.columnDef.header; props: header.getContext(); let rendered\"\n >\n {{ rendered }}\n </ng-container>\n\n <ng-icon [name]=\"_sortIcon[sorted || 'none']\" class=\"shrink-0 text-xs\" aria-hidden=\"true\" />\n </button>\n } @else {\n <ng-container *flexRender=\"header.column.columnDef.header; props: header.getContext(); let rendered\">\n {{ rendered }}\n </ng-container>\n }\n }\n </th>\n }\n </tr>\n }\n </thead>\n\n <tbody yuwTBody>\n @if (loading()) {\n @for (row of _skeletonRows(); track row) {\n <tr yuwTr [class]=\"_rowClass()\">\n @for (column of table.getVisibleLeafColumns(); track column.id) {\n <td yuwTd [class]=\"_cellClasses().get(column.id)?.cell\">\n <span yuwSkeleton class=\"block h-4 w-full\"></span>\n </td>\n }\n </tr>\n }\n } @else if (_isEmpty()) {\n <tr yuwTr [class]=\"_rowClass()\">\n <td yuwTd [attr.colspan]=\"_columnCount()\" class=\"h-24 text-center text-muted-foreground\">\n {{ emptyText() ?? '' }}\n </td>\n </tr>\n } @else {\n @for (row of table.getRowModel().rows; track row.id) {\n <tr yuwTr [class]=\"_rowClass()\" [attr.data-state]=\"row.getIsSelected() ? 'selected' : null\">\n @for (cell of row.getVisibleCells(); track cell.id) {\n <td yuwTd [class]=\"_cellClasses().get(cell.column.id)?.cell\">\n <ng-container *flexRender=\"cell.column.columnDef.cell; props: cell.getContext(); let rendered\">\n {{ rendered }}\n </ng-container>\n </td>\n }\n </tr>\n }\n }\n </tbody>\n </table>\n</div>\n\n@if (paginated()) {\n <div class=\"flex items-center justify-between gap-4 py-3\">\n @if (selectable()) {\n <p class=\"text-sm text-muted-foreground\">\n {{ table.getSelectedRowModel().rows.length }} / {{ table.getFilteredRowModel().rows.length }}\n </p>\n } @else {\n <span></span>\n }\n\n <div class=\"flex items-center\">\n <yuw-pagination\n [page]=\"currentPage()\"\n (pageChange)=\"onPageChange($event)\"\n [totalPages]=\"table.getPageCount() || 1\"\n [previousLabel]=\"previousPageLabel()\"\n [nextLabel]=\"nextPageLabel()\"\n [ellipsisSrText]=\"paginationEllipsisSrText()\"\n [ariaLabel]=\"paginationAriaLabel()\"\n color=\"secondary\"\n size=\"icon-sm\"\n />\n </div>\n </div>\n}\n", dependencies: [{ kind: "directive", type: YuwTableContainerDirective, selector: "[yuwTableContainer]" }, { kind: "directive", type: YuwTableDirective, selector: "[yuwTable]" }, { kind: "directive", type: YuwTHeadDirective, selector: "[yuwTHead]" }, { kind: "directive", type: YuwTBodyDirective, selector: "[yuwTBody]" }, { kind: "directive", type: YuwTrDirective, selector: "[yuwTr]" }, { kind: "directive", type: YuwThDirective, selector: "[yuwTh]" }, { kind: "directive", type: YuwTdDirective, selector: "[yuwTd]" }, { kind: "directive", type: YuwCaptionDirective, selector: "[yuwCaption]" }, { kind: "component", type: YuwPaginationComponent, selector: "yuw-pagination", inputs: ["page", "totalPages", "previousLabel", "nextLabel", "ellipsisSrText", "size", "color", "ariaLabel"], outputs: ["pageChange"] }, { kind: "directive", type: YuwSkeletonDirective, selector: "[yuwSkeleton]" }, { kind: "directive", type: FlexRenderDirective, selector: "ng-template[flexRender]", inputs: ["flexRender", "flexRenderProps", "flexRenderInjector"] }, { kind: "component", type: NgIcon, selector: "ng-icon", inputs: ["name", "svg", "size", "strokeWidth", "color"] }], changeDetection: i0.ChangeDetectionStrategy.OnPush }); }
2919
+ static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "21.2.8", type: YuwDatatableComponent, isStandalone: true, selector: "yuw-datatable", inputs: { columns: { classPropertyName: "columns", publicName: "columns", isSignal: true, isRequired: false, transformFunction: null }, data: { classPropertyName: "data", publicName: "data", isSignal: true, isRequired: false, transformFunction: null }, sortable: { classPropertyName: "sortable", publicName: "sortable", isSignal: true, isRequired: false, transformFunction: null }, paginated: { classPropertyName: "paginated", publicName: "paginated", isSignal: true, isRequired: false, transformFunction: null }, selectable: { classPropertyName: "selectable", publicName: "selectable", isSignal: true, isRequired: false, transformFunction: null }, emptyText: { classPropertyName: "emptyText", publicName: "emptyText", isSignal: true, isRequired: false, transformFunction: null }, loading: { classPropertyName: "loading", publicName: "loading", isSignal: true, isRequired: false, transformFunction: null }, loadingRows: { classPropertyName: "loadingRows", publicName: "loadingRows", isSignal: true, isRequired: false, transformFunction: null }, previousPageLabel: { classPropertyName: "previousPageLabel", publicName: "previousPageLabel", isSignal: true, isRequired: true, transformFunction: null }, nextPageLabel: { classPropertyName: "nextPageLabel", publicName: "nextPageLabel", isSignal: true, isRequired: true, transformFunction: null }, paginationEllipsisSrText: { classPropertyName: "paginationEllipsisSrText", publicName: "paginationEllipsisSrText", isSignal: true, isRequired: true, transformFunction: null }, paginationAriaLabel: { classPropertyName: "paginationAriaLabel", publicName: "paginationAriaLabel", isSignal: true, isRequired: true, transformFunction: null }, caption: { classPropertyName: "caption", publicName: "caption", isSignal: true, isRequired: false, transformFunction: null }, tableClass: { classPropertyName: "tableClass", publicName: "tableClass", isSignal: true, isRequired: false, transformFunction: null }, appearance: { classPropertyName: "appearance", publicName: "appearance", isSignal: true, isRequired: false, transformFunction: null }, sorting: { classPropertyName: "sorting", publicName: "sorting", isSignal: true, isRequired: false, transformFunction: null }, columnFilters: { classPropertyName: "columnFilters", publicName: "columnFilters", isSignal: true, isRequired: false, transformFunction: null }, columnVisibility: { classPropertyName: "columnVisibility", publicName: "columnVisibility", isSignal: true, isRequired: false, transformFunction: null }, rowSelection: { classPropertyName: "rowSelection", publicName: "rowSelection", isSignal: true, isRequired: false, transformFunction: null }, pagination: { classPropertyName: "pagination", publicName: "pagination", isSignal: true, isRequired: false, transformFunction: null } }, outputs: { sorting: "sortingChange", columnFilters: "columnFiltersChange", columnVisibility: "columnVisibilityChange", rowSelection: "rowSelectionChange", pagination: "paginationChange", rowClicked: "rowClicked", selectedRowsChange: "selectedRowsChange" }, host: { classAttribute: "contents" }, providers: [provideIcons({ lucideChevronDown, lucideChevronUp, lucideChevronsUpDown })], ngImport: i0, template: "<div yuwTableContainer [class]=\"_containerClass()\">\n <table yuwTable [class]=\"_tableClass()\">\n @if (caption()) {\n <caption yuwCaption>{{ caption() }}</caption>\n }\n\n <thead yuwTHead [class]=\"_headClass()\">\n @for (headerGroup of table.getHeaderGroups(); track headerGroup.id) {\n <tr yuwTr [class]=\"_rowClass()\">\n @for (header of headerGroup.headers; track header.id) {\n @let sorted = header.column.getIsSorted();\n <th\n yuwTh\n scope=\"col\"\n [attr.colspan]=\"header.colSpan\"\n [attr.aria-sort]=\"sorted ? _ariaSort[sorted] : null\"\n [class]=\"_cellClasses().get(header.column.id)?.header\"\n >\n @if (!header.isPlaceholder) {\n @if (sortable() && header.column.getCanSort()) {\n <button\n type=\"button\"\n class=\"inline-flex items-center gap-1 select-none hover:text-foreground/80\"\n (click)=\"header.column.toggleSorting()\"\n >\n <ng-container\n *flexRender=\"header.column.columnDef.header; props: header.getContext(); let rendered\"\n >\n {{ rendered }}\n </ng-container>\n\n <ng-icon [name]=\"_sortIcon[sorted || 'none']\" class=\"shrink-0 text-xs\" aria-hidden=\"true\" />\n </button>\n } @else {\n <ng-container *flexRender=\"header.column.columnDef.header; props: header.getContext(); let rendered\">\n {{ rendered }}\n </ng-container>\n }\n }\n </th>\n }\n </tr>\n }\n </thead>\n\n <tbody yuwTBody>\n @if (loading()) {\n @for (row of _skeletonRows(); track row) {\n <tr yuwTr [class]=\"_rowClass()\">\n @for (column of table.getVisibleLeafColumns(); track column.id) {\n <td yuwTd [class]=\"_cellClasses().get(column.id)?.cell\">\n <span yuwSkeleton class=\"block h-4 w-full\"></span>\n </td>\n }\n </tr>\n }\n } @else if (_isEmpty()) {\n <tr yuwTr [class]=\"_rowClass()\">\n <td yuwTd [attr.colspan]=\"_columnCount()\" class=\"h-24 text-center text-muted-foreground\">\n {{ emptyText() ?? '' }}\n </td>\n </tr>\n } @else {\n @for (row of table.getRowModel().rows; track row.id) {\n <tr\n yuwTr\n [class]=\"_rowClass()\"\n [attr.data-state]=\"row.getIsSelected() ? 'selected' : null\"\n (click)=\"onRowClick(row.original)\"\n >\n @for (cell of row.getVisibleCells(); track cell.id) {\n <td yuwTd [class]=\"_cellClasses().get(cell.column.id)?.cell\">\n <ng-container *flexRender=\"cell.column.columnDef.cell; props: cell.getContext(); let rendered\">\n {{ rendered }}\n </ng-container>\n </td>\n }\n </tr>\n }\n }\n </tbody>\n </table>\n</div>\n\n@if (paginated()) {\n <div class=\"flex items-center justify-between gap-4 py-3\">\n @if (selectable()) {\n <p class=\"text-sm text-muted-foreground\">\n {{ table.getSelectedRowModel().rows.length }} / {{ table.getFilteredRowModel().rows.length }}\n </p>\n } @else {\n <span></span>\n }\n\n <div class=\"flex items-center\">\n <yuw-pagination\n [page]=\"currentPage()\"\n (pageChange)=\"onPageChange($event)\"\n [totalPages]=\"table.getPageCount() || 1\"\n [previousLabel]=\"previousPageLabel()\"\n [nextLabel]=\"nextPageLabel()\"\n [ellipsisSrText]=\"paginationEllipsisSrText()\"\n [ariaLabel]=\"paginationAriaLabel()\"\n color=\"secondary\"\n size=\"icon-sm\"\n />\n </div>\n </div>\n}\n", dependencies: [{ kind: "directive", type: YuwTableContainerDirective, selector: "[yuwTableContainer]" }, { kind: "directive", type: YuwTableDirective, selector: "[yuwTable]" }, { kind: "directive", type: YuwTHeadDirective, selector: "[yuwTHead]" }, { kind: "directive", type: YuwTBodyDirective, selector: "[yuwTBody]" }, { kind: "directive", type: YuwTrDirective, selector: "[yuwTr]" }, { kind: "directive", type: YuwThDirective, selector: "[yuwTh]" }, { kind: "directive", type: YuwTdDirective, selector: "[yuwTd]" }, { kind: "directive", type: YuwCaptionDirective, selector: "[yuwCaption]" }, { kind: "component", type: YuwPaginationComponent, selector: "yuw-pagination", inputs: ["page", "totalPages", "previousLabel", "nextLabel", "ellipsisSrText", "size", "color", "ariaLabel"], outputs: ["pageChange"] }, { kind: "directive", type: YuwSkeletonDirective, selector: "[yuwSkeleton]" }, { kind: "directive", type: FlexRenderDirective, selector: "ng-template[flexRender]", inputs: ["flexRender", "flexRenderProps", "flexRenderInjector"] }, { kind: "component", type: NgIcon, selector: "ng-icon", inputs: ["name", "svg", "size", "strokeWidth", "color"] }], changeDetection: i0.ChangeDetectionStrategy.OnPush }); }
2913
2920
  }
2914
2921
  i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.8", ngImport: i0, type: YuwDatatableComponent, decorators: [{
2915
2922
  type: Component,
2916
2923
  args: [{ selector: 'yuw-datatable', imports: [...YuwTableImports, YuwPaginationComponent, YuwSkeletonDirective, FlexRenderDirective, NgIcon], providers: [provideIcons({ lucideChevronDown, lucideChevronUp, lucideChevronsUpDown })], host: {
2917
2924
  class: 'contents',
2918
- }, changeDetection: ChangeDetectionStrategy.OnPush, template: "<div yuwTableContainer [class]=\"_containerClass()\">\n <table yuwTable [class]=\"_tableClass()\">\n @if (caption()) {\n <caption yuwCaption>{{ caption() }}</caption>\n }\n\n <thead yuwTHead [class]=\"_headClass()\">\n @for (headerGroup of table.getHeaderGroups(); track headerGroup.id) {\n <tr yuwTr [class]=\"_rowClass()\">\n @for (header of headerGroup.headers; track header.id) {\n @let sorted = header.column.getIsSorted();\n <th\n yuwTh\n scope=\"col\"\n [attr.colspan]=\"header.colSpan\"\n [attr.aria-sort]=\"sorted ? _ariaSort[sorted] : null\"\n [class]=\"_cellClasses().get(header.column.id)?.header\"\n >\n @if (!header.isPlaceholder) {\n @if (sortable() && header.column.getCanSort()) {\n <button\n type=\"button\"\n class=\"inline-flex items-center gap-1 select-none hover:text-foreground/80\"\n (click)=\"header.column.toggleSorting()\"\n >\n <ng-container\n *flexRender=\"header.column.columnDef.header; props: header.getContext(); let rendered\"\n >\n {{ rendered }}\n </ng-container>\n\n <ng-icon [name]=\"_sortIcon[sorted || 'none']\" class=\"shrink-0 text-xs\" aria-hidden=\"true\" />\n </button>\n } @else {\n <ng-container *flexRender=\"header.column.columnDef.header; props: header.getContext(); let rendered\">\n {{ rendered }}\n </ng-container>\n }\n }\n </th>\n }\n </tr>\n }\n </thead>\n\n <tbody yuwTBody>\n @if (loading()) {\n @for (row of _skeletonRows(); track row) {\n <tr yuwTr [class]=\"_rowClass()\">\n @for (column of table.getVisibleLeafColumns(); track column.id) {\n <td yuwTd [class]=\"_cellClasses().get(column.id)?.cell\">\n <span yuwSkeleton class=\"block h-4 w-full\"></span>\n </td>\n }\n </tr>\n }\n } @else if (_isEmpty()) {\n <tr yuwTr [class]=\"_rowClass()\">\n <td yuwTd [attr.colspan]=\"_columnCount()\" class=\"h-24 text-center text-muted-foreground\">\n {{ emptyText() ?? '' }}\n </td>\n </tr>\n } @else {\n @for (row of table.getRowModel().rows; track row.id) {\n <tr yuwTr [class]=\"_rowClass()\" [attr.data-state]=\"row.getIsSelected() ? 'selected' : null\">\n @for (cell of row.getVisibleCells(); track cell.id) {\n <td yuwTd [class]=\"_cellClasses().get(cell.column.id)?.cell\">\n <ng-container *flexRender=\"cell.column.columnDef.cell; props: cell.getContext(); let rendered\">\n {{ rendered }}\n </ng-container>\n </td>\n }\n </tr>\n }\n }\n </tbody>\n </table>\n</div>\n\n@if (paginated()) {\n <div class=\"flex items-center justify-between gap-4 py-3\">\n @if (selectable()) {\n <p class=\"text-sm text-muted-foreground\">\n {{ table.getSelectedRowModel().rows.length }} / {{ table.getFilteredRowModel().rows.length }}\n </p>\n } @else {\n <span></span>\n }\n\n <div class=\"flex items-center\">\n <yuw-pagination\n [page]=\"currentPage()\"\n (pageChange)=\"onPageChange($event)\"\n [totalPages]=\"table.getPageCount() || 1\"\n [previousLabel]=\"previousPageLabel()\"\n [nextLabel]=\"nextPageLabel()\"\n [ellipsisSrText]=\"paginationEllipsisSrText()\"\n [ariaLabel]=\"paginationAriaLabel()\"\n color=\"secondary\"\n size=\"icon-sm\"\n />\n </div>\n </div>\n}\n" }]
2919
- }], propDecorators: { columns: [{ type: i0.Input, args: [{ isSignal: true, alias: "columns", required: false }] }], data: [{ type: i0.Input, args: [{ isSignal: true, alias: "data", required: false }] }], sortable: [{ type: i0.Input, args: [{ isSignal: true, alias: "sortable", required: false }] }], paginated: [{ type: i0.Input, args: [{ isSignal: true, alias: "paginated", required: false }] }], selectable: [{ type: i0.Input, args: [{ isSignal: true, alias: "selectable", required: false }] }], emptyText: [{ type: i0.Input, args: [{ isSignal: true, alias: "emptyText", required: false }] }], loading: [{ type: i0.Input, args: [{ isSignal: true, alias: "loading", required: false }] }], loadingRows: [{ type: i0.Input, args: [{ isSignal: true, alias: "loadingRows", required: false }] }], previousPageLabel: [{ type: i0.Input, args: [{ isSignal: true, alias: "previousPageLabel", required: true }] }], nextPageLabel: [{ type: i0.Input, args: [{ isSignal: true, alias: "nextPageLabel", required: true }] }], paginationEllipsisSrText: [{ type: i0.Input, args: [{ isSignal: true, alias: "paginationEllipsisSrText", required: true }] }], paginationAriaLabel: [{ type: i0.Input, args: [{ isSignal: true, alias: "paginationAriaLabel", required: true }] }], caption: [{ type: i0.Input, args: [{ isSignal: true, alias: "caption", required: false }] }], tableClass: [{ type: i0.Input, args: [{ isSignal: true, alias: "tableClass", required: false }] }], appearance: [{ type: i0.Input, args: [{ isSignal: true, alias: "appearance", required: false }] }], sorting: [{ type: i0.Input, args: [{ isSignal: true, alias: "sorting", required: false }] }, { type: i0.Output, args: ["sortingChange"] }], columnFilters: [{ type: i0.Input, args: [{ isSignal: true, alias: "columnFilters", required: false }] }, { type: i0.Output, args: ["columnFiltersChange"] }], columnVisibility: [{ type: i0.Input, args: [{ isSignal: true, alias: "columnVisibility", required: false }] }, { type: i0.Output, args: ["columnVisibilityChange"] }], rowSelection: [{ type: i0.Input, args: [{ isSignal: true, alias: "rowSelection", required: false }] }, { type: i0.Output, args: ["rowSelectionChange"] }], pagination: [{ type: i0.Input, args: [{ isSignal: true, alias: "pagination", required: false }] }, { type: i0.Output, args: ["paginationChange"] }], selectedRowsChange: [{ type: i0.Output, args: ["selectedRowsChange"] }] } });
2925
+ }, changeDetection: ChangeDetectionStrategy.OnPush, template: "<div yuwTableContainer [class]=\"_containerClass()\">\n <table yuwTable [class]=\"_tableClass()\">\n @if (caption()) {\n <caption yuwCaption>{{ caption() }}</caption>\n }\n\n <thead yuwTHead [class]=\"_headClass()\">\n @for (headerGroup of table.getHeaderGroups(); track headerGroup.id) {\n <tr yuwTr [class]=\"_rowClass()\">\n @for (header of headerGroup.headers; track header.id) {\n @let sorted = header.column.getIsSorted();\n <th\n yuwTh\n scope=\"col\"\n [attr.colspan]=\"header.colSpan\"\n [attr.aria-sort]=\"sorted ? _ariaSort[sorted] : null\"\n [class]=\"_cellClasses().get(header.column.id)?.header\"\n >\n @if (!header.isPlaceholder) {\n @if (sortable() && header.column.getCanSort()) {\n <button\n type=\"button\"\n class=\"inline-flex items-center gap-1 select-none hover:text-foreground/80\"\n (click)=\"header.column.toggleSorting()\"\n >\n <ng-container\n *flexRender=\"header.column.columnDef.header; props: header.getContext(); let rendered\"\n >\n {{ rendered }}\n </ng-container>\n\n <ng-icon [name]=\"_sortIcon[sorted || 'none']\" class=\"shrink-0 text-xs\" aria-hidden=\"true\" />\n </button>\n } @else {\n <ng-container *flexRender=\"header.column.columnDef.header; props: header.getContext(); let rendered\">\n {{ rendered }}\n </ng-container>\n }\n }\n </th>\n }\n </tr>\n }\n </thead>\n\n <tbody yuwTBody>\n @if (loading()) {\n @for (row of _skeletonRows(); track row) {\n <tr yuwTr [class]=\"_rowClass()\">\n @for (column of table.getVisibleLeafColumns(); track column.id) {\n <td yuwTd [class]=\"_cellClasses().get(column.id)?.cell\">\n <span yuwSkeleton class=\"block h-4 w-full\"></span>\n </td>\n }\n </tr>\n }\n } @else if (_isEmpty()) {\n <tr yuwTr [class]=\"_rowClass()\">\n <td yuwTd [attr.colspan]=\"_columnCount()\" class=\"h-24 text-center text-muted-foreground\">\n {{ emptyText() ?? '' }}\n </td>\n </tr>\n } @else {\n @for (row of table.getRowModel().rows; track row.id) {\n <tr\n yuwTr\n [class]=\"_rowClass()\"\n [attr.data-state]=\"row.getIsSelected() ? 'selected' : null\"\n (click)=\"onRowClick(row.original)\"\n >\n @for (cell of row.getVisibleCells(); track cell.id) {\n <td yuwTd [class]=\"_cellClasses().get(cell.column.id)?.cell\">\n <ng-container *flexRender=\"cell.column.columnDef.cell; props: cell.getContext(); let rendered\">\n {{ rendered }}\n </ng-container>\n </td>\n }\n </tr>\n }\n }\n </tbody>\n </table>\n</div>\n\n@if (paginated()) {\n <div class=\"flex items-center justify-between gap-4 py-3\">\n @if (selectable()) {\n <p class=\"text-sm text-muted-foreground\">\n {{ table.getSelectedRowModel().rows.length }} / {{ table.getFilteredRowModel().rows.length }}\n </p>\n } @else {\n <span></span>\n }\n\n <div class=\"flex items-center\">\n <yuw-pagination\n [page]=\"currentPage()\"\n (pageChange)=\"onPageChange($event)\"\n [totalPages]=\"table.getPageCount() || 1\"\n [previousLabel]=\"previousPageLabel()\"\n [nextLabel]=\"nextPageLabel()\"\n [ellipsisSrText]=\"paginationEllipsisSrText()\"\n [ariaLabel]=\"paginationAriaLabel()\"\n color=\"secondary\"\n size=\"icon-sm\"\n />\n </div>\n </div>\n}\n" }]
2926
+ }], propDecorators: { columns: [{ type: i0.Input, args: [{ isSignal: true, alias: "columns", required: false }] }], data: [{ type: i0.Input, args: [{ isSignal: true, alias: "data", required: false }] }], sortable: [{ type: i0.Input, args: [{ isSignal: true, alias: "sortable", required: false }] }], paginated: [{ type: i0.Input, args: [{ isSignal: true, alias: "paginated", required: false }] }], selectable: [{ type: i0.Input, args: [{ isSignal: true, alias: "selectable", required: false }] }], emptyText: [{ type: i0.Input, args: [{ isSignal: true, alias: "emptyText", required: false }] }], loading: [{ type: i0.Input, args: [{ isSignal: true, alias: "loading", required: false }] }], loadingRows: [{ type: i0.Input, args: [{ isSignal: true, alias: "loadingRows", required: false }] }], previousPageLabel: [{ type: i0.Input, args: [{ isSignal: true, alias: "previousPageLabel", required: true }] }], nextPageLabel: [{ type: i0.Input, args: [{ isSignal: true, alias: "nextPageLabel", required: true }] }], paginationEllipsisSrText: [{ type: i0.Input, args: [{ isSignal: true, alias: "paginationEllipsisSrText", required: true }] }], paginationAriaLabel: [{ type: i0.Input, args: [{ isSignal: true, alias: "paginationAriaLabel", required: true }] }], caption: [{ type: i0.Input, args: [{ isSignal: true, alias: "caption", required: false }] }], tableClass: [{ type: i0.Input, args: [{ isSignal: true, alias: "tableClass", required: false }] }], appearance: [{ type: i0.Input, args: [{ isSignal: true, alias: "appearance", required: false }] }], sorting: [{ type: i0.Input, args: [{ isSignal: true, alias: "sorting", required: false }] }, { type: i0.Output, args: ["sortingChange"] }], columnFilters: [{ type: i0.Input, args: [{ isSignal: true, alias: "columnFilters", required: false }] }, { type: i0.Output, args: ["columnFiltersChange"] }], columnVisibility: [{ type: i0.Input, args: [{ isSignal: true, alias: "columnVisibility", required: false }] }, { type: i0.Output, args: ["columnVisibilityChange"] }], rowSelection: [{ type: i0.Input, args: [{ isSignal: true, alias: "rowSelection", required: false }] }, { type: i0.Output, args: ["rowSelectionChange"] }], pagination: [{ type: i0.Input, args: [{ isSignal: true, alias: "pagination", required: false }] }, { type: i0.Output, args: ["paginationChange"] }], rowClicked: [{ type: i0.Output, args: ["rowClicked"] }], selectedRowsChange: [{ type: i0.Output, args: ["selectedRowsChange"] }] } });
2927
+
2928
+ class YuwDatatableRowSelect {
2929
+ constructor() {
2930
+ this.checked = input(false, ...(ngDevMode ? [{ debugName: "checked" }] : /* istanbul ignore next */ []));
2931
+ this.indeterminate = input(false, ...(ngDevMode ? [{ debugName: "indeterminate" }] : /* istanbul ignore next */ []));
2932
+ this.label = input('Select row', ...(ngDevMode ? [{ debugName: "label" }] : /* istanbul ignore next */ []));
2933
+ this.onToggle = input(() => undefined, ...(ngDevMode ? [{ debugName: "onToggle" }] : /* istanbul ignore next */ []));
2934
+ }
2935
+ toggle() {
2936
+ this.onToggle()();
2937
+ }
2938
+ static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.8", ngImport: i0, type: YuwDatatableRowSelect, deps: [], target: i0.ɵɵFactoryTarget.Component }); }
2939
+ static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.1.0", version: "21.2.8", type: YuwDatatableRowSelect, isStandalone: true, selector: "yuw-datatable-row-select", inputs: { checked: { classPropertyName: "checked", publicName: "checked", isSignal: true, isRequired: false, transformFunction: null }, indeterminate: { classPropertyName: "indeterminate", publicName: "indeterminate", isSignal: true, isRequired: false, transformFunction: null }, label: { classPropertyName: "label", publicName: "label", isSignal: true, isRequired: false, transformFunction: null }, onToggle: { classPropertyName: "onToggle", publicName: "onToggle", isSignal: true, isRequired: false, transformFunction: null } }, ngImport: i0, template: `
2940
+ <yuw-checkbox
2941
+ [checked]="checked()"
2942
+ [indeterminate]="indeterminate()"
2943
+ [ariaLabel]="label()"
2944
+ (checkedChange)="toggle()"
2945
+ (click)="$event.stopPropagation()"
2946
+ />
2947
+ `, isInline: true, dependencies: [{ kind: "component", type: YuwCheckboxComponent, selector: "yuw-checkbox", inputs: ["checked", "indeterminate", "disabled", "required", "invalid", "name", "inputId", "ariaLabel", "ariaLabelledby", "ariaDescribedby", "secondary"], outputs: ["checkedChange", "indeterminateChange"] }], changeDetection: i0.ChangeDetectionStrategy.OnPush }); }
2948
+ }
2949
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.8", ngImport: i0, type: YuwDatatableRowSelect, decorators: [{
2950
+ type: Component,
2951
+ args: [{
2952
+ selector: 'yuw-datatable-row-select',
2953
+ standalone: true,
2954
+ imports: [YuwCheckboxComponent],
2955
+ template: `
2956
+ <yuw-checkbox
2957
+ [checked]="checked()"
2958
+ [indeterminate]="indeterminate()"
2959
+ [ariaLabel]="label()"
2960
+ (checkedChange)="toggle()"
2961
+ (click)="$event.stopPropagation()"
2962
+ />
2963
+ `,
2964
+ changeDetection: ChangeDetectionStrategy.OnPush,
2965
+ }]
2966
+ }], propDecorators: { checked: [{ type: i0.Input, args: [{ isSignal: true, alias: "checked", required: false }] }], indeterminate: [{ type: i0.Input, args: [{ isSignal: true, alias: "indeterminate", required: false }] }], label: [{ type: i0.Input, args: [{ isSignal: true, alias: "label", required: false }] }], onToggle: [{ type: i0.Input, args: [{ isSignal: true, alias: "onToggle", required: false }] }] } });
2920
2967
 
2921
2968
  /**
2922
2969
  * Displays a user or entity avatar with optional image, fallback text/initials, status badge, or overlapping group layout.
@@ -4015,44 +4062,142 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.8", ngImpor
4015
4062
  }]
4016
4063
  }] });
4017
4064
 
4018
- /**
4019
- * yukit-web's class layer for the sidebar menu button, applied on top of the helm
4020
- * `sidebarMenuButtonVariants()` output.
4021
- *
4022
- * Registered through the helm `classes()` utility from the `yuwSidebarMenuButton` directive, which
4023
- * runs *after* the helm directive's own registration on the same element. `classes()` merges its
4024
- * sources in registration order through `twMerge`, so each class here displaces the helm class of
4025
- * the same Tailwind group and modifier stack without needing `!important`.
4026
- *
4027
- * These live on the button rather than on `li[yuwSidebarMenuItem]` because every selector here
4028
- * resolves against the button's own box or subtree: the `<li>` is not the hovered control, never
4029
- * carries `aria-expanded`, and its `> span:last-child` is the `yuwSidebarMenuBadge`, not the label.
4030
- *
4031
- * Three details in the collapsed-to-icon block are load-bearing:
4032
- *
4033
- * - `size-auto!`, `w-full!` and `justify-center!` keep their `!` because the helm declarations they
4034
- * replace (`size-8!`, `p-2!`) are themselves `!important`, which `twMerge` cannot outrank on
4035
- * specificity alone. The helm pins the button to a square; ours fills the rail width and centres
4036
- * the icon.
4037
- * - `[&>span:last-child]:hidden` drops the label while collapsed, leaving the icon alone — the
4038
- * tooltip carries the name in that state.
4039
- * - `text-[length:--spacing(6)]` bumps the icon from the helm's 4 units to 6. The `length:` hint is
4040
- * not optional: `text-[…]` is ambiguous between colour and size, and Tailwind resolves the bare
4041
- * form as a colour, so the icon would never resize.
4042
- */
4065
+ const YUW_SIDEBAR_TRANSITION_MS = 200;
4043
4066
  const yuwSidebarMenuButtonClass = [
4067
+ '[&>span]:truncate',
4068
+ '[&>span]:min-w-0',
4044
4069
  'hover:bg-muted',
4045
4070
  'hover:text-foreground',
4046
4071
  'dark:hover:bg-muted/50',
4047
4072
  'aria-expanded:bg-muted',
4048
4073
  'aria-expanded:text-foreground',
4049
- 'transition-all',
4050
- 'group-data-[collapsible=icon]:size-auto!',
4074
+ 'transition-[background-color,color]',
4075
+ 'duration-200',
4076
+ 'ease-linear',
4077
+ 'motion-reduce:transition-none',
4078
+ '[&_ng-icon]:origin-center',
4079
+ '[&_ng-icon]:transition-transform',
4080
+ '[&_ng-icon]:duration-200',
4081
+ '[&_ng-icon]:ease-linear',
4082
+ 'motion-reduce:[&_ng-icon]:transition-none',
4083
+ 'group-data-[collapsible=icon]:h-auto!',
4051
4084
  'group-data-[collapsible=icon]:w-full!',
4052
- 'group-data-[collapsible=icon]:justify-center!',
4053
- 'group-data-[collapsible=icon]:[&>span:last-child]:hidden',
4054
- 'group-data-[collapsible=icon]:[&_ng-icon]:text-[length:--spacing(6)]',
4085
+ 'group-data-[yuw-rail=on]:justify-center!',
4086
+ 'group-data-[yuw-rail=on]:[&>span]:hidden',
4087
+ 'group-data-[yuw-rail=on]:[&_ng-icon]:scale-150',
4088
+ ].join(' ');
4089
+ const yuwSidebarMenuChevronClass = [
4090
+ 'ms-auto',
4091
+ 'shrink-0',
4092
+ 'transition-transform',
4093
+ 'duration-200',
4094
+ 'text-[length:--spacing(4)]!',
4095
+ 'group-aria-expanded/menu-button:rotate-90',
4096
+ 'group-data-[yuw-rail=on]:hidden!',
4097
+ ].join(' ');
4098
+ const yuwSidebarFlyoutClass = [
4099
+ 'w-56',
4100
+ 'ms-2',
4101
+ 'p-1',
4102
+ 'flex',
4103
+ 'flex-col',
4104
+ 'gap-0.5',
4105
+ '[&_[data-sidebar=menu-sub]]:mx-0',
4106
+ '[&_[data-sidebar=menu-sub]]:translate-x-0',
4107
+ '[&_[data-sidebar=menu-sub]]:border-0',
4108
+ '[&_[data-sidebar=menu-sub]]:px-0',
4109
+ '[&_[data-sidebar=menu-sub]]:py-0',
4110
+ '[&_[data-sidebar=menu-sub]]:gap-0.5',
4111
+ '[&_[data-sidebar=menu-sub-button]]:translate-x-0',
4112
+ '[&_[data-sidebar=menu-sub-button]]:h-8',
4113
+ ].join(' ');
4114
+ const yuwSidebarFlyoutLabelClass = [
4115
+ 'text-muted-foreground',
4116
+ 'px-2',
4117
+ 'pt-1',
4118
+ 'pb-1.5',
4119
+ 'text-xs',
4120
+ 'font-medium',
4121
+ 'truncate',
4122
+ ].join(' ');
4123
+ const yuwSidebarContainerClass = 'contain-layout';
4124
+ const yuwSidebarContentClass = [
4125
+ 'overflow-y-auto',
4126
+ 'group-data-[collapsible=icon]:overflow-y-auto!',
4127
+ 'group-data-[collapsible=icon]:overflow-x-hidden',
4128
+ 'group-data-[yuw-rail=on]:gap-1',
4055
4129
  ].join(' ');
4130
+ const yuwSidebarGroupLabelClass = [
4131
+ 'group-data-[collapsible=icon]:mt-0!',
4132
+ 'group-data-[collapsible=icon]:opacity-100',
4133
+ 'transition-opacity',
4134
+ 'duration-200',
4135
+ 'ease-linear',
4136
+ 'motion-reduce:transition-none',
4137
+ 'group-data-[yuw-rail=on]:hidden',
4138
+ ].join(' ');
4139
+ const yuwSidebarGroupClass = 'group-data-[yuw-rail=on]:py-0';
4140
+ const yuwSidebarSubmenuWrapperClass = [
4141
+ 'grid',
4142
+ 'transition-[grid-template-rows]',
4143
+ 'duration-200',
4144
+ 'ease-out',
4145
+ 'motion-reduce:transition-none',
4146
+ '[&>*]:min-h-0',
4147
+ '[&>*]:overflow-hidden',
4148
+ ].join(' ');
4149
+ const yuwSidebarSubmenuOpenClass = 'grid-rows-[1fr]';
4150
+ const yuwSidebarSubmenuClosedClass = 'grid-rows-[0fr]';
4151
+ const yuwSidebarMenuBadgeClass = [
4152
+ 'transition-opacity',
4153
+ 'duration-200',
4154
+ 'ease-linear',
4155
+ 'motion-reduce:transition-none',
4156
+ 'group-data-[yuw-rail=on]:opacity-0',
4157
+ 'group-data-[yuw-rail=on]:block!',
4158
+ 'group-data-[yuw-rail=on]:pointer-events-none',
4159
+ ].join(' ');
4160
+ const yuwSidebarGroupLabelTextClass = ['truncate', 'block', 'min-w-0'].join(' ');
4161
+ const yuwSidebarMenuSubButtonClass = ['[&>span]:truncate', '[&>span]:min-w-0'].join(' ');
4162
+
4163
+ /**
4164
+ * Tracks the sidebar's collapsed state, and a second copy of it that lags behind the width animation.
4165
+ *
4166
+ * The helm flips `data-collapsible` the instant the state changes, while the panel takes
4167
+ * `--sidebar-transition-duration` to reach its new width. Anything keyed off that attribute therefore
4168
+ * restyles against a panel that is still the old size — labels vanish and icons jump to rail geometry
4169
+ * while there is still 16rem of sidebar around them.
4170
+ *
4171
+ * `railSettled` fixes that asymmetrically, because the two directions want opposite timing:
4172
+ *
4173
+ * - Collapsing, the rail look has to wait for the panel to actually be narrow. Applying it up front is
4174
+ * what produces the jump.
4175
+ * - Expanding, the rail look has to go immediately. The labels need the whole animation to fade and
4176
+ * ellipsis into place, so waiting would replace one jump with another at the far end.
4177
+ *
4178
+ * The delay runs through `timer` rather than a `setTimeout` inside an `effect`, and that is not a
4179
+ * stylistic choice: this app is zoneless, so a signal written from a bare timer callback notifies
4180
+ * nobody. Components reading `railSettled` in a template binding are `OnPush`, so they would keep
4181
+ * their stale view until something else happened to schedule a check — the signal flips, the DOM does
4182
+ * not. Going through `toSignal` puts the write back under Angular's own scheduling.
4183
+ *
4184
+ * Provided at the root so `<yuw-sidebar>` and the nav share one instance — the component stamps the
4185
+ * attribute the class layers select on, and the nav reads the same signal to decide between accordion
4186
+ * and flyout, so the two must agree on the exact frame.
4187
+ */
4188
+ class YuwSidebarRailService {
4189
+ constructor() {
4190
+ this.sidebar = inject(HlmSidebarService);
4191
+ this.collapsed = computed(() => (this.sidebar.isMobile() ? !this.sidebar.openMobile() : !this.sidebar.open()), ...(ngDevMode ? [{ debugName: "collapsed" }] : /* istanbul ignore next */ []));
4192
+ this.railSettled = toSignal(toObservable(this.collapsed).pipe(switchMap((collapsed) => (collapsed ? timer(YUW_SIDEBAR_TRANSITION_MS).pipe(map(() => true)) : of(false)))), { initialValue: false });
4193
+ }
4194
+ static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.8", ngImport: i0, type: YuwSidebarRailService, deps: [], target: i0.ɵɵFactoryTarget.Injectable }); }
4195
+ static { this.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "21.2.8", ngImport: i0, type: YuwSidebarRailService, providedIn: 'root' }); }
4196
+ }
4197
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.8", ngImport: i0, type: YuwSidebarRailService, decorators: [{
4198
+ type: Injectable,
4199
+ args: [{ providedIn: 'root' }]
4200
+ }] });
4056
4201
 
4057
4202
  /**
4058
4203
  * Outermost layout directive for a sidebar page. Wraps the sidebar and the main content, and owns
@@ -4107,8 +4252,33 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.8", ngImpor
4107
4252
  hostDirectives: [HlmSidebarHeader],
4108
4253
  }]
4109
4254
  }] });
4110
- /** Scrollable middle area of the sidebar that holds the navigation groups. */
4255
+ /**
4256
+ * Scrollable middle area of the sidebar that holds the navigation groups.
4257
+ *
4258
+ * Restores vertical scrolling in the collapsed state, which the composed primitive switches off with
4259
+ * `group-data-[collapsible=icon]:overflow-hidden`. That is a fair default for a rail of icons alone,
4260
+ * but ours keeps expandable entries reachable there, so a tall nav has to be able to scroll rather
4261
+ * than have its last icons clipped. Horizontal overflow stays hidden: nothing should scroll sideways
4262
+ * in a rail that narrow.
4263
+ *
4264
+ * The `!` is needed because the helm's own declaration sits in the same Tailwind group at the same
4265
+ * modifier, and `twMerge` resolves that by keeping the last one — which would be ours already, except
4266
+ * `overflow-hidden` and `overflow-y-auto` are different properties to it, so both survive and the
4267
+ * shorthand wins on order.
4268
+ *
4269
+ * The scrollbar itself stays hidden, which the primitive's own `no-scrollbar` already handles: a
4270
+ * gutter that only appears once the nav happens to overflow shifts the icons sideways, and the rail is
4271
+ * too narrow to spend 11px on it. Wheel, trackpad and keyboard still scroll; only the thumb is gone.
4272
+ *
4273
+ * Also spaces the groups it stacks while collapsed. Each group's own menu spaces its items, so with
4274
+ * the groups' vertical padding dropped there was nothing left between the last icon of one and the
4275
+ * first of the next; matching that spacing here is what makes the rail read as one evenly spaced
4276
+ * column rather than blocks butted together.
4277
+ */
4111
4278
  class YuwSidebarContentDirective {
4279
+ constructor() {
4280
+ classes(() => yuwSidebarContentClass);
4281
+ }
4112
4282
  static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.8", ngImport: i0, type: YuwSidebarContentDirective, deps: [], target: i0.ɵɵFactoryTarget.Directive }); }
4113
4283
  static { this.ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "14.0.0", version: "21.2.8", type: YuwSidebarContentDirective, isStandalone: true, selector: "[yuwSidebarContent], yuw-sidebar-content", hostDirectives: [{ directive: i1$q.HlmSidebarContent }], ngImport: i0 }); }
4114
4284
  }
@@ -4118,7 +4288,7 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.8", ngImpor
4118
4288
  selector: '[yuwSidebarContent], yuw-sidebar-content',
4119
4289
  hostDirectives: [HlmSidebarContent],
4120
4290
  }]
4121
- }] });
4291
+ }], ctorParameters: () => [] });
4122
4292
  /** Bottom area of the sidebar, below the scrollable content. */
4123
4293
  class YuwSidebarFooterDirective {
4124
4294
  static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.8", ngImport: i0, type: YuwSidebarFooterDirective, deps: [], target: i0.ɵɵFactoryTarget.Directive }); }
@@ -4131,8 +4301,19 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.8", ngImpor
4131
4301
  hostDirectives: [HlmSidebarFooter],
4132
4302
  }]
4133
4303
  }] });
4134
- /** A titled section of the sidebar. */
4304
+ /**
4305
+ * A titled section of the sidebar.
4306
+ *
4307
+ * Drops its vertical padding once collapsed to icons. The composed primitive pads every side with
4308
+ * `p-2`, which is right while headings are visible and separating one group from the next, but on the
4309
+ * rail those headings are gone and two adjacent groups contribute 8px each — a gap in the middle of
4310
+ * what reads as one column of icons. Horizontal padding stays: it is what keeps the icons off the
4311
+ * rail's edges.
4312
+ */
4135
4313
  class YuwSidebarGroupDirective {
4314
+ constructor() {
4315
+ classes(() => yuwSidebarGroupClass);
4316
+ }
4136
4317
  static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.8", ngImport: i0, type: YuwSidebarGroupDirective, deps: [], target: i0.ɵɵFactoryTarget.Directive }); }
4137
4318
  static { this.ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "14.0.0", version: "21.2.8", type: YuwSidebarGroupDirective, isStandalone: true, selector: "[yuwSidebarGroup], yuw-sidebar-group", hostDirectives: [{ directive: i1$q.HlmSidebarGroup }], ngImport: i0 }); }
4138
4319
  }
@@ -4142,9 +4323,20 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.8", ngImpor
4142
4323
  selector: '[yuwSidebarGroup], yuw-sidebar-group',
4143
4324
  hostDirectives: [HlmSidebarGroup],
4144
4325
  }]
4145
- }] });
4146
- /** Heading of a sidebar group. Fades out when the sidebar collapses to icons. */
4326
+ }], ctorParameters: () => [] });
4327
+ /**
4328
+ * Heading of a sidebar group. Removed from the layout when the sidebar collapses to icons.
4329
+ *
4330
+ * The composed primitive hides it with `-mt-8` plus `opacity-0`, which leaves the heading in the flow
4331
+ * still occupying its `h-8` box and cancels that box with a negative margin. The two only net to zero
4332
+ * while the heading is exactly one line at exactly that height, so a group heading left a visible gap
4333
+ * between the icons of one group and the next. `hidden` takes it out of the flow instead, and the
4334
+ * margin is zeroed so the collapsed rail is not pulled upwards by a box that no longer exists.
4335
+ */
4147
4336
  class YuwSidebarGroupLabelDirective {
4337
+ constructor() {
4338
+ classes(() => yuwSidebarGroupLabelClass);
4339
+ }
4148
4340
  static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.8", ngImport: i0, type: YuwSidebarGroupLabelDirective, deps: [], target: i0.ɵɵFactoryTarget.Directive }); }
4149
4341
  static { this.ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "14.0.0", version: "21.2.8", type: YuwSidebarGroupLabelDirective, isStandalone: true, selector: "div[yuwSidebarGroupLabel], button[yuwSidebarGroupLabel]", hostDirectives: [{ directive: i1$q.HlmSidebarGroupLabel }], ngImport: i0 }); }
4150
4342
  }
@@ -4154,7 +4346,7 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.8", ngImpor
4154
4346
  selector: 'div[yuwSidebarGroupLabel], button[yuwSidebarGroupLabel]',
4155
4347
  hostDirectives: [HlmSidebarGroupLabel],
4156
4348
  }]
4157
- }] });
4349
+ }], ctorParameters: () => [] });
4158
4350
  /** Body of a sidebar group, wrapping its menu. */
4159
4351
  class YuwSidebarGroupContentDirective {
4160
4352
  static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.8", ngImport: i0, type: YuwSidebarGroupContentDirective, deps: [], target: i0.ɵɵFactoryTarget.Directive }); }
@@ -4224,16 +4416,56 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.8", ngImpor
4224
4416
  * Interactive control of a sidebar menu item. Accepts `variant` (`'default'`, `'outline'`), `size`
4225
4417
  * (`'default'`, `'sm'`, `'lg'`) and `isActive`.
4226
4418
  *
4227
- * To label the item while the sidebar is collapsed to icons, add Spartan's `tooltip` input
4228
- * alongside this directive it comes from the underlying menu-button primitive and is only shown
4229
- * in the collapsed state. It cannot be re-forwarded through this wrapper's `hostDirectives`
4230
- * (`tooltip` is the alias `HlmSidebarMenuButton` gives its own composed `BrnTooltip`, not a public
4231
- * input of its own), so bind it with `[attr.tooltip]` rather than `[tooltip]` when the value comes
4232
- * from an expression.
4419
+ * `tooltip` labels the item while the sidebar is collapsed to icons, where the label itself is
4420
+ * hidden; the composed primitive shows it only in that state, and only for entries with no flyout of
4421
+ * their own an entry with children opens its submenu on the same hover instead.
4422
+ *
4423
+ * Reaching that input takes composing `BrnTooltip` here under the same `tooltip` alias the helm uses,
4424
+ * rather than forwarding it. `HlmSidebarMenuButton` publishes the alias on its own `hostDirectives`
4425
+ * entry, which does not make it an input of the helm directive — a forward cannot be re-forwarded, the
4426
+ * same limit `[yuwSidebarFlyoutTrigger]` runs into. Angular resolves both entries to the one
4427
+ * `BrnTooltip` instance on the element, so the helm keeps driving `mutableTooltipDisabled` (which is
4428
+ * what confines the tooltip to the collapsed state) while this binding supplies its content.
4429
+ *
4430
+ * `[attr.tooltip]` is not a substitute, and was the bug: it writes an HTML attribute, which never
4431
+ * reaches a signal input, so the tooltip stayed enabled with `null` content and silently showed
4432
+ * nothing.
4233
4433
  *
4234
4434
  * Carries `yuwSidebarMenuButtonClass`, our hover/expanded colouring and collapsed-to-icon geometry.
4235
- * The `classes()` registration below runs after the composed `HlmSidebarMenuButton`'s own, so our
4236
- * classes merge last and win see `sidebar.variants.ts`.
4435
+ * The `classes()` registration below runs after the composed `HlmSidebarMenuButton`'s own, and
4436
+ * `classes()` merges its sources in registration order through `twMerge`, so each of our classes
4437
+ * displaces the helm class of the same Tailwind group and modifier stack without `!important`.
4438
+ *
4439
+ * Those classes sit on the button rather than on `li[yuwSidebarMenuItem]` because every selector in
4440
+ * them resolves against the button's own box or subtree: the `<li>` is not the hovered control, never
4441
+ * carries `aria-expanded`, and its `> span:last-child` is the badge, not the label.
4442
+ *
4443
+ * Three details of the collapsed-to-icon block are load-bearing:
4444
+ *
4445
+ * - `h-auto!`, `w-full!` and `justify-center!` keep their `!` because the helm declarations they
4446
+ * replace (`size-8!`, `p-2!`) are themselves `!important`, which `twMerge` cannot outrank on
4447
+ * specificity alone. The helm pins the button to a square; ours fills the rail width and centres
4448
+ * the icon. Both halves of `size-8!` have to be named separately: a single `size-auto!` occupies
4449
+ * the same `twMerge` group as the base `w-full`, dropping it, so the button would fall back to
4450
+ * shrink-to-fit for the whole width animation — long enough for the label to stop ellipsing and
4451
+ * the trailing chevron to sit against it.
4452
+ * - `[&>span]:hidden` drops the label while collapsed, leaving the icon alone — the tooltip carries
4453
+ * the name in that state, or the flyout does for an entry with children. Matched by element rather
4454
+ * than by `:last-child` (which is what the helm's own `truncate` uses): an expandable entry ends
4455
+ * with a trailing chevron, so the label is no longer the last child and a positional selector
4456
+ * would skip exactly those entries. `span` is unambiguous here — the label is the only one a menu
4457
+ * button has, with the badge living outside the button on the `<li>`.
4458
+ * - The icon grows through `scale-150` rather than a font-size bump, so it can be transitioned: only
4459
+ * `transform`-family properties animate on the compositor, and a `font-size` change would relayout
4460
+ * the row on every frame.
4461
+ *
4462
+ * Which state each class hangs off is load-bearing, because the two attributes fire at different
4463
+ * times. `data-collapsible` flips the instant the toggle is pressed; `data-yuw-rail` waits for the
4464
+ * width animation to finish. Anything that should hold its expanded look *through* the animation
4465
+ * therefore keys off the rail attribute — the label's `hidden`, the centring, the icon's scale — while
4466
+ * the width and height overrides key off `collapsible`, to displace the helm's `size-8!` before it can
4467
+ * snap the row to 32px and truncate the label away in the first frame. That snap is what made the text vanish
4468
+ * on click instead of ellipsing gradually as the panel narrows.
4237
4469
  */
4238
4470
  class YuwSidebarMenuButtonDirective {
4239
4471
  constructor() {
@@ -4290,8 +4522,19 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.8", ngImpor
4290
4522
  hostDirectives: [HlmSidebarMenuSubItem],
4291
4523
  }]
4292
4524
  }] });
4293
- /** Interactive control of a sidebar submenu item. Accepts `size` (`'sm'`, `'md'`) and `isActive`. */
4525
+ /**
4526
+ * Interactive control of a sidebar submenu item. Accepts `size` (`'sm'`, `'md'`) and `isActive`.
4527
+ *
4528
+ * Carries the same label clamp as `[yuwSidebarMenuButton]`. The composed primitive already truncates
4529
+ * its `span:last-child`, but truncation cannot fire while the span is a flex item at its default
4530
+ * `min-width: auto`: that floor keeps it at content width, so the panel widens the row instead of the
4531
+ * text ellipsing. `min-w-0` is what lets it shrink, and the `[&>span]` selector covers a label that is
4532
+ * no longer the last child.
4533
+ */
4294
4534
  class YuwSidebarMenuSubButtonDirective {
4535
+ constructor() {
4536
+ classes(() => yuwSidebarMenuSubButtonClass);
4537
+ }
4295
4538
  static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.8", ngImport: i0, type: YuwSidebarMenuSubButtonDirective, deps: [], target: i0.ɵɵFactoryTarget.Directive }); }
4296
4539
  static { this.ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "14.0.0", version: "21.2.8", type: YuwSidebarMenuSubButtonDirective, isStandalone: true, selector: "a[yuwSidebarMenuSubButton], button[yuwSidebarMenuSubButton]", hostDirectives: [{ directive: i1$q.HlmSidebarMenuSubButton, inputs: ["size", "size", "isActive", "isActive", "closeMobileSidebarOnClick", "closeMobileSidebarOnClick"] }], ngImport: i0 }); }
4297
4540
  }
@@ -4301,7 +4544,180 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.8", ngImpor
4301
4544
  selector: 'a[yuwSidebarMenuSubButton], button[yuwSidebarMenuSubButton]',
4302
4545
  hostDirectives: [{ directive: HlmSidebarMenuSubButton, inputs: ['size', 'isActive', 'closeMobileSidebarOnClick'] }],
4303
4546
  }]
4547
+ }], ctorParameters: () => [] });
4548
+ /**
4549
+ * Host of a collapsed-state flyout: the element that scopes the overlay for one entry. Apply
4550
+ * alongside `[yuwSidebarMenuItem]` on the `<li>` holding the entry and its panel.
4551
+ *
4552
+ * Provides `BrnHoverCardContentService` itself instead of composing `HlmHoverCard`. The service has
4553
+ * to be scoped per `<li>` — it holds the single overlay and its content, so a shared one would have
4554
+ * every entry in the sidebar fighting over the same panel — and providing it here is all that is
4555
+ * needed for that. What `HlmHoverCard` adds on top is a `contentChild` pairing that assigns the
4556
+ * trigger's content in `ngAfterContentInit`, and that pairing is actively harmful here: it writes
4557
+ * into the same writable signal the trigger's own input feeds, so its one-time value outlives and
4558
+ * overrides the binding that is supposed to turn the flyout off while the sidebar is expanded.
4559
+ */
4560
+ class YuwSidebarFlyoutHostDirective {
4561
+ static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.8", ngImport: i0, type: YuwSidebarFlyoutHostDirective, deps: [], target: i0.ɵɵFactoryTarget.Directive }); }
4562
+ static { this.ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "14.0.0", version: "21.2.8", type: YuwSidebarFlyoutHostDirective, isStandalone: true, selector: "[yuwSidebarFlyoutHost]", providers: [BrnHoverCardContentService], ngImport: i0 }); }
4563
+ }
4564
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.8", ngImport: i0, type: YuwSidebarFlyoutHostDirective, decorators: [{
4565
+ type: Directive,
4566
+ args: [{
4567
+ selector: '[yuwSidebarFlyoutHost]',
4568
+ providers: [BrnHoverCardContentService],
4569
+ }]
4570
+ }] });
4571
+ /**
4572
+ * The entry whose hover opens a flyout. Apply to the same element as `[yuwSidebarMenuButton]`, bound
4573
+ * to the panel's `<ng-template>` reference — or to `undefined` to switch the flyout off entirely,
4574
+ * which is how an expanded sidebar keeps its submenus inline.
4575
+ *
4576
+ * Drives `BrnHoverCardContentService` directly instead of composing `BrnHoverCardTrigger`. The brain
4577
+ * trigger has no way to be turned off once it has run: it feeds the panel to the service through an
4578
+ * effect that ignores falsy values, and the service's `show()` consults only its stored content, so
4579
+ * a trigger that was ever enabled keeps opening its overlay forever. Rebinding to `undefined` cannot
4580
+ * undo it, and neither can `hide()`, which detaches the overlay but leaves the content in place.
4581
+ * Owning the wiring here is what makes an unbound panel mean "inert".
4582
+ *
4583
+ * The `effect` is the whole lifecycle: it runs when a panel arrives, and its `onCleanup` closes the
4584
+ * overlay and drops the subscription when the panel goes away or the entry is destroyed. Nothing
4585
+ * else tracks teardown, which is why there is no `DestroyRef` or `takeUntilDestroyed` here — a second
4586
+ * mechanism would only be able to disagree with this one.
4587
+ *
4588
+ * Delays are read inside `switchMap` rather than captured when the effect runs, so retuning them
4589
+ * does not tear down and rebuild the subscription.
4590
+ *
4591
+ * `distinctUntilChanged` before the timer is load-bearing, and not as an optimisation: the five
4592
+ * merged sources overlap, so crossing from the entry to the panel emits a `mouseleave` and the
4593
+ * panel's own hover almost together, and `mouseenter` and `focusin` both fire on the same pointer
4594
+ * arriving. Each duplicate would restart `switchMap` and cancel the timer already in flight, so a
4595
+ * repeat during the show delay could keep the panel from ever opening.
4596
+ *
4597
+ * It cannot dedupe the crossing itself, though — that genuinely alternates `false` then `true`, so
4598
+ * both values are distinct and both survive. `toggle` is therefore guarded against the state it is
4599
+ * already in, because `show()` is not idempotent: it calls `detach()` then `attach()`, tearing the
4600
+ * panel down and rebuilding it. Re-showing an open panel replays its enter animation, which is the
4601
+ * flicker you get when the pointer moves from the rail into the flyout.
4602
+ *
4603
+ * Note there is no click handling. `BrnHoverCardTrigger` maps a click to `false`, which is right for
4604
+ * a hover card — clicking the trigger dismisses it — and wrong for a nav rail, where the entry's own
4605
+ * click has nothing to collapse while collapsed and closing the panel would take away the links the
4606
+ * pointer is travelling to. Activating a child closes the flyout anyway, since the pointer leaves
4607
+ * the panel as the page changes.
4608
+ *
4609
+ * `align` is `'right'` for a sidebar flyout rather than the hover card's own `'bottom'`. It is set as
4610
+ * an input rather than through `provideBrnHoverCardDefaultOptions` because that provider types its
4611
+ * `align` as `'top' | 'bottom'`, even though the position map handles all four sides.
4612
+ */
4613
+ class YuwSidebarFlyoutTriggerDirective {
4614
+ constructor() {
4615
+ this.element = inject(ElementRef);
4616
+ this.viewContainerRef = inject(ViewContainerRef);
4617
+ this.service = inject(BrnHoverCardContentService);
4618
+ this.panel = input(undefined, { ...(ngDevMode ? { debugName: "panel" } : /* istanbul ignore next */ {}), alias: 'yuwSidebarFlyoutTrigger' });
4619
+ this.align = input('right', ...(ngDevMode ? [{ debugName: "align" }] : /* istanbul ignore next */ []));
4620
+ this.sideOffset = input(0, { ...(ngDevMode ? { debugName: "sideOffset" } : /* istanbul ignore next */ {}), transform: numberAttribute });
4621
+ this.showDelay = input(120, { ...(ngDevMode ? { debugName: "showDelay" } : /* istanbul ignore next */ {}), transform: numberAttribute });
4622
+ this.hideDelay = input(300, { ...(ngDevMode ? { debugName: "hideDelay" } : /* istanbul ignore next */ {}), transform: numberAttribute });
4623
+ this.pointerOver = merge(fromEvent(this.element.nativeElement, 'mouseenter').pipe(map(() => true)), fromEvent(this.element.nativeElement, 'mouseleave').pipe(map(() => false)), fromEvent(this.element.nativeElement, 'focusin').pipe(map(() => true)), fromEvent(this.element.nativeElement, 'focusout').pipe(map(() => false)), this.service.hovered$);
4624
+ effect((onCleanup) => {
4625
+ const panel = this.panel();
4626
+ if (!panel)
4627
+ return;
4628
+ this.service.setConfig({
4629
+ attachTo: this.element,
4630
+ align: this.align(),
4631
+ sideOffset: this.sideOffset(),
4632
+ });
4633
+ this.service.setContent(panel, this.viewContainerRef);
4634
+ const subscription = this.pointerOver
4635
+ .pipe(distinctUntilChanged(), switchMap$1((visible) => timer(visible ? this.showDelay() : this.hideDelay()).pipe(map(() => visible))))
4636
+ .subscribe((visible) => this.toggle(visible));
4637
+ onCleanup(() => {
4638
+ subscription.unsubscribe();
4639
+ this.toggle(false);
4640
+ });
4641
+ });
4642
+ }
4643
+ toggle(open) {
4644
+ if (open === (this.service.state() === 'open'))
4645
+ return;
4646
+ this.service.setState(open ? 'open' : 'closed');
4647
+ if (open) {
4648
+ this.service.show();
4649
+ return;
4650
+ }
4651
+ this.service.hide();
4652
+ }
4653
+ static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.8", ngImport: i0, type: YuwSidebarFlyoutTriggerDirective, deps: [], target: i0.ɵɵFactoryTarget.Directive }); }
4654
+ static { this.ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "17.1.0", version: "21.2.8", type: YuwSidebarFlyoutTriggerDirective, isStandalone: true, selector: "[yuwSidebarFlyoutTrigger]", inputs: { panel: { classPropertyName: "panel", publicName: "yuwSidebarFlyoutTrigger", isSignal: true, isRequired: false, transformFunction: null }, align: { classPropertyName: "align", publicName: "align", isSignal: true, isRequired: false, transformFunction: null }, sideOffset: { classPropertyName: "sideOffset", publicName: "sideOffset", isSignal: true, isRequired: false, transformFunction: null }, showDelay: { classPropertyName: "showDelay", publicName: "showDelay", isSignal: true, isRequired: false, transformFunction: null }, hideDelay: { classPropertyName: "hideDelay", publicName: "hideDelay", isSignal: true, isRequired: false, transformFunction: null } }, ngImport: i0 }); }
4655
+ }
4656
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.8", ngImport: i0, type: YuwSidebarFlyoutTriggerDirective, decorators: [{
4657
+ type: Directive,
4658
+ args: [{
4659
+ selector: '[yuwSidebarFlyoutTrigger]',
4660
+ }]
4661
+ }], ctorParameters: () => [], propDecorators: { panel: [{ type: i0.Input, args: [{ isSignal: true, alias: "yuwSidebarFlyoutTrigger", required: false }] }], align: [{ type: i0.Input, args: [{ isSignal: true, alias: "align", required: false }] }], sideOffset: [{ type: i0.Input, args: [{ isSignal: true, alias: "sideOffset", required: false }] }], showDelay: [{ type: i0.Input, args: [{ isSignal: true, alias: "showDelay", required: false }] }], hideDelay: [{ type: i0.Input, args: [{ isSignal: true, alias: "hideDelay", required: false }] }] } });
4662
+ /**
4663
+ * Marks the `<ng-template>` holding a flyout's markup, and is what `[yuwSidebarFlyoutTrigger]` is
4664
+ * bound to. Exported as `yuwSidebarFlyoutPanel` so the template can name it.
4665
+ *
4666
+ * Structural — the composed primitive injects the `TemplateRef`, which is what lets the panel be
4667
+ * portalled into a CDK overlay instead of rendering inside the rail.
4668
+ *
4669
+ * The trigger is bound to the template's own `#ref` (a `TemplateRef`, which its input accepts), so
4670
+ * this directive is never referenced by name — but it cannot be dropped: it is the sole provider of
4671
+ * the exposed state and side tokens that `[yuwSidebarFlyout]` injects from its host, and without it
4672
+ * the panel throws NG0201 the moment the overlay instantiates it.
4673
+ */
4674
+ class YuwSidebarFlyoutPanelDirective {
4675
+ static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.8", ngImport: i0, type: YuwSidebarFlyoutPanelDirective, deps: [], target: i0.ɵɵFactoryTarget.Directive }); }
4676
+ static { this.ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "14.0.0", version: "21.2.8", type: YuwSidebarFlyoutPanelDirective, isStandalone: true, selector: "ng-template[yuwSidebarFlyoutPanel]", hostDirectives: [{ directive: i2$1.HlmHoverCardPortal }], ngImport: i0 }); }
4677
+ }
4678
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.8", ngImport: i0, type: YuwSidebarFlyoutPanelDirective, decorators: [{
4679
+ type: Directive,
4680
+ args: [{
4681
+ selector: 'ng-template[yuwSidebarFlyoutPanel]',
4682
+ hostDirectives: [HlmHoverCardPortal],
4683
+ }]
4304
4684
  }] });
4685
+ /**
4686
+ * The flyout's visible surface. Apply to the single root element inside a `[yuwSidebarFlyoutPanel]`
4687
+ * template.
4688
+ *
4689
+ * Separate from the panel marker because the two sit on different nodes: the marker is the
4690
+ * `<ng-template>`, this is the element the overlay renders. Carries the popover surface of the
4691
+ * composed helm content plus `yuwSidebarFlyoutClass`.
4692
+ *
4693
+ * That class layer exists because the panel lives in the overlay, outside the sidebar's DOM subtree,
4694
+ * and so is no longer a descendant of the `group/sidebar-wrapper` element. Every
4695
+ * `group-data-[collapsible=…]` selector therefore resolves against nothing and stays inert —
4696
+ * including the `hidden` that `HlmSidebarMenuSub` and `HlmSidebarMenuSubButton` apply to themselves
4697
+ * in exactly this state, which is why the submenu markup renders visible in here with no override.
4698
+ * What the layer undoes instead is the indentation and vertical rule those primitives carry for the
4699
+ * inline case, which make no sense in a panel.
4700
+ *
4701
+ * The gap between rail and panel is that layer's `ms-2`, not the trigger's `sideOffset`, which is
4702
+ * deliberately `0`. An offset moves the overlay away from the trigger and leaves dead space between
4703
+ * them: crossing it slowly means the pointer is over neither element, and the hover card closes
4704
+ * mid-journey. A margin keeps the same visual gap inside the overlay's own box, so the pointer never
4705
+ * leaves the hover target on its way in.
4706
+ */
4707
+ class YuwSidebarFlyoutDirective {
4708
+ constructor() {
4709
+ classes(() => yuwSidebarFlyoutClass);
4710
+ }
4711
+ static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.8", ngImport: i0, type: YuwSidebarFlyoutDirective, deps: [], target: i0.ɵɵFactoryTarget.Directive }); }
4712
+ static { this.ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "14.0.0", version: "21.2.8", type: YuwSidebarFlyoutDirective, isStandalone: true, selector: "[yuwSidebarFlyout]", hostDirectives: [{ directive: i2$1.HlmHoverCardContent }], ngImport: i0 }); }
4713
+ }
4714
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.8", ngImport: i0, type: YuwSidebarFlyoutDirective, decorators: [{
4715
+ type: Directive,
4716
+ args: [{
4717
+ selector: '[yuwSidebarFlyout]',
4718
+ hostDirectives: [HlmHoverCardContent],
4719
+ }]
4720
+ }], ctorParameters: () => [] });
4305
4721
  /** Divider between sidebar sections. */
4306
4722
  class YuwSidebarSeparatorDirective {
4307
4723
  static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.8", ngImport: i0, type: YuwSidebarSeparatorDirective, deps: [], target: i0.ɵɵFactoryTarget.Directive }); }
@@ -4349,6 +4765,11 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.8", ngImpor
4349
4765
  }]
4350
4766
  }] });
4351
4767
 
4768
+ const CARET_RIGHT_BORDER_CLASSES = `
4769
+ border-l-4 border-t-4 border-t-transparent border-r-0
4770
+ border-b-4 border-b-transparent -right-[4.5px] border-[var(--sidebar-foreground)]
4771
+ absolute transition-opacity
4772
+ `;
4352
4773
  /**
4353
4774
  * Renders one {@link YuwSidebarContentDto} as the group/menu/item tree.
4354
4775
  *
@@ -4361,42 +4782,157 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.8", ngImpor
4361
4782
  * `[yuwSidebarContent]` / `[yuwSidebarFooter]` wrapper it sits inside. That is what keeps the
4362
4783
  * `group-data-[collapsible=icon]:` selectors — which resolve against the sidebar root — working
4363
4784
  * identically for object-rendered and hand-written markup.
4785
+ *
4786
+ * An entry with `children` renders its submenu two ways, one per sidebar state. Expanded, it is an
4787
+ * accordion: the entry carries `aria-expanded` and the submenu is nested beneath it. Collapsed to
4788
+ * icons, where there is no room for either the label or the nesting, the same submenu moves into a
4789
+ * hover flyout beside the rail. Both are always in the template — the sidebar's own state decides
4790
+ * which one is live, so nothing has to be re-created when the user toggles the rail.
4791
+ *
4792
+ * A click on such an entry toggles the accordion while the panel is open. When the entry also has a
4793
+ * `route` or an `href` it navigates *and* toggles, which is why an active one keeps its pointer
4794
+ * events instead of being locked like a childless active entry; when it has neither, toggling is all
4795
+ * it does and it stays out of `itemClicked`, since opening a submenu is not an action for the
4796
+ * consumer to handle. Collapsed to a rail the click does nothing at all: there is no inline submenu
4797
+ * to fold there, and toggling would mutate state the user cannot see while closing the panel they
4798
+ * are aiming at.
4799
+ *
4800
+ * The chevron marking an expandable entry rotates off that same `aria-expanded`, read from the
4801
+ * button through the `group/menu-button` the helm already declares on every menu button. Its
4802
+ * `yuwSidebarMenuChevronClass` hides it with `hidden!` in the collapsed state, and that `!` is
4803
+ * load-bearing: `ng-icon` sets `display: block` on its own host from a layer outranking Tailwind's
4804
+ * `utilities`, so a plain `hidden` loses and the chevron keeps taking width — which pulls the
4805
+ * entry's real icon off centre, since the button is `justify-center` while collapsed. The same
4806
+ * classes on a `<span>` need no `!`; only the custom element does.
4807
+ *
4808
+ * Which of the two forms is live comes from `isRail`, and all three of its conditions are
4809
+ * load-bearing. `collapsible` must be `'icon'`, the only mode that leaves a narrow rail behind:
4810
+ * `'offcanvas'` moves the whole panel off-screen and `'none'` never collapses, yet the service
4811
+ * reports `state() === 'collapsed'` for both — reading the state alone puts a flyout on a sidebar
4812
+ * sitting there at full width. It must not be mobile, where the panel is a full-width sheet showing
4813
+ * the accordion. And the collapse must have finished animating, which is what `railSettled` waits
4814
+ * for: swapping the accordion for a flyout while the panel is still wide would tear the submenu out
4815
+ * from under the pointer mid-transition. That same settled signal drives the rail's own styling, so
4816
+ * the geometry and the submenu form always change on the same frame.
4817
+ *
4818
+ * The accordion opens and closes over a grid-rows transition rather than by appearing outright, which
4819
+ * is why the submenu stays mounted and is switched between `0fr` and `1fr` instead of living behind an
4820
+ * `@if`: height cannot animate from or to something that is not in the layout, and `auto` is not an
4821
+ * animatable value. A closed submenu is `inert` and `aria-hidden`, so leaving it mounted does not hand
4822
+ * keyboard users links to a menu they cannot see.
4823
+ *
4824
+ * Collapsing to the rail also clears every open accordion, which is what stops an expand from
4825
+ * unfolding several submenus at once and shoving the entries below them down the panel. An entry
4826
+ * holding the active route still opens on its own, since that one is answering "where am I" rather
4827
+ * than restoring a stale choice.
4828
+ *
4829
+ * Which entries are expanded resolves in precedence order: an explicit toggle by the user wins,
4830
+ * otherwise an entry holding the active route is open — a deep link into a child should not hide the
4831
+ * child — otherwise the DTO's `expanded` seed, otherwise closed. The user's toggles live in a
4832
+ * `linkedSignal` on `content()` rather than a plain signal, so replacing the object — a nav rebuilt
4833
+ * from fresh permissions, say — drops toggles that no longer refer to anything instead of keeping a
4834
+ * map that grows with dead ids. The seed feeds the derived state rather than that map, which is what
4835
+ * lets an untouched entry keep following its seed and its active route.
4836
+ *
4837
+ * Whether an entry holds the active route is decided by comparing serialized `routerLink` targets
4838
+ * against the current URL, not by asking the router to match them: `Router.isActive` needs a
4839
+ * `UrlTree` per child and would run on every pass. The URL itself is a signal seeded with
4840
+ * `Router.url`, so a deep link is expanded on first paint, before any navigation event has fired —
4841
+ * `RouterLinkActive` cannot answer this, because it reports on the element it sits on and the entry
4842
+ * that needs to open is the *parent* of the matching child. Matching is by prefix, mirroring
4843
+ * `routerLinkActive`'s own non-exact behaviour, with a boundary check so `/reports` does not match
4844
+ * `/reports-archive`.
4845
+ *
4846
+ * Each entry's render state is resolved once per pass, which is also what keeps
4847
+ * `routerLinkActiveOptions` a stable object identity: a literal in the template
4848
+ * (`[routerLinkActiveOptions]="{exact: item.exact ?? false}"`) allocates a new object on every
4849
+ * change-detection pass, and `RouterLinkActive` treats that as a changed input and re-runs its
4850
+ * subscription. An entry with children resolves no tooltip at all — the flyout already labels it
4851
+ * while collapsed, and a tooltip would fire on the same hover at the same screen position.
4364
4852
  */
4365
4853
  class YuwSidebarNavComponent {
4366
4854
  constructor() {
4855
+ this.router = inject(Router);
4856
+ this.injector = inject(Injector);
4857
+ this.sidebarService = inject(HlmSidebarService);
4858
+ this.rail = inject(YuwSidebarRailService);
4367
4859
  this.content = input.required(...(ngDevMode ? [{ debugName: "content" }] : /* istanbul ignore next */ []));
4860
+ this.collapsible = input('offcanvas', ...(ngDevMode ? [{ debugName: "collapsible" }] : /* istanbul ignore next */ []));
4368
4861
  this.itemClicked = output();
4369
- /**
4370
- * The groups, with each entry's derived render state resolved once.
4371
- *
4372
- * `routerLinkActiveOptions` has to be a stable object identity per entry: a literal in the
4373
- * template (`[routerLinkActiveOptions]="{exact: item.exact ?? false}"`) allocates a new object on
4374
- * every change-detection pass, which `RouterLinkActive` treats as a changed input and re-runs its
4375
- * subscription for. Precomputing it here also keeps the template free of the `?? false` fallback.
4376
- */
4377
- this._groups = computed(() => this.content().groups.map((group) => ({
4378
- ...group,
4379
- items: group.items.map((item) => ({
4380
- ...item,
4381
- tooltipText: item.tooltip ?? item.label,
4382
- activeOptions: { exact: item.exact ?? false },
4383
- children: (item.children ?? []).map((child) => ({
4384
- ...child,
4385
- activeOptions: { exact: child.exact ?? false },
4386
- })),
4387
- })),
4388
- })), ...(ngDevMode ? [{ debugName: "_groups" }] : /* istanbul ignore next */ []));
4862
+ this.activeRoutes = new Map();
4863
+ this.chevronClass = yuwSidebarMenuChevronClass;
4864
+ this.flyoutLabelClass = yuwSidebarFlyoutLabelClass;
4865
+ this.badgeClass = yuwSidebarMenuBadgeClass;
4866
+ this.groupLabelTextClass = yuwSidebarGroupLabelTextClass;
4867
+ this.caretRightBorderClasses = CARET_RIGHT_BORDER_CLASSES;
4868
+ this.isRail = computed(() => this.collapsible() === 'icon' && !this.sidebarService.isMobile() && this.rail.railSettled(), ...(ngDevMode ? [{ debugName: "isRail" }] : /* istanbul ignore next */ []));
4869
+ this.expandedIds = linkedSignal({ ...(ngDevMode ? { debugName: "expandedIds" } : /* istanbul ignore next */ {}), source: () => ({ content: this.content(), rail: this.isRail() }),
4870
+ computation: ({ content, rail }, previous) => rail || previous
4871
+ ? new Set()
4872
+ : new Set(content.groups.flatMap((group) => group.items.filter((item) => item.expanded).map((item) => item.id))) });
4873
+ this._groups = computed(() => {
4874
+ const expandedIds = this.expandedIds();
4875
+ const isRail = this.isRail();
4876
+ return this.content().groups.map((group) => ({
4877
+ ...group,
4878
+ items: group.items.map((item) => {
4879
+ const children = (item.children ?? []).map((child) => ({
4880
+ ...child,
4881
+ activeOptions: { exact: child.exact ?? false },
4882
+ }));
4883
+ const hasChildren = children.length > 0;
4884
+ const expanded = isRail || !hasChildren ? false : expandedIds.has(item.id) || this.holdsActiveRoute(item.children);
4885
+ return {
4886
+ ...item,
4887
+ children,
4888
+ hasChildren,
4889
+ tooltipText: hasChildren ? null : (item.tooltip ?? item.label),
4890
+ activeOptions: { exact: item.exact ?? false },
4891
+ expanded,
4892
+ submenuClass: `${yuwSidebarSubmenuWrapperClass} ${expanded ? yuwSidebarSubmenuOpenClass : yuwSidebarSubmenuClosedClass}`,
4893
+ };
4894
+ }),
4895
+ }));
4896
+ }, ...(ngDevMode ? [{ debugName: "_groups" }] : /* istanbul ignore next */ []));
4897
+ }
4898
+ holdsActiveRoute(children) {
4899
+ return (children ?? []).some((child) => {
4900
+ const route = child.route;
4901
+ return route !== undefined && route !== null && this.routeActive(route)();
4902
+ });
4903
+ }
4904
+ routeActive(route) {
4905
+ const key = this.router.serializeUrl(this.router.createUrlTree(Array.isArray(route) ? route : [route]));
4906
+ const cached = this.activeRoutes.get(key);
4907
+ if (cached)
4908
+ return cached;
4909
+ const signal = runInInjectionContext(this.injector, () => isActive(key, this.router));
4910
+ this.activeRoutes.set(key, signal);
4911
+ return signal;
4389
4912
  }
4390
4913
  onItemClick(id, event) {
4391
4914
  this.itemClicked.emit({ id, event });
4392
4915
  }
4916
+ onParentClick(id, expanded) {
4917
+ if (this.isRail())
4918
+ return;
4919
+ this.expandedIds.update((ids) => {
4920
+ const next = new Set(ids);
4921
+ if (expanded)
4922
+ next.delete(id);
4923
+ else
4924
+ next.add(id);
4925
+ return next;
4926
+ });
4927
+ }
4393
4928
  static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.8", ngImport: i0, type: YuwSidebarNavComponent, deps: [], target: i0.ɵɵFactoryTarget.Component }); }
4394
- static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "21.2.8", type: YuwSidebarNavComponent, isStandalone: true, selector: "yuw-sidebar-nav", inputs: { content: { classPropertyName: "content", publicName: "content", isSignal: true, isRequired: true, transformFunction: null } }, outputs: { itemClicked: "itemClicked" }, host: { classAttribute: "contents" }, ngImport: i0, template: "@for (group of _groups(); track group.id) {\n <div yuwSidebarGroup>\n @if (group.label) {\n <div yuwSidebarGroupLabel>{{ group.label }}</div>\n }\n\n <div yuwSidebarGroupContent>\n <ul yuwSidebarMenu class=\"gap-1\">\n @for (item of group.items; track item.id) {\n <li yuwSidebarMenuItem>\n @if (item.route) {\n <a\n yuwSidebarMenuButton\n closeMobileSidebarOnClick\n [routerLink]=\"item.route\"\n routerLinkActive\n #link=\"routerLinkActive\"\n [routerLinkActiveOptions]=\"item.activeOptions\"\n [isActive]=\"link.isActive\"\n [tooltip]=\"item.tooltipText\"\n [attr.aria-current]=\"link.isActive ? 'page' : null\"\n [attr.aria-disabled]=\"item.disabled ? 'true' : null\"\n [class.pointer-events-none]=\"link.isActive || item.disabled\"\n >\n @if (item.icon) {\n <ng-icon [name]=\"item.icon\" />\n }\n <span>{{ item.label }}</span>\n </a>\n } @else if (item.href) {\n <a\n yuwSidebarMenuButton\n closeMobileSidebarOnClick\n [href]=\"item.href\"\n [attr.target]=\"item.target\"\n [tooltip]=\"item.tooltipText\"\n [attr.aria-disabled]=\"item.disabled ? 'true' : null\"\n [class.pointer-events-none]=\"item.disabled\"\n >\n @if (item.icon) {\n <ng-icon [name]=\"item.icon\" />\n }\n <span>{{ item.label }}</span>\n </a>\n } @else {\n <button\n yuwSidebarMenuButton\n closeMobileSidebarOnClick\n type=\"button\"\n [tooltip]=\"item.tooltipText\"\n [disabled]=\"item.disabled ?? false\"\n (click)=\"onItemClick(item.id, $event)\"\n >\n @if (item.icon) {\n <ng-icon [name]=\"item.icon\" />\n }\n <span>{{ item.label }}</span>\n </button>\n }\n\n @if (item.badge) {\n <span yuwSidebarMenuBadge>{{ item.badge }}</span>\n }\n\n @if (item.children.length) {\n <ul yuwSidebarMenuSub>\n @for (child of item.children; track child.id) {\n <li yuwSidebarMenuSubItem>\n @if (child.route) {\n <a\n yuwSidebarMenuSubButton\n closeMobileSidebarOnClick\n [routerLink]=\"child.route\"\n routerLinkActive\n #childLink=\"routerLinkActive\"\n [routerLinkActiveOptions]=\"child.activeOptions\"\n [isActive]=\"childLink.isActive\"\n [attr.aria-current]=\"childLink.isActive ? 'page' : null\"\n [attr.aria-disabled]=\"child.disabled ? 'true' : null\"\n [class.pointer-events-none]=\"childLink.isActive || child.disabled\"\n >\n <span>{{ child.label }}</span>\n </a>\n } @else if (child.href) {\n <a\n yuwSidebarMenuSubButton\n closeMobileSidebarOnClick\n [href]=\"child.href\"\n [attr.target]=\"child.target\"\n [attr.aria-disabled]=\"child.disabled ? 'true' : null\"\n [class.pointer-events-none]=\"child.disabled\"\n >\n <span>{{ child.label }}</span>\n </a>\n } @else {\n <button\n yuwSidebarMenuSubButton\n closeMobileSidebarOnClick\n type=\"button\"\n [disabled]=\"child.disabled ?? false\"\n (click)=\"onItemClick(child.id, $event)\"\n >\n <span>{{ child.label }}</span>\n </button>\n }\n </li>\n }\n </ul>\n }\n </li>\n }\n </ul>\n </div>\n </div>\n\n @if (group.separatorAfter) {\n <div yuwSidebarSeparator class=\"mx-auto w-4/5!\"></div>\n }\n}\n", dependencies: [{ kind: "component", type: NgIcon, selector: "ng-icon", inputs: ["name", "svg", "size", "strokeWidth", "color"] }, { kind: "directive", type: RouterLink, selector: "[routerLink]", inputs: ["target", "queryParams", "fragment", "queryParamsHandling", "state", "info", "relativeTo", "preserveFragment", "skipLocationChange", "replaceUrl", "routerLink"] }, { kind: "directive", type: RouterLinkActive, selector: "[routerLinkActive]", inputs: ["routerLinkActiveOptions", "ariaCurrentWhenActive", "routerLinkActive"], outputs: ["isActiveChange"], exportAs: ["routerLinkActive"] }, { kind: "directive", type: YuwSidebarGroupDirective, selector: "[yuwSidebarGroup], yuw-sidebar-group" }, { kind: "directive", type: YuwSidebarGroupLabelDirective, selector: "div[yuwSidebarGroupLabel], button[yuwSidebarGroupLabel]" }, { kind: "directive", type: YuwSidebarGroupContentDirective, selector: "div[yuwSidebarGroupContent]" }, { kind: "directive", type: YuwSidebarMenuDirective, selector: "ul[yuwSidebarMenu]" }, { kind: "directive", type: YuwSidebarMenuItemDirective, selector: "li[yuwSidebarMenuItem]" }, { kind: "directive", type: YuwSidebarMenuButtonDirective, selector: "button[yuwSidebarMenuButton], a[yuwSidebarMenuButton]" }, { kind: "directive", type: YuwSidebarMenuBadgeDirective, selector: "[yuwSidebarMenuBadge], yuw-sidebar-menu-badge" }, { kind: "directive", type: YuwSidebarMenuSubDirective, selector: "ul[yuwSidebarMenuSub]" }, { kind: "directive", type: YuwSidebarMenuSubItemDirective, selector: "li[yuwSidebarMenuSubItem]" }, { kind: "directive", type: YuwSidebarMenuSubButtonDirective, selector: "a[yuwSidebarMenuSubButton], button[yuwSidebarMenuSubButton]" }, { kind: "directive", type: YuwSidebarSeparatorDirective, selector: "[yuwSidebarSeparator], yuw-sidebar-separator" }], changeDetection: i0.ChangeDetectionStrategy.OnPush }); }
4929
+ static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "21.2.8", type: YuwSidebarNavComponent, isStandalone: true, selector: "yuw-sidebar-nav", inputs: { content: { classPropertyName: "content", publicName: "content", isSignal: true, isRequired: true, transformFunction: null }, collapsible: { classPropertyName: "collapsible", publicName: "collapsible", isSignal: true, isRequired: false, transformFunction: null } }, outputs: { itemClicked: "itemClicked" }, host: { classAttribute: "contents" }, providers: [provideIcons({ lucideChevronRight })], ngImport: i0, template: "<ng-template #submenu let-item>\n <ul yuwSidebarMenuSub>\n @for (child of item.children; track child.id) {\n <li yuwSidebarMenuSubItem>\n @if (child.route) {\n <a\n yuwSidebarMenuSubButton\n closeMobileSidebarOnClick\n [routerLink]=\"child.route\"\n routerLinkActive\n #childLink=\"routerLinkActive\"\n [routerLinkActiveOptions]=\"child.activeOptions\"\n [isActive]=\"childLink.isActive\"\n [attr.aria-current]=\"childLink.isActive ? 'page' : null\"\n [attr.aria-disabled]=\"child.disabled ? 'true' : null\"\n [class.pointer-events-none]=\"childLink.isActive || child.disabled\"\n >\n <span>{{ child.label }}</span>\n </a>\n } @else if (child.href) {\n <a\n yuwSidebarMenuSubButton\n closeMobileSidebarOnClick\n [href]=\"child.href\"\n [attr.target]=\"child.target\"\n [attr.aria-disabled]=\"child.disabled ? 'true' : null\"\n [class.pointer-events-none]=\"child.disabled\"\n >\n <span>{{ child.label }}</span>\n </a>\n } @else {\n <button\n yuwSidebarMenuSubButton\n closeMobileSidebarOnClick\n type=\"button\"\n [disabled]=\"child.disabled ?? false\"\n (click)=\"onItemClick(child.id, $event)\"\n >\n <span>{{ child.label }}</span>\n </button>\n }\n </li>\n }\n </ul>\n</ng-template>\n\n@for (group of _groups(); track group.id) {\n <div yuwSidebarGroup>\n @if (group.label) {\n <div yuwSidebarGroupLabel>\n <span [class]=\"groupLabelTextClass\">{{ group.label }}</span>\n </div>\n }\n\n <div yuwSidebarGroupContent>\n <ul yuwSidebarMenu class=\"gap-1\">\n @for (item of group.items; track item.id) {\n <li yuwSidebarMenuItem yuwSidebarFlyoutHost>\n <ng-template yuwSidebarFlyoutPanel #panel>\n <div yuwSidebarFlyout>\n <span [class]=\"flyoutLabelClass\">{{ item.label }}</span>\n <ng-container [ngTemplateOutlet]=\"submenu\" [ngTemplateOutletContext]=\"{ $implicit: item }\" />\n </div>\n </ng-template>\n\n @if (item.route) {\n <a\n yuwSidebarMenuButton\n closeMobileSidebarOnClick\n [routerLink]=\"item.route\"\n routerLinkActive\n #link=\"routerLinkActive\"\n [routerLinkActiveOptions]=\"item.activeOptions\"\n [isActive]=\"link.isActive\"\n [tooltip]=\"item.tooltipText\"\n [attr.aria-current]=\"link.isActive ? 'page' : null\"\n [attr.aria-disabled]=\"item.disabled ? 'true' : null\"\n [attr.aria-expanded]=\"item.hasChildren ? item.expanded : null\"\n [class.pointer-events-none]=\"(link.isActive && !item.hasChildren) || item.disabled\"\n [yuwSidebarFlyoutTrigger]=\"item.hasChildren && isRail() ? panel : undefined\"\n align=\"right\"\n [sideOffset]=\"0\"\n [showDelay]=\"120\"\n [hideDelay]=\"300\"\n (click)=\"onParentClick(item.id, item.expanded)\"\n >\n @if (item.icon) {\n <ng-icon [name]=\"item.icon\" />\n }\n <span>{{ item.label }}</span>\n @if (item.hasChildren) {\n <ng-icon name=\"lucideChevronRight\" [class]=\"chevronClass\" />\n }\n </a>\n } @else if (item.href) {\n <a\n yuwSidebarMenuButton\n closeMobileSidebarOnClick\n [href]=\"item.href\"\n [attr.target]=\"item.target\"\n [tooltip]=\"item.tooltipText\"\n [attr.aria-disabled]=\"item.disabled ? 'true' : null\"\n [attr.aria-expanded]=\"item.hasChildren ? item.expanded : null\"\n [class.pointer-events-none]=\"item.disabled\"\n [yuwSidebarFlyoutTrigger]=\"item.hasChildren && isRail() ? panel : undefined\"\n align=\"right\"\n [sideOffset]=\"0\"\n [showDelay]=\"120\"\n [hideDelay]=\"300\"\n (click)=\"onParentClick(item.id, item.expanded)\"\n >\n @if (item.icon) {\n <ng-icon [name]=\"item.icon\" />\n }\n <span>{{ item.label }}</span>\n @if (item.hasChildren) {\n <ng-icon name=\"lucideChevronRight\" [class]=\"chevronClass\" />\n }\n </a>\n } @else {\n <button\n yuwSidebarMenuButton\n closeMobileSidebarOnClick\n type=\"button\"\n [tooltip]=\"item.tooltipText\"\n [disabled]=\"item.disabled ?? false\"\n [attr.aria-expanded]=\"item.hasChildren ? item.expanded : null\"\n [yuwSidebarFlyoutTrigger]=\"item.hasChildren && isRail() ? panel : undefined\"\n align=\"right\"\n [sideOffset]=\"0\"\n [showDelay]=\"120\"\n [hideDelay]=\"300\"\n (click)=\"item.hasChildren ? onParentClick(item.id, item.expanded) : onItemClick(item.id, $event)\"\n >\n @if (item.icon) {\n <ng-icon [name]=\"item.icon\" />\n }\n <span>{{ item.label }}</span>\n @if (item.hasChildren) {\n <ng-icon name=\"lucideChevronRight\" [class]=\"chevronClass\" />\n <div\n [class]=\"caretRightBorderClasses\"\n [class.opacity-100]=\"isRail()\"\n [class.opacity-0]=\"!isRail()\"\n ></div>\n }\n </button>\n }\n\n @if (item.badge) {\n <span yuwSidebarMenuBadge [class]=\"badgeClass\">{{ item.badge }}</span>\n }\n\n @if (item.hasChildren && !isRail()) {\n <div\n [class]=\"item.submenuClass\"\n [attr.inert]=\"item.expanded ? null : ''\"\n [attr.aria-hidden]=\"!item.expanded\"\n >\n <div>\n <ng-container [ngTemplateOutlet]=\"submenu\" [ngTemplateOutletContext]=\"{ $implicit: item }\" />\n </div>\n </div>\n }\n </li>\n }\n </ul>\n </div>\n </div>\n\n @if (group.separatorAfter) {\n <div yuwSidebarSeparator class=\"mx-auto w-4/5!\"></div>\n }\n}\n", dependencies: [{ kind: "component", type: NgIcon, selector: "ng-icon", inputs: ["name", "svg", "size", "strokeWidth", "color"] }, { kind: "directive", type: NgTemplateOutlet, selector: "[ngTemplateOutlet]", inputs: ["ngTemplateOutletContext", "ngTemplateOutlet", "ngTemplateOutletInjector"] }, { 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: YuwSidebarGroupDirective, selector: "[yuwSidebarGroup], yuw-sidebar-group" }, { kind: "directive", type: YuwSidebarGroupLabelDirective, selector: "div[yuwSidebarGroupLabel], button[yuwSidebarGroupLabel]" }, { kind: "directive", type: YuwSidebarGroupContentDirective, selector: "div[yuwSidebarGroupContent]" }, { kind: "directive", type: YuwSidebarMenuDirective, selector: "ul[yuwSidebarMenu]" }, { kind: "directive", type: YuwSidebarMenuItemDirective, selector: "li[yuwSidebarMenuItem]" }, { kind: "directive", type: YuwSidebarMenuButtonDirective, selector: "button[yuwSidebarMenuButton], a[yuwSidebarMenuButton]" }, { kind: "directive", type: YuwSidebarMenuBadgeDirective, selector: "[yuwSidebarMenuBadge], yuw-sidebar-menu-badge" }, { kind: "directive", type: YuwSidebarMenuSubDirective, selector: "ul[yuwSidebarMenuSub]" }, { kind: "directive", type: YuwSidebarMenuSubItemDirective, selector: "li[yuwSidebarMenuSubItem]" }, { kind: "directive", type: YuwSidebarMenuSubButtonDirective, selector: "a[yuwSidebarMenuSubButton], button[yuwSidebarMenuSubButton]" }, { kind: "directive", type: YuwSidebarSeparatorDirective, selector: "[yuwSidebarSeparator], yuw-sidebar-separator" }, { kind: "directive", type: YuwSidebarFlyoutHostDirective, selector: "[yuwSidebarFlyoutHost]" }, { kind: "directive", type: YuwSidebarFlyoutPanelDirective, selector: "ng-template[yuwSidebarFlyoutPanel]" }, { kind: "directive", type: YuwSidebarFlyoutTriggerDirective, selector: "[yuwSidebarFlyoutTrigger]", inputs: ["yuwSidebarFlyoutTrigger", "align", "sideOffset", "showDelay", "hideDelay"] }, { kind: "directive", type: YuwSidebarFlyoutDirective, selector: "[yuwSidebarFlyout]" }], changeDetection: i0.ChangeDetectionStrategy.OnPush }); }
4395
4930
  }
4396
4931
  i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.8", ngImport: i0, type: YuwSidebarNavComponent, decorators: [{
4397
4932
  type: Component,
4398
4933
  args: [{ selector: 'yuw-sidebar-nav', imports: [
4399
4934
  NgIcon,
4935
+ NgTemplateOutlet,
4400
4936
  RouterLink,
4401
4937
  RouterLinkActive,
4402
4938
  YuwSidebarGroupDirective,
@@ -4405,15 +4941,20 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.8", ngImpor
4405
4941
  YuwSidebarMenuDirective,
4406
4942
  YuwSidebarMenuItemDirective,
4407
4943
  YuwSidebarMenuButtonDirective,
4944
+ HlmSidebarMenuButton,
4408
4945
  YuwSidebarMenuBadgeDirective,
4409
4946
  YuwSidebarMenuSubDirective,
4410
4947
  YuwSidebarMenuSubItemDirective,
4411
4948
  YuwSidebarMenuSubButtonDirective,
4412
4949
  YuwSidebarSeparatorDirective,
4413
- ], host: {
4950
+ YuwSidebarFlyoutHostDirective,
4951
+ YuwSidebarFlyoutPanelDirective,
4952
+ YuwSidebarFlyoutTriggerDirective,
4953
+ YuwSidebarFlyoutDirective,
4954
+ ], providers: [provideIcons({ lucideChevronRight })], host: {
4414
4955
  class: 'contents',
4415
- }, changeDetection: ChangeDetectionStrategy.OnPush, template: "@for (group of _groups(); track group.id) {\n <div yuwSidebarGroup>\n @if (group.label) {\n <div yuwSidebarGroupLabel>{{ group.label }}</div>\n }\n\n <div yuwSidebarGroupContent>\n <ul yuwSidebarMenu class=\"gap-1\">\n @for (item of group.items; track item.id) {\n <li yuwSidebarMenuItem>\n @if (item.route) {\n <a\n yuwSidebarMenuButton\n closeMobileSidebarOnClick\n [routerLink]=\"item.route\"\n routerLinkActive\n #link=\"routerLinkActive\"\n [routerLinkActiveOptions]=\"item.activeOptions\"\n [isActive]=\"link.isActive\"\n [tooltip]=\"item.tooltipText\"\n [attr.aria-current]=\"link.isActive ? 'page' : null\"\n [attr.aria-disabled]=\"item.disabled ? 'true' : null\"\n [class.pointer-events-none]=\"link.isActive || item.disabled\"\n >\n @if (item.icon) {\n <ng-icon [name]=\"item.icon\" />\n }\n <span>{{ item.label }}</span>\n </a>\n } @else if (item.href) {\n <a\n yuwSidebarMenuButton\n closeMobileSidebarOnClick\n [href]=\"item.href\"\n [attr.target]=\"item.target\"\n [tooltip]=\"item.tooltipText\"\n [attr.aria-disabled]=\"item.disabled ? 'true' : null\"\n [class.pointer-events-none]=\"item.disabled\"\n >\n @if (item.icon) {\n <ng-icon [name]=\"item.icon\" />\n }\n <span>{{ item.label }}</span>\n </a>\n } @else {\n <button\n yuwSidebarMenuButton\n closeMobileSidebarOnClick\n type=\"button\"\n [tooltip]=\"item.tooltipText\"\n [disabled]=\"item.disabled ?? false\"\n (click)=\"onItemClick(item.id, $event)\"\n >\n @if (item.icon) {\n <ng-icon [name]=\"item.icon\" />\n }\n <span>{{ item.label }}</span>\n </button>\n }\n\n @if (item.badge) {\n <span yuwSidebarMenuBadge>{{ item.badge }}</span>\n }\n\n @if (item.children.length) {\n <ul yuwSidebarMenuSub>\n @for (child of item.children; track child.id) {\n <li yuwSidebarMenuSubItem>\n @if (child.route) {\n <a\n yuwSidebarMenuSubButton\n closeMobileSidebarOnClick\n [routerLink]=\"child.route\"\n routerLinkActive\n #childLink=\"routerLinkActive\"\n [routerLinkActiveOptions]=\"child.activeOptions\"\n [isActive]=\"childLink.isActive\"\n [attr.aria-current]=\"childLink.isActive ? 'page' : null\"\n [attr.aria-disabled]=\"child.disabled ? 'true' : null\"\n [class.pointer-events-none]=\"childLink.isActive || child.disabled\"\n >\n <span>{{ child.label }}</span>\n </a>\n } @else if (child.href) {\n <a\n yuwSidebarMenuSubButton\n closeMobileSidebarOnClick\n [href]=\"child.href\"\n [attr.target]=\"child.target\"\n [attr.aria-disabled]=\"child.disabled ? 'true' : null\"\n [class.pointer-events-none]=\"child.disabled\"\n >\n <span>{{ child.label }}</span>\n </a>\n } @else {\n <button\n yuwSidebarMenuSubButton\n closeMobileSidebarOnClick\n type=\"button\"\n [disabled]=\"child.disabled ?? false\"\n (click)=\"onItemClick(child.id, $event)\"\n >\n <span>{{ child.label }}</span>\n </button>\n }\n </li>\n }\n </ul>\n }\n </li>\n }\n </ul>\n </div>\n </div>\n\n @if (group.separatorAfter) {\n <div yuwSidebarSeparator class=\"mx-auto w-4/5!\"></div>\n }\n}\n" }]
4416
- }], propDecorators: { content: [{ type: i0.Input, args: [{ isSignal: true, alias: "content", required: true }] }], itemClicked: [{ type: i0.Output, args: ["itemClicked"] }] } });
4956
+ }, changeDetection: ChangeDetectionStrategy.OnPush, template: "<ng-template #submenu let-item>\n <ul yuwSidebarMenuSub>\n @for (child of item.children; track child.id) {\n <li yuwSidebarMenuSubItem>\n @if (child.route) {\n <a\n yuwSidebarMenuSubButton\n closeMobileSidebarOnClick\n [routerLink]=\"child.route\"\n routerLinkActive\n #childLink=\"routerLinkActive\"\n [routerLinkActiveOptions]=\"child.activeOptions\"\n [isActive]=\"childLink.isActive\"\n [attr.aria-current]=\"childLink.isActive ? 'page' : null\"\n [attr.aria-disabled]=\"child.disabled ? 'true' : null\"\n [class.pointer-events-none]=\"childLink.isActive || child.disabled\"\n >\n <span>{{ child.label }}</span>\n </a>\n } @else if (child.href) {\n <a\n yuwSidebarMenuSubButton\n closeMobileSidebarOnClick\n [href]=\"child.href\"\n [attr.target]=\"child.target\"\n [attr.aria-disabled]=\"child.disabled ? 'true' : null\"\n [class.pointer-events-none]=\"child.disabled\"\n >\n <span>{{ child.label }}</span>\n </a>\n } @else {\n <button\n yuwSidebarMenuSubButton\n closeMobileSidebarOnClick\n type=\"button\"\n [disabled]=\"child.disabled ?? false\"\n (click)=\"onItemClick(child.id, $event)\"\n >\n <span>{{ child.label }}</span>\n </button>\n }\n </li>\n }\n </ul>\n</ng-template>\n\n@for (group of _groups(); track group.id) {\n <div yuwSidebarGroup>\n @if (group.label) {\n <div yuwSidebarGroupLabel>\n <span [class]=\"groupLabelTextClass\">{{ group.label }}</span>\n </div>\n }\n\n <div yuwSidebarGroupContent>\n <ul yuwSidebarMenu class=\"gap-1\">\n @for (item of group.items; track item.id) {\n <li yuwSidebarMenuItem yuwSidebarFlyoutHost>\n <ng-template yuwSidebarFlyoutPanel #panel>\n <div yuwSidebarFlyout>\n <span [class]=\"flyoutLabelClass\">{{ item.label }}</span>\n <ng-container [ngTemplateOutlet]=\"submenu\" [ngTemplateOutletContext]=\"{ $implicit: item }\" />\n </div>\n </ng-template>\n\n @if (item.route) {\n <a\n yuwSidebarMenuButton\n closeMobileSidebarOnClick\n [routerLink]=\"item.route\"\n routerLinkActive\n #link=\"routerLinkActive\"\n [routerLinkActiveOptions]=\"item.activeOptions\"\n [isActive]=\"link.isActive\"\n [tooltip]=\"item.tooltipText\"\n [attr.aria-current]=\"link.isActive ? 'page' : null\"\n [attr.aria-disabled]=\"item.disabled ? 'true' : null\"\n [attr.aria-expanded]=\"item.hasChildren ? item.expanded : null\"\n [class.pointer-events-none]=\"(link.isActive && !item.hasChildren) || item.disabled\"\n [yuwSidebarFlyoutTrigger]=\"item.hasChildren && isRail() ? panel : undefined\"\n align=\"right\"\n [sideOffset]=\"0\"\n [showDelay]=\"120\"\n [hideDelay]=\"300\"\n (click)=\"onParentClick(item.id, item.expanded)\"\n >\n @if (item.icon) {\n <ng-icon [name]=\"item.icon\" />\n }\n <span>{{ item.label }}</span>\n @if (item.hasChildren) {\n <ng-icon name=\"lucideChevronRight\" [class]=\"chevronClass\" />\n }\n </a>\n } @else if (item.href) {\n <a\n yuwSidebarMenuButton\n closeMobileSidebarOnClick\n [href]=\"item.href\"\n [attr.target]=\"item.target\"\n [tooltip]=\"item.tooltipText\"\n [attr.aria-disabled]=\"item.disabled ? 'true' : null\"\n [attr.aria-expanded]=\"item.hasChildren ? item.expanded : null\"\n [class.pointer-events-none]=\"item.disabled\"\n [yuwSidebarFlyoutTrigger]=\"item.hasChildren && isRail() ? panel : undefined\"\n align=\"right\"\n [sideOffset]=\"0\"\n [showDelay]=\"120\"\n [hideDelay]=\"300\"\n (click)=\"onParentClick(item.id, item.expanded)\"\n >\n @if (item.icon) {\n <ng-icon [name]=\"item.icon\" />\n }\n <span>{{ item.label }}</span>\n @if (item.hasChildren) {\n <ng-icon name=\"lucideChevronRight\" [class]=\"chevronClass\" />\n }\n </a>\n } @else {\n <button\n yuwSidebarMenuButton\n closeMobileSidebarOnClick\n type=\"button\"\n [tooltip]=\"item.tooltipText\"\n [disabled]=\"item.disabled ?? false\"\n [attr.aria-expanded]=\"item.hasChildren ? item.expanded : null\"\n [yuwSidebarFlyoutTrigger]=\"item.hasChildren && isRail() ? panel : undefined\"\n align=\"right\"\n [sideOffset]=\"0\"\n [showDelay]=\"120\"\n [hideDelay]=\"300\"\n (click)=\"item.hasChildren ? onParentClick(item.id, item.expanded) : onItemClick(item.id, $event)\"\n >\n @if (item.icon) {\n <ng-icon [name]=\"item.icon\" />\n }\n <span>{{ item.label }}</span>\n @if (item.hasChildren) {\n <ng-icon name=\"lucideChevronRight\" [class]=\"chevronClass\" />\n <div\n [class]=\"caretRightBorderClasses\"\n [class.opacity-100]=\"isRail()\"\n [class.opacity-0]=\"!isRail()\"\n ></div>\n }\n </button>\n }\n\n @if (item.badge) {\n <span yuwSidebarMenuBadge [class]=\"badgeClass\">{{ item.badge }}</span>\n }\n\n @if (item.hasChildren && !isRail()) {\n <div\n [class]=\"item.submenuClass\"\n [attr.inert]=\"item.expanded ? null : ''\"\n [attr.aria-hidden]=\"!item.expanded\"\n >\n <div>\n <ng-container [ngTemplateOutlet]=\"submenu\" [ngTemplateOutletContext]=\"{ $implicit: item }\" />\n </div>\n </div>\n }\n </li>\n }\n </ul>\n </div>\n </div>\n\n @if (group.separatorAfter) {\n <div yuwSidebarSeparator class=\"mx-auto w-4/5!\"></div>\n }\n}\n" }]
4957
+ }], propDecorators: { content: [{ type: i0.Input, args: [{ isSignal: true, alias: "content", required: true }] }], collapsible: [{ type: i0.Input, args: [{ isSignal: true, alias: "collapsible", required: false }] }], itemClicked: [{ type: i0.Output, args: ["itemClicked"] }] } });
4417
4958
 
4418
4959
  /**
4419
4960
  * Collapsible navigation sidebar. Renders as a fixed panel on desktop and as a slide-in sheet on
@@ -4433,12 +4974,22 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.8", ngImpor
4433
4974
  * markup. Groups → items → optional one level of children. An item with a `route` becomes a
4434
4975
  * `[routerLink]` anchor whose active state, `aria-current` and pointer-lock resolve automatically
4435
4976
  * from `routerLinkActive`; one with an `href` becomes a plain anchor; one with neither becomes a
4436
- * button that reports through `itemClicked`.
4977
+ * button that reports through `itemClicked`. An item with `children` gets a submenu that follows
4978
+ * the sidebar's own state: an accordion while the panel is open, and a hover flyout to the side
4979
+ * once it is collapsed to icons, so nested entries stay reachable from the rail. Its `expanded`
4980
+ * field seeds the accordion; the item holding the active route opens on its own.
4437
4981
  * - `footer`: The same, rendered into the footer region.
4438
4982
  *
4439
4983
  * Outputs:
4440
4984
  * - `itemClicked`: Emits `{id, event}` when a non-navigating entry (no `route`, no `href`) is
4441
4985
  * activated, in either `content` or `footer`.
4986
+ * - `collapsedChange`: Emits `true` when the sidebar collapses and `false` when it expands, reading
4987
+ * the mobile sheet or the desktop panel as appropriate. Fires the moment the state flips, so it is
4988
+ * the one to drive a caller's own layout, which should start moving with the panel.
4989
+ * - `railSettledChange`: The same transition, but `true` only once the collapse has finished
4990
+ * animating, and `false` immediately on expand. Use it for anything that should not restyle against
4991
+ * a panel still mid-width — swapping a logo for a mark, say. The sidebar's own rail geometry is
4992
+ * keyed off this, which is why the labels stay put until the panel is actually narrow.
4442
4993
  *
4443
4994
  * The two forms compose rather than exclude each other, unlike `<yuw-button>`'s `buttons` input
4444
4995
  * which drops projected content when set. `content`/`footer` render their own region; anything
@@ -4479,7 +5030,7 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.8", ngImpor
4479
5030
  * label: 'Gestión',
4480
5031
  * items: [
4481
5032
  * {id: 'orders', label: 'Pedidos', icon: 'lucideReceipt', route: '/orders', badge: '12'},
4482
- * {id: 'reports', label: 'Informes', icon: 'lucideChartLine', children: [
5033
+ * {id: 'reports', label: 'Informes', icon: 'lucideChartLine', expanded: true, children: [
4483
5034
  * {id: 'sales', label: 'Ventas', route: '/reports/sales'},
4484
5035
  * ]},
4485
5036
  * {id: 'sync', label: 'Sincronizar'},
@@ -4491,6 +5042,7 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.8", ngImpor
4491
5042
  class YuwSidebarComponent {
4492
5043
  constructor() {
4493
5044
  this.config = injectHlmSidebarConfig();
5045
+ this._rail = inject(YuwSidebarRailService);
4494
5046
  this.side = input('left', ...(ngDevMode ? [{ debugName: "side" }] : /* istanbul ignore next */ []));
4495
5047
  this.variant = input('sidebar', ...(ngDevMode ? [{ debugName: "variant" }] : /* istanbul ignore next */ []));
4496
5048
  this.collapsible = input('offcanvas', ...(ngDevMode ? [{ debugName: "collapsible" }] : /* istanbul ignore next */ []));
@@ -4499,9 +5051,13 @@ class YuwSidebarComponent {
4499
5051
  this.content = input(undefined, ...(ngDevMode ? [{ debugName: "content" }] : /* istanbul ignore next */ []));
4500
5052
  this.footer = input(undefined, ...(ngDevMode ? [{ debugName: "footer" }] : /* istanbul ignore next */ []));
4501
5053
  this.itemClicked = output();
5054
+ this._containerClass = computed(() => `${yuwSidebarContainerClass} ${this.sidebarContainerClass()}`, ...(ngDevMode ? [{ debugName: "_containerClass" }] : /* istanbul ignore next */ []));
5055
+ this._isRail = computed(() => this.collapsible() === 'icon' && this._rail.railSettled(), ...(ngDevMode ? [{ debugName: "_isRail" }] : /* istanbul ignore next */ []));
5056
+ this.collapsedChange = outputFromObservable(toObservable(this._rail.collapsed).pipe(distinctUntilChanged()));
5057
+ this.railSettledChange = outputFromObservable(toObservable(this._rail.railSettled).pipe(distinctUntilChanged()));
4502
5058
  }
4503
5059
  static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.8", ngImport: i0, type: YuwSidebarComponent, deps: [], target: i0.ɵɵFactoryTarget.Component }); }
4504
- static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "21.2.8", type: YuwSidebarComponent, isStandalone: true, selector: "yuw-sidebar", inputs: { side: { classPropertyName: "side", publicName: "side", isSignal: true, isRequired: false, transformFunction: null }, variant: { classPropertyName: "variant", publicName: "variant", isSignal: true, isRequired: false, transformFunction: null }, collapsible: { classPropertyName: "collapsible", publicName: "collapsible", isSignal: true, isRequired: false, transformFunction: null }, sidebarWidthMobile: { classPropertyName: "sidebarWidthMobile", publicName: "sidebarWidthMobile", isSignal: true, isRequired: false, transformFunction: null }, sidebarContainerClass: { classPropertyName: "sidebarContainerClass", publicName: "sidebarContainerClass", isSignal: true, isRequired: false, transformFunction: null }, content: { classPropertyName: "content", publicName: "content", isSignal: true, isRequired: false, transformFunction: null }, footer: { classPropertyName: "footer", publicName: "footer", isSignal: true, isRequired: false, transformFunction: null } }, outputs: { itemClicked: "itemClicked" }, host: { classAttribute: "contents" }, ngImport: i0, template: "<hlm-sidebar\n [side]=\"side()\"\n [variant]=\"variant()\"\n [collapsible]=\"collapsible()\"\n [sidebarWidthMobile]=\"sidebarWidthMobile()\"\n [sidebarContainerClass]=\"sidebarContainerClass()\"\n>\n <ng-content select=\"[yuwSidebarHeader], yuw-sidebar-header\" />\n\n @if (content(); as nav) {\n <div yuwSidebarContent>\n <div yuwSidebarSeparator class=\"mx-auto w-4/5!\"></div>\n <yuw-sidebar-nav [content]=\"nav\" (itemClicked)=\"itemClicked.emit($event)\" />\n <ng-content select=\"[yuwSidebarContentExtra]\" />\n </div>\n }\n\n <ng-content />\n\n @if (footer(); as nav) {\n <div yuwSidebarFooter>\n <div yuwSidebarSeparator class=\"mx-auto w-4/5!\"></div>\n <yuw-sidebar-nav [content]=\"nav\" (itemClicked)=\"itemClicked.emit($event)\" />\n <ng-content select=\"[yuwSidebarFooterExtra]\" />\n </div>\n }\n</hlm-sidebar>\n", dependencies: [{ kind: "component", type: HlmSidebar, selector: "hlm-sidebar", inputs: ["sidebarWidthMobile", "side", "variant", "collapsible", "sidebarContainerClass"] }, { kind: "component", type: YuwSidebarNavComponent, selector: "yuw-sidebar-nav", inputs: ["content"], outputs: ["itemClicked"] }, { kind: "directive", type: YuwSidebarContentDirective, selector: "[yuwSidebarContent], yuw-sidebar-content" }, { kind: "directive", type: YuwSidebarFooterDirective, selector: "[yuwSidebarFooter], yuw-sidebar-footer" }, { kind: "directive", type: YuwSidebarSeparatorDirective, selector: "[yuwSidebarSeparator], yuw-sidebar-separator" }], changeDetection: i0.ChangeDetectionStrategy.OnPush }); }
5060
+ static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "21.2.8", type: YuwSidebarComponent, isStandalone: true, selector: "yuw-sidebar", inputs: { side: { classPropertyName: "side", publicName: "side", isSignal: true, isRequired: false, transformFunction: null }, variant: { classPropertyName: "variant", publicName: "variant", isSignal: true, isRequired: false, transformFunction: null }, collapsible: { classPropertyName: "collapsible", publicName: "collapsible", isSignal: true, isRequired: false, transformFunction: null }, sidebarWidthMobile: { classPropertyName: "sidebarWidthMobile", publicName: "sidebarWidthMobile", isSignal: true, isRequired: false, transformFunction: null }, sidebarContainerClass: { classPropertyName: "sidebarContainerClass", publicName: "sidebarContainerClass", isSignal: true, isRequired: false, transformFunction: null }, content: { classPropertyName: "content", publicName: "content", isSignal: true, isRequired: false, transformFunction: null }, footer: { classPropertyName: "footer", publicName: "footer", isSignal: true, isRequired: false, transformFunction: null } }, outputs: { itemClicked: "itemClicked", collapsedChange: "collapsedChange", railSettledChange: "railSettledChange" }, host: { classAttribute: "contents" }, ngImport: i0, template: "<hlm-sidebar\n [attr.data-yuw-rail]=\"_isRail() ? 'on' : null\"\n [side]=\"side()\"\n [variant]=\"variant()\"\n [collapsible]=\"collapsible()\"\n [sidebarWidthMobile]=\"sidebarWidthMobile()\"\n [sidebarContainerClass]=\"_containerClass()\"\n>\n <ng-content select=\"[yuwSidebarHeader], yuw-sidebar-header\" />\n\n @if (content(); as nav) {\n <div yuwSidebarContent>\n <div yuwSidebarSeparator class=\"mx-auto w-4/5!\"></div>\n <yuw-sidebar-nav [content]=\"nav\" [collapsible]=\"collapsible()\" (itemClicked)=\"itemClicked.emit($event)\" />\n <ng-content select=\"[yuwSidebarContentExtra]\" />\n </div>\n }\n\n <ng-content />\n\n @if (footer(); as nav) {\n <div yuwSidebarFooter>\n <div yuwSidebarSeparator class=\"mx-auto w-4/5!\"></div>\n <yuw-sidebar-nav [content]=\"nav\" [collapsible]=\"collapsible()\" (itemClicked)=\"itemClicked.emit($event)\" />\n <ng-content select=\"[yuwSidebarFooterExtra]\" />\n </div>\n }\n</hlm-sidebar>\n", dependencies: [{ kind: "component", type: HlmSidebar, selector: "hlm-sidebar", inputs: ["sidebarWidthMobile", "side", "variant", "collapsible", "sidebarContainerClass"] }, { kind: "component", type: YuwSidebarNavComponent, selector: "yuw-sidebar-nav", inputs: ["content", "collapsible"], outputs: ["itemClicked"] }, { kind: "directive", type: YuwSidebarContentDirective, selector: "[yuwSidebarContent], yuw-sidebar-content" }, { kind: "directive", type: YuwSidebarFooterDirective, selector: "[yuwSidebarFooter], yuw-sidebar-footer" }, { kind: "directive", type: YuwSidebarSeparatorDirective, selector: "[yuwSidebarSeparator], yuw-sidebar-separator" }], changeDetection: i0.ChangeDetectionStrategy.OnPush }); }
4505
5061
  }
4506
5062
  i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.8", ngImport: i0, type: YuwSidebarComponent, decorators: [{
4507
5063
  type: Component,
@@ -4513,8 +5069,8 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.8", ngImpor
4513
5069
  YuwSidebarSeparatorDirective,
4514
5070
  ], host: {
4515
5071
  class: 'contents',
4516
- }, changeDetection: ChangeDetectionStrategy.OnPush, template: "<hlm-sidebar\n [side]=\"side()\"\n [variant]=\"variant()\"\n [collapsible]=\"collapsible()\"\n [sidebarWidthMobile]=\"sidebarWidthMobile()\"\n [sidebarContainerClass]=\"sidebarContainerClass()\"\n>\n <ng-content select=\"[yuwSidebarHeader], yuw-sidebar-header\" />\n\n @if (content(); as nav) {\n <div yuwSidebarContent>\n <div yuwSidebarSeparator class=\"mx-auto w-4/5!\"></div>\n <yuw-sidebar-nav [content]=\"nav\" (itemClicked)=\"itemClicked.emit($event)\" />\n <ng-content select=\"[yuwSidebarContentExtra]\" />\n </div>\n }\n\n <ng-content />\n\n @if (footer(); as nav) {\n <div yuwSidebarFooter>\n <div yuwSidebarSeparator class=\"mx-auto w-4/5!\"></div>\n <yuw-sidebar-nav [content]=\"nav\" (itemClicked)=\"itemClicked.emit($event)\" />\n <ng-content select=\"[yuwSidebarFooterExtra]\" />\n </div>\n }\n</hlm-sidebar>\n" }]
4517
- }], propDecorators: { side: [{ type: i0.Input, args: [{ isSignal: true, alias: "side", required: false }] }], variant: [{ type: i0.Input, args: [{ isSignal: true, alias: "variant", required: false }] }], collapsible: [{ type: i0.Input, args: [{ isSignal: true, alias: "collapsible", required: false }] }], sidebarWidthMobile: [{ type: i0.Input, args: [{ isSignal: true, alias: "sidebarWidthMobile", required: false }] }], sidebarContainerClass: [{ type: i0.Input, args: [{ isSignal: true, alias: "sidebarContainerClass", required: false }] }], content: [{ type: i0.Input, args: [{ isSignal: true, alias: "content", required: false }] }], footer: [{ type: i0.Input, args: [{ isSignal: true, alias: "footer", required: false }] }], itemClicked: [{ type: i0.Output, args: ["itemClicked"] }] } });
5072
+ }, changeDetection: ChangeDetectionStrategy.OnPush, template: "<hlm-sidebar\n [attr.data-yuw-rail]=\"_isRail() ? 'on' : null\"\n [side]=\"side()\"\n [variant]=\"variant()\"\n [collapsible]=\"collapsible()\"\n [sidebarWidthMobile]=\"sidebarWidthMobile()\"\n [sidebarContainerClass]=\"_containerClass()\"\n>\n <ng-content select=\"[yuwSidebarHeader], yuw-sidebar-header\" />\n\n @if (content(); as nav) {\n <div yuwSidebarContent>\n <div yuwSidebarSeparator class=\"mx-auto w-4/5!\"></div>\n <yuw-sidebar-nav [content]=\"nav\" [collapsible]=\"collapsible()\" (itemClicked)=\"itemClicked.emit($event)\" />\n <ng-content select=\"[yuwSidebarContentExtra]\" />\n </div>\n }\n\n <ng-content />\n\n @if (footer(); as nav) {\n <div yuwSidebarFooter>\n <div yuwSidebarSeparator class=\"mx-auto w-4/5!\"></div>\n <yuw-sidebar-nav [content]=\"nav\" [collapsible]=\"collapsible()\" (itemClicked)=\"itemClicked.emit($event)\" />\n <ng-content select=\"[yuwSidebarFooterExtra]\" />\n </div>\n }\n</hlm-sidebar>\n" }]
5073
+ }], propDecorators: { side: [{ type: i0.Input, args: [{ isSignal: true, alias: "side", required: false }] }], variant: [{ type: i0.Input, args: [{ isSignal: true, alias: "variant", required: false }] }], collapsible: [{ type: i0.Input, args: [{ isSignal: true, alias: "collapsible", required: false }] }], sidebarWidthMobile: [{ type: i0.Input, args: [{ isSignal: true, alias: "sidebarWidthMobile", required: false }] }], sidebarContainerClass: [{ type: i0.Input, args: [{ isSignal: true, alias: "sidebarContainerClass", required: false }] }], content: [{ type: i0.Input, args: [{ isSignal: true, alias: "content", required: false }] }], footer: [{ type: i0.Input, args: [{ isSignal: true, alias: "footer", required: false }] }], itemClicked: [{ type: i0.Output, args: ["itemClicked"] }], collapsedChange: [{ type: i0.Output, args: ["collapsedChange"] }], railSettledChange: [{ type: i0.Output, args: ["railSettledChange"] }] } });
4518
5074
 
4519
5075
  /**
4520
5076
  * Icon button that toggles the sidebar open or collapsed. Works anywhere on the page, including
@@ -4551,5 +5107,5 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.8", ngImpor
4551
5107
  * Generated bundle index. Do not edit.
4552
5108
  */
4553
5109
 
4554
- export { DATATABLE_ALIGN_CLASS, YUW_DATATABLE_FEATURES, YUW_PASSWORD_REVEAL_STATES, YuwAccordion, YuwAccordionContentComponent, YuwAccordionImports, YuwAccordionItem, YuwAccordionTriggerComponent, YuwAlertActionDirective, YuwAlertComponent, YuwAlertDescriptionDirective, YuwAlertDialogComponent, YuwAlertDialogMediaDirective, YuwAlertDialogTriggerDirective, YuwAlertImports, YuwAlertTitleDirective, YuwAttachmentActionDirective, YuwAttachmentActionsDirective, YuwAttachmentContentDirective, YuwAttachmentDescriptionDirective, YuwAttachmentDirective, YuwAttachmentGroupDirective, YuwAttachmentMediaDirective, YuwAttachmentTitleDirective, YuwAttachmentTriggerDirective, YuwAvatarComponent, YuwBadgeComponent, YuwBreadcrumbComponent, YuwButtonComponent, YuwButtonGroupTextDirective, YuwCaptionDirective, YuwCardActionDirective, YuwCardContentDirective, YuwCardDescriptionDirective, YuwCardDirective, YuwCardFooterDirective, YuwCardHeaderDirective, YuwCardImports, YuwCardTitleDirective, YuwCheckboxComponent, YuwComboboxComponent, YuwComboboxItemDirective, YuwContextMenuCheckboxDirective, YuwContextMenuCheckboxIndicatorComponent, YuwContextMenuDirective, YuwContextMenuGroupDirective, YuwContextMenuImports, YuwContextMenuItemDirective, YuwContextMenuLabelDirective, YuwContextMenuRadioDirective, YuwContextMenuRadioIndicatorComponent, YuwContextMenuSeparatorDirective, YuwContextMenuShortcutDirective, YuwContextMenuSubDirective, YuwContextMenuSubIndicatorComponent, YuwContextMenuSubTriggerDirective, YuwContextMenuTriggerDirective, YuwDatatableComponent, YuwDatepickerComponent, YuwDialogCloseDirective, YuwDialogComponent, YuwDialogFooterDirective, YuwDialogImports, YuwDialogTriggerDirective, YuwEmptyContentDirective, YuwEmptyDescriptionDirective, YuwEmptyDirective, YuwEmptyHeaderDirective, YuwEmptyImports, YuwEmptyMediaDirective, YuwEmptyTitleDirective, YuwInputAddonImports, YuwInputComponent, YuwInputOtpComponent, YuwItemActionsDirective, YuwItemContentDirective, YuwItemDescriptionDirective, YuwItemDirective, YuwItemFooterDirective, YuwItemGroupDirective, YuwItemHeaderDirective, YuwItemImports, YuwItemMediaDirective, YuwItemSeparatorDirective, YuwItemTitleDirective, YuwLabel, YuwLeftAddonDirective, YuwPaginationComponent, YuwPasswordInputComponent, YuwPopoverComponent, YuwPopoverTriggerDirective, YuwRadioGroupComponent, YuwRightAddonDirective, YuwSearchInputComponent, YuwSheetCloseDirective, YuwSheetComponent, YuwSheetFooterDirective, YuwSheetImports, YuwSheetTriggerDirective, YuwSidebarComponent, YuwSidebarContentDirective, YuwSidebarContentExtraDirective, YuwSidebarFooterDirective, YuwSidebarFooterExtraDirective, YuwSidebarGroupContentDirective, YuwSidebarGroupDirective, YuwSidebarGroupLabelDirective, YuwSidebarHeaderDirective, YuwSidebarInsetDirective, YuwSidebarMenuBadgeDirective, YuwSidebarMenuButtonDirective, YuwSidebarMenuDirective, YuwSidebarMenuItemDirective, YuwSidebarMenuSubButtonDirective, YuwSidebarMenuSubDirective, YuwSidebarMenuSubItemDirective, YuwSidebarRailDirective, YuwSidebarSeparatorDirective, YuwSidebarTriggerComponent, YuwSidebarWrapperDirective, YuwSkeletonDirective, YuwSpinnerComponent, YuwSwitchComponent, YuwTBodyDirective, YuwTFootDirective, YuwTHeadDirective, YuwTabPanelDirective, YuwTableContainerDirective, YuwTableDirective, YuwTableImports, YuwTabsComponent, YuwTdDirective, YuwTextareaComponent, YuwThDirective, YuwToasterComponent, YuwTooltipDirective, YuwTrDirective, YuwValueAccessorBase, buildInputOtpGroups, cn, datatableCellVariants, datatableContainerVariants, datatableHeadVariants, datatableHeaderCellVariants, datatableRowVariants, getPaginationRange, provideValueAccessor, totalInputOtpLength };
5110
+ export { DATATABLE_ALIGN_CLASS, YUW_DATATABLE_FEATURES, YUW_PASSWORD_REVEAL_STATES, YuwAccordion, YuwAccordionContentComponent, YuwAccordionImports, YuwAccordionItem, YuwAccordionTriggerComponent, YuwAlertActionDirective, YuwAlertComponent, YuwAlertDescriptionDirective, YuwAlertDialogComponent, YuwAlertDialogMediaDirective, YuwAlertDialogTriggerDirective, YuwAlertImports, YuwAlertTitleDirective, YuwAttachmentActionDirective, YuwAttachmentActionsDirective, YuwAttachmentContentDirective, YuwAttachmentDescriptionDirective, YuwAttachmentDirective, YuwAttachmentGroupDirective, YuwAttachmentMediaDirective, YuwAttachmentTitleDirective, YuwAttachmentTriggerDirective, YuwAvatarComponent, YuwBadgeComponent, YuwBreadcrumbComponent, YuwButtonComponent, YuwButtonGroupTextDirective, YuwCaptionDirective, YuwCardActionDirective, YuwCardContentDirective, YuwCardDescriptionDirective, YuwCardDirective, YuwCardFooterDirective, YuwCardHeaderDirective, YuwCardImports, YuwCardTitleDirective, YuwCheckboxComponent, YuwComboboxComponent, YuwComboboxItemDirective, YuwContextMenuCheckboxDirective, YuwContextMenuCheckboxIndicatorComponent, YuwContextMenuDirective, YuwContextMenuGroupDirective, YuwContextMenuImports, YuwContextMenuItemDirective, YuwContextMenuLabelDirective, YuwContextMenuRadioDirective, YuwContextMenuRadioIndicatorComponent, YuwContextMenuSeparatorDirective, YuwContextMenuShortcutDirective, YuwContextMenuSubDirective, YuwContextMenuSubIndicatorComponent, YuwContextMenuSubTriggerDirective, YuwContextMenuTriggerDirective, YuwDatatableComponent, YuwDatatableRowSelect, YuwDatepickerComponent, YuwDialogCloseDirective, YuwDialogComponent, YuwDialogFooterDirective, YuwDialogImports, YuwDialogTriggerDirective, YuwEmptyContentDirective, YuwEmptyDescriptionDirective, YuwEmptyDirective, YuwEmptyHeaderDirective, YuwEmptyImports, YuwEmptyMediaDirective, YuwEmptyTitleDirective, YuwInputAddonImports, YuwInputComponent, YuwInputOtpComponent, YuwItemActionsDirective, YuwItemContentDirective, YuwItemDescriptionDirective, YuwItemDirective, YuwItemFooterDirective, YuwItemGroupDirective, YuwItemHeaderDirective, YuwItemImports, YuwItemMediaDirective, YuwItemSeparatorDirective, YuwItemTitleDirective, YuwLabel, YuwLeftAddonDirective, YuwPaginationComponent, YuwPasswordInputComponent, YuwPopoverComponent, YuwPopoverTriggerDirective, YuwRadioGroupComponent, YuwRightAddonDirective, YuwSearchInputComponent, YuwSheetCloseDirective, YuwSheetComponent, YuwSheetFooterDirective, YuwSheetImports, YuwSheetTriggerDirective, YuwSidebarComponent, YuwSidebarContentDirective, YuwSidebarContentExtraDirective, YuwSidebarFlyoutDirective, YuwSidebarFlyoutHostDirective, YuwSidebarFlyoutPanelDirective, YuwSidebarFlyoutTriggerDirective, YuwSidebarFooterDirective, YuwSidebarFooterExtraDirective, YuwSidebarGroupContentDirective, YuwSidebarGroupDirective, YuwSidebarGroupLabelDirective, YuwSidebarHeaderDirective, YuwSidebarInsetDirective, YuwSidebarMenuBadgeDirective, YuwSidebarMenuButtonDirective, YuwSidebarMenuDirective, YuwSidebarMenuItemDirective, YuwSidebarMenuSubButtonDirective, YuwSidebarMenuSubDirective, YuwSidebarMenuSubItemDirective, YuwSidebarRailDirective, YuwSidebarRailService, YuwSidebarSeparatorDirective, YuwSidebarTriggerComponent, YuwSidebarWrapperDirective, YuwSkeletonDirective, YuwSpinnerComponent, YuwSwitchComponent, YuwTBodyDirective, YuwTFootDirective, YuwTHeadDirective, YuwTabPanelDirective, YuwTableContainerDirective, YuwTableDirective, YuwTableImports, YuwTabsComponent, YuwTdDirective, YuwTextareaComponent, YuwThDirective, YuwToasterComponent, YuwTooltipDirective, YuwTrDirective, YuwValueAccessorBase, buildInputOtpGroups, cn, datatableCellVariants, datatableContainerVariants, datatableHeadVariants, datatableHeaderCellVariants, datatableRowVariants, getPaginationRange, provideValueAccessor, totalInputOtpLength };
4555
5111
  //# sourceMappingURL=yukit-web.mjs.map