fold-ng 0.6.1 → 0.7.0

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.
package/CHANGELOG.md CHANGED
@@ -8,6 +8,71 @@ All notable changes to **fold-ng** are documented here. The format follows
8
8
 
9
9
  _Nothing yet._
10
10
 
11
+ ## [0.7.0] - 2026-07-29
12
+
13
+ ### Added
14
+
15
+ - **`fold-panel-host` gains two per-panel options: `modal` and `surface`.**
16
+ Passed through `FoldPanelHostService.open(component, { modal, surface })` (and
17
+ available on template-panel descriptors).
18
+ - **`modal`** (default `true`) — the existing modal barrier: page scroll frozen,
19
+ background `inert`, focus trapped, backdrop click dismisses. **`modal: false`**
20
+ makes a **non-modal** panel: the page keeps scrolling and stays interactive
21
+ behind it, focus is not trapped, and clicking outside no longer closes it
22
+ (only the header / `Escape` / `close()` do). The barrier is now gated on
23
+ _whether any open panel is modal_, so a lone non-modal panel never freezes the
24
+ page; `aria-modal` reflects the real modality.
25
+ - **`surface`** (`"glass"` default · `"solid"`) — `solid` renders an **opaque**
26
+ sheet (`--fold-color-surface-card`, no `backdrop-filter`) for content that must
27
+ stay legible over any background or a plain white-sheet design; `glass` keeps
28
+ the frosted translucent look. Both default to today's behaviour, so existing
29
+ panels are unchanged. Specs cover barrier-gating, scroll-lock, pass-through
30
+ dock, surface + `aria-modal` reflection, and focus-trap gating.
31
+
32
+ - **Panel config now cascades through three layers instead of only the call
33
+ site.** A panel's shape (`side`, `width`, `modal`, `surface`) is resolved
34
+ highest-priority-first: the per-call `open()` option → the component's own
35
+ `static readonly foldPanel: FoldPanelDefaults` → an app-wide
36
+ `FOLD_PANEL_DEFAULTS` token. So a panel declares its **intrinsic** nature once
37
+ on the class (a cart _is_ non-modal + solid → `open(CartPanel)` with no
38
+ options), an app sets its **identity** once at bootstrap
39
+ (`provideFoldPanelDefaults({ surface: "solid" })`), and the call site is left
40
+ for genuine one-offs. `data` / `providers` / `stack` / `ariaLabel` stay
41
+ per-call. Fully backward-compatible: with no token and no static, every panel
42
+ keeps today's literal defaults (`right` / `490` / modal / `glass`). New
43
+ exports: `FOLD_PANEL_DEFAULTS`, `provideFoldPanelDefaults`, and the
44
+ `FoldPanelDefaults` / `FoldPanelDefaultsProvider` / `FoldPanelSurface` types.
45
+ Specs cover each layer and their precedence.
46
+
47
+ - **Named panel widths — `width: 'sm' | 'md' | 'lg' | 'xl'`.** A token scale
48
+ (`360 · 490 · 640 · 820px`) replaces the magic pixel number at the call site;
49
+ `md` is the historical default, and a raw `number` still works for a bespoke
50
+ case. Cascades like the rest (`FoldPanelDefaults.width`). New `FoldPanelSize`
51
+ type.
52
+
53
+ - **`disableClose` — guard the casual close.** Set it (per-call, on the
54
+ component static, or app-wide) to suppress the host's _implicit_ dismiss
55
+ gestures — `Escape` and a backdrop click — for a panel with unsaved edits. The
56
+ header close button and `FoldPanelRef.close()` are unaffected, so the panel
57
+ stays closeable on purpose. Default `false`; orthogonal to `modal`. Specs cover
58
+ Escape + backdrop suppression and that an ordinary panel still dismisses.
59
+
60
+ ### Fixed
61
+
62
+ - **A vertical `fold-view-nav` / `fold-tabs` rail no longer flips to a crammed
63
+ horizontal bar on a narrow _window_ while its layout keeps it on the side.**
64
+ The shared tab-bar carried a leftover `@media (max-width: 768px)` block that
65
+ rotated `.dir-vertical` items to a row on the **viewport** width. Since the nav
66
+ redesign, orientation is owned entirely by `resolvedDirection` — an explicit
67
+ `direction`, or, inside a `fold-nav-layout`, the layout folding the rail on top
68
+ on its **own** width. The viewport query fought that: when the window dropped
69
+ below `768px` but the nav-layout's own width stayed above `foldAt` (so it kept
70
+ the rail on the side, `is-row`), the items turned horizontal _inside_ the
71
+ vertical rail instead of moving above the content. The block is removed;
72
+ orientation is now purely container-driven, honouring fold's "responsive on its
73
+ own width, never the viewport" contract. A standalone vertical nav that must
74
+ collapse belongs in a `fold-nav-layout` (the container-driven tool).
75
+
11
76
  ## [0.6.1] - 2026-07-28
12
77
 
13
78
  ### Changed
@@ -650,7 +715,8 @@ design-token stylesheet.
650
715
  `currentColor`; `prefers-reduced-motion` + `forced-colors` are respected;
651
716
  strings localise via inputs / providers (`provideFoldPanelLabels`).
652
717
 
653
- [unreleased]: https://github.com/hugoheynard/fold-ng/compare/v0.6.1...HEAD
718
+ [unreleased]: https://github.com/hugoheynard/fold-ng/compare/v0.7.0...HEAD
719
+ [0.7.0]: https://github.com/hugoheynard/fold-ng/releases/tag/v0.7.0
654
720
  [0.6.1]: https://github.com/hugoheynard/fold-ng/releases/tag/v0.6.1
655
721
  [0.6.0]: https://github.com/hugoheynard/fold-ng/releases/tag/v0.6.0
656
722
  [0.5.2]: https://github.com/hugoheynard/fold-ng/releases/tag/v0.5.2
@@ -7881,7 +7881,7 @@ class FoldViewNavComponent {
7881
7881
  }, /* @ts-ignore */
7882
7882
  ...(ngDevMode ? [{ debugName: "resolvedDirection" }] : /* istanbul ignore next */ []));
7883
7883
  static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "22.0.8", ngImport: i0, type: FoldViewNavComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
7884
- static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "22.0.8", type: FoldViewNavComponent, isStandalone: true, selector: "fold-view-nav", inputs: { items: { classPropertyName: "items", publicName: "items", isSignal: true, isRequired: true, transformFunction: null }, activeKey: { classPropertyName: "activeKey", publicName: "activeKey", isSignal: true, isRequired: false, transformFunction: null }, activeStyle: { classPropertyName: "activeStyle", publicName: "activeStyle", isSignal: true, isRequired: false, transformFunction: null }, direction: { classPropertyName: "direction", publicName: "direction", isSignal: true, isRequired: false, transformFunction: null }, size: { classPropertyName: "size", publicName: "size", isSignal: true, isRequired: false, transformFunction: null }, collapsed: { classPropertyName: "collapsed", publicName: "collapsed", isSignal: true, isRequired: false, transformFunction: null }, background: { classPropertyName: "background", publicName: "background", isSignal: true, isRequired: false, transformFunction: null } }, outputs: { activeKey: "activeKeyChange" }, ngImport: i0, template: "<nav\n class=\"tab-bar\"\n [class.style-underline]=\"activeStyle() === 'underline'\"\n [class.style-fill]=\"activeStyle() === 'fill'\"\n [class.dir-vertical]=\"resolvedDirection() === 'vertical'\"\n [class.size-comfortable]=\"size() === 'comfortable'\"\n [class.is-collapsed]=\"collapsed()\"\n [class.bg-surface]=\"background() === 'surface'\"\n>\n @for (item of items(); track item.key) {\n @if (item.disabled) {\n <button\n type=\"button\"\n class=\"tab-bar-item is-disabled\"\n disabled\n aria-disabled=\"true\"\n >\n <ng-container\n [ngTemplateOutlet]=\"body\"\n [ngTemplateOutletContext]=\"{ $implicit: item, active: false }\"\n />\n </button>\n } @else if (item.link !== undefined) {\n <a\n class=\"tab-bar-item\"\n [routerLink]=\"item.link\"\n routerLinkActive=\"is-active\"\n #rla=\"routerLinkActive\"\n [attr.aria-current]=\"rla.isActive ? 'page' : null\"\n >\n <ng-container\n [ngTemplateOutlet]=\"body\"\n [ngTemplateOutletContext]=\"{ $implicit: item, active: rla.isActive }\"\n />\n </a>\n } @else if (item.href !== undefined) {\n <a\n class=\"tab-bar-item\"\n [href]=\"item.href\"\n [class.is-active]=\"activeKey() === item.key\"\n [attr.aria-current]=\"activeKey() === item.key ? 'page' : null\"\n >\n <ng-container\n [ngTemplateOutlet]=\"body\"\n [ngTemplateOutletContext]=\"{\n $implicit: item,\n active: activeKey() === item.key,\n }\"\n />\n </a>\n } @else {\n <button\n type=\"button\"\n class=\"tab-bar-item\"\n [class.is-active]=\"activeKey() === item.key\"\n [attr.aria-current]=\"activeKey() === item.key ? 'page' : null\"\n (click)=\"activeKey.set(item.key)\"\n >\n <ng-container\n [ngTemplateOutlet]=\"body\"\n [ngTemplateOutletContext]=\"{\n $implicit: item,\n active: activeKey() === item.key,\n }\"\n />\n </button>\n }\n }\n</nav>\n\n<!-- One item's inner content, shared by the link / button branches. -->\n<ng-template #body let-item let-active=\"active\">\n @if (item.icon; as ic) {\n <fold-icon class=\"tab-bar-icon\" [name]=\"ic\" size=\"sm\" />\n } @else if (collapsed()) {\n <!-- Collapsed needs a fixed glyph; an icon-less item falls back to its\n initial so the rail stays icon-width and the label still tooltips. -->\n <span class=\"tab-bar-icon tab-bar-initial\" aria-hidden=\"true\">{{\n item.label.charAt(0)\n }}</span>\n }\n <span class=\"tab-bar-label\">{{ item.label }}</span>\n @if (item.badge !== undefined && item.badge !== null) {\n <fold-badge\n class=\"tab-bar-badge\"\n [content]=\"item.badge + ''\"\n [variant]=\"active ? 'accent' : 'neutral'\"\n />\n }\n</ng-template>\n", styles: ["@charset \"UTF-8\";:host{display:flex;width:100%;max-width:100%;overflow:hidden}.tab-bar{flex:1;display:flex;max-width:100%;gap:2px;-webkit-user-select:none;user-select:none}.bg-surface{background:var(--fold-color-bg-rail-tertiary);padding:var(--fold-space-xs) var(--fold-space-sm) 0}.bg-surface.dir-vertical{padding:var(--fold-space-md) var(--fold-space-sm)}.tab-bar-item{flex:1;display:flex;align-items:center;justify-content:center;gap:var(--fold-space-sm);padding:var(--fold-space-sm) var(--fold-space-sm);background:none;border:none;color:var(--fold-color-text-muted);font-family:inherit;font-size:10px;font-weight:600;cursor:pointer;text-align:center;text-decoration:none;transition:color .1s ease,background .1s ease,border-color .1s ease;white-space:nowrap}.tab-bar-item:hover{color:var(--fold-color-text-secondary)}.tab-bar-item.is-disabled{opacity:.5;cursor:default;pointer-events:none}.size-comfortable .tab-bar-item{flex:0 1 auto;gap:var(--fold-space-sm);padding:var(--fold-space-md) var(--fold-space-lg);font-size:var(--fold-text-sm)}.dir-vertical.size-comfortable .tab-bar-item{padding:var(--fold-space-md) var(--fold-space-md);font-size:var(--fold-text-md)}.style-underline{border-bottom:1px solid var(--fold-color-border)}.style-underline .tab-bar-item{border-bottom:2px solid transparent;margin-bottom:-1px}.style-underline .tab-bar-item.is-active{color:var(--fold-color-text);border-bottom-color:var(--fold-color-primary)}.style-fill .tab-bar-item{border-radius:var(--fold-radius-sm);border:1px solid transparent}.style-fill .tab-bar-item.is-active{background:var(--fold-color-primary-surface);color:var(--fold-color-primary-text);font-weight:600}.style-fill .tab-bar-item:hover:not(.is-active){background:var(--fold-color-surface-hover);color:var(--fold-color-text)}.dir-vertical{flex-direction:column}.dir-vertical .tab-bar-item{flex:none;justify-content:flex-start;text-align:left;padding:var(--fold-space-sm) var(--fold-space-md);gap:var(--fold-space-sm);border-radius:var(--fold-radius-sm);font-size:var(--fold-text-sm);font-weight:500}.dir-vertical.style-underline{border-bottom:none;border-right:1px solid var(--fold-color-border)}.dir-vertical.style-underline .tab-bar-item{border-bottom:none;border-left:2px solid transparent;margin-bottom:0;margin-right:-1px}.dir-vertical.style-underline .tab-bar-item.is-active{border-left-color:var(--fold-color-primary)}.dir-vertical.style-fill .tab-bar-item.is-active{background:var(--fold-color-primary-surface);color:var(--fold-color-primary-text);font-weight:600}.is-collapsed .tab-bar-item{position:relative;flex:0 0 auto;gap:0}.is-collapsed .tab-bar-item:not(.is-active) .tab-bar-badge{display:none}.is-collapsed .tab-bar-item.is-active{flex:1 1 auto;min-width:0;gap:var(--fold-space-sm)}.is-collapsed .tab-bar-item.is-active .tab-bar-label{overflow:hidden;text-overflow:ellipsis}.dir-vertical.is-collapsed .tab-bar-item .tab-bar-icon~.tab-bar-label,.is-collapsed:not(.dir-vertical) .tab-bar-item:not(.is-active) .tab-bar-icon~.tab-bar-label{position:absolute;padding:var(--fold-space-xs) var(--fold-space-sm);border-radius:var(--fold-radius-sm);background:var(--fold-color-glass);border:1px solid var(--fold-color-glass-border);color:var(--fold-color-text);font-size:var(--fold-text-xs);font-weight:500;white-space:nowrap;opacity:0;pointer-events:none;box-shadow:var(--fold-shadow-md);transition:opacity var(--fold-motion-fast);z-index:100}.dir-vertical.is-collapsed .tab-bar-item .tab-bar-icon~.tab-bar-label{left:calc(100% + 8px);top:50%;transform:translateY(-50%)}.is-collapsed:not(.dir-vertical) .tab-bar-item:not(.is-active) .tab-bar-icon~.tab-bar-label{top:calc(100% + 6px);left:50%;transform:translate(-50%)}.dir-vertical.is-collapsed .tab-bar-item:hover .tab-bar-icon~.tab-bar-label,.dir-vertical.is-collapsed .tab-bar-item:focus-visible .tab-bar-icon~.tab-bar-label,.is-collapsed:not(.dir-vertical) .tab-bar-item:not(.is-active):hover .tab-bar-icon~.tab-bar-label,.is-collapsed:not(.dir-vertical) .tab-bar-item:not(.is-active):focus-visible .tab-bar-icon~.tab-bar-label{opacity:1}.dir-vertical.is-collapsed{align-items:center}.dir-vertical.is-collapsed .tab-bar-item,.dir-vertical.is-collapsed .tab-bar-item.is-active{justify-content:center;gap:0}.dir-vertical.is-collapsed .tab-bar-item .tab-bar-badge{display:block;position:absolute;top:-2px;right:-2px;transform:scale(.85);transform-origin:top right;pointer-events:none}:host:has(.is-collapsed){overflow:visible}@media(max-width:768px){.dir-vertical{flex-direction:row;align-items:center}.dir-vertical .tab-bar-item{flex:0 0 auto;justify-content:center;text-align:center;padding:var(--fold-space-sm);gap:0;font-size:var(--fold-text-xs);font-weight:600}.dir-vertical .tab-bar-item .tab-bar-label{display:none}.dir-vertical .tab-bar-item.is-active{flex:1 1 auto;min-width:0;gap:var(--fold-space-sm);padding:var(--fold-space-sm) var(--fold-space-md)}.dir-vertical .tab-bar-item.is-active .tab-bar-label{display:inline;overflow:hidden;text-overflow:ellipsis}.dir-vertical .tab-bar-badge{display:none}.dir-vertical.style-underline{border-right:none;border-bottom:1px solid var(--fold-color-border)}.dir-vertical.style-underline .tab-bar-item{border-left:none;border-bottom:2px solid transparent;margin-right:0;margin-bottom:-1px}.dir-vertical.style-underline .tab-bar-item.is-active{border-bottom-color:var(--fold-color-primary)}.dir-vertical.style-fill{border-right:none}}.tab-bar-icon{flex-shrink:0}.tab-bar-initial{display:grid;place-items:center;width:18px;height:18px;border-radius:var(--fold-radius-sm);font-size:11px;font-weight:700;line-height:1;text-transform:uppercase}.tab-bar-badge{flex-shrink:0;font-variant-numeric:tabular-nums}.tab-bar-item:focus-visible{outline:2px solid var(--fold-color-primary);outline-offset:-2px;border-radius:var(--fold-radius-sm)}\n"], dependencies: [{ kind: "directive", type: NgTemplateOutlet, selector: "[ngTemplateOutlet]", inputs: ["ngTemplateOutletContext", "ngTemplateOutlet", "ngTemplateOutletInjector"] }, { kind: "component", type: FoldIconComponent, selector: "fold-icon", inputs: ["name", "size", "tone", "title"] }, { kind: "component", type: FoldBadgeComponent, selector: "fold-badge", inputs: ["content", "radius", "variant"] }, { kind: "directive", type: RouterLink, selector: "[routerLink]", inputs: ["target", "queryParams", "fragment", "queryParamsHandling", "state", "info", "relativeTo", "preserveFragment", "skipLocationChange", "replaceUrl", "browserUrl", "routerLink"] }, { kind: "directive", type: RouterLinkActive, selector: "[routerLinkActive]", inputs: ["routerLinkActiveOptions", "ariaCurrentWhenActive", "routerLinkActive"], outputs: ["isActiveChange"], exportAs: ["routerLinkActive"] }] });
7884
+ static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "22.0.8", type: FoldViewNavComponent, isStandalone: true, selector: "fold-view-nav", inputs: { items: { classPropertyName: "items", publicName: "items", isSignal: true, isRequired: true, transformFunction: null }, activeKey: { classPropertyName: "activeKey", publicName: "activeKey", isSignal: true, isRequired: false, transformFunction: null }, activeStyle: { classPropertyName: "activeStyle", publicName: "activeStyle", isSignal: true, isRequired: false, transformFunction: null }, direction: { classPropertyName: "direction", publicName: "direction", isSignal: true, isRequired: false, transformFunction: null }, size: { classPropertyName: "size", publicName: "size", isSignal: true, isRequired: false, transformFunction: null }, collapsed: { classPropertyName: "collapsed", publicName: "collapsed", isSignal: true, isRequired: false, transformFunction: null }, background: { classPropertyName: "background", publicName: "background", isSignal: true, isRequired: false, transformFunction: null } }, outputs: { activeKey: "activeKeyChange" }, ngImport: i0, template: "<nav\n class=\"tab-bar\"\n [class.style-underline]=\"activeStyle() === 'underline'\"\n [class.style-fill]=\"activeStyle() === 'fill'\"\n [class.dir-vertical]=\"resolvedDirection() === 'vertical'\"\n [class.size-comfortable]=\"size() === 'comfortable'\"\n [class.is-collapsed]=\"collapsed()\"\n [class.bg-surface]=\"background() === 'surface'\"\n>\n @for (item of items(); track item.key) {\n @if (item.disabled) {\n <button\n type=\"button\"\n class=\"tab-bar-item is-disabled\"\n disabled\n aria-disabled=\"true\"\n >\n <ng-container\n [ngTemplateOutlet]=\"body\"\n [ngTemplateOutletContext]=\"{ $implicit: item, active: false }\"\n />\n </button>\n } @else if (item.link !== undefined) {\n <a\n class=\"tab-bar-item\"\n [routerLink]=\"item.link\"\n routerLinkActive=\"is-active\"\n #rla=\"routerLinkActive\"\n [attr.aria-current]=\"rla.isActive ? 'page' : null\"\n >\n <ng-container\n [ngTemplateOutlet]=\"body\"\n [ngTemplateOutletContext]=\"{ $implicit: item, active: rla.isActive }\"\n />\n </a>\n } @else if (item.href !== undefined) {\n <a\n class=\"tab-bar-item\"\n [href]=\"item.href\"\n [class.is-active]=\"activeKey() === item.key\"\n [attr.aria-current]=\"activeKey() === item.key ? 'page' : null\"\n >\n <ng-container\n [ngTemplateOutlet]=\"body\"\n [ngTemplateOutletContext]=\"{\n $implicit: item,\n active: activeKey() === item.key,\n }\"\n />\n </a>\n } @else {\n <button\n type=\"button\"\n class=\"tab-bar-item\"\n [class.is-active]=\"activeKey() === item.key\"\n [attr.aria-current]=\"activeKey() === item.key ? 'page' : null\"\n (click)=\"activeKey.set(item.key)\"\n >\n <ng-container\n [ngTemplateOutlet]=\"body\"\n [ngTemplateOutletContext]=\"{\n $implicit: item,\n active: activeKey() === item.key,\n }\"\n />\n </button>\n }\n }\n</nav>\n\n<!-- One item's inner content, shared by the link / button branches. -->\n<ng-template #body let-item let-active=\"active\">\n @if (item.icon; as ic) {\n <fold-icon class=\"tab-bar-icon\" [name]=\"ic\" size=\"sm\" />\n } @else if (collapsed()) {\n <!-- Collapsed needs a fixed glyph; an icon-less item falls back to its\n initial so the rail stays icon-width and the label still tooltips. -->\n <span class=\"tab-bar-icon tab-bar-initial\" aria-hidden=\"true\">{{\n item.label.charAt(0)\n }}</span>\n }\n <span class=\"tab-bar-label\">{{ item.label }}</span>\n @if (item.badge !== undefined && item.badge !== null) {\n <fold-badge\n class=\"tab-bar-badge\"\n [content]=\"item.badge + ''\"\n [variant]=\"active ? 'accent' : 'neutral'\"\n />\n }\n</ng-template>\n", styles: ["@charset \"UTF-8\";:host{display:flex;width:100%;max-width:100%;overflow:hidden}.tab-bar{flex:1;display:flex;max-width:100%;gap:2px;-webkit-user-select:none;user-select:none}.bg-surface{background:var(--fold-color-bg-rail-tertiary);padding:var(--fold-space-xs) var(--fold-space-sm) 0}.bg-surface.dir-vertical{padding:var(--fold-space-md) var(--fold-space-sm)}.tab-bar-item{flex:1;display:flex;align-items:center;justify-content:center;gap:var(--fold-space-sm);padding:var(--fold-space-sm) var(--fold-space-sm);background:none;border:none;color:var(--fold-color-text-muted);font-family:inherit;font-size:10px;font-weight:600;cursor:pointer;text-align:center;text-decoration:none;transition:color .1s ease,background .1s ease,border-color .1s ease;white-space:nowrap}.tab-bar-item:hover{color:var(--fold-color-text-secondary)}.tab-bar-item.is-disabled{opacity:.5;cursor:default;pointer-events:none}.size-comfortable .tab-bar-item{flex:0 1 auto;gap:var(--fold-space-sm);padding:var(--fold-space-md) var(--fold-space-lg);font-size:var(--fold-text-sm)}.dir-vertical.size-comfortable .tab-bar-item{padding:var(--fold-space-md) var(--fold-space-md);font-size:var(--fold-text-md)}.style-underline{border-bottom:1px solid var(--fold-color-border)}.style-underline .tab-bar-item{border-bottom:2px solid transparent;margin-bottom:-1px}.style-underline .tab-bar-item.is-active{color:var(--fold-color-text);border-bottom-color:var(--fold-color-primary)}.style-fill .tab-bar-item{border-radius:var(--fold-radius-sm);border:1px solid transparent}.style-fill .tab-bar-item.is-active{background:var(--fold-color-primary-surface);color:var(--fold-color-primary-text);font-weight:600}.style-fill .tab-bar-item:hover:not(.is-active){background:var(--fold-color-surface-hover);color:var(--fold-color-text)}.dir-vertical{flex-direction:column}.dir-vertical .tab-bar-item{flex:none;justify-content:flex-start;text-align:left;padding:var(--fold-space-sm) var(--fold-space-md);gap:var(--fold-space-sm);border-radius:var(--fold-radius-sm);font-size:var(--fold-text-sm);font-weight:500}.dir-vertical.style-underline{border-bottom:none;border-right:1px solid var(--fold-color-border)}.dir-vertical.style-underline .tab-bar-item{border-bottom:none;border-left:2px solid transparent;margin-bottom:0;margin-right:-1px}.dir-vertical.style-underline .tab-bar-item.is-active{border-left-color:var(--fold-color-primary)}.dir-vertical.style-fill .tab-bar-item.is-active{background:var(--fold-color-primary-surface);color:var(--fold-color-primary-text);font-weight:600}.is-collapsed .tab-bar-item{position:relative;flex:0 0 auto;gap:0}.is-collapsed .tab-bar-item:not(.is-active) .tab-bar-badge{display:none}.is-collapsed .tab-bar-item.is-active{flex:1 1 auto;min-width:0;gap:var(--fold-space-sm)}.is-collapsed .tab-bar-item.is-active .tab-bar-label{overflow:hidden;text-overflow:ellipsis}.dir-vertical.is-collapsed .tab-bar-item .tab-bar-icon~.tab-bar-label,.is-collapsed:not(.dir-vertical) .tab-bar-item:not(.is-active) .tab-bar-icon~.tab-bar-label{position:absolute;padding:var(--fold-space-xs) var(--fold-space-sm);border-radius:var(--fold-radius-sm);background:var(--fold-color-glass);border:1px solid var(--fold-color-glass-border);color:var(--fold-color-text);font-size:var(--fold-text-xs);font-weight:500;white-space:nowrap;opacity:0;pointer-events:none;box-shadow:var(--fold-shadow-md);transition:opacity var(--fold-motion-fast);z-index:100}.dir-vertical.is-collapsed .tab-bar-item .tab-bar-icon~.tab-bar-label{left:calc(100% + 8px);top:50%;transform:translateY(-50%)}.is-collapsed:not(.dir-vertical) .tab-bar-item:not(.is-active) .tab-bar-icon~.tab-bar-label{top:calc(100% + 6px);left:50%;transform:translate(-50%)}.dir-vertical.is-collapsed .tab-bar-item:hover .tab-bar-icon~.tab-bar-label,.dir-vertical.is-collapsed .tab-bar-item:focus-visible .tab-bar-icon~.tab-bar-label,.is-collapsed:not(.dir-vertical) .tab-bar-item:not(.is-active):hover .tab-bar-icon~.tab-bar-label,.is-collapsed:not(.dir-vertical) .tab-bar-item:not(.is-active):focus-visible .tab-bar-icon~.tab-bar-label{opacity:1}.dir-vertical.is-collapsed{align-items:center}.dir-vertical.is-collapsed .tab-bar-item,.dir-vertical.is-collapsed .tab-bar-item.is-active{justify-content:center;gap:0}.dir-vertical.is-collapsed .tab-bar-item .tab-bar-badge{display:block;position:absolute;top:-2px;right:-2px;transform:scale(.85);transform-origin:top right;pointer-events:none}:host:has(.is-collapsed){overflow:visible}.tab-bar-icon{flex-shrink:0}.tab-bar-initial{display:grid;place-items:center;width:18px;height:18px;border-radius:var(--fold-radius-sm);font-size:11px;font-weight:700;line-height:1;text-transform:uppercase}.tab-bar-badge{flex-shrink:0;font-variant-numeric:tabular-nums}.tab-bar-item:focus-visible{outline:2px solid var(--fold-color-primary);outline-offset:-2px;border-radius:var(--fold-radius-sm)}\n"], dependencies: [{ kind: "directive", type: NgTemplateOutlet, selector: "[ngTemplateOutlet]", inputs: ["ngTemplateOutletContext", "ngTemplateOutlet", "ngTemplateOutletInjector"] }, { kind: "component", type: FoldIconComponent, selector: "fold-icon", inputs: ["name", "size", "tone", "title"] }, { kind: "component", type: FoldBadgeComponent, selector: "fold-badge", inputs: ["content", "radius", "variant"] }, { kind: "directive", type: RouterLink, selector: "[routerLink]", inputs: ["target", "queryParams", "fragment", "queryParamsHandling", "state", "info", "relativeTo", "preserveFragment", "skipLocationChange", "replaceUrl", "browserUrl", "routerLink"] }, { kind: "directive", type: RouterLinkActive, selector: "[routerLinkActive]", inputs: ["routerLinkActiveOptions", "ariaCurrentWhenActive", "routerLinkActive"], outputs: ["isActiveChange"], exportAs: ["routerLinkActive"] }] });
7885
7885
  }
7886
7886
  i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.0.8", ngImport: i0, type: FoldViewNavComponent, decorators: [{
7887
7887
  type: Component,
@@ -7891,7 +7891,7 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.0.8", ngImpor
7891
7891
  FoldBadgeComponent,
7892
7892
  RouterLink,
7893
7893
  RouterLinkActive,
7894
- ], template: "<nav\n class=\"tab-bar\"\n [class.style-underline]=\"activeStyle() === 'underline'\"\n [class.style-fill]=\"activeStyle() === 'fill'\"\n [class.dir-vertical]=\"resolvedDirection() === 'vertical'\"\n [class.size-comfortable]=\"size() === 'comfortable'\"\n [class.is-collapsed]=\"collapsed()\"\n [class.bg-surface]=\"background() === 'surface'\"\n>\n @for (item of items(); track item.key) {\n @if (item.disabled) {\n <button\n type=\"button\"\n class=\"tab-bar-item is-disabled\"\n disabled\n aria-disabled=\"true\"\n >\n <ng-container\n [ngTemplateOutlet]=\"body\"\n [ngTemplateOutletContext]=\"{ $implicit: item, active: false }\"\n />\n </button>\n } @else if (item.link !== undefined) {\n <a\n class=\"tab-bar-item\"\n [routerLink]=\"item.link\"\n routerLinkActive=\"is-active\"\n #rla=\"routerLinkActive\"\n [attr.aria-current]=\"rla.isActive ? 'page' : null\"\n >\n <ng-container\n [ngTemplateOutlet]=\"body\"\n [ngTemplateOutletContext]=\"{ $implicit: item, active: rla.isActive }\"\n />\n </a>\n } @else if (item.href !== undefined) {\n <a\n class=\"tab-bar-item\"\n [href]=\"item.href\"\n [class.is-active]=\"activeKey() === item.key\"\n [attr.aria-current]=\"activeKey() === item.key ? 'page' : null\"\n >\n <ng-container\n [ngTemplateOutlet]=\"body\"\n [ngTemplateOutletContext]=\"{\n $implicit: item,\n active: activeKey() === item.key,\n }\"\n />\n </a>\n } @else {\n <button\n type=\"button\"\n class=\"tab-bar-item\"\n [class.is-active]=\"activeKey() === item.key\"\n [attr.aria-current]=\"activeKey() === item.key ? 'page' : null\"\n (click)=\"activeKey.set(item.key)\"\n >\n <ng-container\n [ngTemplateOutlet]=\"body\"\n [ngTemplateOutletContext]=\"{\n $implicit: item,\n active: activeKey() === item.key,\n }\"\n />\n </button>\n }\n }\n</nav>\n\n<!-- One item's inner content, shared by the link / button branches. -->\n<ng-template #body let-item let-active=\"active\">\n @if (item.icon; as ic) {\n <fold-icon class=\"tab-bar-icon\" [name]=\"ic\" size=\"sm\" />\n } @else if (collapsed()) {\n <!-- Collapsed needs a fixed glyph; an icon-less item falls back to its\n initial so the rail stays icon-width and the label still tooltips. -->\n <span class=\"tab-bar-icon tab-bar-initial\" aria-hidden=\"true\">{{\n item.label.charAt(0)\n }}</span>\n }\n <span class=\"tab-bar-label\">{{ item.label }}</span>\n @if (item.badge !== undefined && item.badge !== null) {\n <fold-badge\n class=\"tab-bar-badge\"\n [content]=\"item.badge + ''\"\n [variant]=\"active ? 'accent' : 'neutral'\"\n />\n }\n</ng-template>\n", styles: ["@charset \"UTF-8\";:host{display:flex;width:100%;max-width:100%;overflow:hidden}.tab-bar{flex:1;display:flex;max-width:100%;gap:2px;-webkit-user-select:none;user-select:none}.bg-surface{background:var(--fold-color-bg-rail-tertiary);padding:var(--fold-space-xs) var(--fold-space-sm) 0}.bg-surface.dir-vertical{padding:var(--fold-space-md) var(--fold-space-sm)}.tab-bar-item{flex:1;display:flex;align-items:center;justify-content:center;gap:var(--fold-space-sm);padding:var(--fold-space-sm) var(--fold-space-sm);background:none;border:none;color:var(--fold-color-text-muted);font-family:inherit;font-size:10px;font-weight:600;cursor:pointer;text-align:center;text-decoration:none;transition:color .1s ease,background .1s ease,border-color .1s ease;white-space:nowrap}.tab-bar-item:hover{color:var(--fold-color-text-secondary)}.tab-bar-item.is-disabled{opacity:.5;cursor:default;pointer-events:none}.size-comfortable .tab-bar-item{flex:0 1 auto;gap:var(--fold-space-sm);padding:var(--fold-space-md) var(--fold-space-lg);font-size:var(--fold-text-sm)}.dir-vertical.size-comfortable .tab-bar-item{padding:var(--fold-space-md) var(--fold-space-md);font-size:var(--fold-text-md)}.style-underline{border-bottom:1px solid var(--fold-color-border)}.style-underline .tab-bar-item{border-bottom:2px solid transparent;margin-bottom:-1px}.style-underline .tab-bar-item.is-active{color:var(--fold-color-text);border-bottom-color:var(--fold-color-primary)}.style-fill .tab-bar-item{border-radius:var(--fold-radius-sm);border:1px solid transparent}.style-fill .tab-bar-item.is-active{background:var(--fold-color-primary-surface);color:var(--fold-color-primary-text);font-weight:600}.style-fill .tab-bar-item:hover:not(.is-active){background:var(--fold-color-surface-hover);color:var(--fold-color-text)}.dir-vertical{flex-direction:column}.dir-vertical .tab-bar-item{flex:none;justify-content:flex-start;text-align:left;padding:var(--fold-space-sm) var(--fold-space-md);gap:var(--fold-space-sm);border-radius:var(--fold-radius-sm);font-size:var(--fold-text-sm);font-weight:500}.dir-vertical.style-underline{border-bottom:none;border-right:1px solid var(--fold-color-border)}.dir-vertical.style-underline .tab-bar-item{border-bottom:none;border-left:2px solid transparent;margin-bottom:0;margin-right:-1px}.dir-vertical.style-underline .tab-bar-item.is-active{border-left-color:var(--fold-color-primary)}.dir-vertical.style-fill .tab-bar-item.is-active{background:var(--fold-color-primary-surface);color:var(--fold-color-primary-text);font-weight:600}.is-collapsed .tab-bar-item{position:relative;flex:0 0 auto;gap:0}.is-collapsed .tab-bar-item:not(.is-active) .tab-bar-badge{display:none}.is-collapsed .tab-bar-item.is-active{flex:1 1 auto;min-width:0;gap:var(--fold-space-sm)}.is-collapsed .tab-bar-item.is-active .tab-bar-label{overflow:hidden;text-overflow:ellipsis}.dir-vertical.is-collapsed .tab-bar-item .tab-bar-icon~.tab-bar-label,.is-collapsed:not(.dir-vertical) .tab-bar-item:not(.is-active) .tab-bar-icon~.tab-bar-label{position:absolute;padding:var(--fold-space-xs) var(--fold-space-sm);border-radius:var(--fold-radius-sm);background:var(--fold-color-glass);border:1px solid var(--fold-color-glass-border);color:var(--fold-color-text);font-size:var(--fold-text-xs);font-weight:500;white-space:nowrap;opacity:0;pointer-events:none;box-shadow:var(--fold-shadow-md);transition:opacity var(--fold-motion-fast);z-index:100}.dir-vertical.is-collapsed .tab-bar-item .tab-bar-icon~.tab-bar-label{left:calc(100% + 8px);top:50%;transform:translateY(-50%)}.is-collapsed:not(.dir-vertical) .tab-bar-item:not(.is-active) .tab-bar-icon~.tab-bar-label{top:calc(100% + 6px);left:50%;transform:translate(-50%)}.dir-vertical.is-collapsed .tab-bar-item:hover .tab-bar-icon~.tab-bar-label,.dir-vertical.is-collapsed .tab-bar-item:focus-visible .tab-bar-icon~.tab-bar-label,.is-collapsed:not(.dir-vertical) .tab-bar-item:not(.is-active):hover .tab-bar-icon~.tab-bar-label,.is-collapsed:not(.dir-vertical) .tab-bar-item:not(.is-active):focus-visible .tab-bar-icon~.tab-bar-label{opacity:1}.dir-vertical.is-collapsed{align-items:center}.dir-vertical.is-collapsed .tab-bar-item,.dir-vertical.is-collapsed .tab-bar-item.is-active{justify-content:center;gap:0}.dir-vertical.is-collapsed .tab-bar-item .tab-bar-badge{display:block;position:absolute;top:-2px;right:-2px;transform:scale(.85);transform-origin:top right;pointer-events:none}:host:has(.is-collapsed){overflow:visible}@media(max-width:768px){.dir-vertical{flex-direction:row;align-items:center}.dir-vertical .tab-bar-item{flex:0 0 auto;justify-content:center;text-align:center;padding:var(--fold-space-sm);gap:0;font-size:var(--fold-text-xs);font-weight:600}.dir-vertical .tab-bar-item .tab-bar-label{display:none}.dir-vertical .tab-bar-item.is-active{flex:1 1 auto;min-width:0;gap:var(--fold-space-sm);padding:var(--fold-space-sm) var(--fold-space-md)}.dir-vertical .tab-bar-item.is-active .tab-bar-label{display:inline;overflow:hidden;text-overflow:ellipsis}.dir-vertical .tab-bar-badge{display:none}.dir-vertical.style-underline{border-right:none;border-bottom:1px solid var(--fold-color-border)}.dir-vertical.style-underline .tab-bar-item{border-left:none;border-bottom:2px solid transparent;margin-right:0;margin-bottom:-1px}.dir-vertical.style-underline .tab-bar-item.is-active{border-bottom-color:var(--fold-color-primary)}.dir-vertical.style-fill{border-right:none}}.tab-bar-icon{flex-shrink:0}.tab-bar-initial{display:grid;place-items:center;width:18px;height:18px;border-radius:var(--fold-radius-sm);font-size:11px;font-weight:700;line-height:1;text-transform:uppercase}.tab-bar-badge{flex-shrink:0;font-variant-numeric:tabular-nums}.tab-bar-item:focus-visible{outline:2px solid var(--fold-color-primary);outline-offset:-2px;border-radius:var(--fold-radius-sm)}\n"] }]
7894
+ ], template: "<nav\n class=\"tab-bar\"\n [class.style-underline]=\"activeStyle() === 'underline'\"\n [class.style-fill]=\"activeStyle() === 'fill'\"\n [class.dir-vertical]=\"resolvedDirection() === 'vertical'\"\n [class.size-comfortable]=\"size() === 'comfortable'\"\n [class.is-collapsed]=\"collapsed()\"\n [class.bg-surface]=\"background() === 'surface'\"\n>\n @for (item of items(); track item.key) {\n @if (item.disabled) {\n <button\n type=\"button\"\n class=\"tab-bar-item is-disabled\"\n disabled\n aria-disabled=\"true\"\n >\n <ng-container\n [ngTemplateOutlet]=\"body\"\n [ngTemplateOutletContext]=\"{ $implicit: item, active: false }\"\n />\n </button>\n } @else if (item.link !== undefined) {\n <a\n class=\"tab-bar-item\"\n [routerLink]=\"item.link\"\n routerLinkActive=\"is-active\"\n #rla=\"routerLinkActive\"\n [attr.aria-current]=\"rla.isActive ? 'page' : null\"\n >\n <ng-container\n [ngTemplateOutlet]=\"body\"\n [ngTemplateOutletContext]=\"{ $implicit: item, active: rla.isActive }\"\n />\n </a>\n } @else if (item.href !== undefined) {\n <a\n class=\"tab-bar-item\"\n [href]=\"item.href\"\n [class.is-active]=\"activeKey() === item.key\"\n [attr.aria-current]=\"activeKey() === item.key ? 'page' : null\"\n >\n <ng-container\n [ngTemplateOutlet]=\"body\"\n [ngTemplateOutletContext]=\"{\n $implicit: item,\n active: activeKey() === item.key,\n }\"\n />\n </a>\n } @else {\n <button\n type=\"button\"\n class=\"tab-bar-item\"\n [class.is-active]=\"activeKey() === item.key\"\n [attr.aria-current]=\"activeKey() === item.key ? 'page' : null\"\n (click)=\"activeKey.set(item.key)\"\n >\n <ng-container\n [ngTemplateOutlet]=\"body\"\n [ngTemplateOutletContext]=\"{\n $implicit: item,\n active: activeKey() === item.key,\n }\"\n />\n </button>\n }\n }\n</nav>\n\n<!-- One item's inner content, shared by the link / button branches. -->\n<ng-template #body let-item let-active=\"active\">\n @if (item.icon; as ic) {\n <fold-icon class=\"tab-bar-icon\" [name]=\"ic\" size=\"sm\" />\n } @else if (collapsed()) {\n <!-- Collapsed needs a fixed glyph; an icon-less item falls back to its\n initial so the rail stays icon-width and the label still tooltips. -->\n <span class=\"tab-bar-icon tab-bar-initial\" aria-hidden=\"true\">{{\n item.label.charAt(0)\n }}</span>\n }\n <span class=\"tab-bar-label\">{{ item.label }}</span>\n @if (item.badge !== undefined && item.badge !== null) {\n <fold-badge\n class=\"tab-bar-badge\"\n [content]=\"item.badge + ''\"\n [variant]=\"active ? 'accent' : 'neutral'\"\n />\n }\n</ng-template>\n", styles: ["@charset \"UTF-8\";:host{display:flex;width:100%;max-width:100%;overflow:hidden}.tab-bar{flex:1;display:flex;max-width:100%;gap:2px;-webkit-user-select:none;user-select:none}.bg-surface{background:var(--fold-color-bg-rail-tertiary);padding:var(--fold-space-xs) var(--fold-space-sm) 0}.bg-surface.dir-vertical{padding:var(--fold-space-md) var(--fold-space-sm)}.tab-bar-item{flex:1;display:flex;align-items:center;justify-content:center;gap:var(--fold-space-sm);padding:var(--fold-space-sm) var(--fold-space-sm);background:none;border:none;color:var(--fold-color-text-muted);font-family:inherit;font-size:10px;font-weight:600;cursor:pointer;text-align:center;text-decoration:none;transition:color .1s ease,background .1s ease,border-color .1s ease;white-space:nowrap}.tab-bar-item:hover{color:var(--fold-color-text-secondary)}.tab-bar-item.is-disabled{opacity:.5;cursor:default;pointer-events:none}.size-comfortable .tab-bar-item{flex:0 1 auto;gap:var(--fold-space-sm);padding:var(--fold-space-md) var(--fold-space-lg);font-size:var(--fold-text-sm)}.dir-vertical.size-comfortable .tab-bar-item{padding:var(--fold-space-md) var(--fold-space-md);font-size:var(--fold-text-md)}.style-underline{border-bottom:1px solid var(--fold-color-border)}.style-underline .tab-bar-item{border-bottom:2px solid transparent;margin-bottom:-1px}.style-underline .tab-bar-item.is-active{color:var(--fold-color-text);border-bottom-color:var(--fold-color-primary)}.style-fill .tab-bar-item{border-radius:var(--fold-radius-sm);border:1px solid transparent}.style-fill .tab-bar-item.is-active{background:var(--fold-color-primary-surface);color:var(--fold-color-primary-text);font-weight:600}.style-fill .tab-bar-item:hover:not(.is-active){background:var(--fold-color-surface-hover);color:var(--fold-color-text)}.dir-vertical{flex-direction:column}.dir-vertical .tab-bar-item{flex:none;justify-content:flex-start;text-align:left;padding:var(--fold-space-sm) var(--fold-space-md);gap:var(--fold-space-sm);border-radius:var(--fold-radius-sm);font-size:var(--fold-text-sm);font-weight:500}.dir-vertical.style-underline{border-bottom:none;border-right:1px solid var(--fold-color-border)}.dir-vertical.style-underline .tab-bar-item{border-bottom:none;border-left:2px solid transparent;margin-bottom:0;margin-right:-1px}.dir-vertical.style-underline .tab-bar-item.is-active{border-left-color:var(--fold-color-primary)}.dir-vertical.style-fill .tab-bar-item.is-active{background:var(--fold-color-primary-surface);color:var(--fold-color-primary-text);font-weight:600}.is-collapsed .tab-bar-item{position:relative;flex:0 0 auto;gap:0}.is-collapsed .tab-bar-item:not(.is-active) .tab-bar-badge{display:none}.is-collapsed .tab-bar-item.is-active{flex:1 1 auto;min-width:0;gap:var(--fold-space-sm)}.is-collapsed .tab-bar-item.is-active .tab-bar-label{overflow:hidden;text-overflow:ellipsis}.dir-vertical.is-collapsed .tab-bar-item .tab-bar-icon~.tab-bar-label,.is-collapsed:not(.dir-vertical) .tab-bar-item:not(.is-active) .tab-bar-icon~.tab-bar-label{position:absolute;padding:var(--fold-space-xs) var(--fold-space-sm);border-radius:var(--fold-radius-sm);background:var(--fold-color-glass);border:1px solid var(--fold-color-glass-border);color:var(--fold-color-text);font-size:var(--fold-text-xs);font-weight:500;white-space:nowrap;opacity:0;pointer-events:none;box-shadow:var(--fold-shadow-md);transition:opacity var(--fold-motion-fast);z-index:100}.dir-vertical.is-collapsed .tab-bar-item .tab-bar-icon~.tab-bar-label{left:calc(100% + 8px);top:50%;transform:translateY(-50%)}.is-collapsed:not(.dir-vertical) .tab-bar-item:not(.is-active) .tab-bar-icon~.tab-bar-label{top:calc(100% + 6px);left:50%;transform:translate(-50%)}.dir-vertical.is-collapsed .tab-bar-item:hover .tab-bar-icon~.tab-bar-label,.dir-vertical.is-collapsed .tab-bar-item:focus-visible .tab-bar-icon~.tab-bar-label,.is-collapsed:not(.dir-vertical) .tab-bar-item:not(.is-active):hover .tab-bar-icon~.tab-bar-label,.is-collapsed:not(.dir-vertical) .tab-bar-item:not(.is-active):focus-visible .tab-bar-icon~.tab-bar-label{opacity:1}.dir-vertical.is-collapsed{align-items:center}.dir-vertical.is-collapsed .tab-bar-item,.dir-vertical.is-collapsed .tab-bar-item.is-active{justify-content:center;gap:0}.dir-vertical.is-collapsed .tab-bar-item .tab-bar-badge{display:block;position:absolute;top:-2px;right:-2px;transform:scale(.85);transform-origin:top right;pointer-events:none}:host:has(.is-collapsed){overflow:visible}.tab-bar-icon{flex-shrink:0}.tab-bar-initial{display:grid;place-items:center;width:18px;height:18px;border-radius:var(--fold-radius-sm);font-size:11px;font-weight:700;line-height:1;text-transform:uppercase}.tab-bar-badge{flex-shrink:0;font-variant-numeric:tabular-nums}.tab-bar-item:focus-visible{outline:2px solid var(--fold-color-primary);outline-offset:-2px;border-radius:var(--fold-radius-sm)}\n"] }]
7895
7895
  }], propDecorators: { items: [{ type: i0.Input, args: [{ isSignal: true, alias: "items", required: true }] }], activeKey: [{ type: i0.Input, args: [{ isSignal: true, alias: "activeKey", required: false }] }, { type: i0.Output, args: ["activeKeyChange"] }], activeStyle: [{ type: i0.Input, args: [{ isSignal: true, alias: "activeStyle", required: false }] }], direction: [{ type: i0.Input, args: [{ isSignal: true, alias: "direction", required: false }] }], size: [{ type: i0.Input, args: [{ isSignal: true, alias: "size", required: false }] }], collapsed: [{ type: i0.Input, args: [{ isSignal: true, alias: "collapsed", required: false }] }], background: [{ type: i0.Input, args: [{ isSignal: true, alias: "background", required: false }] }] } });
7896
7896
 
7897
7897
  /**
@@ -8022,11 +8022,11 @@ class FoldTabsComponent {
8022
8022
  this.tabButtons()[target]?.nativeElement.focus();
8023
8023
  }
8024
8024
  static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "22.0.8", ngImport: i0, type: FoldTabsComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
8025
- static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "22.0.8", type: FoldTabsComponent, isStandalone: true, selector: "fold-tabs", inputs: { tabs: { classPropertyName: "tabs", publicName: "tabs", isSignal: true, isRequired: true, transformFunction: null }, activeKey: { classPropertyName: "activeKey", publicName: "activeKey", isSignal: true, isRequired: true, transformFunction: null }, activeStyle: { classPropertyName: "activeStyle", publicName: "activeStyle", isSignal: true, isRequired: false, transformFunction: null }, direction: { classPropertyName: "direction", publicName: "direction", isSignal: true, isRequired: false, transformFunction: null }, size: { classPropertyName: "size", publicName: "size", isSignal: true, isRequired: false, transformFunction: null }, collapsed: { classPropertyName: "collapsed", publicName: "collapsed", isSignal: true, isRequired: false, transformFunction: null }, background: { classPropertyName: "background", publicName: "background", isSignal: true, isRequired: false, transformFunction: null } }, outputs: { activeKey: "activeKeyChange" }, viewQueries: [{ propertyName: "tabButtons", predicate: ["tabBtn"], descendants: true, isSignal: true }], exportAs: ["foldTabs"], ngImport: i0, template: "<div\n class=\"tab-bar\"\n role=\"tablist\"\n [attr.aria-orientation]=\"\n resolvedDirection() === 'vertical' ? 'vertical' : 'horizontal'\n \"\n [class.style-underline]=\"activeStyle() === 'underline'\"\n [class.style-fill]=\"activeStyle() === 'fill'\"\n [class.dir-vertical]=\"resolvedDirection() === 'vertical'\"\n [class.size-comfortable]=\"size() === 'comfortable'\"\n [class.is-collapsed]=\"collapsed()\"\n [class.bg-surface]=\"background() === 'surface'\"\n (keydown)=\"onKeydown($event)\"\n>\n @for (tab of tabs(); track tab.key) {\n <button\n #tabBtn\n type=\"button\"\n role=\"tab\"\n class=\"tab-bar-item\"\n [id]=\"tabId(tab.key)\"\n [class.is-active]=\"activeKey() === tab.key\"\n [attr.aria-selected]=\"activeKey() === tab.key\"\n [attr.aria-controls]=\"panelId(tab.key)\"\n [tabindex]=\"activeKey() === tab.key ? 0 : -1\"\n (click)=\"select(tab.key)\"\n >\n @if (tab.icon; as ic) {\n <fold-icon class=\"tab-bar-icon\" [name]=\"ic\" size=\"sm\" />\n } @else if (collapsed()) {\n <span class=\"tab-bar-icon tab-bar-initial\" aria-hidden=\"true\">{{\n tab.label.charAt(0)\n }}</span>\n }\n <span class=\"tab-bar-label\">{{ tab.label }}</span>\n @if (tab.badge !== undefined && tab.badge !== null) {\n <fold-badge\n class=\"tab-bar-badge\"\n [content]=\"tab.badge + ''\"\n [variant]=\"activeKey() === tab.key ? 'accent' : 'neutral'\"\n />\n }\n </button>\n }\n</div>\n", styles: ["@charset \"UTF-8\";:host{display:flex;width:100%;max-width:100%;overflow:hidden}.tab-bar{flex:1;display:flex;max-width:100%;gap:2px;-webkit-user-select:none;user-select:none}.bg-surface{background:var(--fold-color-bg-rail-tertiary);padding:var(--fold-space-xs) var(--fold-space-sm) 0}.bg-surface.dir-vertical{padding:var(--fold-space-md) var(--fold-space-sm)}.tab-bar-item{flex:1;display:flex;align-items:center;justify-content:center;gap:var(--fold-space-sm);padding:var(--fold-space-sm) var(--fold-space-sm);background:none;border:none;color:var(--fold-color-text-muted);font-family:inherit;font-size:10px;font-weight:600;cursor:pointer;text-align:center;text-decoration:none;transition:color .1s ease,background .1s ease,border-color .1s ease;white-space:nowrap}.tab-bar-item:hover{color:var(--fold-color-text-secondary)}.tab-bar-item.is-disabled{opacity:.5;cursor:default;pointer-events:none}.size-comfortable .tab-bar-item{flex:0 1 auto;gap:var(--fold-space-sm);padding:var(--fold-space-md) var(--fold-space-lg);font-size:var(--fold-text-sm)}.dir-vertical.size-comfortable .tab-bar-item{padding:var(--fold-space-md) var(--fold-space-md);font-size:var(--fold-text-md)}.style-underline{border-bottom:1px solid var(--fold-color-border)}.style-underline .tab-bar-item{border-bottom:2px solid transparent;margin-bottom:-1px}.style-underline .tab-bar-item.is-active{color:var(--fold-color-text);border-bottom-color:var(--fold-color-primary)}.style-fill .tab-bar-item{border-radius:var(--fold-radius-sm);border:1px solid transparent}.style-fill .tab-bar-item.is-active{background:var(--fold-color-primary-surface);color:var(--fold-color-primary-text);font-weight:600}.style-fill .tab-bar-item:hover:not(.is-active){background:var(--fold-color-surface-hover);color:var(--fold-color-text)}.dir-vertical{flex-direction:column}.dir-vertical .tab-bar-item{flex:none;justify-content:flex-start;text-align:left;padding:var(--fold-space-sm) var(--fold-space-md);gap:var(--fold-space-sm);border-radius:var(--fold-radius-sm);font-size:var(--fold-text-sm);font-weight:500}.dir-vertical.style-underline{border-bottom:none;border-right:1px solid var(--fold-color-border)}.dir-vertical.style-underline .tab-bar-item{border-bottom:none;border-left:2px solid transparent;margin-bottom:0;margin-right:-1px}.dir-vertical.style-underline .tab-bar-item.is-active{border-left-color:var(--fold-color-primary)}.dir-vertical.style-fill .tab-bar-item.is-active{background:var(--fold-color-primary-surface);color:var(--fold-color-primary-text);font-weight:600}.is-collapsed .tab-bar-item{position:relative;flex:0 0 auto;gap:0}.is-collapsed .tab-bar-item:not(.is-active) .tab-bar-badge{display:none}.is-collapsed .tab-bar-item.is-active{flex:1 1 auto;min-width:0;gap:var(--fold-space-sm)}.is-collapsed .tab-bar-item.is-active .tab-bar-label{overflow:hidden;text-overflow:ellipsis}.dir-vertical.is-collapsed .tab-bar-item .tab-bar-icon~.tab-bar-label,.is-collapsed:not(.dir-vertical) .tab-bar-item:not(.is-active) .tab-bar-icon~.tab-bar-label{position:absolute;padding:var(--fold-space-xs) var(--fold-space-sm);border-radius:var(--fold-radius-sm);background:var(--fold-color-glass);border:1px solid var(--fold-color-glass-border);color:var(--fold-color-text);font-size:var(--fold-text-xs);font-weight:500;white-space:nowrap;opacity:0;pointer-events:none;box-shadow:var(--fold-shadow-md);transition:opacity var(--fold-motion-fast);z-index:100}.dir-vertical.is-collapsed .tab-bar-item .tab-bar-icon~.tab-bar-label{left:calc(100% + 8px);top:50%;transform:translateY(-50%)}.is-collapsed:not(.dir-vertical) .tab-bar-item:not(.is-active) .tab-bar-icon~.tab-bar-label{top:calc(100% + 6px);left:50%;transform:translate(-50%)}.dir-vertical.is-collapsed .tab-bar-item:hover .tab-bar-icon~.tab-bar-label,.dir-vertical.is-collapsed .tab-bar-item:focus-visible .tab-bar-icon~.tab-bar-label,.is-collapsed:not(.dir-vertical) .tab-bar-item:not(.is-active):hover .tab-bar-icon~.tab-bar-label,.is-collapsed:not(.dir-vertical) .tab-bar-item:not(.is-active):focus-visible .tab-bar-icon~.tab-bar-label{opacity:1}.dir-vertical.is-collapsed{align-items:center}.dir-vertical.is-collapsed .tab-bar-item,.dir-vertical.is-collapsed .tab-bar-item.is-active{justify-content:center;gap:0}.dir-vertical.is-collapsed .tab-bar-item .tab-bar-badge{display:block;position:absolute;top:-2px;right:-2px;transform:scale(.85);transform-origin:top right;pointer-events:none}:host:has(.is-collapsed){overflow:visible}@media(max-width:768px){.dir-vertical{flex-direction:row;align-items:center}.dir-vertical .tab-bar-item{flex:0 0 auto;justify-content:center;text-align:center;padding:var(--fold-space-sm);gap:0;font-size:var(--fold-text-xs);font-weight:600}.dir-vertical .tab-bar-item .tab-bar-label{display:none}.dir-vertical .tab-bar-item.is-active{flex:1 1 auto;min-width:0;gap:var(--fold-space-sm);padding:var(--fold-space-sm) var(--fold-space-md)}.dir-vertical .tab-bar-item.is-active .tab-bar-label{display:inline;overflow:hidden;text-overflow:ellipsis}.dir-vertical .tab-bar-badge{display:none}.dir-vertical.style-underline{border-right:none;border-bottom:1px solid var(--fold-color-border)}.dir-vertical.style-underline .tab-bar-item{border-left:none;border-bottom:2px solid transparent;margin-right:0;margin-bottom:-1px}.dir-vertical.style-underline .tab-bar-item.is-active{border-bottom-color:var(--fold-color-primary)}.dir-vertical.style-fill{border-right:none}}.tab-bar-icon{flex-shrink:0}.tab-bar-initial{display:grid;place-items:center;width:18px;height:18px;border-radius:var(--fold-radius-sm);font-size:11px;font-weight:700;line-height:1;text-transform:uppercase}.tab-bar-badge{flex-shrink:0;font-variant-numeric:tabular-nums}.tab-bar-item:focus-visible{outline:2px solid var(--fold-color-primary);outline-offset:-2px;border-radius:var(--fold-radius-sm)}\n"], dependencies: [{ kind: "component", type: FoldIconComponent, selector: "fold-icon", inputs: ["name", "size", "tone", "title"] }, { kind: "component", type: FoldBadgeComponent, selector: "fold-badge", inputs: ["content", "radius", "variant"] }] });
8025
+ static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "22.0.8", type: FoldTabsComponent, isStandalone: true, selector: "fold-tabs", inputs: { tabs: { classPropertyName: "tabs", publicName: "tabs", isSignal: true, isRequired: true, transformFunction: null }, activeKey: { classPropertyName: "activeKey", publicName: "activeKey", isSignal: true, isRequired: true, transformFunction: null }, activeStyle: { classPropertyName: "activeStyle", publicName: "activeStyle", isSignal: true, isRequired: false, transformFunction: null }, direction: { classPropertyName: "direction", publicName: "direction", isSignal: true, isRequired: false, transformFunction: null }, size: { classPropertyName: "size", publicName: "size", isSignal: true, isRequired: false, transformFunction: null }, collapsed: { classPropertyName: "collapsed", publicName: "collapsed", isSignal: true, isRequired: false, transformFunction: null }, background: { classPropertyName: "background", publicName: "background", isSignal: true, isRequired: false, transformFunction: null } }, outputs: { activeKey: "activeKeyChange" }, viewQueries: [{ propertyName: "tabButtons", predicate: ["tabBtn"], descendants: true, isSignal: true }], exportAs: ["foldTabs"], ngImport: i0, template: "<div\n class=\"tab-bar\"\n role=\"tablist\"\n [attr.aria-orientation]=\"\n resolvedDirection() === 'vertical' ? 'vertical' : 'horizontal'\n \"\n [class.style-underline]=\"activeStyle() === 'underline'\"\n [class.style-fill]=\"activeStyle() === 'fill'\"\n [class.dir-vertical]=\"resolvedDirection() === 'vertical'\"\n [class.size-comfortable]=\"size() === 'comfortable'\"\n [class.is-collapsed]=\"collapsed()\"\n [class.bg-surface]=\"background() === 'surface'\"\n (keydown)=\"onKeydown($event)\"\n>\n @for (tab of tabs(); track tab.key) {\n <button\n #tabBtn\n type=\"button\"\n role=\"tab\"\n class=\"tab-bar-item\"\n [id]=\"tabId(tab.key)\"\n [class.is-active]=\"activeKey() === tab.key\"\n [attr.aria-selected]=\"activeKey() === tab.key\"\n [attr.aria-controls]=\"panelId(tab.key)\"\n [tabindex]=\"activeKey() === tab.key ? 0 : -1\"\n (click)=\"select(tab.key)\"\n >\n @if (tab.icon; as ic) {\n <fold-icon class=\"tab-bar-icon\" [name]=\"ic\" size=\"sm\" />\n } @else if (collapsed()) {\n <span class=\"tab-bar-icon tab-bar-initial\" aria-hidden=\"true\">{{\n tab.label.charAt(0)\n }}</span>\n }\n <span class=\"tab-bar-label\">{{ tab.label }}</span>\n @if (tab.badge !== undefined && tab.badge !== null) {\n <fold-badge\n class=\"tab-bar-badge\"\n [content]=\"tab.badge + ''\"\n [variant]=\"activeKey() === tab.key ? 'accent' : 'neutral'\"\n />\n }\n </button>\n }\n</div>\n", styles: ["@charset \"UTF-8\";:host{display:flex;width:100%;max-width:100%;overflow:hidden}.tab-bar{flex:1;display:flex;max-width:100%;gap:2px;-webkit-user-select:none;user-select:none}.bg-surface{background:var(--fold-color-bg-rail-tertiary);padding:var(--fold-space-xs) var(--fold-space-sm) 0}.bg-surface.dir-vertical{padding:var(--fold-space-md) var(--fold-space-sm)}.tab-bar-item{flex:1;display:flex;align-items:center;justify-content:center;gap:var(--fold-space-sm);padding:var(--fold-space-sm) var(--fold-space-sm);background:none;border:none;color:var(--fold-color-text-muted);font-family:inherit;font-size:10px;font-weight:600;cursor:pointer;text-align:center;text-decoration:none;transition:color .1s ease,background .1s ease,border-color .1s ease;white-space:nowrap}.tab-bar-item:hover{color:var(--fold-color-text-secondary)}.tab-bar-item.is-disabled{opacity:.5;cursor:default;pointer-events:none}.size-comfortable .tab-bar-item{flex:0 1 auto;gap:var(--fold-space-sm);padding:var(--fold-space-md) var(--fold-space-lg);font-size:var(--fold-text-sm)}.dir-vertical.size-comfortable .tab-bar-item{padding:var(--fold-space-md) var(--fold-space-md);font-size:var(--fold-text-md)}.style-underline{border-bottom:1px solid var(--fold-color-border)}.style-underline .tab-bar-item{border-bottom:2px solid transparent;margin-bottom:-1px}.style-underline .tab-bar-item.is-active{color:var(--fold-color-text);border-bottom-color:var(--fold-color-primary)}.style-fill .tab-bar-item{border-radius:var(--fold-radius-sm);border:1px solid transparent}.style-fill .tab-bar-item.is-active{background:var(--fold-color-primary-surface);color:var(--fold-color-primary-text);font-weight:600}.style-fill .tab-bar-item:hover:not(.is-active){background:var(--fold-color-surface-hover);color:var(--fold-color-text)}.dir-vertical{flex-direction:column}.dir-vertical .tab-bar-item{flex:none;justify-content:flex-start;text-align:left;padding:var(--fold-space-sm) var(--fold-space-md);gap:var(--fold-space-sm);border-radius:var(--fold-radius-sm);font-size:var(--fold-text-sm);font-weight:500}.dir-vertical.style-underline{border-bottom:none;border-right:1px solid var(--fold-color-border)}.dir-vertical.style-underline .tab-bar-item{border-bottom:none;border-left:2px solid transparent;margin-bottom:0;margin-right:-1px}.dir-vertical.style-underline .tab-bar-item.is-active{border-left-color:var(--fold-color-primary)}.dir-vertical.style-fill .tab-bar-item.is-active{background:var(--fold-color-primary-surface);color:var(--fold-color-primary-text);font-weight:600}.is-collapsed .tab-bar-item{position:relative;flex:0 0 auto;gap:0}.is-collapsed .tab-bar-item:not(.is-active) .tab-bar-badge{display:none}.is-collapsed .tab-bar-item.is-active{flex:1 1 auto;min-width:0;gap:var(--fold-space-sm)}.is-collapsed .tab-bar-item.is-active .tab-bar-label{overflow:hidden;text-overflow:ellipsis}.dir-vertical.is-collapsed .tab-bar-item .tab-bar-icon~.tab-bar-label,.is-collapsed:not(.dir-vertical) .tab-bar-item:not(.is-active) .tab-bar-icon~.tab-bar-label{position:absolute;padding:var(--fold-space-xs) var(--fold-space-sm);border-radius:var(--fold-radius-sm);background:var(--fold-color-glass);border:1px solid var(--fold-color-glass-border);color:var(--fold-color-text);font-size:var(--fold-text-xs);font-weight:500;white-space:nowrap;opacity:0;pointer-events:none;box-shadow:var(--fold-shadow-md);transition:opacity var(--fold-motion-fast);z-index:100}.dir-vertical.is-collapsed .tab-bar-item .tab-bar-icon~.tab-bar-label{left:calc(100% + 8px);top:50%;transform:translateY(-50%)}.is-collapsed:not(.dir-vertical) .tab-bar-item:not(.is-active) .tab-bar-icon~.tab-bar-label{top:calc(100% + 6px);left:50%;transform:translate(-50%)}.dir-vertical.is-collapsed .tab-bar-item:hover .tab-bar-icon~.tab-bar-label,.dir-vertical.is-collapsed .tab-bar-item:focus-visible .tab-bar-icon~.tab-bar-label,.is-collapsed:not(.dir-vertical) .tab-bar-item:not(.is-active):hover .tab-bar-icon~.tab-bar-label,.is-collapsed:not(.dir-vertical) .tab-bar-item:not(.is-active):focus-visible .tab-bar-icon~.tab-bar-label{opacity:1}.dir-vertical.is-collapsed{align-items:center}.dir-vertical.is-collapsed .tab-bar-item,.dir-vertical.is-collapsed .tab-bar-item.is-active{justify-content:center;gap:0}.dir-vertical.is-collapsed .tab-bar-item .tab-bar-badge{display:block;position:absolute;top:-2px;right:-2px;transform:scale(.85);transform-origin:top right;pointer-events:none}:host:has(.is-collapsed){overflow:visible}.tab-bar-icon{flex-shrink:0}.tab-bar-initial{display:grid;place-items:center;width:18px;height:18px;border-radius:var(--fold-radius-sm);font-size:11px;font-weight:700;line-height:1;text-transform:uppercase}.tab-bar-badge{flex-shrink:0;font-variant-numeric:tabular-nums}.tab-bar-item:focus-visible{outline:2px solid var(--fold-color-primary);outline-offset:-2px;border-radius:var(--fold-radius-sm)}\n"], dependencies: [{ kind: "component", type: FoldIconComponent, selector: "fold-icon", inputs: ["name", "size", "tone", "title"] }, { kind: "component", type: FoldBadgeComponent, selector: "fold-badge", inputs: ["content", "radius", "variant"] }] });
8026
8026
  }
8027
8027
  i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.0.8", ngImport: i0, type: FoldTabsComponent, decorators: [{
8028
8028
  type: Component,
8029
- args: [{ selector: "fold-tabs", standalone: true, exportAs: "foldTabs", imports: [FoldIconComponent, FoldBadgeComponent], template: "<div\n class=\"tab-bar\"\n role=\"tablist\"\n [attr.aria-orientation]=\"\n resolvedDirection() === 'vertical' ? 'vertical' : 'horizontal'\n \"\n [class.style-underline]=\"activeStyle() === 'underline'\"\n [class.style-fill]=\"activeStyle() === 'fill'\"\n [class.dir-vertical]=\"resolvedDirection() === 'vertical'\"\n [class.size-comfortable]=\"size() === 'comfortable'\"\n [class.is-collapsed]=\"collapsed()\"\n [class.bg-surface]=\"background() === 'surface'\"\n (keydown)=\"onKeydown($event)\"\n>\n @for (tab of tabs(); track tab.key) {\n <button\n #tabBtn\n type=\"button\"\n role=\"tab\"\n class=\"tab-bar-item\"\n [id]=\"tabId(tab.key)\"\n [class.is-active]=\"activeKey() === tab.key\"\n [attr.aria-selected]=\"activeKey() === tab.key\"\n [attr.aria-controls]=\"panelId(tab.key)\"\n [tabindex]=\"activeKey() === tab.key ? 0 : -1\"\n (click)=\"select(tab.key)\"\n >\n @if (tab.icon; as ic) {\n <fold-icon class=\"tab-bar-icon\" [name]=\"ic\" size=\"sm\" />\n } @else if (collapsed()) {\n <span class=\"tab-bar-icon tab-bar-initial\" aria-hidden=\"true\">{{\n tab.label.charAt(0)\n }}</span>\n }\n <span class=\"tab-bar-label\">{{ tab.label }}</span>\n @if (tab.badge !== undefined && tab.badge !== null) {\n <fold-badge\n class=\"tab-bar-badge\"\n [content]=\"tab.badge + ''\"\n [variant]=\"activeKey() === tab.key ? 'accent' : 'neutral'\"\n />\n }\n </button>\n }\n</div>\n", styles: ["@charset \"UTF-8\";:host{display:flex;width:100%;max-width:100%;overflow:hidden}.tab-bar{flex:1;display:flex;max-width:100%;gap:2px;-webkit-user-select:none;user-select:none}.bg-surface{background:var(--fold-color-bg-rail-tertiary);padding:var(--fold-space-xs) var(--fold-space-sm) 0}.bg-surface.dir-vertical{padding:var(--fold-space-md) var(--fold-space-sm)}.tab-bar-item{flex:1;display:flex;align-items:center;justify-content:center;gap:var(--fold-space-sm);padding:var(--fold-space-sm) var(--fold-space-sm);background:none;border:none;color:var(--fold-color-text-muted);font-family:inherit;font-size:10px;font-weight:600;cursor:pointer;text-align:center;text-decoration:none;transition:color .1s ease,background .1s ease,border-color .1s ease;white-space:nowrap}.tab-bar-item:hover{color:var(--fold-color-text-secondary)}.tab-bar-item.is-disabled{opacity:.5;cursor:default;pointer-events:none}.size-comfortable .tab-bar-item{flex:0 1 auto;gap:var(--fold-space-sm);padding:var(--fold-space-md) var(--fold-space-lg);font-size:var(--fold-text-sm)}.dir-vertical.size-comfortable .tab-bar-item{padding:var(--fold-space-md) var(--fold-space-md);font-size:var(--fold-text-md)}.style-underline{border-bottom:1px solid var(--fold-color-border)}.style-underline .tab-bar-item{border-bottom:2px solid transparent;margin-bottom:-1px}.style-underline .tab-bar-item.is-active{color:var(--fold-color-text);border-bottom-color:var(--fold-color-primary)}.style-fill .tab-bar-item{border-radius:var(--fold-radius-sm);border:1px solid transparent}.style-fill .tab-bar-item.is-active{background:var(--fold-color-primary-surface);color:var(--fold-color-primary-text);font-weight:600}.style-fill .tab-bar-item:hover:not(.is-active){background:var(--fold-color-surface-hover);color:var(--fold-color-text)}.dir-vertical{flex-direction:column}.dir-vertical .tab-bar-item{flex:none;justify-content:flex-start;text-align:left;padding:var(--fold-space-sm) var(--fold-space-md);gap:var(--fold-space-sm);border-radius:var(--fold-radius-sm);font-size:var(--fold-text-sm);font-weight:500}.dir-vertical.style-underline{border-bottom:none;border-right:1px solid var(--fold-color-border)}.dir-vertical.style-underline .tab-bar-item{border-bottom:none;border-left:2px solid transparent;margin-bottom:0;margin-right:-1px}.dir-vertical.style-underline .tab-bar-item.is-active{border-left-color:var(--fold-color-primary)}.dir-vertical.style-fill .tab-bar-item.is-active{background:var(--fold-color-primary-surface);color:var(--fold-color-primary-text);font-weight:600}.is-collapsed .tab-bar-item{position:relative;flex:0 0 auto;gap:0}.is-collapsed .tab-bar-item:not(.is-active) .tab-bar-badge{display:none}.is-collapsed .tab-bar-item.is-active{flex:1 1 auto;min-width:0;gap:var(--fold-space-sm)}.is-collapsed .tab-bar-item.is-active .tab-bar-label{overflow:hidden;text-overflow:ellipsis}.dir-vertical.is-collapsed .tab-bar-item .tab-bar-icon~.tab-bar-label,.is-collapsed:not(.dir-vertical) .tab-bar-item:not(.is-active) .tab-bar-icon~.tab-bar-label{position:absolute;padding:var(--fold-space-xs) var(--fold-space-sm);border-radius:var(--fold-radius-sm);background:var(--fold-color-glass);border:1px solid var(--fold-color-glass-border);color:var(--fold-color-text);font-size:var(--fold-text-xs);font-weight:500;white-space:nowrap;opacity:0;pointer-events:none;box-shadow:var(--fold-shadow-md);transition:opacity var(--fold-motion-fast);z-index:100}.dir-vertical.is-collapsed .tab-bar-item .tab-bar-icon~.tab-bar-label{left:calc(100% + 8px);top:50%;transform:translateY(-50%)}.is-collapsed:not(.dir-vertical) .tab-bar-item:not(.is-active) .tab-bar-icon~.tab-bar-label{top:calc(100% + 6px);left:50%;transform:translate(-50%)}.dir-vertical.is-collapsed .tab-bar-item:hover .tab-bar-icon~.tab-bar-label,.dir-vertical.is-collapsed .tab-bar-item:focus-visible .tab-bar-icon~.tab-bar-label,.is-collapsed:not(.dir-vertical) .tab-bar-item:not(.is-active):hover .tab-bar-icon~.tab-bar-label,.is-collapsed:not(.dir-vertical) .tab-bar-item:not(.is-active):focus-visible .tab-bar-icon~.tab-bar-label{opacity:1}.dir-vertical.is-collapsed{align-items:center}.dir-vertical.is-collapsed .tab-bar-item,.dir-vertical.is-collapsed .tab-bar-item.is-active{justify-content:center;gap:0}.dir-vertical.is-collapsed .tab-bar-item .tab-bar-badge{display:block;position:absolute;top:-2px;right:-2px;transform:scale(.85);transform-origin:top right;pointer-events:none}:host:has(.is-collapsed){overflow:visible}@media(max-width:768px){.dir-vertical{flex-direction:row;align-items:center}.dir-vertical .tab-bar-item{flex:0 0 auto;justify-content:center;text-align:center;padding:var(--fold-space-sm);gap:0;font-size:var(--fold-text-xs);font-weight:600}.dir-vertical .tab-bar-item .tab-bar-label{display:none}.dir-vertical .tab-bar-item.is-active{flex:1 1 auto;min-width:0;gap:var(--fold-space-sm);padding:var(--fold-space-sm) var(--fold-space-md)}.dir-vertical .tab-bar-item.is-active .tab-bar-label{display:inline;overflow:hidden;text-overflow:ellipsis}.dir-vertical .tab-bar-badge{display:none}.dir-vertical.style-underline{border-right:none;border-bottom:1px solid var(--fold-color-border)}.dir-vertical.style-underline .tab-bar-item{border-left:none;border-bottom:2px solid transparent;margin-right:0;margin-bottom:-1px}.dir-vertical.style-underline .tab-bar-item.is-active{border-bottom-color:var(--fold-color-primary)}.dir-vertical.style-fill{border-right:none}}.tab-bar-icon{flex-shrink:0}.tab-bar-initial{display:grid;place-items:center;width:18px;height:18px;border-radius:var(--fold-radius-sm);font-size:11px;font-weight:700;line-height:1;text-transform:uppercase}.tab-bar-badge{flex-shrink:0;font-variant-numeric:tabular-nums}.tab-bar-item:focus-visible{outline:2px solid var(--fold-color-primary);outline-offset:-2px;border-radius:var(--fold-radius-sm)}\n"] }]
8029
+ args: [{ selector: "fold-tabs", standalone: true, exportAs: "foldTabs", imports: [FoldIconComponent, FoldBadgeComponent], template: "<div\n class=\"tab-bar\"\n role=\"tablist\"\n [attr.aria-orientation]=\"\n resolvedDirection() === 'vertical' ? 'vertical' : 'horizontal'\n \"\n [class.style-underline]=\"activeStyle() === 'underline'\"\n [class.style-fill]=\"activeStyle() === 'fill'\"\n [class.dir-vertical]=\"resolvedDirection() === 'vertical'\"\n [class.size-comfortable]=\"size() === 'comfortable'\"\n [class.is-collapsed]=\"collapsed()\"\n [class.bg-surface]=\"background() === 'surface'\"\n (keydown)=\"onKeydown($event)\"\n>\n @for (tab of tabs(); track tab.key) {\n <button\n #tabBtn\n type=\"button\"\n role=\"tab\"\n class=\"tab-bar-item\"\n [id]=\"tabId(tab.key)\"\n [class.is-active]=\"activeKey() === tab.key\"\n [attr.aria-selected]=\"activeKey() === tab.key\"\n [attr.aria-controls]=\"panelId(tab.key)\"\n [tabindex]=\"activeKey() === tab.key ? 0 : -1\"\n (click)=\"select(tab.key)\"\n >\n @if (tab.icon; as ic) {\n <fold-icon class=\"tab-bar-icon\" [name]=\"ic\" size=\"sm\" />\n } @else if (collapsed()) {\n <span class=\"tab-bar-icon tab-bar-initial\" aria-hidden=\"true\">{{\n tab.label.charAt(0)\n }}</span>\n }\n <span class=\"tab-bar-label\">{{ tab.label }}</span>\n @if (tab.badge !== undefined && tab.badge !== null) {\n <fold-badge\n class=\"tab-bar-badge\"\n [content]=\"tab.badge + ''\"\n [variant]=\"activeKey() === tab.key ? 'accent' : 'neutral'\"\n />\n }\n </button>\n }\n</div>\n", styles: ["@charset \"UTF-8\";:host{display:flex;width:100%;max-width:100%;overflow:hidden}.tab-bar{flex:1;display:flex;max-width:100%;gap:2px;-webkit-user-select:none;user-select:none}.bg-surface{background:var(--fold-color-bg-rail-tertiary);padding:var(--fold-space-xs) var(--fold-space-sm) 0}.bg-surface.dir-vertical{padding:var(--fold-space-md) var(--fold-space-sm)}.tab-bar-item{flex:1;display:flex;align-items:center;justify-content:center;gap:var(--fold-space-sm);padding:var(--fold-space-sm) var(--fold-space-sm);background:none;border:none;color:var(--fold-color-text-muted);font-family:inherit;font-size:10px;font-weight:600;cursor:pointer;text-align:center;text-decoration:none;transition:color .1s ease,background .1s ease,border-color .1s ease;white-space:nowrap}.tab-bar-item:hover{color:var(--fold-color-text-secondary)}.tab-bar-item.is-disabled{opacity:.5;cursor:default;pointer-events:none}.size-comfortable .tab-bar-item{flex:0 1 auto;gap:var(--fold-space-sm);padding:var(--fold-space-md) var(--fold-space-lg);font-size:var(--fold-text-sm)}.dir-vertical.size-comfortable .tab-bar-item{padding:var(--fold-space-md) var(--fold-space-md);font-size:var(--fold-text-md)}.style-underline{border-bottom:1px solid var(--fold-color-border)}.style-underline .tab-bar-item{border-bottom:2px solid transparent;margin-bottom:-1px}.style-underline .tab-bar-item.is-active{color:var(--fold-color-text);border-bottom-color:var(--fold-color-primary)}.style-fill .tab-bar-item{border-radius:var(--fold-radius-sm);border:1px solid transparent}.style-fill .tab-bar-item.is-active{background:var(--fold-color-primary-surface);color:var(--fold-color-primary-text);font-weight:600}.style-fill .tab-bar-item:hover:not(.is-active){background:var(--fold-color-surface-hover);color:var(--fold-color-text)}.dir-vertical{flex-direction:column}.dir-vertical .tab-bar-item{flex:none;justify-content:flex-start;text-align:left;padding:var(--fold-space-sm) var(--fold-space-md);gap:var(--fold-space-sm);border-radius:var(--fold-radius-sm);font-size:var(--fold-text-sm);font-weight:500}.dir-vertical.style-underline{border-bottom:none;border-right:1px solid var(--fold-color-border)}.dir-vertical.style-underline .tab-bar-item{border-bottom:none;border-left:2px solid transparent;margin-bottom:0;margin-right:-1px}.dir-vertical.style-underline .tab-bar-item.is-active{border-left-color:var(--fold-color-primary)}.dir-vertical.style-fill .tab-bar-item.is-active{background:var(--fold-color-primary-surface);color:var(--fold-color-primary-text);font-weight:600}.is-collapsed .tab-bar-item{position:relative;flex:0 0 auto;gap:0}.is-collapsed .tab-bar-item:not(.is-active) .tab-bar-badge{display:none}.is-collapsed .tab-bar-item.is-active{flex:1 1 auto;min-width:0;gap:var(--fold-space-sm)}.is-collapsed .tab-bar-item.is-active .tab-bar-label{overflow:hidden;text-overflow:ellipsis}.dir-vertical.is-collapsed .tab-bar-item .tab-bar-icon~.tab-bar-label,.is-collapsed:not(.dir-vertical) .tab-bar-item:not(.is-active) .tab-bar-icon~.tab-bar-label{position:absolute;padding:var(--fold-space-xs) var(--fold-space-sm);border-radius:var(--fold-radius-sm);background:var(--fold-color-glass);border:1px solid var(--fold-color-glass-border);color:var(--fold-color-text);font-size:var(--fold-text-xs);font-weight:500;white-space:nowrap;opacity:0;pointer-events:none;box-shadow:var(--fold-shadow-md);transition:opacity var(--fold-motion-fast);z-index:100}.dir-vertical.is-collapsed .tab-bar-item .tab-bar-icon~.tab-bar-label{left:calc(100% + 8px);top:50%;transform:translateY(-50%)}.is-collapsed:not(.dir-vertical) .tab-bar-item:not(.is-active) .tab-bar-icon~.tab-bar-label{top:calc(100% + 6px);left:50%;transform:translate(-50%)}.dir-vertical.is-collapsed .tab-bar-item:hover .tab-bar-icon~.tab-bar-label,.dir-vertical.is-collapsed .tab-bar-item:focus-visible .tab-bar-icon~.tab-bar-label,.is-collapsed:not(.dir-vertical) .tab-bar-item:not(.is-active):hover .tab-bar-icon~.tab-bar-label,.is-collapsed:not(.dir-vertical) .tab-bar-item:not(.is-active):focus-visible .tab-bar-icon~.tab-bar-label{opacity:1}.dir-vertical.is-collapsed{align-items:center}.dir-vertical.is-collapsed .tab-bar-item,.dir-vertical.is-collapsed .tab-bar-item.is-active{justify-content:center;gap:0}.dir-vertical.is-collapsed .tab-bar-item .tab-bar-badge{display:block;position:absolute;top:-2px;right:-2px;transform:scale(.85);transform-origin:top right;pointer-events:none}:host:has(.is-collapsed){overflow:visible}.tab-bar-icon{flex-shrink:0}.tab-bar-initial{display:grid;place-items:center;width:18px;height:18px;border-radius:var(--fold-radius-sm);font-size:11px;font-weight:700;line-height:1;text-transform:uppercase}.tab-bar-badge{flex-shrink:0;font-variant-numeric:tabular-nums}.tab-bar-item:focus-visible{outline:2px solid var(--fold-color-primary);outline-offset:-2px;border-radius:var(--fold-radius-sm)}\n"] }]
8030
8030
  }], propDecorators: { tabs: [{ type: i0.Input, args: [{ isSignal: true, alias: "tabs", required: true }] }], activeKey: [{ type: i0.Input, args: [{ isSignal: true, alias: "activeKey", required: true }] }, { type: i0.Output, args: ["activeKeyChange"] }], activeStyle: [{ type: i0.Input, args: [{ isSignal: true, alias: "activeStyle", required: false }] }], direction: [{ type: i0.Input, args: [{ isSignal: true, alias: "direction", required: false }] }], size: [{ type: i0.Input, args: [{ isSignal: true, alias: "size", required: false }] }], collapsed: [{ type: i0.Input, args: [{ isSignal: true, alias: "collapsed", required: false }] }], background: [{ type: i0.Input, args: [{ isSignal: true, alias: "background", required: false }] }], tabButtons: [{ type: i0.ViewChildren, args: ["tabBtn", { isSignal: true }] }] } });
8031
8031
 
8032
8032
  /**
@@ -8428,6 +8428,54 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.0.8", ngImpor
8428
8428
  args: [{ selector: "fold-panel-header", standalone: true, imports: [FoldIconComponent], host: { "[attr.title]": "null" }, template: "<header class=\"ph\" [class.ph--eyebrow]=\"variant() === 'eyebrow'\">\n <div class=\"ph__titles\">\n <div class=\"ph__titleRow\">\n @if (icon(); as ic) {\n <fold-icon class=\"ph__icon\" [name]=\"ic\" [size]=\"iconSize()\" />\n }\n <h2 class=\"ph__title\" [attr.id]=\"titleId()\">{{ title() }}</h2>\n </div>\n @if (subtitle()) {\n <p class=\"ph__subtitle\">{{ subtitle() }}</p>\n }\n <div class=\"ph__desc\"><ng-content /></div>\n </div>\n <div class=\"ph__actions\">\n <ng-content select=\"[actions]\" />\n <button\n type=\"button\"\n class=\"ph__close\"\n [attr.aria-label]=\"effectiveCloseLabel()\"\n (click)=\"onClose()\"\n >\n <fold-icon name=\"close\" size=\"sm\" />\n </button>\n </div>\n</header>\n", styles: ["@charset \"UTF-8\";:host{display:block;flex:none}.ph{display:flex;align-items:flex-start;gap:var(--fold-space-md);padding:var(--fold-space-lg) var(--fold-space-lg) var(--fold-space-md);border-bottom:1px solid var(--fold-color-glass-border)}.ph:not(:has(.ph__subtitle)):not(:has(.ph__desc:not(:empty))){align-items:center}.ph__titles{flex:1 1 auto;display:flex;flex-direction:column;gap:var(--fold-space-xs);min-width:0}.ph__titleRow{display:flex;align-items:center;gap:var(--fold-space-xs);min-width:0}.ph__icon{flex:none;color:var(--fold-color-text-secondary)}.ph__title{margin:0;font-size:var(--fold-text-lg);font-weight:600;color:var(--fold-color-text);letter-spacing:-.005em;line-height:1.25;overflow:hidden;text-overflow:ellipsis}.ph__subtitle{margin:0;font-size:var(--fold-text-xs);color:var(--fold-color-text-faded);font-variant-numeric:tabular-nums}.ph__desc{margin-top:var(--fold-space-sm);font-size:var(--fold-text-sm);color:var(--fold-color-text-secondary);line-height:1.5}.ph__desc:empty{display:none}.ph__actions{flex:none;display:inline-flex;align-items:center;gap:var(--fold-space-xs)}.ph__close{all:unset;box-sizing:border-box;flex:none;display:inline-flex;align-items:center;justify-content:center;width:28px;height:28px;border-radius:var(--fold-radius-xs);color:var(--fold-color-text-secondary);cursor:pointer;transition:background-color var(--fold-motion-fast),color var(--fold-motion-fast)}.ph__close:hover{background:var(--fold-color-surface-hover);color:var(--fold-color-text)}.ph--eyebrow{align-items:center;padding:var(--fold-space-md) var(--fold-space-lg)}.ph--eyebrow .ph__icon{opacity:.75}.ph--eyebrow .ph__title{font-size:var(--fold-text-xs);font-weight:600;letter-spacing:.06em;text-transform:uppercase;color:var(--fold-color-text-muted)}\n"] }]
8429
8429
  }], propDecorators: { title: [{ type: i0.Input, args: [{ isSignal: true, alias: "title", required: true }] }], subtitle: [{ type: i0.Input, args: [{ isSignal: true, alias: "subtitle", required: false }] }], icon: [{ type: i0.Input, args: [{ isSignal: true, alias: "icon", required: false }] }], variant: [{ type: i0.Input, args: [{ isSignal: true, alias: "variant", required: false }] }], closeLabel: [{ type: i0.Input, args: [{ isSignal: true, alias: "closeLabel", required: false }] }], closed: [{ type: i0.Output, args: ["closed"] }] } });
8430
8430
 
8431
+ /** The named width scale, in pixels. `md` is the historical default (490). */
8432
+ const PANEL_SIZE_PX = {
8433
+ sm: 360,
8434
+ md: 490,
8435
+ lg: 640,
8436
+ xl: 820,
8437
+ };
8438
+ /** Resolve a `width` (px number or named size) to pixels; `undefined` → `md`. */
8439
+ function panelWidthPx(width) {
8440
+ if (typeof width === "number") {
8441
+ return width;
8442
+ }
8443
+ return PANEL_SIZE_PX[width ?? "md"];
8444
+ }
8445
+ /**
8446
+ * App-wide panel defaults — the base layer of the cascade (see
8447
+ * {@link FoldPanelDefaults}). Provide it once at bootstrap to give every panel a
8448
+ * product-level identity (e.g. "our panels are solid, and dock left"); a
8449
+ * component's static `foldPanel` and a per-call `open()` option both win over it.
8450
+ */
8451
+ const FOLD_PANEL_DEFAULTS = new InjectionToken("FOLD_PANEL_DEFAULTS");
8452
+ /**
8453
+ * Provide app-wide panel defaults once at bootstrap.
8454
+ *
8455
+ * @example
8456
+ * ```ts
8457
+ * // app.config.ts
8458
+ * providers: [provideFoldPanelDefaults({ surface: "solid" })];
8459
+ * ```
8460
+ */
8461
+ function provideFoldPanelDefaults(defaults) {
8462
+ return { provide: FOLD_PANEL_DEFAULTS, useValue: defaults };
8463
+ }
8464
+ /**
8465
+ * Type-guard: does this class declare a static `foldPanel` object? Uses `in`
8466
+ * narrowing (no type assertion) so the property is reachable, then checks it is
8467
+ * a non-null object before trusting it as {@link FoldPanelDefaults}.
8468
+ */
8469
+ function declaresPanelDefaults(component) {
8470
+ return ("foldPanel" in component &&
8471
+ component.foldPanel !== null &&
8472
+ typeof component.foldPanel === "object");
8473
+ }
8474
+ /** Read a component's static `foldPanel` shape, or `{}` if it declares none. */
8475
+ function readComponentPanelDefaults(component) {
8476
+ return declaresPanelDefaults(component) ? component.foldPanel : {};
8477
+ }
8478
+
8431
8479
  /**
8432
8480
  * Single source of truth for the layout-owned side-panel region.
8433
8481
  *
@@ -8441,6 +8489,9 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.0.8", ngImpor
8441
8489
  */
8442
8490
  class FoldPanelHostService {
8443
8491
  rootInjector = inject(Injector);
8492
+ hostDefaults = inject(FOLD_PANEL_DEFAULTS, {
8493
+ optional: true,
8494
+ });
8444
8495
  nextId = 1;
8445
8496
  _panels = signal([], /* @ts-ignore */
8446
8497
  ...(ngDevMode ? [{ debugName: "_panels" }] : /* istanbul ignore next */ []));
@@ -8448,31 +8499,55 @@ class FoldPanelHostService {
8448
8499
  panels = this._panels.asReadonly();
8449
8500
  open(component, config = {}) {
8450
8501
  const id = this.takeId();
8502
+ const resolved = this.resolveConfig(component, config);
8451
8503
  const ref = new FoldPanelRef(id, () => this.dismiss(id));
8452
8504
  const injector = Injector.create({
8453
8505
  parent: this.rootInjector,
8454
8506
  providers: [
8455
8507
  { provide: FoldPanelRef, useValue: ref },
8456
- ...(config.providers ?? []),
8508
+ ...(resolved.providers ?? []),
8457
8509
  ],
8458
8510
  });
8459
8511
  const descriptor = {
8460
8512
  kind: "component",
8461
8513
  id,
8462
8514
  component,
8463
- data: config.data,
8464
- side: config.side ?? "right",
8465
- width: signal(config.width ?? 490),
8515
+ data: resolved.data,
8516
+ side: resolved.side ?? "right",
8517
+ width: signal(panelWidthPx(resolved.width)),
8466
8518
  injector,
8467
- ariaLabel: config.ariaLabel,
8519
+ ariaLabel: resolved.ariaLabel,
8520
+ modal: resolved.modal ?? true,
8521
+ surface: resolved.surface ?? "glass",
8522
+ disableClose: resolved.disableClose ?? false,
8468
8523
  onClose: () => ref.close(),
8469
8524
  };
8470
- if (!config.stack) {
8525
+ if (!resolved.stack) {
8471
8526
  this.closeExisting();
8472
8527
  }
8473
8528
  this.add(descriptor);
8474
8529
  return ref;
8475
8530
  }
8531
+ /**
8532
+ * Merge the three default layers into the effective config, highest priority
8533
+ * first: the per-call `config`, then the component's static `foldPanel`, then
8534
+ * the app-wide `FOLD_PANEL_DEFAULTS`. Only the defaultable fields cascade —
8535
+ * `data`/`providers`/`stack`/`ariaLabel` pass straight through from `config`.
8536
+ */
8537
+ resolveConfig(component, config) {
8538
+ const fromComponent = readComponentPanelDefaults(component);
8539
+ const fromHost = this.hostDefaults ?? {};
8540
+ return {
8541
+ ...config,
8542
+ side: config.side ?? fromComponent.side ?? fromHost.side,
8543
+ width: config.width ?? fromComponent.width ?? fromHost.width,
8544
+ modal: config.modal ?? fromComponent.modal ?? fromHost.modal,
8545
+ surface: config.surface ?? fromComponent.surface ?? fromHost.surface,
8546
+ disableClose: config.disableClose ??
8547
+ fromComponent.disableClose ??
8548
+ fromHost.disableClose,
8549
+ };
8550
+ }
8476
8551
  /**
8477
8552
  * Register a declarative (projected-template) panel; returns a handle. These
8478
8553
  * are self-managed by their `<fold-side-panel>`'s `[open]` binding, so they are
@@ -8548,16 +8623,17 @@ class FoldPanelHostComponent {
8548
8623
  /** Elements this host made `inert`, so it removes exactly those on close. */
8549
8624
  inerted = [];
8550
8625
  constructor() {
8551
- // Freeze page scroll + inert the background while any panel is open — once,
8552
- // driven by whether the panel list is non-empty.
8626
+ // Freeze page scroll + inert the background while a **modal** panel is open
8627
+ // — once, driven by whether any open panel is modal. A purely non-modal
8628
+ // panel leaves the page scrollable and interactive.
8553
8629
  effect(() => {
8554
- const open = this.panels().length > 0;
8555
- if (open && !this.locked) {
8630
+ const barrier = this.panels().some((p) => p.modal !== false);
8631
+ if (barrier && !this.locked) {
8556
8632
  this.scrollLock.lock();
8557
8633
  this.applyBackgroundBarrier();
8558
8634
  this.locked = true;
8559
8635
  }
8560
- else if (!open && this.locked) {
8636
+ else if (!barrier && this.locked) {
8561
8637
  this.scrollLock.unlock();
8562
8638
  this.removeBackgroundBarrier();
8563
8639
  this.locked = false;
@@ -8595,13 +8671,36 @@ class FoldPanelHostComponent {
8595
8671
  const top = panels[panels.length - 1];
8596
8672
  return top?.id === panel.id;
8597
8673
  }
8598
- /** Escape closes the top-most (last-opened) panel. */
8674
+ /** A panel is modal unless it explicitly opts out (`modal: false`). */
8675
+ isModal(panel) {
8676
+ return panel.modal !== false;
8677
+ }
8678
+ /** Trap focus only for the top-most **modal** panel. */
8679
+ shouldTrap(panel) {
8680
+ return this.isModal(panel) && this.isTopMost(panel);
8681
+ }
8682
+ /** Surface treatment for the panel shell; defaults to `glass`. */
8683
+ panelSurface(panel) {
8684
+ return panel.surface ?? "glass";
8685
+ }
8686
+ /**
8687
+ * The implicit dismiss gestures (Escape, backdrop) are suppressed when a panel
8688
+ * sets `disableClose` — the header close button and `FoldPanelRef.close()`
8689
+ * bypass this, so the panel stays intentionally closeable.
8690
+ */
8691
+ allowsImplicitClose(panel) {
8692
+ return panel.disableClose !== true;
8693
+ }
8694
+ /** Escape closes the top-most (last-opened) panel, unless it guards close. */
8599
8695
  onEscape() {
8600
8696
  const top = this.panels().at(-1);
8601
- top?.onClose();
8697
+ if (top && this.allowsImplicitClose(top)) {
8698
+ top.onClose();
8699
+ }
8602
8700
  }
8603
8701
  onBackdrop(event, panel) {
8604
- if (event.target === event.currentTarget) {
8702
+ if (event.target === event.currentTarget &&
8703
+ this.allowsImplicitClose(panel)) {
8605
8704
  panel.onClose();
8606
8705
  }
8607
8706
  }
@@ -8633,7 +8732,7 @@ class FoldPanelHostComponent {
8633
8732
  this.inerted = [];
8634
8733
  }
8635
8734
  static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "22.0.8", ngImport: i0, type: FoldPanelHostComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
8636
- static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "22.0.8", type: FoldPanelHostComponent, isStandalone: true, selector: "fold-panel-host", host: { listeners: { "document:keydown.escape": "onEscape()" } }, ngImport: i0, template: "@for (panel of panels(); track panel.id) {\n <div\n class=\"panel-dock\"\n [class.panel-dock--left]=\"panel.side === 'left'\"\n (click)=\"onBackdrop($event, panel)\"\n >\n <aside\n class=\"panel\"\n [class.panel--left]=\"panel.side === 'left'\"\n [style.--panel-width.px]=\"panel.width()\"\n role=\"dialog\"\n aria-modal=\"true\"\n [attr.aria-label]=\"ariaLabel(panel)\"\n [attr.aria-labelledby]=\"ariaLabelledby(panel)\"\n tabindex=\"-1\"\n [foldFocusTrap]=\"isTopMost(panel)\"\n (click)=\"$event.stopPropagation()\"\n >\n @if (panel.kind === \"template\") {\n <fold-panel-header\n [title]=\"panel.title()\"\n [subtitle]=\"panel.subtitle()\"\n (closed)=\"panel.onClose()\"\n />\n <div class=\"panel-body\">\n <ng-container [ngTemplateOutlet]=\"panel.templateRef\" />\n </div>\n } @else {\n <ng-container [foldPanelComponentOutlet]=\"panel\" />\n }\n </aside>\n </div>\n}\n", styles: ["@charset \"UTF-8\";:host{display:contents}.panel-dock{position:absolute;inset:0;z-index:50;display:flex;justify-content:flex-end}.panel-dock--left{justify-content:flex-start}.panel{--panel-width: 490px;display:flex;flex-direction:column;width:min(var(--panel-width),100%);height:100%;overflow:hidden;font-feature-settings:\"tnum\" on;background:var(--fold-color-glass);backdrop-filter:blur(var(--fold-blur-glass)) saturate(1.5);-webkit-backdrop-filter:blur(var(--fold-blur-glass)) saturate(1.5);border-left:1px solid var(--fold-color-glass-border);box-shadow:var(--fold-shadow-panel-right);animation:panel-slide-in-right .2s cubic-bezier(.4,0,.2,1)}.panel--left{border-left:none;border-right:1px solid var(--fold-color-glass-border);box-shadow:var(--fold-shadow-panel-left);animation-name:panel-slide-in-left}@media(max-width:768px){.panel{width:100vw}}.panel-body{flex:1 1 auto;overflow-y:auto;padding:var(--fold-space-lg)}@keyframes panel-slide-in-right{0%{transform:translate(100%)}to{transform:translate(0)}}@keyframes panel-slide-in-left{0%{transform:translate(-100%)}to{transform:translate(0)}}\n"], dependencies: [{ kind: "directive", type: NgTemplateOutlet, selector: "[ngTemplateOutlet]", inputs: ["ngTemplateOutletContext", "ngTemplateOutlet", "ngTemplateOutletInjector"] }, { kind: "directive", type: FocusTrapDirective, selector: "[foldFocusTrap]", inputs: ["foldFocusTrap"] }, { kind: "directive", type: FoldPanelComponentOutletDirective, selector: "[foldPanelComponentOutlet]", inputs: ["foldPanelComponentOutlet"] }, { kind: "component", type: FoldPanelHeaderComponent, selector: "fold-panel-header", inputs: ["title", "subtitle", "icon", "variant", "closeLabel"], outputs: ["closed"] }] });
8735
+ static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "22.0.8", type: FoldPanelHostComponent, isStandalone: true, selector: "fold-panel-host", host: { listeners: { "document:keydown.escape": "onEscape()" } }, ngImport: i0, template: "@for (panel of panels(); track panel.id) {\n <div\n class=\"panel-dock\"\n [class.panel-dock--left]=\"panel.side === 'left'\"\n [class.panel-dock--passthrough]=\"!isModal(panel)\"\n (click)=\"onBackdrop($event, panel)\"\n >\n <aside\n class=\"panel\"\n [class.panel--left]=\"panel.side === 'left'\"\n [attr.data-surface]=\"panelSurface(panel)\"\n [style.--panel-width.px]=\"panel.width()\"\n role=\"dialog\"\n [attr.aria-modal]=\"isModal(panel)\"\n [attr.aria-label]=\"ariaLabel(panel)\"\n [attr.aria-labelledby]=\"ariaLabelledby(panel)\"\n tabindex=\"-1\"\n [foldFocusTrap]=\"shouldTrap(panel)\"\n (click)=\"$event.stopPropagation()\"\n >\n @if (panel.kind === \"template\") {\n <fold-panel-header\n [title]=\"panel.title()\"\n [subtitle]=\"panel.subtitle()\"\n (closed)=\"panel.onClose()\"\n />\n <div class=\"panel-body\">\n <ng-container [ngTemplateOutlet]=\"panel.templateRef\" />\n </div>\n } @else {\n <ng-container [foldPanelComponentOutlet]=\"panel\" />\n }\n </aside>\n </div>\n}\n", styles: ["@charset \"UTF-8\";:host{display:contents}.panel-dock{position:absolute;inset:0;z-index:50;display:flex;justify-content:flex-end}.panel-dock--left{justify-content:flex-start}.panel-dock--passthrough{pointer-events:none}.panel-dock--passthrough .panel{pointer-events:auto}.panel{--panel-width: 490px;display:flex;flex-direction:column;width:min(var(--panel-width),100%);height:100%;overflow:hidden;font-feature-settings:\"tnum\" on;background:var(--fold-color-glass);backdrop-filter:blur(var(--fold-blur-glass)) saturate(1.5);-webkit-backdrop-filter:blur(var(--fold-blur-glass)) saturate(1.5);border-left:1px solid var(--fold-color-glass-border);box-shadow:var(--fold-shadow-panel-right);animation:panel-slide-in-right .2s cubic-bezier(.4,0,.2,1)}.panel--left{border-left:none;border-right:1px solid var(--fold-color-glass-border);box-shadow:var(--fold-shadow-panel-left);animation-name:panel-slide-in-left}.panel[data-surface=solid]{background:var(--fold-color-surface-card);backdrop-filter:none;-webkit-backdrop-filter:none;border-color:var(--fold-color-border)}@media(max-width:768px){.panel{width:100vw}}.panel-body{flex:1 1 auto;overflow-y:auto;padding:var(--fold-space-lg)}@keyframes panel-slide-in-right{0%{transform:translate(100%)}to{transform:translate(0)}}@keyframes panel-slide-in-left{0%{transform:translate(-100%)}to{transform:translate(0)}}\n"], dependencies: [{ kind: "directive", type: NgTemplateOutlet, selector: "[ngTemplateOutlet]", inputs: ["ngTemplateOutletContext", "ngTemplateOutlet", "ngTemplateOutletInjector"] }, { kind: "directive", type: FocusTrapDirective, selector: "[foldFocusTrap]", inputs: ["foldFocusTrap"] }, { kind: "directive", type: FoldPanelComponentOutletDirective, selector: "[foldPanelComponentOutlet]", inputs: ["foldPanelComponentOutlet"] }, { kind: "component", type: FoldPanelHeaderComponent, selector: "fold-panel-header", inputs: ["title", "subtitle", "icon", "variant", "closeLabel"], outputs: ["closed"] }] });
8637
8736
  }
8638
8737
  i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.0.8", ngImport: i0, type: FoldPanelHostComponent, decorators: [{
8639
8738
  type: Component,
@@ -8642,7 +8741,7 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.0.8", ngImpor
8642
8741
  FocusTrapDirective,
8643
8742
  FoldPanelComponentOutletDirective,
8644
8743
  FoldPanelHeaderComponent,
8645
- ], template: "@for (panel of panels(); track panel.id) {\n <div\n class=\"panel-dock\"\n [class.panel-dock--left]=\"panel.side === 'left'\"\n (click)=\"onBackdrop($event, panel)\"\n >\n <aside\n class=\"panel\"\n [class.panel--left]=\"panel.side === 'left'\"\n [style.--panel-width.px]=\"panel.width()\"\n role=\"dialog\"\n aria-modal=\"true\"\n [attr.aria-label]=\"ariaLabel(panel)\"\n [attr.aria-labelledby]=\"ariaLabelledby(panel)\"\n tabindex=\"-1\"\n [foldFocusTrap]=\"isTopMost(panel)\"\n (click)=\"$event.stopPropagation()\"\n >\n @if (panel.kind === \"template\") {\n <fold-panel-header\n [title]=\"panel.title()\"\n [subtitle]=\"panel.subtitle()\"\n (closed)=\"panel.onClose()\"\n />\n <div class=\"panel-body\">\n <ng-container [ngTemplateOutlet]=\"panel.templateRef\" />\n </div>\n } @else {\n <ng-container [foldPanelComponentOutlet]=\"panel\" />\n }\n </aside>\n </div>\n}\n", styles: ["@charset \"UTF-8\";:host{display:contents}.panel-dock{position:absolute;inset:0;z-index:50;display:flex;justify-content:flex-end}.panel-dock--left{justify-content:flex-start}.panel{--panel-width: 490px;display:flex;flex-direction:column;width:min(var(--panel-width),100%);height:100%;overflow:hidden;font-feature-settings:\"tnum\" on;background:var(--fold-color-glass);backdrop-filter:blur(var(--fold-blur-glass)) saturate(1.5);-webkit-backdrop-filter:blur(var(--fold-blur-glass)) saturate(1.5);border-left:1px solid var(--fold-color-glass-border);box-shadow:var(--fold-shadow-panel-right);animation:panel-slide-in-right .2s cubic-bezier(.4,0,.2,1)}.panel--left{border-left:none;border-right:1px solid var(--fold-color-glass-border);box-shadow:var(--fold-shadow-panel-left);animation-name:panel-slide-in-left}@media(max-width:768px){.panel{width:100vw}}.panel-body{flex:1 1 auto;overflow-y:auto;padding:var(--fold-space-lg)}@keyframes panel-slide-in-right{0%{transform:translate(100%)}to{transform:translate(0)}}@keyframes panel-slide-in-left{0%{transform:translate(-100%)}to{transform:translate(0)}}\n"] }]
8744
+ ], template: "@for (panel of panels(); track panel.id) {\n <div\n class=\"panel-dock\"\n [class.panel-dock--left]=\"panel.side === 'left'\"\n [class.panel-dock--passthrough]=\"!isModal(panel)\"\n (click)=\"onBackdrop($event, panel)\"\n >\n <aside\n class=\"panel\"\n [class.panel--left]=\"panel.side === 'left'\"\n [attr.data-surface]=\"panelSurface(panel)\"\n [style.--panel-width.px]=\"panel.width()\"\n role=\"dialog\"\n [attr.aria-modal]=\"isModal(panel)\"\n [attr.aria-label]=\"ariaLabel(panel)\"\n [attr.aria-labelledby]=\"ariaLabelledby(panel)\"\n tabindex=\"-1\"\n [foldFocusTrap]=\"shouldTrap(panel)\"\n (click)=\"$event.stopPropagation()\"\n >\n @if (panel.kind === \"template\") {\n <fold-panel-header\n [title]=\"panel.title()\"\n [subtitle]=\"panel.subtitle()\"\n (closed)=\"panel.onClose()\"\n />\n <div class=\"panel-body\">\n <ng-container [ngTemplateOutlet]=\"panel.templateRef\" />\n </div>\n } @else {\n <ng-container [foldPanelComponentOutlet]=\"panel\" />\n }\n </aside>\n </div>\n}\n", styles: ["@charset \"UTF-8\";:host{display:contents}.panel-dock{position:absolute;inset:0;z-index:50;display:flex;justify-content:flex-end}.panel-dock--left{justify-content:flex-start}.panel-dock--passthrough{pointer-events:none}.panel-dock--passthrough .panel{pointer-events:auto}.panel{--panel-width: 490px;display:flex;flex-direction:column;width:min(var(--panel-width),100%);height:100%;overflow:hidden;font-feature-settings:\"tnum\" on;background:var(--fold-color-glass);backdrop-filter:blur(var(--fold-blur-glass)) saturate(1.5);-webkit-backdrop-filter:blur(var(--fold-blur-glass)) saturate(1.5);border-left:1px solid var(--fold-color-glass-border);box-shadow:var(--fold-shadow-panel-right);animation:panel-slide-in-right .2s cubic-bezier(.4,0,.2,1)}.panel--left{border-left:none;border-right:1px solid var(--fold-color-glass-border);box-shadow:var(--fold-shadow-panel-left);animation-name:panel-slide-in-left}.panel[data-surface=solid]{background:var(--fold-color-surface-card);backdrop-filter:none;-webkit-backdrop-filter:none;border-color:var(--fold-color-border)}@media(max-width:768px){.panel{width:100vw}}.panel-body{flex:1 1 auto;overflow-y:auto;padding:var(--fold-space-lg)}@keyframes panel-slide-in-right{0%{transform:translate(100%)}to{transform:translate(0)}}@keyframes panel-slide-in-left{0%{transform:translate(-100%)}to{transform:translate(0)}}\n"] }]
8646
8745
  }], ctorParameters: () => [], propDecorators: { onEscape: [{
8647
8746
  type: HostListener,
8648
8747
  args: ["document:keydown.escape"]
@@ -8936,5 +9035,5 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.0.8", ngImpor
8936
9035
  * Generated bundle index. Do not edit.
8937
9036
  */
8938
9037
 
8939
- export { FOLD_AUTO_PALETTES, FOLD_BLUR_TOKENS, FOLD_BUILTIN_ICONS, FOLD_DATA_TABLE_DEFAULT_LABELS, FOLD_DATA_TABLE_LABELS, FOLD_INLINE_CONFIRM_DEFAULT_LABELS, FOLD_INLINE_CONFIRM_LABELS, FOLD_MOTION_TOKENS, FOLD_PAGINATOR_DEFAULT_LABELS, FOLD_PAGINATOR_LABELS, FOLD_PALETTE_DEFAULT, FOLD_PANEL_CLOSE_LABEL, FOLD_RADIUS_TOKENS, FOLD_SEMANTIC_COLOR_TOKENS, FOLD_SHADOW_TOKENS, FOLD_SPACE_TOKENS, FOLD_TEXT_TOKENS, FOLD_TOAST_CONFIG, FoldAppShellComponent, FoldAsideLayoutComponent, FoldAvatarComponent, FoldAvatarDetailComponent, FoldAvatarListComponent, FoldBadgeComponent, FoldButtonComponent, FoldButtonIconComponent, FoldCalloutComponent, FoldCardComponent, FoldCheckboxComponent, FoldChoiceRowComponent, FoldContextCardComponent, FoldDataTableCellDirective, FoldDataTableComponent, FoldDataTableRowCardDirective, FoldDisclosureComponent, FoldDropdownComponent, FoldDropdownItemComponent, FoldElementTitleComponent, FoldElevatedDirective, FoldEmptyStateComponent, FoldFieldComponent, FoldFieldIdDirective, FoldFieldListComponent, FoldFileDropzoneComponent, FoldHeroCardComponent, FoldHeroSectionComponent, FoldIconComponent, FoldIconRegistry, FoldIdService, FoldInlineConfirmComponent, FoldInputComponent, FoldLinkComponent, FoldListboxComponent, FoldLoadingStateComponent, FoldMenuComponent, FoldMenuItemComponent, FoldMenuSectionComponent, FoldMenuSeparatorComponent, FoldMultiselectComponent, FoldNavLauncherComponent, FoldNavLayoutComponent, FoldNavTileComponent, FoldNumberInputComponent, FoldOptionComponent, FoldPageLayoutComponent, FoldPageSectionComponent, FoldPageTitleDirective, FoldPaginatorComponent, FoldPaletteRegistry, FoldPanelComponentOutletDirective, FoldPanelHeaderComponent, FoldPanelHostComponent, FoldPanelHostService, FoldPanelRef, FoldPanelToggle, FoldPasswordFieldComponent, FoldPopoverComponent, FoldPopoverTriggerDirective, FoldRangeSliderComponent, FoldRepeatPressDirective, FoldSearchComponent, FoldSelectComponent, FoldSliderComponent, FoldSpinnerComponent, FoldStatusBadgeComponent, FoldStickyColumnDirective, FoldSurfaceDirective, FoldTabPanelComponent, FoldTabsComponent, FoldTimelineComponent, FoldToastComponent, FoldToastContainerComponent, FoldToastService, FoldToggleIconComponent, FoldViewNavComponent, FoldViewToggleComponent, autoUpdate, computePlacement, foldBlurVar, foldCardBandChrome, foldColorProperty, foldColorVar, foldDefaultPasswordRules, foldHashSeed, foldMotionVar, foldRadiusVar, foldRegexRule, foldResolvePalette, foldShadowVar, foldSpaceVar, foldTextVar, observeElementWidth, provideFoldDataTableLabels, provideFoldIcons, provideFoldInlineConfirmLabels, provideFoldPaginatorLabels, provideFoldPalette, provideFoldPanelLabels, provideFoldToasts };
9038
+ export { FOLD_AUTO_PALETTES, FOLD_BLUR_TOKENS, FOLD_BUILTIN_ICONS, FOLD_DATA_TABLE_DEFAULT_LABELS, FOLD_DATA_TABLE_LABELS, FOLD_INLINE_CONFIRM_DEFAULT_LABELS, FOLD_INLINE_CONFIRM_LABELS, FOLD_MOTION_TOKENS, FOLD_PAGINATOR_DEFAULT_LABELS, FOLD_PAGINATOR_LABELS, FOLD_PALETTE_DEFAULT, FOLD_PANEL_CLOSE_LABEL, FOLD_PANEL_DEFAULTS, FOLD_RADIUS_TOKENS, FOLD_SEMANTIC_COLOR_TOKENS, FOLD_SHADOW_TOKENS, FOLD_SPACE_TOKENS, FOLD_TEXT_TOKENS, FOLD_TOAST_CONFIG, FoldAppShellComponent, FoldAsideLayoutComponent, FoldAvatarComponent, FoldAvatarDetailComponent, FoldAvatarListComponent, FoldBadgeComponent, FoldButtonComponent, FoldButtonIconComponent, FoldCalloutComponent, FoldCardComponent, FoldCheckboxComponent, FoldChoiceRowComponent, FoldContextCardComponent, FoldDataTableCellDirective, FoldDataTableComponent, FoldDataTableRowCardDirective, FoldDisclosureComponent, FoldDropdownComponent, FoldDropdownItemComponent, FoldElementTitleComponent, FoldElevatedDirective, FoldEmptyStateComponent, FoldFieldComponent, FoldFieldIdDirective, FoldFieldListComponent, FoldFileDropzoneComponent, FoldHeroCardComponent, FoldHeroSectionComponent, FoldIconComponent, FoldIconRegistry, FoldIdService, FoldInlineConfirmComponent, FoldInputComponent, FoldLinkComponent, FoldListboxComponent, FoldLoadingStateComponent, FoldMenuComponent, FoldMenuItemComponent, FoldMenuSectionComponent, FoldMenuSeparatorComponent, FoldMultiselectComponent, FoldNavLauncherComponent, FoldNavLayoutComponent, FoldNavTileComponent, FoldNumberInputComponent, FoldOptionComponent, FoldPageLayoutComponent, FoldPageSectionComponent, FoldPageTitleDirective, FoldPaginatorComponent, FoldPaletteRegistry, FoldPanelComponentOutletDirective, FoldPanelHeaderComponent, FoldPanelHostComponent, FoldPanelHostService, FoldPanelRef, FoldPanelToggle, FoldPasswordFieldComponent, FoldPopoverComponent, FoldPopoverTriggerDirective, FoldRangeSliderComponent, FoldRepeatPressDirective, FoldSearchComponent, FoldSelectComponent, FoldSliderComponent, FoldSpinnerComponent, FoldStatusBadgeComponent, FoldStickyColumnDirective, FoldSurfaceDirective, FoldTabPanelComponent, FoldTabsComponent, FoldTimelineComponent, FoldToastComponent, FoldToastContainerComponent, FoldToastService, FoldToggleIconComponent, FoldViewNavComponent, FoldViewToggleComponent, autoUpdate, computePlacement, foldBlurVar, foldCardBandChrome, foldColorProperty, foldColorVar, foldDefaultPasswordRules, foldHashSeed, foldMotionVar, foldRadiusVar, foldRegexRule, foldResolvePalette, foldShadowVar, foldSpaceVar, foldTextVar, observeElementWidth, provideFoldDataTableLabels, provideFoldIcons, provideFoldInlineConfirmLabels, provideFoldPaginatorLabels, provideFoldPalette, provideFoldPanelDefaults, provideFoldPanelLabels, provideFoldToasts };
8940
9039
  //# sourceMappingURL=fold-ng.mjs.map