forty-cdk 0.26.0 → 0.28.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/accordion/README.md +25 -25
- package/aspect-ratio/README.md +7 -7
- package/avatar/README.md +6 -6
- package/breadcrumbs/README.md +5 -5
- package/breakpoints/README.md +17 -17
- package/button/README.md +14 -14
- package/calendar/README.md +50 -45
- package/carousel/README.md +60 -34
- package/checkbox/README.md +55 -27
- package/combobox/README.md +86 -86
- package/context-menu/README.md +40 -41
- package/date-field/README.md +40 -35
- package/date-picker/README.md +47 -45
- package/dialog/README.md +84 -49
- package/disclosure/README.md +15 -26
- package/drag-drop/README.md +78 -38
- package/drawer/README.md +61 -50
- package/dropdown-menu/README.md +46 -45
- package/fesm2022/forty-cdk-avatar.mjs +4 -0
- package/fesm2022/forty-cdk-avatar.mjs.map +1 -1
- package/fesm2022/forty-cdk-breadcrumbs.mjs +8 -4
- package/fesm2022/forty-cdk-breadcrumbs.mjs.map +1 -1
- package/fesm2022/forty-cdk-breakpoints.mjs +4 -1
- package/fesm2022/forty-cdk-breakpoints.mjs.map +1 -1
- package/fesm2022/forty-cdk-calendar.mjs +7 -1
- package/fesm2022/forty-cdk-calendar.mjs.map +1 -1
- package/fesm2022/forty-cdk-carousel.mjs +28 -11
- package/fesm2022/forty-cdk-carousel.mjs.map +1 -1
- package/fesm2022/forty-cdk-combobox.mjs +21 -10
- package/fesm2022/forty-cdk-combobox.mjs.map +1 -1
- package/fesm2022/forty-cdk-context-menu.mjs +61 -15
- package/fesm2022/forty-cdk-context-menu.mjs.map +1 -1
- package/fesm2022/forty-cdk-core-overlay.mjs +172 -100
- package/fesm2022/forty-cdk-core-overlay.mjs.map +1 -1
- package/fesm2022/forty-cdk-core.mjs +177 -9
- package/fesm2022/forty-cdk-core.mjs.map +1 -1
- package/fesm2022/forty-cdk-date-field.mjs +26 -12
- package/fesm2022/forty-cdk-date-field.mjs.map +1 -1
- package/fesm2022/forty-cdk-date-picker.mjs +16 -4
- package/fesm2022/forty-cdk-date-picker.mjs.map +1 -1
- package/fesm2022/forty-cdk-dialog.mjs +149 -9
- package/fesm2022/forty-cdk-dialog.mjs.map +1 -1
- package/fesm2022/forty-cdk-drag-drop.mjs +11 -4
- package/fesm2022/forty-cdk-drag-drop.mjs.map +1 -1
- package/fesm2022/forty-cdk-drawer.mjs +90 -7
- package/fesm2022/forty-cdk-drawer.mjs.map +1 -1
- package/fesm2022/forty-cdk-dropdown-menu.mjs +4 -0
- package/fesm2022/forty-cdk-dropdown-menu.mjs.map +1 -1
- package/fesm2022/forty-cdk-field.mjs +108 -27
- package/fesm2022/forty-cdk-field.mjs.map +1 -1
- package/fesm2022/forty-cdk-fieldset.mjs +6 -1
- package/fesm2022/forty-cdk-fieldset.mjs.map +1 -1
- package/fesm2022/forty-cdk-hover-card.mjs +11 -6
- package/fesm2022/forty-cdk-hover-card.mjs.map +1 -1
- package/fesm2022/forty-cdk-listbox.mjs +4 -0
- package/fesm2022/forty-cdk-listbox.mjs.map +1 -1
- package/fesm2022/forty-cdk-menu.mjs +4 -0
- package/fesm2022/forty-cdk-menu.mjs.map +1 -1
- package/fesm2022/forty-cdk-menubar.mjs +4 -0
- package/fesm2022/forty-cdk-menubar.mjs.map +1 -1
- package/fesm2022/forty-cdk-navigation-menu.mjs +4 -0
- package/fesm2022/forty-cdk-navigation-menu.mjs.map +1 -1
- package/fesm2022/forty-cdk-number-input.mjs +4 -0
- package/fesm2022/forty-cdk-number-input.mjs.map +1 -1
- package/fesm2022/forty-cdk-pagination.mjs +4 -0
- package/fesm2022/forty-cdk-pagination.mjs.map +1 -1
- package/fesm2022/forty-cdk-popover.mjs +86 -7
- package/fesm2022/forty-cdk-popover.mjs.map +1 -1
- package/fesm2022/forty-cdk-progress.mjs +7 -3
- package/fesm2022/forty-cdk-progress.mjs.map +1 -1
- package/fesm2022/forty-cdk-radio-group.mjs +4 -0
- package/fesm2022/forty-cdk-radio-group.mjs.map +1 -1
- package/fesm2022/forty-cdk-scroll-area.mjs +4 -0
- package/fesm2022/forty-cdk-scroll-area.mjs.map +1 -1
- package/fesm2022/forty-cdk-search.mjs +8 -4
- package/fesm2022/forty-cdk-search.mjs.map +1 -1
- package/fesm2022/forty-cdk-select.mjs +12 -4
- package/fesm2022/forty-cdk-select.mjs.map +1 -1
- package/fesm2022/forty-cdk-slider.mjs +4 -0
- package/fesm2022/forty-cdk-slider.mjs.map +1 -1
- package/fesm2022/forty-cdk-stepper.mjs +4 -0
- package/fesm2022/forty-cdk-stepper.mjs.map +1 -1
- package/fesm2022/forty-cdk-table.mjs +3 -1
- package/fesm2022/forty-cdk-table.mjs.map +1 -1
- package/fesm2022/forty-cdk-tabs.mjs +4 -0
- package/fesm2022/forty-cdk-tabs.mjs.map +1 -1
- package/fesm2022/forty-cdk-time-field.mjs +26 -12
- package/fesm2022/forty-cdk-time-field.mjs.map +1 -1
- package/fesm2022/forty-cdk-time-picker.mjs +12 -4
- package/fesm2022/forty-cdk-time-picker.mjs.map +1 -1
- package/fesm2022/forty-cdk-toast.mjs +76 -21
- package/fesm2022/forty-cdk-toast.mjs.map +1 -1
- package/fesm2022/forty-cdk-toggle.mjs +4 -0
- package/fesm2022/forty-cdk-toggle.mjs.map +1 -1
- package/fesm2022/forty-cdk-toolbar.mjs +4 -0
- package/fesm2022/forty-cdk-toolbar.mjs.map +1 -1
- package/fesm2022/forty-cdk-tooltip.mjs +18 -5
- package/fesm2022/forty-cdk-tooltip.mjs.map +1 -1
- package/fesm2022/forty-cdk-tree.mjs +18 -1
- package/fesm2022/forty-cdk-tree.mjs.map +1 -1
- package/fesm2022/forty-cdk-virtualization.mjs +41 -2
- package/fesm2022/forty-cdk-virtualization.mjs.map +1 -1
- package/field/README.md +44 -28
- package/fieldset/README.md +13 -22
- package/file-upload/README.md +14 -30
- package/hover-card/README.md +39 -23
- package/input/README.md +38 -65
- package/internationalized-date/README.md +3 -3
- package/listbox/README.md +39 -40
- package/menu/README.md +51 -51
- package/menubar/README.md +47 -49
- package/meter/README.md +9 -9
- package/navigation-menu/README.md +15 -15
- package/number-input/README.md +16 -17
- package/otp-input/README.md +10 -10
- package/package.json +1 -1
- package/pagination/README.md +3 -3
- package/pane-resizer/README.md +20 -20
- package/popover/README.md +64 -35
- package/progress/README.md +7 -7
- package/radio-group/README.md +38 -21
- package/scroll-area/README.md +39 -39
- package/search/README.md +10 -10
- package/select/README.md +83 -83
- package/separator/README.md +6 -6
- package/shared/README.md +49 -23
- package/slider/README.md +29 -31
- package/stepper/README.md +23 -23
- package/switch/README.md +18 -18
- package/table/README.md +77 -77
- package/table-virtualization/README.md +19 -19
- package/tabs/README.md +24 -24
- package/time-field/README.md +35 -30
- package/time-picker/README.md +11 -11
- package/toast/README.md +94 -56
- package/toggle/README.md +41 -43
- package/toolbar/README.md +12 -12
- package/tooltip/README.md +46 -30
- package/tree/README.md +53 -39
- package/types/forty-cdk-avatar.d.ts +5 -1
- package/types/forty-cdk-breadcrumbs.d.ts +8 -3
- package/types/forty-cdk-breakpoints.d.ts +4 -1
- package/types/forty-cdk-calendar.d.ts +16 -4
- package/types/forty-cdk-carousel.d.ts +29 -7
- package/types/forty-cdk-combobox.d.ts +14 -6
- package/types/forty-cdk-context-menu.d.ts +30 -4
- package/types/forty-cdk-core-overlay.d.ts +144 -81
- package/types/forty-cdk-core.d.ts +133 -18
- package/types/forty-cdk-date-field.d.ts +34 -12
- package/types/forty-cdk-date-picker.d.ts +13 -2
- package/types/forty-cdk-dialog.d.ts +75 -5
- package/types/forty-cdk-drag-drop.d.ts +16 -9
- package/types/forty-cdk-drawer.d.ts +66 -4
- package/types/forty-cdk-dropdown-menu.d.ts +5 -1
- package/types/forty-cdk-field.d.ts +61 -10
- package/types/forty-cdk-hover-card.d.ts +24 -6
- package/types/forty-cdk-listbox.d.ts +5 -1
- package/types/forty-cdk-menu.d.ts +5 -1
- package/types/forty-cdk-menubar.d.ts +5 -1
- package/types/forty-cdk-navigation-menu.d.ts +5 -1
- package/types/forty-cdk-number-input.d.ts +5 -1
- package/types/forty-cdk-pagination.d.ts +5 -1
- package/types/forty-cdk-popover.d.ts +69 -4
- package/types/forty-cdk-progress.d.ts +7 -2
- package/types/forty-cdk-radio-group.d.ts +5 -1
- package/types/forty-cdk-scroll-area.d.ts +5 -1
- package/types/forty-cdk-search.d.ts +8 -4
- package/types/forty-cdk-select.d.ts +8 -1
- package/types/forty-cdk-shared.d.ts +1 -1
- package/types/forty-cdk-slider.d.ts +5 -1
- package/types/forty-cdk-stepper.d.ts +5 -1
- package/types/forty-cdk-tabs.d.ts +5 -1
- package/types/forty-cdk-time-field.d.ts +33 -11
- package/types/forty-cdk-time-picker.d.ts +8 -1
- package/types/forty-cdk-toast.d.ts +78 -21
- package/types/forty-cdk-toggle.d.ts +5 -1
- package/types/forty-cdk-toolbar.d.ts +5 -1
- package/types/forty-cdk-tooltip.d.ts +36 -11
- package/types/forty-cdk-tree.d.ts +14 -1
- package/types/forty-cdk-virtualization.d.ts +7 -1
- package/virtual-reorder/README.md +7 -7
- package/virtualization/README.md +13 -8
- package/visually-hidden/README.md +14 -14
package/accordion/README.md
CHANGED
|
@@ -11,9 +11,9 @@ A stack of collapsible sections, optionally allowing multiple panels open at onc
|
|
|
11
11
|
|
|
12
12
|
## When to choose
|
|
13
13
|
|
|
14
|
-
- **Accordion
|
|
15
|
-
- **[Disclosure](../disclosure/README.md)
|
|
16
|
-
- **[Tabs](../tabs/README.md)
|
|
14
|
+
- **Accordion**: a group of collapsible items under one root. `[(value)]` holds which are open, `multiple` decides whether more than one may be, and ArrowUp / ArrowDown / Home / End move focus across the triggers.
|
|
15
|
+
- **[Disclosure](../disclosure/README.md)**: a single trigger and its region, with no shared state and no arrow-key navigation. Stacking several of them is not an accordion, and that is the right shape when the panels are unrelated.
|
|
16
|
+
- **[Tabs](../tabs/README.md)**: when exactly one panel is ever visible and the panels are alternatives rather than sections the reader may open together.
|
|
17
17
|
|
|
18
18
|
## Anatomy
|
|
19
19
|
|
|
@@ -111,14 +111,14 @@ A disabled item cannot be toggled and is skipped by the arrow keys, while stayin
|
|
|
111
111
|
|
|
112
112
|
### `ForAccordion`
|
|
113
113
|
|
|
114
|
-
| Property | Type | Description
|
|
115
|
-
| ------------- | ----------------------------------- |
|
|
116
|
-
| `value` | `model<readonly string[]>` | Currently open item values. In single mode the array has 0 or 1 element.<br>**Default:** —
|
|
117
|
-
| `multiple` | `input<boolean>` | When true, multiple items can be open simultaneously.<br>**Default:** `false`
|
|
118
|
-
| `collapsible` | `input<boolean>` | Single mode only: when true, the open item can be collapsed by clicking it. Otherwise once any item is open, exactly one stays open.<br>**Default:** `false`
|
|
119
|
-
| `disabled` | `input<boolean>` | When true, disables every item
|
|
120
|
-
| `orientation` | `input<'horizontal' \| 'vertical'>` | Layout direction of the trigger list. In horizontal mode ArrowLeft/Right replace ArrowUp/Down.<br>**Default:** `'vertical'`
|
|
121
|
-
| `dir` | `input<'ltr' \| 'rtl'>` | Writing direction. Only relevant in horizontal mode
|
|
114
|
+
| Property | Type | Description |
|
|
115
|
+
| ------------- | ----------------------------------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
|
|
116
|
+
| `value` | `model<readonly string[]>` | Currently open item values. In single mode the array has 0 or 1 element.<br>**Default:** — |
|
|
117
|
+
| `multiple` | `input<boolean>` | When true, multiple items can be open simultaneously.<br>**Default:** `false` |
|
|
118
|
+
| `collapsible` | `input<boolean>` | Single mode only: when true, the open item can be collapsed by clicking it. Otherwise once any item is open, exactly one stays open.<br>**Default:** `false` |
|
|
119
|
+
| `disabled` | `input<boolean>` | When true, disables every item: each trigger reflects the native `disabled` attribute and cannot toggle. Composes with a per-item `[disabled]`.<br>**Default:** `false` |
|
|
120
|
+
| `orientation` | `input<'horizontal' \| 'vertical'>` | Layout direction of the trigger list. In horizontal mode ArrowLeft/Right replace ArrowUp/Down.<br>**Default:** `'vertical'` |
|
|
121
|
+
| `dir` | `input<'ltr' \| 'rtl'>` | Writing direction. Only relevant in horizontal mode, where it swaps the meaning of Left/Right arrows.<br>**Default:** — |
|
|
122
122
|
|
|
123
123
|
| Data attribute | Values |
|
|
124
124
|
| ------------------ | -------------------------- |
|
|
@@ -154,39 +154,39 @@ A disabled item cannot be toggled and is skipped by the arrow keys, while stayin
|
|
|
154
154
|
|
|
155
155
|
## Keyboard
|
|
156
156
|
|
|
157
|
-
| Key | Action
|
|
158
|
-
| -------------------------------------------- |
|
|
159
|
-
| <kbd>Enter</kbd> / <kbd>Space</kbd> | Toggle the focused trigger (native button).
|
|
160
|
-
| <kbd>ArrowDown</kbd> / <kbd>ArrowUp</kbd> | Move focus between triggers (vertical, default). Wrap-around, skips disabled.
|
|
161
|
-
| <kbd>ArrowLeft</kbd> / <kbd>ArrowRight</kbd> | Move focus between triggers (horizontal
|
|
162
|
-
| <kbd>Home</kbd> | Jump to the first trigger.
|
|
163
|
-
| <kbd>End</kbd> | Jump to the last trigger.
|
|
157
|
+
| Key | Action |
|
|
158
|
+
| -------------------------------------------- | ------------------------------------------------------------------------------------------------- |
|
|
159
|
+
| <kbd>Enter</kbd> / <kbd>Space</kbd> | Toggle the focused trigger (native button). |
|
|
160
|
+
| <kbd>ArrowDown</kbd> / <kbd>ArrowUp</kbd> | Move focus between triggers (vertical, default). Wrap-around, skips disabled. |
|
|
161
|
+
| <kbd>ArrowLeft</kbd> / <kbd>ArrowRight</kbd> | Move focus between triggers (horizontal, flipped under `dir='rtl'`). Wrap-around, skips disabled. |
|
|
162
|
+
| <kbd>Home</kbd> | Jump to the first trigger. |
|
|
163
|
+
| <kbd>End</kbd> | Jump to the last trigger. |
|
|
164
164
|
|
|
165
165
|
## Accessibility
|
|
166
166
|
|
|
167
|
-
- **Heading wrapper is your job.** The library does not render a heading around the trigger
|
|
167
|
+
- **Heading wrapper is your job.** The library does not render a heading around the trigger, so wrap it in the heading level (`<h2>`–`<h6>`) appropriate to your document outline. Without it, screen-reader landmark navigation is broken.
|
|
168
168
|
- **Use a real `<button type="button">` for the trigger.** Native Enter / Space activation and focus come for free; the directive does not synthesize them.
|
|
169
169
|
- **`role="region"`** is added to every panel automatically. APG recommends suppressing it on accordions with 6+ panels to avoid landmark proliferation; there is currently no opt-out.
|
|
170
170
|
- **Closed panels leave the accessibility tree.** While closed, `ForAccordionContent` sets `aria-hidden="true"` and `inert` on the panel, removing it from both the accessibility tree and the focus order. The directive does **not** apply `[hidden]`, so pick how to hide it visually:
|
|
171
|
-
- **Mount / unmount with `@if (item.expanded())
|
|
172
|
-
- **Leave it mounted
|
|
171
|
+
- **Mount / unmount with `@if (item.expanded())`**: the panel is absent from the DOM while closed; the cleanest path for `animate.enter` / `animate.leave`. The trigger emits `aria-controls` only while expanded, so the reference never dangles at an unmounted panel.
|
|
172
|
+
- **Leave it mounted**: preserve internal state or run CSS-only transitions off `data-state`. Add `display: none` (or your own collapse animation) keyed on `[data-state="closed"]` to also hide it visually.
|
|
173
173
|
- **`aria-disabled`** is applied to the open trigger only when single mode is active and `collapsible=false`, indicating the user cannot collapse it from this trigger.
|
|
174
174
|
- **A truly disabled item (`[disabled]` on `[forAccordionItem]`) uses the native `disabled` attribute on the trigger, by design.** The trigger is a real single-purpose `<button>`, not a roving-tabindex collection item (each trigger stays independently in the Tab order; arrow-key navigation is the APG-optional enhancement on top). The disabled trigger leaves the Tab order and the arrow-key navigation (which already skips it), but stays in the accessibility tree so screen readers announce it as unavailable in browse mode. The [APG Accordion pattern](https://www.w3.org/WAI/ARIA/apg/patterns/accordion/) does not require disabled headers to remain focusable.
|
|
175
175
|
|
|
176
176
|
## Styling
|
|
177
177
|
|
|
178
|
-
forty-cdk ships no styles
|
|
178
|
+
forty-cdk ships no styles: put your own class on each piece and key your CSS off the `data-*` attributes listed under [API](#api), not off the `for*` selectors ([Styling forty-cdk](../../../docs/styling.md) explains why).
|
|
179
179
|
|
|
180
180
|
```css
|
|
181
|
-
.
|
|
181
|
+
.chevron {
|
|
182
182
|
transition: transform 150ms ease;
|
|
183
183
|
}
|
|
184
184
|
|
|
185
|
-
.
|
|
185
|
+
.acc-trigger[data-state='open'] .chevron {
|
|
186
186
|
transform: rotate(180deg);
|
|
187
187
|
}
|
|
188
188
|
```
|
|
189
189
|
|
|
190
190
|
## Wrapping in a design system
|
|
191
191
|
|
|
192
|
-
|
|
192
|
+
Subclass the root and re-provide `FOR_ACCORDION_CONTEXT` with `useExisting` pointing at the subclass, since Angular does not inherit a directive's `providers`; [Wrapping non-form roots](../../../docs/wrapping-non-form-roots.md) walks the pattern.
|
package/aspect-ratio/README.md
CHANGED
|
@@ -8,21 +8,21 @@ archetype: [composable-ui]
|
|
|
8
8
|
|
|
9
9
|
A container that keeps its content at a fixed width-to-height ratio.
|
|
10
10
|
|
|
11
|
-
|
|
11
|
+
It is a pure visual utility that locks an element's box via the native CSS `aspect-ratio` property, with no ARIA semantics. Reach for it to reserve space for media before it loads (preventing layout shift), keep cards on a grid uniform, or wrap responsive iframes.
|
|
12
12
|
|
|
13
13
|
## Why this exists
|
|
14
14
|
|
|
15
|
-
|
|
15
|
+
You don't need this primitive for a fixed, never-changing ratio, which is one line of CSS:
|
|
16
16
|
|
|
17
17
|
```css
|
|
18
|
-
.
|
|
18
|
+
.box {
|
|
19
19
|
aspect-ratio: 16 / 9;
|
|
20
20
|
}
|
|
21
21
|
```
|
|
22
22
|
|
|
23
23
|
`[forAspectRatio]` earns its place when the ratio is **dynamic or must be validated**. It is more than the static declaration:
|
|
24
24
|
|
|
25
|
-
- **Reactive `ratio` input.** Bind `[ratio]="ratio()"` and the host style recomputes as the value changes
|
|
25
|
+
- **Reactive `ratio` input.** Bind `[ratio]="ratio()"` and the host style recomputes as the value changes, with no manual style writes.
|
|
26
26
|
- **Invalid-value guarding.** `0`, negative, and non-finite ratios fall back to `1`, so a bad computed value never emits invalid CSS.
|
|
27
27
|
- **SSR-safe.** The `aspect-ratio` style is bound declaratively (never touched imperatively), so it renders identically on the server and hydrates cleanly.
|
|
28
28
|
- **Consistent headless API.** Same shape as the other primitives, so it composes the same way.
|
|
@@ -39,7 +39,7 @@ If your ratio is a literal constant, prefer the CSS property directly and keep t
|
|
|
39
39
|
|
|
40
40
|
## Examples
|
|
41
41
|
|
|
42
|
-
Resize the preview and watch the frame hold its 16 / 9 ratio
|
|
42
|
+
Resize the preview and watch the frame hold its 16 / 9 ratio. The primitive writes the ratio and nothing else, so every border, colour and inset below is your own CSS.
|
|
43
43
|
|
|
44
44
|
```ts
|
|
45
45
|
import { ChangeDetectionStrategy, Component } from '@angular/core';
|
|
@@ -60,7 +60,7 @@ export class AspectRatioDefaultExample {}
|
|
|
60
60
|
|
|
61
61
|
### Square (1 / 1)
|
|
62
62
|
|
|
63
|
-
Set `ratio` to `1` to keep a box perfectly square at any width
|
|
63
|
+
Set `ratio` to `1` to keep a box perfectly square at any width. That is handy for avatars, thumbnails, or uniform grid cards.
|
|
64
64
|
|
|
65
65
|
## API
|
|
66
66
|
|
|
@@ -76,7 +76,7 @@ Set `ratio` to `1` to keep a box perfectly square at any width — handy for ava
|
|
|
76
76
|
|
|
77
77
|
## Styling
|
|
78
78
|
|
|
79
|
-
forty-cdk ships no styles
|
|
79
|
+
forty-cdk ships no styles: put your own class on the host rather than styling the `for*` selector ([Styling forty-cdk](../../../docs/styling.md) explains why). This primitive is purely structural: its only host effect is the native `aspect-ratio` style, so it reflects no `data-*` attributes and writes no CSS custom properties.
|
|
80
80
|
|
|
81
81
|
## Behavior notes
|
|
82
82
|
|
package/avatar/README.md
CHANGED
|
@@ -8,7 +8,7 @@ archetype: [composable-ui]
|
|
|
8
8
|
|
|
9
9
|
A user image with a graceful fallback across its loading lifecycle.
|
|
10
10
|
|
|
11
|
-
|
|
11
|
+
It is headless and presentational: it tracks the load lifecycle of an `<img>` and lets you choose what to show while loading or after an error. There is no WAI-ARIA pattern for avatars, so the directive imposes no `role` of its own.
|
|
12
12
|
|
|
13
13
|
## Anatomy
|
|
14
14
|
|
|
@@ -64,7 +64,7 @@ export class AvatarDefaultExample {
|
|
|
64
64
|
|
|
65
65
|
### Failed load
|
|
66
66
|
|
|
67
|
-
When the image errors, the directive flips `shouldShowFallback()` and the initials render in its place
|
|
67
|
+
When the image errors, the directive flips `shouldShowFallback()` and the initials render in its place. An error shows the fallback at once, skipping the `fallbackDelayMs` wait.
|
|
68
68
|
|
|
69
69
|
## API
|
|
70
70
|
|
|
@@ -102,7 +102,7 @@ The directive does not impose a `role`. Pair the avatar with visible name text o
|
|
|
102
102
|
|
|
103
103
|
## Styling
|
|
104
104
|
|
|
105
|
-
forty-cdk ships no styles
|
|
105
|
+
forty-cdk ships no styles: put your own class on each piece and key your CSS off the `data-*` attributes listed under [API](#api), not off the `for*` selectors ([Styling forty-cdk](../../../docs/styling.md) explains why).
|
|
106
106
|
|
|
107
107
|
```css
|
|
108
108
|
.avatar-image:not([data-status='loaded']) {
|
|
@@ -115,11 +115,11 @@ forty-cdk ships no styles. Add your own class to each piece — the `for*` selec
|
|
|
115
115
|
|
|
116
116
|
## Behavior notes
|
|
117
117
|
|
|
118
|
-
- **Cached images are detected on first render.** If the browser already has the image cached, `load`/`error` may not fire
|
|
118
|
+
- **Cached images are detected on first render.** If the browser already has the image cached, `load`/`error` may not fire. The directive checks `<img>.complete` and `naturalWidth` after the first render and reports `loaded` / `error` accordingly. A cached image that is `complete` but has zero intrinsic width (e.g. an SVG without explicit dimensions) is ambiguous, so the directive stays `loading` and confirms validity with `img.decode()` rather than pessimistically flagging `error`.
|
|
119
119
|
- **Multiple images per avatar are not supported.** Each `[forAvatar]` expects exactly one `[forAvatarImage]`. If you need cascading sources (CDN → fallback URL → fallback content), swap `src` on a single image.
|
|
120
|
-
- **`alt` is consumer territory.** Because `<img>` is the host element, the consumer keeps full control of `alt
|
|
120
|
+
- **`alt` is consumer territory.** Because `<img>` is the host element, the consumer keeps full control of `alt`. Set `""` for purely decorative avatars next to a name, or describe the person if the avatar stands alone.
|
|
121
121
|
- **The image stays in the DOM.** Hide it via CSS `[data-status="loading"], [data-status="error"] { display: none }` if your consumer-side styling needs it gone. The fallback uses `@if`, so it only mounts when needed.
|
|
122
122
|
|
|
123
123
|
## Wrapping in a design system
|
|
124
124
|
|
|
125
|
-
|
|
125
|
+
Subclass the root and re-provide `FOR_AVATAR_CONTEXT` with `useExisting` pointing at the subclass, since Angular does not inherit a directive's `providers`; [Wrapping non-form roots](../../../docs/wrapping-non-form-roots.md) walks the pattern.
|
package/breadcrumbs/README.md
CHANGED
|
@@ -23,7 +23,7 @@ A labelled navigation landmark for a breadcrumb trail: links with aria-current='
|
|
|
23
23
|
|
|
24
24
|
## Examples
|
|
25
25
|
|
|
26
|
-
Walk the trail with `Tab
|
|
26
|
+
Walk the trail with `Tab`: the last crumb is the page you are on, so it carries `aria-current="page"` and is not a link back to itself.
|
|
27
27
|
|
|
28
28
|
```ts
|
|
29
29
|
import { ChangeDetectionStrategy, Component, signal } from '@angular/core';
|
|
@@ -82,11 +82,9 @@ export class BreadcrumbsDefaultExample {
|
|
|
82
82
|
}
|
|
83
83
|
```
|
|
84
84
|
|
|
85
|
-
The root defaults its label to `Breadcrumb`. Override it with `ariaLabel="…"` (or point a native `aria-labelledby` at a visible heading) when a page hosts more than one breadcrumb trail.
|
|
86
|
-
|
|
87
85
|
### Collapsing a long trail
|
|
88
86
|
|
|
89
|
-
The primitive renders whatever items you give it, so collapsing a deep path is a consumer decision. Here the middle is folded into an expandable ellipsis button that reveals the hidden crumbs
|
|
87
|
+
The primitive renders whatever items you give it, so collapsing a deep path is a consumer decision. Here the middle is folded into an expandable ellipsis button that reveals the hidden crumbs. The trail stays a single accessible navigation landmark either way.
|
|
90
88
|
|
|
91
89
|
## Localizing the label
|
|
92
90
|
|
|
@@ -102,6 +100,8 @@ bootstrapApplication(App, {
|
|
|
102
100
|
});
|
|
103
101
|
```
|
|
104
102
|
|
|
103
|
+
For a language the app sets or switches after bootstrap, pass `label` as a function and the overrides as a factory, as [Localizing default text](../shared/README.md#localizing-default-text) shows.
|
|
104
|
+
|
|
105
105
|
## API
|
|
106
106
|
|
|
107
107
|
### `ForBreadcrumbs`
|
|
@@ -120,7 +120,7 @@ bootstrapApplication(App, {
|
|
|
120
120
|
|
|
121
121
|
Implements the [WAI-ARIA Breadcrumb pattern](https://www.w3.org/WAI/ARIA/apg/patterns/breadcrumb/).
|
|
122
122
|
|
|
123
|
-
- **Navigation landmark.** `[forBreadcrumbs]` applies `role="navigation"` and labels it `aria-label="Breadcrumb"` by default, creating a named landmark that screen-reader users can jump to directly.
|
|
123
|
+
- **Navigation landmark.** `[forBreadcrumbs]` applies `role="navigation"` and labels it `aria-label="Breadcrumb"` by default, creating a named landmark that screen-reader users can jump to directly. When a page hosts more than one trail, name each with `[ariaLabel]`, or point a native `aria-labelledby` at a visible heading.
|
|
124
124
|
- **Current page.** Set `current` on `[forBreadcrumbItem]` for the active page; the directive reflects `aria-current="page"` so assistive technology announces the user's location in the trail.
|
|
125
125
|
- **Decorative separators.** `[forBreadcrumbSeparator]` reflects `aria-hidden="true"` so the visual divider (e.g. `/`) is skipped by screen readers.
|
|
126
126
|
|
package/breakpoints/README.md
CHANGED
|
@@ -6,13 +6,13 @@ archetype: [headless-utility]
|
|
|
6
6
|
|
|
7
7
|
# Breakpoints
|
|
8
8
|
|
|
9
|
-
A signal-first, zoneless, SSR-safe viewport breakpoint observer (injectBreakpoints). Configure the breakpoint map once via provideForBreakpointsDefaults
|
|
9
|
+
A signal-first, zoneless, SSR-safe viewport breakpoint observer (injectBreakpoints). Configure the breakpoint map once via provideForBreakpointsDefaults (or use the Tailwind scale by default), then read up / down / between / only / active or any arbitrary media query, each as a live Signal<boolean>.
|
|
10
10
|
|
|
11
|
-
It is a headless reactive utility, not a UI primitive: no DOM, no ARIA, no template. Configure the breakpoint map **once** via a provider
|
|
11
|
+
It is a headless reactive utility, not a UI primitive: no DOM, no ARIA, no template. Configure the breakpoint map **once** via a provider and read it anywhere with `injectBreakpoints()`, so there is no need to repeat the breakpoint set at every call site.
|
|
12
12
|
|
|
13
13
|
## Setup
|
|
14
14
|
|
|
15
|
-
Configuring is optional
|
|
15
|
+
Configuring is optional: without a provider the Tailwind scale (`sm` 640, `md` 768, `lg` 1024, `xl` 1280, `2xl` 1536) is used. To define your own:
|
|
16
16
|
|
|
17
17
|
```ts
|
|
18
18
|
import { ApplicationConfig } from '@angular/core';
|
|
@@ -95,25 +95,17 @@ export class BreakpointsActiveExample {
|
|
|
95
95
|
}
|
|
96
96
|
```
|
|
97
97
|
|
|
98
|
-
The returned handle captures its injection context, so the query methods can be called lazily from a `computed()` or a template, not only during construction:
|
|
99
|
-
|
|
100
|
-
<!-- snippet: fragment -->
|
|
101
|
-
|
|
102
|
-
```ts
|
|
103
|
-
protected columns = computed(() => (this.bp.up('xl')() ? 4 : this.bp.up('md')() ? 2 : 1));
|
|
104
|
-
```
|
|
105
|
-
|
|
106
98
|
### Responsive layout
|
|
107
99
|
|
|
108
100
|
Derive UI from the breakpoint inside `computed()` and `@if` instead of repeating media queries in the template. The card grid picks its column count from `up('md')` / `up('lg')` / `up('xl')`, and the sidebar is only mounted at `lg` and wider.
|
|
109
101
|
|
|
110
102
|
### Arbitrary media queries
|
|
111
103
|
|
|
112
|
-
`matches(query)` is the escape hatch for any media feature the named width helpers don't cover
|
|
104
|
+
`matches(query)` is the escape hatch for any media feature the named width helpers don't cover: orientation, pointer, hover, and the `prefers-*` user settings. Each call returns a live `Signal<boolean>` from the same cached `MediaQueryList` layer.
|
|
113
105
|
|
|
114
106
|
## Typed custom names
|
|
115
107
|
|
|
116
|
-
The default map gives you fully-typed names out of the box (`up('md')` autocompletes; `up('foo')` is a type error). When you provide a custom map, recover the same typing by augmenting `BreakpointRegistry` once
|
|
108
|
+
The default map gives you fully-typed names out of the box (`up('md')` autocompletes; `up('foo')` is a type error). When you provide a custom map, recover the same typing by augmenting `BreakpointRegistry` once. Derive the keys from your map so you never write them twice:
|
|
117
109
|
|
|
118
110
|
```ts
|
|
119
111
|
// breakpoints.ts
|
|
@@ -137,13 +129,21 @@ Now `injectBreakpoints()` autocompletes `'mobile' | 'tablet' | 'laptop' | 'deskt
|
|
|
137
129
|
|
|
138
130
|
| Method | Matches |
|
|
139
131
|
| ---------------- | ------------------------------------------------------------------------------ |
|
|
140
|
-
| `up(name)` | the breakpoint and wider
|
|
141
|
-
| `down(name)` | narrower than the breakpoint
|
|
132
|
+
| `up(name)` | the breakpoint and wider: `(min-width: N px)` |
|
|
133
|
+
| `down(name)` | narrower than the breakpoint: `(max-width: (N − 0.02) px)` |
|
|
142
134
|
| `between(a, b)` | from `a` (inclusive) up to but not including `b` |
|
|
143
135
|
| `only(name)` | the breakpoint's own band, up to but not including the next-larger one |
|
|
144
136
|
| `active` | the largest breakpoint whose `min-width` matches, or `null` below the smallest |
|
|
145
137
|
| `matches(query)` | escape hatch for an arbitrary media query (orientation, `prefers-*`, …) |
|
|
146
138
|
|
|
139
|
+
The returned handle captures its injection context, so the query methods can be called lazily from a `computed()` or a template, not only during construction:
|
|
140
|
+
|
|
141
|
+
<!-- snippet: fragment -->
|
|
142
|
+
|
|
143
|
+
```ts
|
|
144
|
+
protected columns = computed(() => (this.bp.up('xl')() ? 4 : this.bp.up('md')() ? 2 : 1));
|
|
145
|
+
```
|
|
146
|
+
|
|
147
147
|
### `injectPrefersReducedMotion`
|
|
148
148
|
|
|
149
149
|
The same shape for a different query: `injectPrefersReducedMotion()` returns a `Signal<boolean>` that is `true` while the user has asked their OS to suppress animation, and flips if they change the setting mid-session. Call it from an injection context, like `injectBreakpoints()`.
|
|
@@ -161,9 +161,9 @@ export class Panel {
|
|
|
161
161
|
}
|
|
162
162
|
```
|
|
163
163
|
|
|
164
|
-
It is published here because forty-cdk ships no styles: the animation on a `data-state` change is yours, so honouring the preference is yours too
|
|
164
|
+
It is published here because forty-cdk ships no styles: the animation on a `data-state` change is yours, so honouring the preference is yours too. A signal is also what a `computed()` or a `[style]` binding can branch on, which a CSS `@media` block cannot. Treat `true` as "skip the animated path entirely", not "shorten the duration": the setting asks for no motion, not less of it.
|
|
165
165
|
|
|
166
|
-
`bp.matches('(prefers-reduced-motion: reduce)')` resolves to the same thing. Prefer the named helper
|
|
166
|
+
`bp.matches('(prefers-reduced-motion: reduce)')` resolves to the same thing. Prefer the named helper: it is the one the library's own motion-bearing primitives (drag gestures, carousel, drawer) read, so the query string stays spelled in one place.
|
|
167
167
|
|
|
168
168
|
## SSR
|
|
169
169
|
|
package/button/README.md
CHANGED
|
@@ -7,7 +7,7 @@ apgUrl: https://www.w3.org/WAI/ARIA/apg/patterns/button/
|
|
|
7
7
|
|
|
8
8
|
# ForButton
|
|
9
9
|
|
|
10
|
-
Turns any element
|
|
10
|
+
Turns any element (a native `<button>` or a custom host like `<div>` / `<span>`) into an accessible button with keyboard activation. Disabled stays focusable (aria-disabled, never the native attribute) and pressed / hovered / focus-visible are reflected as data-\* hooks.
|
|
11
11
|
|
|
12
12
|
A single `[forButton]` directive does all of this. On a native `<button>` host the platform owns Enter/Space activation and `type` handling; on any non-button host the directive adds `role="button"`, `tabindex="0"`, and keyboard activation so the contract matches.
|
|
13
13
|
|
|
@@ -23,7 +23,7 @@ A single `[forButton]` directive does all of this. On a native `<button>` host t
|
|
|
23
23
|
|
|
24
24
|
## Examples
|
|
25
25
|
|
|
26
|
-
Press and hold either control
|
|
26
|
+
Press and hold either control (a native `<button>` and a `<span>`) and watch `data-pressed`, `data-hovered` and `data-focus-visible` appear on both, so one rule styles the pair.
|
|
27
27
|
|
|
28
28
|
```ts
|
|
29
29
|
import { ChangeDetectionStrategy, Component } from '@angular/core';
|
|
@@ -45,7 +45,7 @@ export class ButtonDefaultExample {}
|
|
|
45
45
|
|
|
46
46
|
### Disabled stays focusable
|
|
47
47
|
|
|
48
|
-
Per the APG, a disabled button must stay reachable so assistive tech can announce it. `forButton` never sets the native `disabled` attribute
|
|
48
|
+
Per the APG, a disabled button must stay reachable so assistive tech can announce it. `forButton` never sets the native `disabled` attribute. Instead, it reflects `aria-disabled='true'` + `data-disabled` and makes activation a no-op. The native disabled button is skipped entirely.
|
|
49
49
|
|
|
50
50
|
## Disabled
|
|
51
51
|
|
|
@@ -55,7 +55,7 @@ Disabled buttons stay focusable so assistive technology can announce them. The n
|
|
|
55
55
|
<button forButton [disabled]="isSaving()" (activate)="save()">Save</button>
|
|
56
56
|
```
|
|
57
57
|
|
|
58
|
-
A surrounding disabled `[forFieldset]` disables the button too
|
|
58
|
+
A surrounding disabled `[forFieldset]` disables the button too: its `disabled` input is OR'd with the group's, so `aria-disabled` / `data-disabled` are reflected and activation is suppressed. This matters most on a non-native host (`<div forButton>`), which a native `<fieldset disabled>` cannot reach.
|
|
59
59
|
|
|
60
60
|
```html
|
|
61
61
|
<fieldset forFieldset [disabled]="locked()">
|
|
@@ -81,7 +81,7 @@ A native `<button>` without an explicit `type` attribute defaults to `type="butt
|
|
|
81
81
|
| `disabled` | `input<boolean>` | Suppresses activation and reflects `aria-disabled` + `data-disabled`. OR'd with a surrounding `[forFieldset]`'s disabled state.<br>**Default:** `false` |
|
|
82
82
|
| `activate` | `output<void>` | Fires once per user activation (click, Enter, Space). Never fires when disabled.<br>**Default:** — |
|
|
83
83
|
|
|
84
|
-
The directive reflects boolean `data-*` attributes (present with an empty-string value when true, absent when false). There is no `data-state
|
|
84
|
+
The directive reflects boolean `data-*` attributes (present with an empty-string value when true, absent when false). There is no `data-state`, because this primitive has no open/closed or checked/unchecked logical state.
|
|
85
85
|
|
|
86
86
|
| Data attribute | Values |
|
|
87
87
|
| -------------------- | ----------------- |
|
|
@@ -94,14 +94,14 @@ The directive reflects boolean `data-*` attributes (present with an empty-string
|
|
|
94
94
|
|
|
95
95
|
## Keyboard
|
|
96
96
|
|
|
97
|
-
On a native `<button>` host the platform owns activation: every key handler the directive binds returns immediately, and nothing in this table is its doing. On any other host (`<div forButton>`, `<span forButton>`) it synthesizes the activation itself, through the same `(click)` path a pointer takes
|
|
97
|
+
On a native `<button>` host the platform owns activation: every key handler the directive binds returns immediately, and nothing in this table is its doing. On any other host (`<div forButton>`, `<span forButton>`) it synthesizes the activation itself, through the same `(click)` path a pointer takes. The split between the two keys is deliberately asymmetric, because that is what a native button does.
|
|
98
98
|
|
|
99
|
-
| Key
|
|
100
|
-
|
|
|
101
|
-
| `Enter`
|
|
102
|
-
| `Enter`
|
|
103
|
-
| `Space`
|
|
104
|
-
| `Space`
|
|
99
|
+
| Key | Action |
|
|
100
|
+
| ------------------------------ | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
|
|
101
|
+
| `Enter` on a native `<button>` | The platform synthesizes the click; the directive adds nothing. |
|
|
102
|
+
| `Enter` on any other host | Activates on `keydown`, so `(activate)` fires while the key is still held. While disabled the event is left alone entirely: not even its default is prevented. |
|
|
103
|
+
| `Space` on a native `<button>` | The platform synthesizes the click on release and suppresses the page scroll itself. |
|
|
104
|
+
| `Space` on any other host | Activates on `keyup`, and only when the matching `keydown` reached the same host. Focus leaving mid-press drops the press. Its `keydown` always calls `preventDefault()` to stop the page scrolling, **even while the button is disabled**. |
|
|
105
105
|
|
|
106
106
|
Both keys drive `data-pressed` on every host: present from `keydown` until `keyup`, until focus leaves, or until the pointer is released. `data-focus-visible` instead follows the keyboard modality, so a `keydown` carrying `Meta` / `Control` / `Alt` is read as a shortcut and does not turn it on, while `Shift` does.
|
|
107
107
|
|
|
@@ -110,12 +110,12 @@ Both keys drive `data-pressed` on every host: present from `keydown` until `keyu
|
|
|
110
110
|
Implements the [WAI-ARIA Button pattern](https://www.w3.org/WAI/ARIA/apg/patterns/button/).
|
|
111
111
|
|
|
112
112
|
- **Native `<button>` semantics are preserved.** On a native host, no extra ARIA is added; the browser's built-in button role, keyboard activation, and `type` handling all apply.
|
|
113
|
-
- **Non-button hosts get `role="button"` and `tabindex="0"`**, and the directive synthesizes the activation the platform would have
|
|
113
|
+
- **Non-button hosts get `role="button"` and `tabindex="0"`**, and the directive synthesizes the activation the platform would have (see [Keyboard](#keyboard)).
|
|
114
114
|
- **Disabled buttons stay focusable.** `aria-disabled="true"` is used instead of the native `disabled` attribute so assistive technology can still announce the control's purpose.
|
|
115
115
|
|
|
116
116
|
## Styling
|
|
117
117
|
|
|
118
|
-
forty-cdk ships no styles
|
|
118
|
+
forty-cdk ships no styles: put your own class on each piece and key your CSS off the `data-*` attributes listed under [API](#api), not off the `for*` selectors ([Styling forty-cdk](../../../docs/styling.md) explains why).
|
|
119
119
|
|
|
120
120
|
```css
|
|
121
121
|
[forButton][data-disabled] {
|