yukit-web 0.0.6 → 0.0.7

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, 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';
@@ -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, merge, fromEvent, timer } 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';
@@ -82,9 +82,13 @@ 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
84
  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';
85
+ import { HlmSidebarWrapper, HlmSidebarHeader, HlmSidebarContent, HlmSidebarFooter, HlmSidebarGroup, HlmSidebarGroupLabel, HlmSidebarGroupContent, HlmSidebarMenu, HlmSidebarMenuItem, HlmSidebarMenuButton, HlmSidebarMenuBadge, HlmSidebarMenuSub, HlmSidebarMenuSubItem, HlmSidebarMenuSubButton, HlmSidebarSeparator, HlmSidebarRail, HlmSidebarInset, HlmSidebarService, injectHlmSidebarConfig, HlmSidebar, HlmSidebarTrigger } from 'yukit-web/helm/sidebar';
86
86
  export { HlmSidebarService as YuwSidebarService, provideHlmSidebarConfig as provideYuwSidebarConfig } from 'yukit-web/helm/sidebar';
87
- import { RouterLink, RouterLinkActive } from '@angular/router';
87
+ import { Router, isActive, RouterLink, RouterLinkActive } from '@angular/router';
88
+ import { map, distinctUntilChanged, switchMap } from 'rxjs/operators';
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,31 +4062,6 @@ 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
- */
4043
4065
  const yuwSidebarMenuButtonClass = [
4044
4066
  'hover:bg-muted',
4045
4067
  'hover:text-foreground',
@@ -4050,9 +4072,43 @@ const yuwSidebarMenuButtonClass = [
4050
4072
  'group-data-[collapsible=icon]:size-auto!',
4051
4073
  'group-data-[collapsible=icon]:w-full!',
4052
4074
  'group-data-[collapsible=icon]:justify-center!',
4053
- 'group-data-[collapsible=icon]:[&>span:last-child]:hidden',
4075
+ 'group-data-[collapsible=icon]:[&>span]:hidden',
4054
4076
  'group-data-[collapsible=icon]:[&_ng-icon]:text-[length:--spacing(6)]',
4055
4077
  ].join(' ');
4078
+ const yuwSidebarMenuChevronClass = [
4079
+ 'ms-auto',
4080
+ 'shrink-0',
4081
+ 'transition-transform',
4082
+ 'duration-200',
4083
+ 'text-[length:--spacing(4)]!',
4084
+ 'group-aria-expanded/menu-button:rotate-90',
4085
+ 'group-data-[collapsible=icon]:hidden!',
4086
+ ].join(' ');
4087
+ const yuwSidebarFlyoutClass = [
4088
+ 'w-56',
4089
+ 'ms-2',
4090
+ 'p-1',
4091
+ 'flex',
4092
+ 'flex-col',
4093
+ 'gap-0.5',
4094
+ '[&_[data-sidebar=menu-sub]]:mx-0',
4095
+ '[&_[data-sidebar=menu-sub]]:translate-x-0',
4096
+ '[&_[data-sidebar=menu-sub]]:border-0',
4097
+ '[&_[data-sidebar=menu-sub]]:px-0',
4098
+ '[&_[data-sidebar=menu-sub]]:py-0',
4099
+ '[&_[data-sidebar=menu-sub]]:gap-0.5',
4100
+ '[&_[data-sidebar=menu-sub-button]]:translate-x-0',
4101
+ '[&_[data-sidebar=menu-sub-button]]:h-8',
4102
+ ].join(' ');
4103
+ const yuwSidebarFlyoutLabelClass = [
4104
+ 'text-muted-foreground',
4105
+ 'px-2',
4106
+ 'pt-1',
4107
+ 'pb-1.5',
4108
+ 'text-xs',
4109
+ 'font-medium',
4110
+ 'truncate',
4111
+ ].join(' ');
4056
4112
 
4057
4113
  /**
4058
4114
  * Outermost layout directive for a sidebar page. Wraps the sidebar and the main content, and owns
@@ -4232,8 +4288,29 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.8", ngImpor
4232
4288
  * from an expression.
4233
4289
  *
4234
4290
  * 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`.
4291
+ * The `classes()` registration below runs after the composed `HlmSidebarMenuButton`'s own, and
4292
+ * `classes()` merges its sources in registration order through `twMerge`, so each of our classes
4293
+ * displaces the helm class of the same Tailwind group and modifier stack without `!important`.
4294
+ *
4295
+ * Those classes sit on the button rather than on `li[yuwSidebarMenuItem]` because every selector in
4296
+ * them resolves against the button's own box or subtree: the `<li>` is not the hovered control, never
4297
+ * carries `aria-expanded`, and its `> span:last-child` is the badge, not the label.
4298
+ *
4299
+ * Three details of the collapsed-to-icon block are load-bearing:
4300
+ *
4301
+ * - `size-auto!`, `w-full!` and `justify-center!` keep their `!` because the helm declarations they
4302
+ * replace (`size-8!`, `p-2!`) are themselves `!important`, which `twMerge` cannot outrank on
4303
+ * specificity alone. The helm pins the button to a square; ours fills the rail width and centres
4304
+ * the icon.
4305
+ * - `[&>span]:hidden` drops the label while collapsed, leaving the icon alone — the tooltip carries
4306
+ * the name in that state, or the flyout does for an entry with children. Matched by element rather
4307
+ * than by `:last-child` (which is what the helm's own `truncate` uses): an expandable entry ends
4308
+ * with a trailing chevron, so the label is no longer the last child and a positional selector
4309
+ * would skip exactly those entries. `span` is unambiguous here — the label is the only one a menu
4310
+ * button has, with the badge living outside the button on the `<li>`.
4311
+ * - `text-[length:--spacing(6)]` bumps the icon from the helm's 4 units to 6. The `length:` hint is
4312
+ * not optional: `text-[…]` is ambiguous between colour and size, and Tailwind resolves the bare
4313
+ * form as a colour, so the icon would never resize.
4237
4314
  */
4238
4315
  class YuwSidebarMenuButtonDirective {
4239
4316
  constructor() {
@@ -4302,6 +4379,179 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.8", ngImpor
4302
4379
  hostDirectives: [{ directive: HlmSidebarMenuSubButton, inputs: ['size', 'isActive', 'closeMobileSidebarOnClick'] }],
4303
4380
  }]
4304
4381
  }] });
4382
+ /**
4383
+ * Host of a collapsed-state flyout: the element that scopes the overlay for one entry. Apply
4384
+ * alongside `[yuwSidebarMenuItem]` on the `<li>` holding the entry and its panel.
4385
+ *
4386
+ * Provides `BrnHoverCardContentService` itself instead of composing `HlmHoverCard`. The service has
4387
+ * to be scoped per `<li>` — it holds the single overlay and its content, so a shared one would have
4388
+ * every entry in the sidebar fighting over the same panel — and providing it here is all that is
4389
+ * needed for that. What `HlmHoverCard` adds on top is a `contentChild` pairing that assigns the
4390
+ * trigger's content in `ngAfterContentInit`, and that pairing is actively harmful here: it writes
4391
+ * into the same writable signal the trigger's own input feeds, so its one-time value outlives and
4392
+ * overrides the binding that is supposed to turn the flyout off while the sidebar is expanded.
4393
+ */
4394
+ class YuwSidebarFlyoutHostDirective {
4395
+ static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.8", ngImport: i0, type: YuwSidebarFlyoutHostDirective, deps: [], target: i0.ɵɵFactoryTarget.Directive }); }
4396
+ static { this.ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "14.0.0", version: "21.2.8", type: YuwSidebarFlyoutHostDirective, isStandalone: true, selector: "[yuwSidebarFlyoutHost]", providers: [BrnHoverCardContentService], ngImport: i0 }); }
4397
+ }
4398
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.8", ngImport: i0, type: YuwSidebarFlyoutHostDirective, decorators: [{
4399
+ type: Directive,
4400
+ args: [{
4401
+ selector: '[yuwSidebarFlyoutHost]',
4402
+ providers: [BrnHoverCardContentService],
4403
+ }]
4404
+ }] });
4405
+ /**
4406
+ * The entry whose hover opens a flyout. Apply to the same element as `[yuwSidebarMenuButton]`, bound
4407
+ * to the panel's `<ng-template>` reference — or to `undefined` to switch the flyout off entirely,
4408
+ * which is how an expanded sidebar keeps its submenus inline.
4409
+ *
4410
+ * Drives `BrnHoverCardContentService` directly instead of composing `BrnHoverCardTrigger`. The brain
4411
+ * trigger has no way to be turned off once it has run: it feeds the panel to the service through an
4412
+ * effect that ignores falsy values, and the service's `show()` consults only its stored content, so
4413
+ * a trigger that was ever enabled keeps opening its overlay forever. Rebinding to `undefined` cannot
4414
+ * undo it, and neither can `hide()`, which detaches the overlay but leaves the content in place.
4415
+ * Owning the wiring here is what makes an unbound panel mean "inert".
4416
+ *
4417
+ * The `effect` is the whole lifecycle: it runs when a panel arrives, and its `onCleanup` closes the
4418
+ * overlay and drops the subscription when the panel goes away or the entry is destroyed. Nothing
4419
+ * else tracks teardown, which is why there is no `DestroyRef` or `takeUntilDestroyed` here — a second
4420
+ * mechanism would only be able to disagree with this one.
4421
+ *
4422
+ * Delays are read inside `switchMap` rather than captured when the effect runs, so retuning them
4423
+ * does not tear down and rebuild the subscription.
4424
+ *
4425
+ * `distinctUntilChanged` before the timer is load-bearing, and not as an optimisation: the five
4426
+ * merged sources overlap, so crossing from the entry to the panel emits a `mouseleave` and the
4427
+ * panel's own hover almost together, and `mouseenter` and `focusin` both fire on the same pointer
4428
+ * arriving. Each duplicate would restart `switchMap` and cancel the timer already in flight, so a
4429
+ * repeat during the show delay could keep the panel from ever opening.
4430
+ *
4431
+ * It cannot dedupe the crossing itself, though — that genuinely alternates `false` then `true`, so
4432
+ * both values are distinct and both survive. `toggle` is therefore guarded against the state it is
4433
+ * already in, because `show()` is not idempotent: it calls `detach()` then `attach()`, tearing the
4434
+ * panel down and rebuilding it. Re-showing an open panel replays its enter animation, which is the
4435
+ * flicker you get when the pointer moves from the rail into the flyout.
4436
+ *
4437
+ * Note there is no click handling. `BrnHoverCardTrigger` maps a click to `false`, which is right for
4438
+ * a hover card — clicking the trigger dismisses it — and wrong for a nav rail, where the entry's own
4439
+ * click has nothing to collapse while collapsed and closing the panel would take away the links the
4440
+ * pointer is travelling to. Activating a child closes the flyout anyway, since the pointer leaves
4441
+ * the panel as the page changes.
4442
+ *
4443
+ * `align` is `'right'` for a sidebar flyout rather than the hover card's own `'bottom'`. It is set as
4444
+ * an input rather than through `provideBrnHoverCardDefaultOptions` because that provider types its
4445
+ * `align` as `'top' | 'bottom'`, even though the position map handles all four sides.
4446
+ */
4447
+ class YuwSidebarFlyoutTriggerDirective {
4448
+ constructor() {
4449
+ this.element = inject(ElementRef);
4450
+ this.viewContainerRef = inject(ViewContainerRef);
4451
+ this.service = inject(BrnHoverCardContentService);
4452
+ this.panel = input(undefined, { ...(ngDevMode ? { debugName: "panel" } : /* istanbul ignore next */ {}), alias: 'yuwSidebarFlyoutTrigger' });
4453
+ this.align = input('right', ...(ngDevMode ? [{ debugName: "align" }] : /* istanbul ignore next */ []));
4454
+ this.sideOffset = input(0, { ...(ngDevMode ? { debugName: "sideOffset" } : /* istanbul ignore next */ {}), transform: numberAttribute });
4455
+ this.showDelay = input(120, { ...(ngDevMode ? { debugName: "showDelay" } : /* istanbul ignore next */ {}), transform: numberAttribute });
4456
+ this.hideDelay = input(300, { ...(ngDevMode ? { debugName: "hideDelay" } : /* istanbul ignore next */ {}), transform: numberAttribute });
4457
+ 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$);
4458
+ effect((onCleanup) => {
4459
+ const panel = this.panel();
4460
+ if (!panel)
4461
+ return;
4462
+ this.service.setConfig({
4463
+ attachTo: this.element,
4464
+ align: this.align(),
4465
+ sideOffset: this.sideOffset(),
4466
+ });
4467
+ this.service.setContent(panel, this.viewContainerRef);
4468
+ const subscription = this.pointerOver
4469
+ .pipe(distinctUntilChanged(), switchMap((visible) => timer(visible ? this.showDelay() : this.hideDelay()).pipe(map(() => visible))))
4470
+ .subscribe((visible) => this.toggle(visible));
4471
+ onCleanup(() => {
4472
+ subscription.unsubscribe();
4473
+ this.toggle(false);
4474
+ });
4475
+ });
4476
+ }
4477
+ toggle(open) {
4478
+ if (open === (this.service.state() === 'open'))
4479
+ return;
4480
+ this.service.setState(open ? 'open' : 'closed');
4481
+ if (open) {
4482
+ this.service.show();
4483
+ return;
4484
+ }
4485
+ this.service.hide();
4486
+ }
4487
+ static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.8", ngImport: i0, type: YuwSidebarFlyoutTriggerDirective, deps: [], target: i0.ɵɵFactoryTarget.Directive }); }
4488
+ 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 }); }
4489
+ }
4490
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.8", ngImport: i0, type: YuwSidebarFlyoutTriggerDirective, decorators: [{
4491
+ type: Directive,
4492
+ args: [{
4493
+ selector: '[yuwSidebarFlyoutTrigger]',
4494
+ }]
4495
+ }], 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 }] }] } });
4496
+ /**
4497
+ * Marks the `<ng-template>` holding a flyout's markup, and is what `[yuwSidebarFlyoutTrigger]` is
4498
+ * bound to. Exported as `yuwSidebarFlyoutPanel` so the template can name it.
4499
+ *
4500
+ * Structural — the composed primitive injects the `TemplateRef`, which is what lets the panel be
4501
+ * portalled into a CDK overlay instead of rendering inside the rail.
4502
+ *
4503
+ * The trigger is bound to the template's own `#ref` (a `TemplateRef`, which its input accepts), so
4504
+ * this directive is never referenced by name — but it cannot be dropped: it is the sole provider of
4505
+ * the exposed state and side tokens that `[yuwSidebarFlyout]` injects from its host, and without it
4506
+ * the panel throws NG0201 the moment the overlay instantiates it.
4507
+ */
4508
+ class YuwSidebarFlyoutPanelDirective {
4509
+ static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.8", ngImport: i0, type: YuwSidebarFlyoutPanelDirective, deps: [], target: i0.ɵɵFactoryTarget.Directive }); }
4510
+ 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 }); }
4511
+ }
4512
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.8", ngImport: i0, type: YuwSidebarFlyoutPanelDirective, decorators: [{
4513
+ type: Directive,
4514
+ args: [{
4515
+ selector: 'ng-template[yuwSidebarFlyoutPanel]',
4516
+ hostDirectives: [HlmHoverCardPortal],
4517
+ }]
4518
+ }] });
4519
+ /**
4520
+ * The flyout's visible surface. Apply to the single root element inside a `[yuwSidebarFlyoutPanel]`
4521
+ * template.
4522
+ *
4523
+ * Separate from the panel marker because the two sit on different nodes: the marker is the
4524
+ * `<ng-template>`, this is the element the overlay renders. Carries the popover surface of the
4525
+ * composed helm content plus `yuwSidebarFlyoutClass`.
4526
+ *
4527
+ * That class layer exists because the panel lives in the overlay, outside the sidebar's DOM subtree,
4528
+ * and so is no longer a descendant of the `group/sidebar-wrapper` element. Every
4529
+ * `group-data-[collapsible=…]` selector therefore resolves against nothing and stays inert —
4530
+ * including the `hidden` that `HlmSidebarMenuSub` and `HlmSidebarMenuSubButton` apply to themselves
4531
+ * in exactly this state, which is why the submenu markup renders visible in here with no override.
4532
+ * What the layer undoes instead is the indentation and vertical rule those primitives carry for the
4533
+ * inline case, which make no sense in a panel.
4534
+ *
4535
+ * The gap between rail and panel is that layer's `ms-2`, not the trigger's `sideOffset`, which is
4536
+ * deliberately `0`. An offset moves the overlay away from the trigger and leaves dead space between
4537
+ * them: crossing it slowly means the pointer is over neither element, and the hover card closes
4538
+ * mid-journey. A margin keeps the same visual gap inside the overlay's own box, so the pointer never
4539
+ * leaves the hover target on its way in.
4540
+ */
4541
+ class YuwSidebarFlyoutDirective {
4542
+ constructor() {
4543
+ classes(() => yuwSidebarFlyoutClass);
4544
+ }
4545
+ static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.8", ngImport: i0, type: YuwSidebarFlyoutDirective, deps: [], target: i0.ɵɵFactoryTarget.Directive }); }
4546
+ 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 }); }
4547
+ }
4548
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.8", ngImport: i0, type: YuwSidebarFlyoutDirective, decorators: [{
4549
+ type: Directive,
4550
+ args: [{
4551
+ selector: '[yuwSidebarFlyout]',
4552
+ hostDirectives: [HlmHoverCardContent],
4553
+ }]
4554
+ }], ctorParameters: () => [] });
4305
4555
  /** Divider between sidebar sections. */
4306
4556
  class YuwSidebarSeparatorDirective {
4307
4557
  static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.8", ngImport: i0, type: YuwSidebarSeparatorDirective, deps: [], target: i0.ɵɵFactoryTarget.Directive }); }
@@ -4361,42 +4611,128 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.8", ngImpor
4361
4611
  * `[yuwSidebarContent]` / `[yuwSidebarFooter]` wrapper it sits inside. That is what keeps the
4362
4612
  * `group-data-[collapsible=icon]:` selectors — which resolve against the sidebar root — working
4363
4613
  * identically for object-rendered and hand-written markup.
4614
+ *
4615
+ * An entry with `children` renders its submenu two ways, one per sidebar state. Expanded, it is an
4616
+ * accordion: the entry carries `aria-expanded` and the submenu is nested beneath it. Collapsed to
4617
+ * icons, where there is no room for either the label or the nesting, the same submenu moves into a
4618
+ * hover flyout beside the rail. Both are always in the template — the sidebar's own state decides
4619
+ * which one is live, so nothing has to be re-created when the user toggles the rail.
4620
+ *
4621
+ * A click on such an entry toggles the accordion while the panel is open. When the entry also has a
4622
+ * `route` or an `href` it navigates *and* toggles, which is why an active one keeps its pointer
4623
+ * events instead of being locked like a childless active entry; when it has neither, toggling is all
4624
+ * it does and it stays out of `itemClicked`, since opening a submenu is not an action for the
4625
+ * consumer to handle. Collapsed to a rail the click does nothing at all: there is no inline submenu
4626
+ * to fold there, and toggling would mutate state the user cannot see while closing the panel they
4627
+ * are aiming at.
4628
+ *
4629
+ * The chevron marking an expandable entry rotates off that same `aria-expanded`, read from the
4630
+ * button through the `group/menu-button` the helm already declares on every menu button. Its
4631
+ * `yuwSidebarMenuChevronClass` hides it with `hidden!` in the collapsed state, and that `!` is
4632
+ * load-bearing: `ng-icon` sets `display: block` on its own host from a layer outranking Tailwind's
4633
+ * `utilities`, so a plain `hidden` loses and the chevron keeps taking width — which pulls the
4634
+ * entry's real icon off centre, since the button is `justify-center` while collapsed. The same
4635
+ * classes on a `<span>` need no `!`; only the custom element does.
4636
+ *
4637
+ * Which of the two forms is live comes from `isRail`, and all three of its conditions are
4638
+ * load-bearing. `collapsible` must be `'icon'`, the only mode that leaves a narrow rail behind:
4639
+ * `'offcanvas'` moves the whole panel off-screen and `'none'` never collapses, yet the service
4640
+ * reports `state() === 'collapsed'` for both — reading the state alone puts a flyout on a sidebar
4641
+ * sitting there at full width. It must not be mobile, where the panel is a full-width sheet showing
4642
+ * the accordion. And the state must actually be collapsed, since an `'icon'` sidebar is a normal wide
4643
+ * panel while open.
4644
+ *
4645
+ * Which entries are expanded resolves in precedence order: an explicit toggle by the user wins,
4646
+ * otherwise an entry holding the active route is open — a deep link into a child should not hide the
4647
+ * child — otherwise the DTO's `expanded` seed, otherwise closed. The user's toggles live in a
4648
+ * `linkedSignal` on `content()` rather than a plain signal, so replacing the object — a nav rebuilt
4649
+ * from fresh permissions, say — drops toggles that no longer refer to anything instead of keeping a
4650
+ * map that grows with dead ids. The seed feeds the derived state rather than that map, which is what
4651
+ * lets an untouched entry keep following its seed and its active route.
4652
+ *
4653
+ * Whether an entry holds the active route is decided by comparing serialized `routerLink` targets
4654
+ * against the current URL, not by asking the router to match them: `Router.isActive` needs a
4655
+ * `UrlTree` per child and would run on every pass. The URL itself is a signal seeded with
4656
+ * `Router.url`, so a deep link is expanded on first paint, before any navigation event has fired —
4657
+ * `RouterLinkActive` cannot answer this, because it reports on the element it sits on and the entry
4658
+ * that needs to open is the *parent* of the matching child. Matching is by prefix, mirroring
4659
+ * `routerLinkActive`'s own non-exact behaviour, with a boundary check so `/reports` does not match
4660
+ * `/reports-archive`.
4661
+ *
4662
+ * Each entry's render state is resolved once per pass, which is also what keeps
4663
+ * `routerLinkActiveOptions` a stable object identity: a literal in the template
4664
+ * (`[routerLinkActiveOptions]="{exact: item.exact ?? false}"`) allocates a new object on every
4665
+ * change-detection pass, and `RouterLinkActive` treats that as a changed input and re-runs its
4666
+ * subscription. An entry with children resolves no tooltip at all — the flyout already labels it
4667
+ * while collapsed, and a tooltip would fire on the same hover at the same screen position.
4364
4668
  */
4365
4669
  class YuwSidebarNavComponent {
4366
4670
  constructor() {
4671
+ this.router = inject(Router);
4672
+ this.injector = inject(Injector);
4673
+ this.sidebarService = inject(HlmSidebarService);
4674
+ this.activeRoutes = new Map();
4367
4675
  this.content = input.required(...(ngDevMode ? [{ debugName: "content" }] : /* istanbul ignore next */ []));
4676
+ this.collapsible = input('offcanvas', ...(ngDevMode ? [{ debugName: "collapsible" }] : /* istanbul ignore next */ []));
4368
4677
  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 */ []));
4678
+ this.chevronClass = yuwSidebarMenuChevronClass;
4679
+ this.flyoutLabelClass = yuwSidebarFlyoutLabelClass;
4680
+ this.isRail = computed(() => this.collapsible() === 'icon' && this.sidebarService.state() === 'collapsed' && !this.sidebarService.isMobile(), ...(ngDevMode ? [{ debugName: "isRail" }] : /* istanbul ignore next */ []));
4681
+ this.userToggles = linkedSignal({ ...(ngDevMode ? { debugName: "userToggles" } : /* istanbul ignore next */ {}), source: this.content,
4682
+ computation: () => new Map() });
4683
+ this._groups = computed(() => {
4684
+ const toggles = this.userToggles();
4685
+ return this.content().groups.map((group) => ({
4686
+ ...group,
4687
+ items: group.items.map((item) => {
4688
+ const children = (item.children ?? []).map((child) => ({
4689
+ ...child,
4690
+ activeOptions: { exact: child.exact ?? false },
4691
+ }));
4692
+ const hasChildren = children.length > 0;
4693
+ return {
4694
+ ...item,
4695
+ children,
4696
+ hasChildren,
4697
+ tooltipText: hasChildren ? undefined : (item.tooltip ?? item.label),
4698
+ activeOptions: { exact: item.exact ?? false },
4699
+ expanded: toggles.get(item.id) ?? (this.holdsActiveRoute(item.children) || (item.expanded ?? false)),
4700
+ };
4701
+ }),
4702
+ }));
4703
+ }, ...(ngDevMode ? [{ debugName: "_groups" }] : /* istanbul ignore next */ []));
4704
+ }
4705
+ holdsActiveRoute(children) {
4706
+ return (children ?? []).some((child) => {
4707
+ const route = child.route;
4708
+ return route !== undefined && route !== null && this.routeActive(route)();
4709
+ });
4710
+ }
4711
+ routeActive(route) {
4712
+ const key = this.router.serializeUrl(this.router.createUrlTree(Array.isArray(route) ? route : [route]));
4713
+ const cached = this.activeRoutes.get(key);
4714
+ if (cached)
4715
+ return cached;
4716
+ const signal = runInInjectionContext(this.injector, () => isActive(key, this.router));
4717
+ this.activeRoutes.set(key, signal);
4718
+ return signal;
4389
4719
  }
4390
4720
  onItemClick(id, event) {
4391
4721
  this.itemClicked.emit({ id, event });
4392
4722
  }
4723
+ onParentClick(id, expanded) {
4724
+ if (this.isRail())
4725
+ return;
4726
+ this.userToggles.update((toggles) => new Map(toggles).set(id, !expanded));
4727
+ }
4393
4728
  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 }); }
4729
+ 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>{{ 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 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 [attr.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 [attr.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 [attr.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 }\n </button>\n }\n\n @if (item.badge) {\n <span yuwSidebarMenuBadge>{{ item.badge }}</span>\n }\n\n @if (item.hasChildren && item.expanded && !isRail()) {\n <ng-container [ngTemplateOutlet]=\"submenu\" [ngTemplateOutletContext]=\"{ $implicit: item }\" />\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
4730
  }
4396
4731
  i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.8", ngImport: i0, type: YuwSidebarNavComponent, decorators: [{
4397
4732
  type: Component,
4398
4733
  args: [{ selector: 'yuw-sidebar-nav', imports: [
4399
4734
  NgIcon,
4735
+ NgTemplateOutlet,
4400
4736
  RouterLink,
4401
4737
  RouterLinkActive,
4402
4738
  YuwSidebarGroupDirective,
@@ -4410,10 +4746,14 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.8", ngImpor
4410
4746
  YuwSidebarMenuSubItemDirective,
4411
4747
  YuwSidebarMenuSubButtonDirective,
4412
4748
  YuwSidebarSeparatorDirective,
4413
- ], host: {
4749
+ YuwSidebarFlyoutHostDirective,
4750
+ YuwSidebarFlyoutPanelDirective,
4751
+ YuwSidebarFlyoutTriggerDirective,
4752
+ YuwSidebarFlyoutDirective,
4753
+ ], providers: [provideIcons({ lucideChevronRight })], host: {
4414
4754
  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"] }] } });
4755
+ }, 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>{{ 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 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 [attr.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 [attr.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 [attr.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 }\n </button>\n }\n\n @if (item.badge) {\n <span yuwSidebarMenuBadge>{{ item.badge }}</span>\n }\n\n @if (item.hasChildren && item.expanded && !isRail()) {\n <ng-container [ngTemplateOutlet]=\"submenu\" [ngTemplateOutletContext]=\"{ $implicit: item }\" />\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" }]
4756
+ }], 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
4757
 
4418
4758
  /**
4419
4759
  * Collapsible navigation sidebar. Renders as a fixed panel on desktop and as a slide-in sheet on
@@ -4433,7 +4773,10 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.8", ngImpor
4433
4773
  * markup. Groups → items → optional one level of children. An item with a `route` becomes a
4434
4774
  * `[routerLink]` anchor whose active state, `aria-current` and pointer-lock resolve automatically
4435
4775
  * from `routerLinkActive`; one with an `href` becomes a plain anchor; one with neither becomes a
4436
- * button that reports through `itemClicked`.
4776
+ * button that reports through `itemClicked`. An item with `children` gets a submenu that follows
4777
+ * the sidebar's own state: an accordion while the panel is open, and a hover flyout to the side
4778
+ * once it is collapsed to icons, so nested entries stay reachable from the rail. Its `expanded`
4779
+ * field seeds the accordion; the item holding the active route opens on its own.
4437
4780
  * - `footer`: The same, rendered into the footer region.
4438
4781
  *
4439
4782
  * Outputs:
@@ -4479,7 +4822,7 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.8", ngImpor
4479
4822
  * label: 'Gestión',
4480
4823
  * items: [
4481
4824
  * {id: 'orders', label: 'Pedidos', icon: 'lucideReceipt', route: '/orders', badge: '12'},
4482
- * {id: 'reports', label: 'Informes', icon: 'lucideChartLine', children: [
4825
+ * {id: 'reports', label: 'Informes', icon: 'lucideChartLine', expanded: true, children: [
4483
4826
  * {id: 'sales', label: 'Ventas', route: '/reports/sales'},
4484
4827
  * ]},
4485
4828
  * {id: 'sync', label: 'Sincronizar'},
@@ -4501,7 +4844,7 @@ class YuwSidebarComponent {
4501
4844
  this.itemClicked = output();
4502
4845
  }
4503
4846
  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 }); }
4847
+ 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\" [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
4848
  }
4506
4849
  i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.8", ngImport: i0, type: YuwSidebarComponent, decorators: [{
4507
4850
  type: Component,
@@ -4513,7 +4856,7 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.8", ngImpor
4513
4856
  YuwSidebarSeparatorDirective,
4514
4857
  ], host: {
4515
4858
  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" }]
4859
+ }, 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\" [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" }]
4517
4860
  }], 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"] }] } });
4518
4861
 
4519
4862
  /**
@@ -4551,5 +4894,5 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.8", ngImpor
4551
4894
  * Generated bundle index. Do not edit.
4552
4895
  */
4553
4896
 
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 };
4897
+ 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, 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
4898
  //# sourceMappingURL=yukit-web.mjs.map