fold-ng 0.3.0 → 0.4.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 +67 -1
- package/README.md +127 -50
- package/fesm2022/fold-ng.mjs +202 -51
- package/fesm2022/fold-ng.mjs.map +1 -1
- package/llms.txt +1 -1
- package/package.json +1 -1
- package/tokens/primitives.css +19 -0
- package/tokens/scales.css +11 -0
- package/tokens/semantic.css +238 -0
- package/types/fold-ng.d.ts +108 -27
- package/types/fold-ng.d.ts.map +1 -1
package/CHANGELOG.md
CHANGED
|
@@ -8,6 +8,71 @@ All notable changes to **fold-ng** are documented here. The format follows
|
|
|
8
8
|
|
|
9
9
|
_Nothing yet._
|
|
10
10
|
|
|
11
|
+
## [0.4.0] - 2026-07-25
|
|
12
|
+
|
|
13
|
+
### Added
|
|
14
|
+
|
|
15
|
+
- **Auto-inverting accent surface.** A new `[data-surface="accent"]` region
|
|
16
|
+
(stamped by `fold-card surface="accent"`, `fold-hero-card surface="accent"`,
|
|
17
|
+
or the `foldSurface` directive) fills with the brand accent and re-points its
|
|
18
|
+
**whole content sub-tree** to an on-accent palette — text, borders, band
|
|
19
|
+
gradation, and even nested buttons / links / icon-tiles read on the accent
|
|
20
|
+
with no per-component code. It is theme-agnostic and derived (every value a
|
|
21
|
+
`color-mix` of the captured accent pair), and swaps the brand pair
|
|
22
|
+
(`primary` ↔ `on-primary`) without a CSS custom-property cycle by capturing on
|
|
23
|
+
the surface and inverting on descendants. A theme can override any role by
|
|
24
|
+
nesting a rule for its own `[data-theme=…]` under `[data-surface="accent"]`.
|
|
25
|
+
`FoldSurfaceName` gains `'accent'`. See `docs/surfaces.md`.
|
|
26
|
+
- **On-accent contrast contract.** A contract test derives the on-accent text
|
|
27
|
+
ramp per theme and asserts it clears a documented WCAG floor (the accent is an
|
|
28
|
+
emphasis surface — AA-large 3:1 — or the theme must override the ramp). No
|
|
29
|
+
eyeballing.
|
|
30
|
+
- **`fold-card` — an accessible interactive contract.** `interactive` cards are
|
|
31
|
+
now real controls: `role="button"`, `tabindex`, `Enter`/`Space` activation, an
|
|
32
|
+
`(activated)` output, an `ariaLabel` input, a visible focus ring, and
|
|
33
|
+
`prefers-reduced-motion` respected. The projected bands are neutral `<div>`s
|
|
34
|
+
(not `<header>`/`<footer>`), so a card is a single control with no nested
|
|
35
|
+
landmarks.
|
|
36
|
+
- **`fold-link` — `target` + `rel` for external links.** A linked `fold-link`
|
|
37
|
+
takes `target` (e.g. `_blank`) and `rel`; `rel` defaults to a safe
|
|
38
|
+
`noopener noreferrer` whenever `target="_blank"`, and `(clicked)` now emits the
|
|
39
|
+
`MouseEvent` (so cmd/middle-click and modifier state are observable).
|
|
40
|
+
- **`titan` theme — brushed titanium.** A fifth `[data-theme]`: a light, warm
|
|
41
|
+
brushed-steel read. A cool `steel` ground with the header + rails at the page's
|
|
42
|
+
own tint (a frameless top), bright polished cards floating off it on the shared
|
|
43
|
+
elevation shadow, and a heat-anodized `titanium` **copper-orange** brand.
|
|
44
|
+
Borders re-point to a **solid** steel primitive (a palpable machined seam, not
|
|
45
|
+
the alpha hairline the light themes share); corners soften a step in
|
|
46
|
+
`scales.css`. In the gallery both rails float as steel plates while the header
|
|
47
|
+
stays flat. Uniform-polarity, so no chrome override. The token contract (theme
|
|
48
|
+
parity, no-hex, no dead primitives) stays green.
|
|
49
|
+
|
|
50
|
+
### Changed
|
|
51
|
+
|
|
52
|
+
- **BREAKING — `fold-card` band chrome is per-band.** `separators` and
|
|
53
|
+
`raisedBands` change from booleans to a `FoldCardBandChrome`
|
|
54
|
+
(`'none' | 'header' | 'footer' | 'both'`), so a header and a footer are dressed
|
|
55
|
+
independently. Migration: `<fold-card separators>` → `separators="both"`;
|
|
56
|
+
drop the attribute for `'none'`.
|
|
57
|
+
|
|
58
|
+
### Fixed
|
|
59
|
+
|
|
60
|
+
- **`fold-avatar` — a broken image falls back to the initials** instead of the
|
|
61
|
+
browser's broken-image glyph, and retries when `imageUrl` changes. `ghost`
|
|
62
|
+
combined with `imageUrl` is no longer a silent no-op — a guest keeps the
|
|
63
|
+
dashed edge even with a photo.
|
|
64
|
+
- **`fold-avatar` — initials stay legible on every palette fill.** The initials
|
|
65
|
+
ink is now the higher-contrast of the dark/light pair (was a magic-threshold
|
|
66
|
+
guess), and a contrast contract asserts every built-in palette fill clears AA
|
|
67
|
+
(≥ 4.5:1). A status-ring perceivability contract locks the `ring` colours
|
|
68
|
+
against a WCAG 1.4.11 regression.
|
|
69
|
+
|
|
70
|
+
### Docs
|
|
71
|
+
|
|
72
|
+
- **`docs/surfaces.md`** documents the auto-inversion principle and the
|
|
73
|
+
per-theme override seam; a `/surfaces` gallery page shows the live plain-vs-
|
|
74
|
+
accent proof. `docs/STRENGTHS.md` captures the top-tier design arguments.
|
|
75
|
+
|
|
11
76
|
## [0.3.0] - 2026-07-25
|
|
12
77
|
|
|
13
78
|
### Added
|
|
@@ -133,7 +198,8 @@ design-token stylesheet.
|
|
|
133
198
|
`currentColor`; `prefers-reduced-motion` + `forced-colors` are respected;
|
|
134
199
|
strings localise via inputs / providers (`provideFoldPanelLabels`).
|
|
135
200
|
|
|
136
|
-
[unreleased]: https://github.com/hugoheynard/fold-ng/compare/v0.
|
|
201
|
+
[unreleased]: https://github.com/hugoheynard/fold-ng/compare/v0.4.0...HEAD
|
|
202
|
+
[0.4.0]: https://github.com/hugoheynard/fold-ng/releases/tag/v0.4.0
|
|
137
203
|
[0.3.0]: https://github.com/hugoheynard/fold-ng/releases/tag/v0.3.0
|
|
138
204
|
[0.2.1]: https://github.com/hugoheynard/fold-ng/releases/tag/v0.2.1
|
|
139
205
|
[0.2.0]: https://github.com/hugoheynard/fold-ng/releases/tag/v0.2.0
|
package/README.md
CHANGED
|
@@ -90,12 +90,14 @@ set `data-theme` on an ancestor — usually `<html>`:
|
|
|
90
90
|
<html data-theme="lumen"></html>
|
|
91
91
|
```
|
|
92
92
|
|
|
93
|
-
|
|
94
|
-
`bubbly`
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
93
|
+
Five themes ship: `umbra` (the dark base, no attribute), `lumen` (light),
|
|
94
|
+
`bubbly` (festive lavender, violet brand, rounded), `navi` (dark chrome, light
|
|
95
|
+
page) and `titan` (brushed titanium — a light brushed-steel ground with a
|
|
96
|
+
frameless top and floating rails, bright cards, a heat-anodized copper-orange
|
|
97
|
+
brand, solid steel borders, iPhone-soft corners). The extras exist to prove the point — each
|
|
98
|
+
is the umbra or lumen block with its primitive families re-pointed. Adding a
|
|
99
|
+
sixth is a new `[data-theme]` block in `semantic.css` plus the primitives it
|
|
100
|
+
names.
|
|
99
101
|
|
|
100
102
|
`bubbly` and `navi` also change their corners — **radius is the one scale a theme may
|
|
101
103
|
re-declare**, because corner softness is a brand axis (friendly vs
|
|
@@ -111,6 +113,81 @@ roles cannot express. It gets there by re-declaring those roles on
|
|
|
111
113
|
theme never names a component's internals. Variables only. If mixed chrome ever
|
|
112
114
|
stops being a demo, the catalogue should grow real `*-on-chrome` roles.
|
|
113
115
|
|
|
116
|
+
## Auto-inverting surfaces
|
|
117
|
+
|
|
118
|
+
The same `[data-surface]` seam powers an **accent** surface — a region filled
|
|
119
|
+
with the brand accent whose entire content sub-tree flips to a compatible
|
|
120
|
+
on-accent palette **with no per-component code**. Drop a `fold-card` in a grid
|
|
121
|
+
and set `surface="accent"` (or stamp `foldSurface="accent"` on any element):
|
|
122
|
+
|
|
123
|
+
```html
|
|
124
|
+
<fold-card surface="accent">
|
|
125
|
+
<h3>Studio plan</h3>
|
|
126
|
+
<p>Everything in Pro, plus shared workspaces.</p>
|
|
127
|
+
<fold-badge content="Popular" variant="accent" />
|
|
128
|
+
<fold-link href="/plans">Compare plans</fold-link>
|
|
129
|
+
<button foldButton>Choose</button>
|
|
130
|
+
</fold-card>
|
|
131
|
+
```
|
|
132
|
+
|
|
133
|
+
Every nested thing — the text ramp, the hairline border, a raised band, the
|
|
134
|
+
badge, the link, the button, even a filled icon tile — reads correctly on the
|
|
135
|
+
accent. Not because the card special-cases them, but because the region
|
|
136
|
+
**re-points the semantic roles** they already resolve against.
|
|
137
|
+
|
|
138
|
+
### How it works (and why it survives a solid button)
|
|
139
|
+
|
|
140
|
+
An inverting surface has to do something a chrome surface never does: **swap the
|
|
141
|
+
brand pair**. On the accent, `--fold-color-primary` should become the light ink
|
|
142
|
+
(so a link or a filled tile's ground reads), and `--fold-color-on-primary` should
|
|
143
|
+
become the accent itself (so the label _on_ that tile reads). Written naively
|
|
144
|
+
that's a CSS custom-property cycle (`a: var(b); b: var(a)` → both invalid).
|
|
145
|
+
|
|
146
|
+
The trick: **capture on the surface, invert on the descendants.** The surface
|
|
147
|
+
element records the accent and its ink into two private vars _while the tokens
|
|
148
|
+
still hold their normal values_, and the inverted role-set is applied to
|
|
149
|
+
descendants from those captures — so a role can reference the pre-inversion value
|
|
150
|
+
it is replacing, no cycle:
|
|
151
|
+
|
|
152
|
+
```css
|
|
153
|
+
[data-surface="accent"] {
|
|
154
|
+
--_accent-ink: var(--fold-color-on-primary); /* captured here… */
|
|
155
|
+
--_accent-fill: var(--fold-color-primary);
|
|
156
|
+
}
|
|
157
|
+
[data-surface="accent"] * {
|
|
158
|
+
--fold-color-text: var(--_accent-ink); /* …consumed here */
|
|
159
|
+
--fold-color-primary: var(--_accent-ink); /* fill → light ink */
|
|
160
|
+
--fold-color-on-primary: var(--_accent-fill); /* on-fill → the accent */
|
|
161
|
+
/* …surfaces/borders as color-mix of the captured pair… */
|
|
162
|
+
}
|
|
163
|
+
```
|
|
164
|
+
|
|
165
|
+
Every value is a `color-mix` of the captured pair, so it is **derived, not
|
|
166
|
+
authored** — one definition holds on all five themes, and the surface/band steps
|
|
167
|
+
stay a lighter shade of the accent (gradation kept in-hue).
|
|
168
|
+
|
|
169
|
+
### Overriding per theme
|
|
170
|
+
|
|
171
|
+
None of this is a cage. Writing your own CSS in a card is always free — raw
|
|
172
|
+
values don't reference the roles, so a surface never touches them. An _override_
|
|
173
|
+
isn't a hack: it re-anchors one **relationship** (text ↔ ground ↔ accent) inside
|
|
174
|
+
a controlled frame, and coherence follows because the ratios are preserved. Speak
|
|
175
|
+
in roles and gain the adaptation, or paint a pixel and own it — both coexist.
|
|
176
|
+
|
|
177
|
+
The derived defaults are good, not sacred. A theme that wants a different
|
|
178
|
+
on-accent ramp (a light accent might want darker text, say) overrides any role by
|
|
179
|
+
nesting its own theme selector under the surface — the same seam chrome uses:
|
|
180
|
+
|
|
181
|
+
```css
|
|
182
|
+
[data-theme="titan"] [data-surface="accent"] * {
|
|
183
|
+
--fold-color-text: var(--fold-ref-steel-900); /* dark ink on a light accent */
|
|
184
|
+
}
|
|
185
|
+
```
|
|
186
|
+
|
|
187
|
+
The one honest limit: an accent surface is a _single_ ground, so `surface`
|
|
188
|
+
stays one axis — there is no `accent` × `sunken`. That is a feature (a card in a
|
|
189
|
+
grid has one job: stand out), not a gap.
|
|
190
|
+
|
|
114
191
|
Then style against the semantic tokens — never a raw colour:
|
|
115
192
|
|
|
116
193
|
```css
|
|
@@ -210,50 +287,50 @@ radius / text / icon-size / space / motion / blur scales — see
|
|
|
210
287
|
All standalone, signals-first, styled against the semantic tokens. Import from
|
|
211
288
|
the package root.
|
|
212
289
|
|
|
213
|
-
| Component | Selector | What it is
|
|
214
|
-
| -------------------------------------------------------- | -------------------------------------- |
|
|
215
|
-
| `FoldAppShellComponent` | `fold-app-shell` | Responsive app skeleton (rails + header + content + self-collapsing `footer` slots; `headerLayout`/`footerLayout` inset·full, `footerBehavior` pinned·scroll; `mobileNav` drawer·none — `[(mobileNavOpen)]` off-canvas drawer for the primary rail on mobile, or `none` to compose an `fold-nav-launcher`; `contentScroll` clip·auto; built-in skip-link to a focusable `<main>`. Regions float per-surface via `foldElevated`, not a shell flag).
|
|
216
|
-
| `FoldMenuComponent` (+ `Item` / `Section` / `Separator`) | `fold-menu` | Collapsible nav rail — coloured sections, `tint="follow"`, depth `level`, collapse-toggle placement. Items are `a[fold-menu-item]`.
|
|
217
|
-
| `FoldNavLauncherComponent` (+ `FoldNavTileComponent`) | `fold-nav-launcher` | Full-screen mobile nav launcher — a centred tile grid over a blurred scrim (scrim / `Escape` / close dismissal, focus-trap, scroll-lock). `columns="auto"` scales tiles to the count. Pairs with `fold-app-shell mobileNav="none"`. Tiles are `a[fold-nav-tile]` — `variant="surface"`·`filled`.
|
|
218
|
-
| `FoldPageLayoutComponent` | `fold-page-layout` | Page scaffold — gutter + header + body rhythm; fills its container (width is a content concern). Tokens `--fold-page-gutter` / `--fold-page-gap`; sections can `bleed` edge-to-edge.
|
|
219
|
-
| `FoldPageSectionComponent` | `fold-page-section` | Semantic `<section>` grouping — eyebrow title (names the region via `aria-labelledby`) + description + actions; `stack` / `bleed` helpers. Not a box — compose a `fold-card` inside for that.
|
|
220
|
-
| `FoldHeroSectionComponent` | `fold-hero-section` | Full-bleed page splash — the borderless intro band at the top of a page (carries the `<h1>`). Direct child of `fold-page-layout`: cancels the gutter + top pad to sit flush, brand-tinted wash + hairline. `align` center·start, `wash`, `[heroBackdrop]` decorative lane. (For a bordered header card, see `fold-hero-card`.)
|
|
221
|
-
| `FoldAsideLayoutComponent` | `fold-aside-layout` | Detail-page grid — a centred column flanked by up to two sticky rails (`[asideLeft]` / `[asideRight]`), collapsing to one column on its own container width (`:has()`-driven, container queries). Labelled rails become `complementary` landmarks; every track is a CSS var.
|
|
222
|
-
| `FoldNavLayoutComponent` | `fold-nav-layout` | Places a bar (`[tabNav]` — a `fold-view-nav` or a `fold-tabs`) with its content — `placement="top"` or a `side` rail that folds back on top (hysteretic, on its own width) below `foldAt`. `exportAs="foldNavLayout"` exposes `stacked()` so the projected bar follows in one binding.
|
|
223
|
-
| `FoldCardComponent` | `fold-card` | Raised content surface (`surface
|
|
224
|
-
| `FoldContextCardComponent` | `fold-context-card` | Titled info card: icon header + body + optional footer action.
|
|
225
|
-
| `FoldHeroCardComponent` | `fold-hero-card` | Prominent header **card** — bordered surface × accent overlay + optional accent bar. (For a full-bleed page splash, see `fold-hero-section`.)
|
|
226
|
-
| `FoldElementTitleComponent` | `fold-element-title` | Uppercase section/card mini-title (eyebrow · bar variants).
|
|
227
|
-
| `FoldFieldListComponent` / `…Field` | `fold-field-list` | Read-only `dl/dt/dd` recap — label/value pairs (`[empty]` placeholder). The _display_ half of a record; `fold-input` is the _edit_ half.
|
|
228
|
-
| `FoldInputComponent` | `fold-input` | Text-input control (`value: string`) — Signal Forms (`[formField]`) or standalone `[(value)]`; size × align × variant, `label` / `required` / `hint`. The _edit_ half of a record (`fold-field` reads).
|
|
229
|
-
| `FoldNumberInputComponent` | `fold-number-input` | Numeric sibling of `fold-input` (`value: number \| null`, empty ⇒ `null`); owns `min` / `max` / `step` + `label` / `required` / `hint`. Split so each control keeps its true type.
|
|
230
|
-
| `FoldSearchComponent` | `fold-search` | Debounced search box — an `fold-input` that emits `searchChange` once typing settles (`delayMs`), trimmed + de-duplicated.
|
|
231
|
-
| `FoldSliderComponent` | `fold-slider` | Single-value range slider — a styled native `<input type="range">` (design-system track/fill/thumb), two-way `[(value)]`.
|
|
232
|
-
| `FoldRangeSliderComponent` | `fold-range-slider` | Dual-thumb slider selecting a `{ min, max }` window over `[min, max]`; shares the slider track/fill/thumb.
|
|
233
|
-
| `FoldFileDropzoneComponent` | `fold-file-dropzone` | File-picker dropzone — drag-over visuals, keyboard activation, hidden `<input type=file>` plumbing; emits the picked `File[]` (presentational — never uploads).
|
|
234
|
-
| `FoldLinkComponent` | `fold-link` | Inline text link / link-button (icons, accent · muted).
|
|
235
|
-
| `FoldButtonComponent` | `button[foldButton]` · `a[foldButton]` | Action button — applied to a real `<button>` **or** `<a>` (link that looks like a button, gets `href`/`routerLink`); orthogonal `emphasis` (solid·soft·outline) × `intent` (primary·neutral·warning·danger) × 3 sizes × shape/`block`; `icon`/`iconTrailing` shorthand (auto-sized) or project content; `loading` (spinner + `aria-busy`). Use native `(click)`.
|
|
236
|
-
| `FoldButtonIconComponent` | `fold-button-icon` | Icon-only **momentary** button — shape × size × tone; a one-shot action (no pressed state). For a text button use `fold-button`; for on/off use `fold-toggle-icon`.
|
|
237
|
-
| `FoldToggleIconComponent` | `fold-toggle-icon` | Icon-only **toggle** — the same surface as `fold-button-icon`, plus `[(active)]` + `aria-pressed` (true/false) and a pressed state. Emits `toggled`.
|
|
238
|
-
| `FoldDataTableComponent` | `fold-data-table` | Controlled roster table (sortable, tone rows, mobile cards).
|
|
239
|
-
| `FoldPaginatorComponent` | `fold-paginator` | Server-side paginator (size selector + range + page nav).
|
|
240
|
-
| `FoldTimelineComponent` | `fold-timeline` | Connected rail of nodes (dot + optional date + label) — `vertical` navigable history or `horizontal` step progress; nodes optionally clickable.
|
|
241
|
-
| `FoldBadgeComponent` | `fold-badge` | Status / count pill (accent/info/warning/alert/success).
|
|
242
|
-
| `FoldStatusBadgeComponent` | `fold-status-badge` | Status→colour badge (maps a domain status key to a tone).
|
|
243
|
-
| `FoldChoiceRowComponent` | `fold-choice-row` | Segmented / chip selector.
|
|
244
|
-
| `FoldViewNavComponent` | `fold-view-nav` | Navigation bar styled as tabs. Items carry a `link` (routerLink → a real `<a>`: cmd-click, deep-links, active state auto), an `href`, or nothing (a button); `aria-current="page"` on the active one. `direction="auto"` follows a wrapping `fold-nav-layout`; `collapsed` for an icon rail. For in-page panel switching use `fold-tabs` instead.
|
|
245
|
-
| `FoldTabsComponent` + `FoldTabPanelComponent` | `fold-tabs` + `fold-tab-panel` | The in-page ARIA Tabs widget: `role="tablist"` + roving arrow-key keyboard, `aria-selected`/`aria-orientation`, each tab wired to its `fold-tab-panel` (`aria-controls` ↔ `aria-labelledby`). Panels take the bar by ref (`[tabs]="t"`) so they coordinate across `fold-nav-layout` slots.
|
|
246
|
-
| `FoldIconComponent` | `fold-icon` | SVG icon (114-icon built-in set + `FoldIconRegistry`).
|
|
247
|
-
| `FoldSpinnerComponent` | `fold-spinner` | Indeterminate loading arc (`currentColor`, icon-sized, reduced-motion aware). Decorative by default; `label` → `role="status"`. Powers `loading` on the buttons.
|
|
248
|
-
| `FoldAvatarComponent` / `…Detail` | `fold-avatar` | Initials/image avatar (square, muted, status ring) + identity cell.
|
|
249
|
-
| `FoldAvatarListComponent` | `fold-avatar-list` | Overlapping avatar cluster (per-face variant, `limit` + a `+N` overflow chip).
|
|
250
|
-
| `FoldToastComponent` / `…Container` | `fold-toast` | Frosted snackbar (variant glyph + dismiss) + queue host (+ `FoldToastService`).
|
|
251
|
-
| `FoldLoadingStateComponent` | `fold-loading` | Loading placeholder — `fold-spinner` + message, in a `role="status"` region; `size` input; stretches to fill.
|
|
252
|
-
| `FoldEmptyStateComponent` | `fold-empty-state` | Empty-state block (icon + title + message + optional action).
|
|
253
|
-
| `FoldCalloutComponent` | `fold-callout` | Tinted message row — status colour + icon + message + optional trailing actions; `inset` (bordered, in-flow) appearance.
|
|
254
|
-
| `FoldDisclosureComponent` | `fold-disclosure` | One summary toggling one collapsible panel — the accordion primitive (open-state is the consumer's to bind); keeps content mounted, unlike native `<details>`.
|
|
255
|
-
| `FoldPanelHostComponent` | `fold-panel-host` | Side-panel / overlay host (+ `FoldPanelHostService` / `FoldPanelRef` / `FoldPanelToggle`). Modal: accessible name, `inert` background barrier, top-most focus trap, scroll-lock. Localise the close label once via `provideFoldPanelLabels({ close })`.
|
|
256
|
-
| `FoldPanelHeaderComponent` | `fold-panel-header` | Standard panel header (title/eyebrow, self-closing). Names its dialog (`aria-labelledby`) and reads the app-wide close label.
|
|
290
|
+
| Component | Selector | What it is |
|
|
291
|
+
| -------------------------------------------------------- | -------------------------------------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
|
|
292
|
+
| `FoldAppShellComponent` | `fold-app-shell` | Responsive app skeleton (rails + header + content + self-collapsing `footer` slots; `headerLayout`/`footerLayout` inset·full, `footerBehavior` pinned·scroll; `mobileNav` drawer·none — `[(mobileNavOpen)]` off-canvas drawer for the primary rail on mobile, or `none` to compose an `fold-nav-launcher`; `contentScroll` clip·auto; built-in skip-link to a focusable `<main>`. Regions float per-surface via `foldElevated`, not a shell flag). |
|
|
293
|
+
| `FoldMenuComponent` (+ `Item` / `Section` / `Separator`) | `fold-menu` | Collapsible nav rail — coloured sections, `tint="follow"`, depth `level`, collapse-toggle placement. Items are `a[fold-menu-item]`. |
|
|
294
|
+
| `FoldNavLauncherComponent` (+ `FoldNavTileComponent`) | `fold-nav-launcher` | Full-screen mobile nav launcher — a centred tile grid over a blurred scrim (scrim / `Escape` / close dismissal, focus-trap, scroll-lock). `columns="auto"` scales tiles to the count. Pairs with `fold-app-shell mobileNav="none"`. Tiles are `a[fold-nav-tile]` — `variant="surface"`·`filled`. |
|
|
295
|
+
| `FoldPageLayoutComponent` | `fold-page-layout` | Page scaffold — gutter + header + body rhythm; fills its container (width is a content concern). Tokens `--fold-page-gutter` / `--fold-page-gap`; sections can `bleed` edge-to-edge. |
|
|
296
|
+
| `FoldPageSectionComponent` | `fold-page-section` | Semantic `<section>` grouping — eyebrow title (names the region via `aria-labelledby`) + description + actions; `stack` / `bleed` helpers. Not a box — compose a `fold-card` inside for that. |
|
|
297
|
+
| `FoldHeroSectionComponent` | `fold-hero-section` | Full-bleed page splash — the borderless intro band at the top of a page (carries the `<h1>`). Direct child of `fold-page-layout`: cancels the gutter + top pad to sit flush, brand-tinted wash + hairline. `align` center·start, `wash`, `[heroBackdrop]` decorative lane. (For a bordered header card, see `fold-hero-card`.) |
|
|
298
|
+
| `FoldAsideLayoutComponent` | `fold-aside-layout` | Detail-page grid — a centred column flanked by up to two sticky rails (`[asideLeft]` / `[asideRight]`), collapsing to one column on its own container width (`:has()`-driven, container queries). Labelled rails become `complementary` landmarks; every track is a CSS var. |
|
|
299
|
+
| `FoldNavLayoutComponent` | `fold-nav-layout` | Places a bar (`[tabNav]` — a `fold-view-nav` or a `fold-tabs`) with its content — `placement="top"` or a `side` rail that folds back on top (hysteretic, on its own width) below `foldAt`. `exportAs="foldNavLayout"` exposes `stacked()` so the projected bar follows in one binding. |
|
|
300
|
+
| `FoldCardComponent` | `fold-card` | Raised content surface (`surface` = `card`/`sunken`/`accent`, hairline border, consistent radius). `accent` is an **auto-inverting** accent-filled card: the whole content sub-tree re-points to a compatible on-accent palette (text, borders, band gradation, nested buttons/links/icon-tiles) — every value a `color-mix` of the accent, so it holds on all themes (see [auto-inverting surfaces](#auto-inverting-surfaces)). Optional projected `[cardHeader]`/`[cardFooter]` bands with per-band chrome (`separators`/`raisedBands` = `none`/`header`/`footer`/`both`); the body padding never shifts when a band toggles. `interactive` makes the whole card an accessible button (`role`/`tabindex`, focus ring, Enter/Space/click → `(activated)`). |
|
|
301
|
+
| `FoldContextCardComponent` | `fold-context-card` | Titled info card: icon header + body + optional footer action. |
|
|
302
|
+
| `FoldHeroCardComponent` | `fold-hero-card` | Prominent header **card** — bordered surface × accent overlay + optional accent bar. (For a full-bleed page splash, see `fold-hero-section`.) |
|
|
303
|
+
| `FoldElementTitleComponent` | `fold-element-title` | Uppercase section/card mini-title (eyebrow · bar variants). |
|
|
304
|
+
| `FoldFieldListComponent` / `…Field` | `fold-field-list` | Read-only `dl/dt/dd` recap — label/value pairs (`[empty]` placeholder). The _display_ half of a record; `fold-input` is the _edit_ half. |
|
|
305
|
+
| `FoldInputComponent` | `fold-input` | Text-input control (`value: string`) — Signal Forms (`[formField]`) or standalone `[(value)]`; size × align × variant, `label` / `required` / `hint`. The _edit_ half of a record (`fold-field` reads). |
|
|
306
|
+
| `FoldNumberInputComponent` | `fold-number-input` | Numeric sibling of `fold-input` (`value: number \| null`, empty ⇒ `null`); owns `min` / `max` / `step` + `label` / `required` / `hint`. Split so each control keeps its true type. |
|
|
307
|
+
| `FoldSearchComponent` | `fold-search` | Debounced search box — an `fold-input` that emits `searchChange` once typing settles (`delayMs`), trimmed + de-duplicated. |
|
|
308
|
+
| `FoldSliderComponent` | `fold-slider` | Single-value range slider — a styled native `<input type="range">` (design-system track/fill/thumb), two-way `[(value)]`. |
|
|
309
|
+
| `FoldRangeSliderComponent` | `fold-range-slider` | Dual-thumb slider selecting a `{ min, max }` window over `[min, max]`; shares the slider track/fill/thumb. |
|
|
310
|
+
| `FoldFileDropzoneComponent` | `fold-file-dropzone` | File-picker dropzone — drag-over visuals, keyboard activation, hidden `<input type=file>` plumbing; emits the picked `File[]` (presentational — never uploads). |
|
|
311
|
+
| `FoldLinkComponent` | `fold-link` | Inline text link / link-button (icons, accent · muted). |
|
|
312
|
+
| `FoldButtonComponent` | `button[foldButton]` · `a[foldButton]` | Action button — applied to a real `<button>` **or** `<a>` (link that looks like a button, gets `href`/`routerLink`); orthogonal `emphasis` (solid·soft·outline) × `intent` (primary·neutral·warning·danger) × 3 sizes × shape/`block`; `icon`/`iconTrailing` shorthand (auto-sized) or project content; `loading` (spinner + `aria-busy`). Use native `(click)`. |
|
|
313
|
+
| `FoldButtonIconComponent` | `fold-button-icon` | Icon-only **momentary** button — shape × size × tone; a one-shot action (no pressed state). For a text button use `fold-button`; for on/off use `fold-toggle-icon`. |
|
|
314
|
+
| `FoldToggleIconComponent` | `fold-toggle-icon` | Icon-only **toggle** — the same surface as `fold-button-icon`, plus `[(active)]` + `aria-pressed` (true/false) and a pressed state. Emits `toggled`. |
|
|
315
|
+
| `FoldDataTableComponent` | `fold-data-table` | Controlled roster table (sortable, tone rows, mobile cards). |
|
|
316
|
+
| `FoldPaginatorComponent` | `fold-paginator` | Server-side paginator (size selector + range + page nav). |
|
|
317
|
+
| `FoldTimelineComponent` | `fold-timeline` | Connected rail of nodes (dot + optional date + label) — `vertical` navigable history or `horizontal` step progress; nodes optionally clickable. |
|
|
318
|
+
| `FoldBadgeComponent` | `fold-badge` | Status / count pill (accent/info/warning/alert/success). |
|
|
319
|
+
| `FoldStatusBadgeComponent` | `fold-status-badge` | Status→colour badge (maps a domain status key to a tone). |
|
|
320
|
+
| `FoldChoiceRowComponent` | `fold-choice-row` | Segmented / chip selector. |
|
|
321
|
+
| `FoldViewNavComponent` | `fold-view-nav` | Navigation bar styled as tabs. Items carry a `link` (routerLink → a real `<a>`: cmd-click, deep-links, active state auto), an `href`, or nothing (a button); `aria-current="page"` on the active one. `direction="auto"` follows a wrapping `fold-nav-layout`; `collapsed` for an icon rail. For in-page panel switching use `fold-tabs` instead. |
|
|
322
|
+
| `FoldTabsComponent` + `FoldTabPanelComponent` | `fold-tabs` + `fold-tab-panel` | The in-page ARIA Tabs widget: `role="tablist"` + roving arrow-key keyboard, `aria-selected`/`aria-orientation`, each tab wired to its `fold-tab-panel` (`aria-controls` ↔ `aria-labelledby`). Panels take the bar by ref (`[tabs]="t"`) so they coordinate across `fold-nav-layout` slots. |
|
|
323
|
+
| `FoldIconComponent` | `fold-icon` | SVG icon (114-icon built-in set + `FoldIconRegistry`). |
|
|
324
|
+
| `FoldSpinnerComponent` | `fold-spinner` | Indeterminate loading arc (`currentColor`, icon-sized, reduced-motion aware). Decorative by default; `label` → `role="status"`. Powers `loading` on the buttons. |
|
|
325
|
+
| `FoldAvatarComponent` / `…Detail` | `fold-avatar` | Initials/image avatar (square, muted, status ring) + identity cell. |
|
|
326
|
+
| `FoldAvatarListComponent` | `fold-avatar-list` | Overlapping avatar cluster (per-face variant, `limit` + a `+N` overflow chip). |
|
|
327
|
+
| `FoldToastComponent` / `…Container` | `fold-toast` | Frosted snackbar (variant glyph + dismiss) + queue host (+ `FoldToastService`). |
|
|
328
|
+
| `FoldLoadingStateComponent` | `fold-loading` | Loading placeholder — `fold-spinner` + message, in a `role="status"` region; `size` input; stretches to fill. |
|
|
329
|
+
| `FoldEmptyStateComponent` | `fold-empty-state` | Empty-state block (icon + title + message + optional action). |
|
|
330
|
+
| `FoldCalloutComponent` | `fold-callout` | Tinted message row — status colour + icon + message + optional trailing actions; `inset` (bordered, in-flow) appearance. |
|
|
331
|
+
| `FoldDisclosureComponent` | `fold-disclosure` | One summary toggling one collapsible panel — the accordion primitive (open-state is the consumer's to bind); keeps content mounted, unlike native `<details>`. |
|
|
332
|
+
| `FoldPanelHostComponent` | `fold-panel-host` | Side-panel / overlay host (+ `FoldPanelHostService` / `FoldPanelRef` / `FoldPanelToggle`). Modal: accessible name, `inert` background barrier, top-most focus trap, scroll-lock. Localise the close label once via `provideFoldPanelLabels({ close })`. |
|
|
333
|
+
| `FoldPanelHeaderComponent` | `fold-panel-header` | Standard panel header (title/eyebrow, self-closing). Names its dialog (`aria-labelledby`) and reads the app-wide close label. |
|
|
257
334
|
|
|
258
335
|
Directives worth knowing: **`foldSurface`** (`page`·`chrome` — the seam a mixed
|
|
259
336
|
theme re-colours across), **`foldElevated`** (raise any bg-owning element into
|