yukit-web 0.0.7 → 0.0.8

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -1,7 +1,7 @@
1
1
  import { clsx } from 'clsx';
2
2
  import { twMerge } from 'tailwind-merge';
3
3
  import * as i0 from '@angular/core';
4
- import { forwardRef, signal, Directive, input, inject, TemplateRef, ElementRef, booleanAttribute, output, computed, contentChildren, ChangeDetectionStrategy, Component, model, contentChild, viewChild, Injector, afterNextRender, effect, numberAttribute, linkedSignal, 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,84 @@ 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
+ * The delay runs through `timer` rather than a `setTimeout` inside an `effect`, and that is not a
4179
+ * stylistic choice: this app is zoneless, so a signal written from a bare timer callback notifies
4180
+ * nobody. Components reading `railSettled` in a template binding are `OnPush`, so they would keep
4181
+ * their stale view until something else happened to schedule a check — the signal flips, the DOM does
4182
+ * not. Going through `toSignal` puts the write back under Angular's own scheduling.
4183
+ *
4184
+ * Provided at the root so `<yuw-sidebar>` and the nav share one instance — the component stamps the
4185
+ * attribute the class layers select on, and the nav reads the same signal to decide between accordion
4186
+ * and flyout, so the two must agree on the exact frame.
4187
+ */
4188
+ class YuwSidebarRailService {
4189
+ constructor() {
4190
+ this.sidebar = inject(HlmSidebarService);
4191
+ this.collapsed = computed(() => (this.sidebar.isMobile() ? !this.sidebar.openMobile() : !this.sidebar.open()), ...(ngDevMode ? [{ debugName: "collapsed" }] : /* istanbul ignore next */ []));
4192
+ this.railSettled = toSignal(toObservable(this.collapsed).pipe(switchMap((collapsed) => (collapsed ? timer(YUW_SIDEBAR_TRANSITION_MS).pipe(map(() => true)) : of(false)))), { initialValue: false });
4193
+ }
4194
+ static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.8", ngImport: i0, type: YuwSidebarRailService, deps: [], target: i0.ɵɵFactoryTarget.Injectable }); }
4195
+ static { this.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "21.2.8", ngImport: i0, type: YuwSidebarRailService, providedIn: 'root' }); }
4196
+ }
4197
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.8", ngImport: i0, type: YuwSidebarRailService, decorators: [{
4198
+ type: Injectable,
4199
+ args: [{ providedIn: 'root' }]
4200
+ }] });
4112
4201
 
4113
4202
  /**
4114
4203
  * Outermost layout directive for a sidebar page. Wraps the sidebar and the main content, and owns
@@ -4163,8 +4252,33 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.8", ngImpor
4163
4252
  hostDirectives: [HlmSidebarHeader],
4164
4253
  }]
4165
4254
  }] });
4166
- /** Scrollable middle area of the sidebar that holds the navigation groups. */
4255
+ /**
4256
+ * Scrollable middle area of the sidebar that holds the navigation groups.
4257
+ *
4258
+ * Restores vertical scrolling in the collapsed state, which the composed primitive switches off with
4259
+ * `group-data-[collapsible=icon]:overflow-hidden`. That is a fair default for a rail of icons alone,
4260
+ * but ours keeps expandable entries reachable there, so a tall nav has to be able to scroll rather
4261
+ * than have its last icons clipped. Horizontal overflow stays hidden: nothing should scroll sideways
4262
+ * in a rail that narrow.
4263
+ *
4264
+ * The `!` is needed because the helm's own declaration sits in the same Tailwind group at the same
4265
+ * modifier, and `twMerge` resolves that by keeping the last one — which would be ours already, except
4266
+ * `overflow-hidden` and `overflow-y-auto` are different properties to it, so both survive and the
4267
+ * shorthand wins on order.
4268
+ *
4269
+ * The scrollbar itself stays hidden, which the primitive's own `no-scrollbar` already handles: a
4270
+ * gutter that only appears once the nav happens to overflow shifts the icons sideways, and the rail is
4271
+ * too narrow to spend 11px on it. Wheel, trackpad and keyboard still scroll; only the thumb is gone.
4272
+ *
4273
+ * Also spaces the groups it stacks while collapsed. Each group's own menu spaces its items, so with
4274
+ * the groups' vertical padding dropped there was nothing left between the last icon of one and the
4275
+ * first of the next; matching that spacing here is what makes the rail read as one evenly spaced
4276
+ * column rather than blocks butted together.
4277
+ */
4167
4278
  class YuwSidebarContentDirective {
4279
+ constructor() {
4280
+ classes(() => yuwSidebarContentClass);
4281
+ }
4168
4282
  static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.8", ngImport: i0, type: YuwSidebarContentDirective, deps: [], target: i0.ɵɵFactoryTarget.Directive }); }
4169
4283
  static { this.ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "14.0.0", version: "21.2.8", type: YuwSidebarContentDirective, isStandalone: true, selector: "[yuwSidebarContent], yuw-sidebar-content", hostDirectives: [{ directive: i1$q.HlmSidebarContent }], ngImport: i0 }); }
4170
4284
  }
@@ -4174,7 +4288,7 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.8", ngImpor
4174
4288
  selector: '[yuwSidebarContent], yuw-sidebar-content',
4175
4289
  hostDirectives: [HlmSidebarContent],
4176
4290
  }]
4177
- }] });
4291
+ }], ctorParameters: () => [] });
4178
4292
  /** Bottom area of the sidebar, below the scrollable content. */
4179
4293
  class YuwSidebarFooterDirective {
4180
4294
  static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.8", ngImport: i0, type: YuwSidebarFooterDirective, deps: [], target: i0.ɵɵFactoryTarget.Directive }); }
@@ -4187,8 +4301,19 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.8", ngImpor
4187
4301
  hostDirectives: [HlmSidebarFooter],
4188
4302
  }]
4189
4303
  }] });
4190
- /** A titled section of the sidebar. */
4304
+ /**
4305
+ * A titled section of the sidebar.
4306
+ *
4307
+ * Drops its vertical padding once collapsed to icons. The composed primitive pads every side with
4308
+ * `p-2`, which is right while headings are visible and separating one group from the next, but on the
4309
+ * rail those headings are gone and two adjacent groups contribute 8px each — a gap in the middle of
4310
+ * what reads as one column of icons. Horizontal padding stays: it is what keeps the icons off the
4311
+ * rail's edges.
4312
+ */
4191
4313
  class YuwSidebarGroupDirective {
4314
+ constructor() {
4315
+ classes(() => yuwSidebarGroupClass);
4316
+ }
4192
4317
  static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.8", ngImport: i0, type: YuwSidebarGroupDirective, deps: [], target: i0.ɵɵFactoryTarget.Directive }); }
4193
4318
  static { this.ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "14.0.0", version: "21.2.8", type: YuwSidebarGroupDirective, isStandalone: true, selector: "[yuwSidebarGroup], yuw-sidebar-group", hostDirectives: [{ directive: i1$q.HlmSidebarGroup }], ngImport: i0 }); }
4194
4319
  }
@@ -4198,9 +4323,20 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.8", ngImpor
4198
4323
  selector: '[yuwSidebarGroup], yuw-sidebar-group',
4199
4324
  hostDirectives: [HlmSidebarGroup],
4200
4325
  }]
4201
- }] });
4202
- /** Heading of a sidebar group. Fades out when the sidebar collapses to icons. */
4326
+ }], ctorParameters: () => [] });
4327
+ /**
4328
+ * Heading of a sidebar group. Removed from the layout when the sidebar collapses to icons.
4329
+ *
4330
+ * The composed primitive hides it with `-mt-8` plus `opacity-0`, which leaves the heading in the flow
4331
+ * still occupying its `h-8` box and cancels that box with a negative margin. The two only net to zero
4332
+ * while the heading is exactly one line at exactly that height, so a group heading left a visible gap
4333
+ * between the icons of one group and the next. `hidden` takes it out of the flow instead, and the
4334
+ * margin is zeroed so the collapsed rail is not pulled upwards by a box that no longer exists.
4335
+ */
4203
4336
  class YuwSidebarGroupLabelDirective {
4337
+ constructor() {
4338
+ classes(() => yuwSidebarGroupLabelClass);
4339
+ }
4204
4340
  static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.8", ngImport: i0, type: YuwSidebarGroupLabelDirective, deps: [], target: i0.ɵɵFactoryTarget.Directive }); }
4205
4341
  static { this.ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "14.0.0", version: "21.2.8", type: YuwSidebarGroupLabelDirective, isStandalone: true, selector: "div[yuwSidebarGroupLabel], button[yuwSidebarGroupLabel]", hostDirectives: [{ directive: i1$q.HlmSidebarGroupLabel }], ngImport: i0 }); }
4206
4342
  }
@@ -4210,7 +4346,7 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.8", ngImpor
4210
4346
  selector: 'div[yuwSidebarGroupLabel], button[yuwSidebarGroupLabel]',
4211
4347
  hostDirectives: [HlmSidebarGroupLabel],
4212
4348
  }]
4213
- }] });
4349
+ }], ctorParameters: () => [] });
4214
4350
  /** Body of a sidebar group, wrapping its menu. */
4215
4351
  class YuwSidebarGroupContentDirective {
4216
4352
  static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.8", ngImport: i0, type: YuwSidebarGroupContentDirective, deps: [], target: i0.ɵɵFactoryTarget.Directive }); }
@@ -4280,12 +4416,20 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.8", ngImpor
4280
4416
  * Interactive control of a sidebar menu item. Accepts `variant` (`'default'`, `'outline'`), `size`
4281
4417
  * (`'default'`, `'sm'`, `'lg'`) and `isActive`.
4282
4418
  *
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.
4419
+ * `tooltip` labels the item while the sidebar is collapsed to icons, where the label itself is
4420
+ * hidden; the composed primitive shows it only in that state, and only for entries with no flyout of
4421
+ * their own an entry with children opens its submenu on the same hover instead.
4422
+ *
4423
+ * Reaching that input takes composing `BrnTooltip` here under the same `tooltip` alias the helm uses,
4424
+ * rather than forwarding it. `HlmSidebarMenuButton` publishes the alias on its own `hostDirectives`
4425
+ * entry, which does not make it an input of the helm directive — a forward cannot be re-forwarded, the
4426
+ * same limit `[yuwSidebarFlyoutTrigger]` runs into. Angular resolves both entries to the one
4427
+ * `BrnTooltip` instance on the element, so the helm keeps driving `mutableTooltipDisabled` (which is
4428
+ * what confines the tooltip to the collapsed state) while this binding supplies its content.
4429
+ *
4430
+ * `[attr.tooltip]` is not a substitute, and was the bug: it writes an HTML attribute, which never
4431
+ * reaches a signal input, so the tooltip stayed enabled with `null` content and silently showed
4432
+ * nothing.
4289
4433
  *
4290
4434
  * Carries `yuwSidebarMenuButtonClass`, our hover/expanded colouring and collapsed-to-icon geometry.
4291
4435
  * The `classes()` registration below runs after the composed `HlmSidebarMenuButton`'s own, and
@@ -4298,19 +4442,30 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.8", ngImpor
4298
4442
  *
4299
4443
  * Three details of the collapsed-to-icon block are load-bearing:
4300
4444
  *
4301
- * - `size-auto!`, `w-full!` and `justify-center!` keep their `!` because the helm declarations they
4445
+ * - `h-auto!`, `w-full!` and `justify-center!` keep their `!` because the helm declarations they
4302
4446
  * replace (`size-8!`, `p-2!`) are themselves `!important`, which `twMerge` cannot outrank on
4303
4447
  * specificity alone. The helm pins the button to a square; ours fills the rail width and centres
4304
- * the icon.
4448
+ * the icon. Both halves of `size-8!` have to be named separately: a single `size-auto!` occupies
4449
+ * the same `twMerge` group as the base `w-full`, dropping it, so the button would fall back to
4450
+ * shrink-to-fit for the whole width animation — long enough for the label to stop ellipsing and
4451
+ * the trailing chevron to sit against it.
4305
4452
  * - `[&>span]:hidden` drops the label while collapsed, leaving the icon alone — the tooltip carries
4306
4453
  * the name in that state, or the flyout does for an entry with children. Matched by element rather
4307
4454
  * than by `:last-child` (which is what the helm's own `truncate` uses): an expandable entry ends
4308
4455
  * with a trailing chevron, so the label is no longer the last child and a positional selector
4309
4456
  * would skip exactly those entries. `span` is unambiguous here — the label is the only one a menu
4310
4457
  * 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.
4458
+ * - The icon grows through `scale-150` rather than a font-size bump, so it can be transitioned: only
4459
+ * `transform`-family properties animate on the compositor, and a `font-size` change would relayout
4460
+ * the row on every frame.
4461
+ *
4462
+ * Which state each class hangs off is load-bearing, because the two attributes fire at different
4463
+ * times. `data-collapsible` flips the instant the toggle is pressed; `data-yuw-rail` waits for the
4464
+ * width animation to finish. Anything that should hold its expanded look *through* the animation
4465
+ * therefore keys off the rail attribute — the label's `hidden`, the centring, the icon's scale — while
4466
+ * the width and height overrides key off `collapsible`, to displace the helm's `size-8!` before it can
4467
+ * snap the row to 32px and truncate the label away in the first frame. That snap is what made the text vanish
4468
+ * on click instead of ellipsing gradually as the panel narrows.
4314
4469
  */
4315
4470
  class YuwSidebarMenuButtonDirective {
4316
4471
  constructor() {
@@ -4367,8 +4522,19 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.8", ngImpor
4367
4522
  hostDirectives: [HlmSidebarMenuSubItem],
4368
4523
  }]
4369
4524
  }] });
4370
- /** Interactive control of a sidebar submenu item. Accepts `size` (`'sm'`, `'md'`) and `isActive`. */
4525
+ /**
4526
+ * Interactive control of a sidebar submenu item. Accepts `size` (`'sm'`, `'md'`) and `isActive`.
4527
+ *
4528
+ * Carries the same label clamp as `[yuwSidebarMenuButton]`. The composed primitive already truncates
4529
+ * its `span:last-child`, but truncation cannot fire while the span is a flex item at its default
4530
+ * `min-width: auto`: that floor keeps it at content width, so the panel widens the row instead of the
4531
+ * text ellipsing. `min-w-0` is what lets it shrink, and the `[&>span]` selector covers a label that is
4532
+ * no longer the last child.
4533
+ */
4371
4534
  class YuwSidebarMenuSubButtonDirective {
4535
+ constructor() {
4536
+ classes(() => yuwSidebarMenuSubButtonClass);
4537
+ }
4372
4538
  static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.8", ngImport: i0, type: YuwSidebarMenuSubButtonDirective, deps: [], target: i0.ɵɵFactoryTarget.Directive }); }
4373
4539
  static { this.ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "14.0.0", version: "21.2.8", type: YuwSidebarMenuSubButtonDirective, isStandalone: true, selector: "a[yuwSidebarMenuSubButton], button[yuwSidebarMenuSubButton]", hostDirectives: [{ directive: i1$q.HlmSidebarMenuSubButton, inputs: ["size", "size", "isActive", "isActive", "closeMobileSidebarOnClick", "closeMobileSidebarOnClick"] }], ngImport: i0 }); }
4374
4540
  }
@@ -4378,7 +4544,7 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.8", ngImpor
4378
4544
  selector: 'a[yuwSidebarMenuSubButton], button[yuwSidebarMenuSubButton]',
4379
4545
  hostDirectives: [{ directive: HlmSidebarMenuSubButton, inputs: ['size', 'isActive', 'closeMobileSidebarOnClick'] }],
4380
4546
  }]
4381
- }] });
4547
+ }], ctorParameters: () => [] });
4382
4548
  /**
4383
4549
  * Host of a collapsed-state flyout: the element that scopes the overlay for one entry. Apply
4384
4550
  * alongside `[yuwSidebarMenuItem]` on the `<li>` holding the entry and its panel.
@@ -4466,7 +4632,7 @@ class YuwSidebarFlyoutTriggerDirective {
4466
4632
  });
4467
4633
  this.service.setContent(panel, this.viewContainerRef);
4468
4634
  const subscription = this.pointerOver
4469
- .pipe(distinctUntilChanged(), switchMap((visible) => timer(visible ? this.showDelay() : this.hideDelay()).pipe(map(() => visible))))
4635
+ .pipe(distinctUntilChanged(), switchMap$1((visible) => timer(visible ? this.showDelay() : this.hideDelay()).pipe(map(() => visible))))
4470
4636
  .subscribe((visible) => this.toggle(visible));
4471
4637
  onCleanup(() => {
4472
4638
  subscription.unsubscribe();
@@ -4599,6 +4765,11 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.8", ngImpor
4599
4765
  }]
4600
4766
  }] });
4601
4767
 
4768
+ const CARET_RIGHT_BORDER_CLASSES = `
4769
+ border-l-4 border-t-4 border-t-transparent border-r-0
4770
+ border-b-4 border-b-transparent -right-[4.5px] border-[var(--sidebar-foreground)]
4771
+ absolute transition-opacity
4772
+ `;
4602
4773
  /**
4603
4774
  * Renders one {@link YuwSidebarContentDto} as the group/menu/item tree.
4604
4775
  *
@@ -4639,8 +4810,21 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.8", ngImpor
4639
4810
  * `'offcanvas'` moves the whole panel off-screen and `'none'` never collapses, yet the service
4640
4811
  * reports `state() === 'collapsed'` for both — reading the state alone puts a flyout on a sidebar
4641
4812
  * 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.
4813
+ * the accordion. And the collapse must have finished animating, which is what `railSettled` waits
4814
+ * for: swapping the accordion for a flyout while the panel is still wide would tear the submenu out
4815
+ * from under the pointer mid-transition. That same settled signal drives the rail's own styling, so
4816
+ * the geometry and the submenu form always change on the same frame.
4817
+ *
4818
+ * The accordion opens and closes over a grid-rows transition rather than by appearing outright, which
4819
+ * is why the submenu stays mounted and is switched between `0fr` and `1fr` instead of living behind an
4820
+ * `@if`: height cannot animate from or to something that is not in the layout, and `auto` is not an
4821
+ * animatable value. A closed submenu is `inert` and `aria-hidden`, so leaving it mounted does not hand
4822
+ * keyboard users links to a menu they cannot see.
4823
+ *
4824
+ * Collapsing to the rail also clears every open accordion, which is what stops an expand from
4825
+ * unfolding several submenus at once and shoving the entries below them down the panel. An entry
4826
+ * holding the active route still opens on its own, since that one is answering "where am I" rather
4827
+ * than restoring a stale choice.
4644
4828
  *
4645
4829
  * Which entries are expanded resolves in precedence order: an explicit toggle by the user wins,
4646
4830
  * otherwise an entry holding the active route is open — a deep link into a child should not hide the
@@ -4671,17 +4855,24 @@ class YuwSidebarNavComponent {
4671
4855
  this.router = inject(Router);
4672
4856
  this.injector = inject(Injector);
4673
4857
  this.sidebarService = inject(HlmSidebarService);
4674
- this.activeRoutes = new Map();
4858
+ this.rail = inject(YuwSidebarRailService);
4675
4859
  this.content = input.required(...(ngDevMode ? [{ debugName: "content" }] : /* istanbul ignore next */ []));
4676
4860
  this.collapsible = input('offcanvas', ...(ngDevMode ? [{ debugName: "collapsible" }] : /* istanbul ignore next */ []));
4677
4861
  this.itemClicked = output();
4862
+ this.activeRoutes = new Map();
4678
4863
  this.chevronClass = yuwSidebarMenuChevronClass;
4679
4864
  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() });
4865
+ this.badgeClass = yuwSidebarMenuBadgeClass;
4866
+ this.groupLabelTextClass = yuwSidebarGroupLabelTextClass;
4867
+ this.caretRightBorderClasses = CARET_RIGHT_BORDER_CLASSES;
4868
+ this.isRail = computed(() => this.collapsible() === 'icon' && !this.sidebarService.isMobile() && this.rail.railSettled(), ...(ngDevMode ? [{ debugName: "isRail" }] : /* istanbul ignore next */ []));
4869
+ this.expandedIds = linkedSignal({ ...(ngDevMode ? { debugName: "expandedIds" } : /* istanbul ignore next */ {}), source: () => ({ content: this.content(), rail: this.isRail() }),
4870
+ computation: ({ content, rail }, previous) => rail || previous
4871
+ ? new Set()
4872
+ : new Set(content.groups.flatMap((group) => group.items.filter((item) => item.expanded).map((item) => item.id))) });
4683
4873
  this._groups = computed(() => {
4684
- const toggles = this.userToggles();
4874
+ const expandedIds = this.expandedIds();
4875
+ const isRail = this.isRail();
4685
4876
  return this.content().groups.map((group) => ({
4686
4877
  ...group,
4687
4878
  items: group.items.map((item) => {
@@ -4690,13 +4881,15 @@ class YuwSidebarNavComponent {
4690
4881
  activeOptions: { exact: child.exact ?? false },
4691
4882
  }));
4692
4883
  const hasChildren = children.length > 0;
4884
+ const expanded = isRail || !hasChildren ? false : expandedIds.has(item.id) || this.holdsActiveRoute(item.children);
4693
4885
  return {
4694
4886
  ...item,
4695
4887
  children,
4696
4888
  hasChildren,
4697
- tooltipText: hasChildren ? undefined : (item.tooltip ?? item.label),
4889
+ tooltipText: hasChildren ? null : (item.tooltip ?? item.label),
4698
4890
  activeOptions: { exact: item.exact ?? false },
4699
- expanded: toggles.get(item.id) ?? (this.holdsActiveRoute(item.children) || (item.expanded ?? false)),
4891
+ expanded,
4892
+ submenuClass: `${yuwSidebarSubmenuWrapperClass} ${expanded ? yuwSidebarSubmenuOpenClass : yuwSidebarSubmenuClosedClass}`,
4700
4893
  };
4701
4894
  }),
4702
4895
  }));
@@ -4723,10 +4916,17 @@ class YuwSidebarNavComponent {
4723
4916
  onParentClick(id, expanded) {
4724
4917
  if (this.isRail())
4725
4918
  return;
4726
- this.userToggles.update((toggles) => new Map(toggles).set(id, !expanded));
4919
+ this.expandedIds.update((ids) => {
4920
+ const next = new Set(ids);
4921
+ if (expanded)
4922
+ next.delete(id);
4923
+ else
4924
+ next.add(id);
4925
+ return next;
4926
+ });
4727
4927
  }
4728
4928
  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 }); }
4929
+ static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "21.2.8", type: YuwSidebarNavComponent, isStandalone: true, selector: "yuw-sidebar-nav", inputs: { content: { classPropertyName: "content", publicName: "content", isSignal: true, isRequired: true, transformFunction: null }, collapsible: { classPropertyName: "collapsible", publicName: "collapsible", isSignal: true, isRequired: false, transformFunction: null } }, outputs: { itemClicked: "itemClicked" }, host: { classAttribute: "contents" }, providers: [provideIcons({ lucideChevronRight })], ngImport: i0, template: "<ng-template #submenu let-item>\n <ul yuwSidebarMenuSub>\n @for (child of item.children; track child.id) {\n <li yuwSidebarMenuSubItem>\n @if (child.route) {\n <a\n yuwSidebarMenuSubButton\n closeMobileSidebarOnClick\n [routerLink]=\"child.route\"\n routerLinkActive\n #childLink=\"routerLinkActive\"\n [routerLinkActiveOptions]=\"child.activeOptions\"\n [isActive]=\"childLink.isActive\"\n [attr.aria-current]=\"childLink.isActive ? 'page' : null\"\n [attr.aria-disabled]=\"child.disabled ? 'true' : null\"\n [class.pointer-events-none]=\"childLink.isActive || child.disabled\"\n >\n <span>{{ child.label }}</span>\n </a>\n } @else if (child.href) {\n <a\n yuwSidebarMenuSubButton\n closeMobileSidebarOnClick\n [href]=\"child.href\"\n [attr.target]=\"child.target\"\n [attr.aria-disabled]=\"child.disabled ? 'true' : null\"\n [class.pointer-events-none]=\"child.disabled\"\n >\n <span>{{ child.label }}</span>\n </a>\n } @else {\n <button\n yuwSidebarMenuSubButton\n closeMobileSidebarOnClick\n type=\"button\"\n [disabled]=\"child.disabled ?? false\"\n (click)=\"onItemClick(child.id, $event)\"\n >\n <span>{{ child.label }}</span>\n </button>\n }\n </li>\n }\n </ul>\n</ng-template>\n\n@for (group of _groups(); track group.id) {\n <div yuwSidebarGroup>\n @if (group.label) {\n <div yuwSidebarGroupLabel>\n <span [class]=\"groupLabelTextClass\">{{ group.label }}</span>\n </div>\n }\n\n <div yuwSidebarGroupContent>\n <ul yuwSidebarMenu class=\"gap-1\">\n @for (item of group.items; track item.id) {\n <li yuwSidebarMenuItem yuwSidebarFlyoutHost>\n <ng-template yuwSidebarFlyoutPanel #panel>\n <div yuwSidebarFlyout>\n <span [class]=\"flyoutLabelClass\">{{ item.label }}</span>\n <ng-container [ngTemplateOutlet]=\"submenu\" [ngTemplateOutletContext]=\"{ $implicit: item }\" />\n </div>\n </ng-template>\n\n @if (item.route) {\n <a\n yuwSidebarMenuButton\n closeMobileSidebarOnClick\n [routerLink]=\"item.route\"\n routerLinkActive\n #link=\"routerLinkActive\"\n [routerLinkActiveOptions]=\"item.activeOptions\"\n [isActive]=\"link.isActive\"\n [tooltip]=\"item.tooltipText\"\n [attr.aria-current]=\"link.isActive ? 'page' : null\"\n [attr.aria-disabled]=\"item.disabled ? 'true' : null\"\n [attr.aria-expanded]=\"item.hasChildren ? item.expanded : null\"\n [class.pointer-events-none]=\"(link.isActive && !item.hasChildren) || item.disabled\"\n [yuwSidebarFlyoutTrigger]=\"item.hasChildren && isRail() ? panel : undefined\"\n align=\"right\"\n [sideOffset]=\"0\"\n [showDelay]=\"120\"\n [hideDelay]=\"300\"\n (click)=\"onParentClick(item.id, item.expanded)\"\n >\n @if (item.icon) {\n <ng-icon [name]=\"item.icon\" />\n }\n <span>{{ item.label }}</span>\n @if (item.hasChildren) {\n <ng-icon name=\"lucideChevronRight\" [class]=\"chevronClass\" />\n }\n </a>\n } @else if (item.href) {\n <a\n yuwSidebarMenuButton\n closeMobileSidebarOnClick\n [href]=\"item.href\"\n [attr.target]=\"item.target\"\n [tooltip]=\"item.tooltipText\"\n [attr.aria-disabled]=\"item.disabled ? 'true' : null\"\n [attr.aria-expanded]=\"item.hasChildren ? item.expanded : null\"\n [class.pointer-events-none]=\"item.disabled\"\n [yuwSidebarFlyoutTrigger]=\"item.hasChildren && isRail() ? panel : undefined\"\n align=\"right\"\n [sideOffset]=\"0\"\n [showDelay]=\"120\"\n [hideDelay]=\"300\"\n (click)=\"onParentClick(item.id, item.expanded)\"\n >\n @if (item.icon) {\n <ng-icon [name]=\"item.icon\" />\n }\n <span>{{ item.label }}</span>\n @if (item.hasChildren) {\n <ng-icon name=\"lucideChevronRight\" [class]=\"chevronClass\" />\n }\n </a>\n } @else {\n <button\n yuwSidebarMenuButton\n closeMobileSidebarOnClick\n type=\"button\"\n [tooltip]=\"item.tooltipText\"\n [disabled]=\"item.disabled ?? false\"\n [attr.aria-expanded]=\"item.hasChildren ? item.expanded : null\"\n [yuwSidebarFlyoutTrigger]=\"item.hasChildren && isRail() ? panel : undefined\"\n align=\"right\"\n [sideOffset]=\"0\"\n [showDelay]=\"120\"\n [hideDelay]=\"300\"\n (click)=\"item.hasChildren ? onParentClick(item.id, item.expanded) : onItemClick(item.id, $event)\"\n >\n @if (item.icon) {\n <ng-icon [name]=\"item.icon\" />\n }\n <span>{{ item.label }}</span>\n @if (item.hasChildren) {\n <ng-icon name=\"lucideChevronRight\" [class]=\"chevronClass\" />\n <div\n [class]=\"caretRightBorderClasses\"\n [class.opacity-100]=\"isRail()\"\n [class.opacity-0]=\"!isRail()\"\n ></div>\n }\n </button>\n }\n\n @if (item.badge) {\n <span yuwSidebarMenuBadge [class]=\"badgeClass\">{{ item.badge }}</span>\n }\n\n @if (item.hasChildren && !isRail()) {\n <div\n [class]=\"item.submenuClass\"\n [attr.inert]=\"item.expanded ? null : ''\"\n [attr.aria-hidden]=\"!item.expanded\"\n >\n <div>\n <ng-container [ngTemplateOutlet]=\"submenu\" [ngTemplateOutletContext]=\"{ $implicit: item }\" />\n </div>\n </div>\n }\n </li>\n }\n </ul>\n </div>\n </div>\n\n @if (group.separatorAfter) {\n <div yuwSidebarSeparator class=\"mx-auto w-4/5!\"></div>\n }\n}\n", dependencies: [{ kind: "component", type: NgIcon, selector: "ng-icon", inputs: ["name", "svg", "size", "strokeWidth", "color"] }, { kind: "directive", type: NgTemplateOutlet, selector: "[ngTemplateOutlet]", inputs: ["ngTemplateOutletContext", "ngTemplateOutlet", "ngTemplateOutletInjector"] }, { kind: "directive", type: RouterLink, selector: "[routerLink]", inputs: ["target", "queryParams", "fragment", "queryParamsHandling", "state", "info", "relativeTo", "preserveFragment", "skipLocationChange", "replaceUrl", "routerLink"] }, { kind: "directive", type: RouterLinkActive, selector: "[routerLinkActive]", inputs: ["routerLinkActiveOptions", "ariaCurrentWhenActive", "routerLinkActive"], outputs: ["isActiveChange"], exportAs: ["routerLinkActive"] }, { kind: "directive", type: YuwSidebarGroupDirective, selector: "[yuwSidebarGroup], yuw-sidebar-group" }, { kind: "directive", type: YuwSidebarGroupLabelDirective, selector: "div[yuwSidebarGroupLabel], button[yuwSidebarGroupLabel]" }, { kind: "directive", type: YuwSidebarGroupContentDirective, selector: "div[yuwSidebarGroupContent]" }, { kind: "directive", type: YuwSidebarMenuDirective, selector: "ul[yuwSidebarMenu]" }, { kind: "directive", type: YuwSidebarMenuItemDirective, selector: "li[yuwSidebarMenuItem]" }, { kind: "directive", type: YuwSidebarMenuButtonDirective, selector: "button[yuwSidebarMenuButton], a[yuwSidebarMenuButton]" }, { kind: "directive", type: YuwSidebarMenuBadgeDirective, selector: "[yuwSidebarMenuBadge], yuw-sidebar-menu-badge" }, { kind: "directive", type: YuwSidebarMenuSubDirective, selector: "ul[yuwSidebarMenuSub]" }, { kind: "directive", type: YuwSidebarMenuSubItemDirective, selector: "li[yuwSidebarMenuSubItem]" }, { kind: "directive", type: YuwSidebarMenuSubButtonDirective, selector: "a[yuwSidebarMenuSubButton], button[yuwSidebarMenuSubButton]" }, { kind: "directive", type: YuwSidebarSeparatorDirective, selector: "[yuwSidebarSeparator], yuw-sidebar-separator" }, { kind: "directive", type: YuwSidebarFlyoutHostDirective, selector: "[yuwSidebarFlyoutHost]" }, { kind: "directive", type: YuwSidebarFlyoutPanelDirective, selector: "ng-template[yuwSidebarFlyoutPanel]" }, { kind: "directive", type: YuwSidebarFlyoutTriggerDirective, selector: "[yuwSidebarFlyoutTrigger]", inputs: ["yuwSidebarFlyoutTrigger", "align", "sideOffset", "showDelay", "hideDelay"] }, { kind: "directive", type: YuwSidebarFlyoutDirective, selector: "[yuwSidebarFlyout]" }], changeDetection: i0.ChangeDetectionStrategy.OnPush }); }
4730
4930
  }
4731
4931
  i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.8", ngImport: i0, type: YuwSidebarNavComponent, decorators: [{
4732
4932
  type: Component,
@@ -4741,6 +4941,7 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.8", ngImpor
4741
4941
  YuwSidebarMenuDirective,
4742
4942
  YuwSidebarMenuItemDirective,
4743
4943
  YuwSidebarMenuButtonDirective,
4944
+ HlmSidebarMenuButton,
4744
4945
  YuwSidebarMenuBadgeDirective,
4745
4946
  YuwSidebarMenuSubDirective,
4746
4947
  YuwSidebarMenuSubItemDirective,
@@ -4752,7 +4953,7 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.8", ngImpor
4752
4953
  YuwSidebarFlyoutDirective,
4753
4954
  ], providers: [provideIcons({ lucideChevronRight })], host: {
4754
4955
  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" }]
4956
+ }, changeDetection: ChangeDetectionStrategy.OnPush, template: "<ng-template #submenu let-item>\n <ul yuwSidebarMenuSub>\n @for (child of item.children; track child.id) {\n <li yuwSidebarMenuSubItem>\n @if (child.route) {\n <a\n yuwSidebarMenuSubButton\n closeMobileSidebarOnClick\n [routerLink]=\"child.route\"\n routerLinkActive\n #childLink=\"routerLinkActive\"\n [routerLinkActiveOptions]=\"child.activeOptions\"\n [isActive]=\"childLink.isActive\"\n [attr.aria-current]=\"childLink.isActive ? 'page' : null\"\n [attr.aria-disabled]=\"child.disabled ? 'true' : null\"\n [class.pointer-events-none]=\"childLink.isActive || child.disabled\"\n >\n <span>{{ child.label }}</span>\n </a>\n } @else if (child.href) {\n <a\n yuwSidebarMenuSubButton\n closeMobileSidebarOnClick\n [href]=\"child.href\"\n [attr.target]=\"child.target\"\n [attr.aria-disabled]=\"child.disabled ? 'true' : null\"\n [class.pointer-events-none]=\"child.disabled\"\n >\n <span>{{ child.label }}</span>\n </a>\n } @else {\n <button\n yuwSidebarMenuSubButton\n closeMobileSidebarOnClick\n type=\"button\"\n [disabled]=\"child.disabled ?? false\"\n (click)=\"onItemClick(child.id, $event)\"\n >\n <span>{{ child.label }}</span>\n </button>\n }\n </li>\n }\n </ul>\n</ng-template>\n\n@for (group of _groups(); track group.id) {\n <div yuwSidebarGroup>\n @if (group.label) {\n <div yuwSidebarGroupLabel>\n <span [class]=\"groupLabelTextClass\">{{ group.label }}</span>\n </div>\n }\n\n <div yuwSidebarGroupContent>\n <ul yuwSidebarMenu class=\"gap-1\">\n @for (item of group.items; track item.id) {\n <li yuwSidebarMenuItem yuwSidebarFlyoutHost>\n <ng-template yuwSidebarFlyoutPanel #panel>\n <div yuwSidebarFlyout>\n <span [class]=\"flyoutLabelClass\">{{ item.label }}</span>\n <ng-container [ngTemplateOutlet]=\"submenu\" [ngTemplateOutletContext]=\"{ $implicit: item }\" />\n </div>\n </ng-template>\n\n @if (item.route) {\n <a\n yuwSidebarMenuButton\n closeMobileSidebarOnClick\n [routerLink]=\"item.route\"\n routerLinkActive\n #link=\"routerLinkActive\"\n [routerLinkActiveOptions]=\"item.activeOptions\"\n [isActive]=\"link.isActive\"\n [tooltip]=\"item.tooltipText\"\n [attr.aria-current]=\"link.isActive ? 'page' : null\"\n [attr.aria-disabled]=\"item.disabled ? 'true' : null\"\n [attr.aria-expanded]=\"item.hasChildren ? item.expanded : null\"\n [class.pointer-events-none]=\"(link.isActive && !item.hasChildren) || item.disabled\"\n [yuwSidebarFlyoutTrigger]=\"item.hasChildren && isRail() ? panel : undefined\"\n align=\"right\"\n [sideOffset]=\"0\"\n [showDelay]=\"120\"\n [hideDelay]=\"300\"\n (click)=\"onParentClick(item.id, item.expanded)\"\n >\n @if (item.icon) {\n <ng-icon [name]=\"item.icon\" />\n }\n <span>{{ item.label }}</span>\n @if (item.hasChildren) {\n <ng-icon name=\"lucideChevronRight\" [class]=\"chevronClass\" />\n }\n </a>\n } @else if (item.href) {\n <a\n yuwSidebarMenuButton\n closeMobileSidebarOnClick\n [href]=\"item.href\"\n [attr.target]=\"item.target\"\n [tooltip]=\"item.tooltipText\"\n [attr.aria-disabled]=\"item.disabled ? 'true' : null\"\n [attr.aria-expanded]=\"item.hasChildren ? item.expanded : null\"\n [class.pointer-events-none]=\"item.disabled\"\n [yuwSidebarFlyoutTrigger]=\"item.hasChildren && isRail() ? panel : undefined\"\n align=\"right\"\n [sideOffset]=\"0\"\n [showDelay]=\"120\"\n [hideDelay]=\"300\"\n (click)=\"onParentClick(item.id, item.expanded)\"\n >\n @if (item.icon) {\n <ng-icon [name]=\"item.icon\" />\n }\n <span>{{ item.label }}</span>\n @if (item.hasChildren) {\n <ng-icon name=\"lucideChevronRight\" [class]=\"chevronClass\" />\n }\n </a>\n } @else {\n <button\n yuwSidebarMenuButton\n closeMobileSidebarOnClick\n type=\"button\"\n [tooltip]=\"item.tooltipText\"\n [disabled]=\"item.disabled ?? false\"\n [attr.aria-expanded]=\"item.hasChildren ? item.expanded : null\"\n [yuwSidebarFlyoutTrigger]=\"item.hasChildren && isRail() ? panel : undefined\"\n align=\"right\"\n [sideOffset]=\"0\"\n [showDelay]=\"120\"\n [hideDelay]=\"300\"\n (click)=\"item.hasChildren ? onParentClick(item.id, item.expanded) : onItemClick(item.id, $event)\"\n >\n @if (item.icon) {\n <ng-icon [name]=\"item.icon\" />\n }\n <span>{{ item.label }}</span>\n @if (item.hasChildren) {\n <ng-icon name=\"lucideChevronRight\" [class]=\"chevronClass\" />\n <div\n [class]=\"caretRightBorderClasses\"\n [class.opacity-100]=\"isRail()\"\n [class.opacity-0]=\"!isRail()\"\n ></div>\n }\n </button>\n }\n\n @if (item.badge) {\n <span yuwSidebarMenuBadge [class]=\"badgeClass\">{{ item.badge }}</span>\n }\n\n @if (item.hasChildren && !isRail()) {\n <div\n [class]=\"item.submenuClass\"\n [attr.inert]=\"item.expanded ? null : ''\"\n [attr.aria-hidden]=\"!item.expanded\"\n >\n <div>\n <ng-container [ngTemplateOutlet]=\"submenu\" [ngTemplateOutletContext]=\"{ $implicit: item }\" />\n </div>\n </div>\n }\n </li>\n }\n </ul>\n </div>\n </div>\n\n @if (group.separatorAfter) {\n <div yuwSidebarSeparator class=\"mx-auto w-4/5!\"></div>\n }\n}\n" }]
4756
4957
  }], propDecorators: { content: [{ type: i0.Input, args: [{ isSignal: true, alias: "content", required: true }] }], collapsible: [{ type: i0.Input, args: [{ isSignal: true, alias: "collapsible", required: false }] }], itemClicked: [{ type: i0.Output, args: ["itemClicked"] }] } });
4757
4958
 
4758
4959
  /**
@@ -4782,6 +4983,13 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.8", ngImpor
4782
4983
  * Outputs:
4783
4984
  * - `itemClicked`: Emits `{id, event}` when a non-navigating entry (no `route`, no `href`) is
4784
4985
  * activated, in either `content` or `footer`.
4986
+ * - `collapsedChange`: Emits `true` when the sidebar collapses and `false` when it expands, reading
4987
+ * the mobile sheet or the desktop panel as appropriate. Fires the moment the state flips, so it is
4988
+ * the one to drive a caller's own layout, which should start moving with the panel.
4989
+ * - `railSettledChange`: The same transition, but `true` only once the collapse has finished
4990
+ * animating, and `false` immediately on expand. Use it for anything that should not restyle against
4991
+ * a panel still mid-width — swapping a logo for a mark, say. The sidebar's own rail geometry is
4992
+ * keyed off this, which is why the labels stay put until the panel is actually narrow.
4785
4993
  *
4786
4994
  * The two forms compose rather than exclude each other, unlike `<yuw-button>`'s `buttons` input
4787
4995
  * which drops projected content when set. `content`/`footer` render their own region; anything
@@ -4834,6 +5042,7 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.8", ngImpor
4834
5042
  class YuwSidebarComponent {
4835
5043
  constructor() {
4836
5044
  this.config = injectHlmSidebarConfig();
5045
+ this._rail = inject(YuwSidebarRailService);
4837
5046
  this.side = input('left', ...(ngDevMode ? [{ debugName: "side" }] : /* istanbul ignore next */ []));
4838
5047
  this.variant = input('sidebar', ...(ngDevMode ? [{ debugName: "variant" }] : /* istanbul ignore next */ []));
4839
5048
  this.collapsible = input('offcanvas', ...(ngDevMode ? [{ debugName: "collapsible" }] : /* istanbul ignore next */ []));
@@ -4842,9 +5051,13 @@ class YuwSidebarComponent {
4842
5051
  this.content = input(undefined, ...(ngDevMode ? [{ debugName: "content" }] : /* istanbul ignore next */ []));
4843
5052
  this.footer = input(undefined, ...(ngDevMode ? [{ debugName: "footer" }] : /* istanbul ignore next */ []));
4844
5053
  this.itemClicked = output();
5054
+ this._containerClass = computed(() => `${yuwSidebarContainerClass} ${this.sidebarContainerClass()}`, ...(ngDevMode ? [{ debugName: "_containerClass" }] : /* istanbul ignore next */ []));
5055
+ this._isRail = computed(() => this.collapsible() === 'icon' && this._rail.railSettled(), ...(ngDevMode ? [{ debugName: "_isRail" }] : /* istanbul ignore next */ []));
5056
+ this.collapsedChange = outputFromObservable(toObservable(this._rail.collapsed).pipe(distinctUntilChanged()));
5057
+ this.railSettledChange = outputFromObservable(toObservable(this._rail.railSettled).pipe(distinctUntilChanged()));
4845
5058
  }
4846
5059
  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 }); }
5060
+ static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "21.2.8", type: YuwSidebarComponent, isStandalone: true, selector: "yuw-sidebar", inputs: { side: { classPropertyName: "side", publicName: "side", isSignal: true, isRequired: false, transformFunction: null }, variant: { classPropertyName: "variant", publicName: "variant", isSignal: true, isRequired: false, transformFunction: null }, collapsible: { classPropertyName: "collapsible", publicName: "collapsible", isSignal: true, isRequired: false, transformFunction: null }, sidebarWidthMobile: { classPropertyName: "sidebarWidthMobile", publicName: "sidebarWidthMobile", isSignal: true, isRequired: false, transformFunction: null }, sidebarContainerClass: { classPropertyName: "sidebarContainerClass", publicName: "sidebarContainerClass", isSignal: true, isRequired: false, transformFunction: null }, content: { classPropertyName: "content", publicName: "content", isSignal: true, isRequired: false, transformFunction: null }, footer: { classPropertyName: "footer", publicName: "footer", isSignal: true, isRequired: false, transformFunction: null } }, outputs: { itemClicked: "itemClicked", collapsedChange: "collapsedChange", railSettledChange: "railSettledChange" }, host: { classAttribute: "contents" }, ngImport: i0, template: "<hlm-sidebar\n [attr.data-yuw-rail]=\"_isRail() ? 'on' : null\"\n [side]=\"side()\"\n [variant]=\"variant()\"\n [collapsible]=\"collapsible()\"\n [sidebarWidthMobile]=\"sidebarWidthMobile()\"\n [sidebarContainerClass]=\"_containerClass()\"\n>\n <ng-content select=\"[yuwSidebarHeader], yuw-sidebar-header\" />\n\n @if (content(); as nav) {\n <div yuwSidebarContent>\n <div yuwSidebarSeparator class=\"mx-auto w-4/5!\"></div>\n <yuw-sidebar-nav [content]=\"nav\" [collapsible]=\"collapsible()\" (itemClicked)=\"itemClicked.emit($event)\" />\n <ng-content select=\"[yuwSidebarContentExtra]\" />\n </div>\n }\n\n <ng-content />\n\n @if (footer(); as nav) {\n <div yuwSidebarFooter>\n <div yuwSidebarSeparator class=\"mx-auto w-4/5!\"></div>\n <yuw-sidebar-nav [content]=\"nav\" [collapsible]=\"collapsible()\" (itemClicked)=\"itemClicked.emit($event)\" />\n <ng-content select=\"[yuwSidebarFooterExtra]\" />\n </div>\n }\n</hlm-sidebar>\n", dependencies: [{ kind: "component", type: HlmSidebar, selector: "hlm-sidebar", inputs: ["sidebarWidthMobile", "side", "variant", "collapsible", "sidebarContainerClass"] }, { kind: "component", type: YuwSidebarNavComponent, selector: "yuw-sidebar-nav", inputs: ["content", "collapsible"], outputs: ["itemClicked"] }, { kind: "directive", type: YuwSidebarContentDirective, selector: "[yuwSidebarContent], yuw-sidebar-content" }, { kind: "directive", type: YuwSidebarFooterDirective, selector: "[yuwSidebarFooter], yuw-sidebar-footer" }, { kind: "directive", type: YuwSidebarSeparatorDirective, selector: "[yuwSidebarSeparator], yuw-sidebar-separator" }], changeDetection: i0.ChangeDetectionStrategy.OnPush }); }
4848
5061
  }
4849
5062
  i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.8", ngImport: i0, type: YuwSidebarComponent, decorators: [{
4850
5063
  type: Component,
@@ -4856,8 +5069,8 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.8", ngImpor
4856
5069
  YuwSidebarSeparatorDirective,
4857
5070
  ], host: {
4858
5071
  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"] }] } });
5072
+ }, changeDetection: ChangeDetectionStrategy.OnPush, template: "<hlm-sidebar\n [attr.data-yuw-rail]=\"_isRail() ? 'on' : null\"\n [side]=\"side()\"\n [variant]=\"variant()\"\n [collapsible]=\"collapsible()\"\n [sidebarWidthMobile]=\"sidebarWidthMobile()\"\n [sidebarContainerClass]=\"_containerClass()\"\n>\n <ng-content select=\"[yuwSidebarHeader], yuw-sidebar-header\" />\n\n @if (content(); as nav) {\n <div yuwSidebarContent>\n <div yuwSidebarSeparator class=\"mx-auto w-4/5!\"></div>\n <yuw-sidebar-nav [content]=\"nav\" [collapsible]=\"collapsible()\" (itemClicked)=\"itemClicked.emit($event)\" />\n <ng-content select=\"[yuwSidebarContentExtra]\" />\n </div>\n }\n\n <ng-content />\n\n @if (footer(); as nav) {\n <div yuwSidebarFooter>\n <div yuwSidebarSeparator class=\"mx-auto w-4/5!\"></div>\n <yuw-sidebar-nav [content]=\"nav\" [collapsible]=\"collapsible()\" (itemClicked)=\"itemClicked.emit($event)\" />\n <ng-content select=\"[yuwSidebarFooterExtra]\" />\n </div>\n }\n</hlm-sidebar>\n" }]
5073
+ }], propDecorators: { side: [{ type: i0.Input, args: [{ isSignal: true, alias: "side", required: false }] }], variant: [{ type: i0.Input, args: [{ isSignal: true, alias: "variant", required: false }] }], collapsible: [{ type: i0.Input, args: [{ isSignal: true, alias: "collapsible", required: false }] }], sidebarWidthMobile: [{ type: i0.Input, args: [{ isSignal: true, alias: "sidebarWidthMobile", required: false }] }], sidebarContainerClass: [{ type: i0.Input, args: [{ isSignal: true, alias: "sidebarContainerClass", required: false }] }], content: [{ type: i0.Input, args: [{ isSignal: true, alias: "content", required: false }] }], footer: [{ type: i0.Input, args: [{ isSignal: true, alias: "footer", required: false }] }], itemClicked: [{ type: i0.Output, args: ["itemClicked"] }], collapsedChange: [{ type: i0.Output, args: ["collapsedChange"] }], railSettledChange: [{ type: i0.Output, args: ["railSettledChange"] }] } });
4861
5074
 
4862
5075
  /**
4863
5076
  * Icon button that toggles the sidebar open or collapsed. Works anywhere on the page, including
@@ -4894,5 +5107,5 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.8", ngImpor
4894
5107
  * Generated bundle index. Do not edit.
4895
5108
  */
4896
5109
 
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 };
5110
+ export { DATATABLE_ALIGN_CLASS, YUW_DATATABLE_FEATURES, YUW_PASSWORD_REVEAL_STATES, YuwAccordion, YuwAccordionContentComponent, YuwAccordionImports, YuwAccordionItem, YuwAccordionTriggerComponent, YuwAlertActionDirective, YuwAlertComponent, YuwAlertDescriptionDirective, YuwAlertDialogComponent, YuwAlertDialogMediaDirective, YuwAlertDialogTriggerDirective, YuwAlertImports, YuwAlertTitleDirective, YuwAttachmentActionDirective, YuwAttachmentActionsDirective, YuwAttachmentContentDirective, YuwAttachmentDescriptionDirective, YuwAttachmentDirective, YuwAttachmentGroupDirective, YuwAttachmentMediaDirective, YuwAttachmentTitleDirective, YuwAttachmentTriggerDirective, YuwAvatarComponent, YuwBadgeComponent, YuwBreadcrumbComponent, YuwButtonComponent, YuwButtonGroupTextDirective, YuwCaptionDirective, YuwCardActionDirective, YuwCardContentDirective, YuwCardDescriptionDirective, YuwCardDirective, YuwCardFooterDirective, YuwCardHeaderDirective, YuwCardImports, YuwCardTitleDirective, YuwCheckboxComponent, YuwComboboxComponent, YuwComboboxItemDirective, YuwContextMenuCheckboxDirective, YuwContextMenuCheckboxIndicatorComponent, YuwContextMenuDirective, YuwContextMenuGroupDirective, YuwContextMenuImports, YuwContextMenuItemDirective, YuwContextMenuLabelDirective, YuwContextMenuRadioDirective, YuwContextMenuRadioIndicatorComponent, YuwContextMenuSeparatorDirective, YuwContextMenuShortcutDirective, YuwContextMenuSubDirective, YuwContextMenuSubIndicatorComponent, YuwContextMenuSubTriggerDirective, YuwContextMenuTriggerDirective, YuwDatatableComponent, YuwDatatableRowSelect, YuwDatepickerComponent, YuwDialogCloseDirective, YuwDialogComponent, YuwDialogFooterDirective, YuwDialogImports, YuwDialogTriggerDirective, YuwEmptyContentDirective, YuwEmptyDescriptionDirective, YuwEmptyDirective, YuwEmptyHeaderDirective, YuwEmptyImports, YuwEmptyMediaDirective, YuwEmptyTitleDirective, YuwInputAddonImports, YuwInputComponent, YuwInputOtpComponent, YuwItemActionsDirective, YuwItemContentDirective, YuwItemDescriptionDirective, YuwItemDirective, YuwItemFooterDirective, YuwItemGroupDirective, YuwItemHeaderDirective, YuwItemImports, YuwItemMediaDirective, YuwItemSeparatorDirective, YuwItemTitleDirective, YuwLabel, YuwLeftAddonDirective, YuwPaginationComponent, YuwPasswordInputComponent, YuwPopoverComponent, YuwPopoverTriggerDirective, YuwRadioGroupComponent, YuwRightAddonDirective, YuwSearchInputComponent, YuwSheetCloseDirective, YuwSheetComponent, YuwSheetFooterDirective, YuwSheetImports, YuwSheetTriggerDirective, YuwSidebarComponent, YuwSidebarContentDirective, YuwSidebarContentExtraDirective, YuwSidebarFlyoutDirective, YuwSidebarFlyoutHostDirective, YuwSidebarFlyoutPanelDirective, YuwSidebarFlyoutTriggerDirective, YuwSidebarFooterDirective, YuwSidebarFooterExtraDirective, YuwSidebarGroupContentDirective, YuwSidebarGroupDirective, YuwSidebarGroupLabelDirective, YuwSidebarHeaderDirective, YuwSidebarInsetDirective, YuwSidebarMenuBadgeDirective, YuwSidebarMenuButtonDirective, YuwSidebarMenuDirective, YuwSidebarMenuItemDirective, YuwSidebarMenuSubButtonDirective, YuwSidebarMenuSubDirective, YuwSidebarMenuSubItemDirective, YuwSidebarRailDirective, YuwSidebarRailService, YuwSidebarSeparatorDirective, YuwSidebarTriggerComponent, YuwSidebarWrapperDirective, YuwSkeletonDirective, YuwSpinnerComponent, YuwSwitchComponent, YuwTBodyDirective, YuwTFootDirective, YuwTHeadDirective, YuwTabPanelDirective, YuwTableContainerDirective, YuwTableDirective, YuwTableImports, YuwTabsComponent, YuwTdDirective, YuwTextareaComponent, YuwThDirective, YuwToasterComponent, YuwTooltipDirective, YuwTrDirective, YuwValueAccessorBase, buildInputOtpGroups, cn, datatableCellVariants, datatableContainerVariants, datatableHeadVariants, datatableHeaderCellVariants, datatableRowVariants, getPaginationRange, provideValueAccessor, totalInputOtpLength };
4898
5111
  //# sourceMappingURL=yukit-web.mjs.map