fold-ng 0.28.0 → 0.28.2
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 +37 -1
- package/fesm2022/fold-ng.mjs +48 -16
- package/fesm2022/fold-ng.mjs.map +1 -1
- package/package.json +1 -1
- package/tmp-esm2022/tsconfig.lib.tsbuildinfo +1 -1
- package/types/fold-ng.d.ts +22 -4
- package/types/fold-ng.d.ts.map +1 -1
package/CHANGELOG.md
CHANGED
|
@@ -8,6 +8,40 @@ All notable changes to **fold-ng** are documented here. The format follows
|
|
|
8
8
|
|
|
9
9
|
_Nothing yet._
|
|
10
10
|
|
|
11
|
+
## [0.28.2] - 2026-10-13
|
|
12
|
+
|
|
13
|
+
### Fixed
|
|
14
|
+
|
|
15
|
+
- **`fold-menu` replié défile.** Replié, le corps du menu gardait
|
|
16
|
+
`overflow: visible` pour laisser sortir les infobulles : un menu plus haut
|
|
17
|
+
que l'écran débordait et ses entrées se tassaient. Le corps défile désormais
|
|
18
|
+
dans les deux états (barre masquée replié), les entrées ne rétrécissent plus
|
|
19
|
+
(`flex-shrink: 0`), et l'infobulle passe en `position: fixed`, placée au
|
|
20
|
+
survol (`--mi-tip-x/y`), pour échapper au défilement.
|
|
21
|
+
|
|
22
|
+
### Changed
|
|
23
|
+
|
|
24
|
+
- **`fold-menu-section` déplié : un retrait et une barre de couleur.** Menu
|
|
25
|
+
déplié, les entrées d'une section ont un léger retrait derrière une barre
|
|
26
|
+
verticale à la couleur de la section, pour les distinguer du premier niveau.
|
|
27
|
+
Le rail replié ne change pas.
|
|
28
|
+
|
|
29
|
+
## [0.28.1] - 2026-10-06
|
|
30
|
+
|
|
31
|
+
### Fixed
|
|
32
|
+
|
|
33
|
+
- **`fold-nav-launcher` défile au niveau 1.** La grille portait les tuiles dans
|
|
34
|
+
un corps `overflow: hidden` : au-delà d'un écran, les dernières tuiles étaient
|
|
35
|
+
coupées et inatteignables (iPad). C'est la grille qui défile désormais
|
|
36
|
+
(`overflow-y: auto; overscroll-behavior: contain`) — pas le corps, sans quoi
|
|
37
|
+
la feuille du niveau 2 s'ouvrirait décalée — et le pied reste en place.
|
|
38
|
+
- **`fold-nav-launcher` : des tuiles de taille bornée sur tablette.** En
|
|
39
|
+
`columns="auto"` (défaut) la largeur décide : `auto-fill` avec un minimum de
|
|
40
|
+
96 px (144 px pour ≤4 éléments). Téléphone inchangé (3 colonnes, ou 2), iPad
|
|
41
|
+
7 colonnes de ~96 px au lieu de 2 de ~370 px. La grille est plafonnée à
|
|
42
|
+
`--fold-nav-launcher-max-width` (720 px), centrée — y compris avec un
|
|
43
|
+
`columns` numérique, qui reste prioritaire.
|
|
44
|
+
|
|
11
45
|
## [0.28.0] - 2026-10-05
|
|
12
46
|
|
|
13
47
|
### Added
|
|
@@ -2622,7 +2656,9 @@ design-token stylesheet.
|
|
|
2622
2656
|
`currentColor`; `prefers-reduced-motion` + `forced-colors` are respected;
|
|
2623
2657
|
strings localise via inputs / providers (`provideFoldPanelLabels`).
|
|
2624
2658
|
|
|
2625
|
-
[unreleased]: https://github.com/hugoheynard/fold-ng/compare/v0.28.
|
|
2659
|
+
[unreleased]: https://github.com/hugoheynard/fold-ng/compare/v0.28.2...HEAD
|
|
2660
|
+
[0.28.2]: https://github.com/hugoheynard/fold-ng/releases/tag/v0.28.2
|
|
2661
|
+
[0.28.1]: https://github.com/hugoheynard/fold-ng/releases/tag/v0.28.1
|
|
2626
2662
|
[0.28.0]: https://github.com/hugoheynard/fold-ng/releases/tag/v0.28.0
|
|
2627
2663
|
[0.27.2]: https://github.com/hugoheynard/fold-ng/releases/tag/v0.27.2
|
|
2628
2664
|
[0.27.1]: https://github.com/hugoheynard/fold-ng/releases/tag/v0.27.1
|
package/fesm2022/fold-ng.mjs
CHANGED
|
@@ -4359,7 +4359,7 @@ class FoldMenuComponent {
|
|
|
4359
4359
|
this.expanded.set(!this.isExpanded());
|
|
4360
4360
|
}
|
|
4361
4361
|
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "22.0.8", ngImport: i0, type: FoldMenuComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
|
|
4362
|
-
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "22.0.8", type: FoldMenuComponent, isStandalone: true, selector: "fold-menu", inputs: { collapsible: { classPropertyName: "collapsible", publicName: "collapsible", isSignal: true, isRequired: false, transformFunction: null }, expanded: { classPropertyName: "expanded", publicName: "expanded", isSignal: true, isRequired: false, transformFunction: null }, tint: { classPropertyName: "tint", publicName: "tint", isSignal: true, isRequired: false, transformFunction: null }, level: { classPropertyName: "level", publicName: "level", isSignal: true, isRequired: false, transformFunction: null }, togglePlacement: { classPropertyName: "togglePlacement", publicName: "togglePlacement", isSignal: true, isRequired: false, transformFunction: null }, navLabel: { classPropertyName: "navLabel", publicName: "navLabel", isSignal: true, isRequired: false, transformFunction: null } }, outputs: { expanded: "expandedChange" }, host: { properties: { "class.expanded": "isExpanded()", "attr.data-tint": "tint()", "attr.data-level": "level()" } }, viewQueries: [{ propertyName: "headRef", first: true, predicate: ["head"], descendants: true, isSignal: true }, { propertyName: "footRef", first: true, predicate: ["foot"], descendants: true, isSignal: true }], ngImport: i0, template: "<div\n class=\"menu-head\"\n [class.head-has-toggle]=\"collapsible() && resolvedPlacement() === 'header'\"\n #head\n>\n <ng-content select=\"[header]\" />\n @if (collapsible() && resolvedPlacement() === \"header\") {\n <ng-container [ngTemplateOutlet]=\"toggleTpl\" />\n }\n</div>\n\n<nav class=\"menu-body\" [attr.aria-label]=\"navLabel() ?? null\">\n <ng-content />\n @if (collapsible() && resolvedPlacement() === \"body\") {\n <ng-container [ngTemplateOutlet]=\"toggleTpl\" />\n }\n</nav>\n\n<div\n class=\"menu-foot\"\n [class.foot-has-toggle]=\"collapsible() && resolvedPlacement() === 'footer'\"\n #foot\n>\n @if (collapsible() && resolvedPlacement() === \"footer\") {\n <ng-container [ngTemplateOutlet]=\"toggleTpl\" />\n }\n <ng-content select=\"[footer]\" />\n</div>\n\n<ng-template #toggleTpl>\n <button\n type=\"button\"\n class=\"menu-toggle\"\n [attr.aria-label]=\"isExpanded() ? 'Collapse menu' : 'Expand menu'\"\n (click)=\"toggle()\"\n >\n <fold-icon\n [name]=\"isExpanded() ? 'chevron-left' : 'chevron-right'\"\n [size]=\"14\"\n />\n </button>\n</ng-template>\n", styles: ["@charset \"UTF-8\";:host{display:flex;flex-direction:column;align-items:center;width:var(--fold-shell-rail-width, var(--fold-rail-primary, 64px));height:100%;box-sizing:border-box;padding:var(--fold-space-sm) 0;gap:var(--fold-space-xs);background:var(--fold-color-bg-rail-primary);border-right:1px solid var(--fold-color-border);overflow:visible;-webkit-user-select:none;user-select:none;transition:width var(--fold-motion-base)}:host([data-level=secondary]){background:var(--fold-color-bg-rail-secondary)}:host([data-level=tertiary]){background:var(--fold-color-bg-rail-tertiary)}:host([data-elevated]){border-right:none}:host(.expanded){width:max-content;min-width:190px;max-width:260px;align-items:stretch}.menu-head,.menu-foot{flex-shrink:0;display:flex;flex-direction:column;align-items:center;gap:var(--fold-space-xs);width:100%}.menu-head:empty,.menu-foot:empty{display:none}.menu-head{padding-bottom:var(--fold-space-sm);border-bottom:1px solid var(--fold-color-border-subtle)}.menu-foot{padding-top:var(--fold-space-sm);border-top:1px solid var(--fold-color-border-subtle)}:host(.expanded) .menu-head,:host(.expanded) .menu-foot{align-items:stretch;width:auto;padding-left:var(--fold-space-sm);padding-right:var(--fold-space-sm)}.menu-body{flex:1;display:flex;flex-direction:column;align-items:center;gap:var(--fold-space-xs);width:100
|
|
4362
|
+
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "22.0.8", type: FoldMenuComponent, isStandalone: true, selector: "fold-menu", inputs: { collapsible: { classPropertyName: "collapsible", publicName: "collapsible", isSignal: true, isRequired: false, transformFunction: null }, expanded: { classPropertyName: "expanded", publicName: "expanded", isSignal: true, isRequired: false, transformFunction: null }, tint: { classPropertyName: "tint", publicName: "tint", isSignal: true, isRequired: false, transformFunction: null }, level: { classPropertyName: "level", publicName: "level", isSignal: true, isRequired: false, transformFunction: null }, togglePlacement: { classPropertyName: "togglePlacement", publicName: "togglePlacement", isSignal: true, isRequired: false, transformFunction: null }, navLabel: { classPropertyName: "navLabel", publicName: "navLabel", isSignal: true, isRequired: false, transformFunction: null } }, outputs: { expanded: "expandedChange" }, host: { properties: { "class.expanded": "isExpanded()", "attr.data-tint": "tint()", "attr.data-level": "level()" } }, viewQueries: [{ propertyName: "headRef", first: true, predicate: ["head"], descendants: true, isSignal: true }, { propertyName: "footRef", first: true, predicate: ["foot"], descendants: true, isSignal: true }], ngImport: i0, template: "<div\n class=\"menu-head\"\n [class.head-has-toggle]=\"collapsible() && resolvedPlacement() === 'header'\"\n #head\n>\n <ng-content select=\"[header]\" />\n @if (collapsible() && resolvedPlacement() === \"header\") {\n <ng-container [ngTemplateOutlet]=\"toggleTpl\" />\n }\n</div>\n\n<nav class=\"menu-body\" [attr.aria-label]=\"navLabel() ?? null\">\n <ng-content />\n @if (collapsible() && resolvedPlacement() === \"body\") {\n <ng-container [ngTemplateOutlet]=\"toggleTpl\" />\n }\n</nav>\n\n<div\n class=\"menu-foot\"\n [class.foot-has-toggle]=\"collapsible() && resolvedPlacement() === 'footer'\"\n #foot\n>\n @if (collapsible() && resolvedPlacement() === \"footer\") {\n <ng-container [ngTemplateOutlet]=\"toggleTpl\" />\n }\n <ng-content select=\"[footer]\" />\n</div>\n\n<ng-template #toggleTpl>\n <button\n type=\"button\"\n class=\"menu-toggle\"\n [attr.aria-label]=\"isExpanded() ? 'Collapse menu' : 'Expand menu'\"\n (click)=\"toggle()\"\n >\n <fold-icon\n [name]=\"isExpanded() ? 'chevron-left' : 'chevron-right'\"\n [size]=\"14\"\n />\n </button>\n</ng-template>\n", styles: ["@charset \"UTF-8\";:host{display:flex;flex-direction:column;align-items:center;width:var(--fold-shell-rail-width, var(--fold-rail-primary, 64px));height:100%;box-sizing:border-box;padding:var(--fold-space-sm) 0;gap:var(--fold-space-xs);background:var(--fold-color-bg-rail-primary);border-right:1px solid var(--fold-color-border);overflow:visible;-webkit-user-select:none;user-select:none;transition:width var(--fold-motion-base)}:host([data-level=secondary]){background:var(--fold-color-bg-rail-secondary)}:host([data-level=tertiary]){background:var(--fold-color-bg-rail-tertiary)}:host([data-elevated]){border-right:none}:host(.expanded){width:max-content;min-width:190px;max-width:260px;align-items:stretch}.menu-head,.menu-foot{flex-shrink:0;display:flex;flex-direction:column;align-items:center;gap:var(--fold-space-xs);width:100%}.menu-head:empty,.menu-foot:empty{display:none}.menu-head{padding-bottom:var(--fold-space-sm);border-bottom:1px solid var(--fold-color-border-subtle)}.menu-foot{padding-top:var(--fold-space-sm);border-top:1px solid var(--fold-color-border-subtle)}:host(.expanded) .menu-head,:host(.expanded) .menu-foot{align-items:stretch;width:auto;padding-left:var(--fold-space-sm);padding-right:var(--fold-space-sm)}.menu-body{flex:1;display:flex;flex-direction:column;align-items:center;gap:var(--fold-space-xs);width:100%;min-height:0;overflow-y:auto;overscroll-behavior:contain;scrollbar-width:none}.menu-body::-webkit-scrollbar{display:none}:host(.expanded) .menu-body{align-items:stretch;width:auto;padding:0 var(--fold-space-sm);scrollbar-width:thin}.menu-toggle{flex-shrink:0;width:28px;height:28px;display:grid;place-items:center;border:none;border-radius:var(--fold-radius-sm);background:none;color:var(--fold-color-text-muted);cursor:pointer;transition:background var(--fold-motion-fast),color var(--fold-motion-fast)}.menu-toggle:hover{background:var(--fold-color-surface-hover);color:var(--fold-color-text-secondary)}:host(.expanded) .menu-toggle{align-self:flex-end;margin-right:var(--fold-space-sm)}:host(.expanded) .menu-head.head-has-toggle,:host(.expanded) .menu-foot.foot-has-toggle{position:relative;padding-right:var(--fold-space-4xl)}:host(.expanded) .menu-head.head-has-toggle .menu-toggle,:host(.expanded) .menu-foot.foot-has-toggle .menu-toggle{position:absolute;right:8px;bottom:8px;margin:0}\n"], dependencies: [{ kind: "component", type: FoldIconComponent, selector: "fold-icon", inputs: ["name", "size", "tone", "title"] }, { kind: "directive", type: NgTemplateOutlet, selector: "[ngTemplateOutlet]", inputs: ["ngTemplateOutletContext", "ngTemplateOutlet", "ngTemplateOutletInjector"] }] });
|
|
4363
4363
|
}
|
|
4364
4364
|
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.0.8", ngImport: i0, type: FoldMenuComponent, decorators: [{
|
|
4365
4365
|
type: Component,
|
|
@@ -4367,7 +4367,7 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.0.8", ngImpor
|
|
|
4367
4367
|
"[class.expanded]": "isExpanded()",
|
|
4368
4368
|
"[attr.data-tint]": "tint()",
|
|
4369
4369
|
"[attr.data-level]": "level()",
|
|
4370
|
-
}, template: "<div\n class=\"menu-head\"\n [class.head-has-toggle]=\"collapsible() && resolvedPlacement() === 'header'\"\n #head\n>\n <ng-content select=\"[header]\" />\n @if (collapsible() && resolvedPlacement() === \"header\") {\n <ng-container [ngTemplateOutlet]=\"toggleTpl\" />\n }\n</div>\n\n<nav class=\"menu-body\" [attr.aria-label]=\"navLabel() ?? null\">\n <ng-content />\n @if (collapsible() && resolvedPlacement() === \"body\") {\n <ng-container [ngTemplateOutlet]=\"toggleTpl\" />\n }\n</nav>\n\n<div\n class=\"menu-foot\"\n [class.foot-has-toggle]=\"collapsible() && resolvedPlacement() === 'footer'\"\n #foot\n>\n @if (collapsible() && resolvedPlacement() === \"footer\") {\n <ng-container [ngTemplateOutlet]=\"toggleTpl\" />\n }\n <ng-content select=\"[footer]\" />\n</div>\n\n<ng-template #toggleTpl>\n <button\n type=\"button\"\n class=\"menu-toggle\"\n [attr.aria-label]=\"isExpanded() ? 'Collapse menu' : 'Expand menu'\"\n (click)=\"toggle()\"\n >\n <fold-icon\n [name]=\"isExpanded() ? 'chevron-left' : 'chevron-right'\"\n [size]=\"14\"\n />\n </button>\n</ng-template>\n", styles: ["@charset \"UTF-8\";:host{display:flex;flex-direction:column;align-items:center;width:var(--fold-shell-rail-width, var(--fold-rail-primary, 64px));height:100%;box-sizing:border-box;padding:var(--fold-space-sm) 0;gap:var(--fold-space-xs);background:var(--fold-color-bg-rail-primary);border-right:1px solid var(--fold-color-border);overflow:visible;-webkit-user-select:none;user-select:none;transition:width var(--fold-motion-base)}:host([data-level=secondary]){background:var(--fold-color-bg-rail-secondary)}:host([data-level=tertiary]){background:var(--fold-color-bg-rail-tertiary)}:host([data-elevated]){border-right:none}:host(.expanded){width:max-content;min-width:190px;max-width:260px;align-items:stretch}.menu-head,.menu-foot{flex-shrink:0;display:flex;flex-direction:column;align-items:center;gap:var(--fold-space-xs);width:100%}.menu-head:empty,.menu-foot:empty{display:none}.menu-head{padding-bottom:var(--fold-space-sm);border-bottom:1px solid var(--fold-color-border-subtle)}.menu-foot{padding-top:var(--fold-space-sm);border-top:1px solid var(--fold-color-border-subtle)}:host(.expanded) .menu-head,:host(.expanded) .menu-foot{align-items:stretch;width:auto;padding-left:var(--fold-space-sm);padding-right:var(--fold-space-sm)}.menu-body{flex:1;display:flex;flex-direction:column;align-items:center;gap:var(--fold-space-xs);width:100
|
|
4370
|
+
}, template: "<div\n class=\"menu-head\"\n [class.head-has-toggle]=\"collapsible() && resolvedPlacement() === 'header'\"\n #head\n>\n <ng-content select=\"[header]\" />\n @if (collapsible() && resolvedPlacement() === \"header\") {\n <ng-container [ngTemplateOutlet]=\"toggleTpl\" />\n }\n</div>\n\n<nav class=\"menu-body\" [attr.aria-label]=\"navLabel() ?? null\">\n <ng-content />\n @if (collapsible() && resolvedPlacement() === \"body\") {\n <ng-container [ngTemplateOutlet]=\"toggleTpl\" />\n }\n</nav>\n\n<div\n class=\"menu-foot\"\n [class.foot-has-toggle]=\"collapsible() && resolvedPlacement() === 'footer'\"\n #foot\n>\n @if (collapsible() && resolvedPlacement() === \"footer\") {\n <ng-container [ngTemplateOutlet]=\"toggleTpl\" />\n }\n <ng-content select=\"[footer]\" />\n</div>\n\n<ng-template #toggleTpl>\n <button\n type=\"button\"\n class=\"menu-toggle\"\n [attr.aria-label]=\"isExpanded() ? 'Collapse menu' : 'Expand menu'\"\n (click)=\"toggle()\"\n >\n <fold-icon\n [name]=\"isExpanded() ? 'chevron-left' : 'chevron-right'\"\n [size]=\"14\"\n />\n </button>\n</ng-template>\n", styles: ["@charset \"UTF-8\";:host{display:flex;flex-direction:column;align-items:center;width:var(--fold-shell-rail-width, var(--fold-rail-primary, 64px));height:100%;box-sizing:border-box;padding:var(--fold-space-sm) 0;gap:var(--fold-space-xs);background:var(--fold-color-bg-rail-primary);border-right:1px solid var(--fold-color-border);overflow:visible;-webkit-user-select:none;user-select:none;transition:width var(--fold-motion-base)}:host([data-level=secondary]){background:var(--fold-color-bg-rail-secondary)}:host([data-level=tertiary]){background:var(--fold-color-bg-rail-tertiary)}:host([data-elevated]){border-right:none}:host(.expanded){width:max-content;min-width:190px;max-width:260px;align-items:stretch}.menu-head,.menu-foot{flex-shrink:0;display:flex;flex-direction:column;align-items:center;gap:var(--fold-space-xs);width:100%}.menu-head:empty,.menu-foot:empty{display:none}.menu-head{padding-bottom:var(--fold-space-sm);border-bottom:1px solid var(--fold-color-border-subtle)}.menu-foot{padding-top:var(--fold-space-sm);border-top:1px solid var(--fold-color-border-subtle)}:host(.expanded) .menu-head,:host(.expanded) .menu-foot{align-items:stretch;width:auto;padding-left:var(--fold-space-sm);padding-right:var(--fold-space-sm)}.menu-body{flex:1;display:flex;flex-direction:column;align-items:center;gap:var(--fold-space-xs);width:100%;min-height:0;overflow-y:auto;overscroll-behavior:contain;scrollbar-width:none}.menu-body::-webkit-scrollbar{display:none}:host(.expanded) .menu-body{align-items:stretch;width:auto;padding:0 var(--fold-space-sm);scrollbar-width:thin}.menu-toggle{flex-shrink:0;width:28px;height:28px;display:grid;place-items:center;border:none;border-radius:var(--fold-radius-sm);background:none;color:var(--fold-color-text-muted);cursor:pointer;transition:background var(--fold-motion-fast),color var(--fold-motion-fast)}.menu-toggle:hover{background:var(--fold-color-surface-hover);color:var(--fold-color-text-secondary)}:host(.expanded) .menu-toggle{align-self:flex-end;margin-right:var(--fold-space-sm)}:host(.expanded) .menu-head.head-has-toggle,:host(.expanded) .menu-foot.foot-has-toggle{position:relative;padding-right:var(--fold-space-4xl)}:host(.expanded) .menu-head.head-has-toggle .menu-toggle,:host(.expanded) .menu-foot.foot-has-toggle .menu-toggle{position:absolute;right:8px;bottom:8px;margin:0}\n"] }]
|
|
4371
4371
|
}], ctorParameters: () => [], propDecorators: { collapsible: [{ type: i0.Input, args: [{ isSignal: true, alias: "collapsible", required: false }] }], expanded: [{ type: i0.Input, args: [{ isSignal: true, alias: "expanded", required: false }] }, { type: i0.Output, args: ["expandedChange"] }], tint: [{ type: i0.Input, args: [{ isSignal: true, alias: "tint", required: false }] }], level: [{ type: i0.Input, args: [{ isSignal: true, alias: "level", required: false }] }], togglePlacement: [{ type: i0.Input, args: [{ isSignal: true, alias: "togglePlacement", required: false }] }], navLabel: [{ type: i0.Input, args: [{ isSignal: true, alias: "navLabel", required: false }] }], headRef: [{ type: i0.ViewChild, args: ["head", { isSignal: true }] }], footRef: [{ type: i0.ViewChild, args: ["foot", { isSignal: true }] }] } });
|
|
4372
4372
|
|
|
4373
4373
|
/** Solid accent colour per semantic tone (drives the dot + follow-pill). */
|
|
@@ -4406,6 +4406,18 @@ const TONE_ACCENT = {
|
|
|
4406
4406
|
* ```
|
|
4407
4407
|
*/
|
|
4408
4408
|
class FoldMenuItemComponent {
|
|
4409
|
+
host = inject(ElementRef);
|
|
4410
|
+
/**
|
|
4411
|
+
* Pins the collapsed-rail tooltip next to the item, in viewport coordinates.
|
|
4412
|
+
* The chip is `position: fixed` so the scrolling rail body cannot clip it;
|
|
4413
|
+
* it therefore needs the item's on-screen position at the moment it shows.
|
|
4414
|
+
*/
|
|
4415
|
+
placeTip() {
|
|
4416
|
+
const el = this.host.nativeElement;
|
|
4417
|
+
const box = el.getBoundingClientRect();
|
|
4418
|
+
el.style.setProperty("--mi-tip-x", `${box.right + 8}px`);
|
|
4419
|
+
el.style.setProperty("--mi-tip-y", `${box.top + box.height / 2}px`);
|
|
4420
|
+
}
|
|
4409
4421
|
icon = input.required(/* @ts-ignore */
|
|
4410
4422
|
...(ngDevMode ? [{ debugName: "icon" }] : /* istanbul ignore next */ []));
|
|
4411
4423
|
/** The label shown in the hover tooltip (also the accessible name). */
|
|
@@ -4465,7 +4477,7 @@ class FoldMenuItemComponent {
|
|
|
4465
4477
|
ariaLabel = computed(() => this.hasBadge() ? `${this.label()}, ${this.badgeText()}` : null, /* @ts-ignore */
|
|
4466
4478
|
...(ngDevMode ? [{ debugName: "ariaLabel" }] : /* istanbul ignore next */ []));
|
|
4467
4479
|
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "22.0.8", ngImport: i0, type: FoldMenuItemComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
|
|
4468
|
-
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "22.0.8", type: FoldMenuItemComponent, isStandalone: true, selector: "a[fold-menu-item], button[fold-menu-item]", inputs: { icon: { classPropertyName: "icon", publicName: "icon", isSignal: true, isRequired: true, transformFunction: null }, label: { classPropertyName: "label", publicName: "label", isSignal: true, isRequired: true, transformFunction: null }, active: { classPropertyName: "active", publicName: "active", isSignal: true, isRequired: false, transformFunction: null }, badge: { classPropertyName: "badge", publicName: "badge", isSignal: true, isRequired: false, transformFunction: null }, badgeTone: { classPropertyName: "badgeTone", publicName: "badgeTone", isSignal: true, isRequired: false, transformFunction: null } }, host: { properties: { "class.is-active": "active()", "attr.aria-label": "ariaLabel()", "style.--mi-badge-accent": "badgeAccent()" } }, ngImport: i0, template: "<fold-icon [name]=\"icon()\" [size]=\"18\" class=\"mi-icon\" />\n\n<!-- Collapsed rail: a corner dot, or a count bubble for a number. -->\n@if (hasBadge()) {\n <span class=\"mi-dot\" [class.mi-dot-count]=\"isCount()\" aria-hidden=\"true\">{{\n dotText()\n }}</span>\n}\n\n<span class=\"mi-tip\">{{ label() }}</span>\n\n<!-- Expanded rail: the badge pill, pushed to the row's trailing edge. `follow`\n tints from the item's own accent; the semantic tones reuse fold-badge. -->\n@if (hasBadge()) {\n @if (isFollowTone()) {\n <span class=\"mi-badge mi-badge-follow\">{{ badgeText() }}</span>\n } @else {\n <fold-badge\n class=\"mi-badge\"\n [content]=\"badgeText()\"\n [variant]=\"badgeVariant()\"\n />\n }\n}\n", styles: ["@charset \"UTF-8\";:host{position:relative;width:40px;height:36px;box-sizing:border-box;display:grid;place-items:center;border-radius:var(--fold-radius-sm);color:var(--fold-color-text-muted);background:transparent;border:none;cursor:pointer;text-decoration:none;transition:background var(--fold-motion-fast),color var(--fold-motion-fast);--mi-accent: var(--fold-menu-section-color, var(--fold-color-text-secondary));--mi-hover-bg: color-mix( in srgb, var(--mi-accent) 16%, var(--fold-color-surface-hover) );--mi-hover-fg: var(--mi-accent);--mi-active-bg: color-mix(in srgb, var(--mi-accent) 15%, transparent);--mi-active-fg: color-mix( in srgb, var(--mi-accent) 80%, var(--fold-color-text) );--mi-active-icon: var(--mi-accent)}:host-context(fold-menu[data-tint=neutral]){--mi-accent: var(--fold-color-text-secondary);--mi-hover-bg: var(--fold-color-surface-hover);--mi-hover-fg: var(--fold-color-text-secondary);--mi-active-bg: var(--fold-color-surface-hover);--mi-active-fg: var(--fold-color-text);--mi-active-icon: var(--fold-color-text)}:host-context(fold-menu[data-tint=primary]){--mi-accent: var(--fold-color-primary)}:host(:hover){background:var(--mi-hover-bg);color:var(--mi-hover-fg)}:host(:focus-visible){outline:2px solid var(--fold-color-primary);outline-offset:2px}:host(.is-active){color:var(--mi-active-fg);background:var(--mi-active-bg)}:host(.is-active) .mi-icon{color:var(--mi-active-icon)}:host(.is-active):before{content:\"\";position:absolute;left:-8px;top:8px;bottom:8px;width:2px;border-radius:0 2px 2px 0;background:var(--mi-accent);box-shadow:0 0 8px var(--mi-accent)}.mi-icon{color:inherit;transition:color var(--fold-motion-fast)}.mi-dot{position:absolute;top:5px;right:5px;width:8px;height:8px;border-radius:var(--fold-radius-round);background:var(--mi-badge-accent, var(--mi-accent));pointer-events:none}.mi-dot-count{top:2px;right:2px;width:auto;min-width:16px;height:16px;padding:0 var(--fold-space-xs);display:grid;place-items:center;border-radius:var(--fold-radius-pill);font-size:var(--fold-text-2xs);font-weight:var(--fold-weight-semibold);line-height:var(--fold-leading-none);color:var(--fold-color-on-primary)}.mi-badge{display:none}.mi-badge-follow{padding:1px var(--fold-space-sm);border-radius:var(--fold-radius-pill);font-size:var(--fold-text-xs);font-weight:var(--fold-weight-medium);line-height:var(--fold-leading-normal);white-space:nowrap;background:color-mix(in srgb,var(--mi-badge-accent) 16%,transparent);border:1px solid color-mix(in srgb,var(--mi-badge-accent) 35%,transparent);color:color-mix(in srgb,var(--mi-badge-accent) 85%,var(--fold-color-text))}:host-context(fold-menu.expanded) .mi-dot{display:none}:host-context(fold-menu.expanded) .mi-badge{display:inline-flex;margin-left:auto}.mi-tip{position:
|
|
4480
|
+
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "22.0.8", type: FoldMenuItemComponent, isStandalone: true, selector: "a[fold-menu-item], button[fold-menu-item]", inputs: { icon: { classPropertyName: "icon", publicName: "icon", isSignal: true, isRequired: true, transformFunction: null }, label: { classPropertyName: "label", publicName: "label", isSignal: true, isRequired: true, transformFunction: null }, active: { classPropertyName: "active", publicName: "active", isSignal: true, isRequired: false, transformFunction: null }, badge: { classPropertyName: "badge", publicName: "badge", isSignal: true, isRequired: false, transformFunction: null }, badgeTone: { classPropertyName: "badgeTone", publicName: "badgeTone", isSignal: true, isRequired: false, transformFunction: null } }, host: { listeners: { "mouseenter": "placeTip()", "focusin": "placeTip()" }, properties: { "class.is-active": "active()", "attr.aria-label": "ariaLabel()", "style.--mi-badge-accent": "badgeAccent()" } }, ngImport: i0, template: "<fold-icon [name]=\"icon()\" [size]=\"18\" class=\"mi-icon\" />\n\n<!-- Collapsed rail: a corner dot, or a count bubble for a number. -->\n@if (hasBadge()) {\n <span class=\"mi-dot\" [class.mi-dot-count]=\"isCount()\" aria-hidden=\"true\">{{\n dotText()\n }}</span>\n}\n\n<span class=\"mi-tip\">{{ label() }}</span>\n\n<!-- Expanded rail: the badge pill, pushed to the row's trailing edge. `follow`\n tints from the item's own accent; the semantic tones reuse fold-badge. -->\n@if (hasBadge()) {\n @if (isFollowTone()) {\n <span class=\"mi-badge mi-badge-follow\">{{ badgeText() }}</span>\n } @else {\n <fold-badge\n class=\"mi-badge\"\n [content]=\"badgeText()\"\n [variant]=\"badgeVariant()\"\n />\n }\n}\n", styles: ["@charset \"UTF-8\";:host{position:relative;width:40px;height:36px;flex-shrink:0;box-sizing:border-box;display:grid;place-items:center;border-radius:var(--fold-radius-sm);color:var(--fold-color-text-muted);background:transparent;border:none;cursor:pointer;text-decoration:none;transition:background var(--fold-motion-fast),color var(--fold-motion-fast);--mi-accent: var(--fold-menu-section-color, var(--fold-color-text-secondary));--mi-hover-bg: color-mix( in srgb, var(--mi-accent) 16%, var(--fold-color-surface-hover) );--mi-hover-fg: var(--mi-accent);--mi-active-bg: color-mix(in srgb, var(--mi-accent) 15%, transparent);--mi-active-fg: color-mix( in srgb, var(--mi-accent) 80%, var(--fold-color-text) );--mi-active-icon: var(--mi-accent)}:host-context(fold-menu[data-tint=neutral]){--mi-accent: var(--fold-color-text-secondary);--mi-hover-bg: var(--fold-color-surface-hover);--mi-hover-fg: var(--fold-color-text-secondary);--mi-active-bg: var(--fold-color-surface-hover);--mi-active-fg: var(--fold-color-text);--mi-active-icon: var(--fold-color-text)}:host-context(fold-menu[data-tint=primary]){--mi-accent: var(--fold-color-primary)}:host(:hover){background:var(--mi-hover-bg);color:var(--mi-hover-fg)}:host(:focus-visible){outline:2px solid var(--fold-color-primary);outline-offset:2px}:host(.is-active){color:var(--mi-active-fg);background:var(--mi-active-bg)}:host(.is-active) .mi-icon{color:var(--mi-active-icon)}:host(.is-active):before{content:\"\";position:absolute;left:-8px;top:8px;bottom:8px;width:2px;border-radius:0 2px 2px 0;background:var(--mi-accent);box-shadow:0 0 8px var(--mi-accent)}.mi-icon{color:inherit;transition:color var(--fold-motion-fast)}.mi-dot{position:absolute;top:5px;right:5px;width:8px;height:8px;border-radius:var(--fold-radius-round);background:var(--mi-badge-accent, var(--mi-accent));pointer-events:none}.mi-dot-count{top:2px;right:2px;width:auto;min-width:16px;height:16px;padding:0 var(--fold-space-xs);display:grid;place-items:center;border-radius:var(--fold-radius-pill);font-size:var(--fold-text-2xs);font-weight:var(--fold-weight-semibold);line-height:var(--fold-leading-none);color:var(--fold-color-on-primary)}.mi-badge{display:none}.mi-badge-follow{padding:1px var(--fold-space-sm);border-radius:var(--fold-radius-pill);font-size:var(--fold-text-xs);font-weight:var(--fold-weight-medium);line-height:var(--fold-leading-normal);white-space:nowrap;background:color-mix(in srgb,var(--mi-badge-accent) 16%,transparent);border:1px solid color-mix(in srgb,var(--mi-badge-accent) 35%,transparent);color:color-mix(in srgb,var(--mi-badge-accent) 85%,var(--fold-color-text))}:host-context(fold-menu.expanded) .mi-dot{display:none}:host-context(fold-menu.expanded) .mi-badge{display:inline-flex;margin-left:auto}.mi-tip{position:fixed;left:var(--mi-tip-x, -9999px);top:var(--mi-tip-y, 0);transform:translateY(-50%);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);white-space:nowrap;opacity:0;pointer-events:none;box-shadow:var(--fold-shadow-md);transition:opacity var(--fold-motion-fast);z-index:100}:host(:hover) .mi-tip{opacity:1}:host-context(fold-menu.expanded){width:auto;height:36px;display:flex;align-items:center;gap:var(--fold-space-md);padding:0 var(--fold-space-md)}:host-context(fold-menu.expanded) .mi-tip{position:static;transform:none;padding:0;border:none;background:none;box-shadow:none;color:inherit;font-size:var(--fold-text-sm);opacity:1;pointer-events:auto}\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"] }] });
|
|
4469
4481
|
}
|
|
4470
4482
|
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.0.8", ngImport: i0, type: FoldMenuItemComponent, decorators: [{
|
|
4471
4483
|
type: Component,
|
|
@@ -4473,7 +4485,9 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.0.8", ngImpor
|
|
|
4473
4485
|
"[class.is-active]": "active()",
|
|
4474
4486
|
"[attr.aria-label]": "ariaLabel()",
|
|
4475
4487
|
"[style.--mi-badge-accent]": "badgeAccent()",
|
|
4476
|
-
|
|
4488
|
+
"(mouseenter)": "placeTip()",
|
|
4489
|
+
"(focusin)": "placeTip()",
|
|
4490
|
+
}, template: "<fold-icon [name]=\"icon()\" [size]=\"18\" class=\"mi-icon\" />\n\n<!-- Collapsed rail: a corner dot, or a count bubble for a number. -->\n@if (hasBadge()) {\n <span class=\"mi-dot\" [class.mi-dot-count]=\"isCount()\" aria-hidden=\"true\">{{\n dotText()\n }}</span>\n}\n\n<span class=\"mi-tip\">{{ label() }}</span>\n\n<!-- Expanded rail: the badge pill, pushed to the row's trailing edge. `follow`\n tints from the item's own accent; the semantic tones reuse fold-badge. -->\n@if (hasBadge()) {\n @if (isFollowTone()) {\n <span class=\"mi-badge mi-badge-follow\">{{ badgeText() }}</span>\n } @else {\n <fold-badge\n class=\"mi-badge\"\n [content]=\"badgeText()\"\n [variant]=\"badgeVariant()\"\n />\n }\n}\n", styles: ["@charset \"UTF-8\";:host{position:relative;width:40px;height:36px;flex-shrink:0;box-sizing:border-box;display:grid;place-items:center;border-radius:var(--fold-radius-sm);color:var(--fold-color-text-muted);background:transparent;border:none;cursor:pointer;text-decoration:none;transition:background var(--fold-motion-fast),color var(--fold-motion-fast);--mi-accent: var(--fold-menu-section-color, var(--fold-color-text-secondary));--mi-hover-bg: color-mix( in srgb, var(--mi-accent) 16%, var(--fold-color-surface-hover) );--mi-hover-fg: var(--mi-accent);--mi-active-bg: color-mix(in srgb, var(--mi-accent) 15%, transparent);--mi-active-fg: color-mix( in srgb, var(--mi-accent) 80%, var(--fold-color-text) );--mi-active-icon: var(--mi-accent)}:host-context(fold-menu[data-tint=neutral]){--mi-accent: var(--fold-color-text-secondary);--mi-hover-bg: var(--fold-color-surface-hover);--mi-hover-fg: var(--fold-color-text-secondary);--mi-active-bg: var(--fold-color-surface-hover);--mi-active-fg: var(--fold-color-text);--mi-active-icon: var(--fold-color-text)}:host-context(fold-menu[data-tint=primary]){--mi-accent: var(--fold-color-primary)}:host(:hover){background:var(--mi-hover-bg);color:var(--mi-hover-fg)}:host(:focus-visible){outline:2px solid var(--fold-color-primary);outline-offset:2px}:host(.is-active){color:var(--mi-active-fg);background:var(--mi-active-bg)}:host(.is-active) .mi-icon{color:var(--mi-active-icon)}:host(.is-active):before{content:\"\";position:absolute;left:-8px;top:8px;bottom:8px;width:2px;border-radius:0 2px 2px 0;background:var(--mi-accent);box-shadow:0 0 8px var(--mi-accent)}.mi-icon{color:inherit;transition:color var(--fold-motion-fast)}.mi-dot{position:absolute;top:5px;right:5px;width:8px;height:8px;border-radius:var(--fold-radius-round);background:var(--mi-badge-accent, var(--mi-accent));pointer-events:none}.mi-dot-count{top:2px;right:2px;width:auto;min-width:16px;height:16px;padding:0 var(--fold-space-xs);display:grid;place-items:center;border-radius:var(--fold-radius-pill);font-size:var(--fold-text-2xs);font-weight:var(--fold-weight-semibold);line-height:var(--fold-leading-none);color:var(--fold-color-on-primary)}.mi-badge{display:none}.mi-badge-follow{padding:1px var(--fold-space-sm);border-radius:var(--fold-radius-pill);font-size:var(--fold-text-xs);font-weight:var(--fold-weight-medium);line-height:var(--fold-leading-normal);white-space:nowrap;background:color-mix(in srgb,var(--mi-badge-accent) 16%,transparent);border:1px solid color-mix(in srgb,var(--mi-badge-accent) 35%,transparent);color:color-mix(in srgb,var(--mi-badge-accent) 85%,var(--fold-color-text))}:host-context(fold-menu.expanded) .mi-dot{display:none}:host-context(fold-menu.expanded) .mi-badge{display:inline-flex;margin-left:auto}.mi-tip{position:fixed;left:var(--mi-tip-x, -9999px);top:var(--mi-tip-y, 0);transform:translateY(-50%);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);white-space:nowrap;opacity:0;pointer-events:none;box-shadow:var(--fold-shadow-md);transition:opacity var(--fold-motion-fast);z-index:100}:host(:hover) .mi-tip{opacity:1}:host-context(fold-menu.expanded){width:auto;height:36px;display:flex;align-items:center;gap:var(--fold-space-md);padding:0 var(--fold-space-md)}:host-context(fold-menu.expanded) .mi-tip{position:static;transform:none;padding:0;border:none;background:none;box-shadow:none;color:inherit;font-size:var(--fold-text-sm);opacity:1;pointer-events:auto}\n"] }]
|
|
4477
4491
|
}], propDecorators: { icon: [{ type: i0.Input, args: [{ isSignal: true, alias: "icon", required: true }] }], label: [{ type: i0.Input, args: [{ isSignal: true, alias: "label", required: true }] }], active: [{ type: i0.Input, args: [{ isSignal: true, alias: "active", required: false }] }], badge: [{ type: i0.Input, args: [{ isSignal: true, alias: "badge", required: false }] }], badgeTone: [{ type: i0.Input, args: [{ isSignal: true, alias: "badgeTone", required: false }] }] } });
|
|
4478
4492
|
|
|
4479
4493
|
/**
|
|
@@ -4559,11 +4573,11 @@ class FoldMenuSectionComponent {
|
|
|
4559
4573
|
this.collapsed.update((v) => !v);
|
|
4560
4574
|
}
|
|
4561
4575
|
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "22.0.8", ngImport: i0, type: FoldMenuSectionComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
|
|
4562
|
-
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "22.0.8", type: FoldMenuSectionComponent, isStandalone: true, selector: "fold-menu-section", inputs: { label: { classPropertyName: "label", publicName: "label", isSignal: true, isRequired: false, transformFunction: null }, color: { classPropertyName: "color", publicName: "color", isSignal: true, isRequired: false, transformFunction: null }, collapsible: { classPropertyName: "collapsible", publicName: "collapsible", isSignal: true, isRequired: false, transformFunction: null }, collapsed: { classPropertyName: "collapsed", publicName: "collapsed", isSignal: true, isRequired: false, transformFunction: null } }, outputs: { collapsed: "collapsedChange" }, host: { properties: { "style.--fold-menu-section-color": "color() ?? null" } }, queries: [{ propertyName: "items", predicate: FoldMenuItemComponent, descendants: true, isSignal: true }], ngImport: i0, template: "@if (collapsible()) {\n <button\n type=\"button\"\n class=\"section-head\"\n [attr.aria-expanded]=\"open()\"\n [attr.aria-controls]=\"bodyId\"\n (click)=\"toggle()\"\n >\n <fold-menu-separator [label]=\"label()\" [color]=\"color()\" />\n <fold-icon\n class=\"section-chevron\"\n [class.is-open]=\"open()\"\n name=\"chevron-right\"\n [size]=\"12\"\n aria-hidden=\"true\"\n />\n </button>\n} @else {\n <fold-menu-separator [label]=\"label()\" [color]=\"color()\" />\n}\n\n<div\n class=\"section-items\"\n [id]=\"bodyId\"\n [class.foldable]=\"collapsible()\"\n [class.is-collapsed]=\"!open()\"\n>\n <ng-content />\n</div>\n", styles: ["@charset \"UTF-8\";:host{display:flex;flex-direction:column;align-items:center;gap:var(--fold-space-xs);width:100%}:host-context(fold-menu.expanded){align-items:stretch;width:auto}.section-items{display:contents}.section-head{all:unset;display:flex;align-items:center;width:100%;box-sizing:border-box;cursor:pointer}.section-head fold-menu-separator{flex:1;min-width:0}.section-chevron{flex-shrink:0;margin-left:auto;margin-right:var(--fold-space-sm);color:var(--fold-color-text-faded);transition:transform var(--fold-motion-fast)}.section-chevron.is-open{transform:rotate(90deg)}:host-context(fold-menu:not(.expanded)) .section-head{pointer-events:none}:host-context(fold-menu:not(.expanded)) .section-chevron{display:none}.section-items.foldable{display:flex;flex-direction:column;align-items:center;gap:var(--fold-space-xs);width:100%;overflow:hidden;max-height:60vh;opacity:1;transition:max-height var(--fold-motion-base),opacity var(--fold-motion-base)}:host-context(fold-menu.expanded) .section-items.foldable{align-items:stretch;width:auto}.section-items.foldable.is-collapsed{max-height:0;opacity:0}:host-context(fold-menu:not(.expanded)) .section-items.foldable{max-height:none;opacity:1}@media(prefers-reduced-motion:reduce){.section-items.foldable,.section-chevron{transition:none}}\n"], dependencies: [{ kind: "component", type: FoldMenuSeparatorComponent, selector: "fold-menu-separator", inputs: ["label", "color"] }, { kind: "component", type: FoldIconComponent, selector: "fold-icon", inputs: ["name", "size", "tone", "title"] }] });
|
|
4576
|
+
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "22.0.8", type: FoldMenuSectionComponent, isStandalone: true, selector: "fold-menu-section", inputs: { label: { classPropertyName: "label", publicName: "label", isSignal: true, isRequired: false, transformFunction: null }, color: { classPropertyName: "color", publicName: "color", isSignal: true, isRequired: false, transformFunction: null }, collapsible: { classPropertyName: "collapsible", publicName: "collapsible", isSignal: true, isRequired: false, transformFunction: null }, collapsed: { classPropertyName: "collapsed", publicName: "collapsed", isSignal: true, isRequired: false, transformFunction: null } }, outputs: { collapsed: "collapsedChange" }, host: { properties: { "style.--fold-menu-section-color": "color() ?? null" } }, queries: [{ propertyName: "items", predicate: FoldMenuItemComponent, descendants: true, isSignal: true }], ngImport: i0, template: "@if (collapsible()) {\n <button\n type=\"button\"\n class=\"section-head\"\n [attr.aria-expanded]=\"open()\"\n [attr.aria-controls]=\"bodyId\"\n (click)=\"toggle()\"\n >\n <fold-menu-separator [label]=\"label()\" [color]=\"color()\" />\n <fold-icon\n class=\"section-chevron\"\n [class.is-open]=\"open()\"\n name=\"chevron-right\"\n [size]=\"12\"\n aria-hidden=\"true\"\n />\n </button>\n} @else {\n <fold-menu-separator [label]=\"label()\" [color]=\"color()\" />\n}\n\n<div\n class=\"section-items\"\n [id]=\"bodyId\"\n [class.foldable]=\"collapsible()\"\n [class.is-collapsed]=\"!open()\"\n>\n <ng-content />\n</div>\n", styles: ["@charset \"UTF-8\";:host{display:flex;flex-direction:column;align-items:center;gap:var(--fold-space-xs);width:100%}:host-context(fold-menu.expanded){align-items:stretch;width:auto}.section-items{display:contents}.section-head{all:unset;display:flex;align-items:center;width:100%;box-sizing:border-box;cursor:pointer}.section-head fold-menu-separator{flex:1;min-width:0}.section-chevron{flex-shrink:0;margin-left:auto;margin-right:var(--fold-space-sm);color:var(--fold-color-text-faded);transition:transform var(--fold-motion-fast)}.section-chevron.is-open{transform:rotate(90deg)}:host-context(fold-menu:not(.expanded)) .section-head{pointer-events:none}:host-context(fold-menu:not(.expanded)) .section-chevron{display:none}.section-items.foldable{display:flex;flex-direction:column;align-items:center;gap:var(--fold-space-xs);width:100%;overflow:hidden;max-height:60vh;opacity:1;transition:max-height var(--fold-motion-base),opacity var(--fold-motion-base)}:host-context(fold-menu.expanded) .section-items.foldable{align-items:stretch;width:auto}.section-items.foldable.is-collapsed{max-height:0;opacity:0}:host-context(fold-menu:not(.expanded)) .section-items.foldable{max-height:none;opacity:1}@media(prefers-reduced-motion:reduce){.section-items.foldable,.section-chevron{transition:none}}:host-context(fold-menu.expanded) .section-items{display:flex;flex-direction:column;align-items:stretch;gap:var(--fold-space-xs);margin-left:var(--fold-space-md);padding-left:var(--fold-space-xs);border-left:2px solid color-mix(in srgb,var(--fold-menu-section-color, var(--fold-color-border)) 60%,transparent)}\n"], dependencies: [{ kind: "component", type: FoldMenuSeparatorComponent, selector: "fold-menu-separator", inputs: ["label", "color"] }, { kind: "component", type: FoldIconComponent, selector: "fold-icon", inputs: ["name", "size", "tone", "title"] }] });
|
|
4563
4577
|
}
|
|
4564
4578
|
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.0.8", ngImport: i0, type: FoldMenuSectionComponent, decorators: [{
|
|
4565
4579
|
type: Component,
|
|
4566
|
-
args: [{ selector: "fold-menu-section", standalone: true, imports: [FoldMenuSeparatorComponent, FoldIconComponent], host: { "[style.--fold-menu-section-color]": "color() ?? null" }, template: "@if (collapsible()) {\n <button\n type=\"button\"\n class=\"section-head\"\n [attr.aria-expanded]=\"open()\"\n [attr.aria-controls]=\"bodyId\"\n (click)=\"toggle()\"\n >\n <fold-menu-separator [label]=\"label()\" [color]=\"color()\" />\n <fold-icon\n class=\"section-chevron\"\n [class.is-open]=\"open()\"\n name=\"chevron-right\"\n [size]=\"12\"\n aria-hidden=\"true\"\n />\n </button>\n} @else {\n <fold-menu-separator [label]=\"label()\" [color]=\"color()\" />\n}\n\n<div\n class=\"section-items\"\n [id]=\"bodyId\"\n [class.foldable]=\"collapsible()\"\n [class.is-collapsed]=\"!open()\"\n>\n <ng-content />\n</div>\n", styles: ["@charset \"UTF-8\";:host{display:flex;flex-direction:column;align-items:center;gap:var(--fold-space-xs);width:100%}:host-context(fold-menu.expanded){align-items:stretch;width:auto}.section-items{display:contents}.section-head{all:unset;display:flex;align-items:center;width:100%;box-sizing:border-box;cursor:pointer}.section-head fold-menu-separator{flex:1;min-width:0}.section-chevron{flex-shrink:0;margin-left:auto;margin-right:var(--fold-space-sm);color:var(--fold-color-text-faded);transition:transform var(--fold-motion-fast)}.section-chevron.is-open{transform:rotate(90deg)}:host-context(fold-menu:not(.expanded)) .section-head{pointer-events:none}:host-context(fold-menu:not(.expanded)) .section-chevron{display:none}.section-items.foldable{display:flex;flex-direction:column;align-items:center;gap:var(--fold-space-xs);width:100%;overflow:hidden;max-height:60vh;opacity:1;transition:max-height var(--fold-motion-base),opacity var(--fold-motion-base)}:host-context(fold-menu.expanded) .section-items.foldable{align-items:stretch;width:auto}.section-items.foldable.is-collapsed{max-height:0;opacity:0}:host-context(fold-menu:not(.expanded)) .section-items.foldable{max-height:none;opacity:1}@media(prefers-reduced-motion:reduce){.section-items.foldable,.section-chevron{transition:none}}\n"] }]
|
|
4580
|
+
args: [{ selector: "fold-menu-section", standalone: true, imports: [FoldMenuSeparatorComponent, FoldIconComponent], host: { "[style.--fold-menu-section-color]": "color() ?? null" }, template: "@if (collapsible()) {\n <button\n type=\"button\"\n class=\"section-head\"\n [attr.aria-expanded]=\"open()\"\n [attr.aria-controls]=\"bodyId\"\n (click)=\"toggle()\"\n >\n <fold-menu-separator [label]=\"label()\" [color]=\"color()\" />\n <fold-icon\n class=\"section-chevron\"\n [class.is-open]=\"open()\"\n name=\"chevron-right\"\n [size]=\"12\"\n aria-hidden=\"true\"\n />\n </button>\n} @else {\n <fold-menu-separator [label]=\"label()\" [color]=\"color()\" />\n}\n\n<div\n class=\"section-items\"\n [id]=\"bodyId\"\n [class.foldable]=\"collapsible()\"\n [class.is-collapsed]=\"!open()\"\n>\n <ng-content />\n</div>\n", styles: ["@charset \"UTF-8\";:host{display:flex;flex-direction:column;align-items:center;gap:var(--fold-space-xs);width:100%}:host-context(fold-menu.expanded){align-items:stretch;width:auto}.section-items{display:contents}.section-head{all:unset;display:flex;align-items:center;width:100%;box-sizing:border-box;cursor:pointer}.section-head fold-menu-separator{flex:1;min-width:0}.section-chevron{flex-shrink:0;margin-left:auto;margin-right:var(--fold-space-sm);color:var(--fold-color-text-faded);transition:transform var(--fold-motion-fast)}.section-chevron.is-open{transform:rotate(90deg)}:host-context(fold-menu:not(.expanded)) .section-head{pointer-events:none}:host-context(fold-menu:not(.expanded)) .section-chevron{display:none}.section-items.foldable{display:flex;flex-direction:column;align-items:center;gap:var(--fold-space-xs);width:100%;overflow:hidden;max-height:60vh;opacity:1;transition:max-height var(--fold-motion-base),opacity var(--fold-motion-base)}:host-context(fold-menu.expanded) .section-items.foldable{align-items:stretch;width:auto}.section-items.foldable.is-collapsed{max-height:0;opacity:0}:host-context(fold-menu:not(.expanded)) .section-items.foldable{max-height:none;opacity:1}@media(prefers-reduced-motion:reduce){.section-items.foldable,.section-chevron{transition:none}}:host-context(fold-menu.expanded) .section-items{display:flex;flex-direction:column;align-items:stretch;gap:var(--fold-space-xs);margin-left:var(--fold-space-md);padding-left:var(--fold-space-xs);border-left:2px solid color-mix(in srgb,var(--fold-menu-section-color, var(--fold-color-border)) 60%,transparent)}\n"] }]
|
|
4567
4581
|
}], propDecorators: { label: [{ type: i0.Input, args: [{ isSignal: true, alias: "label", required: false }] }], color: [{ type: i0.Input, args: [{ isSignal: true, alias: "color", required: false }] }], collapsible: [{ type: i0.Input, args: [{ isSignal: true, alias: "collapsible", required: false }] }], collapsed: [{ type: i0.Input, args: [{ isSignal: true, alias: "collapsed", required: false }] }, { type: i0.Output, args: ["collapsedChange"] }], items: [{ type: i0.ContentChildren, args: [i0.forwardRef(() => FoldMenuItemComponent), { ...{
|
|
4568
4582
|
descendants: true,
|
|
4569
4583
|
}, isSignal: true }] }] } });
|
|
@@ -4930,6 +4944,8 @@ const DRILL_MS = 260;
|
|
|
4930
4944
|
const BACK_MS = 200;
|
|
4931
4945
|
/** When the entrance cascade is over and `:active` gets the transform back (ms). */
|
|
4932
4946
|
const SETTLE_MS = 760;
|
|
4947
|
+
/** Up to this many level-1 items, `"auto"` lays out large tiles. */
|
|
4948
|
+
const FEW_ITEMS = 4;
|
|
4933
4949
|
/** Horizontal travel that counts as a "swipe right" (px). */
|
|
4934
4950
|
const SWIPE_PX = 56;
|
|
4935
4951
|
/**
|
|
@@ -4999,8 +5015,14 @@ class FoldNavLauncherComponent {
|
|
|
4999
5015
|
*/
|
|
5000
5016
|
glass = input(false, { ...(ngDevMode ? { debugName: "glass" } : /* istanbul ignore next */ {}), transform: booleanAttribute });
|
|
5001
5017
|
/**
|
|
5002
|
-
* Grid column count. `"auto"` (default)
|
|
5003
|
-
*
|
|
5018
|
+
* Grid column count. `"auto"` (default) lets the WIDTH decide: tiles fill the
|
|
5019
|
+
* row at a minimum size, so a phone keeps 2 (≤4 items) or 3 columns while a
|
|
5020
|
+
* tablet gets more, smaller columns instead of four 370 px squares. The
|
|
5021
|
+
* minimum depends on the item count — few items, large tiles.
|
|
5022
|
+
*
|
|
5023
|
+
* A number pins the count. Either way the grid never grows past
|
|
5024
|
+
* `--fold-nav-launcher-max-width` (default `720px`), centred, so a pinned
|
|
5025
|
+
* count cannot blow tiles up on a wide screen either.
|
|
5004
5026
|
*/
|
|
5005
5027
|
columns = input("auto", /* @ts-ignore */
|
|
5006
5028
|
...(ngDevMode ? [{ debugName: "columns" }] : /* istanbul ignore next */ []));
|
|
@@ -5032,15 +5054,25 @@ class FoldNavLauncherComponent {
|
|
|
5032
5054
|
/** The group whose tile is the anchor: the open one, or the one being opened. */
|
|
5033
5055
|
anchor = computed(() => this.openGroup() ?? this.pending(), /* @ts-ignore */
|
|
5034
5056
|
...(ngDevMode ? [{ debugName: "anchor" }] : /* istanbul ignore next */ []));
|
|
5035
|
-
/** The
|
|
5036
|
-
|
|
5057
|
+
/** The pinned column count, or `null` when the width decides (`"auto"`). */
|
|
5058
|
+
fixedCols = computed(() => {
|
|
5037
5059
|
const cols = this.columns();
|
|
5038
|
-
|
|
5039
|
-
|
|
5060
|
+
return cols === "auto" ? null : cols;
|
|
5061
|
+
}, /* @ts-ignore */
|
|
5062
|
+
...(ngDevMode ? [{ debugName: "fixedCols" }] : /* istanbul ignore next */ []));
|
|
5063
|
+
/**
|
|
5064
|
+
* Tile density in `"auto"` mode — picks the tile's minimum width in CSS:
|
|
5065
|
+
* `few` (≤4 items) → large tiles, `many` → compact ones. `null` when pinned.
|
|
5066
|
+
*/
|
|
5067
|
+
density = computed(() => {
|
|
5068
|
+
if (this.fixedCols() !== null) {
|
|
5069
|
+
return null;
|
|
5040
5070
|
}
|
|
5041
|
-
return this.tiles().length + this.groups().length <=
|
|
5071
|
+
return this.tiles().length + this.groups().length <= FEW_ITEMS
|
|
5072
|
+
? "few"
|
|
5073
|
+
: "many";
|
|
5042
5074
|
}, /* @ts-ignore */
|
|
5043
|
-
...(ngDevMode ? [{ debugName: "
|
|
5075
|
+
...(ngDevMode ? [{ debugName: "density" }] : /* istanbul ignore next */ []));
|
|
5044
5076
|
/** The sheet's subtitle — derived from the group's own children, never passed. */
|
|
5045
5077
|
entryCountText = computed(() => {
|
|
5046
5078
|
const group = this.openGroup();
|
|
@@ -5223,13 +5255,13 @@ class FoldNavLauncherComponent {
|
|
|
5223
5255
|
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "22.0.8", ngImport: i0, type: FoldNavLauncherComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
|
|
5224
5256
|
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "22.0.8", type: FoldNavLauncherComponent, isStandalone: true, selector: "fold-nav-launcher", inputs: { open: { classPropertyName: "open", publicName: "open", isSignal: true, isRequired: false, transformFunction: null }, label: { classPropertyName: "label", publicName: "label", isSignal: true, isRequired: false, transformFunction: null }, eyebrow: { classPropertyName: "eyebrow", publicName: "eyebrow", isSignal: true, isRequired: false, transformFunction: null }, heading: { classPropertyName: "heading", publicName: "heading", isSignal: true, isRequired: false, transformFunction: null }, closeLabel: { classPropertyName: "closeLabel", publicName: "closeLabel", isSignal: true, isRequired: false, transformFunction: null }, backLabel: { classPropertyName: "backLabel", publicName: "backLabel", isSignal: true, isRequired: false, transformFunction: null }, glass: { classPropertyName: "glass", publicName: "glass", isSignal: true, isRequired: false, transformFunction: null }, columns: { classPropertyName: "columns", publicName: "columns", isSignal: true, isRequired: false, transformFunction: null } }, outputs: { open: "openChange" }, host: { listeners: { "document:keydown.escape": "onEscape()" } }, providers: [
|
|
5225
5257
|
{ provide: FOLD_NAV_LAUNCHER, useExisting: FoldNavLauncherComponent },
|
|
5226
|
-
], queries: [{ propertyName: "tiles", predicate: FoldNavTileComponent, isSignal: true }, { propertyName: "groups", predicate: FoldNavGroupComponent, isSignal: true }], ngImport: i0, template: "@if (open()) {\n <div class=\"nl-scrim\" aria-hidden=\"true\"></div>\n <!-- Le gestionnaire de renvoi vit sur le DIALOGUE, pas sur le voile : le\n dialogue est `position: fixed; inset: 0` par-dessus, donc un clic\n n'atteignait jamais le voile. Le clavier sort par `Escape`. -->\n <!-- Une SURFACE DE CHROME, et pas seulement un fond sombre : sans cette\n d\u00E9claration le lanceur peignait le sol du rail tout en lisant l'encre de\n la PAGE \u2014 texte sombre sur sombre, et des tuiles claires au milieu d'un\n panneau noir, sous tout th\u00E8me mixte (navi). Peindre le sol d'une famille\n sans en rejoindre la polarit\u00E9, c'est en revendiquer la moiti\u00E9. -->\n <div\n class=\"nl-dialog\"\n foldSurface=\"chrome\"\n role=\"dialog\"\n aria-modal=\"true\"\n [attr.aria-label]=\"label()\"\n [attr.data-level]=\"level()\"\n [attr.data-glass]=\"glass() ? '' : null\"\n [foldFocusTrap]=\"open()\"\n tabindex=\"-1\"\n (click)=\"onSurfaceClick($event)\"\n >\n <!-- Le voile de l'option verre. Sans lui, le flou n'a rien \u00E0 flouter et on\n n'obtient que des panneaux plus sombres. -->\n <div class=\"nl-veil\" aria-hidden=\"true\"></div>\n\n <header class=\"nl-head\">\n @if (anchor(); as group) {\n <button\n type=\"button\"\n class=\"nl-back\"\n [attr.aria-label]=\"backLabel()\"\n (click)=\"back()\"\n >\n <fold-icon name=\"chevron-left\" size=\"sm\" />\n </button>\n <!-- L'ANCRE. La tuile touch\u00E9e ne dispara\u00EEt pas : elle remonte ici, \u00E0\n sa taille de pastille. Cliquable, parce que l'\u00E9l\u00E9ment qui a servi\n de porte doit aussi servir de sortie. -->\n <button\n type=\"button\"\n class=\"nl-anchor\"\n [attr.aria-label]=\"backLabel()\"\n (click)=\"back()\"\n >\n @if (group.icon(); as name) {\n <fold-icon [name]=\"name\" size=\"sm\" />\n } @else {\n <span aria-hidden=\"true\">{{ group.label().charAt(0) }}</span>\n }\n </button>\n <span class=\"nl-titles\">\n <span class=\"nl-title\">{{ group.label() }}</span>\n <span class=\"nl-sub\">{{ entryCountText() }}</span>\n </span>\n } @else {\n <span class=\"nl-titles\">\n @if (eyebrow(); as e) {\n <span class=\"nl-eyebrow\">{{ e }}</span>\n }\n @if (heading(); as h) {\n <span class=\"nl-heading\">{{ h }}</span>\n }\n </span>\n }\n\n <button\n type=\"button\"\n class=\"nl-close\"\n [attr.aria-label]=\"closeLabel()\"\n (click)=\"close()\"\n >\n <fold-icon name=\"close\" size=\"md\" />\n </button>\n </header>\n\n <div\n class=\"nl-body\"\n (pointerdown)=\"onPointerDown($event)\"\n (pointerup)=\"onPointerUp($event)\"\n >\n <!-- La grille porte les DEUX niveaux : un groupe ouvert sort de la\n grille et couvre ce corps, sans que rien ne bouge dans le DOM. -->\n <div
|
|
5258
|
+
], queries: [{ propertyName: "tiles", predicate: FoldNavTileComponent, isSignal: true }, { propertyName: "groups", predicate: FoldNavGroupComponent, isSignal: true }], ngImport: i0, template: "@if (open()) {\n <div class=\"nl-scrim\" aria-hidden=\"true\"></div>\n <!-- Le gestionnaire de renvoi vit sur le DIALOGUE, pas sur le voile : le\n dialogue est `position: fixed; inset: 0` par-dessus, donc un clic\n n'atteignait jamais le voile. Le clavier sort par `Escape`. -->\n <!-- Une SURFACE DE CHROME, et pas seulement un fond sombre : sans cette\n d\u00E9claration le lanceur peignait le sol du rail tout en lisant l'encre de\n la PAGE \u2014 texte sombre sur sombre, et des tuiles claires au milieu d'un\n panneau noir, sous tout th\u00E8me mixte (navi). Peindre le sol d'une famille\n sans en rejoindre la polarit\u00E9, c'est en revendiquer la moiti\u00E9. -->\n <div\n class=\"nl-dialog\"\n foldSurface=\"chrome\"\n role=\"dialog\"\n aria-modal=\"true\"\n [attr.aria-label]=\"label()\"\n [attr.data-level]=\"level()\"\n [attr.data-glass]=\"glass() ? '' : null\"\n [foldFocusTrap]=\"open()\"\n tabindex=\"-1\"\n (click)=\"onSurfaceClick($event)\"\n >\n <!-- Le voile de l'option verre. Sans lui, le flou n'a rien \u00E0 flouter et on\n n'obtient que des panneaux plus sombres. -->\n <div class=\"nl-veil\" aria-hidden=\"true\"></div>\n\n <header class=\"nl-head\">\n @if (anchor(); as group) {\n <button\n type=\"button\"\n class=\"nl-back\"\n [attr.aria-label]=\"backLabel()\"\n (click)=\"back()\"\n >\n <fold-icon name=\"chevron-left\" size=\"sm\" />\n </button>\n <!-- L'ANCRE. La tuile touch\u00E9e ne dispara\u00EEt pas : elle remonte ici, \u00E0\n sa taille de pastille. Cliquable, parce que l'\u00E9l\u00E9ment qui a servi\n de porte doit aussi servir de sortie. -->\n <button\n type=\"button\"\n class=\"nl-anchor\"\n [attr.aria-label]=\"backLabel()\"\n (click)=\"back()\"\n >\n @if (group.icon(); as name) {\n <fold-icon [name]=\"name\" size=\"sm\" />\n } @else {\n <span aria-hidden=\"true\">{{ group.label().charAt(0) }}</span>\n }\n </button>\n <span class=\"nl-titles\">\n <span class=\"nl-title\">{{ group.label() }}</span>\n <span class=\"nl-sub\">{{ entryCountText() }}</span>\n </span>\n } @else {\n <span class=\"nl-titles\">\n @if (eyebrow(); as e) {\n <span class=\"nl-eyebrow\">{{ e }}</span>\n }\n @if (heading(); as h) {\n <span class=\"nl-heading\">{{ h }}</span>\n }\n </span>\n }\n\n <button\n type=\"button\"\n class=\"nl-close\"\n [attr.aria-label]=\"closeLabel()\"\n (click)=\"close()\"\n >\n <fold-icon name=\"close\" size=\"md\" />\n </button>\n </header>\n\n <div\n class=\"nl-body\"\n (pointerdown)=\"onPointerDown($event)\"\n (pointerup)=\"onPointerUp($event)\"\n >\n <!-- La grille porte les DEUX niveaux : un groupe ouvert sort de la\n grille et couvre ce corps, sans que rien ne bouge dans le DOM. -->\n <div\n class=\"nl-grid\"\n [style.--nav-cols]=\"fixedCols()\"\n [attr.data-cols]=\"fixedCols() === null ? null : ''\"\n [attr.data-density]=\"density()\"\n >\n <ng-content />\n </div>\n </div>\n\n <div class=\"nl-foot\">\n <ng-content select=\"[footer]\" />\n </div>\n\n <!-- Les deux crans de profondeur. `aria-hidden` : la r\u00E9gion vive dit la\n m\u00EAme chose en mots, et un lecteur d'\u00E9cran n'a que faire de deux\n pastilles. -->\n <div class=\"nl-dots\" aria-hidden=\"true\">\n <span class=\"nl-dot\" [class.is-on]=\"level() === 1\"></span>\n <span class=\"nl-dot\" [class.is-on]=\"level() === 2\"></span>\n </div>\n\n <!-- La descente est MUETTE sans ceci : l'animation ne compense rien. -->\n <p class=\"nl-live\" aria-live=\"polite\">{{ announcement() }}</p>\n </div>\n}\n", styles: ["@charset \"UTF-8\";:host{display:contents}.nl-scrim{position:fixed;inset:0;z-index:200;background:var(--fold-color-scrim);backdrop-filter:blur(var(--fold-blur-glass));-webkit-backdrop-filter:blur(var(--fold-blur-glass));animation:fold-nl-fade .2s ease}.nl-dialog{--fold-nl-gutter: var(--fold-space-xl);--fold-nav-launcher-max-width: 720px;--fold-nl-ease-in: cubic-bezier(.22, 1, .36, 1);--fold-nl-tile-bg: var(--fold-color-surface-raised);--fold-nl-accent-bg: var(--fold-color-primary-surface);--fold-nl-sheet-bg: var(--fold-color-bg-rail-secondary);--fold-nl-row-bg: var(--fold-color-surface-card);--fold-nl-backdrop: none;--fold-nl-sheet-backdrop: none;position:fixed;inset:0;z-index:201;display:flex;flex-direction:column;padding:var(--fold-space-3xl) var(--fold-nl-gutter) var(--fold-space-xl);background:var(--fold-color-bg-rail-primary);color:var(--fold-color-text)}.nl-head{flex:none;display:flex;align-items:center;justify-content:space-between;gap:var(--fold-space-md);min-height:44px;margin-bottom:var(--fold-space-xl)}.nl-titles{display:flex;min-width:0;flex-direction:column}.nl-eyebrow{font-family:var(--fold-font-mono);font-size:var(--fold-text-xs);letter-spacing:var(--fold-tracking-caps);text-transform:uppercase;color:var(--fold-color-text-muted)}.nl-heading{font-size:var(--fold-text-xl);font-weight:var(--fold-weight-bold);letter-spacing:var(--fold-tracking-tighter);color:var(--fold-color-text)}.nl-title{overflow:hidden;text-overflow:ellipsis;white-space:nowrap;font-size:var(--fold-text-lg);font-weight:var(--fold-weight-bold);letter-spacing:var(--fold-tracking-tighter);color:var(--fold-color-text);animation:fold-nl-crumb .32s var(--fold-nl-ease-in) both;animation-delay:40ms}.nl-sub{font-size:var(--fold-text-xs);color:var(--fold-color-text-muted);animation:fold-nl-crumb .32s var(--fold-nl-ease-in) both;animation-delay:40ms}.nl-back,.nl-close,.nl-anchor{flex:none;display:grid;place-items:center;width:30px;height:30px;padding:0;border-radius:var(--fold-radius-sm);background:var(--fold-color-surface-raised);border:1px solid var(--fold-color-border);color:var(--fold-color-text-secondary);cursor:pointer;transition:background .14s ease,color .14s ease}.nl-back:hover,.nl-close:hover{background:var(--fold-color-surface-hover);color:var(--fold-color-text)}.nl-anchor{background:var(--fold-color-primary);border-color:transparent;color:var(--fold-color-on-primary);animation:fold-nl-anchor-in .3s var(--fold-nl-ease-in) both}.nl-close{margin-inline-start:auto}.nl-body{position:relative;display:flex;flex-direction:column;flex:1 1 auto;min-height:0;margin-inline:calc(-1 * var(--fold-nl-gutter));overflow:hidden}.nl-grid{--nav-tile-min: 96px;flex:1 1 auto;min-height:0;overflow-y:auto;overscroll-behavior:contain;-webkit-overflow-scrolling:touch;padding-inline:max(var(--fold-nl-gutter),(100% - var(--fold-nav-launcher-max-width)) / 2);padding-block-end:var(--fold-space-sm);display:grid;grid-template-columns:repeat(auto-fill,minmax(min(100%,var(--nav-tile-min)),1fr));grid-auto-rows:max-content;align-content:start;gap:var(--fold-space-sm)}.nl-grid[data-density=few]{--nav-tile-min: 144px}.nl-grid[data-cols]{grid-template-columns:repeat(var(--nav-cols),minmax(0,1fr))}@media(max-width:360px){.nl-grid,.nl-grid[data-cols]{grid-template-columns:repeat(2,minmax(0,1fr))}}.nl-dialog[data-level=\"2\"] .nl-grid{visibility:hidden}.nl-foot:not(:empty){flex:none;margin-top:auto;padding-top:var(--fold-space-md);border-top:1px solid var(--fold-color-border-subtle)}.nl-dots{flex:none;display:flex;align-items:center;justify-content:center;gap:var(--fold-space-xs);margin-top:var(--fold-space-md)}.nl-dot{width:22px;height:3px;border-radius:var(--fold-radius-pill);background:var(--fold-color-border);transition:background .28s ease}.nl-dot.is-on{background:var(--fold-color-primary)}.nl-live{position:absolute;width:1px;height:1px;margin:0;overflow:hidden;clip-path:inset(50%);white-space:nowrap}.nl-veil{position:absolute;inset:0;opacity:0;pointer-events:none;transition:opacity .3s ease;background:radial-gradient(120% 70% at 12% 4%,color-mix(in srgb,var(--fold-color-primary) 34%,transparent),transparent 58%),radial-gradient(90% 60% at 88% 22%,color-mix(in srgb,var(--fold-color-primary-strong) 30%,transparent),transparent 60%),radial-gradient(80% 55% at 70% 96%,color-mix(in srgb,var(--fold-color-warning) 16%,transparent),transparent 62%)}.nl-dialog[data-glass]{--fold-nl-tile-bg: color-mix( in srgb, var(--fold-color-bg-rail-secondary) 52%, transparent );--fold-nl-accent-bg: color-mix( in srgb, var(--fold-color-primary) 14%, transparent );--fold-nl-sheet-bg: color-mix( in srgb, var(--fold-color-bg-rail-secondary) 60%, transparent );--fold-nl-row-bg: color-mix( in srgb, var(--fold-color-surface-card) 50%, transparent );--fold-nl-backdrop: blur(20px) saturate(150%);--fold-nl-sheet-backdrop: blur(26px) saturate(150%);background:var(--fold-color-bg-header)}.nl-dialog[data-glass] .nl-veil{opacity:1}@keyframes fold-nl-fade{0%{opacity:0}to{opacity:1}}@keyframes fold-nl-crumb{0%{opacity:0;transform:translate(-12px)}to{opacity:1;transform:none}}@keyframes fold-nl-anchor-in{0%{opacity:0;transform:scale(.6) rotate(-8deg)}to{opacity:1;transform:none}}@media(prefers-reduced-motion:reduce){.nl-scrim,.nl-title,.nl-sub,.nl-anchor{animation:none}}\n"], dependencies: [{ kind: "directive", type: FocusTrapDirective, selector: "[foldFocusTrap]", inputs: ["foldFocusTrap"] }, { kind: "component", type: FoldIconComponent, selector: "fold-icon", inputs: ["name", "size", "tone", "title"] }, { kind: "directive", type: FoldSurfaceDirective, selector: "[foldSurface]", inputs: ["foldSurface"] }] });
|
|
5227
5259
|
}
|
|
5228
5260
|
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.0.8", ngImport: i0, type: FoldNavLauncherComponent, decorators: [{
|
|
5229
5261
|
type: Component,
|
|
5230
5262
|
args: [{ selector: "fold-nav-launcher", standalone: true, imports: [FocusTrapDirective, FoldIconComponent, FoldSurfaceDirective], providers: [
|
|
5231
5263
|
{ provide: FOLD_NAV_LAUNCHER, useExisting: FoldNavLauncherComponent },
|
|
5232
|
-
], template: "@if (open()) {\n <div class=\"nl-scrim\" aria-hidden=\"true\"></div>\n <!-- Le gestionnaire de renvoi vit sur le DIALOGUE, pas sur le voile : le\n dialogue est `position: fixed; inset: 0` par-dessus, donc un clic\n n'atteignait jamais le voile. Le clavier sort par `Escape`. -->\n <!-- Une SURFACE DE CHROME, et pas seulement un fond sombre : sans cette\n d\u00E9claration le lanceur peignait le sol du rail tout en lisant l'encre de\n la PAGE \u2014 texte sombre sur sombre, et des tuiles claires au milieu d'un\n panneau noir, sous tout th\u00E8me mixte (navi). Peindre le sol d'une famille\n sans en rejoindre la polarit\u00E9, c'est en revendiquer la moiti\u00E9. -->\n <div\n class=\"nl-dialog\"\n foldSurface=\"chrome\"\n role=\"dialog\"\n aria-modal=\"true\"\n [attr.aria-label]=\"label()\"\n [attr.data-level]=\"level()\"\n [attr.data-glass]=\"glass() ? '' : null\"\n [foldFocusTrap]=\"open()\"\n tabindex=\"-1\"\n (click)=\"onSurfaceClick($event)\"\n >\n <!-- Le voile de l'option verre. Sans lui, le flou n'a rien \u00E0 flouter et on\n n'obtient que des panneaux plus sombres. -->\n <div class=\"nl-veil\" aria-hidden=\"true\"></div>\n\n <header class=\"nl-head\">\n @if (anchor(); as group) {\n <button\n type=\"button\"\n class=\"nl-back\"\n [attr.aria-label]=\"backLabel()\"\n (click)=\"back()\"\n >\n <fold-icon name=\"chevron-left\" size=\"sm\" />\n </button>\n <!-- L'ANCRE. La tuile touch\u00E9e ne dispara\u00EEt pas : elle remonte ici, \u00E0\n sa taille de pastille. Cliquable, parce que l'\u00E9l\u00E9ment qui a servi\n de porte doit aussi servir de sortie. -->\n <button\n type=\"button\"\n class=\"nl-anchor\"\n [attr.aria-label]=\"backLabel()\"\n (click)=\"back()\"\n >\n @if (group.icon(); as name) {\n <fold-icon [name]=\"name\" size=\"sm\" />\n } @else {\n <span aria-hidden=\"true\">{{ group.label().charAt(0) }}</span>\n }\n </button>\n <span class=\"nl-titles\">\n <span class=\"nl-title\">{{ group.label() }}</span>\n <span class=\"nl-sub\">{{ entryCountText() }}</span>\n </span>\n } @else {\n <span class=\"nl-titles\">\n @if (eyebrow(); as e) {\n <span class=\"nl-eyebrow\">{{ e }}</span>\n }\n @if (heading(); as h) {\n <span class=\"nl-heading\">{{ h }}</span>\n }\n </span>\n }\n\n <button\n type=\"button\"\n class=\"nl-close\"\n [attr.aria-label]=\"closeLabel()\"\n (click)=\"close()\"\n >\n <fold-icon name=\"close\" size=\"md\" />\n </button>\n </header>\n\n <div\n class=\"nl-body\"\n (pointerdown)=\"onPointerDown($event)\"\n (pointerup)=\"onPointerUp($event)\"\n >\n <!-- La grille porte les DEUX niveaux : un groupe ouvert sort de la\n grille et couvre ce corps, sans que rien ne bouge dans le DOM. -->\n <div
|
|
5264
|
+
], template: "@if (open()) {\n <div class=\"nl-scrim\" aria-hidden=\"true\"></div>\n <!-- Le gestionnaire de renvoi vit sur le DIALOGUE, pas sur le voile : le\n dialogue est `position: fixed; inset: 0` par-dessus, donc un clic\n n'atteignait jamais le voile. Le clavier sort par `Escape`. -->\n <!-- Une SURFACE DE CHROME, et pas seulement un fond sombre : sans cette\n d\u00E9claration le lanceur peignait le sol du rail tout en lisant l'encre de\n la PAGE \u2014 texte sombre sur sombre, et des tuiles claires au milieu d'un\n panneau noir, sous tout th\u00E8me mixte (navi). Peindre le sol d'une famille\n sans en rejoindre la polarit\u00E9, c'est en revendiquer la moiti\u00E9. -->\n <div\n class=\"nl-dialog\"\n foldSurface=\"chrome\"\n role=\"dialog\"\n aria-modal=\"true\"\n [attr.aria-label]=\"label()\"\n [attr.data-level]=\"level()\"\n [attr.data-glass]=\"glass() ? '' : null\"\n [foldFocusTrap]=\"open()\"\n tabindex=\"-1\"\n (click)=\"onSurfaceClick($event)\"\n >\n <!-- Le voile de l'option verre. Sans lui, le flou n'a rien \u00E0 flouter et on\n n'obtient que des panneaux plus sombres. -->\n <div class=\"nl-veil\" aria-hidden=\"true\"></div>\n\n <header class=\"nl-head\">\n @if (anchor(); as group) {\n <button\n type=\"button\"\n class=\"nl-back\"\n [attr.aria-label]=\"backLabel()\"\n (click)=\"back()\"\n >\n <fold-icon name=\"chevron-left\" size=\"sm\" />\n </button>\n <!-- L'ANCRE. La tuile touch\u00E9e ne dispara\u00EEt pas : elle remonte ici, \u00E0\n sa taille de pastille. Cliquable, parce que l'\u00E9l\u00E9ment qui a servi\n de porte doit aussi servir de sortie. -->\n <button\n type=\"button\"\n class=\"nl-anchor\"\n [attr.aria-label]=\"backLabel()\"\n (click)=\"back()\"\n >\n @if (group.icon(); as name) {\n <fold-icon [name]=\"name\" size=\"sm\" />\n } @else {\n <span aria-hidden=\"true\">{{ group.label().charAt(0) }}</span>\n }\n </button>\n <span class=\"nl-titles\">\n <span class=\"nl-title\">{{ group.label() }}</span>\n <span class=\"nl-sub\">{{ entryCountText() }}</span>\n </span>\n } @else {\n <span class=\"nl-titles\">\n @if (eyebrow(); as e) {\n <span class=\"nl-eyebrow\">{{ e }}</span>\n }\n @if (heading(); as h) {\n <span class=\"nl-heading\">{{ h }}</span>\n }\n </span>\n }\n\n <button\n type=\"button\"\n class=\"nl-close\"\n [attr.aria-label]=\"closeLabel()\"\n (click)=\"close()\"\n >\n <fold-icon name=\"close\" size=\"md\" />\n </button>\n </header>\n\n <div\n class=\"nl-body\"\n (pointerdown)=\"onPointerDown($event)\"\n (pointerup)=\"onPointerUp($event)\"\n >\n <!-- La grille porte les DEUX niveaux : un groupe ouvert sort de la\n grille et couvre ce corps, sans que rien ne bouge dans le DOM. -->\n <div\n class=\"nl-grid\"\n [style.--nav-cols]=\"fixedCols()\"\n [attr.data-cols]=\"fixedCols() === null ? null : ''\"\n [attr.data-density]=\"density()\"\n >\n <ng-content />\n </div>\n </div>\n\n <div class=\"nl-foot\">\n <ng-content select=\"[footer]\" />\n </div>\n\n <!-- Les deux crans de profondeur. `aria-hidden` : la r\u00E9gion vive dit la\n m\u00EAme chose en mots, et un lecteur d'\u00E9cran n'a que faire de deux\n pastilles. -->\n <div class=\"nl-dots\" aria-hidden=\"true\">\n <span class=\"nl-dot\" [class.is-on]=\"level() === 1\"></span>\n <span class=\"nl-dot\" [class.is-on]=\"level() === 2\"></span>\n </div>\n\n <!-- La descente est MUETTE sans ceci : l'animation ne compense rien. -->\n <p class=\"nl-live\" aria-live=\"polite\">{{ announcement() }}</p>\n </div>\n}\n", styles: ["@charset \"UTF-8\";:host{display:contents}.nl-scrim{position:fixed;inset:0;z-index:200;background:var(--fold-color-scrim);backdrop-filter:blur(var(--fold-blur-glass));-webkit-backdrop-filter:blur(var(--fold-blur-glass));animation:fold-nl-fade .2s ease}.nl-dialog{--fold-nl-gutter: var(--fold-space-xl);--fold-nav-launcher-max-width: 720px;--fold-nl-ease-in: cubic-bezier(.22, 1, .36, 1);--fold-nl-tile-bg: var(--fold-color-surface-raised);--fold-nl-accent-bg: var(--fold-color-primary-surface);--fold-nl-sheet-bg: var(--fold-color-bg-rail-secondary);--fold-nl-row-bg: var(--fold-color-surface-card);--fold-nl-backdrop: none;--fold-nl-sheet-backdrop: none;position:fixed;inset:0;z-index:201;display:flex;flex-direction:column;padding:var(--fold-space-3xl) var(--fold-nl-gutter) var(--fold-space-xl);background:var(--fold-color-bg-rail-primary);color:var(--fold-color-text)}.nl-head{flex:none;display:flex;align-items:center;justify-content:space-between;gap:var(--fold-space-md);min-height:44px;margin-bottom:var(--fold-space-xl)}.nl-titles{display:flex;min-width:0;flex-direction:column}.nl-eyebrow{font-family:var(--fold-font-mono);font-size:var(--fold-text-xs);letter-spacing:var(--fold-tracking-caps);text-transform:uppercase;color:var(--fold-color-text-muted)}.nl-heading{font-size:var(--fold-text-xl);font-weight:var(--fold-weight-bold);letter-spacing:var(--fold-tracking-tighter);color:var(--fold-color-text)}.nl-title{overflow:hidden;text-overflow:ellipsis;white-space:nowrap;font-size:var(--fold-text-lg);font-weight:var(--fold-weight-bold);letter-spacing:var(--fold-tracking-tighter);color:var(--fold-color-text);animation:fold-nl-crumb .32s var(--fold-nl-ease-in) both;animation-delay:40ms}.nl-sub{font-size:var(--fold-text-xs);color:var(--fold-color-text-muted);animation:fold-nl-crumb .32s var(--fold-nl-ease-in) both;animation-delay:40ms}.nl-back,.nl-close,.nl-anchor{flex:none;display:grid;place-items:center;width:30px;height:30px;padding:0;border-radius:var(--fold-radius-sm);background:var(--fold-color-surface-raised);border:1px solid var(--fold-color-border);color:var(--fold-color-text-secondary);cursor:pointer;transition:background .14s ease,color .14s ease}.nl-back:hover,.nl-close:hover{background:var(--fold-color-surface-hover);color:var(--fold-color-text)}.nl-anchor{background:var(--fold-color-primary);border-color:transparent;color:var(--fold-color-on-primary);animation:fold-nl-anchor-in .3s var(--fold-nl-ease-in) both}.nl-close{margin-inline-start:auto}.nl-body{position:relative;display:flex;flex-direction:column;flex:1 1 auto;min-height:0;margin-inline:calc(-1 * var(--fold-nl-gutter));overflow:hidden}.nl-grid{--nav-tile-min: 96px;flex:1 1 auto;min-height:0;overflow-y:auto;overscroll-behavior:contain;-webkit-overflow-scrolling:touch;padding-inline:max(var(--fold-nl-gutter),(100% - var(--fold-nav-launcher-max-width)) / 2);padding-block-end:var(--fold-space-sm);display:grid;grid-template-columns:repeat(auto-fill,minmax(min(100%,var(--nav-tile-min)),1fr));grid-auto-rows:max-content;align-content:start;gap:var(--fold-space-sm)}.nl-grid[data-density=few]{--nav-tile-min: 144px}.nl-grid[data-cols]{grid-template-columns:repeat(var(--nav-cols),minmax(0,1fr))}@media(max-width:360px){.nl-grid,.nl-grid[data-cols]{grid-template-columns:repeat(2,minmax(0,1fr))}}.nl-dialog[data-level=\"2\"] .nl-grid{visibility:hidden}.nl-foot:not(:empty){flex:none;margin-top:auto;padding-top:var(--fold-space-md);border-top:1px solid var(--fold-color-border-subtle)}.nl-dots{flex:none;display:flex;align-items:center;justify-content:center;gap:var(--fold-space-xs);margin-top:var(--fold-space-md)}.nl-dot{width:22px;height:3px;border-radius:var(--fold-radius-pill);background:var(--fold-color-border);transition:background .28s ease}.nl-dot.is-on{background:var(--fold-color-primary)}.nl-live{position:absolute;width:1px;height:1px;margin:0;overflow:hidden;clip-path:inset(50%);white-space:nowrap}.nl-veil{position:absolute;inset:0;opacity:0;pointer-events:none;transition:opacity .3s ease;background:radial-gradient(120% 70% at 12% 4%,color-mix(in srgb,var(--fold-color-primary) 34%,transparent),transparent 58%),radial-gradient(90% 60% at 88% 22%,color-mix(in srgb,var(--fold-color-primary-strong) 30%,transparent),transparent 60%),radial-gradient(80% 55% at 70% 96%,color-mix(in srgb,var(--fold-color-warning) 16%,transparent),transparent 62%)}.nl-dialog[data-glass]{--fold-nl-tile-bg: color-mix( in srgb, var(--fold-color-bg-rail-secondary) 52%, transparent );--fold-nl-accent-bg: color-mix( in srgb, var(--fold-color-primary) 14%, transparent );--fold-nl-sheet-bg: color-mix( in srgb, var(--fold-color-bg-rail-secondary) 60%, transparent );--fold-nl-row-bg: color-mix( in srgb, var(--fold-color-surface-card) 50%, transparent );--fold-nl-backdrop: blur(20px) saturate(150%);--fold-nl-sheet-backdrop: blur(26px) saturate(150%);background:var(--fold-color-bg-header)}.nl-dialog[data-glass] .nl-veil{opacity:1}@keyframes fold-nl-fade{0%{opacity:0}to{opacity:1}}@keyframes fold-nl-crumb{0%{opacity:0;transform:translate(-12px)}to{opacity:1;transform:none}}@keyframes fold-nl-anchor-in{0%{opacity:0;transform:scale(.6) rotate(-8deg)}to{opacity:1;transform:none}}@media(prefers-reduced-motion:reduce){.nl-scrim,.nl-title,.nl-sub,.nl-anchor{animation:none}}\n"] }]
|
|
5233
5265
|
}], ctorParameters: () => [], propDecorators: { open: [{ type: i0.Input, args: [{ isSignal: true, alias: "open", required: false }] }, { type: i0.Output, args: ["openChange"] }], label: [{ type: i0.Input, args: [{ isSignal: true, alias: "label", required: false }] }], eyebrow: [{ type: i0.Input, args: [{ isSignal: true, alias: "eyebrow", required: false }] }], heading: [{ type: i0.Input, args: [{ isSignal: true, alias: "heading", required: false }] }], closeLabel: [{ type: i0.Input, args: [{ isSignal: true, alias: "closeLabel", required: false }] }], backLabel: [{ type: i0.Input, args: [{ isSignal: true, alias: "backLabel", required: false }] }], glass: [{ type: i0.Input, args: [{ isSignal: true, alias: "glass", required: false }] }], columns: [{ type: i0.Input, args: [{ isSignal: true, alias: "columns", required: false }] }], tiles: [{ type: i0.ContentChildren, args: [i0.forwardRef(() => FoldNavTileComponent), { isSignal: true }] }], groups: [{ type: i0.ContentChildren, args: [i0.forwardRef(() => FoldNavGroupComponent), { isSignal: true }] }], onEscape: [{
|
|
5234
5266
|
type: HostListener,
|
|
5235
5267
|
args: ["document:keydown.escape"]
|