forty-cdk 0.27.0 → 0.29.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 +2 -2
- package/aspect-ratio/README.md +1 -1
- package/avatar/README.md +2 -2
- package/breadcrumbs/README.md +2 -0
- package/button/README.md +1 -1
- package/calendar/README.md +26 -19
- package/carousel/README.md +41 -15
- package/checkbox/README.md +2 -2
- package/combobox/README.md +61 -16
- package/context-menu/README.md +3 -2
- package/date-field/README.md +32 -25
- package/date-picker/README.md +72 -22
- package/dialog/README.md +47 -12
- package/disclosure/README.md +2 -2
- package/drag-drop/README.md +41 -1
- package/drawer/README.md +17 -7
- package/dropdown-menu/README.md +2 -2
- 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 +9 -13
- package/fesm2022/forty-cdk-breakpoints.mjs.map +1 -1
- package/fesm2022/forty-cdk-calendar.mjs +17 -2
- 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 +165 -25
- 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 +188 -119
- package/fesm2022/forty-cdk-core-overlay.mjs.map +1 -1
- package/fesm2022/forty-cdk-core.mjs +270 -29
- package/fesm2022/forty-cdk-core.mjs.map +1 -1
- package/fesm2022/forty-cdk-date-field.mjs +108 -33
- package/fesm2022/forty-cdk-date-field.mjs.map +1 -1
- package/fesm2022/forty-cdk-date-picker.mjs +211 -45
- package/fesm2022/forty-cdk-date-picker.mjs.map +1 -1
- package/fesm2022/forty-cdk-dialog.mjs +144 -8
- 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 +92 -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 +140 -7
- package/fesm2022/forty-cdk-field.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-input.mjs +31 -6
- package/fesm2022/forty-cdk-input.mjs.map +1 -1
- package/fesm2022/forty-cdk-internationalized-date.mjs +18 -2
- package/fesm2022/forty-cdk-internationalized-date.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-otp-input.mjs +17 -3
- package/fesm2022/forty-cdk-otp-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 +92 -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 +17 -7
- 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 +108 -33
- package/fesm2022/forty-cdk-time-field.mjs.map +1 -1
- package/fesm2022/forty-cdk-time-picker.mjs +146 -20
- 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 +19 -3
- 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 +17 -5
- package/fesm2022/forty-cdk-tooltip.mjs.map +1 -1
- package/fesm2022/forty-cdk-tree.mjs +4 -0
- 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 +63 -2
- package/fieldset/README.md +2 -2
- package/file-upload/README.md +2 -2
- package/hover-card/README.md +19 -3
- package/input/README.md +51 -26
- package/listbox/README.md +2 -2
- package/menu/README.md +2 -2
- package/menubar/README.md +2 -2
- package/meter/README.md +2 -2
- package/navigation-menu/README.md +2 -2
- package/number-input/README.md +1 -1
- package/otp-input/README.md +11 -5
- package/package.json +1 -1
- package/pagination/README.md +1 -1
- package/pane-resizer/README.md +1 -1
- package/popover/README.md +30 -3
- package/progress/README.md +2 -2
- package/radio-group/README.md +1 -1
- package/scroll-area/README.md +2 -2
- package/select/README.md +2 -2
- package/separator/README.md +1 -1
- package/shared/README.md +27 -1
- package/slider/README.md +1 -1
- package/stepper/README.md +2 -2
- package/switch/README.md +1 -1
- package/table/README.md +1 -1
- package/tabs/README.md +2 -2
- package/time-field/README.md +24 -17
- package/time-picker/README.md +74 -26
- package/toast/README.md +44 -6
- package/toggle/README.md +20 -19
- package/toolbar/README.md +2 -2
- package/tooltip/README.md +19 -3
- package/tree/README.md +4 -2
- 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 +13 -9
- package/types/forty-cdk-calendar.d.ts +29 -10
- package/types/forty-cdk-carousel.d.ts +29 -7
- package/types/forty-cdk-combobox.d.ts +138 -26
- package/types/forty-cdk-context-menu.d.ts +30 -4
- package/types/forty-cdk-core-overlay.d.ts +171 -112
- package/types/forty-cdk-core.d.ts +324 -50
- package/types/forty-cdk-date-field.d.ts +69 -18
- package/types/forty-cdk-date-picker.d.ts +156 -24
- package/types/forty-cdk-dialog.d.ts +73 -4
- package/types/forty-cdk-drag-drop.d.ts +14 -7
- 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 +113 -29
- package/types/forty-cdk-hover-card.d.ts +24 -6
- package/types/forty-cdk-input.d.ts +12 -0
- package/types/forty-cdk-internationalized-date.d.ts +16 -4
- 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-otp-input.d.ts +12 -2
- 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 +12 -5
- 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 +68 -17
- package/types/forty-cdk-time-picker.d.ts +92 -16
- package/types/forty-cdk-toast.d.ts +78 -21
- package/types/forty-cdk-toggle.d.ts +23 -6
- package/types/forty-cdk-toolbar.d.ts +5 -1
- package/types/forty-cdk-tooltip.d.ts +30 -6
- package/types/forty-cdk-tree.d.ts +5 -1
- package/types/forty-cdk-virtualization.d.ts +7 -1
- package/virtualization/README.md +6 -1
- package/visually-hidden/README.md +1 -1
package/accordion/README.md
CHANGED
|
@@ -175,7 +175,7 @@ A disabled item cannot be toggled and is skipped by the arrow keys, while stayin
|
|
|
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 {
|
|
@@ -189,4 +189,4 @@ forty-cdk ships no styles. Add your own class to each piece. The `for*` selector
|
|
|
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
|
@@ -76,7 +76,7 @@ Set `ratio` to `1` to keep a box perfectly square at any width. That is handy fo
|
|
|
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
|
@@ -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']) {
|
|
@@ -122,4 +122,4 @@ forty-cdk ships no styles. Add your own class to each piece. The `for*` selector
|
|
|
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
|
@@ -100,6 +100,8 @@ bootstrapApplication(App, {
|
|
|
100
100
|
});
|
|
101
101
|
```
|
|
102
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
|
+
|
|
103
105
|
## API
|
|
104
106
|
|
|
105
107
|
### `ForBreadcrumbs`
|
package/button/README.md
CHANGED
|
@@ -115,7 +115,7 @@ Implements the [WAI-ARIA Button pattern](https://www.w3.org/WAI/ARIA/apg/pattern
|
|
|
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] {
|
package/calendar/README.md
CHANGED
|
@@ -210,22 +210,22 @@ Click the heading button to cycle from day → month → year view. Click a mont
|
|
|
210
210
|
|
|
211
211
|
### `ForCalendar`
|
|
212
212
|
|
|
213
|
-
| Property | Type | Description
|
|
214
|
-
| ------------------- | -------------------------------------- |
|
|
215
|
-
| `value` | `model<D \| null>` | Two-way bindable selected date, or `null`. Used in `selectionMode="single"`. `(valueChange)` fires only on internal selection.<br>**Default:** `null`
|
|
216
|
-
| `selectionMode` | `input<'single' \| 'range'>` | `'single'` (default) keeps the single-date `value` flow. `'range'` switches to anchor → commit and exposes `range`.<br>**Default:** `'single'`
|
|
217
|
-
| `range` | `model<DateRange<D> \| null>` | Two-way bindable committed range. Only used in `selectionMode="range"`. `(rangeChange)` fires only on internal commits/clears.<br>**Default:** `null`
|
|
218
|
-
| `minRangeLength` | `input<number \| null>` | Minimum inclusive day count. A commit shorter than this is a no-op.<br>**Default:** `null` (no minimum)
|
|
219
|
-
| `maxRangeLength` | `input<number \| null>` | Maximum inclusive day count. A commit longer than this is a no-op.<br>**Default:** `null` (no maximum)
|
|
220
|
-
| `min` | `input<D \| null>` | Minimum selectable date (inclusive). Earlier dates are unavailable.<br>**Default:** `null`
|
|
221
|
-
| `max` | `input<D \| null>` | Maximum selectable date (inclusive). Later dates are unavailable.<br>**Default:** `null`
|
|
222
|
-
| `isDateUnavailable` | `input<(date: D) => boolean>` | Per-date predicate marking a date unavailable (present but not selectable).<br>**Default:** `() => false`
|
|
223
|
-
| `dateLabel` | `input<CalendarDateLabelFormatter<D>>` | Formats each gridcell's `aria-label` (full accessible date).<br>**Default:** localized full date, outside-month days
|
|
224
|
-
| `disabled` | `input<boolean>` | Disables the whole calendar (no focus movement, no selection). Reflected as `data-disabled`.<br>**Default:** —
|
|
225
|
-
| `readonly` | `input<boolean>` | Read-only: dates stay focusable, selection is blocked. Reflected as `data-readonly`.<br>**Default:** —
|
|
226
|
-
| `firstDayOfWeek` | `input<number \| null>` | First column's weekday, **0-6** (`0` = Sunday).<br>**Default:** `null` → the adapter's value (or `provideForCalendarDefaults`)
|
|
227
|
-
| `locale` | `input<string \| null>` | BCP 47 locale for the heading, weekday headers, month-picker options and cell `aria-label` names. The calendar system stays Gregorian.<br>**Default:** `null` → the
|
|
228
|
-
| `dir` | `input<'ltr' \| 'rtl' \| null>` | Writing direction.<br>**Default:** `null` resolves the ambient direction; reflected to the host `dir` and mirrors horizontal arrows
|
|
213
|
+
| Property | Type | Description |
|
|
214
|
+
| ------------------- | -------------------------------------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
|
|
215
|
+
| `value` | `model<D \| null>` | Two-way bindable selected date, or `null`. Used in `selectionMode="single"`. `(valueChange)` fires only on internal selection.<br>**Default:** `null` |
|
|
216
|
+
| `selectionMode` | `input<'single' \| 'range'>` | `'single'` (default) keeps the single-date `value` flow. `'range'` switches to anchor → commit and exposes `range`.<br>**Default:** `'single'` |
|
|
217
|
+
| `range` | `model<DateRange<D> \| null>` | Two-way bindable committed range. Only used in `selectionMode="range"`. `(rangeChange)` fires only on internal commits/clears.<br>**Default:** `null` |
|
|
218
|
+
| `minRangeLength` | `input<number \| null>` | Minimum inclusive day count. A commit shorter than this is a no-op.<br>**Default:** `null` (no minimum) |
|
|
219
|
+
| `maxRangeLength` | `input<number \| null>` | Maximum inclusive day count. A commit longer than this is a no-op.<br>**Default:** `null` (no maximum) |
|
|
220
|
+
| `min` | `input<D \| null>` | Minimum selectable date (inclusive). Earlier dates are unavailable.<br>**Default:** `null` |
|
|
221
|
+
| `max` | `input<D \| null>` | Maximum selectable date (inclusive). Later dates are unavailable.<br>**Default:** `null` |
|
|
222
|
+
| `isDateUnavailable` | `input<(date: D) => boolean>` | Per-date predicate marking a date unavailable (present but not selectable).<br>**Default:** `() => false` |
|
|
223
|
+
| `dateLabel` | `input<CalendarDateLabelFormatter<D>>` | Formats each gridcell's `aria-label` (full accessible date).<br>**Default:** localized full date, outside-month days through the scope's `outsideMonthLabel` |
|
|
224
|
+
| `disabled` | `input<boolean>` | Disables the whole calendar (no focus movement, no selection). Reflected as `data-disabled`.<br>**Default:** — |
|
|
225
|
+
| `readonly` | `input<boolean>` | Read-only: dates stay focusable, selection is blocked. Reflected as `data-readonly`.<br>**Default:** — |
|
|
226
|
+
| `firstDayOfWeek` | `input<number \| null>` | First column's weekday, **0-6** (`0` = Sunday).<br>**Default:** `null` → the adapter's value (or `provideForCalendarDefaults`) |
|
|
227
|
+
| `locale` | `input<string \| null>` | BCP 47 locale for the heading, weekday headers, month-picker options and cell `aria-label` names. The calendar system stays Gregorian.<br>**Default:** `null` → the adapter's `locale()`, then the runtime locale |
|
|
228
|
+
| `dir` | `input<'ltr' \| 'rtl' \| null>` | Writing direction.<br>**Default:** `null` resolves the ambient direction; reflected to the host `dir` and mirrors horizontal arrows |
|
|
229
229
|
|
|
230
230
|
### Data attributes
|
|
231
231
|
|
|
@@ -538,9 +538,16 @@ Auto-disabled when the entire previous / next page would be outside `[min, max]`
|
|
|
538
538
|
import { provideForCalendarDefaults } from 'forty-cdk/calendar';
|
|
539
539
|
|
|
540
540
|
// app config or a component's providers — Monday-first weeks for this scope
|
|
541
|
-
providers: [
|
|
541
|
+
providers: [
|
|
542
|
+
provideForCalendarDefaults({
|
|
543
|
+
firstDayOfWeek: 1,
|
|
544
|
+
outsideMonthLabel: (formattedDate) => `${formattedDate} (fuera del mes)`,
|
|
545
|
+
}),
|
|
546
|
+
];
|
|
542
547
|
```
|
|
543
548
|
|
|
549
|
+
`outsideMonthLabel` builds the `aria-label` of a padding day outside the visible month from its formatted full date (default `"<date> (outside month)"`), so assistive tech can tell it apart from the month on screen. A calendar bound to its own `[dateLabel]` formatter ignores it.
|
|
550
|
+
|
|
544
551
|
## Keyboard
|
|
545
552
|
|
|
546
553
|
LTR (horizontal arrows mirror under `dir="rtl"`):
|
|
@@ -569,7 +576,7 @@ Implements the [WAI-ARIA Grid pattern](https://www.w3.org/WAI/ARIA/apg/patterns/
|
|
|
569
576
|
|
|
570
577
|
## Styling
|
|
571
578
|
|
|
572
|
-
forty-cdk ships no styles
|
|
579
|
+
forty-cdk ships no styles: put your own class on each piece and key your CSS off the `data-*` attributes listed under [Data attributes](#data-attributes), not off the `forCalendar*` selectors ([Styling forty-cdk](../../../docs/styling.md) explains why).
|
|
573
580
|
|
|
574
581
|
```css
|
|
575
582
|
.calendar-cell {
|
|
@@ -615,4 +622,4 @@ export class DatePage {
|
|
|
615
622
|
|
|
616
623
|
## Wrapping in a design system
|
|
617
624
|
|
|
618
|
-
|
|
625
|
+
Subclass the root and re-provide `FOR_CALENDAR_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/carousel/README.md
CHANGED
|
@@ -74,7 +74,8 @@ import {
|
|
|
74
74
|
|
|
75
75
|
interface Slide {
|
|
76
76
|
readonly id: number;
|
|
77
|
-
readonly
|
|
77
|
+
readonly title: string;
|
|
78
|
+
readonly summary: string;
|
|
78
79
|
}
|
|
79
80
|
|
|
80
81
|
@Component({
|
|
@@ -98,7 +99,7 @@ interface Slide {
|
|
|
98
99
|
loop
|
|
99
100
|
orientation="horizontal"
|
|
100
101
|
align="start"
|
|
101
|
-
ariaLabel="Featured
|
|
102
|
+
ariaLabel="Featured stories"
|
|
102
103
|
>
|
|
103
104
|
<div class="car-controls-row">
|
|
104
105
|
<button forCarouselPrevious class="car-btn" aria-label="Previous slide">
|
|
@@ -131,7 +132,8 @@ interface Slide {
|
|
|
131
132
|
<div forCarouselTrack class="car-track">
|
|
132
133
|
@for (slide of slides; track slide.id; let i = $index) {
|
|
133
134
|
<div forCarouselSlide class="car-slide" [class]="'car-slide--' + (i + 1)">
|
|
134
|
-
<
|
|
135
|
+
<p class="car-slide-title">{{ slide.title }}</p>
|
|
136
|
+
<p class="car-slide-summary">{{ slide.summary }}</p>
|
|
135
137
|
</div>
|
|
136
138
|
}
|
|
137
139
|
</div>
|
|
@@ -151,11 +153,27 @@ interface Slide {
|
|
|
151
153
|
})
|
|
152
154
|
export class CarouselDefaultExample {
|
|
153
155
|
protected readonly slides: readonly Slide[] = [
|
|
154
|
-
{
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
156
|
+
{
|
|
157
|
+
id: 1,
|
|
158
|
+
title: 'The coast road north',
|
|
159
|
+
summary: 'Four days, three ferries and one small car.',
|
|
160
|
+
},
|
|
161
|
+
{
|
|
162
|
+
id: 2,
|
|
163
|
+
title: 'Markets before dawn',
|
|
164
|
+
summary: 'Where the city buys its fish, flowers and coffee.',
|
|
165
|
+
},
|
|
166
|
+
{
|
|
167
|
+
id: 3,
|
|
168
|
+
title: 'A week without screens',
|
|
169
|
+
summary: 'What changed, and the one habit that stuck.',
|
|
170
|
+
},
|
|
171
|
+
{ id: 4, title: 'Bread, slowly', summary: 'A starter, a schedule and a forgiving first loaf.' },
|
|
172
|
+
{
|
|
173
|
+
id: 5,
|
|
174
|
+
title: 'Mapping the old river',
|
|
175
|
+
summary: 'Tracing a buried stream through five neighbourhoods.',
|
|
176
|
+
},
|
|
159
177
|
];
|
|
160
178
|
|
|
161
179
|
protected readonly activeIndex = signal(0);
|
|
@@ -339,9 +357,11 @@ captured, so page scrolling on the perpendicular axis is unaffected.
|
|
|
339
357
|
|
|
340
358
|
Each slide's default `aria-label` is the positional `"N of M"` string, each
|
|
341
359
|
indicator's is `"Go to slide N"`, and the rotation control's swaps between
|
|
342
|
-
`"Start automatic slide show"` and `"Stop automatic slide show"`.
|
|
343
|
-
|
|
344
|
-
|
|
360
|
+
`"Start automatic slide show"` and `"Stop automatic slide show"`. The root and
|
|
361
|
+
each slide also carry an `aria-roledescription` (`"carousel"` / `"slide"`), which
|
|
362
|
+
a screen reader speaks in place of the `group` role. Localize them all centrally
|
|
363
|
+
with `provideForCarouselDefaults` instead of setting `ariaLabel` on every slide
|
|
364
|
+
and indicator:
|
|
345
365
|
|
|
346
366
|
<!-- snippet: fragment -->
|
|
347
367
|
|
|
@@ -352,6 +372,8 @@ providers: [
|
|
|
352
372
|
indicatorLabel: (position) => `Ir a la diapositiva ${position}`,
|
|
353
373
|
rotationStartLabel: 'Iniciar la presentación',
|
|
354
374
|
rotationStopLabel: 'Detener la presentación',
|
|
375
|
+
roleDescription: 'carrusel',
|
|
376
|
+
slideRoleDescription: 'diapositiva',
|
|
355
377
|
}),
|
|
356
378
|
];
|
|
357
379
|
```
|
|
@@ -360,7 +382,10 @@ providers: [
|
|
|
360
382
|
merge with the parent scope, so you can localize just the labels and inherit the
|
|
361
383
|
rest of the defaults. A per-element `ariaLabel` on `[forCarouselSlide]` /
|
|
362
384
|
`[forCarouselIndicator]` still takes precedence over the localized default, as do
|
|
363
|
-
`[startLabel]` / `[stopLabel]` on `[forCarouselRotationControl]`.
|
|
385
|
+
`[startLabel]` / `[stopLabel]` on `[forCarouselRotationControl]`. For a language
|
|
386
|
+
the app sets or switches after bootstrap, pass the text keys as functions and the
|
|
387
|
+
overrides as a factory, as
|
|
388
|
+
[Localizing default text](../shared/README.md#localizing-default-text) shows.
|
|
364
389
|
|
|
365
390
|
## Indicators map 1:1 to slides
|
|
366
391
|
|
|
@@ -455,7 +480,8 @@ Implements the [WAI-ARIA Carousel pattern](https://www.w3.org/WAI/ARIA/apg/patte
|
|
|
455
480
|
should describe the carousel's purpose without using the word "carousel" (APG guidance).
|
|
456
481
|
- Each slide carries `role="group"`, `aria-roledescription="slide"`, and
|
|
457
482
|
`aria-label="N of M"` by default. Override per slide with the `ariaLabel` input,
|
|
458
|
-
or localize the default format app-wide with
|
|
483
|
+
or localize the default format and both role descriptions app-wide with
|
|
484
|
+
`provideForCarouselDefaults` (see
|
|
459
485
|
[Localizing the default labels](#localizing-the-default-labels)).
|
|
460
486
|
- Off-view slides receive `aria-hidden="true"` and `inert` to remove them from the
|
|
461
487
|
accessibility tree and focus order.
|
|
@@ -473,7 +499,7 @@ Implements the [WAI-ARIA Carousel pattern](https://www.w3.org/WAI/ARIA/apg/patte
|
|
|
473
499
|
|
|
474
500
|
## Styling
|
|
475
501
|
|
|
476
|
-
forty-cdk ships no styles
|
|
502
|
+
forty-cdk ships no styles: put your own class on each piece rather than styling the `for*` selectors ([Styling forty-cdk](../../../docs/styling.md) explains why). The directive publishes geometry as CSS custom properties on the root element so they cascade to the track. The consumer applies the transform and transition.
|
|
477
503
|
|
|
478
504
|
```css
|
|
479
505
|
[forCarouselViewport] {
|
|
@@ -577,4 +603,4 @@ The example CSS above is LTR-only by default.
|
|
|
577
603
|
|
|
578
604
|
## Wrapping in a design system
|
|
579
605
|
|
|
580
|
-
|
|
606
|
+
Subclass the root and re-provide `FOR_CAROUSEL_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/checkbox/README.md
CHANGED
|
@@ -188,7 +188,7 @@ Implements the [WAI-ARIA Checkbox pattern](https://www.w3.org/WAI/ARIA/apg/patte
|
|
|
188
188
|
|
|
189
189
|
## Styling
|
|
190
190
|
|
|
191
|
-
forty-cdk ships no styles
|
|
191
|
+
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).
|
|
192
192
|
|
|
193
193
|
```css
|
|
194
194
|
.cb-check {
|
|
@@ -213,4 +213,4 @@ forty-cdk ships no styles. Add your own class to each piece. The for\* selectors
|
|
|
213
213
|
|
|
214
214
|
## Wrapping in a design system
|
|
215
215
|
|
|
216
|
-
|
|
216
|
+
[Wrapping form primitives](../../../docs/wrapping-form-primitives.md) documents both supported wrapper patterns: `hostDirectives` with the exported `FOR_CHECKBOX_HOST_DIRECTIVE_INPUTS` / `FOR_CHECKBOX_HOST_DIRECTIVE_OUTPUTS` name tuples, and subclassing.
|
package/combobox/README.md
CHANGED
|
@@ -207,6 +207,8 @@ Input tables are not yet tabulated for this primitive. See the feature sections
|
|
|
207
207
|
| `[forCombobox]` | `data-readonly` | present / absent |
|
|
208
208
|
| `[forComboboxInput]` | `data-state` | `open` \| `closed` |
|
|
209
209
|
| `[forComboboxInput]` | `data-disabled` | present / absent |
|
|
210
|
+
| `[forComboboxToggle]` | `data-state` | `open` \| `closed` |
|
|
211
|
+
| `[forComboboxToggle]` | `data-disabled` | present / absent |
|
|
210
212
|
| `[forComboboxContent]` | `data-state` | `open` \| `closed` |
|
|
211
213
|
| `[forComboboxOption]` | `data-state` | `checked` \| `unchecked` (membership in `value()`, both modes) |
|
|
212
214
|
| `[forComboboxOption]` | `data-highlighted` | present / absent (the current `aria-activedescendant`) |
|
|
@@ -245,7 +247,31 @@ By default the listbox is positioned against `[forComboboxInput]`. When the inpu
|
|
|
245
247
|
</div>
|
|
246
248
|
```
|
|
247
249
|
|
|
248
|
-
`[forComboboxAnchor]` changes **only** positioning. The input keeps `aria-controls` / `aria-expanded` / `aria-activedescendant`, all keyboard interaction, and its exemption from outside-pointer dismissal. Without an anchor the listbox falls back to the input, so existing markup is unaffected. Each `[forCombobox]` takes
|
|
250
|
+
`[forComboboxAnchor]` changes **only** positioning. The input keeps `aria-controls` / `aria-expanded` / `aria-activedescendant`, all keyboard interaction, and its exemption from outside-pointer dismissal. Without an anchor the listbox falls back to the input, so existing markup is unaffected. It wins over a surrounding field's [`[forFieldAnchor]`](../field/README.md#positioning-anchor). Each `[forCombobox]` takes one `[forComboboxAnchor]`, and a second one warns in dev mode. In multi mode, wrap `[forComboboxChips]` (which already wraps the chips + input) to anchor against the full chip cluster.
|
|
251
|
+
|
|
252
|
+
## Toggle button
|
|
253
|
+
|
|
254
|
+
An editable combobox often carries a chevron button next to the input, as in the APG's [editable combobox examples](https://www.w3.org/WAI/ARIA/apg/patterns/combobox/examples/combobox-autocomplete-list/). Put `[forComboboxToggle]` on a real `<button>`:
|
|
255
|
+
|
|
256
|
+
```html
|
|
257
|
+
<div forCombobox #combobox="forCombobox" [(query)]="query" [(value)]="value">
|
|
258
|
+
<div forComboboxAnchor class="field-box">
|
|
259
|
+
<input forComboboxInput placeholder="Search a fruit…" />
|
|
260
|
+
<button forComboboxToggle>▾</button>
|
|
261
|
+
</div>
|
|
262
|
+
@if (combobox.open()) {
|
|
263
|
+
<div forComboboxContent>
|
|
264
|
+
@for (it of filtered; track it.id) {
|
|
265
|
+
<div forComboboxOption [value]="it.id" [label]="it.label">{{ it.label }}</div>
|
|
266
|
+
}
|
|
267
|
+
</div>
|
|
268
|
+
}
|
|
269
|
+
</div>
|
|
270
|
+
```
|
|
271
|
+
|
|
272
|
+
A press closes an open listbox, or opens a closed one with the committed selection highlighted (the first enabled option when nothing is selected) and moves focus into the input. The press never takes focus itself, so an input that already has focus keeps it and the combobox is not marked touched. The button is exempt from the listbox's outside-pointer dismissal, so one press is one `(openChange)`.
|
|
273
|
+
|
|
274
|
+
Unlike `[forComboboxTrigger]`, a toggle keeps the editable anatomy: `commitOnSelect` still copies the picked label into the input, and `query` survives a close. The button is out of the Tab sequence (`tabindex="-1"`) because the input already owns the keyboard, reflects `aria-expanded` and `aria-controls` (the listbox, while open), and carries native `disabled` from the combobox's effective disabled. Its accessible name defaults to `'Show options'`; override it per instance with `[ariaLabel]`, or for the scope with `provideForComboboxDefaults({ toggleAriaLabel })`.
|
|
249
275
|
|
|
250
276
|
## Picker anatomy
|
|
251
277
|
|
|
@@ -402,6 +428,7 @@ They diverge while the user types and resync on activation:
|
|
|
402
428
|
- **Multi mode** → option's value is toggled in/out of `value`. If `commitOnSelect` is on (default), `query` is **cleared** so the user can search the next item. Listbox stays open.
|
|
403
429
|
- Clear button → both reset.
|
|
404
430
|
- `clearOnQueryChange` (off by default, **single mode only**): flip on to drop `value` automatically whenever the query is edited (useful when the user editing means "I'm picking a new one").
|
|
431
|
+
- `restoreQueryOnClose` (off by default, **single mode only**): flip on to put the selected label back into the input when the listbox closes without a pick. See [`restoreQueryOnClose`](#restorequeryonclose).
|
|
405
432
|
|
|
406
433
|
### `commitOnSelect`: single vs multi
|
|
407
434
|
|
|
@@ -429,6 +456,19 @@ Multi, commitOnSelect=false
|
|
|
429
456
|
|
|
430
457
|
Disable `commitOnSelect` when your filter logic compares against `query` directly and the listbox should keep showing the just-narrowed set after activation, instead of resetting to "everything matches the picked label".
|
|
431
458
|
|
|
459
|
+
### `restoreQueryOnClose`
|
|
460
|
+
|
|
461
|
+
In the editable anatomy, closing the listbox leaves `query` as the user left it, so typing "ap" over a committed "Banana" and pressing Escape keeps showing "ap". With `[restoreQueryOnClose]="true"`, a single-select combobox restores the selected option's label on every close that is not a pick (Escape, an outside press, Tab, a `[forComboboxToggle]` press, `closeOverlay()`), and clears the input when nothing is selected. The input keeps focus on Escape, and the restored text reaches it even while focused. A pick still follows `commitOnSelect`.
|
|
462
|
+
|
|
463
|
+
```text
|
|
464
|
+
Single, restoreQueryOnClose=true
|
|
465
|
+
user activates "Banana" → query="Banana" value=["banana"]
|
|
466
|
+
user types "ap" → query="ap" value=["banana"]
|
|
467
|
+
user presses Escape → query="Banana" value=["banana"] ← label restored, listbox closes
|
|
468
|
+
```
|
|
469
|
+
|
|
470
|
+
The label is the one `selected()` resolves: the option's own label once it has rendered, `[itemToStringLabel]` before that (a value bound before the listbox ever opened). Multi mode and the picker anatomy ignore the input. Enable it for the whole scope with `provideForComboboxDefaults({ restoreQueryOnClose: true })`.
|
|
471
|
+
|
|
432
472
|
## Multi mode
|
|
433
473
|
|
|
434
474
|
Pass `multiple` and let the consumer render chips inside `[forComboboxChips]`. The primitive's `selected()` computed returns `{ value, label }` pairs ready for `@for`:
|
|
@@ -493,6 +533,10 @@ When the input is empty (no query) and the user presses Backspace, focus jumps t
|
|
|
493
533
|
| Auto-highlight first option | `true` | `[autoHighlight]="false"` to require arrowing to an option first |
|
|
494
534
|
| Commit label / clear query on select | `true` | `[commitOnSelect]="false"` |
|
|
495
535
|
| Clear value on query edit (single only) | `false` | `[clearOnQueryChange]="true"` |
|
|
536
|
+
| Highlight the selection on open | `first` | `openHighlight="selected"` |
|
|
537
|
+
| Restore label on close (single only) | `false` | `[restoreQueryOnClose]="true"` |
|
|
538
|
+
|
|
539
|
+
`openHighlight` decides where the editable anatomy's highlight lands when the listbox opens from focus, click, ArrowDown / ArrowUp or `openOverlay()` without an argument. With `'selected'`, a single-select combobox showing "Spain" reopens on "Spain" rather than on the first option; with nothing selected, ArrowDown still lands on the first option and ArrowUp on the last. Opening from a typed query always highlights the first match, because the list is a filter result there, and the picker anatomy always opens on the selection. Both inputs take their default from the scope: `provideForComboboxDefaults({ openHighlight: 'selected', restoreQueryOnClose: true })`.
|
|
496
540
|
|
|
497
541
|
## Autocomplete modes
|
|
498
542
|
|
|
@@ -735,20 +779,20 @@ A single-select field is modeled as the same `readonly T[]`, kept at length ≤
|
|
|
735
779
|
|
|
736
780
|
Focus stays in the input throughout: arrow keys move the listbox's _active descendant_ (the highlighted option), not DOM focus.
|
|
737
781
|
|
|
738
|
-
| Key | Action
|
|
739
|
-
| -------------------------------------------- |
|
|
740
|
-
| **ArrowDown** | Open listbox + move activedescendant to next enabled option (or first when none).
|
|
741
|
-
| **ArrowUp** | Open listbox + move activedescendant to previous enabled option (or last when none).
|
|
742
|
-
| **Home** _(open)_ | Move activedescendant to first enabled option.
|
|
743
|
-
| **End** _(open)_ | Move activedescendant to last enabled option.
|
|
744
|
-
| **PageUp** _(open)_ | Move activedescendant to first enabled option.
|
|
745
|
-
| **PageDown** _(open)_ | Move activedescendant to last enabled option.
|
|
746
|
-
| **Enter** _(open)_ | Activate the activedescendant (single: replace + close; multi: toggle + stay open).
|
|
747
|
-
| **Escape** _(open)_ | Close the listbox. Focus stays in the input.
|
|
748
|
-
| **Tab** _(open, no action)_ | Close the listbox and let Tab flow to the next focusable.
|
|
749
|
-
| **Tab / Shift+Tab** _(open, action present)_ | Move focus around the input↔actions ring without dismissing (see [Action items](#action-items)).
|
|
750
|
-
| **Backspace** _(empty input, multi only)_ | Focus the last chip; a second Backspace there removes it.
|
|
751
|
-
| Printable keys | Update `query`. With `'inline'` / `'both'` autocomplete, complete the rest of the first match into the input as selected text.
|
|
782
|
+
| Key | Action |
|
|
783
|
+
| -------------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------ |
|
|
784
|
+
| **ArrowDown** | Open listbox + move activedescendant to next enabled option (or first when none; the selection under `openHighlight="selected"`). |
|
|
785
|
+
| **ArrowUp** | Open listbox + move activedescendant to previous enabled option (or last when none; the selection under `openHighlight="selected"`). |
|
|
786
|
+
| **Home** _(open)_ | Move activedescendant to first enabled option. |
|
|
787
|
+
| **End** _(open)_ | Move activedescendant to last enabled option. |
|
|
788
|
+
| **PageUp** _(open)_ | Move activedescendant to first enabled option. |
|
|
789
|
+
| **PageDown** _(open)_ | Move activedescendant to last enabled option. |
|
|
790
|
+
| **Enter** _(open)_ | Activate the activedescendant (single: replace + close; multi: toggle + stay open). |
|
|
791
|
+
| **Escape** _(open)_ | Close the listbox. Focus stays in the input. |
|
|
792
|
+
| **Tab** _(open, no action)_ | Close the listbox and let Tab flow to the next focusable. |
|
|
793
|
+
| **Tab / Shift+Tab** _(open, action present)_ | Move focus around the input↔actions ring without dismissing (see [Action items](#action-items)). |
|
|
794
|
+
| **Backspace** _(empty input, multi only)_ | Focus the last chip; a second Backspace there removes it. |
|
|
795
|
+
| Printable keys | Update `query`. With `'inline'` / `'both'` autocomplete, complete the rest of the first match into the input as selected text. |
|
|
752
796
|
|
|
753
797
|
Hovering an option also makes it the activedescendant, so mouse and keyboard intent stay synchronized.
|
|
754
798
|
|
|
@@ -760,6 +804,7 @@ Implements the [WAI-ARIA Combobox pattern](https://www.w3.org/WAI/ARIA/apg/patte
|
|
|
760
804
|
- `role="listbox"` lives on `[forComboboxContent]` in the editable anatomy and on `[forComboboxList]` in the picker anatomy; the input's `aria-controls` targets whichever carries it. In the picker anatomy the popup surface (`[forComboboxContent]`) is role-less so it can hold the input next to the list without an `aria-required-owned-elements` violation.
|
|
761
805
|
- `aria-multiselectable="true"` (multi mode) and the labelled role (`aria-label` / `aria-labelledby`, pointing at the input) sit on whichever element carries `role="listbox"`: content in the editable anatomy, the list in the picker anatomy.
|
|
762
806
|
- `[forComboboxTrigger]` (picker anatomy) is a real `<button>` reflecting `aria-haspopup="listbox"`, `aria-expanded`, `aria-controls` (the popup surface, while open), and native `disabled` from the combobox's effective disabled. It is exempt from the popup's outside-pointer dismissal layer, like the input.
|
|
807
|
+
- `[forComboboxToggle]` (editable anatomy) is a real `<button>` with `tabindex="-1"`, a localizable `aria-label`, `aria-expanded`, `aria-controls` (the listbox, while open) and native `disabled`. It cancels `mousedown` so focus stays in the input, and it is exempt from the outside-pointer dismissal layer.
|
|
763
808
|
- In single mode, `aria-selected="true"` follows the activedescendant (the option Enter would activate). In multi mode it follows membership in `value()`, so every selected option carries `aria-selected="true"` simultaneously.
|
|
764
809
|
- `data-state="checked" | "unchecked"` always reflects membership in `value()`, so consumers can paint a checkmark icon with pure CSS regardless of mode.
|
|
765
810
|
- `data-highlighted=""` marks the option that is the current `aria-activedescendant`. Because focus stays on the `<input>`, there is no `:focus` on the option to style. `data-highlighted` is the canonical CSS hook.
|
|
@@ -772,7 +817,7 @@ Implements the [WAI-ARIA Combobox pattern](https://www.w3.org/WAI/ARIA/apg/patte
|
|
|
772
817
|
|
|
773
818
|
## Styling
|
|
774
819
|
|
|
775
|
-
forty-cdk ships no styles
|
|
820
|
+
forty-cdk ships no styles: put your own class on each piece and key your CSS off the `data-*` attributes listed under [Data attributes](#data-attributes), not off the `for*` selectors ([Styling forty-cdk](../../../docs/styling.md) explains why).
|
|
776
821
|
|
|
777
822
|
### CSS custom properties
|
|
778
823
|
|
package/context-menu/README.md
CHANGED
|
@@ -122,7 +122,7 @@ Same vetoable dismiss API as DropdownMenu. Call `preventDefault()` on the emitte
|
|
|
122
122
|
|
|
123
123
|
## Styling
|
|
124
124
|
|
|
125
|
-
forty-cdk ships no styles
|
|
125
|
+
forty-cdk ships no styles: put your own class on each piece and key your CSS off the `data-*` attributes listed under [Data attributes](#data-attributes), not off the `for*` selectors ([Styling forty-cdk](../../../docs/styling.md) explains why).
|
|
126
126
|
|
|
127
127
|
> The menu content (`[forMenuContent]`, from the [`menu/`](../menu/README.md) folder) portals to `document.body`, so it sits outside the trigger's DOM subtree and descendant selectors won't reach it. Style it with **global CSS** or a class on the content element. The content host also exposes the shared positioner custom properties (`--for-floating-anchor-width` / `--for-floating-anchor-height`, `--for-floating-available-width` / `--for-floating-available-height`, `--for-floating-content-transform-origin`); see [Styling floating content](../../../docs/styling-floating-content.md) for the full list and the animation rules.
|
|
128
128
|
|
|
@@ -138,6 +138,7 @@ forty-cdk ships no styles. Add your own class to each piece. The for\* selectors
|
|
|
138
138
|
- **Virtual anchor.** Right-click captures a 0×0 rect at the pointer location. `Shift+F10` and `ContextMenu` snapshot the bounding rect of the focused element (or the trigger if focus is on it directly), so the menu floats off the element under attention. Both forms feed floating-ui's `flip` and `shift` middleware, so corners and screen edges work without special-casing.
|
|
139
139
|
- **Keyboard activators only fire while focus is inside the trigger.** Keyboard events dispatch to the focused element, so `Shift+F10` / `ContextMenu` anywhere outside the trigger goes to the browser default. The trigger is focusable by default (host-bound `tabindex="-1"`), so this works out of the box and focus can return to it programmatically when the menu closes. Your own `tabindex` wins over that default: use `tabindex="0"` if you want the region itself reachable via Tab.
|
|
140
140
|
- **Native menu suppressed.** The trigger calls `event.preventDefault()` on `contextmenu` and on the keyboard activators. Set `disabled` to let the browser's native menu surface for that region.
|
|
141
|
+
- **An open that renders nothing closes again.** When a right-click, `Shift+F10`, the `ContextMenu` key or a long-press opens a menu whose template renders no `[forMenuContent]`, the trigger closes it after the next render with reason `'programmatic'`, and dev mode logs `FORCDK-CONTEXT-MENU-002` once. The native menu cannot come back for that gesture, because it was already suppressed, so bind `[disabled]` to the same condition that renders the content: `[disabled]="!hasActions(col)"` beside `@if (hasActions(col))`.
|
|
141
142
|
- **Touch long-press.** The trigger runs its own long-press timer (a `touch` `pointerdown` held ~500 ms, without lifting or moving past a small tolerance, opens the menu at the touch point). This is required because iOS Safari never fires the `contextmenu` event a long-press synthesizes elsewhere; where the browser does synthesize it (Android, desktop touch emulation) the two paths stay mutually exclusive, so the menu opens exactly once. For the press to survive on iOS, suppress the native callout / text-selection on the trigger with CSS, since otherwise the OS gesture cancels the press:
|
|
142
143
|
|
|
143
144
|
```css
|
|
@@ -201,4 +202,4 @@ Both triggers carry `[menuPositioning]`, a partial `{ side, align, sideOffset, a
|
|
|
201
202
|
|
|
202
203
|
## Wrapping in a design system
|
|
203
204
|
|
|
204
|
-
|
|
205
|
+
Subclass the root and re-provide `FOR_MENU_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/date-field/README.md
CHANGED
|
@@ -149,17 +149,17 @@ With a time-capable adapter, a `granularity` coarser than `'day'` appends time s
|
|
|
149
149
|
|
|
150
150
|
### `ForDateField`
|
|
151
151
|
|
|
152
|
-
| Property | Type | Description
|
|
153
|
-
| ------------- | ------------------------------------------------ |
|
|
154
|
-
| `value` | `model<D \| null>` | Two-way bindable entered date, or `null` while any segment is empty. The `FormValueControl` backing.<br>**Default:** `null`
|
|
155
|
-
| `minDate` | `input<D \| null>` | Minimum date (inclusive). A composed value below it is clamped up. Named `minDate` (see note below).<br>**Default:** `null`
|
|
156
|
-
| `maxDate` | `input<D \| null>` | Maximum date (inclusive). A composed value above it is clamped down.<br>**Default:** `null`
|
|
157
|
-
| `granularity` | `input<'day' \| 'hour' \| 'minute' \| 'second'>` | Date-time precision. `'day'` is date-only; coarser-than-day appends time segments. See below.<br>**Default:** `'day'`
|
|
158
|
-
| `hourCycle` | `input<12 \| 24 \| null>` | 12/24-hour cycle for the time segments. `null` → locale. 12-hour adds the AM/PM segment.<br>**Default:** `null`
|
|
159
|
-
| `locale` | `input<string \| null>` | BCP 47 locale driving segment order, separators, and month name. `null` → runtime locale.<br>**Default:** `null` |
|
|
160
|
-
| `placeholder` | `input<Partial<Record<SegmentType, string>>>` | Per-segment placeholder while empty. Unspecified parts fall back to `dd` / `mm` / `yyyy` / `hh` / `mm` / `ss` / `--`.<br>**Default:** `{}` |
|
|
161
|
-
| `ariaLabel` | `input<string \| null>` | Accessible name for the group. Emits no `aria-label` while `null`.<br>**Default:** `null`
|
|
162
|
-
| `dir` | `input<'ltr' \| 'rtl' \| null>` | Writing direction. `null` resolves the ambient direction; mirrors ArrowLeft / ArrowRight segment navigation.<br>**Default:** `null`
|
|
152
|
+
| Property | Type | Description |
|
|
153
|
+
| ------------- | ------------------------------------------------ | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
|
|
154
|
+
| `value` | `model<D \| null>` | Two-way bindable entered date, or `null` while any segment is empty. The `FormValueControl` backing.<br>**Default:** `null` |
|
|
155
|
+
| `minDate` | `input<D \| null>` | Minimum date (inclusive). A composed value below it is clamped up. Named `minDate` (see note below).<br>**Default:** `null` |
|
|
156
|
+
| `maxDate` | `input<D \| null>` | Maximum date (inclusive). A composed value above it is clamped down.<br>**Default:** `null` |
|
|
157
|
+
| `granularity` | `input<'day' \| 'hour' \| 'minute' \| 'second'>` | Date-time precision. `'day'` is date-only; coarser-than-day appends time segments. See below.<br>**Default:** `'day'` |
|
|
158
|
+
| `hourCycle` | `input<12 \| 24 \| null>` | 12/24-hour cycle for the time segments. `null` → the scope's `hourCycle`, then the locale. 12-hour adds the AM/PM segment.<br>**Default:** `null` |
|
|
159
|
+
| `locale` | `input<string \| null>` | BCP 47 locale driving segment order, separators, and month name. `null` → the adapter's `locale()`, then the runtime locale.<br>**Default:** `null` |
|
|
160
|
+
| `placeholder` | `input<Partial<Record<SegmentType, string>>>` | Per-segment placeholder while empty. Unspecified parts fall back to the scope's `placeholder`, then to `dd` / `mm` / `yyyy` / `hh` / `mm` / `ss` / `--`.<br>**Default:** `{}` |
|
|
161
|
+
| `ariaLabel` | `input<string \| null>` | Accessible name for the group. Emits no `aria-label` while `null`.<br>**Default:** `null` |
|
|
162
|
+
| `dir` | `input<'ltr' \| 'rtl' \| null>` | Writing direction. `null` resolves the ambient direction; mirrors ArrowLeft / ArrowRight segment navigation.<br>**Default:** `null` |
|
|
163
163
|
|
|
164
164
|
Plus the shared `FormUiControl` members from `@angular/forms/signals`: `disabled`, `readonly`, `required`, `invalid`, `name`, `errors`, `touched` (bound automatically by `[formField]`).
|
|
165
165
|
|
|
@@ -207,18 +207,25 @@ On the AM/PM segment, `a` / `p` set the period and ArrowUp / ArrowDown toggle it
|
|
|
207
207
|
```ts
|
|
208
208
|
import { provideForDateFieldDefaults } from 'forty-cdk/date-field';
|
|
209
209
|
|
|
210
|
-
// app config or a component's providers — localize segment labels
|
|
211
|
-
// empty-segment announcement for every nested [forDateField].
|
|
210
|
+
// app config or a component's providers — localize segment labels, the
|
|
211
|
+
// empty-segment announcement and the placeholders for every nested [forDateField].
|
|
212
212
|
providers: [
|
|
213
213
|
provideForDateFieldDefaults({
|
|
214
214
|
emptySegmentText: 'Vacío',
|
|
215
215
|
segmentLabels: { day: 'día', month: 'mes', year: 'año', dayPeriod: 'AM/PM' },
|
|
216
|
+
placeholder: { day: 'dd', month: 'mm', year: 'aaaa' },
|
|
216
217
|
}),
|
|
217
218
|
];
|
|
218
219
|
```
|
|
219
220
|
|
|
220
221
|
`segmentLabels` supplies each segment's default `aria-label`, keyed by part type. Unset keys keep the library default (the part name, and `'AM/PM'` for the `dayPeriod` segment), so overriding a single key never wipes the rest. A segment's own `[ariaLabel]` still wins over the scope default.
|
|
221
222
|
|
|
223
|
+
`placeholder` is the text an empty segment shows, keyed the same way. A field's own `[placeholder]` wins for the parts it names and only those, and a part neither names keeps the letter-repeat default. `provideForDateRangeFieldDefaults` takes the same keys for `[forDateRangeField]`.
|
|
224
|
+
|
|
225
|
+
`hourCycle` sets the 12- or 24-hour cycle of every field that doesn't bind `[hourCycle]`, so a product on a 24-hour clock sets it once instead of on each field. Its fallback `null` derives the cycle from the locale.
|
|
226
|
+
|
|
227
|
+
For a language the app sets or switches after bootstrap, pass the text keys as functions and the overrides as a factory, as [Localizing default text](../shared/README.md#localizing-default-text) shows.
|
|
228
|
+
|
|
222
229
|
## Range selection — `ForDateRangeField`
|
|
223
230
|
|
|
224
231
|
For a date range use the dedicated `ForDateRangeField` root (selector `[forDateRangeField]`), shipped from this same entry point. It is the keyboard-first, form-capable counterpart to [DateRangePicker](../date-picker/README.md): two labelled `role="group"` endpoints (start / end) nested inside one outer `role="group"`. Each endpoint holds a row of spinbutton segments built on the same machinery as `ForDateField`. It implements `FormValueControl<DateRange<D> | null>`, the **same** contract as `ForDateRangePicker`, so the committed range auto-wires with `[formField]`. The value stays `null` until **both** endpoints are fully entered and ordered (`start <= end`).
|
|
@@ -263,17 +270,17 @@ readonly booking = form(this.model);
|
|
|
263
270
|
|
|
264
271
|
### `ForDateRangeField` API
|
|
265
272
|
|
|
266
|
-
| Property | Type | Description
|
|
267
|
-
| ------------- | ------------------------------------------------ |
|
|
268
|
-
| `value` | `model<DateRange<D> \| null>` | Two-way bindable committed range, or `null` while incomplete or out of order. The `FormValueControl` backing.<br>**Default:** `null`
|
|
269
|
-
| `minDate` | `input<D \| null>` | Minimum date (inclusive) for both endpoints. A composed endpoint below it is clamped up. Named `minDate` (see note below).<br>**Default:** `null`
|
|
270
|
-
| `maxDate` | `input<D \| null>` | Maximum date (inclusive) for both endpoints. A composed endpoint above it is clamped down.<br>**Default:** `null`
|
|
271
|
-
| `granularity` | `input<'day' \| 'hour' \| 'minute' \| 'second'>` | Date-time precision shared by both endpoints. `'day'` is date-only; coarser-than-day appends time segments.<br>**Default:** `'day'`
|
|
272
|
-
| `hourCycle` | `input<12 \| 24 \| null>` | 12/24-hour cycle for the time segments. `null` → locale. 12-hour adds the AM/PM segment.<br>**Default:** `null`
|
|
273
|
-
| `locale` | `input<string \| null>` | BCP 47 locale driving segment order, separators, and month name. `null` → runtime locale.<br>**Default:** `null`
|
|
274
|
-
| `placeholder` | `input<Partial<Record<SegmentType, string>>>` | Per-segment placeholder while empty, applied to both endpoints
|
|
275
|
-
| `ariaLabel` | `input<string \| null>` | Accessible name for the whole range field group. Emits no `aria-label` while `null`.<br>**Default:** `null`
|
|
276
|
-
| `dir` | `input<'ltr' \| 'rtl' \| null>` | Writing direction. `null` resolves the ambient direction; mirrors ArrowLeft / ArrowRight segment navigation.<br>**Default:** `null`
|
|
273
|
+
| Property | Type | Description |
|
|
274
|
+
| ------------- | ------------------------------------------------ | --------------------------------------------------------------------------------------------------------------------------------------------------- |
|
|
275
|
+
| `value` | `model<DateRange<D> \| null>` | Two-way bindable committed range, or `null` while incomplete or out of order. The `FormValueControl` backing.<br>**Default:** `null` |
|
|
276
|
+
| `minDate` | `input<D \| null>` | Minimum date (inclusive) for both endpoints. A composed endpoint below it is clamped up. Named `minDate` (see note below).<br>**Default:** `null` |
|
|
277
|
+
| `maxDate` | `input<D \| null>` | Maximum date (inclusive) for both endpoints. A composed endpoint above it is clamped down.<br>**Default:** `null` |
|
|
278
|
+
| `granularity` | `input<'day' \| 'hour' \| 'minute' \| 'second'>` | Date-time precision shared by both endpoints. `'day'` is date-only; coarser-than-day appends time segments.<br>**Default:** `'day'` |
|
|
279
|
+
| `hourCycle` | `input<12 \| 24 \| null>` | 12/24-hour cycle for the time segments. `null` → the scope's `hourCycle`, then the locale. 12-hour adds the AM/PM segment.<br>**Default:** `null` |
|
|
280
|
+
| `locale` | `input<string \| null>` | BCP 47 locale driving segment order, separators, and month name. `null` → the adapter's `locale()`, then the runtime locale.<br>**Default:** `null` |
|
|
281
|
+
| `placeholder` | `input<Partial<Record<SegmentType, string>>>` | Per-segment placeholder while empty, applied to both endpoints. Unspecified parts fall back to the scope's `placeholder`.<br>**Default:** `{}` |
|
|
282
|
+
| `ariaLabel` | `input<string \| null>` | Accessible name for the whole range field group. Emits no `aria-label` while `null`.<br>**Default:** `null` |
|
|
283
|
+
| `dir` | `input<'ltr' \| 'rtl' \| null>` | Writing direction. `null` resolves the ambient direction; mirrors ArrowLeft / ArrowRight segment navigation.<br>**Default:** `null` |
|
|
277
284
|
|
|
278
285
|
The endpoint groups each accept an `ariaLabel` input for their own group label, falling back to the scope defaults (`'Start date'` / `'End date'`). Plus the shared `FormUiControl` members bound automatically by `[formField]`.
|
|
279
286
|
|
|
@@ -323,7 +330,7 @@ Composes the [WAI-ARIA Spinbutton pattern](https://www.w3.org/WAI/ARIA/apg/patte
|
|
|
323
330
|
|
|
324
331
|
The library is styleless, so style the boolean `data-*` hooks yourself: `[data-highlighted]` (the focused/roving segment), `[data-placeholder]` (empty), `[data-disabled]` and `[data-readonly]` on the segments, and `[data-empty]` / `[data-disabled]` / `[data-readonly]` on the root group.
|
|
325
332
|
|
|
326
|
-
forty-cdk ships no styles
|
|
333
|
+
forty-cdk ships no styles: put your own class on each piece and key your CSS off the `data-*` attributes listed under [Data attributes](#data-attributes), not off the `for*` selectors ([Styling forty-cdk](../../../docs/styling.md) explains why).
|
|
327
334
|
|
|
328
335
|
```css
|
|
329
336
|
.date-field-segment[data-placeholder] {
|