fold-ng 0.8.1 → 0.10.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 +305 -1
- package/README.md +55 -4
- package/devtools/package.json +4 -0
- package/fesm2022/fold-ng-src-devtools.mjs +218 -0
- package/fesm2022/fold-ng-src-devtools.mjs.map +1 -0
- package/fesm2022/fold-ng.mjs +2238 -1035
- package/fesm2022/fold-ng.mjs.map +1 -1
- package/llms.txt +14 -3
- package/package.json +12 -2
- package/tmp-esm2022/tsconfig.lib.tsbuildinfo +1 -0
- package/tokens/semantic.css +57 -0
- package/types/fold-ng-src-devtools.d.ts +86 -0
- package/types/fold-ng-src-devtools.d.ts.map +1 -0
- package/types/fold-ng.d.ts +925 -44
- package/types/fold-ng.d.ts.map +1 -1
package/CHANGELOG.md
CHANGED
|
@@ -8,6 +8,308 @@ All notable changes to **fold-ng** are documented here. The format follows
|
|
|
8
8
|
|
|
9
9
|
_Nothing yet._
|
|
10
10
|
|
|
11
|
+
## [0.10.0] - 2026-08-11
|
|
12
|
+
|
|
13
|
+
### Changed
|
|
14
|
+
|
|
15
|
+
- **BREAKING — `fold-file-dropzone` defaults to English copy.** `label` was
|
|
16
|
+
`"Glissez un fichier ou parcourez"` and `busyLabel` `"Téléversement en
|
|
17
|
+
cours…"`; they are now `"Drag a file or browse"` and `"Uploading…"`. Both were
|
|
18
|
+
always inputs, so the fix for a French app is to pass the old strings — but a
|
|
19
|
+
library that defaults to one natural language makes every other consumer
|
|
20
|
+
override it just to be readable, which is the portability promise leaking. It
|
|
21
|
+
was the last of the seven release blockers in `docs/RELEASE-READINESS.md`.
|
|
22
|
+
|
|
23
|
+
- **BREAKING — identical toasts collapse instead of stacking.** A `show()` whose
|
|
24
|
+
message _and_ variant match a toast already on screen now folds into it as a
|
|
25
|
+
`×N` tally and restarts its countdown, rather than queueing a copy: a retry
|
|
26
|
+
loop used to bury the screen under the same sentence. Opt out with
|
|
27
|
+
`provideFoldToasts({ dedupe: false })`. `FoldToast` gained a required
|
|
28
|
+
`repeats` field, so anything constructing that type by hand must supply it.
|
|
29
|
+
|
|
30
|
+
- **`FoldToastService.show()` returns the toast's id** (it returned `void`). The
|
|
31
|
+
id was generated and thrown away, which made a sticky "Uploading…" impossible
|
|
32
|
+
to close from the code that opened it. A deduped call returns the id of the
|
|
33
|
+
toast it folded into. Ids now come from `FoldIdService`'s counter rather than
|
|
34
|
+
`crypto.randomUUID()`, which **throws outright** in a non-secure context
|
|
35
|
+
(plain http off localhost) and whose randomness bought nothing for an id that
|
|
36
|
+
only has to be unique within one queue.
|
|
37
|
+
|
|
38
|
+
### Added
|
|
39
|
+
|
|
40
|
+
- **`fold-info` — the `i` that answers "what is this?", now a primitive.** The
|
|
41
|
+
affordance shipped inlined in the field label row; it is extracted so the same
|
|
42
|
+
bubble works where there is no field at all — a dashboard card's corner, a
|
|
43
|
+
table header — which is exactly where the second consumer had hand-rolled it
|
|
44
|
+
(LaFolieDouce's admin: ~30 sites across the growth dashboard and the booking
|
|
45
|
+
rules). `text` · `label` (accessible name, English default) · `placement`.
|
|
46
|
+
`fold-input-base` now composes it instead of carrying its own copy, so the
|
|
47
|
+
`info` input on every labelled field renders the same component. A click, not
|
|
48
|
+
a hover: hover-only help is unreachable on a touch screen.
|
|
49
|
+
|
|
50
|
+
- **`maxVisible` bounds the toast stack.** Beyond the cap the oldest toast is
|
|
51
|
+
evicted — it has been on screen longest, so it is the one already read. Unset
|
|
52
|
+
(the default) stays unbounded. Deliberately eviction and not a waiting queue:
|
|
53
|
+
a queue only drains when a visible toast leaves, and a sticky one — an
|
|
54
|
+
`error`, by default — never does, so the backlog would sit behind it forever.
|
|
55
|
+
|
|
56
|
+
- **`fold-toast` pauses its countdown while it is being read.** Hovering the
|
|
57
|
+
toast, or moving the keyboard focus into it, freezes the auto-dismiss timer;
|
|
58
|
+
leaving resumes it with **the time that was left**, not a fresh `duration` —
|
|
59
|
+
a toast that renewed itself on every mouse pass would never leave. Focus
|
|
60
|
+
moving between the message and the close button counts as staying inside.
|
|
61
|
+
This is WCAG 2.2.1 (Timing Adjustable): the previous timer ran regardless, so
|
|
62
|
+
a message could expire mid-sentence, or while the pointer was travelling to
|
|
63
|
+
its ✕. The paused state is exposed as `data-paused` for styling.
|
|
64
|
+
|
|
65
|
+
- **`info` on every labelled input — the explanation a `hint` can't carry.** An
|
|
66
|
+
`i` button at the end of the label line reveals a sentence or two in a
|
|
67
|
+
`fold-popover`. Lives in `fold-input-base`, so it lands on the whole family at
|
|
68
|
+
once: `fold-input`, `fold-number-input`, `fold-select`, `fold-textarea`,
|
|
69
|
+
`fold-date`, `fold-time`, `fold-listbox`, `fold-multiselect` (`[info]`, plus
|
|
70
|
+
`[infoLabel]` for the button's accessible name, default `More information`).
|
|
71
|
+
Composes with `hint` rather than replacing it — short line under the control,
|
|
72
|
+
the _why_ behind the `i`. The panel rides the popover's native top layer, so a
|
|
73
|
+
long explanation never pushes the next control down, and it escapes any
|
|
74
|
+
`overflow: hidden`. Consumers were hand-rolling this: LaFolieDouce B2B had a
|
|
75
|
+
bespoke absolutely-positioned bubble anchored to each field wrapper.
|
|
76
|
+
|
|
77
|
+
### Fixed
|
|
78
|
+
|
|
79
|
+
- **Opening a panel no longer shoves the page sideways.** The main content
|
|
80
|
+
jumped left by the panel's width and eased back — a long-standing glitch whose
|
|
81
|
+
cause turned out to be neither of the two suspects (an inner scrollbar, a
|
|
82
|
+
`backdrop-filter` repaint). Measured frame by frame: a panel begins its enter
|
|
83
|
+
animation parked off-edge at `translateX(100%)`, the dock did not clip, so the
|
|
84
|
+
parked panel joined the positioned host's **scrollable overflow**
|
|
85
|
+
(`scrollWidth` 960 → 1221 on the gallery); the focus trap then moved focus into
|
|
86
|
+
it and the browser scrolled the host sideways to reveal it
|
|
87
|
+
(`scrollLeft` 0 → 261); the slide-in shrank the overflow again and the scroll
|
|
88
|
+
was clamped back frame by frame, hence the eased return. Fixed with
|
|
89
|
+
`overflow: clip` on the dock — a parked panel has no business in anyone's
|
|
90
|
+
scrollable overflow — plus `focus({ preventScroll: true })` when a focus trap
|
|
91
|
+
activates, since entering an overlay must never scroll the page behind it.
|
|
92
|
+
`e2e/panel.spec.ts` samples the whole animation and fails on any sideways
|
|
93
|
+
scroll; jsdom cannot see this class of bug at all.
|
|
94
|
+
|
|
95
|
+
- **A horizontal tab bar that doesn't fit now scrolls instead of clipping its
|
|
96
|
+
tail.** `fold-view-nav` and `fold-tabs` share a bar whose host clipped its
|
|
97
|
+
overflow while its items never wrap — so on a phone, the last entries of a
|
|
98
|
+
four-item `size="comfortable"` bar simply vanished, and with them any way of
|
|
99
|
+
reaching those pages. The host now scrolls on the inline axis (thin house
|
|
100
|
+
scrollbar, `overscroll-behavior-x: contain`) and the bar keeps its natural
|
|
101
|
+
width. Vertical rails are untouched — the page scroll already covers them, and
|
|
102
|
+
an inner scroll box there would trap the wheel — and so is `collapsed`, the
|
|
103
|
+
icon accordion, which is designed to fit any width and needs its overflow
|
|
104
|
+
visible for its tooltips.
|
|
105
|
+
|
|
106
|
+
## [0.9.0] - 2026-08-04
|
|
107
|
+
|
|
108
|
+
### Changed
|
|
109
|
+
|
|
110
|
+
- **BREAKING — the shell owns the content scroll by default; pages flow.** The
|
|
111
|
+
all-in-one scroll model (`docs/scroll.md`), slice A. `fold-app-shell`'s
|
|
112
|
+
`contentScroll="clip" | "auto"` input is **renamed and reshaped** to
|
|
113
|
+
`scroll="scroll" | "stage"`, and the **default flips**: the shell's content
|
|
114
|
+
region now owns the scroll (`scroll`, was `clip`/page-owns), so a
|
|
115
|
+
`fold-page-layout` inside it no longer double-scrolls. `fold-page-layout` gains
|
|
116
|
+
`scroll="flow" | "own"` and **defaults to `flow`** — it owns no scroll box and
|
|
117
|
+
flows inside the shell. Net effect for a normal page: identical, minus the P0
|
|
118
|
+
bug where a `footerBehavior="scroll"` footer sat below an unreachable
|
|
119
|
+
`overscroll-behavior: contain` boundary (this **deletes the LaFolieDouce B2B
|
|
120
|
+
`!important` workaround**). The scroll lives on an **inner** box, never the
|
|
121
|
+
content region itself, so a docked panel anchored to the region stays fixed
|
|
122
|
+
over the frame. Migration: a page that must scroll as a self-contained unit
|
|
123
|
+
(a split view whose shell must not move) sets `fold-app-shell scroll="stage"`
|
|
124
|
+
and/or `fold-page-layout scroll="own"`. A short page still pins a trailing
|
|
125
|
+
`scroll` footer to the bottom (the content grows to fill), replacing the old
|
|
126
|
+
`margin-top: auto` glue.
|
|
127
|
+
|
|
128
|
+
- **`@angular/router` is now a declared (optional) peer dependency.** `fold-view-nav`
|
|
129
|
+
imports `RouterLink`/`RouterLinkActive`, but the package only listed router as a
|
|
130
|
+
devDependency — an undeclared peer that happened to resolve because every Angular
|
|
131
|
+
app ships Router. It's now in `peerDependencies` with `peerDependenciesMeta:
|
|
132
|
+
{ "@angular/router": { optional: true } }`, so apps that use the router-coupled
|
|
133
|
+
nav components (view-nav, and the new breadcrumb / back-link) get a correct
|
|
134
|
+
install signal, while apps that don't aren't forced to add it (those components
|
|
135
|
+
tree-shake out). No API change.
|
|
136
|
+
|
|
137
|
+
- **`FoldPanelHostService.open()` accepts an optional-data panel without a manual
|
|
138
|
+
type widen.** A panel whose `data` input is optional (`data = input<T>()` →
|
|
139
|
+
`InputSignal<T | undefined>`) used to force `open<T | undefined, R>()` to dodge
|
|
140
|
+
a `TS2345` (hit by the LaFolieDouce B2B PickupPanel). `FoldPanelContent<T>.data`
|
|
141
|
+
is now typed as the covariant **read** side (`Signal<T | undefined>`) instead of
|
|
142
|
+
the invariant `InputSignal<T>`, so both a required (`input.required<T>()`) and an
|
|
143
|
+
optional data input satisfy the contract — `open(Cmp, { data })` infers `T` from
|
|
144
|
+
the value with no widen, and the data value stays type-checked. Non-breaking for
|
|
145
|
+
existing panels (an `InputSignal<T>` still assigns to the contract).
|
|
146
|
+
|
|
147
|
+
### Added
|
|
148
|
+
|
|
149
|
+
- **House scrollbar tokens + `overflow-anchor` — scroll-system Slice C.** The
|
|
150
|
+
shell content scroll box and every `[foldScrollRegion]` now paint one tokenised
|
|
151
|
+
scrollbar: `--fold-scrollbar-size` / `-radius` / `-thumb` / `-track`, with the
|
|
152
|
+
thumb derived from the surface's own text so it adapts per theme **and** per
|
|
153
|
+
surface (a chrome rail vs the page). Standard `scrollbar-width`/`scrollbar-color`
|
|
154
|
+
everywhere, plus a `@supports selector(::-webkit-scrollbar)` layer (shipped in
|
|
155
|
+
`tokens.css`) for the thumb radius on Blink/WebKit. Both regions also set
|
|
156
|
+
`overflow-anchor: auto` so the reading position survives content reflowing above
|
|
157
|
+
them. (The `--fold-scrollbar-*` knobs are component vars, out of the colour
|
|
158
|
+
catalogue — retune them on any ancestor. The viewport-**resize** anchoring
|
|
159
|
+
correction, which native `overflow-anchor` doesn't cover, is a deferred
|
|
160
|
+
follow-up — see `docs/scroll.md`.)
|
|
161
|
+
|
|
162
|
+
- **`[foldScrollRegion]` + the shell scroll registry — scroll-system Slice B.**
|
|
163
|
+
The one opt-in of the scroll model (`docs/scroll.md`): with `fold-app-shell`
|
|
164
|
+
owning the page scroll, a layout that needs an independently-scrolling area (a
|
|
165
|
+
split list/detail, a data-table body, a sticky sidebar, a panel body) marks it
|
|
166
|
+
with `[foldScrollRegion]` instead of hand-rolling `overflow`. The directive sets
|
|
167
|
+
the three foot-guns (`overflow`, `min-*: 0`, `overscroll-behavior: contain`) and
|
|
168
|
+
the thin house scrollbar, and takes an axis (`block` default · `inline` · `both`).
|
|
169
|
+
It **registers with the new `ScrollRegionRegistry`**, which the shell also feeds
|
|
170
|
+
with its own content scroll box; the panel host freezes the registry when a
|
|
171
|
+
modal opens, so the page stops scrolling behind the overlay even though the
|
|
172
|
+
scroll owner is an inner box, not `document.body`. Freezing toggles a
|
|
173
|
+
`.fold-scroll-frozen` class (`overflow: hidden !important`, shipped in
|
|
174
|
+
`tokens.css`), never an inline write, so a region's own overflow is never
|
|
175
|
+
clobbered. Registry injection is optional, so the directive is a useful bounded
|
|
176
|
+
scroll box even without a shell. Gallery `/scroll-region`; 19 specs. (Migrating
|
|
177
|
+
the data-table / panel bodies onto it is deferred — they already scroll
|
|
178
|
+
correctly; the win there is registry coordination, not the overflow.)
|
|
179
|
+
|
|
180
|
+
- **`fold-back-link` — the “← Back” affordance for a detail page.** Three modes,
|
|
181
|
+
picked by which input is set: an in-app `routerLink`, a plain `href`, or — with
|
|
182
|
+
neither — a `<button>` that goes **back in history** (`Location.back()`).
|
|
183
|
+
Router-coupled but degradable (the history mode needs no router; `RouterLink`
|
|
184
|
+
only instantiates on a `routerLink`). Gallery `/back-link`; 4 specs.
|
|
185
|
+
|
|
186
|
+
- **`fold-breadcrumb` — a hierarchical link trail.** Data-driven: pass `[items]`
|
|
187
|
+
where each crumb links by an Angular `routerLink` **or** a plain `href`, so it
|
|
188
|
+
works in a router app and degrades to anchors without one (importing it never
|
|
189
|
+
forces `@angular/router` — `RouterLink` only instantiates on a crumb that sets
|
|
190
|
+
`routerLink`). The last item renders as the current page (`aria-current="page"`),
|
|
191
|
+
never a link; it's a `navigation` landmark with decorative chevron separators.
|
|
192
|
+
Gallery `/breadcrumb`; 5 specs.
|
|
193
|
+
|
|
194
|
+
- **Panel bottom sheet (`side: 'bottom'`) + responsive `side: 'auto'`.** The panel
|
|
195
|
+
host gained two docking edges beyond `left`/`right`: `bottom` is a full-width
|
|
196
|
+
sheet whose height is content-driven up to a max (`85dvh`) with the body
|
|
197
|
+
scrolling, slides up, rounded top, and a top **grabber** that taps to dismiss
|
|
198
|
+
(honours `disableClose`). `auto` docks **right on a wide host, bottom on a
|
|
199
|
+
narrow one** — the switch is container-driven via `@container` on the panel
|
|
200
|
+
host's own inline-size (fold's "responsive on its own width", not the viewport),
|
|
201
|
+
so it reacts to the content region, not the screen. All the modal machinery
|
|
202
|
+
(focus-trap, `inert` barrier, scroll-lock, `disableClose`) is edge-agnostic and
|
|
203
|
+
reused as-is. Motivated by the LaFolieDouce storefront cart on mobile. Gallery
|
|
204
|
+
`/panel` gained “Bottom sheet” + “Auto (by width)” triggers; +6 host specs.
|
|
205
|
+
(Pointer-drag-to-dismiss on the grabber is a deferred nice-to-have.)
|
|
206
|
+
|
|
207
|
+
- **`fold-panel-footer` — the action bar for panels/dialogs.** Pairs with
|
|
208
|
+
`fold-panel-header`: the tokenised bar at a panel's bottom edge (glass top
|
|
209
|
+
border + padding + button alignment), so a panel no longer hand-rolls a
|
|
210
|
+
`<footer class="foot">`. `align="end"` (default — the Annuler/Confirmer pair)
|
|
211
|
+
· `between` (a leading total + trailing actions) · `start`. Sits with
|
|
212
|
+
`flex: none`, so it stays pinned while the body scrolls — no `position: sticky`.
|
|
213
|
+
Probed against the 2nd consumer (LaFolieDouce): **17** hand-rolled panel footers
|
|
214
|
+
across its 3 apps, so it earns a primitive. Gallery `/panel` “Panel footer”; 3 specs.
|
|
215
|
+
|
|
216
|
+
- **`fold-danger-zone` — the destructive-action block.** A framed region for
|
|
217
|
+
“delete X” settings: a title, a projected explanation, and a guarded action.
|
|
218
|
+
**Two appearances** — `filled` (alert-tinted block) and `section`, a danger
|
|
219
|
+
_section_ with a **normal-background body** so it can host ordinary content, only
|
|
220
|
+
the frame + heading signalling danger (the GitHub “Danger Zone” look). The
|
|
221
|
+
destructive control's confirm **reveals on click**: an `actionLabel` button
|
|
222
|
+
opens an in-place `fold-inline-confirm` — a plain “are you sure?”, or a
|
|
223
|
+
type-to-confirm field when `confirmPhrase` is set (the input is never shown until
|
|
224
|
+
the button is clicked). `(confirmed)` emits the typed text (or `""`); omit
|
|
225
|
+
`actionLabel` for a framed section with no action. `role="group"` +
|
|
226
|
+
`aria-labelledby`. Gallery `/danger-zone`; 5 specs.
|
|
227
|
+
|
|
228
|
+
- **`fold-multiselect` bulk actions — `allowSelectAll` / `allowClear`.** A sticky
|
|
229
|
+
bar at the top of the panel offers **Select all** (adds every enabled option,
|
|
230
|
+
skipping disabled rows and preserving an already-picked disabled one) and
|
|
231
|
+
**Clear** (empties the set). Each button is gated — select-all disables once
|
|
232
|
+
everything enabled is picked, clear disables while empty. Labels are overridable
|
|
233
|
+
(`selectAllLabel` / `clearLabel`). The panel is now a wrapper around the
|
|
234
|
+
`role="listbox"` (the bar sits outside it, so it stays valid ARIA). Gallery
|
|
235
|
+
`/listbox` multiselect tab enables both; 5 specs.
|
|
236
|
+
|
|
237
|
+
- **`fold-optgroup` — labelled option groups for the styleable selects.** The
|
|
238
|
+
counterpart to the native `<optgroup>`: wrap `<fold-option>`s in
|
|
239
|
+
`<fold-optgroup label="…">` to sort a long list into sections. Purely
|
|
240
|
+
presentational — the owning `fold-listbox` / `fold-multiselect` now discovers
|
|
241
|
+
options with a `descendants: true` query, so grouped options join the same
|
|
242
|
+
flat, document-ordered list the roving keyboard core walks; the header carries
|
|
243
|
+
`role="group"` + `aria-labelledby` (no `role="option"`), so nav skips straight
|
|
244
|
+
over it. Also supported in the data-driven **`[options]` array API**: an entry
|
|
245
|
+
is a `FoldSelectOption<T>` or a labelled `FoldSelectOptionGroup<T>` (mix both),
|
|
246
|
+
narrowed by the exported `isFoldSelectOptionGroup` guard. Gallery `/listbox`
|
|
247
|
+
“grouped” tab shows both forms; specs cover projected + array discovery,
|
|
248
|
+
cross-group roving and selection.
|
|
249
|
+
|
|
250
|
+
- **The icon devtool browses by category.** `FoldIconDevtoolComponent` now
|
|
251
|
+
groups the live registry into **collapsible sections** — UI · Navigation ·
|
|
252
|
+
Commerce · Music · Status · People · Brands (+ a **Custom** bucket for
|
|
253
|
+
host-registered icons) — each with its icon count; a search only surfaces the
|
|
254
|
+
categories it hits. New public `FOLD_BUILTIN_ICON_CATEGORIES` (+ `FoldIconCategoryId`)
|
|
255
|
+
is the single source of truth for the grouping (each icon file owns its slice).
|
|
256
|
+
|
|
257
|
+
- **`fold-ng/devtools` now builds as a real ng-packagr secondary entry**, so
|
|
258
|
+
`import("fold-ng/devtools")` resolves for **published (npm) consumers**, not
|
|
259
|
+
only source-consumed ones. It compiles to its own FESM + `d.ts` and imports the
|
|
260
|
+
primary `fold-ng` by name; `finalize-dist` normalises ng-packagr's flattened
|
|
261
|
+
`./src/devtools` export to the public `./devtools` subpath (+ a node10 directory
|
|
262
|
+
manifest). `attw` all-🟢, `publint` clean. The api-surface guard was generalised
|
|
263
|
+
to snapshot every published entry point (`.` + `./devtools`).
|
|
264
|
+
|
|
265
|
+
- **`fold-ng/devtools` — an opt-in dev-tools entry, starting with
|
|
266
|
+
`FoldIconDevtoolComponent`.** A **dev-only** floating panel that browses the live
|
|
267
|
+
`FoldIconRegistry` (built-ins + whatever the host app registered), with a search,
|
|
268
|
+
a preview grid, and a mini playground that builds a `<fold-icon>` snippet and
|
|
269
|
+
copies it. The panel is **draggable** (grab the header) and **minimisable**
|
|
270
|
+
(collapses to a pill). Published from a **separate entry** so it never lands in a
|
|
271
|
+
bundle that doesn't ask for it — import it behind a dev guard
|
|
272
|
+
(`if (isDevMode())` + a dynamic `import("fold-ng/devtools")`) so production
|
|
273
|
+
tree-shakes it away. Dogfooded in the gallery (primary-rail "Dev tools" + the
|
|
274
|
+
`/icons` hero CTA).
|
|
275
|
+
- **`FoldIconRegistry.names()`** — the sorted list of every registered icon name
|
|
276
|
+
(built-ins + runtime additions), reactive. Powers catalogue tooling (the icon
|
|
277
|
+
devtool).
|
|
278
|
+
|
|
279
|
+
- **A `commerce` icon category — 21 e-commerce glyphs.** The built-in set had no
|
|
280
|
+
cart, catalogue, payment or fulfilment icons, so a consumer reused `package` as a
|
|
281
|
+
placeholder for both a cart and a delivery tab (`docs/consumer-friction.md` Round
|
|
282
|
+
4 #3). New `COMMERCE_ICONS` (the 7th category, wired into `FOLD_BUILTIN_ICONS` and
|
|
283
|
+
the `/icons` gallery): `shopping-cart` · `shopping-bag` · `basket` · `package` ·
|
|
284
|
+
`package-check` · `tag` · `tags` · `barcode` · `qr-code` · `gift` · `credit-card`
|
|
285
|
+
· `wallet` · `receipt` · `coins` · `banknote` · `percent` · `truck` · `store` ·
|
|
286
|
+
`warehouse` · `map-pin` · `package-return`. Same self-contained inlined-SVG /
|
|
287
|
+
`currentColor` contract; names autocomplete on `FoldIconName`.
|
|
288
|
+
|
|
289
|
+
- **`fold-textarea` — the multiline sibling of `fold-input`.** Same box chrome
|
|
290
|
+
(tokens, sizes, `panel` variant, focus/disabled) via `input-shell.scss` and the
|
|
291
|
+
same label / required / hint / error chrome via `fold-input-base` — so a note
|
|
292
|
+
field is no longer a hand-rolled native `<textarea>` + copied box CSS. **No
|
|
293
|
+
resize handle by design**: the box keeps its `rows` height and **wraps +
|
|
294
|
+
scrolls** overflow (`resize: none; overflow-y: auto`), so a user-dragged corner
|
|
295
|
+
can't break a panel layout. `FormValueControl<string>` (`[formField]` or
|
|
296
|
+
`[(value)]`).
|
|
297
|
+
- **`fold-date` + `fold-time` — the temporal-field wrappers.** Two sibling
|
|
298
|
+
controls (distinct selectors for call-site clarity, the same "one control, one
|
|
299
|
+
job" split as `fold-input` vs `fold-number-input`): `fold-date` wraps the native
|
|
300
|
+
`<input type="date">` family (`type`: `date` · `datetime-local` · `month` ·
|
|
301
|
+
`week`), `fold-time` wraps `<input type="time">`. Both wrap the native control
|
|
302
|
+
the way `fold-select` wraps `<select>` — keeping the OS calendar/clock + mobile
|
|
303
|
+
keyboard — and hand back a **typed `[(value)]`** (the native string, `YYYY-MM-DD`
|
|
304
|
+
/ `HH:mm`), so consumers stop hand-writing an `inputValue($event)` reader.
|
|
305
|
+
`min` / `max` / `step` pass through; both share the `fold-input` box + field
|
|
306
|
+
chrome. **Not** a calendar popover (that's the `fold-calendar` family) — the plain
|
|
307
|
+
fields. `FormValueControl<string>`.
|
|
308
|
+
- Surfaced by the 2nd consumer (LaFolieDouce B2B); see `docs/consumer-friction.md`
|
|
309
|
+
Round 4 #2. The shared `_field-box.scss` `size()` mixin gained a `$height: false`
|
|
310
|
+
opt-out (a `<textarea>`'s height is content-driven), and `readInputValue` now
|
|
311
|
+
reads `<textarea>` targets.
|
|
312
|
+
|
|
11
313
|
## [0.8.1] - 2026-08-02
|
|
12
314
|
|
|
13
315
|
### Changed
|
|
@@ -1056,7 +1358,9 @@ design-token stylesheet.
|
|
|
1056
1358
|
`currentColor`; `prefers-reduced-motion` + `forced-colors` are respected;
|
|
1057
1359
|
strings localise via inputs / providers (`provideFoldPanelLabels`).
|
|
1058
1360
|
|
|
1059
|
-
[unreleased]: https://github.com/hugoheynard/fold-ng/compare/v0.
|
|
1361
|
+
[unreleased]: https://github.com/hugoheynard/fold-ng/compare/v0.10.0...HEAD
|
|
1362
|
+
[0.10.0]: https://github.com/hugoheynard/fold-ng/releases/tag/v0.10.0
|
|
1363
|
+
[0.9.0]: https://github.com/hugoheynard/fold-ng/releases/tag/v0.9.0
|
|
1060
1364
|
[0.8.1]: https://github.com/hugoheynard/fold-ng/releases/tag/v0.8.1
|
|
1061
1365
|
[0.8.0]: https://github.com/hugoheynard/fold-ng/releases/tag/v0.8.0
|
|
1062
1366
|
[0.7.0]: https://github.com/hugoheynard/fold-ng/releases/tag/v0.7.0
|
package/README.md
CHANGED
|
@@ -287,9 +287,47 @@ radius / text / icon-size / space / motion / blur scales — see
|
|
|
287
287
|
All standalone, signals-first, styled against the semantic tokens. Import from
|
|
288
288
|
the package root.
|
|
289
289
|
|
|
290
|
+
### Find one by what you need
|
|
291
|
+
|
|
292
|
+
The reference table below is keyed by component **name** — but you usually know
|
|
293
|
+
your **intent**, not the name (that's how an uppercase mini-title gets hand-rolled
|
|
294
|
+
instead of reaching for `fold-element-title`). Start here; **before hand-rolling a
|
|
295
|
+
label, field, badge, card or overlay, scan this table** — fold almost certainly
|
|
296
|
+
ships it.
|
|
297
|
+
|
|
298
|
+
| I need to… | Reach for |
|
|
299
|
+
| ---------------------------------------------------------------- | ------------------------------------------------------------------------------------------------------ |
|
|
300
|
+
| a small **uppercase label / eyebrow** over a group | `fold-element-title` (`variant="eyebrow"` · `bar` · `title`) |
|
|
301
|
+
| a **section** with a title + description + actions | `fold-page-section` (semantic `<section>` + `aria-labelledby`) |
|
|
302
|
+
| show **read-only label/value pairs** (a recap) | `fold-field-list` / `fold-field` (`dl/dt/dd`) |
|
|
303
|
+
| a **text** field | `fold-input` — number → `fold-number-input` · multiline note → `fold-textarea` |
|
|
304
|
+
| a **date** / **time** field | `fold-date` (date·datetime-local·month·week) · `fold-time` |
|
|
305
|
+
| a **dropdown** | `fold-select` (native) — custom rows → `fold-listbox` · multi → `fold-multiselect` |
|
|
306
|
+
| an **on/off** field · a **password** field | `fold-checkbox` · `fold-password-field` |
|
|
307
|
+
| a **range** / **debounced search** | `fold-slider` / `fold-range-slider` · `fold-search` |
|
|
308
|
+
| a **button** · **icon-only** action · icon **on/off** | `fold-button` (`<button>`/`<a>`) · `fold-button-icon` · `fold-toggle-icon` · text link → `fold-link` |
|
|
309
|
+
| an inline **"are you sure?"** guard | `fold-inline-confirm` (no modal — simple · type-to-confirm · secret) |
|
|
310
|
+
| a **"delete X" danger block** (type-to-confirm) | `fold-danger-zone` (alert frame + blast-radius text + retype-to-arm) |
|
|
311
|
+
| a **status / count pill** · status→colour | `fold-badge` · `fold-status-badge` |
|
|
312
|
+
| a **tinted message / alert** row | `fold-callout` (`inset` for in-flow) |
|
|
313
|
+
| a **"what is this?"** help bubble | `fold-info` (the `i` → popover; also the `info` input on every labelled field) |
|
|
314
|
+
| a transient **toast** | `fold-toast` + `FoldToastService` |
|
|
315
|
+
| a **card** · titled info card · page **splash** | `fold-card` · `fold-context-card` · `fold-hero-section` (bordered → `fold-hero-card`) |
|
|
316
|
+
| in-page **tabs** · a routed **nav bar** · a segmented control | `fold-tabs` · `fold-view-nav` · `fold-view-toggle` / `fold-choice-row` |
|
|
317
|
+
| a **breadcrumb** trail (routerLink or href) | `fold-breadcrumb` (`[items]`, last = current page) |
|
|
318
|
+
| a **"← Back"** link (route, href, or history) | `fold-back-link` (`routerLink` / `href` / history-back button) |
|
|
319
|
+
| a **table** + **pagination** | `fold-data-table` · `fold-paginator` |
|
|
320
|
+
| an **avatar** · a cluster | `fold-avatar` (+ `…Detail`) · `fold-avatar-list` |
|
|
321
|
+
| an **empty** / **loading** state | `fold-empty-state` · `fold-loading` / `fold-spinner` |
|
|
322
|
+
| a **side panel** · anchored **popover** · actions **menu** | `fold-panel-host` · `fold-popover` · `fold-dropdown` |
|
|
323
|
+
| a **collapsible** section | `fold-disclosure` (a modal dialog is roadmap — use a modal `fold-panel-host` or `fold-inline-confirm`) |
|
|
324
|
+
| an **icon** · a **calendar** · a **timeline / stepper** | `fold-icon` · `fold-calendar-month`/`-week`/`-day`/`-list`/`-agenda`/`-timegrid` · `fold-timeline` |
|
|
325
|
+
| a **nav rail** · app **skeleton** · a **detail page** with rails | `fold-menu` · `fold-app-shell` · `fold-aside-layout` (page scaffold → `fold-page-layout`) |
|
|
326
|
+
| **drag-drop** file upload | `fold-file-dropzone` |
|
|
327
|
+
|
|
290
328
|
| Component | Selector | What it is |
|
|
291
329
|
| -------------------------------------------------------- | -------------------------------------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
|
|
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`; `
|
|
330
|
+
| `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`; `scroll` scroll·stage — the shell owns the content scroll by default so pages flow (`[foldScrollRegion]` opts a nested area back into its own scroll); built-in skip-link to a focusable `<main>`. Regions float per-surface via `foldElevated`, not a shell flag). |
|
|
293
331
|
| `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
332
|
| `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
333
|
| `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. |
|
|
@@ -304,21 +342,26 @@ the package root.
|
|
|
304
342
|
| `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
343
|
| `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
344
|
| `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. |
|
|
345
|
+
| `FoldTextareaComponent` | `fold-textarea` | Multiline sibling of `fold-input` (`value: string`). **No resize handle** — fixed `rows` height, wraps + scrolls overflow. Shares the box + `label`/`required`/`hint`/`error` chrome. Signal Forms or `[(value)]`. |
|
|
346
|
+
| `FoldSelectComponent` | `fold-select` | Native `<select>` wrapper (options projected as `<option>`); shares `fold-input`'s box chrome. Signal Forms (`FormValueControl<string>`) or `[(value)]`. For custom rows use `fold-listbox`. |
|
|
347
|
+
| `FoldDateComponent` | `fold-date` | Native calendar-date wrapper (`type` = date · datetime-local · month · week) — keeps the OS picker, hands back a typed `[(value)]` string (`YYYY-MM-DD`). `min`/`max`/`step` pass through. Time-of-day → `fold-time`. |
|
|
348
|
+
| `FoldTimeComponent` | `fold-time` | Native time-of-day wrapper (`<input type="time">`) — typed `[(value)]` string (`HH:mm`), `min`/`max`/`step`. The sibling of `fold-date`. |
|
|
307
349
|
| `FoldCheckboxComponent` | `fold-checkbox` | Boolean control — a native `<input type="checkbox">` (keyboard, `indeterminate`, forms) restyled to tokens. Signal Forms (`[formField]`, a `FormCheckboxControl`) or standalone `[(checked)]`; `indeterminate`, `label`/`ariaLabel`, `hint`/`errors`, `size`. |
|
|
308
350
|
| `FoldPasswordFieldComponent` | `fold-password-field` | Password input + a live requirements checklist (a dot/tick per rule). Rules injected via `FoldPasswordRule` (`{ label, test }` — regex/zod/anything); `revealable` eye (a `fold-input` capability); `marker` dot/check; `[rules]` slot to redesign the list; `validChange`; Signal Forms. |
|
|
309
351
|
| `FoldViewToggleComponent` | `fold-view-toggle` | Segmented single-select (Cards/Table, density, chart-mode…). Generic `options` (`{ value, icon?, label?, ariaLabel?, disabled? }`) + `[(value)]`; a real `role="radiogroup"` — roving tabindex, arrow keys, Home/End, disabled-skip; `size`, `iconOnly`, `activeStyle` (raised / accent). |
|
|
310
352
|
| `FoldSearchComponent` | `fold-search` | Debounced search box — an `fold-input` that emits `searchChange` once typing settles (`delayMs`), trimmed + de-duplicated. |
|
|
311
353
|
| `FoldListboxComponent` / `FoldOptionComponent` | `fold-listbox` / `fold-option` | Styleable single-select — the richer sibling of `fold-select` (native `<select>`) for options that need custom rows (icon, second line, status). On `fold-popover`; `role="listbox"` + `aria-activedescendant`, full keyboard (↑/↓, `Home`/`End`, type-ahead, `Enter`). Signal Forms (`FormValueControl<string>`, `[formField]`/`[(value)]`); shares `fold-input`'s box chrome. |
|
|
312
354
|
| `FoldMultiselectComponent` | `fold-multiselect` | Multi-select sibling of `fold-listbox` (same popover + `fold-option` rows). Value is a set (`readonly string[]`); activating a row toggles it and the panel stays open. Separate component — not a `multiple` flag — so the Signal-Forms value type stays honest. `role="listbox"` + `aria-multiselectable`; the trigger summarises the picks. |
|
|
355
|
+
| `FoldOptgroupComponent` | `fold-optgroup` | Labelled group of `<fold-option>`s inside a `fold-listbox` / `fold-multiselect` — the styleable `<optgroup>`. Presentational: `role="group"` + `aria-labelledby` header (no `role="option"`, so keyboard nav skips it); the owner discovers grouped options in document order, so roving crosses groups seamlessly. |
|
|
313
356
|
| `FoldSliderComponent` | `fold-slider` | Single-value range slider — a styled native `<input type="range">` (design-system track/fill/thumb). Signal Forms (`[formField]`, a `FormValueControl<number>`) or `[(value)]`; real `<label for>`, `aria-valuetext`, `hint`/`errors`, focus ring. |
|
|
314
357
|
| `FoldRangeSliderComponent` | `fold-range-slider` | Dual-thumb range slider selecting a `{ min, max }` window (shares the slider track/thumb). Two-way `[(value)]`; a labelled `role="group"`, per-thumb i18n aria (`minLabel`/`maxLabel`) + formatted `aria-valuetext`, `disabled`. |
|
|
315
|
-
| `FoldRangeSliderComponent` | `fold-range-slider` | Dual-thumb slider selecting a `{ min, max }` window over `[min, max]`; shares the slider track/fill/thumb. |
|
|
316
358
|
| `FoldFileDropzoneComponent` | `fold-file-dropzone` | File-picker dropzone — drag-over visuals, keyboard activation, hidden `<input type=file>` plumbing; emits the picked `File[]` (presentational — never uploads). |
|
|
317
359
|
| `FoldLinkComponent` | `fold-link` | Inline text link / link-button (icons, accent · muted). |
|
|
318
360
|
| `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)`. |
|
|
319
361
|
| `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`. |
|
|
320
362
|
| `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`. |
|
|
321
363
|
| `FoldInlineConfirmComponent` | `fold-inline-confirm` | In-place “are you sure?” guard — the projected trigger swaps to a confirm/cancel row (no modal). Simple (`confirmed` emits `""`), type-to-confirm (`[match]`), or secret (`password`, masked, emits the value). `confirmIcon` + a chosen `cancelIcon`; `Escape` cancels; `message` announced via `aria-describedby`; focus in-then-back; controlled `[(open)]` + `keepOpenOnConfirm` for async pending; i18n via `provideFoldInlineConfirmLabels`. |
|
|
364
|
+
| `FoldDangerZoneComponent` | `fold-danger-zone` | Framed destructive-action block for “delete X” settings. `appearance="filled"` (alert-tinted) or `"section"` (a danger section: alert border + normal-background body for ordinary content). The confirm **reveals on click** — an `actionLabel` button opens an in-place `fold-inline-confirm` (plain “are you sure?”, or type-to-confirm when `confirmPhrase` is set); `(confirmed)` emits the typed text. Omit `actionLabel` for a section with no action. `role="group"` + `aria-labelledby`. |
|
|
322
365
|
| `FoldDataTableComponent` | `fold-data-table` | Controlled roster table — sortable sticky header, tone rows, controlled selection (checkbox column), roving-keyboard nav, `mobileLayout` (scroll / auto-cards / custom `foldRowCard`), an optional `foldToolbar` bar, sticky-first, density. |
|
|
323
366
|
| `FoldPaginatorComponent` | `fold-paginator` | Server-side paginator (size selector + range + page nav). |
|
|
324
367
|
| `FoldTimelineComponent` | `fold-timeline` | Connected rail of nodes (dot + optional date + label) — `vertical` navigable history or `horizontal` step progress; nodes optionally clickable. |
|
|
@@ -326,8 +369,10 @@ the package root.
|
|
|
326
369
|
| `FoldStatusBadgeComponent` | `fold-status-badge` | Status→colour badge (maps a domain status key to a tone). |
|
|
327
370
|
| `FoldChoiceRowComponent` | `fold-choice-row` | Segmented / chip selector. |
|
|
328
371
|
| `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. |
|
|
372
|
+
| `FoldBreadcrumbComponent` | `fold-breadcrumb` | Hierarchical link trail. Data-driven `[items]` where each crumb links by `routerLink` **or** `href` (works without the router; `RouterLink` only instantiates on a `routerLink` crumb). Last item is the current page (`aria-current="page"`), not a link. `navigation` landmark, decorative chevron separators. Needs `@angular/router` only when a crumb uses `routerLink` (optional peer). |
|
|
373
|
+
| `FoldBackLinkComponent` | `fold-back-link` | The “← Back” affordance for a detail page. Three modes by input: `routerLink` (in-app), `href` (external / non-router), or neither → a history-back `<button>` (`Location.back()`). Router-coupled but degradable — the history mode needs no router. `label` + leading `icon` (default `chevron-left`). |
|
|
329
374
|
| `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. |
|
|
330
|
-
| `FoldIconComponent` | `fold-icon` | SVG icon (
|
|
375
|
+
| `FoldIconComponent` | `fold-icon` | SVG icon (~135 built-in glyphs across 7 categories incl. `commerce` + `FoldIconRegistry`). |
|
|
331
376
|
| `FoldSpinnerComponent` | `fold-spinner` | Indeterminate loading arc (`currentColor`, icon-sized, reduced-motion aware). Decorative by default; `label` → `role="status"`. Powers `loading` on the buttons. |
|
|
332
377
|
| `FoldAvatarComponent` / `…Detail` | `fold-avatar` | Initials/image avatar (square, muted, status ring) + identity cell. |
|
|
333
378
|
| `FoldAvatarListComponent` | `fold-avatar-list` | Overlapping avatar cluster (per-face variant, `limit` + a `+N` overflow chip). |
|
|
@@ -338,8 +383,10 @@ the package root.
|
|
|
338
383
|
| `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>`. |
|
|
339
384
|
| `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 })`. |
|
|
340
385
|
| `FoldPanelHeaderComponent` | `fold-panel-header` | Standard panel header (title/eyebrow, self-closing). Names its dialog (`aria-labelledby`) and reads the app-wide close label. |
|
|
386
|
+
| `FoldPanelFooterComponent` | `fold-panel-footer` | Panel/dialog action bar pairing with `fold-panel-header`: tokenised top border + padding + `align="end" \| "between" \| "start"`. Projects the buttons; sits `flex: none` so it stays pinned to the panel bottom while the body scrolls (no `position: sticky`). |
|
|
341
387
|
| `FoldPopoverComponent` | `fold-popover` | Anchored floating layer — projected content in the native top layer (escapes `overflow`/`z-index`), positioned by a dependency-free **flip → size → shift** engine (`computePlacement`): a tall panel gets a `max-height` and scrolls inside the viewport. `[(open)]`; `autoUpdate` (ResizeObserver); optional `arrow`; native CSS enter/exit (`@starting-style` + `allow-discrete`); outside-click + `Escape` dismissal, focus-return, auto-wired `aria-haspopup`/`expanded`/`controls`. |
|
|
342
388
|
| `FoldDropdownComponent` | `fold-dropdown` | Actions menu on `fold-popover` — `role="menu"` with `<fold-dropdown-item>`s, ↑/↓ roving, `Home`/`End`, type-ahead; opens onto the first enabled item, closes returning focus to the trigger. Give the trigger `foldPopoverTrigger="menu"`. |
|
|
389
|
+
| `FoldInfoComponent` | `fold-info` | The small `i` that answers "what is this?" — a quiet round trigger revealing a sentence or two in a `fold-popover` (native top layer, so it escapes `overflow: hidden` and every `z-index`). A **click**, not a hover: hover-only help is unreachable by touch. `text` · `label` (accessible name) · `placement`. It is what the `info` input on every labelled field renders, and it stands alone where there is no field — a card corner, a table header. |
|
|
343
390
|
|
|
344
391
|
| `FoldCalendarMonthComponent` | `fold-calendar-month` | Month grid where events **span** the days they cover: a date-axis `role="grid"` with one roving tab stop, and over it a lane-packed layer of bands (one per week crossed, with open edges). `+N` chips sit on the crowded day, not at the end of the row. |
|
|
345
392
|
| `FoldCalendarWeekComponent` | `fold-calendar-week` | Seven day columns of stacked chips — nothing spans, so nothing is clipped and every chip is a real button in the tab order. Container-queried: labels and icons drop out before they truncate. |
|
|
@@ -397,7 +444,11 @@ an inset, rounded, shadowed card — the per-surface "floating" mechanism, drive
|
|
|
397
444
|
by `--fold-surface-inset`/`-radius`/`-shadow`), **`foldStickyColumn`** (turn an
|
|
398
445
|
`<aside>` into a sticky side column — `sticky="top·center·bottom"` + `stickyOffset`,
|
|
399
446
|
the rest tunable via `--fold-sticky-column-*`; un-stick with
|
|
400
|
-
`--fold-sticky-column-position: static` at the page's stacking breakpoint),
|
|
447
|
+
`--fold-sticky-column-position: static` at the page's stacking breakpoint),
|
|
448
|
+
**`foldScrollRegion`** (turn any element into a bounded, coordinated scroll box —
|
|
449
|
+
`overflow` + `min-*: 0` + `overscroll-behavior` + the house scrollbar, on a
|
|
450
|
+
`block`·`inline`·`both` axis; the one opt-in of the shell scroll system, it
|
|
451
|
+
registers with the shell so an overlay freezes it while a modal is open), and
|
|
401
452
|
**`foldRepeatPress`** (press-and-hold auto-repeat for a stepper button — fires
|
|
402
453
|
once on press then on a tunable cadence while held, and stops the instant
|
|
403
454
|
`foldRepeatPressDisabled` goes true mid-hold).
|