fold-ng 0.14.0 → 0.16.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 +46 -1
- package/fesm2022/fold-ng.mjs +52 -7
- 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 +46 -5
- package/types/fold-ng.d.ts.map +1 -1
package/CHANGELOG.md
CHANGED
|
@@ -8,6 +8,49 @@ All notable changes to **fold-ng** are documented here. The format follows
|
|
|
8
8
|
|
|
9
9
|
_Nothing yet._
|
|
10
10
|
|
|
11
|
+
## [0.16.0] - 2026-08-24
|
|
12
|
+
|
|
13
|
+
### Added
|
|
14
|
+
|
|
15
|
+
- **`fold-page-layout` a un créneau `[pageSubtitle]`** — la ligne posée SERRÉE
|
|
16
|
+
sous le titre : les faits qui identifient la page (une référence, une famille,
|
|
17
|
+
un compte), pas de la prose. C'est un autre registre que `[description]`, et
|
|
18
|
+
c'est toute la raison d'être du créneau : une ligne de faits poussée dans la
|
|
19
|
+
description se lit avec l'espacement d'un paragraphe — et l'espacement d'un
|
|
20
|
+
paragraphe est une promesse de paragraphe. Les deux cohabitent : les faits
|
|
21
|
+
serrés, la prose avec sa propre respiration en dessous.
|
|
22
|
+
|
|
23
|
+
- **`fold-page-layout` gagne `separator`** — l'en-tête se ferme sur un filet.
|
|
24
|
+
Éteint par défaut : sur une page dont le corps est une pile de cartes, le
|
|
25
|
+
rythme de page sépare déjà, et le filet n'ajouterait que de l'encre. On
|
|
26
|
+
l'allume quand le corps arrive au ras de l'en-tête — un formulaire, un
|
|
27
|
+
tableau, des sections sans surface propre — là où l'en-tête se lirait sinon
|
|
28
|
+
comme la première ligne du contenu.
|
|
29
|
+
|
|
30
|
+
## [0.15.0] - 2026-08-24
|
|
31
|
+
|
|
32
|
+
### Added
|
|
33
|
+
|
|
34
|
+
- **`fold-page-layout` a un créneau `[pageEyebrow]`** — la rangée AU-DESSUS du
|
|
35
|
+
titre, pour un fil d'Ariane, un lien de retour, une étiquette de rubrique.
|
|
36
|
+
C'est le seul créneau d'en-tête dont la mise en page ne restyle pas le
|
|
37
|
+
contenu : un fil et une étiquette n'ont rien de typographique en commun, donc
|
|
38
|
+
ce qu'on y projette garde son visage. Un eyebrow seul **n'allume pas**
|
|
39
|
+
l'en-tête — une étiquette sans titre n'étiquette rien.
|
|
40
|
+
|
|
41
|
+
Ce que ça remplace : un lien « ← Retour » projeté dans `[pageActions]`, donc
|
|
42
|
+
peint en haut à DROITE alors qu'il désigne le haut de la hiérarchie. Il y
|
|
43
|
+
était faute de place pour l'écrire ailleurs.
|
|
44
|
+
|
|
45
|
+
- **`fold-breadcrumb` gagne `[currentPage]`** (défaut `true`, aucun changement).
|
|
46
|
+
À `false`, le fil ne nomme que les **ancêtres** : le dernier maillon se
|
|
47
|
+
comporte comme les autres — lien s'il porte une cible, texte sinon — et plus
|
|
48
|
+
rien ne porte `aria-current`. C'est la forme qu'un fil prend au-dessus d'un
|
|
49
|
+
`<h1>` : le titre de la page EST la page courante. Sans ça, un fil posé dans
|
|
50
|
+
`[pageEyebrow]` devait soit répéter le titre en dernier maillon (du bruit que
|
|
51
|
+
l'œil saute), soit désigner la famille comme page courante — ce qui raconte au
|
|
52
|
+
lecteur d'écran quelque chose de faux.
|
|
53
|
+
|
|
11
54
|
## [0.14.0] - 2026-08-23
|
|
12
55
|
|
|
13
56
|
### Changed
|
|
@@ -1912,7 +1955,9 @@ design-token stylesheet.
|
|
|
1912
1955
|
`currentColor`; `prefers-reduced-motion` + `forced-colors` are respected;
|
|
1913
1956
|
strings localise via inputs / providers (`provideFoldPanelLabels`).
|
|
1914
1957
|
|
|
1915
|
-
[unreleased]: https://github.com/hugoheynard/fold-ng/compare/v0.
|
|
1958
|
+
[unreleased]: https://github.com/hugoheynard/fold-ng/compare/v0.16.0...HEAD
|
|
1959
|
+
[0.16.0]: https://github.com/hugoheynard/fold-ng/releases/tag/v0.16.0
|
|
1960
|
+
[0.15.0]: https://github.com/hugoheynard/fold-ng/releases/tag/v0.15.0
|
|
1916
1961
|
[0.14.0]: https://github.com/hugoheynard/fold-ng/releases/tag/v0.14.0
|
|
1917
1962
|
[0.13.0]: https://github.com/hugoheynard/fold-ng/releases/tag/v0.13.0
|
|
1918
1963
|
[0.12.1]: https://github.com/hugoheynard/fold-ng/releases/tag/v0.12.1
|
package/fesm2022/fold-ng.mjs
CHANGED
|
@@ -11517,11 +11517,25 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.0.8", ngImpor
|
|
|
11517
11517
|
*
|
|
11518
11518
|
* Content projection:
|
|
11519
11519
|
* - default slot → the page body (sections, cards, banners…).
|
|
11520
|
+
* - `[pageEyebrow]` → the row **above** the title: a {@link FoldBreadcrumbComponent}
|
|
11521
|
+
* trail, a {@link FoldBackLinkComponent}, a kicker label. It is the one header
|
|
11522
|
+
* row the layout does not restyle — a trail and a kicker share no typography,
|
|
11523
|
+
* so what you project keeps its own face. A breadcrumb placed here should name
|
|
11524
|
+
* the **ancestors only** (`[currentPage]="false"`): the page's own `<h1>` is
|
|
11525
|
+
* the current page, and repeating it in the trail is noise. Projecting an
|
|
11526
|
+
* eyebrow alone does **not** switch the header on — an eyebrow without a title
|
|
11527
|
+
* is a label with nothing to label.
|
|
11520
11528
|
* - `[pageTitle]` ({@link FoldPageTitleDirective}) → a custom title, rendered
|
|
11521
11529
|
* inside the `<h1>` in place of the `icon` + `title` inputs, for when a plain
|
|
11522
11530
|
* string won't do (an avatar, a two-tone title). Its presence alone switches
|
|
11523
11531
|
* the header on.
|
|
11524
11532
|
* - `[titleBadge]` → an inline pill beside the title (e.g. a status/kind badge).
|
|
11533
|
+
* - `[pageSubtitle]` → the line **directly under the title**, set tight against
|
|
11534
|
+
* it: the page's identifying FACTS (a reference, a category, a count), not
|
|
11535
|
+
* prose. It is a different register from `[description]` and that is the whole
|
|
11536
|
+
* reason it exists — a facts line pushed into the description slot reads with
|
|
11537
|
+
* a paragraph's spacing, which is a paragraph's promise. Both can appear: the
|
|
11538
|
+
* facts sit tight, the prose gets its own room below.
|
|
11525
11539
|
* - `p[description]` → the intro under the title. A **slot**, not a string
|
|
11526
11540
|
* input: a description that needs a `<code>`, a link or a second sentence is
|
|
11527
11541
|
* the common case, not the exception. It must be a `<p description>` — the
|
|
@@ -11565,6 +11579,16 @@ class FoldPageLayoutComponent {
|
|
|
11565
11579
|
/** An optional leading icon shown beside the title. */
|
|
11566
11580
|
icon = input(/* @ts-ignore */
|
|
11567
11581
|
...(ngDevMode ? [undefined, { debugName: "icon" }] : /* istanbul ignore next */ []));
|
|
11582
|
+
/**
|
|
11583
|
+
* Draw a hairline rule under the header, closing it off from the body.
|
|
11584
|
+
*
|
|
11585
|
+
* Off by default: on a page whose body is a stack of cards, the header is
|
|
11586
|
+
* already separated by the page rhythm and a rule would just add ink. Turn it
|
|
11587
|
+
* on when the body runs flush against the header — a form, a table, sections
|
|
11588
|
+
* with no surface of their own — and the header would otherwise read as the
|
|
11589
|
+
* first row of the content.
|
|
11590
|
+
*/
|
|
11591
|
+
separator = input(false, { ...(ngDevMode ? { debugName: "separator" } : /* istanbul ignore next */ {}), transform: booleanAttribute });
|
|
11568
11592
|
/**
|
|
11569
11593
|
* Who owns the page's scroll:
|
|
11570
11594
|
* - `"flow"` (default) — the page flows inside its host's scroll (the shell
|
|
@@ -11579,12 +11603,16 @@ class FoldPageLayoutComponent {
|
|
|
11579
11603
|
customTitle = contentChild(FoldPageTitleDirective, /* @ts-ignore */
|
|
11580
11604
|
...(ngDevMode ? [{ debugName: "customTitle" }] : /* istanbul ignore next */ []));
|
|
11581
11605
|
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "22.0.8", ngImport: i0, type: FoldPageLayoutComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
|
|
11582
|
-
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "22.0.8", type: FoldPageLayoutComponent, isStandalone: true, selector: "fold-page-layout", inputs: { title: { classPropertyName: "title", publicName: "title", isSignal: true, isRequired: false, transformFunction: null }, icon: { classPropertyName: "icon", publicName: "icon", isSignal: true, isRequired: false, transformFunction: null }, scroll: { classPropertyName: "scroll", publicName: "scroll", isSignal: true, isRequired: false, transformFunction: null } }, host: { properties: { "attr.title": "null", "attr.data-scroll": "scroll()" } }, queries: [{ propertyName: "customTitle", first: true, predicate: FoldPageTitleDirective, descendants: true, isSignal: true }], ngImport: i0, template: "@if (title() || customTitle()) {\n <header class=\"page-head\">\n <div class=\"page-head-text\">\n <h1 class=\"page-title\">\n @if (title(); as t) {\n @if (icon(); as ic) {\n <fold-icon class=\"page-icon\" [name]=\"ic\" [size]=\"22\" />\n }\n <span>{{ t }}</span>\n }\n <ng-content select=\"[pageTitle]\" />\n <span class=\"page-title-badge\"\n ><ng-content select=\"[titleBadge]\"\n /></span>\n </h1>\n <div class=\"page-desc\"><ng-content select=\"p[description]\" /></div>\n </div>\n <div class=\"page-actions\"><ng-content select=\"[pageActions]\" /></div>\n </header>\n}\n<div class=\"page-body\"><ng-content /></div>\n", styles: ["@charset \"UTF-8\";:host{display:flex;flex-direction:column;gap:var(--fold-page-gap, 32px);box-sizing:border-box;padding-block:var(--fold-page-pad-top, 28px) var(--fold-page-pad-bottom, 40px);padding-inline:var(--fold-page-gutter, 32px);flex:1 0 auto;min-height:0}:host([data-scroll=own]){flex:1 1 auto;overflow-y:auto;overscroll-behavior:contain}.page-head{display:flex;align-items:flex-start;justify-content:space-between;gap:var(--fold-space-lg)}.page-head-text{display:flex;flex-direction:column;gap:var(--fold-space-xs);min-width:0}.page-title{margin:0;display:flex;align-items:center;gap:var(--fold-space-sm);font-size:var(--fold-text-xl);font-weight:var(--fold-weight-bold);letter-spacing:var(--fold-tracking-tighter);line-height:var(--fold-leading-tight);color:var(--fold-color-text)}.page-icon{flex:none;color:var(--fold-color-primary-text)}.page-title-badge{display:inline-flex;align-items:center;gap:var(--fold-space-sm)}.page-title-badge:empty{display:none}.page-desc{font-size:var(--fold-text-sm);line-height:var(--fold-leading-normal);max-width:var(--fold-page-desc-measure, none);color:var(--fold-color-text-muted)}.page-desc:empty{display:none}.page-desc>*{margin:0}.page-actions{flex:none;display:inline-flex;align-items:center;flex-wrap:wrap;gap:var(--fold-space-sm)}.page-actions:empty{display:none}@media(max-width:640px){.page-head{flex-direction:column;align-items:stretch;gap:var(--fold-space-md)}.page-actions{justify-content:flex-start}:host{padding-inline:calc(var(--fold-page-gutter, 32px) / 2)}}@container (max-width: 640px){.page-head{flex-direction:column;align-items:stretch;gap:var(--fold-space-md)}.page-actions{justify-content:flex-start}:host{padding-inline:calc(var(--fold-page-gutter, 32px) / 2)}}.page-body{display:flex;flex-direction:column;gap:var(--fold-page-gap, 32px)}\n"], dependencies: [{ kind: "component", type: FoldIconComponent, selector: "fold-icon", inputs: ["name", "size", "tone", "title"] }] });
|
|
11606
|
+
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "22.0.8", type: FoldPageLayoutComponent, isStandalone: true, selector: "fold-page-layout", inputs: { title: { classPropertyName: "title", publicName: "title", isSignal: true, isRequired: false, transformFunction: null }, icon: { classPropertyName: "icon", publicName: "icon", isSignal: true, isRequired: false, transformFunction: null }, separator: { classPropertyName: "separator", publicName: "separator", isSignal: true, isRequired: false, transformFunction: null }, scroll: { classPropertyName: "scroll", publicName: "scroll", isSignal: true, isRequired: false, transformFunction: null } }, host: { properties: { "attr.title": "null", "attr.data-scroll": "scroll()", "attr.data-separator": "separator() ? '' : null" } }, queries: [{ propertyName: "customTitle", first: true, predicate: FoldPageTitleDirective, descendants: true, isSignal: true }], ngImport: i0, template: "@if (title() || customTitle()) {\n <header class=\"page-head\">\n <div class=\"page-head-text\">\n <div class=\"page-eyebrow\"><ng-content select=\"[pageEyebrow]\" /></div>\n <h1 class=\"page-title\">\n @if (title(); as t) {\n @if (icon(); as ic) {\n <fold-icon class=\"page-icon\" [name]=\"ic\" [size]=\"22\" />\n }\n <span>{{ t }}</span>\n }\n <ng-content select=\"[pageTitle]\" />\n <span class=\"page-title-badge\"\n ><ng-content select=\"[titleBadge]\"\n /></span>\n </h1>\n <div class=\"page-subtitle\"><ng-content select=\"[pageSubtitle]\" /></div>\n <div class=\"page-desc\"><ng-content select=\"p[description]\" /></div>\n </div>\n <div class=\"page-actions\"><ng-content select=\"[pageActions]\" /></div>\n </header>\n}\n<div class=\"page-body\"><ng-content /></div>\n", styles: ["@charset \"UTF-8\";:host{display:flex;flex-direction:column;gap:var(--fold-page-gap, 32px);box-sizing:border-box;padding-block:var(--fold-page-pad-top, 28px) var(--fold-page-pad-bottom, 40px);padding-inline:var(--fold-page-gutter, 32px);flex:1 0 auto;min-height:0}:host([data-scroll=own]){flex:1 1 auto;overflow-y:auto;overscroll-behavior:contain}.page-head{display:flex;align-items:flex-start;justify-content:space-between;gap:var(--fold-space-lg)}:host([data-separator]) .page-head{padding-block-end:var(--fold-space-lg);border-block-end:1px solid var(--fold-color-border)}.page-head-text{display:flex;flex-direction:column;gap:var(--fold-space-xs);min-width:0}.page-eyebrow{margin-block-end:var(--fold-space-xs)}.page-eyebrow:empty{display:none}.page-title{margin:0;display:flex;align-items:center;gap:var(--fold-space-sm);font-size:var(--fold-text-xl);font-weight:var(--fold-weight-bold);letter-spacing:var(--fold-tracking-tighter);line-height:var(--fold-leading-tight);color:var(--fold-color-text)}.page-icon{flex:none;color:var(--fold-color-primary-text)}.page-title-badge{display:inline-flex;align-items:center;gap:var(--fold-space-sm)}.page-title-badge:empty{display:none}.page-subtitle{font-size:var(--fold-text-sm);line-height:var(--fold-leading-snug);color:var(--fold-color-text-muted)}.page-subtitle:empty{display:none}.page-subtitle>*{margin:0}.page-subtitle:not(:empty)+.page-desc{margin-block-start:var(--fold-space-xs)}.page-desc{font-size:var(--fold-text-sm);line-height:var(--fold-leading-normal);max-width:var(--fold-page-desc-measure, none);color:var(--fold-color-text-muted)}.page-desc:empty{display:none}.page-desc>*{margin:0}.page-actions{flex:none;display:inline-flex;align-items:center;flex-wrap:wrap;gap:var(--fold-space-sm)}.page-actions:empty{display:none}@media(max-width:640px){.page-head{flex-direction:column;align-items:stretch;gap:var(--fold-space-md)}.page-actions{justify-content:flex-start}:host{padding-inline:calc(var(--fold-page-gutter, 32px) / 2)}}@container (max-width: 640px){.page-head{flex-direction:column;align-items:stretch;gap:var(--fold-space-md)}.page-actions{justify-content:flex-start}:host{padding-inline:calc(var(--fold-page-gutter, 32px) / 2)}}.page-body{display:flex;flex-direction:column;gap:var(--fold-page-gap, 32px)}\n"], dependencies: [{ kind: "component", type: FoldIconComponent, selector: "fold-icon", inputs: ["name", "size", "tone", "title"] }] });
|
|
11583
11607
|
}
|
|
11584
11608
|
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.0.8", ngImport: i0, type: FoldPageLayoutComponent, decorators: [{
|
|
11585
11609
|
type: Component,
|
|
11586
|
-
args: [{ selector: "fold-page-layout", standalone: true, imports: [FoldIconComponent], host: {
|
|
11587
|
-
|
|
11610
|
+
args: [{ selector: "fold-page-layout", standalone: true, imports: [FoldIconComponent], host: {
|
|
11611
|
+
"[attr.title]": "null",
|
|
11612
|
+
"[attr.data-scroll]": "scroll()",
|
|
11613
|
+
"[attr.data-separator]": "separator() ? '' : null",
|
|
11614
|
+
}, template: "@if (title() || customTitle()) {\n <header class=\"page-head\">\n <div class=\"page-head-text\">\n <div class=\"page-eyebrow\"><ng-content select=\"[pageEyebrow]\" /></div>\n <h1 class=\"page-title\">\n @if (title(); as t) {\n @if (icon(); as ic) {\n <fold-icon class=\"page-icon\" [name]=\"ic\" [size]=\"22\" />\n }\n <span>{{ t }}</span>\n }\n <ng-content select=\"[pageTitle]\" />\n <span class=\"page-title-badge\"\n ><ng-content select=\"[titleBadge]\"\n /></span>\n </h1>\n <div class=\"page-subtitle\"><ng-content select=\"[pageSubtitle]\" /></div>\n <div class=\"page-desc\"><ng-content select=\"p[description]\" /></div>\n </div>\n <div class=\"page-actions\"><ng-content select=\"[pageActions]\" /></div>\n </header>\n}\n<div class=\"page-body\"><ng-content /></div>\n", styles: ["@charset \"UTF-8\";:host{display:flex;flex-direction:column;gap:var(--fold-page-gap, 32px);box-sizing:border-box;padding-block:var(--fold-page-pad-top, 28px) var(--fold-page-pad-bottom, 40px);padding-inline:var(--fold-page-gutter, 32px);flex:1 0 auto;min-height:0}:host([data-scroll=own]){flex:1 1 auto;overflow-y:auto;overscroll-behavior:contain}.page-head{display:flex;align-items:flex-start;justify-content:space-between;gap:var(--fold-space-lg)}:host([data-separator]) .page-head{padding-block-end:var(--fold-space-lg);border-block-end:1px solid var(--fold-color-border)}.page-head-text{display:flex;flex-direction:column;gap:var(--fold-space-xs);min-width:0}.page-eyebrow{margin-block-end:var(--fold-space-xs)}.page-eyebrow:empty{display:none}.page-title{margin:0;display:flex;align-items:center;gap:var(--fold-space-sm);font-size:var(--fold-text-xl);font-weight:var(--fold-weight-bold);letter-spacing:var(--fold-tracking-tighter);line-height:var(--fold-leading-tight);color:var(--fold-color-text)}.page-icon{flex:none;color:var(--fold-color-primary-text)}.page-title-badge{display:inline-flex;align-items:center;gap:var(--fold-space-sm)}.page-title-badge:empty{display:none}.page-subtitle{font-size:var(--fold-text-sm);line-height:var(--fold-leading-snug);color:var(--fold-color-text-muted)}.page-subtitle:empty{display:none}.page-subtitle>*{margin:0}.page-subtitle:not(:empty)+.page-desc{margin-block-start:var(--fold-space-xs)}.page-desc{font-size:var(--fold-text-sm);line-height:var(--fold-leading-normal);max-width:var(--fold-page-desc-measure, none);color:var(--fold-color-text-muted)}.page-desc:empty{display:none}.page-desc>*{margin:0}.page-actions{flex:none;display:inline-flex;align-items:center;flex-wrap:wrap;gap:var(--fold-space-sm)}.page-actions:empty{display:none}@media(max-width:640px){.page-head{flex-direction:column;align-items:stretch;gap:var(--fold-space-md)}.page-actions{justify-content:flex-start}:host{padding-inline:calc(var(--fold-page-gutter, 32px) / 2)}}@container (max-width: 640px){.page-head{flex-direction:column;align-items:stretch;gap:var(--fold-space-md)}.page-actions{justify-content:flex-start}:host{padding-inline:calc(var(--fold-page-gutter, 32px) / 2)}}.page-body{display:flex;flex-direction:column;gap:var(--fold-page-gap, 32px)}\n"] }]
|
|
11615
|
+
}], propDecorators: { title: [{ type: i0.Input, args: [{ isSignal: true, alias: "title", required: false }] }], icon: [{ type: i0.Input, args: [{ isSignal: true, alias: "icon", required: false }] }], separator: [{ type: i0.Input, args: [{ isSignal: true, alias: "separator", required: false }] }], scroll: [{ type: i0.Input, args: [{ isSignal: true, alias: "scroll", required: false }] }], customTitle: [{ type: i0.ContentChild, args: [i0.forwardRef(() => FoldPageTitleDirective), { isSignal: true }] }] } });
|
|
11588
11616
|
|
|
11589
11617
|
/**
|
|
11590
11618
|
* `<fold-page-section>` — a titled, semantic **`<section>`** grouping of page
|
|
@@ -12297,7 +12325,8 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.0.8", ngImpor
|
|
|
12297
12325
|
* works in a router app and degrades to plain anchors without one (importing it
|
|
12298
12326
|
* never forces `@angular/router` — `RouterLink` is only instantiated on a crumb
|
|
12299
12327
|
* that actually sets `routerLink`). The last item renders as the current page
|
|
12300
|
-
* (`aria-current="page"`), not a link
|
|
12328
|
+
* (`aria-current="page"`), not a link — unless the trail names ancestors ONLY,
|
|
12329
|
+
* for which see {@link currentPage}. Chevron separators are decorative.
|
|
12301
12330
|
*
|
|
12302
12331
|
* ```html
|
|
12303
12332
|
* <fold-breadcrumb
|
|
@@ -12318,16 +12347,32 @@ class FoldBreadcrumbComponent {
|
|
|
12318
12347
|
/** Accessible name of the navigation landmark. @default 'Breadcrumb' */
|
|
12319
12348
|
ariaLabel = input("Breadcrumb", /* @ts-ignore */
|
|
12320
12349
|
...(ngDevMode ? [{ debugName: "ariaLabel" }] : /* istanbul ignore next */ []));
|
|
12350
|
+
/**
|
|
12351
|
+
* Does the last crumb stand for the **current page**?
|
|
12352
|
+
*
|
|
12353
|
+
* `true` (default) — the trail ends *on* the page you are reading: the last
|
|
12354
|
+
* crumb is emphasised, never a link, and carries `aria-current="page"`.
|
|
12355
|
+
*
|
|
12356
|
+
* `false` — the trail names the **ancestors only**, and the page's own `<h1>`
|
|
12357
|
+
* is the current page (the shape a breadcrumb takes when it sits above a
|
|
12358
|
+
* title, e.g. in `fold-page-layout`'s `[pageEyebrow]`). The last crumb then
|
|
12359
|
+
* behaves like any other: a link when it carries a target, plain text when it
|
|
12360
|
+
* does not, and no `aria-current` anywhere — because claiming a parent is the
|
|
12361
|
+
* current page tells a screen reader something untrue, and repeating the
|
|
12362
|
+
* heading as a final crumb is noise a sighted reader has to skip.
|
|
12363
|
+
*/
|
|
12364
|
+
currentPage = input(true, /* @ts-ignore */
|
|
12365
|
+
...(ngDevMode ? [{ debugName: "currentPage" }] : /* istanbul ignore next */ []));
|
|
12321
12366
|
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "22.0.8", ngImport: i0, type: FoldBreadcrumbComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
|
|
12322
|
-
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "22.0.8", type: FoldBreadcrumbComponent, isStandalone: true, selector: "fold-breadcrumb", inputs: { items: { classPropertyName: "items", publicName: "items", isSignal: true, isRequired: true, transformFunction: null }, ariaLabel: { classPropertyName: "ariaLabel", publicName: "ariaLabel", isSignal: true, isRequired: false, transformFunction: null } }, host: { attributes: { "role": "navigation" }, properties: { "attr.aria-label": "ariaLabel()" } }, ngImport: i0, template: "<ol class=\"bc-list\">\n @for (item of items(); track $index; let last = $last) {\n <li class=\"bc-item\">\n @if (last) {\n <span class=\"bc-node bc-current\" aria-current=\"page\">{{\n item.label\n }}</span>\n } @else if (item.routerLink !== undefined) {\n <a class=\"bc-node bc-link\" [routerLink]=\"item.routerLink\">{{\n item.label\n }}</a>\n } @else if (item.href !== undefined) {\n <a class=\"bc-node bc-link\" [href]=\"item.href\">{{ item.label }}</a>\n } @else {\n <span class=\"bc-node\">{{ item.label }}</span>\n }\n\n @if (!last) {\n <fold-icon\n class=\"bc-sep\"\n name=\"chevron-right\"\n size=\"sm\"\n aria-hidden=\"true\"\n />\n }\n </li>\n }\n</ol>\n", styles: ["@charset \"UTF-8\";:host{display:block}.bc-list{display:flex;flex-wrap:wrap;align-items:center;gap:.15rem;margin:0;padding:0;list-style:none;font-size:var(--fold-text-sm, .875rem)}.bc-item{display:inline-flex;align-items:center;gap:.15rem;min-width:0}.bc-node{padding:.15rem .3rem;border-radius:var(--fold-radius-sm, 8px);color:var(--fold-color-text-muted);white-space:nowrap;overflow:hidden;text-overflow:ellipsis}.bc-link{text-decoration:none;cursor:pointer;transition:color var(--fold-motion-fast)}.bc-link:hover{color:var(--fold-color-text);background:var(--fold-color-surface-hover)}.bc-link:focus-visible{outline:2px solid var(--fold-color-primary-border);outline-offset:0}@media(prefers-reduced-motion:reduce){.bc-link{transition:none}}.bc-current{color:var(--fold-color-text);font-weight:var(--fold-weight-semibold)}.bc-sep{flex:none;color:var(--fold-color-text-faded)}@media(forced-colors:active){.bc-link:hover{background:Highlight;color:HighlightText}}\n"], dependencies: [{ kind: "directive", type: RouterLink, selector: "[routerLink]", inputs: ["target", "queryParams", "fragment", "queryParamsHandling", "state", "info", "relativeTo", "preserveFragment", "skipLocationChange", "replaceUrl", "browserUrl", "routerLink"] }, { kind: "component", type: FoldIconComponent, selector: "fold-icon", inputs: ["name", "size", "tone", "title"] }], changeDetection: i0.ChangeDetectionStrategy.OnPush });
|
|
12367
|
+
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "22.0.8", type: FoldBreadcrumbComponent, isStandalone: true, selector: "fold-breadcrumb", inputs: { items: { classPropertyName: "items", publicName: "items", isSignal: true, isRequired: true, transformFunction: null }, ariaLabel: { classPropertyName: "ariaLabel", publicName: "ariaLabel", isSignal: true, isRequired: false, transformFunction: null }, currentPage: { classPropertyName: "currentPage", publicName: "currentPage", isSignal: true, isRequired: false, transformFunction: null } }, host: { attributes: { "role": "navigation" }, properties: { "attr.aria-label": "ariaLabel()" } }, ngImport: i0, template: "<ol class=\"bc-list\">\n @for (item of items(); track $index; let last = $last) {\n <li class=\"bc-item\">\n @if (last && currentPage()) {\n <span class=\"bc-node bc-current\" aria-current=\"page\">{{\n item.label\n }}</span>\n } @else if (item.routerLink !== undefined) {\n <a class=\"bc-node bc-link\" [routerLink]=\"item.routerLink\">{{\n item.label\n }}</a>\n } @else if (item.href !== undefined) {\n <a class=\"bc-node bc-link\" [href]=\"item.href\">{{ item.label }}</a>\n } @else {\n <span class=\"bc-node\">{{ item.label }}</span>\n }\n\n @if (!last) {\n <fold-icon\n class=\"bc-sep\"\n name=\"chevron-right\"\n size=\"sm\"\n aria-hidden=\"true\"\n />\n }\n </li>\n }\n</ol>\n", styles: ["@charset \"UTF-8\";:host{display:block}.bc-list{display:flex;flex-wrap:wrap;align-items:center;gap:.15rem;margin:0;padding:0;list-style:none;font-size:var(--fold-text-sm, .875rem)}.bc-item{display:inline-flex;align-items:center;gap:.15rem;min-width:0}.bc-node{padding:.15rem .3rem;border-radius:var(--fold-radius-sm, 8px);color:var(--fold-color-text-muted);white-space:nowrap;overflow:hidden;text-overflow:ellipsis}.bc-link{text-decoration:none;cursor:pointer;transition:color var(--fold-motion-fast)}.bc-link:hover{color:var(--fold-color-text);background:var(--fold-color-surface-hover)}.bc-link:focus-visible{outline:2px solid var(--fold-color-primary-border);outline-offset:0}@media(prefers-reduced-motion:reduce){.bc-link{transition:none}}.bc-current{color:var(--fold-color-text);font-weight:var(--fold-weight-semibold)}.bc-sep{flex:none;color:var(--fold-color-text-faded)}@media(forced-colors:active){.bc-link:hover{background:Highlight;color:HighlightText}}\n"], dependencies: [{ kind: "directive", type: RouterLink, selector: "[routerLink]", inputs: ["target", "queryParams", "fragment", "queryParamsHandling", "state", "info", "relativeTo", "preserveFragment", "skipLocationChange", "replaceUrl", "browserUrl", "routerLink"] }, { kind: "component", type: FoldIconComponent, selector: "fold-icon", inputs: ["name", "size", "tone", "title"] }], changeDetection: i0.ChangeDetectionStrategy.OnPush });
|
|
12323
12368
|
}
|
|
12324
12369
|
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.0.8", ngImport: i0, type: FoldBreadcrumbComponent, decorators: [{
|
|
12325
12370
|
type: Component,
|
|
12326
12371
|
args: [{ selector: "fold-breadcrumb", standalone: true, changeDetection: ChangeDetectionStrategy.OnPush, imports: [RouterLink, FoldIconComponent], host: {
|
|
12327
12372
|
role: "navigation",
|
|
12328
12373
|
"[attr.aria-label]": "ariaLabel()",
|
|
12329
|
-
}, template: "<ol class=\"bc-list\">\n @for (item of items(); track $index; let last = $last) {\n <li class=\"bc-item\">\n @if (last) {\n <span class=\"bc-node bc-current\" aria-current=\"page\">{{\n item.label\n }}</span>\n } @else if (item.routerLink !== undefined) {\n <a class=\"bc-node bc-link\" [routerLink]=\"item.routerLink\">{{\n item.label\n }}</a>\n } @else if (item.href !== undefined) {\n <a class=\"bc-node bc-link\" [href]=\"item.href\">{{ item.label }}</a>\n } @else {\n <span class=\"bc-node\">{{ item.label }}</span>\n }\n\n @if (!last) {\n <fold-icon\n class=\"bc-sep\"\n name=\"chevron-right\"\n size=\"sm\"\n aria-hidden=\"true\"\n />\n }\n </li>\n }\n</ol>\n", styles: ["@charset \"UTF-8\";:host{display:block}.bc-list{display:flex;flex-wrap:wrap;align-items:center;gap:.15rem;margin:0;padding:0;list-style:none;font-size:var(--fold-text-sm, .875rem)}.bc-item{display:inline-flex;align-items:center;gap:.15rem;min-width:0}.bc-node{padding:.15rem .3rem;border-radius:var(--fold-radius-sm, 8px);color:var(--fold-color-text-muted);white-space:nowrap;overflow:hidden;text-overflow:ellipsis}.bc-link{text-decoration:none;cursor:pointer;transition:color var(--fold-motion-fast)}.bc-link:hover{color:var(--fold-color-text);background:var(--fold-color-surface-hover)}.bc-link:focus-visible{outline:2px solid var(--fold-color-primary-border);outline-offset:0}@media(prefers-reduced-motion:reduce){.bc-link{transition:none}}.bc-current{color:var(--fold-color-text);font-weight:var(--fold-weight-semibold)}.bc-sep{flex:none;color:var(--fold-color-text-faded)}@media(forced-colors:active){.bc-link:hover{background:Highlight;color:HighlightText}}\n"] }]
|
|
12330
|
-
}], propDecorators: { items: [{ type: i0.Input, args: [{ isSignal: true, alias: "items", required: true }] }], ariaLabel: [{ type: i0.Input, args: [{ isSignal: true, alias: "ariaLabel", required: false }] }] } });
|
|
12374
|
+
}, template: "<ol class=\"bc-list\">\n @for (item of items(); track $index; let last = $last) {\n <li class=\"bc-item\">\n @if (last && currentPage()) {\n <span class=\"bc-node bc-current\" aria-current=\"page\">{{\n item.label\n }}</span>\n } @else if (item.routerLink !== undefined) {\n <a class=\"bc-node bc-link\" [routerLink]=\"item.routerLink\">{{\n item.label\n }}</a>\n } @else if (item.href !== undefined) {\n <a class=\"bc-node bc-link\" [href]=\"item.href\">{{ item.label }}</a>\n } @else {\n <span class=\"bc-node\">{{ item.label }}</span>\n }\n\n @if (!last) {\n <fold-icon\n class=\"bc-sep\"\n name=\"chevron-right\"\n size=\"sm\"\n aria-hidden=\"true\"\n />\n }\n </li>\n }\n</ol>\n", styles: ["@charset \"UTF-8\";:host{display:block}.bc-list{display:flex;flex-wrap:wrap;align-items:center;gap:.15rem;margin:0;padding:0;list-style:none;font-size:var(--fold-text-sm, .875rem)}.bc-item{display:inline-flex;align-items:center;gap:.15rem;min-width:0}.bc-node{padding:.15rem .3rem;border-radius:var(--fold-radius-sm, 8px);color:var(--fold-color-text-muted);white-space:nowrap;overflow:hidden;text-overflow:ellipsis}.bc-link{text-decoration:none;cursor:pointer;transition:color var(--fold-motion-fast)}.bc-link:hover{color:var(--fold-color-text);background:var(--fold-color-surface-hover)}.bc-link:focus-visible{outline:2px solid var(--fold-color-primary-border);outline-offset:0}@media(prefers-reduced-motion:reduce){.bc-link{transition:none}}.bc-current{color:var(--fold-color-text);font-weight:var(--fold-weight-semibold)}.bc-sep{flex:none;color:var(--fold-color-text-faded)}@media(forced-colors:active){.bc-link:hover{background:Highlight;color:HighlightText}}\n"] }]
|
|
12375
|
+
}], propDecorators: { items: [{ type: i0.Input, args: [{ isSignal: true, alias: "items", required: true }] }], ariaLabel: [{ type: i0.Input, args: [{ isSignal: true, alias: "ariaLabel", required: false }] }], currentPage: [{ type: i0.Input, args: [{ isSignal: true, alias: "currentPage", required: false }] }] } });
|
|
12331
12376
|
|
|
12332
12377
|
/**
|
|
12333
12378
|
* `<fold-back-link>` — the “← Back” affordance for a detail page. Three modes,
|