yukit-web 0.0.7 → 0.0.9

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, ViewContainerRef, runInInjectionContext } from '@angular/core';
4
+ import { forwardRef, signal, Directive, input, inject, TemplateRef, ElementRef, booleanAttribute, output, computed, contentChildren, ChangeDetectionStrategy, Component, model, contentChild, viewChild, Injector, afterNextRender, effect, numberAttribute, linkedSignal, Injectable, ViewContainerRef, runInInjectionContext } from '@angular/core';
5
5
  import { NG_VALUE_ACCESSOR } from '@angular/forms';
6
6
  import { NgTemplateOutlet } from '@angular/common';
7
7
  import { HlmButton, provideBrnButtonConfig } from 'yukit-web/helm/button';
@@ -39,7 +39,7 @@ import { HlmCard, HlmCardHeader, HlmCardTitle, HlmCardDescription, HlmCardAction
39
39
  import * as i1$9 from 'yukit-web/helm/empty';
40
40
  import { HlmEmpty, HlmEmptyHeader, HlmEmptyMedia, HlmEmptyTitle, HlmEmptyDescription, HlmEmptyContent } from 'yukit-web/helm/empty';
41
41
  import { CdkContextMenuTrigger, CdkMenuItem, CdkMenuItemCheckbox, CdkMenuItemRadio, CdkMenuTrigger } from '@angular/cdk/menu';
42
- import { outputFromObservable, toObservable } from '@angular/core/rxjs-interop';
42
+ import { outputFromObservable, toObservable, toSignal } from '@angular/core/rxjs-interop';
43
43
  import * as i1$a from 'yukit-web/helm/context-menu';
44
44
  import { HlmContextMenuTrigger } from 'yukit-web/helm/context-menu';
45
45
  import * as i1$b from 'yukit-web/helm/date-picker';
@@ -48,7 +48,7 @@ import * as i1$c from 'yukit-web/helm/table';
48
48
  import { HlmTableContainer, HlmTable, HlmTHead, HlmTBody, HlmTFoot, HlmTr, HlmTh, HlmTd, HlmCaption } from 'yukit-web/helm/table';
49
49
  import { injectTable, FlexRenderDirective } from '@tanstack/angular-table';
50
50
  import { rowSortingFeature, rowSelectionFeature, rowPaginationFeature, columnVisibilityFeature, columnFilteringFeature, sortFns, createPaginatedRowModel, createSortedRowModel, createFilteredRowModel, createCoreRowModel } from '@tanstack/table-core';
51
- import { skip, merge, fromEvent, timer } from 'rxjs';
51
+ import { skip, switchMap, timer, of, merge, fromEvent } from 'rxjs';
52
52
  import * as i1$d from 'yukit-web/helm/avatar';
53
53
  import { HlmAvatarImports } from 'yukit-web/helm/avatar';
54
54
  import * as i1$e from 'yukit-web/helm/item';
@@ -81,11 +81,11 @@ import * as i1$o from 'yukit-web/helm/tabs';
81
81
  import { HlmTabsImports } from 'yukit-web/helm/tabs';
82
82
  import * as i1$p from 'yukit-web/helm/attachment';
83
83
  import { HlmAttachment, HlmAttachmentGroup, HlmAttachmentMedia, HlmAttachmentContent, HlmAttachmentTitle, HlmAttachmentDescription, HlmAttachmentActions, HlmAttachmentAction, HlmAttachmentTrigger } from 'yukit-web/helm/attachment';
84
+ import { map, distinctUntilChanged, switchMap as switchMap$1 } from 'rxjs/operators';
84
85
  import * as i1$q from 'yukit-web/helm/sidebar';
85
- import { HlmSidebarWrapper, HlmSidebarHeader, HlmSidebarContent, HlmSidebarFooter, HlmSidebarGroup, HlmSidebarGroupLabel, HlmSidebarGroupContent, HlmSidebarMenu, HlmSidebarMenuItem, HlmSidebarMenuButton, HlmSidebarMenuBadge, HlmSidebarMenuSub, HlmSidebarMenuSubItem, HlmSidebarMenuSubButton, HlmSidebarSeparator, HlmSidebarRail, HlmSidebarInset, HlmSidebarService, injectHlmSidebarConfig, HlmSidebar, HlmSidebarTrigger } from 'yukit-web/helm/sidebar';
86
+ import { HlmSidebarService, HlmSidebarWrapper, HlmSidebarHeader, HlmSidebarContent, HlmSidebarFooter, HlmSidebarGroup, HlmSidebarGroupLabel, HlmSidebarGroupContent, HlmSidebarMenu, HlmSidebarMenuItem, HlmSidebarMenuButton, HlmSidebarMenuBadge, HlmSidebarMenuSub, HlmSidebarMenuSubItem, HlmSidebarMenuSubButton, HlmSidebarSeparator, HlmSidebarRail, HlmSidebarInset, injectHlmSidebarConfig, HlmSidebar, HlmSidebarTrigger } from 'yukit-web/helm/sidebar';
86
87
  export { HlmSidebarService as YuwSidebarService, provideHlmSidebarConfig as provideYuwSidebarConfig } from 'yukit-web/helm/sidebar';
87
88
  import { Router, isActive, RouterLink, RouterLinkActive } from '@angular/router';
88
- import { map, distinctUntilChanged, switchMap } from 'rxjs/operators';
89
89
  import * as i2$1 from 'yukit-web/helm/hover-card';
90
90
  import { HlmHoverCardPortal, HlmHoverCardContent } from 'yukit-web/helm/hover-card';
91
91
  import { BrnHoverCardContentService } from '@spartan-ng/brain/hover-card';
@@ -4062,18 +4062,29 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.8", ngImpor
4062
4062
  }]
4063
4063
  }] });
4064
4064
 
4065
+ const YUW_SIDEBAR_TRANSITION_MS = 200;
4065
4066
  const yuwSidebarMenuButtonClass = [
4067
+ '[&>span]:truncate',
4068
+ '[&>span]:min-w-0',
4066
4069
  'hover:bg-muted',
4067
4070
  'hover:text-foreground',
4068
4071
  'dark:hover:bg-muted/50',
4069
4072
  'aria-expanded:bg-muted',
4070
4073
  'aria-expanded:text-foreground',
4071
- 'transition-all',
4072
- 'group-data-[collapsible=icon]:size-auto!',
4074
+ 'transition-[background-color,color]',
4075
+ 'duration-200',
4076
+ 'ease-linear',
4077
+ 'motion-reduce:transition-none',
4078
+ '[&_ng-icon]:origin-center',
4079
+ '[&_ng-icon]:transition-transform',
4080
+ '[&_ng-icon]:duration-200',
4081
+ '[&_ng-icon]:ease-linear',
4082
+ 'motion-reduce:[&_ng-icon]:transition-none',
4083
+ 'group-data-[collapsible=icon]:h-auto!',
4073
4084
  'group-data-[collapsible=icon]:w-full!',
4074
- 'group-data-[collapsible=icon]:justify-center!',
4075
- 'group-data-[collapsible=icon]:[&>span]:hidden',
4076
- 'group-data-[collapsible=icon]:[&_ng-icon]:text-[length:--spacing(6)]',
4085
+ 'group-data-[yuw-rail=on]:justify-center!',
4086
+ 'group-data-[yuw-rail=on]:[&>span]:hidden',
4087
+ 'group-data-[yuw-rail=on]:[&_ng-icon]:scale-150',
4077
4088
  ].join(' ');
4078
4089
  const yuwSidebarMenuChevronClass = [
4079
4090
  'ms-auto',
@@ -4082,7 +4093,7 @@ const yuwSidebarMenuChevronClass = [
4082
4093
  'duration-200',
4083
4094
  'text-[length:--spacing(4)]!',
4084
4095
  'group-aria-expanded/menu-button:rotate-90',
4085
- 'group-data-[collapsible=icon]:hidden!',
4096
+ 'group-data-[yuw-rail=on]:hidden!',
4086
4097
  ].join(' ');
4087
4098
  const yuwSidebarFlyoutClass = [
4088
4099
  'w-56',
@@ -4109,6 +4120,94 @@ const yuwSidebarFlyoutLabelClass = [
4109
4120
  'font-medium',
4110
4121
  'truncate',
4111
4122
  ].join(' ');
4123
+ const yuwSidebarContainerClass = 'contain-layout';
4124
+ const yuwSidebarContentClass = [
4125
+ 'overflow-y-auto',
4126
+ 'group-data-[collapsible=icon]:overflow-y-auto!',
4127
+ 'group-data-[collapsible=icon]:overflow-x-hidden',
4128
+ 'group-data-[yuw-rail=on]:gap-1',
4129
+ ].join(' ');
4130
+ const yuwSidebarGroupLabelClass = [
4131
+ 'group-data-[collapsible=icon]:mt-0!',
4132
+ 'group-data-[collapsible=icon]:opacity-100',
4133
+ 'transition-opacity',
4134
+ 'duration-200',
4135
+ 'ease-linear',
4136
+ 'motion-reduce:transition-none',
4137
+ 'group-data-[yuw-rail=on]:hidden',
4138
+ ].join(' ');
4139
+ const yuwSidebarGroupClass = 'group-data-[yuw-rail=on]:py-0';
4140
+ const yuwSidebarSubmenuWrapperClass = [
4141
+ 'grid',
4142
+ 'transition-[grid-template-rows]',
4143
+ 'duration-200',
4144
+ 'ease-out',
4145
+ 'motion-reduce:transition-none',
4146
+ '[&>*]:min-h-0',
4147
+ '[&>*]:overflow-hidden',
4148
+ ].join(' ');
4149
+ const yuwSidebarSubmenuOpenClass = 'grid-rows-[1fr]';
4150
+ const yuwSidebarSubmenuClosedClass = 'grid-rows-[0fr]';
4151
+ const yuwSidebarMenuBadgeClass = [
4152
+ 'transition-opacity',
4153
+ 'duration-200',
4154
+ 'ease-linear',
4155
+ 'motion-reduce:transition-none',
4156
+ 'group-data-[yuw-rail=on]:opacity-0',
4157
+ 'group-data-[yuw-rail=on]:block!',
4158
+ 'group-data-[yuw-rail=on]:pointer-events-none',
4159
+ ].join(' ');
4160
+ const yuwSidebarGroupLabelTextClass = ['truncate', 'block', 'min-w-0'].join(' ');
4161
+ const yuwSidebarMenuSubButtonClass = ['[&>span]:truncate', '[&>span]:min-w-0'].join(' ');
4162
+
4163
+ /**
4164
+ * Tracks the sidebar's collapsed state, and a second copy of it that lags behind the width animation.
4165
+ *
4166
+ * The helm flips `data-collapsible` the instant the state changes, while the panel takes
4167
+ * `--sidebar-transition-duration` to reach its new width. Anything keyed off that attribute therefore
4168
+ * restyles against a panel that is still the old size — labels vanish and icons jump to rail geometry
4169
+ * while there is still 16rem of sidebar around them.
4170
+ *
4171
+ * `railSettled` fixes that asymmetrically, because the two directions want opposite timing:
4172
+ *
4173
+ * - Collapsing, the rail look has to wait for the panel to actually be narrow. Applying it up front is
4174
+ * what produces the jump.
4175
+ * - Expanding, the rail look has to go immediately. The labels need the whole animation to fade and
4176
+ * ellipsis into place, so waiting would replace one jump with another at the far end.
4177
+ *
4178
+ * `railPending` is the mirror of it, for anything whose *presence* has to span the whole collapse
4179
+ * rather than arrive at the end of it: `true` the instant the panel starts narrowing, `false` only
4180
+ * once the expand has finished widening. The pair brackets the animation from both sides — every
4181
+ * frame in which the panel is at, or moving towards, rail width has `railPending` set, while only the
4182
+ * frames where it has actually arrived have `railSettled` set. Something that must not be visible
4183
+ * during the motion keys off this one; something that must not be restyled during the motion keys off
4184
+ * `railSettled`.
4185
+ *
4186
+ * The delay runs through `timer` rather than a `setTimeout` inside an `effect`, and that is not a
4187
+ * stylistic choice: this app is zoneless, so a signal written from a bare timer callback notifies
4188
+ * nobody. Components reading `railSettled` in a template binding are `OnPush`, so they would keep
4189
+ * their stale view until something else happened to schedule a check — the signal flips, the DOM does
4190
+ * not. Going through `toSignal` puts the write back under Angular's own scheduling.
4191
+ *
4192
+ * Provided at the root so `<yuw-sidebar>` and the nav share one instance — the component stamps the
4193
+ * attribute the class layers select on, and the nav reads the same signal to decide between accordion
4194
+ * and flyout, so the two must agree on the exact frame.
4195
+ */
4196
+ class YuwSidebarRailService {
4197
+ constructor() {
4198
+ this.sidebar = inject(HlmSidebarService);
4199
+ this.collapsed = computed(() => (this.sidebar.isMobile() ? !this.sidebar.openMobile() : !this.sidebar.open()), ...(ngDevMode ? [{ debugName: "collapsed" }] : /* istanbul ignore next */ []));
4200
+ this.collapsed$ = toObservable(this.collapsed);
4201
+ this.railSettled = toSignal(this.collapsed$.pipe(switchMap((collapsed) => (collapsed ? timer(YUW_SIDEBAR_TRANSITION_MS).pipe(map(() => true)) : of(false)))), { initialValue: false });
4202
+ this.railPending = toSignal(this.collapsed$.pipe(switchMap((collapsed) => (collapsed ? of(true) : timer(YUW_SIDEBAR_TRANSITION_MS).pipe(map(() => false))))), { initialValue: false });
4203
+ }
4204
+ static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.8", ngImport: i0, type: YuwSidebarRailService, deps: [], target: i0.ɵɵFactoryTarget.Injectable }); }
4205
+ static { this.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "21.2.8", ngImport: i0, type: YuwSidebarRailService, providedIn: 'root' }); }
4206
+ }
4207
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.8", ngImport: i0, type: YuwSidebarRailService, decorators: [{
4208
+ type: Injectable,
4209
+ args: [{ providedIn: 'root' }]
4210
+ }] });
4112
4211
 
4113
4212
  /**
4114
4213
  * Outermost layout directive for a sidebar page. Wraps the sidebar and the main content, and owns
@@ -4163,8 +4262,33 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.8", ngImpor
4163
4262
  hostDirectives: [HlmSidebarHeader],
4164
4263
  }]
4165
4264
  }] });
4166
- /** Scrollable middle area of the sidebar that holds the navigation groups. */
4265
+ /**
4266
+ * Scrollable middle area of the sidebar that holds the navigation groups.
4267
+ *
4268
+ * Restores vertical scrolling in the collapsed state, which the composed primitive switches off with
4269
+ * `group-data-[collapsible=icon]:overflow-hidden`. That is a fair default for a rail of icons alone,
4270
+ * but ours keeps expandable entries reachable there, so a tall nav has to be able to scroll rather
4271
+ * than have its last icons clipped. Horizontal overflow stays hidden: nothing should scroll sideways
4272
+ * in a rail that narrow.
4273
+ *
4274
+ * The `!` is needed because the helm's own declaration sits in the same Tailwind group at the same
4275
+ * modifier, and `twMerge` resolves that by keeping the last one — which would be ours already, except
4276
+ * `overflow-hidden` and `overflow-y-auto` are different properties to it, so both survive and the
4277
+ * shorthand wins on order.
4278
+ *
4279
+ * The scrollbar itself stays hidden, which the primitive's own `no-scrollbar` already handles: a
4280
+ * gutter that only appears once the nav happens to overflow shifts the icons sideways, and the rail is
4281
+ * too narrow to spend 11px on it. Wheel, trackpad and keyboard still scroll; only the thumb is gone.
4282
+ *
4283
+ * Also spaces the groups it stacks while collapsed. Each group's own menu spaces its items, so with
4284
+ * the groups' vertical padding dropped there was nothing left between the last icon of one and the
4285
+ * first of the next; matching that spacing here is what makes the rail read as one evenly spaced
4286
+ * column rather than blocks butted together.
4287
+ */
4167
4288
  class YuwSidebarContentDirective {
4289
+ constructor() {
4290
+ classes(() => yuwSidebarContentClass);
4291
+ }
4168
4292
  static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.8", ngImport: i0, type: YuwSidebarContentDirective, deps: [], target: i0.ɵɵFactoryTarget.Directive }); }
4169
4293
  static { this.ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "14.0.0", version: "21.2.8", type: YuwSidebarContentDirective, isStandalone: true, selector: "[yuwSidebarContent], yuw-sidebar-content", hostDirectives: [{ directive: i1$q.HlmSidebarContent }], ngImport: i0 }); }
4170
4294
  }
@@ -4174,7 +4298,7 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.8", ngImpor
4174
4298
  selector: '[yuwSidebarContent], yuw-sidebar-content',
4175
4299
  hostDirectives: [HlmSidebarContent],
4176
4300
  }]
4177
- }] });
4301
+ }], ctorParameters: () => [] });
4178
4302
  /** Bottom area of the sidebar, below the scrollable content. */
4179
4303
  class YuwSidebarFooterDirective {
4180
4304
  static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.8", ngImport: i0, type: YuwSidebarFooterDirective, deps: [], target: i0.ɵɵFactoryTarget.Directive }); }
@@ -4187,8 +4311,19 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.8", ngImpor
4187
4311
  hostDirectives: [HlmSidebarFooter],
4188
4312
  }]
4189
4313
  }] });
4190
- /** A titled section of the sidebar. */
4314
+ /**
4315
+ * A titled section of the sidebar.
4316
+ *
4317
+ * Drops its vertical padding once collapsed to icons. The composed primitive pads every side with
4318
+ * `p-2`, which is right while headings are visible and separating one group from the next, but on the
4319
+ * rail those headings are gone and two adjacent groups contribute 8px each — a gap in the middle of
4320
+ * what reads as one column of icons. Horizontal padding stays: it is what keeps the icons off the
4321
+ * rail's edges.
4322
+ */
4191
4323
  class YuwSidebarGroupDirective {
4324
+ constructor() {
4325
+ classes(() => yuwSidebarGroupClass);
4326
+ }
4192
4327
  static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.8", ngImport: i0, type: YuwSidebarGroupDirective, deps: [], target: i0.ɵɵFactoryTarget.Directive }); }
4193
4328
  static { this.ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "14.0.0", version: "21.2.8", type: YuwSidebarGroupDirective, isStandalone: true, selector: "[yuwSidebarGroup], yuw-sidebar-group", hostDirectives: [{ directive: i1$q.HlmSidebarGroup }], ngImport: i0 }); }
4194
4329
  }
@@ -4198,9 +4333,20 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.8", ngImpor
4198
4333
  selector: '[yuwSidebarGroup], yuw-sidebar-group',
4199
4334
  hostDirectives: [HlmSidebarGroup],
4200
4335
  }]
4201
- }] });
4202
- /** Heading of a sidebar group. Fades out when the sidebar collapses to icons. */
4336
+ }], ctorParameters: () => [] });
4337
+ /**
4338
+ * Heading of a sidebar group. Removed from the layout when the sidebar collapses to icons.
4339
+ *
4340
+ * The composed primitive hides it with `-mt-8` plus `opacity-0`, which leaves the heading in the flow
4341
+ * still occupying its `h-8` box and cancels that box with a negative margin. The two only net to zero
4342
+ * while the heading is exactly one line at exactly that height, so a group heading left a visible gap
4343
+ * between the icons of one group and the next. `hidden` takes it out of the flow instead, and the
4344
+ * margin is zeroed so the collapsed rail is not pulled upwards by a box that no longer exists.
4345
+ */
4203
4346
  class YuwSidebarGroupLabelDirective {
4347
+ constructor() {
4348
+ classes(() => yuwSidebarGroupLabelClass);
4349
+ }
4204
4350
  static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.8", ngImport: i0, type: YuwSidebarGroupLabelDirective, deps: [], target: i0.ɵɵFactoryTarget.Directive }); }
4205
4351
  static { this.ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "14.0.0", version: "21.2.8", type: YuwSidebarGroupLabelDirective, isStandalone: true, selector: "div[yuwSidebarGroupLabel], button[yuwSidebarGroupLabel]", hostDirectives: [{ directive: i1$q.HlmSidebarGroupLabel }], ngImport: i0 }); }
4206
4352
  }
@@ -4210,7 +4356,7 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.8", ngImpor
4210
4356
  selector: 'div[yuwSidebarGroupLabel], button[yuwSidebarGroupLabel]',
4211
4357
  hostDirectives: [HlmSidebarGroupLabel],
4212
4358
  }]
4213
- }] });
4359
+ }], ctorParameters: () => [] });
4214
4360
  /** Body of a sidebar group, wrapping its menu. */
4215
4361
  class YuwSidebarGroupContentDirective {
4216
4362
  static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.8", ngImport: i0, type: YuwSidebarGroupContentDirective, deps: [], target: i0.ɵɵFactoryTarget.Directive }); }
@@ -4280,12 +4426,20 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.8", ngImpor
4280
4426
  * Interactive control of a sidebar menu item. Accepts `variant` (`'default'`, `'outline'`), `size`
4281
4427
  * (`'default'`, `'sm'`, `'lg'`) and `isActive`.
4282
4428
  *
4283
- * To label the item while the sidebar is collapsed to icons, add Spartan's `tooltip` input
4284
- * alongside this directive it comes from the underlying menu-button primitive and is only shown
4285
- * in the collapsed state. It cannot be re-forwarded through this wrapper's `hostDirectives`
4286
- * (`tooltip` is the alias `HlmSidebarMenuButton` gives its own composed `BrnTooltip`, not a public
4287
- * input of its own), so bind it with `[attr.tooltip]` rather than `[tooltip]` when the value comes
4288
- * from an expression.
4429
+ * `tooltip` labels the item while the sidebar is collapsed to icons, where the label itself is
4430
+ * hidden; the composed primitive shows it only in that state, and only for entries with no flyout of
4431
+ * their own an entry with children opens its submenu on the same hover instead.
4432
+ *
4433
+ * Reaching that input takes composing `BrnTooltip` here under the same `tooltip` alias the helm uses,
4434
+ * rather than forwarding it. `HlmSidebarMenuButton` publishes the alias on its own `hostDirectives`
4435
+ * entry, which does not make it an input of the helm directive — a forward cannot be re-forwarded, the
4436
+ * same limit `[yuwSidebarFlyoutTrigger]` runs into. Angular resolves both entries to the one
4437
+ * `BrnTooltip` instance on the element, so the helm keeps driving `mutableTooltipDisabled` (which is
4438
+ * what confines the tooltip to the collapsed state) while this binding supplies its content.
4439
+ *
4440
+ * `[attr.tooltip]` is not a substitute, and was the bug: it writes an HTML attribute, which never
4441
+ * reaches a signal input, so the tooltip stayed enabled with `null` content and silently showed
4442
+ * nothing.
4289
4443
  *
4290
4444
  * Carries `yuwSidebarMenuButtonClass`, our hover/expanded colouring and collapsed-to-icon geometry.
4291
4445
  * The `classes()` registration below runs after the composed `HlmSidebarMenuButton`'s own, and
@@ -4298,19 +4452,30 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.8", ngImpor
4298
4452
  *
4299
4453
  * Three details of the collapsed-to-icon block are load-bearing:
4300
4454
  *
4301
- * - `size-auto!`, `w-full!` and `justify-center!` keep their `!` because the helm declarations they
4455
+ * - `h-auto!`, `w-full!` and `justify-center!` keep their `!` because the helm declarations they
4302
4456
  * replace (`size-8!`, `p-2!`) are themselves `!important`, which `twMerge` cannot outrank on
4303
4457
  * specificity alone. The helm pins the button to a square; ours fills the rail width and centres
4304
- * the icon.
4458
+ * the icon. Both halves of `size-8!` have to be named separately: a single `size-auto!` occupies
4459
+ * the same `twMerge` group as the base `w-full`, dropping it, so the button would fall back to
4460
+ * shrink-to-fit for the whole width animation — long enough for the label to stop ellipsing and
4461
+ * the trailing chevron to sit against it.
4305
4462
  * - `[&>span]:hidden` drops the label while collapsed, leaving the icon alone — the tooltip carries
4306
4463
  * the name in that state, or the flyout does for an entry with children. Matched by element rather
4307
4464
  * than by `:last-child` (which is what the helm's own `truncate` uses): an expandable entry ends
4308
4465
  * with a trailing chevron, so the label is no longer the last child and a positional selector
4309
4466
  * would skip exactly those entries. `span` is unambiguous here — the label is the only one a menu
4310
4467
  * 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.
4468
+ * - The icon grows through `scale-150` rather than a font-size bump, so it can be transitioned: only
4469
+ * `transform`-family properties animate on the compositor, and a `font-size` change would relayout
4470
+ * the row on every frame.
4471
+ *
4472
+ * Which state each class hangs off is load-bearing, because the two attributes fire at different
4473
+ * times. `data-collapsible` flips the instant the toggle is pressed; `data-yuw-rail` waits for the
4474
+ * width animation to finish. Anything that should hold its expanded look *through* the animation
4475
+ * therefore keys off the rail attribute — the label's `hidden`, the centring, the icon's scale — while
4476
+ * the width and height overrides key off `collapsible`, to displace the helm's `size-8!` before it can
4477
+ * snap the row to 32px and truncate the label away in the first frame. That snap is what made the text vanish
4478
+ * on click instead of ellipsing gradually as the panel narrows.
4314
4479
  */
4315
4480
  class YuwSidebarMenuButtonDirective {
4316
4481
  constructor() {
@@ -4367,8 +4532,19 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.8", ngImpor
4367
4532
  hostDirectives: [HlmSidebarMenuSubItem],
4368
4533
  }]
4369
4534
  }] });
4370
- /** Interactive control of a sidebar submenu item. Accepts `size` (`'sm'`, `'md'`) and `isActive`. */
4535
+ /**
4536
+ * Interactive control of a sidebar submenu item. Accepts `size` (`'sm'`, `'md'`) and `isActive`.
4537
+ *
4538
+ * Carries the same label clamp as `[yuwSidebarMenuButton]`. The composed primitive already truncates
4539
+ * its `span:last-child`, but truncation cannot fire while the span is a flex item at its default
4540
+ * `min-width: auto`: that floor keeps it at content width, so the panel widens the row instead of the
4541
+ * text ellipsing. `min-w-0` is what lets it shrink, and the `[&>span]` selector covers a label that is
4542
+ * no longer the last child.
4543
+ */
4371
4544
  class YuwSidebarMenuSubButtonDirective {
4545
+ constructor() {
4546
+ classes(() => yuwSidebarMenuSubButtonClass);
4547
+ }
4372
4548
  static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.8", ngImport: i0, type: YuwSidebarMenuSubButtonDirective, deps: [], target: i0.ɵɵFactoryTarget.Directive }); }
4373
4549
  static { this.ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "14.0.0", version: "21.2.8", type: YuwSidebarMenuSubButtonDirective, isStandalone: true, selector: "a[yuwSidebarMenuSubButton], button[yuwSidebarMenuSubButton]", hostDirectives: [{ directive: i1$q.HlmSidebarMenuSubButton, inputs: ["size", "size", "isActive", "isActive", "closeMobileSidebarOnClick", "closeMobileSidebarOnClick"] }], ngImport: i0 }); }
4374
4550
  }
@@ -4378,7 +4554,7 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.8", ngImpor
4378
4554
  selector: 'a[yuwSidebarMenuSubButton], button[yuwSidebarMenuSubButton]',
4379
4555
  hostDirectives: [{ directive: HlmSidebarMenuSubButton, inputs: ['size', 'isActive', 'closeMobileSidebarOnClick'] }],
4380
4556
  }]
4381
- }] });
4557
+ }], ctorParameters: () => [] });
4382
4558
  /**
4383
4559
  * Host of a collapsed-state flyout: the element that scopes the overlay for one entry. Apply
4384
4560
  * alongside `[yuwSidebarMenuItem]` on the `<li>` holding the entry and its panel.
@@ -4466,7 +4642,7 @@ class YuwSidebarFlyoutTriggerDirective {
4466
4642
  });
4467
4643
  this.service.setContent(panel, this.viewContainerRef);
4468
4644
  const subscription = this.pointerOver
4469
- .pipe(distinctUntilChanged(), switchMap((visible) => timer(visible ? this.showDelay() : this.hideDelay()).pipe(map(() => visible))))
4645
+ .pipe(distinctUntilChanged(), switchMap$1((visible) => timer(visible ? this.showDelay() : this.hideDelay()).pipe(map(() => visible))))
4470
4646
  .subscribe((visible) => this.toggle(visible));
4471
4647
  onCleanup(() => {
4472
4648
  subscription.unsubscribe();
@@ -4599,6 +4775,11 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.8", ngImpor
4599
4775
  }]
4600
4776
  }] });
4601
4777
 
4778
+ const CARET_RIGHT_BORDER_CLASSES = `
4779
+ border-l-4 border-t-4 border-t-transparent border-r-0
4780
+ border-b-4 border-b-transparent -right-[4.5px] border-[var(--sidebar-foreground)]
4781
+ absolute transition-opacity
4782
+ `;
4602
4783
  /**
4603
4784
  * Renders one {@link YuwSidebarContentDto} as the group/menu/item tree.
4604
4785
  *
@@ -4639,8 +4820,21 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.8", ngImpor
4639
4820
  * `'offcanvas'` moves the whole panel off-screen and `'none'` never collapses, yet the service
4640
4821
  * reports `state() === 'collapsed'` for both — reading the state alone puts a flyout on a sidebar
4641
4822
  * 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.
4823
+ * the accordion. And the collapse must have finished animating, which is what `railSettled` waits
4824
+ * for: swapping the accordion for a flyout while the panel is still wide would tear the submenu out
4825
+ * from under the pointer mid-transition. That same settled signal drives the rail's own styling, so
4826
+ * the geometry and the submenu form always change on the same frame.
4827
+ *
4828
+ * The accordion opens and closes over a grid-rows transition rather than by appearing outright, which
4829
+ * is why the submenu stays mounted and is switched between `0fr` and `1fr` instead of living behind an
4830
+ * `@if`: height cannot animate from or to something that is not in the layout, and `auto` is not an
4831
+ * animatable value. A closed submenu is `inert` and `aria-hidden`, so leaving it mounted does not hand
4832
+ * keyboard users links to a menu they cannot see.
4833
+ *
4834
+ * Collapsing to the rail also clears every open accordion, which is what stops an expand from
4835
+ * unfolding several submenus at once and shoving the entries below them down the panel. An entry
4836
+ * holding the active route still opens on its own, since that one is answering "where am I" rather
4837
+ * than restoring a stale choice.
4644
4838
  *
4645
4839
  * Which entries are expanded resolves in precedence order: an explicit toggle by the user wins,
4646
4840
  * otherwise an entry holding the active route is open — a deep link into a child should not hide the
@@ -4671,17 +4865,24 @@ class YuwSidebarNavComponent {
4671
4865
  this.router = inject(Router);
4672
4866
  this.injector = inject(Injector);
4673
4867
  this.sidebarService = inject(HlmSidebarService);
4674
- this.activeRoutes = new Map();
4868
+ this.rail = inject(YuwSidebarRailService);
4675
4869
  this.content = input.required(...(ngDevMode ? [{ debugName: "content" }] : /* istanbul ignore next */ []));
4676
4870
  this.collapsible = input('offcanvas', ...(ngDevMode ? [{ debugName: "collapsible" }] : /* istanbul ignore next */ []));
4677
4871
  this.itemClicked = output();
4872
+ this.activeRoutes = new Map();
4678
4873
  this.chevronClass = yuwSidebarMenuChevronClass;
4679
4874
  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() });
4875
+ this.badgeClass = yuwSidebarMenuBadgeClass;
4876
+ this.groupLabelTextClass = yuwSidebarGroupLabelTextClass;
4877
+ this.caretRightBorderClasses = CARET_RIGHT_BORDER_CLASSES;
4878
+ this.isRail = computed(() => this.collapsible() === 'icon' && !this.sidebarService.isMobile() && this.rail.railSettled(), ...(ngDevMode ? [{ debugName: "isRail" }] : /* istanbul ignore next */ []));
4879
+ this.expandedIds = linkedSignal({ ...(ngDevMode ? { debugName: "expandedIds" } : /* istanbul ignore next */ {}), source: () => ({ content: this.content(), rail: this.isRail() }),
4880
+ computation: ({ content, rail }, previous) => rail || previous
4881
+ ? new Set()
4882
+ : new Set(content.groups.flatMap((group) => group.items.filter((item) => item.expanded).map((item) => item.id))) });
4683
4883
  this._groups = computed(() => {
4684
- const toggles = this.userToggles();
4884
+ const expandedIds = this.expandedIds();
4885
+ const isRail = this.isRail();
4685
4886
  return this.content().groups.map((group) => ({
4686
4887
  ...group,
4687
4888
  items: group.items.map((item) => {
@@ -4690,13 +4891,15 @@ class YuwSidebarNavComponent {
4690
4891
  activeOptions: { exact: child.exact ?? false },
4691
4892
  }));
4692
4893
  const hasChildren = children.length > 0;
4894
+ const expanded = isRail || !hasChildren ? false : expandedIds.has(item.id) || this.holdsActiveRoute(item.children);
4693
4895
  return {
4694
4896
  ...item,
4695
4897
  children,
4696
4898
  hasChildren,
4697
- tooltipText: hasChildren ? undefined : (item.tooltip ?? item.label),
4899
+ tooltipText: hasChildren ? null : (item.tooltip ?? item.label),
4698
4900
  activeOptions: { exact: item.exact ?? false },
4699
- expanded: toggles.get(item.id) ?? (this.holdsActiveRoute(item.children) || (item.expanded ?? false)),
4901
+ expanded,
4902
+ submenuClass: `${yuwSidebarSubmenuWrapperClass} ${expanded ? yuwSidebarSubmenuOpenClass : yuwSidebarSubmenuClosedClass}`,
4700
4903
  };
4701
4904
  }),
4702
4905
  }));
@@ -4723,10 +4926,17 @@ class YuwSidebarNavComponent {
4723
4926
  onParentClick(id, expanded) {
4724
4927
  if (this.isRail())
4725
4928
  return;
4726
- this.userToggles.update((toggles) => new Map(toggles).set(id, !expanded));
4929
+ this.expandedIds.update((ids) => {
4930
+ const next = new Set(ids);
4931
+ if (expanded)
4932
+ next.delete(id);
4933
+ else
4934
+ next.add(id);
4935
+ return next;
4936
+ });
4727
4937
  }
4728
4938
  static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.8", ngImport: i0, type: YuwSidebarNavComponent, deps: [], target: i0.ɵɵFactoryTarget.Component }); }
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 }); }
4939
+ static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "21.2.8", type: YuwSidebarNavComponent, isStandalone: true, selector: "yuw-sidebar-nav", inputs: { content: { classPropertyName: "content", publicName: "content", isSignal: true, isRequired: true, transformFunction: null }, collapsible: { classPropertyName: "collapsible", publicName: "collapsible", isSignal: true, isRequired: false, transformFunction: null } }, outputs: { itemClicked: "itemClicked" }, host: { classAttribute: "contents" }, providers: [provideIcons({ lucideChevronRight })], ngImport: i0, template: "<ng-template #submenu let-item>\n <ul yuwSidebarMenuSub>\n @for (child of item.children; track child.id) {\n <li yuwSidebarMenuSubItem>\n @if (child.route) {\n <a\n yuwSidebarMenuSubButton\n closeMobileSidebarOnClick\n [routerLink]=\"child.route\"\n routerLinkActive\n #childLink=\"routerLinkActive\"\n [routerLinkActiveOptions]=\"child.activeOptions\"\n [isActive]=\"childLink.isActive\"\n [attr.aria-current]=\"childLink.isActive ? 'page' : null\"\n [attr.aria-disabled]=\"child.disabled ? 'true' : null\"\n [class.pointer-events-none]=\"childLink.isActive || child.disabled\"\n >\n <span>{{ child.label }}</span>\n </a>\n } @else if (child.href) {\n <a\n yuwSidebarMenuSubButton\n closeMobileSidebarOnClick\n [href]=\"child.href\"\n [attr.target]=\"child.target\"\n [attr.aria-disabled]=\"child.disabled ? 'true' : null\"\n [class.pointer-events-none]=\"child.disabled\"\n >\n <span>{{ child.label }}</span>\n </a>\n } @else {\n <button\n yuwSidebarMenuSubButton\n closeMobileSidebarOnClick\n type=\"button\"\n [disabled]=\"child.disabled ?? false\"\n (click)=\"onItemClick(child.id, $event)\"\n >\n <span>{{ child.label }}</span>\n </button>\n }\n </li>\n }\n </ul>\n</ng-template>\n\n@for (group of _groups(); track group.id) {\n <div yuwSidebarGroup>\n @if (group.label) {\n <div yuwSidebarGroupLabel>\n <span [class]=\"groupLabelTextClass\">{{ group.label }}</span>\n </div>\n }\n\n <div yuwSidebarGroupContent>\n <ul yuwSidebarMenu class=\"gap-1\">\n @for (item of group.items; track item.id) {\n <li yuwSidebarMenuItem yuwSidebarFlyoutHost>\n <ng-template yuwSidebarFlyoutPanel #panel>\n <div yuwSidebarFlyout>\n <span [class]=\"flyoutLabelClass\">{{ item.label }}</span>\n <ng-container [ngTemplateOutlet]=\"submenu\" [ngTemplateOutletContext]=\"{ $implicit: item }\" />\n </div>\n </ng-template>\n\n @if (item.route) {\n <a\n yuwSidebarMenuButton\n closeMobileSidebarOnClick\n [routerLink]=\"item.route\"\n routerLinkActive\n #link=\"routerLinkActive\"\n [routerLinkActiveOptions]=\"item.activeOptions\"\n [isActive]=\"link.isActive\"\n [tooltip]=\"item.tooltipText\"\n [attr.aria-current]=\"link.isActive ? 'page' : null\"\n [attr.aria-disabled]=\"item.disabled ? 'true' : null\"\n [attr.aria-expanded]=\"item.hasChildren ? item.expanded : null\"\n [class.pointer-events-none]=\"(link.isActive && !item.hasChildren) || item.disabled\"\n [yuwSidebarFlyoutTrigger]=\"item.hasChildren && isRail() ? panel : undefined\"\n align=\"right\"\n [sideOffset]=\"0\"\n [showDelay]=\"120\"\n [hideDelay]=\"300\"\n (click)=\"onParentClick(item.id, item.expanded)\"\n >\n @if (item.icon) {\n <ng-icon [name]=\"item.icon\" />\n }\n <span>{{ item.label }}</span>\n @if (item.hasChildren) {\n <ng-icon name=\"lucideChevronRight\" [class]=\"chevronClass\" />\n }\n </a>\n } @else if (item.href) {\n <a\n yuwSidebarMenuButton\n closeMobileSidebarOnClick\n [href]=\"item.href\"\n [attr.target]=\"item.target\"\n [tooltip]=\"item.tooltipText\"\n [attr.aria-disabled]=\"item.disabled ? 'true' : null\"\n [attr.aria-expanded]=\"item.hasChildren ? item.expanded : null\"\n [class.pointer-events-none]=\"item.disabled\"\n [yuwSidebarFlyoutTrigger]=\"item.hasChildren && isRail() ? panel : undefined\"\n align=\"right\"\n [sideOffset]=\"0\"\n [showDelay]=\"120\"\n [hideDelay]=\"300\"\n (click)=\"onParentClick(item.id, item.expanded)\"\n >\n @if (item.icon) {\n <ng-icon [name]=\"item.icon\" />\n }\n <span>{{ item.label }}</span>\n @if (item.hasChildren) {\n <ng-icon name=\"lucideChevronRight\" [class]=\"chevronClass\" />\n }\n </a>\n } @else {\n <button\n yuwSidebarMenuButton\n closeMobileSidebarOnClick\n type=\"button\"\n [tooltip]=\"item.tooltipText\"\n [disabled]=\"item.disabled ?? false\"\n [attr.aria-expanded]=\"item.hasChildren ? item.expanded : null\"\n [yuwSidebarFlyoutTrigger]=\"item.hasChildren && isRail() ? panel : undefined\"\n align=\"right\"\n [sideOffset]=\"0\"\n [showDelay]=\"120\"\n [hideDelay]=\"300\"\n (click)=\"item.hasChildren ? onParentClick(item.id, item.expanded) : onItemClick(item.id, $event)\"\n >\n @if (item.icon) {\n <ng-icon [name]=\"item.icon\" />\n }\n <span>{{ item.label }}</span>\n @if (item.hasChildren) {\n <ng-icon name=\"lucideChevronRight\" [class]=\"chevronClass\" />\n <div\n [class]=\"caretRightBorderClasses\"\n [class.opacity-100]=\"isRail()\"\n [class.opacity-0]=\"!isRail()\"\n ></div>\n }\n </button>\n }\n\n @if (item.badge) {\n <span yuwSidebarMenuBadge [class]=\"badgeClass\">{{ item.badge }}</span>\n }\n\n @if (item.hasChildren && !isRail()) {\n <div\n [class]=\"item.submenuClass\"\n [attr.inert]=\"item.expanded ? null : ''\"\n [attr.aria-hidden]=\"!item.expanded\"\n >\n <div>\n <ng-container [ngTemplateOutlet]=\"submenu\" [ngTemplateOutletContext]=\"{ $implicit: item }\" />\n </div>\n </div>\n }\n </li>\n }\n </ul>\n </div>\n </div>\n\n @if (group.separatorAfter) {\n <div yuwSidebarSeparator class=\"mx-auto w-4/5!\"></div>\n }\n}\n", dependencies: [{ kind: "component", type: NgIcon, selector: "ng-icon", inputs: ["name", "svg", "size", "strokeWidth", "color"] }, { kind: "directive", type: NgTemplateOutlet, selector: "[ngTemplateOutlet]", inputs: ["ngTemplateOutletContext", "ngTemplateOutlet", "ngTemplateOutletInjector"] }, { kind: "directive", type: RouterLink, selector: "[routerLink]", inputs: ["target", "queryParams", "fragment", "queryParamsHandling", "state", "info", "relativeTo", "preserveFragment", "skipLocationChange", "replaceUrl", "routerLink"] }, { kind: "directive", type: RouterLinkActive, selector: "[routerLinkActive]", inputs: ["routerLinkActiveOptions", "ariaCurrentWhenActive", "routerLinkActive"], outputs: ["isActiveChange"], exportAs: ["routerLinkActive"] }, { kind: "directive", type: YuwSidebarGroupDirective, selector: "[yuwSidebarGroup], yuw-sidebar-group" }, { kind: "directive", type: YuwSidebarGroupLabelDirective, selector: "div[yuwSidebarGroupLabel], button[yuwSidebarGroupLabel]" }, { kind: "directive", type: YuwSidebarGroupContentDirective, selector: "div[yuwSidebarGroupContent]" }, { kind: "directive", type: YuwSidebarMenuDirective, selector: "ul[yuwSidebarMenu]" }, { kind: "directive", type: YuwSidebarMenuItemDirective, selector: "li[yuwSidebarMenuItem]" }, { kind: "directive", type: YuwSidebarMenuButtonDirective, selector: "button[yuwSidebarMenuButton], a[yuwSidebarMenuButton]" }, { kind: "directive", type: YuwSidebarMenuBadgeDirective, selector: "[yuwSidebarMenuBadge], yuw-sidebar-menu-badge" }, { kind: "directive", type: YuwSidebarMenuSubDirective, selector: "ul[yuwSidebarMenuSub]" }, { kind: "directive", type: YuwSidebarMenuSubItemDirective, selector: "li[yuwSidebarMenuSubItem]" }, { kind: "directive", type: YuwSidebarMenuSubButtonDirective, selector: "a[yuwSidebarMenuSubButton], button[yuwSidebarMenuSubButton]" }, { kind: "directive", type: YuwSidebarSeparatorDirective, selector: "[yuwSidebarSeparator], yuw-sidebar-separator" }, { kind: "directive", type: YuwSidebarFlyoutHostDirective, selector: "[yuwSidebarFlyoutHost]" }, { kind: "directive", type: YuwSidebarFlyoutPanelDirective, selector: "ng-template[yuwSidebarFlyoutPanel]" }, { kind: "directive", type: YuwSidebarFlyoutTriggerDirective, selector: "[yuwSidebarFlyoutTrigger]", inputs: ["yuwSidebarFlyoutTrigger", "align", "sideOffset", "showDelay", "hideDelay"] }, { kind: "directive", type: YuwSidebarFlyoutDirective, selector: "[yuwSidebarFlyout]" }], changeDetection: i0.ChangeDetectionStrategy.OnPush }); }
4730
4940
  }
4731
4941
  i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.8", ngImport: i0, type: YuwSidebarNavComponent, decorators: [{
4732
4942
  type: Component,
@@ -4741,6 +4951,7 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.8", ngImpor
4741
4951
  YuwSidebarMenuDirective,
4742
4952
  YuwSidebarMenuItemDirective,
4743
4953
  YuwSidebarMenuButtonDirective,
4954
+ HlmSidebarMenuButton,
4744
4955
  YuwSidebarMenuBadgeDirective,
4745
4956
  YuwSidebarMenuSubDirective,
4746
4957
  YuwSidebarMenuSubItemDirective,
@@ -4752,7 +4963,7 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.8", ngImpor
4752
4963
  YuwSidebarFlyoutDirective,
4753
4964
  ], providers: [provideIcons({ lucideChevronRight })], host: {
4754
4965
  class: 'contents',
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" }]
4966
+ }, changeDetection: ChangeDetectionStrategy.OnPush, template: "<ng-template #submenu let-item>\n <ul yuwSidebarMenuSub>\n @for (child of item.children; track child.id) {\n <li yuwSidebarMenuSubItem>\n @if (child.route) {\n <a\n yuwSidebarMenuSubButton\n closeMobileSidebarOnClick\n [routerLink]=\"child.route\"\n routerLinkActive\n #childLink=\"routerLinkActive\"\n [routerLinkActiveOptions]=\"child.activeOptions\"\n [isActive]=\"childLink.isActive\"\n [attr.aria-current]=\"childLink.isActive ? 'page' : null\"\n [attr.aria-disabled]=\"child.disabled ? 'true' : null\"\n [class.pointer-events-none]=\"childLink.isActive || child.disabled\"\n >\n <span>{{ child.label }}</span>\n </a>\n } @else if (child.href) {\n <a\n yuwSidebarMenuSubButton\n closeMobileSidebarOnClick\n [href]=\"child.href\"\n [attr.target]=\"child.target\"\n [attr.aria-disabled]=\"child.disabled ? 'true' : null\"\n [class.pointer-events-none]=\"child.disabled\"\n >\n <span>{{ child.label }}</span>\n </a>\n } @else {\n <button\n yuwSidebarMenuSubButton\n closeMobileSidebarOnClick\n type=\"button\"\n [disabled]=\"child.disabled ?? false\"\n (click)=\"onItemClick(child.id, $event)\"\n >\n <span>{{ child.label }}</span>\n </button>\n }\n </li>\n }\n </ul>\n</ng-template>\n\n@for (group of _groups(); track group.id) {\n <div yuwSidebarGroup>\n @if (group.label) {\n <div yuwSidebarGroupLabel>\n <span [class]=\"groupLabelTextClass\">{{ group.label }}</span>\n </div>\n }\n\n <div yuwSidebarGroupContent>\n <ul yuwSidebarMenu class=\"gap-1\">\n @for (item of group.items; track item.id) {\n <li yuwSidebarMenuItem yuwSidebarFlyoutHost>\n <ng-template yuwSidebarFlyoutPanel #panel>\n <div yuwSidebarFlyout>\n <span [class]=\"flyoutLabelClass\">{{ item.label }}</span>\n <ng-container [ngTemplateOutlet]=\"submenu\" [ngTemplateOutletContext]=\"{ $implicit: item }\" />\n </div>\n </ng-template>\n\n @if (item.route) {\n <a\n yuwSidebarMenuButton\n closeMobileSidebarOnClick\n [routerLink]=\"item.route\"\n routerLinkActive\n #link=\"routerLinkActive\"\n [routerLinkActiveOptions]=\"item.activeOptions\"\n [isActive]=\"link.isActive\"\n [tooltip]=\"item.tooltipText\"\n [attr.aria-current]=\"link.isActive ? 'page' : null\"\n [attr.aria-disabled]=\"item.disabled ? 'true' : null\"\n [attr.aria-expanded]=\"item.hasChildren ? item.expanded : null\"\n [class.pointer-events-none]=\"(link.isActive && !item.hasChildren) || item.disabled\"\n [yuwSidebarFlyoutTrigger]=\"item.hasChildren && isRail() ? panel : undefined\"\n align=\"right\"\n [sideOffset]=\"0\"\n [showDelay]=\"120\"\n [hideDelay]=\"300\"\n (click)=\"onParentClick(item.id, item.expanded)\"\n >\n @if (item.icon) {\n <ng-icon [name]=\"item.icon\" />\n }\n <span>{{ item.label }}</span>\n @if (item.hasChildren) {\n <ng-icon name=\"lucideChevronRight\" [class]=\"chevronClass\" />\n }\n </a>\n } @else if (item.href) {\n <a\n yuwSidebarMenuButton\n closeMobileSidebarOnClick\n [href]=\"item.href\"\n [attr.target]=\"item.target\"\n [tooltip]=\"item.tooltipText\"\n [attr.aria-disabled]=\"item.disabled ? 'true' : null\"\n [attr.aria-expanded]=\"item.hasChildren ? item.expanded : null\"\n [class.pointer-events-none]=\"item.disabled\"\n [yuwSidebarFlyoutTrigger]=\"item.hasChildren && isRail() ? panel : undefined\"\n align=\"right\"\n [sideOffset]=\"0\"\n [showDelay]=\"120\"\n [hideDelay]=\"300\"\n (click)=\"onParentClick(item.id, item.expanded)\"\n >\n @if (item.icon) {\n <ng-icon [name]=\"item.icon\" />\n }\n <span>{{ item.label }}</span>\n @if (item.hasChildren) {\n <ng-icon name=\"lucideChevronRight\" [class]=\"chevronClass\" />\n }\n </a>\n } @else {\n <button\n yuwSidebarMenuButton\n closeMobileSidebarOnClick\n type=\"button\"\n [tooltip]=\"item.tooltipText\"\n [disabled]=\"item.disabled ?? false\"\n [attr.aria-expanded]=\"item.hasChildren ? item.expanded : null\"\n [yuwSidebarFlyoutTrigger]=\"item.hasChildren && isRail() ? panel : undefined\"\n align=\"right\"\n [sideOffset]=\"0\"\n [showDelay]=\"120\"\n [hideDelay]=\"300\"\n (click)=\"item.hasChildren ? onParentClick(item.id, item.expanded) : onItemClick(item.id, $event)\"\n >\n @if (item.icon) {\n <ng-icon [name]=\"item.icon\" />\n }\n <span>{{ item.label }}</span>\n @if (item.hasChildren) {\n <ng-icon name=\"lucideChevronRight\" [class]=\"chevronClass\" />\n <div\n [class]=\"caretRightBorderClasses\"\n [class.opacity-100]=\"isRail()\"\n [class.opacity-0]=\"!isRail()\"\n ></div>\n }\n </button>\n }\n\n @if (item.badge) {\n <span yuwSidebarMenuBadge [class]=\"badgeClass\">{{ item.badge }}</span>\n }\n\n @if (item.hasChildren && !isRail()) {\n <div\n [class]=\"item.submenuClass\"\n [attr.inert]=\"item.expanded ? null : ''\"\n [attr.aria-hidden]=\"!item.expanded\"\n >\n <div>\n <ng-container [ngTemplateOutlet]=\"submenu\" [ngTemplateOutletContext]=\"{ $implicit: item }\" />\n </div>\n </div>\n }\n </li>\n }\n </ul>\n </div>\n </div>\n\n @if (group.separatorAfter) {\n <div yuwSidebarSeparator class=\"mx-auto w-4/5!\"></div>\n }\n}\n" }]
4756
4967
  }], 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"] }] } });
4757
4968
 
4758
4969
  /**
@@ -4782,6 +4993,13 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.8", ngImpor
4782
4993
  * Outputs:
4783
4994
  * - `itemClicked`: Emits `{id, event}` when a non-navigating entry (no `route`, no `href`) is
4784
4995
  * activated, in either `content` or `footer`.
4996
+ * - `collapsedChange`: Emits `true` when the sidebar collapses and `false` when it expands, reading
4997
+ * the mobile sheet or the desktop panel as appropriate. Fires the moment the state flips, so it is
4998
+ * the one to drive a caller's own layout, which should start moving with the panel.
4999
+ * - `railSettledChange`: The same transition, but `true` only once the collapse has finished
5000
+ * animating, and `false` immediately on expand. Use it for anything that should not restyle against
5001
+ * a panel still mid-width — swapping a logo for a mark, say. The sidebar's own rail geometry is
5002
+ * keyed off this, which is why the labels stay put until the panel is actually narrow.
4785
5003
  *
4786
5004
  * The two forms compose rather than exclude each other, unlike `<yuw-button>`'s `buttons` input
4787
5005
  * which drops projected content when set. `content`/`footer` render their own region; anything
@@ -4834,6 +5052,7 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.8", ngImpor
4834
5052
  class YuwSidebarComponent {
4835
5053
  constructor() {
4836
5054
  this.config = injectHlmSidebarConfig();
5055
+ this._rail = inject(YuwSidebarRailService);
4837
5056
  this.side = input('left', ...(ngDevMode ? [{ debugName: "side" }] : /* istanbul ignore next */ []));
4838
5057
  this.variant = input('sidebar', ...(ngDevMode ? [{ debugName: "variant" }] : /* istanbul ignore next */ []));
4839
5058
  this.collapsible = input('offcanvas', ...(ngDevMode ? [{ debugName: "collapsible" }] : /* istanbul ignore next */ []));
@@ -4842,9 +5061,13 @@ class YuwSidebarComponent {
4842
5061
  this.content = input(undefined, ...(ngDevMode ? [{ debugName: "content" }] : /* istanbul ignore next */ []));
4843
5062
  this.footer = input(undefined, ...(ngDevMode ? [{ debugName: "footer" }] : /* istanbul ignore next */ []));
4844
5063
  this.itemClicked = output();
5064
+ this._containerClass = computed(() => `${yuwSidebarContainerClass} ${this.sidebarContainerClass()}`, ...(ngDevMode ? [{ debugName: "_containerClass" }] : /* istanbul ignore next */ []));
5065
+ this._isRail = computed(() => this.collapsible() === 'icon' && this._rail.railSettled(), ...(ngDevMode ? [{ debugName: "_isRail" }] : /* istanbul ignore next */ []));
5066
+ this.collapsedChange = outputFromObservable(toObservable(this._rail.collapsed).pipe(distinctUntilChanged()));
5067
+ this.railSettledChange = outputFromObservable(toObservable(this._rail.railSettled).pipe(distinctUntilChanged()));
4845
5068
  }
4846
5069
  static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.8", ngImport: i0, type: YuwSidebarComponent, deps: [], target: i0.ɵɵFactoryTarget.Component }); }
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 }); }
5070
+ static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "21.2.8", type: YuwSidebarComponent, isStandalone: true, selector: "yuw-sidebar", inputs: { side: { classPropertyName: "side", publicName: "side", isSignal: true, isRequired: false, transformFunction: null }, variant: { classPropertyName: "variant", publicName: "variant", isSignal: true, isRequired: false, transformFunction: null }, collapsible: { classPropertyName: "collapsible", publicName: "collapsible", isSignal: true, isRequired: false, transformFunction: null }, sidebarWidthMobile: { classPropertyName: "sidebarWidthMobile", publicName: "sidebarWidthMobile", isSignal: true, isRequired: false, transformFunction: null }, sidebarContainerClass: { classPropertyName: "sidebarContainerClass", publicName: "sidebarContainerClass", isSignal: true, isRequired: false, transformFunction: null }, content: { classPropertyName: "content", publicName: "content", isSignal: true, isRequired: false, transformFunction: null }, footer: { classPropertyName: "footer", publicName: "footer", isSignal: true, isRequired: false, transformFunction: null } }, outputs: { itemClicked: "itemClicked", collapsedChange: "collapsedChange", railSettledChange: "railSettledChange" }, host: { classAttribute: "contents" }, ngImport: i0, template: "<hlm-sidebar\n [attr.data-yuw-rail]=\"_isRail() ? 'on' : null\"\n [side]=\"side()\"\n [variant]=\"variant()\"\n [collapsible]=\"collapsible()\"\n [sidebarWidthMobile]=\"sidebarWidthMobile()\"\n [sidebarContainerClass]=\"_containerClass()\"\n>\n <ng-content select=\"[yuwSidebarHeader], yuw-sidebar-header\" />\n\n @if (content(); as nav) {\n <div yuwSidebarContent>\n <div yuwSidebarSeparator class=\"mx-auto w-4/5!\"></div>\n <yuw-sidebar-nav [content]=\"nav\" [collapsible]=\"collapsible()\" (itemClicked)=\"itemClicked.emit($event)\" />\n <ng-content select=\"[yuwSidebarContentExtra]\" />\n </div>\n }\n\n <ng-content />\n\n @if (footer(); as nav) {\n <div yuwSidebarFooter>\n <div yuwSidebarSeparator class=\"mx-auto w-4/5!\"></div>\n <yuw-sidebar-nav [content]=\"nav\" [collapsible]=\"collapsible()\" (itemClicked)=\"itemClicked.emit($event)\" />\n <ng-content select=\"[yuwSidebarFooterExtra]\" />\n </div>\n }\n</hlm-sidebar>\n", dependencies: [{ kind: "component", type: HlmSidebar, selector: "hlm-sidebar", inputs: ["sidebarWidthMobile", "side", "variant", "collapsible", "sidebarContainerClass"] }, { kind: "component", type: YuwSidebarNavComponent, selector: "yuw-sidebar-nav", inputs: ["content", "collapsible"], outputs: ["itemClicked"] }, { kind: "directive", type: YuwSidebarContentDirective, selector: "[yuwSidebarContent], yuw-sidebar-content" }, { kind: "directive", type: YuwSidebarFooterDirective, selector: "[yuwSidebarFooter], yuw-sidebar-footer" }, { kind: "directive", type: YuwSidebarSeparatorDirective, selector: "[yuwSidebarSeparator], yuw-sidebar-separator" }], changeDetection: i0.ChangeDetectionStrategy.OnPush }); }
4848
5071
  }
4849
5072
  i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.8", ngImport: i0, type: YuwSidebarComponent, decorators: [{
4850
5073
  type: Component,
@@ -4856,8 +5079,8 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.8", ngImpor
4856
5079
  YuwSidebarSeparatorDirective,
4857
5080
  ], host: {
4858
5081
  class: 'contents',
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" }]
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"] }] } });
5082
+ }, changeDetection: ChangeDetectionStrategy.OnPush, template: "<hlm-sidebar\n [attr.data-yuw-rail]=\"_isRail() ? 'on' : null\"\n [side]=\"side()\"\n [variant]=\"variant()\"\n [collapsible]=\"collapsible()\"\n [sidebarWidthMobile]=\"sidebarWidthMobile()\"\n [sidebarContainerClass]=\"_containerClass()\"\n>\n <ng-content select=\"[yuwSidebarHeader], yuw-sidebar-header\" />\n\n @if (content(); as nav) {\n <div yuwSidebarContent>\n <div yuwSidebarSeparator class=\"mx-auto w-4/5!\"></div>\n <yuw-sidebar-nav [content]=\"nav\" [collapsible]=\"collapsible()\" (itemClicked)=\"itemClicked.emit($event)\" />\n <ng-content select=\"[yuwSidebarContentExtra]\" />\n </div>\n }\n\n <ng-content />\n\n @if (footer(); as nav) {\n <div yuwSidebarFooter>\n <div yuwSidebarSeparator class=\"mx-auto w-4/5!\"></div>\n <yuw-sidebar-nav [content]=\"nav\" [collapsible]=\"collapsible()\" (itemClicked)=\"itemClicked.emit($event)\" />\n <ng-content select=\"[yuwSidebarFooterExtra]\" />\n </div>\n }\n</hlm-sidebar>\n" }]
5083
+ }], propDecorators: { side: [{ type: i0.Input, args: [{ isSignal: true, alias: "side", required: false }] }], variant: [{ type: i0.Input, args: [{ isSignal: true, alias: "variant", required: false }] }], collapsible: [{ type: i0.Input, args: [{ isSignal: true, alias: "collapsible", required: false }] }], sidebarWidthMobile: [{ type: i0.Input, args: [{ isSignal: true, alias: "sidebarWidthMobile", required: false }] }], sidebarContainerClass: [{ type: i0.Input, args: [{ isSignal: true, alias: "sidebarContainerClass", required: false }] }], content: [{ type: i0.Input, args: [{ isSignal: true, alias: "content", required: false }] }], footer: [{ type: i0.Input, args: [{ isSignal: true, alias: "footer", required: false }] }], itemClicked: [{ type: i0.Output, args: ["itemClicked"] }], collapsedChange: [{ type: i0.Output, args: ["collapsedChange"] }], railSettledChange: [{ type: i0.Output, args: ["railSettledChange"] }] } });
4861
5084
 
4862
5085
  /**
4863
5086
  * Icon button that toggles the sidebar open or collapsed. Works anywhere on the page, including
@@ -4894,5 +5117,5 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.8", ngImpor
4894
5117
  * Generated bundle index. Do not edit.
4895
5118
  */
4896
5119
 
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 };
5120
+ export { DATATABLE_ALIGN_CLASS, YUW_DATATABLE_FEATURES, YUW_PASSWORD_REVEAL_STATES, YuwAccordion, YuwAccordionContentComponent, YuwAccordionImports, YuwAccordionItem, YuwAccordionTriggerComponent, YuwAlertActionDirective, YuwAlertComponent, YuwAlertDescriptionDirective, YuwAlertDialogComponent, YuwAlertDialogMediaDirective, YuwAlertDialogTriggerDirective, YuwAlertImports, YuwAlertTitleDirective, YuwAttachmentActionDirective, YuwAttachmentActionsDirective, YuwAttachmentContentDirective, YuwAttachmentDescriptionDirective, YuwAttachmentDirective, YuwAttachmentGroupDirective, YuwAttachmentMediaDirective, YuwAttachmentTitleDirective, YuwAttachmentTriggerDirective, YuwAvatarComponent, YuwBadgeComponent, YuwBreadcrumbComponent, YuwButtonComponent, YuwButtonGroupTextDirective, YuwCaptionDirective, YuwCardActionDirective, YuwCardContentDirective, YuwCardDescriptionDirective, YuwCardDirective, YuwCardFooterDirective, YuwCardHeaderDirective, YuwCardImports, YuwCardTitleDirective, YuwCheckboxComponent, YuwComboboxComponent, YuwComboboxItemDirective, YuwContextMenuCheckboxDirective, YuwContextMenuCheckboxIndicatorComponent, YuwContextMenuDirective, YuwContextMenuGroupDirective, YuwContextMenuImports, YuwContextMenuItemDirective, YuwContextMenuLabelDirective, YuwContextMenuRadioDirective, YuwContextMenuRadioIndicatorComponent, YuwContextMenuSeparatorDirective, YuwContextMenuShortcutDirective, YuwContextMenuSubDirective, YuwContextMenuSubIndicatorComponent, YuwContextMenuSubTriggerDirective, YuwContextMenuTriggerDirective, YuwDatatableComponent, YuwDatatableRowSelect, YuwDatepickerComponent, YuwDialogCloseDirective, YuwDialogComponent, YuwDialogFooterDirective, YuwDialogImports, YuwDialogTriggerDirective, YuwEmptyContentDirective, YuwEmptyDescriptionDirective, YuwEmptyDirective, YuwEmptyHeaderDirective, YuwEmptyImports, YuwEmptyMediaDirective, YuwEmptyTitleDirective, YuwInputAddonImports, YuwInputComponent, YuwInputOtpComponent, YuwItemActionsDirective, YuwItemContentDirective, YuwItemDescriptionDirective, YuwItemDirective, YuwItemFooterDirective, YuwItemGroupDirective, YuwItemHeaderDirective, YuwItemImports, YuwItemMediaDirective, YuwItemSeparatorDirective, YuwItemTitleDirective, YuwLabel, YuwLeftAddonDirective, YuwPaginationComponent, YuwPasswordInputComponent, YuwPopoverComponent, YuwPopoverTriggerDirective, YuwRadioGroupComponent, YuwRightAddonDirective, YuwSearchInputComponent, YuwSheetCloseDirective, YuwSheetComponent, YuwSheetFooterDirective, YuwSheetImports, YuwSheetTriggerDirective, YuwSidebarComponent, YuwSidebarContentDirective, YuwSidebarContentExtraDirective, YuwSidebarFlyoutDirective, YuwSidebarFlyoutHostDirective, YuwSidebarFlyoutPanelDirective, YuwSidebarFlyoutTriggerDirective, YuwSidebarFooterDirective, YuwSidebarFooterExtraDirective, YuwSidebarGroupContentDirective, YuwSidebarGroupDirective, YuwSidebarGroupLabelDirective, YuwSidebarHeaderDirective, YuwSidebarInsetDirective, YuwSidebarMenuBadgeDirective, YuwSidebarMenuButtonDirective, YuwSidebarMenuDirective, YuwSidebarMenuItemDirective, YuwSidebarMenuSubButtonDirective, YuwSidebarMenuSubDirective, YuwSidebarMenuSubItemDirective, YuwSidebarRailDirective, YuwSidebarRailService, YuwSidebarSeparatorDirective, YuwSidebarTriggerComponent, YuwSidebarWrapperDirective, YuwSkeletonDirective, YuwSpinnerComponent, YuwSwitchComponent, YuwTBodyDirective, YuwTFootDirective, YuwTHeadDirective, YuwTabPanelDirective, YuwTableContainerDirective, YuwTableDirective, YuwTableImports, YuwTabsComponent, YuwTdDirective, YuwTextareaComponent, YuwThDirective, YuwToasterComponent, YuwTooltipDirective, YuwTrDirective, YuwValueAccessorBase, buildInputOtpGroups, cn, datatableCellVariants, datatableContainerVariants, datatableHeadVariants, datatableHeaderCellVariants, datatableRowVariants, getPaginationRange, provideValueAccessor, totalInputOtpLength };
4898
5121
  //# sourceMappingURL=yukit-web.mjs.map