forty-cdk 0.15.0 → 0.17.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/LICENSE +21 -21
- package/README.md +1 -1
- package/accordion/README.md +5 -1
- package/aspect-ratio/README.md +1 -1
- package/avatar/README.md +5 -1
- package/button/README.md +1 -1
- package/calendar/README.md +5 -1
- package/carousel/README.md +32 -20
- package/checkbox/README.md +9 -6
- package/combobox/README.md +25 -18
- package/context-menu/README.md +9 -5
- package/date-field/README.md +2 -2
- package/date-picker/README.md +7 -7
- package/date-range-field/README.md +2 -2
- package/dialog/README.md +10 -6
- package/disclosure/README.md +6 -2
- package/drag-drop/README.md +39 -4
- package/drawer/README.md +38 -31
- package/dropdown-menu/README.md +9 -5
- package/fesm2022/forty-cdk-accordion.mjs +38 -7
- package/fesm2022/forty-cdk-accordion.mjs.map +1 -1
- package/fesm2022/forty-cdk-button.mjs +9 -43
- package/fesm2022/forty-cdk-button.mjs.map +1 -1
- package/fesm2022/forty-cdk-calendar.mjs +10 -7
- package/fesm2022/forty-cdk-calendar.mjs.map +1 -1
- package/fesm2022/forty-cdk-carousel.mjs +62 -19
- package/fesm2022/forty-cdk-carousel.mjs.map +1 -1
- package/fesm2022/forty-cdk-checkbox.mjs +34 -8
- package/fesm2022/forty-cdk-checkbox.mjs.map +1 -1
- package/fesm2022/forty-cdk-combobox.mjs +60 -171
- package/fesm2022/forty-cdk-combobox.mjs.map +1 -1
- package/fesm2022/forty-cdk-context-menu.mjs +10 -2
- package/fesm2022/forty-cdk-context-menu.mjs.map +1 -1
- package/fesm2022/forty-cdk-core.mjs +434 -117
- package/fesm2022/forty-cdk-core.mjs.map +1 -1
- package/fesm2022/forty-cdk-date-field.mjs +7 -2
- package/fesm2022/forty-cdk-date-field.mjs.map +1 -1
- package/fesm2022/forty-cdk-date-picker.mjs +17 -10
- package/fesm2022/forty-cdk-date-picker.mjs.map +1 -1
- package/fesm2022/forty-cdk-date-range-field.mjs +7 -2
- package/fesm2022/forty-cdk-date-range-field.mjs.map +1 -1
- package/fesm2022/forty-cdk-dialog.mjs +14 -11
- package/fesm2022/forty-cdk-dialog.mjs.map +1 -1
- package/fesm2022/forty-cdk-disclosure.mjs +8 -5
- package/fesm2022/forty-cdk-disclosure.mjs.map +1 -1
- package/fesm2022/forty-cdk-drag-drop.mjs +30 -20
- package/fesm2022/forty-cdk-drag-drop.mjs.map +1 -1
- package/fesm2022/forty-cdk-drawer.mjs +121 -101
- package/fesm2022/forty-cdk-drawer.mjs.map +1 -1
- package/fesm2022/forty-cdk-dropdown-menu.mjs +7 -6
- package/fesm2022/forty-cdk-dropdown-menu.mjs.map +1 -1
- package/fesm2022/forty-cdk-file-upload.mjs +4 -3
- package/fesm2022/forty-cdk-file-upload.mjs.map +1 -1
- package/fesm2022/forty-cdk-hover-card.mjs +4 -4
- package/fesm2022/forty-cdk-hover-card.mjs.map +1 -1
- package/fesm2022/forty-cdk-input.mjs +2 -4
- package/fesm2022/forty-cdk-input.mjs.map +1 -1
- package/fesm2022/forty-cdk-listbox.mjs +18 -17
- package/fesm2022/forty-cdk-listbox.mjs.map +1 -1
- package/fesm2022/forty-cdk-menu.mjs +39 -24
- package/fesm2022/forty-cdk-menu.mjs.map +1 -1
- package/fesm2022/forty-cdk-menubar.mjs +156 -63
- package/fesm2022/forty-cdk-menubar.mjs.map +1 -1
- package/fesm2022/forty-cdk-navigation-menu.mjs +166 -49
- package/fesm2022/forty-cdk-navigation-menu.mjs.map +1 -1
- package/fesm2022/forty-cdk-number-input.mjs +8 -7
- package/fesm2022/forty-cdk-number-input.mjs.map +1 -1
- package/fesm2022/forty-cdk-otp-input.mjs +14 -15
- package/fesm2022/forty-cdk-otp-input.mjs.map +1 -1
- package/fesm2022/forty-cdk-pagination.mjs +10 -7
- package/fesm2022/forty-cdk-pagination.mjs.map +1 -1
- package/fesm2022/forty-cdk-popover.mjs +16 -12
- package/fesm2022/forty-cdk-popover.mjs.map +1 -1
- package/fesm2022/forty-cdk-radio-group.mjs +47 -10
- package/fesm2022/forty-cdk-radio-group.mjs.map +1 -1
- package/fesm2022/forty-cdk-search.mjs +6 -6
- package/fesm2022/forty-cdk-search.mjs.map +1 -1
- package/fesm2022/forty-cdk-select.mjs +74 -86
- package/fesm2022/forty-cdk-select.mjs.map +1 -1
- package/fesm2022/forty-cdk-shared.mjs +1 -1
- package/fesm2022/forty-cdk-slider.mjs +31 -29
- package/fesm2022/forty-cdk-slider.mjs.map +1 -1
- package/fesm2022/forty-cdk-stepper.mjs +13 -9
- package/fesm2022/forty-cdk-stepper.mjs.map +1 -1
- package/fesm2022/forty-cdk-switch.mjs +33 -7
- package/fesm2022/forty-cdk-switch.mjs.map +1 -1
- package/fesm2022/forty-cdk-table.mjs +52 -18
- package/fesm2022/forty-cdk-table.mjs.map +1 -1
- package/fesm2022/forty-cdk-tabs.mjs +45 -26
- package/fesm2022/forty-cdk-tabs.mjs.map +1 -1
- package/fesm2022/forty-cdk-time-field.mjs +7 -2
- package/fesm2022/forty-cdk-time-field.mjs.map +1 -1
- package/fesm2022/forty-cdk-time-picker.mjs +25 -9
- package/fesm2022/forty-cdk-time-picker.mjs.map +1 -1
- package/fesm2022/forty-cdk-time-range-field.mjs +7 -2
- package/fesm2022/forty-cdk-time-range-field.mjs.map +1 -1
- package/fesm2022/forty-cdk-toast.mjs +65 -26
- package/fesm2022/forty-cdk-toast.mjs.map +1 -1
- package/fesm2022/forty-cdk-toggle.mjs +14 -9
- package/fesm2022/forty-cdk-toggle.mjs.map +1 -1
- package/fesm2022/forty-cdk-toolbar.mjs +13 -6
- package/fesm2022/forty-cdk-toolbar.mjs.map +1 -1
- package/fesm2022/forty-cdk-tooltip.mjs +4 -4
- package/fesm2022/forty-cdk-tooltip.mjs.map +1 -1
- package/fesm2022/forty-cdk-tree.mjs +4 -3
- package/fesm2022/forty-cdk-tree.mjs.map +1 -1
- package/fesm2022/forty-cdk-virtualization.mjs +15 -10
- package/fesm2022/forty-cdk-virtualization.mjs.map +1 -1
- package/field/README.md +5 -1
- package/fieldset/README.md +5 -1
- package/file-upload/README.md +5 -1
- package/hover-card/README.md +10 -6
- package/input/README.md +6 -5
- package/internationalized-date/README.md +23 -23
- package/listbox/README.md +13 -13
- package/menu/README.md +10 -6
- package/menubar/README.md +24 -6
- package/meter/README.md +5 -1
- package/navigation-menu/README.md +9 -5
- package/number-input/README.md +4 -3
- package/otp-input/README.md +8 -7
- package/package.json +1 -1
- package/pagination/README.md +4 -0
- package/pane-resizer/README.md +1 -1
- package/popover/README.md +13 -9
- package/progress/README.md +5 -1
- package/radio-group/README.md +2 -2
- package/scroll-area/README.md +5 -1
- package/search/README.md +5 -3
- package/select/README.md +25 -26
- package/separator/README.md +1 -1
- package/shared/README.md +18 -3
- package/signal-forms/README.md +2 -2
- package/slider/README.md +22 -23
- package/stepper/README.md +6 -2
- package/switch/README.md +9 -7
- package/table/README.md +21 -957
- package/tabs/README.md +5 -1
- package/time-field/README.md +2 -2
- package/time-picker/README.md +2 -2
- package/time-range-field/README.md +2 -2
- package/toast/README.md +7 -3
- package/toggle/README.md +6 -5
- package/toolbar/README.md +5 -1
- package/tooltip/README.md +8 -4
- package/tree/README.md +5 -1
- package/types/forty-cdk-accordion.d.ts +48 -9
- package/types/forty-cdk-breakpoints.d.ts +1 -1
- package/types/forty-cdk-button.d.ts +1 -1
- package/types/forty-cdk-calendar.d.ts +3 -0
- package/types/forty-cdk-carousel.d.ts +83 -30
- package/types/forty-cdk-checkbox.d.ts +20 -4
- package/types/forty-cdk-combobox.d.ts +43 -23
- package/types/forty-cdk-context-menu.d.ts +10 -2
- package/types/forty-cdk-core.d.ts +406 -113
- package/types/forty-cdk-date-field.d.ts +5 -0
- package/types/forty-cdk-date-picker.d.ts +18 -11
- package/types/forty-cdk-date-range-field.d.ts +5 -0
- package/types/forty-cdk-dialog.d.ts +10 -6
- package/types/forty-cdk-disclosure.d.ts +5 -1
- package/types/forty-cdk-drag-drop.d.ts +11 -10
- package/types/forty-cdk-drawer.d.ts +93 -58
- package/types/forty-cdk-dropdown-menu.d.ts +3 -2
- package/types/forty-cdk-file-upload.d.ts +1 -0
- package/types/forty-cdk-hover-card.d.ts +5 -5
- package/types/forty-cdk-listbox.d.ts +10 -9
- package/types/forty-cdk-menu.d.ts +14 -4
- package/types/forty-cdk-menubar.d.ts +99 -14
- package/types/forty-cdk-navigation-menu.d.ts +151 -44
- package/types/forty-cdk-number-input.d.ts +2 -0
- package/types/forty-cdk-otp-input.d.ts +7 -7
- package/types/forty-cdk-pagination.d.ts +3 -0
- package/types/forty-cdk-popover.d.ts +12 -7
- package/types/forty-cdk-radio-group.d.ts +35 -19
- package/types/forty-cdk-search.d.ts +15 -14
- package/types/forty-cdk-select.d.ts +33 -16
- package/types/forty-cdk-shared.d.ts +1 -1
- package/types/forty-cdk-slider.d.ts +28 -23
- package/types/forty-cdk-stepper.d.ts +8 -4
- package/types/forty-cdk-switch.d.ts +23 -7
- package/types/forty-cdk-tabs.d.ts +73 -16
- package/types/forty-cdk-time-field.d.ts +5 -0
- package/types/forty-cdk-time-picker.d.ts +21 -4
- package/types/forty-cdk-time-range-field.d.ts +5 -0
- package/types/forty-cdk-toast.d.ts +70 -23
- package/types/forty-cdk-toggle.d.ts +6 -1
- package/types/forty-cdk-toolbar.d.ts +5 -2
- package/types/forty-cdk-tooltip.d.ts +5 -5
- package/types/forty-cdk-tree.d.ts +1 -0
- package/virtualization/README.md +4 -0
- package/visually-hidden/README.md +1 -1
package/LICENSE
CHANGED
|
@@ -1,21 +1,21 @@
|
|
|
1
|
-
MIT License
|
|
2
|
-
|
|
3
|
-
Copyright (c) 2026 tutkli
|
|
4
|
-
|
|
5
|
-
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
-
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
-
in the Software without restriction, including without limitation the rights
|
|
8
|
-
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
-
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
-
furnished to do so, subject to the following conditions:
|
|
11
|
-
|
|
12
|
-
The above copyright notice and this permission notice shall be included in all
|
|
13
|
-
copies or substantial portions of the Software.
|
|
14
|
-
|
|
15
|
-
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
-
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
-
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
-
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
-
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
-
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
-
SOFTWARE.
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 tutkli
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
package/README.md
CHANGED
|
@@ -98,7 +98,7 @@ The tables below group the primitives by purpose. The link on each name opens th
|
|
|
98
98
|
| ------------------------------------ | ---------------------------------------------------------------------------------------------------------- |
|
|
99
99
|
| [Calendar](calendar) | A single-date calendar grid (APG Grid) over a pluggable date adapter, with roving-tabindex navigation. |
|
|
100
100
|
| [Date Field](date-field) | A segmented date (and optional time) input — each part a spinbutton with locale-driven order and clamping. |
|
|
101
|
-
| [Date Picker](date-picker) | A trigger that opens a floating calendar to pick a date, composing Calendar inside a
|
|
101
|
+
| [Date Picker](date-picker) | A trigger that opens a floating calendar to pick a date, composing Calendar inside a dismissible popover. |
|
|
102
102
|
| [Date Range Field](date-range-field) | Two labelled spinbutton endpoints (start / end) sharing locale, granularity and bounds. |
|
|
103
103
|
| [Time Field](time-field) | A segmented time-of-day input with 12 / 24-hour cycles, optional seconds and min / max clamping. |
|
|
104
104
|
| [Time Picker](time-picker) | A trigger that opens a floating listbox of generated time slots over a pluggable date adapter. |
|
package/accordion/README.md
CHANGED
|
@@ -120,7 +120,7 @@ export class DemoFaq {
|
|
|
120
120
|
|
|
121
121
|
## Styling
|
|
122
122
|
|
|
123
|
-
forty-cdk ships no styles. Add your own class to each piece — the `for*` selectors are the behavior API, not a styling contract (see [Styling forty-cdk](
|
|
123
|
+
forty-cdk ships no styles. Add your own class to each piece — the `for*` selectors are the behavior API, not a styling contract (see [Styling forty-cdk](../../../docs/styling.md)). Key your CSS off the reflected `data-*` attributes listed per piece in the [API](#api) section.
|
|
124
124
|
|
|
125
125
|
```css
|
|
126
126
|
.trigger-chevron {
|
|
@@ -131,3 +131,7 @@ forty-cdk ships no styles. Add your own class to each piece — the `for*` selec
|
|
|
131
131
|
transform: rotate(180deg);
|
|
132
132
|
}
|
|
133
133
|
```
|
|
134
|
+
|
|
135
|
+
## Wrapping in a design system
|
|
136
|
+
|
|
137
|
+
Subclassing the root is the supported pattern; the subclass must spread `provideForAccordion(MyRoot)` into its own `providers` because Angular does not inherit a directive's `providers`, and every projected piece resolves its context through it. Re-providing `FOR_ACCORDION_CONTEXT` by hand is not enough: the root also provides an unexported registration token the wrapper cannot name. See [Wrapping non-form roots](../../../docs/wrapping-non-form-roots.md).
|
package/aspect-ratio/README.md
CHANGED
|
@@ -87,7 +87,7 @@ export class DemoAspectRatio {}
|
|
|
87
87
|
|
|
88
88
|
## Styling
|
|
89
89
|
|
|
90
|
-
forty-cdk ships no styles. Add your own class to each piece — the `for*` selectors are the behavior API, not a styling contract (see [Styling forty-cdk](
|
|
90
|
+
forty-cdk ships no styles. Add your own class to each piece — the `for*` selectors are the behavior API, not a styling contract (see [Styling forty-cdk](../../../docs/styling.md)). 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. Style the host through your own class on `[forAspectRatio]`.
|
|
91
91
|
|
|
92
92
|
## Behavior notes
|
|
93
93
|
|
package/avatar/README.md
CHANGED
|
@@ -98,7 +98,7 @@ The directive does not impose a `role`. Pair the avatar with visible name text o
|
|
|
98
98
|
|
|
99
99
|
## Styling
|
|
100
100
|
|
|
101
|
-
forty-cdk ships no styles. Add your own class to each piece — the `for*` selectors are the behavior API, not a styling contract (see [Styling forty-cdk](
|
|
101
|
+
forty-cdk ships no styles. Add your own class to each piece — the `for*` selectors are the behavior API, not a styling contract (see [Styling forty-cdk](../../../docs/styling.md)). Key your CSS off the reflected `data-*` attributes listed per piece in the [API](#api) section.
|
|
102
102
|
|
|
103
103
|
```css
|
|
104
104
|
.avatar-image:not([data-status='loaded']) {
|
|
@@ -115,3 +115,7 @@ forty-cdk ships no styles. Add your own class to each piece — the `for*` selec
|
|
|
115
115
|
- **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.
|
|
116
116
|
- **`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.
|
|
117
117
|
- **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.
|
|
118
|
+
|
|
119
|
+
## Wrapping in a design system
|
|
120
|
+
|
|
121
|
+
Subclassing the root is the supported pattern; the subclass must re-provide `FOR_AVATAR_CONTEXT` because Angular does not inherit a directive's `providers`, and every projected piece resolves its context through it. See [Wrapping non-form roots](../../../docs/wrapping-non-form-roots.md).
|
package/button/README.md
CHANGED
|
@@ -81,7 +81,7 @@ Implements the [WAI-ARIA Button pattern](https://www.w3.org/WAI/ARIA/apg/pattern
|
|
|
81
81
|
|
|
82
82
|
## Styling
|
|
83
83
|
|
|
84
|
-
forty-cdk ships no styles. Add your own class to each piece — the `for*` selectors are the behavior API, not a styling contract (see [Styling forty-cdk](
|
|
84
|
+
forty-cdk ships no styles. Add your own class to each piece — the `for*` selectors are the behavior API, not a styling contract (see [Styling forty-cdk](../../../docs/styling.md)). Key your CSS off the reflected `data-*` attributes listed per piece in the [API](#api) section.
|
|
85
85
|
|
|
86
86
|
```css
|
|
87
87
|
[forButton][data-disabled] {
|
package/calendar/README.md
CHANGED
|
@@ -438,7 +438,7 @@ Implements the [WAI-ARIA Grid pattern](https://www.w3.org/WAI/ARIA/apg/patterns/
|
|
|
438
438
|
|
|
439
439
|
## Styling
|
|
440
440
|
|
|
441
|
-
forty-cdk ships no styles. Add your own class to each piece — the `forCalendar*` selectors are the behavior API, not a styling contract (see [Styling forty-cdk](
|
|
441
|
+
forty-cdk ships no styles. Add your own class to each piece — the `forCalendar*` selectors are the behavior API, not a styling contract (see [Styling forty-cdk](../../../docs/styling.md)). Key your CSS off the reflected `data-*` attributes listed under [Data attributes](#data-attributes).
|
|
442
442
|
|
|
443
443
|
```css
|
|
444
444
|
.calendar-cell {
|
|
@@ -481,3 +481,7 @@ export class DatePage {
|
|
|
481
481
|
}
|
|
482
482
|
}
|
|
483
483
|
```
|
|
484
|
+
|
|
485
|
+
## Wrapping in a design system
|
|
486
|
+
|
|
487
|
+
Subclassing the root is the supported pattern; the subclass must re-provide `FOR_CALENDAR_CONTEXT` because Angular does not inherit a directive's `providers`, and every projected piece resolves its context through it. See [Wrapping non-form roots](../../../docs/wrapping-non-form-roots.md).
|
package/carousel/README.md
CHANGED
|
@@ -146,17 +146,22 @@ don't use it.
|
|
|
146
146
|
|
|
147
147
|
### CSS contract
|
|
148
148
|
|
|
149
|
-
The directive publishes `--for-carousel-
|
|
150
|
-
|
|
151
|
-
|
|
149
|
+
The directive publishes the live displacement as `--for-carousel-swipe-movement-x`
|
|
150
|
+
(horizontal carousels) or `--for-carousel-swipe-movement-y` (vertical), a raw px
|
|
151
|
+
value on the viewport host; only the primary-axis property is written. Compose it
|
|
152
|
+
with `--for-carousel-offset` on the track transform:
|
|
152
153
|
|
|
153
154
|
```css
|
|
154
155
|
[forCarouselTrack] {
|
|
155
|
-
transform: translateX(
|
|
156
|
+
transform: translateX(
|
|
157
|
+
calc(var(--for-carousel-offset) + var(--for-carousel-swipe-movement-x, 0px))
|
|
158
|
+
);
|
|
156
159
|
transition: transform 300ms ease;
|
|
157
160
|
}
|
|
158
161
|
[forCarousel][data-orientation='vertical'] [forCarouselTrack] {
|
|
159
|
-
transform: translateY(
|
|
162
|
+
transform: translateY(
|
|
163
|
+
calc(var(--for-carousel-offset) + var(--for-carousel-swipe-movement-y, 0px))
|
|
164
|
+
);
|
|
160
165
|
}
|
|
161
166
|
/* Kill the settle transition while the finger is down so the track follows 1:1 */
|
|
162
167
|
[forCarouselViewport][data-dragging] [forCarouselTrack] {
|
|
@@ -169,20 +174,22 @@ transform:
|
|
|
169
174
|
|
|
170
175
|
### RTL
|
|
171
176
|
|
|
172
|
-
`--for-carousel-
|
|
173
|
-
it **without** the `-1` factor the consumer may apply to
|
|
174
|
-
in RTL:
|
|
177
|
+
`--for-carousel-swipe-movement-x` is always the **physical** finger displacement,
|
|
178
|
+
so compose it **without** the `-1` factor the consumer may apply to
|
|
179
|
+
`--for-carousel-offset` in RTL:
|
|
175
180
|
|
|
176
181
|
```css
|
|
177
182
|
[dir='rtl'] [forCarouselTrack] {
|
|
178
|
-
transform: translateX(
|
|
183
|
+
transform: translateX(
|
|
184
|
+
calc(-1 * var(--for-carousel-offset) + var(--for-carousel-swipe-movement-x, 0px))
|
|
185
|
+
);
|
|
179
186
|
}
|
|
180
187
|
```
|
|
181
188
|
|
|
182
189
|
### Reduced motion
|
|
183
190
|
|
|
184
191
|
Under `prefers-reduced-motion: reduce` the directive does **not** publish
|
|
185
|
-
`--for-carousel-
|
|
192
|
+
`--for-carousel-swipe-movement-x` / `-y` (no live track motion). The gesture still snaps
|
|
186
193
|
`activeIndex` on release — only the continuous live offset is suppressed.
|
|
187
194
|
|
|
188
195
|
### Cross-axis / touch
|
|
@@ -319,7 +326,7 @@ Implements the [WAI-ARIA Carousel pattern](https://www.w3.org/WAI/ARIA/apg/patte
|
|
|
319
326
|
|
|
320
327
|
## Styling
|
|
321
328
|
|
|
322
|
-
forty-cdk ships no styles. Add your own class to each piece — the `for*` selectors are the behavior API, not a styling contract (see [Styling forty-cdk](
|
|
329
|
+
forty-cdk ships no styles. Add your own class to each piece — the `for*` selectors are the behavior API, not a styling contract (see [Styling forty-cdk](../../../docs/styling.md)). 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.
|
|
323
330
|
|
|
324
331
|
```css
|
|
325
332
|
[forCarouselViewport] {
|
|
@@ -349,15 +356,16 @@ forty-cdk ships no styles. Add your own class to each piece — the `for*` selec
|
|
|
349
356
|
The following properties are set on the `[forCarousel]` host and cascade to
|
|
350
357
|
children, unless noted otherwise:
|
|
351
358
|
|
|
352
|
-
| Property
|
|
353
|
-
|
|
|
354
|
-
| `--for-carousel-offset`
|
|
355
|
-
| `--for-carousel-active-index`
|
|
356
|
-
| `--for-carousel-slide-count`
|
|
357
|
-
| `--for-carousel-slides-per-view`
|
|
358
|
-
| `--for-carousel-viewport-width`
|
|
359
|
-
| `--for-carousel-viewport-height`
|
|
360
|
-
| `--for-carousel-
|
|
359
|
+
| Property | Host | Value | Notes |
|
|
360
|
+
| --------------------------------- | ----------------------- | ------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ |
|
|
361
|
+
| `--for-carousel-offset` | `[forCarousel]` | e.g. `-100%` | Pure arithmetic from `activeIndex`, `slidesPerView`, `align`. |
|
|
362
|
+
| `--for-carousel-active-index` | `[forCarousel]` | integer | Current `activeIndex`. |
|
|
363
|
+
| `--for-carousel-slide-count` | `[forCarousel]` | integer | Total registered slides. |
|
|
364
|
+
| `--for-carousel-slides-per-view` | `[forCarousel]` | integer | From the `slidesPerView` input. |
|
|
365
|
+
| `--for-carousel-viewport-width` | `[forCarousel]` | e.g. `640px` | Measured via `ResizeObserver`. Absent on the server and before first measurement. |
|
|
366
|
+
| `--for-carousel-viewport-height` | `[forCarousel]` | e.g. `400px` | Same as above, for the block axis. |
|
|
367
|
+
| `--for-carousel-swipe-movement-x` | `[forCarouselViewport]` | e.g. `-128px` | Live px displacement along the primary axis during a swipe. Only the axis matching `orientation` is written; the other is absent, as is both at rest and under `prefers-reduced-motion: reduce`. |
|
|
368
|
+
| `--for-carousel-swipe-movement-y` | `[forCarouselViewport]` | e.g. `-128px` | Live px displacement along the primary axis during a swipe. Only the axis matching `orientation` is written; the other is absent, as is both at rest and under `prefers-reduced-motion: reduce`. |
|
|
361
369
|
|
|
362
370
|
### Autoplay styling hooks
|
|
363
371
|
|
|
@@ -415,3 +423,7 @@ in RTL is the consumer's CSS concern. For example, to flip the translate sign in
|
|
|
415
423
|
```
|
|
416
424
|
|
|
417
425
|
The example CSS above is LTR-only by default.
|
|
426
|
+
|
|
427
|
+
## Wrapping in a design system
|
|
428
|
+
|
|
429
|
+
Subclassing the root is the supported pattern; the subclass must spread `provideForCarousel(MyRoot)` into its own `providers` because Angular does not inherit a directive's `providers`, and every projected piece resolves its context through it. Re-providing `FOR_CAROUSEL_CONTEXT` by hand is not enough: the root also provides an unexported registration token the wrapper cannot name. See [Wrapping non-form roots](../../../docs/wrapping-non-form-roots.md).
|
package/checkbox/README.md
CHANGED
|
@@ -136,23 +136,26 @@ Optional styling slot inside a `[forCheckbox]`. Mirrors the parent's `data-state
|
|
|
136
136
|
|
|
137
137
|
## Keyboard
|
|
138
138
|
|
|
139
|
-
| Key | Action
|
|
140
|
-
| ------- |
|
|
141
|
-
| `Space` | Toggle the checkbox. The only key APG mandates.
|
|
142
|
-
| `Enter` | Also toggles —
|
|
139
|
+
| Key | Action |
|
|
140
|
+
| ------- | ----------------------------------------------------------- |
|
|
141
|
+
| `Space` | Toggle the checkbox. The only key APG mandates. |
|
|
142
|
+
| `Enter` | Also toggles — a documented superset, not an APG violation. |
|
|
143
143
|
|
|
144
144
|
Activating an indeterminate checkbox clears `indeterminate` and toggles `checked` (matches native `<input type="checkbox">`).
|
|
145
145
|
|
|
146
|
+
Both keys work on any host element. On a `<button>` they come from native button behavior; on any other host (`<div>`, `<span>`, or a `hostDirectives` wrapper's own host) the directive adds `tabindex="0"` and synthesizes the same activation, so a styled-from-scratch checkbox is never announced as a checkbox it is impossible to operate. `Space` keydown always blocks page scrolling; the toggle fires on its keyup.
|
|
147
|
+
|
|
146
148
|
## Accessibility
|
|
147
149
|
|
|
148
150
|
Implements the [WAI-ARIA Checkbox pattern](https://www.w3.org/WAI/ARIA/apg/patterns/checkbox/).
|
|
149
151
|
|
|
150
152
|
- **Provide an accessible name.** Wrap the button in a `<label>`, or set `aria-labelledby` / `aria-label`. Without one, the control is announced as just "checkbox" with no purpose.
|
|
153
|
+
- **Any host element works.** A `<button>` is the recommended host (the directive forces `type="button"` through a host binding, so it never submits a surrounding form even if you write `type="submit"` yourself), but a non-button host gets `tabindex="0"` and synthesized `Space` / `Enter` activation, so it is keyboard-operable too. A non-button host gets no `type` attribute at all — `type` is not valid on a `<div>` / `<span>`, and there is no form submission to protect against.
|
|
151
154
|
- **`role="checkbox"`** with `aria-checked="mixed"` is the canonical tri-state contract. Some legacy screen readers handle "mixed" differently — test with your target SRs.
|
|
152
155
|
|
|
153
156
|
## Styling
|
|
154
157
|
|
|
155
|
-
forty-cdk ships no styles. Add your own class to each piece — the for\* selectors are the behavior API, not a styling contract (see [Styling forty-cdk](
|
|
158
|
+
forty-cdk ships no styles. Add your own class to each piece — the for\* selectors are the behavior API, not a styling contract (see [Styling forty-cdk](../../../docs/styling.md)). Key your CSS off the reflected data-\* attributes listed per piece in the [API](#api) section.
|
|
156
159
|
|
|
157
160
|
```css
|
|
158
161
|
.checkbox-indicator[data-state='unchecked'] {
|
|
@@ -166,4 +169,4 @@ forty-cdk ships no styles. Add your own class to each piece — the for\* select
|
|
|
166
169
|
|
|
167
170
|
## Wrapping in a design system
|
|
168
171
|
|
|
169
|
-
Both supported wrapper patterns — `hostDirectives` with the exported `FOR_CHECKBOX_HOST_DIRECTIVE_INPUTS` / `FOR_CHECKBOX_HOST_DIRECTIVE_OUTPUTS` name tuples, and subclassing — are documented in [Wrapping form primitives](
|
|
172
|
+
Both supported wrapper patterns — `hostDirectives` with the exported `FOR_CHECKBOX_HOST_DIRECTIVE_INPUTS` / `FOR_CHECKBOX_HOST_DIRECTIVE_OUTPUTS` name tuples, and subclassing — are documented in [Wrapping form primitives](../../../docs/wrapping-form-primitives.md).
|
package/combobox/README.md
CHANGED
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
|
|
3
3
|
An editable input paired with a filterable listbox popup, supporting single or multi selection with chips.
|
|
4
4
|
|
|
5
|
-
> New to overlays in forty-cdk? [Your first overlay](
|
|
5
|
+
> New to overlays in forty-cdk? [Your first overlay](../../../docs/your-first-overlay.md) walks a Popover from empty markup to styled-and-animated and explains the `@if` / open-state model and the portal → global CSS rule.
|
|
6
6
|
|
|
7
7
|
Headless: `role="combobox"` on the input, `role="listbox"` on the surface, `role="option"` on items, plus `aria-activedescendant` so DOM focus stays in the input. Implements the `FormValueControl<readonly T[]>` interface from `@angular/forms/signals`.
|
|
8
8
|
|
|
@@ -232,7 +232,7 @@ runtime. This is the "editable + list" shape (no `[forComboboxTrigger]` needed).
|
|
|
232
232
|
<input forComboboxInput placeholder="Search…" />
|
|
233
233
|
@if (combobox.open()) {
|
|
234
234
|
<div forComboboxContent>
|
|
235
|
-
<button forComboboxAction (
|
|
235
|
+
<button forComboboxAction (activate)="createNew(query())">Create "{{ query() }}"</button>
|
|
236
236
|
<div forComboboxList>
|
|
237
237
|
@for (it of filtered; track it.id) {
|
|
238
238
|
<div forComboboxOption [value]="it.id" [label]="it.label">{{ it.label }}</div>
|
|
@@ -247,7 +247,7 @@ An action:
|
|
|
247
247
|
|
|
248
248
|
- **never touches `value` / `options()`.** It registers in a collection separate
|
|
249
249
|
from options, so `options()`, `aria-setsize`, and `aria-posinset` are
|
|
250
|
-
unaffected and activation emits `(
|
|
250
|
+
unaffected and activation emits `(activate)` instead of mutating `[(value)]`. The
|
|
251
251
|
consumer decides what happens and whether to close the popup afterwards.
|
|
252
252
|
- **is `role="button"`, not `role="option"`.** Assistive tech announces it as an
|
|
253
253
|
action, not as one of N choices.
|
|
@@ -270,7 +270,7 @@ a bottom-pinned option cannot guarantee under infinite scroll.
|
|
|
270
270
|
Because focus is trapped in the input↔actions ring while open, **Escape** (or an
|
|
271
271
|
outside pointer) is how you leave: Escape from an action closes the popup and
|
|
272
272
|
returns focus to the input (editable anatomy) or the `[forComboboxTrigger]`
|
|
273
|
-
(picker anatomy). Activation is **click / Enter / Space** and routes to `(
|
|
273
|
+
(picker anatomy). Activation is **click / Enter / Space** and routes to `(activate)`
|
|
274
274
|
only. With no action registered, Tab keeps its default "close and let Tab flow on"
|
|
275
275
|
behaviour, so existing comboboxes are unchanged.
|
|
276
276
|
|
|
@@ -283,11 +283,12 @@ outside-focus dismissal checks, exactly like the input.
|
|
|
283
283
|
| Member | Type | Notes |
|
|
284
284
|
| ------------ | -------------- | ---------------------------------------------------------------------------------------------------------- |
|
|
285
285
|
| `[disabled]` | `boolean` | Drops the action out of the focus ring (`tabindex` removed), reflects `aria-disabled`, ignores activation. |
|
|
286
|
-
| `(
|
|
286
|
+
| `(activate)` | `output<void>` | Fired on click / Enter / Space. Never mutates `[(value)]`. |
|
|
287
287
|
|
|
288
|
-
`[forComboboxAction]` host-binds `role="button"`, `type="button"
|
|
289
|
-
|
|
290
|
-
`
|
|
288
|
+
`[forComboboxAction]` host-binds `role="button"`, `type="button"` (on a native
|
|
289
|
+
`<button>` host only — any other element gets no `type`), a primitive-managed
|
|
290
|
+
`tabindex`, `aria-disabled` (when disabled), and reflects `data-highlighted`
|
|
291
|
+
while it holds DOM focus + `data-disabled` when disabled.
|
|
291
292
|
|
|
292
293
|
> **Out of scope (v1):** grouped action clusters / multiple action zones,
|
|
293
294
|
> submenu-style nested actions, and actions that mutate `value` (use a plain
|
|
@@ -380,7 +381,13 @@ Chips are intentionally **out of the Tab cycle** — Tab from outside lands on t
|
|
|
380
381
|
|
|
381
382
|
In RTL the chip cluster lays out right-to-left, so **ArrowRight** moves to the visually-next chip (DOM-previous) and **ArrowLeft** moves to the visually-previous one (DOM-next, hopping to the input at the leftmost visual edge).
|
|
382
383
|
|
|
383
|
-
`[forComboboxChipRemove]` is a click-only target (also out of Tab cycle) with auto-generated `aria-label="Remove <chip label>"`.
|
|
384
|
+
`[forComboboxChipRemove]` is a click-only target (also out of Tab cycle) with auto-generated `aria-label="Remove <chip label>"`. The name is computed per chip, so the piece takes no `[ariaLabel]` input and ignores a static `aria-label` attribute — localize it centrally by overriding the scope's builder:
|
|
385
|
+
|
|
386
|
+
```ts
|
|
387
|
+
@Component({
|
|
388
|
+
providers: [provideForComboboxDefaults({ chipRemoveLabel: (label) => `Quitar ${label}` })],
|
|
389
|
+
})
|
|
390
|
+
```
|
|
384
391
|
|
|
385
392
|
### Multi-mode Backspace heuristic
|
|
386
393
|
|
|
@@ -440,11 +447,11 @@ Real apps usually have richer option models — `{ id, label, ... }` — where t
|
|
|
440
447
|
|
|
441
448
|
Three inputs configure the object behaviour. Defaults make string mode work unchanged:
|
|
442
449
|
|
|
443
|
-
| Input
|
|
444
|
-
|
|
|
445
|
-
| `[
|
|
446
|
-
| `[itemToStringLabel]`
|
|
447
|
-
| `[itemToFormValue]`
|
|
450
|
+
| Input | Default | Purpose |
|
|
451
|
+
| --------------------- | ------------------------------------------------------------------ | --------------------------------------------------------------------------------------------------------------- |
|
|
452
|
+
| `[compareWith]` | `(a, b) => a === b` | How two items compare. Override for object values so selection / removal locate by id (or any stable key). |
|
|
453
|
+
| `[itemToStringLabel]` | `(item) => String(item)` | Render an item as a string. Drives `commitOnSelect` writes into the input and the chip-label fallback. |
|
|
454
|
+
| `[itemToFormValue]` | `(item) => typeof item === 'string' ? item : JSON.stringify(item)` | Serialize an item for the hidden input. Override to emit a per-item id (or any wire format your backend wants). |
|
|
448
455
|
|
|
449
456
|
```html
|
|
450
457
|
@let q = query().toLowerCase(); @let filtered = cities().filter((c) =>
|
|
@@ -455,7 +462,7 @@ c.name.toLowerCase().includes(q));
|
|
|
455
462
|
[(query)]="query"
|
|
456
463
|
[(value)]="value"
|
|
457
464
|
[(open)]="open"
|
|
458
|
-
[
|
|
465
|
+
[compareWith]="byId"
|
|
459
466
|
[itemToStringLabel]="toName"
|
|
460
467
|
name="city"
|
|
461
468
|
[itemToFormValue]="toId"
|
|
@@ -617,7 +624,7 @@ Implements the [WAI-ARIA Combobox pattern](https://www.w3.org/WAI/ARIA/apg/patte
|
|
|
617
624
|
|
|
618
625
|
## Styling
|
|
619
626
|
|
|
620
|
-
forty-cdk ships no styles. Add your own class to each piece — the for\* selectors are the behavior API, not a styling contract (see [Styling forty-cdk](
|
|
627
|
+
forty-cdk ships no styles. Add your own class to each piece — the for\* selectors are the behavior API, not a styling contract (see [Styling forty-cdk](../../../docs/styling.md)). Key your CSS off the reflected data-\* attributes listed under [Data attributes](#data-attributes).
|
|
621
628
|
|
|
622
629
|
### CSS custom properties
|
|
623
630
|
|
|
@@ -631,7 +638,7 @@ forty-cdk ships no styles. Add your own class to each piece — the for\* select
|
|
|
631
638
|
| `--for-available-height` | px | Space available along the block axis — clamp with `max-height`. |
|
|
632
639
|
| `--for-content-transform-origin` | `<origin>` keywords | `transform-origin` matching the resolved side / align, so a `scale` enter animation pivots from the input. |
|
|
633
640
|
|
|
634
|
-
> `[forComboboxContent]` is portaled to `document.body`, so it lives outside your component's view-encapsulated styles. Style it with global CSS (or a class you pass through) and the shared positioner properties above. See [Styling floating content](
|
|
641
|
+
> `[forComboboxContent]` is portaled to `document.body`, so it lives outside your component's view-encapsulated styles. Style it with global CSS (or a class you pass through) and the shared positioner properties above. See [Styling floating content](../../../docs/styling-floating-content.md) for the full positioner-variable list and the portal styling rules.
|
|
635
642
|
|
|
636
643
|
```css
|
|
637
644
|
.option[data-highlighted] {
|
|
@@ -645,4 +652,4 @@ forty-cdk ships no styles. Add your own class to each piece — the for\* select
|
|
|
645
652
|
|
|
646
653
|
## Wrapping in a design system
|
|
647
654
|
|
|
648
|
-
Both supported wrapper patterns — `hostDirectives` with the exported `FOR_COMBOBOX_HOST_DIRECTIVE_INPUTS` / `FOR_COMBOBOX_HOST_DIRECTIVE_OUTPUTS` name tuples, and subclassing — are documented in [Wrapping form primitives](
|
|
655
|
+
Both supported wrapper patterns — `hostDirectives` with the exported `FOR_COMBOBOX_HOST_DIRECTIVE_INPUTS` / `FOR_COMBOBOX_HOST_DIRECTIVE_OUTPUTS` name tuples, and subclassing — are documented in [Wrapping form primitives](../../../docs/wrapping-form-primitives.md).
|
package/context-menu/README.md
CHANGED
|
@@ -4,7 +4,7 @@ A menu opened by right-click or long-press, anchored to the pointer position.
|
|
|
4
4
|
|
|
5
5
|
Opened via the `contextmenu` event (right-click, long-press on touch) and via the keyboard activators `Shift+F10` and the dedicated `ContextMenu` key. The native browser context menu is suppressed. Pointer activations anchor the menu at the cursor; keyboard activations anchor it at the bounding rect of the focused element so screen-reader / keyboard-only users get the menu next to whatever they're working on. Floating-ui's virtual element handles either case — placement, flip, and shift middleware still apply, so the menu is repositioned to stay on-screen automatically.
|
|
6
6
|
|
|
7
|
-
> New to overlays in forty-cdk? [Your first overlay](
|
|
7
|
+
> New to overlays in forty-cdk? [Your first overlay](../../../docs/your-first-overlay.md) walks a Popover from empty markup to styled-and-animated and explains the `@if` / open-state model and the portal → global CSS rule.
|
|
8
8
|
|
|
9
9
|
## Anatomy
|
|
10
10
|
|
|
@@ -113,7 +113,7 @@ Angular resolves `ng-template` DI at the template's **declaration** site, not wh
|
|
|
113
113
|
| `dismissible` | `input<boolean>` | When `false`, Escape and outside interactions don't close.<br>**Default:** `true` |
|
|
114
114
|
| `returnFocus` | `input<boolean>` | When `true`, focus returns to the trigger element on close.<br>**Default:** `true` |
|
|
115
115
|
| `ariaLabel` | `input<string \| null>` | Accessible name reflected as `aria-label` on `[forMenuContent]`. The root's only name hook for a context menu — the right-click region is never used as an `aria-labelledby` target.<br>**Default:** `null` |
|
|
116
|
-
| `escapeKeyDown` | `output<VetoableNativeEvent<KeyboardEvent>>` | Output. Escape pressed while the menu is the topmost
|
|
116
|
+
| `escapeKeyDown` | `output<VetoableNativeEvent<KeyboardEvent>>` | Output. Escape pressed while the menu is the topmost dismissible layer.<br>**Default:** — |
|
|
117
117
|
| `pointerDownOutside` | `output<VetoableNativeEvent<PointerEvent>>` | Output. Pointer-down on a target outside content + trigger.<br>**Default:** — |
|
|
118
118
|
| `focusOutside` | `output<VetoableNativeEvent<FocusEvent>>` | Output. Focus moves outside content + trigger.<br>**Default:** — |
|
|
119
119
|
| `interactOutside` | `output<VetoableNativeEvent<PointerEvent \| FocusEvent>>` | Output. Composite — fires alongside the two above (and shares their veto state).<br>**Default:** — |
|
|
@@ -122,7 +122,7 @@ Angular resolves `ng-template` DI at the template's **declaration** site, not wh
|
|
|
122
122
|
|
|
123
123
|
Same vetoable dismiss API as DropdownMenu. Call `preventDefault()` on the emitted veto to suppress the directive's default action; the original DOM event, when present, is on `.event`.
|
|
124
124
|
|
|
125
|
-
`(autoFocusOnOpen)` / `(autoFocusOnClose)` are output-shape because ContextMenu always routes close transitions through `[(open)]` (via the implicit `openChange` emitter). See [
|
|
125
|
+
`(autoFocusOnOpen)` / `(autoFocusOnClose)` are output-shape because ContextMenu always routes close transitions through `[(open)]` (via the implicit `openChange` emitter). See [Conventions › Auto-focus hook shape](../../../.claude/rules/conventions.md#auto-focus-hook-shape) for why Dialog uses callback-shape inputs instead.
|
|
126
126
|
|
|
127
127
|
### Data attributes
|
|
128
128
|
|
|
@@ -141,9 +141,9 @@ Same vetoable dismiss API as DropdownMenu. Call `preventDefault()` on the emitte
|
|
|
141
141
|
|
|
142
142
|
## Styling
|
|
143
143
|
|
|
144
|
-
forty-cdk ships no styles. Add your own class to each piece — the for\* selectors are the behavior API, not a styling contract (see [Styling forty-cdk](
|
|
144
|
+
forty-cdk ships no styles. Add your own class to each piece — the for\* selectors are the behavior API, not a styling contract (see [Styling forty-cdk](../../../docs/styling.md)). Key your CSS off the reflected data-\* attributes listed under [Data attributes](#data-attributes).
|
|
145
145
|
|
|
146
|
-
> The menu content (`[forMenuContent]`, from the [`menu/`](../menu/README.md) folder) portals to `document.body`, so it sits outside the trigger's DOM subtree — 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-anchor-width` / `--for-anchor-height`, `--for-available-width` / `--for-available-height`, `--for-content-transform-origin`); see [Styling floating content](
|
|
146
|
+
> The menu content (`[forMenuContent]`, from the [`menu/`](../menu/README.md) folder) portals to `document.body`, so it sits outside the trigger's DOM subtree — 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-anchor-width` / `--for-anchor-height`, `--for-available-width` / `--for-available-height`, `--for-content-transform-origin`); see [Styling floating content](../../../docs/styling-floating-content.md) for the full list and the animation rules.
|
|
147
147
|
|
|
148
148
|
```css
|
|
149
149
|
.context-menu-trigger[data-state='open'] {
|
|
@@ -167,3 +167,7 @@ forty-cdk ships no styles. Add your own class to each piece — the for\* select
|
|
|
167
167
|
```
|
|
168
168
|
|
|
169
169
|
- **Mount equals open.** Same convention as the rest of the library — wrap `[forMenuContent]` in `@if (open())` and use `animate.enter` / `animate.leave` for transitions.
|
|
170
|
+
|
|
171
|
+
## Wrapping in a design system
|
|
172
|
+
|
|
173
|
+
Subclassing the root is the supported pattern; the subclass must re-provide `FOR_MENU_CONTEXT` because Angular does not inherit a directive's `providers`, and every projected piece resolves its context through it. See [Wrapping non-form roots](../../../docs/wrapping-non-form-roots.md).
|
package/date-field/README.md
CHANGED
|
@@ -216,7 +216,7 @@ Composes the [WAI-ARIA Spinbutton pattern](https://www.w3.org/WAI/ARIA/apg/patte
|
|
|
216
216
|
|
|
217
217
|
## Styling
|
|
218
218
|
|
|
219
|
-
forty-cdk ships no styles. Add your own class to each piece — the for\* selectors are the behavior API, not a styling contract (see [Styling forty-cdk](
|
|
219
|
+
forty-cdk ships no styles. Add your own class to each piece — the for\* selectors are the behavior API, not a styling contract (see [Styling forty-cdk](../../../docs/styling.md)). Key your CSS off the reflected data-\* attributes listed under [Data attributes](#data-attributes).
|
|
220
220
|
|
|
221
221
|
```css
|
|
222
222
|
.date-field-segment[data-placeholder] {
|
|
@@ -233,4 +233,4 @@ forty-cdk ships no styles. Add your own class to each piece — the for\* select
|
|
|
233
233
|
|
|
234
234
|
## Wrapping in a design system
|
|
235
235
|
|
|
236
|
-
Both supported wrapper patterns — `hostDirectives` with the exported `FOR_DATE_FIELD_HOST_DIRECTIVE_INPUTS` / `FOR_DATE_FIELD_HOST_DIRECTIVE_OUTPUTS` name tuples, and subclassing — are documented in [Wrapping form primitives](
|
|
236
|
+
Both supported wrapper patterns — `hostDirectives` with the exported `FOR_DATE_FIELD_HOST_DIRECTIVE_INPUTS` / `FOR_DATE_FIELD_HOST_DIRECTIVE_OUTPUTS` name tuples, and subclassing — are documented in [Wrapping form primitives](../../../docs/wrapping-form-primitives.md).
|
package/date-picker/README.md
CHANGED
|
@@ -1,10 +1,10 @@
|
|
|
1
1
|
# DatePicker
|
|
2
2
|
|
|
3
|
-
A trigger that opens a floating calendar to pick a date, composing ForCalendar inside a
|
|
3
|
+
A trigger that opens a floating calendar to pick a date, composing ForCalendar inside a dismissible popover with min / max bounds and per-date availability.
|
|
4
4
|
|
|
5
5
|
Reinterpreted idiomatically for modern Angular: a focusable trigger that opens a floating surface wrapping a projected [`ForCalendar`](../calendar/README.md).
|
|
6
6
|
|
|
7
|
-
`ForDatePicker` is the root **and** the form value — it implements `FormValueControl<D | null>` from `@angular/forms/signals`, so it auto-wires with `[formField]`. The trigger is the focusable control that carries `name` / `disabled` / `invalid`; selection state flows root → projected calendar via `[(value)]`. The library reuses its existing overlay stack (trigger-anchored Popover positioning,
|
|
7
|
+
`ForDatePicker` is the root **and** the form value — it implements `FormValueControl<D | null>` from `@angular/forms/signals`, so it auto-wires with `[formField]`. The trigger is the focusable control that carries `name` / `disabled` / `invalid`; selection state flows root → projected calendar via `[(value)]`. The library reuses its existing overlay stack (trigger-anchored Popover positioning, dismissible layer, return-focus) rather than re-implementing positioning, dismissal, or focus return — and the modal opt-in routes through the shared modal shell (focus trap + inert background + scroll lock).
|
|
8
8
|
|
|
9
9
|
## Date adapter
|
|
10
10
|
|
|
@@ -318,7 +318,7 @@ readonly booking = form(this.model, (p) => required(p.stay));
|
|
|
318
318
|
- **Native submission.** When `name` is set, two hidden inputs `<name>-start` / `<name>-end` mirror the committed endpoints as ISO `YYYY-MM-DD` for native `<form>` posts.
|
|
319
319
|
- **Bounds naming.** `minDate` / `maxDate` (not `min` / `max`) for the same reason as `ForDatePicker` — and additionally because `FormUiControl.min` / `max` are typed `NonNullable<TValue>` (the range object itself), which is meaningless as a bound.
|
|
320
320
|
|
|
321
|
-
Defaults are configured with `provideForDateRangePickerDefaults` (`sideOffset` / `collisionPadding`), and both wrapper patterns work via the exported `FOR_DATE_RANGE_PICKER_HOST_DIRECTIVE_INPUTS` / `FOR_DATE_RANGE_PICKER_HOST_DIRECTIVE_OUTPUTS` tuples — see [Wrapping form primitives](
|
|
321
|
+
Defaults are configured with `provideForDateRangePickerDefaults` (`sideOffset` / `collisionPadding`), and both wrapper patterns work via the exported `FOR_DATE_RANGE_PICKER_HOST_DIRECTIVE_INPUTS` / `FOR_DATE_RANGE_PICKER_HOST_DIRECTIVE_OUTPUTS` tuples — see [Wrapping form primitives](../../../docs/wrapping-form-primitives.md).
|
|
322
322
|
|
|
323
323
|
## Keyboard
|
|
324
324
|
|
|
@@ -335,15 +335,15 @@ Implements the [WAI-ARIA Date Picker Dialog pattern](https://www.w3.org/WAI/ARIA
|
|
|
335
335
|
|
|
336
336
|
- **`aria-haspopup="dialog"`** on the trigger, with `aria-expanded` reflecting `open()` and `aria-controls` pointing at the surface while open.
|
|
337
337
|
- **`role="dialog"`** on the surface, named by `[ariaLabel]` (or `aria-labelledby` the trigger when no label is set). `aria-modal="true"` only in modal mode (truthy-only).
|
|
338
|
-
- **Form-control ARIA** (`aria-
|
|
338
|
+
- **Form-control ARIA** (`aria-readonly` / `aria-required` / `aria-invalid` / `aria-busy`) is reflected on the focusable trigger so assistive tech announces validity on the element that takes focus. The disabled state is the exception: it reflects through the native `disabled` attribute alone (plus `data-disabled`), never `aria-disabled` — one channel per #561 D2.
|
|
339
339
|
- **Focus management**: focus enters the surface on open (the calendar's roving cell in non-modal mode) and returns to the trigger on close, both vetoable via `(autoFocusOnOpen)` / `(autoFocusOnClose)`.
|
|
340
340
|
- **Dismissal**: Escape (`(escapeKeyDown)`) and outside-pointer (`(pointerDownOutside)` / `(interactOutside)`) close the surface, each vetoable.
|
|
341
341
|
|
|
342
342
|
## Styling
|
|
343
343
|
|
|
344
|
-
forty-cdk ships no styles. Add your own class to each piece — the `for*` selectors are the behavior API, not a styling contract (see [Styling forty-cdk](
|
|
344
|
+
forty-cdk ships no styles. Add your own class to each piece — the `for*` selectors are the behavior API, not a styling contract (see [Styling forty-cdk](../../../docs/styling.md)). Key your CSS off the reflected `data-*` attributes listed under [Data attributes](#data-attributes).
|
|
345
345
|
|
|
346
|
-
> `[forDatePickerContent]` is portaled to `document.body`, so it lives outside your component's view-encapsulated styles. Style it with **global CSS** (or a class you pass through) rather than component-scoped rules — see [Styling floating content](
|
|
346
|
+
> `[forDatePickerContent]` is portaled to `document.body`, so it lives outside your component's view-encapsulated styles. Style it with **global CSS** (or a class you pass through) rather than component-scoped rules — see [Styling floating content](../../../docs/styling-floating-content.md). In non-modal (anchored) mode the surface also exposes the shared positioner custom properties (`--for-anchor-width` / `--for-anchor-height`, `--for-available-width` / `--for-available-height`, `--for-content-transform-origin`); that same guide tabulates the full set.
|
|
347
347
|
|
|
348
348
|
```css
|
|
349
349
|
.date-picker-trigger .date-picker-value[data-placeholder] {
|
|
@@ -360,4 +360,4 @@ forty-cdk ships no styles. Add your own class to each piece — the `for*` selec
|
|
|
360
360
|
|
|
361
361
|
## Wrapping in a design system
|
|
362
362
|
|
|
363
|
-
Both supported wrapper patterns — `hostDirectives` with the exported `FOR_DATE_PICKER_HOST_DIRECTIVE_INPUTS` / `FOR_DATE_PICKER_HOST_DIRECTIVE_OUTPUTS` name tuples, and subclassing — are documented in [Wrapping form primitives](
|
|
363
|
+
Both supported wrapper patterns — `hostDirectives` with the exported `FOR_DATE_PICKER_HOST_DIRECTIVE_INPUTS` / `FOR_DATE_PICKER_HOST_DIRECTIVE_OUTPUTS` name tuples, and subclassing — are documented in [Wrapping form primitives](../../../docs/wrapping-form-primitives.md).
|
|
@@ -246,8 +246,8 @@ Each segment implements the [WAI-ARIA Spinbutton pattern](https://www.w3.org/WAI
|
|
|
246
246
|
|
|
247
247
|
## Styling
|
|
248
248
|
|
|
249
|
-
forty-cdk ships no styles. Add your own class to each piece — the for\* selectors are the behavior API, not a styling contract (see [Styling forty-cdk](
|
|
249
|
+
forty-cdk ships no styles. Add your own class to each piece — the for\* selectors are the behavior API, not a styling contract (see [Styling forty-cdk](../../../docs/styling.md)). Key your CSS off the reflected data-\* attributes listed under [Data attributes](#data-attributes).
|
|
250
250
|
|
|
251
251
|
## Wrapping in a design system
|
|
252
252
|
|
|
253
|
-
Both supported wrapper patterns — `hostDirectives` with the exported `FOR_DATE_RANGE_FIELD_HOST_DIRECTIVE_INPUTS` / `FOR_DATE_RANGE_FIELD_HOST_DIRECTIVE_OUTPUTS` name tuples, and subclassing — are documented in [Wrapping form primitives](
|
|
253
|
+
Both supported wrapper patterns — `hostDirectives` with the exported `FOR_DATE_RANGE_FIELD_HOST_DIRECTIVE_INPUTS` / `FOR_DATE_RANGE_FIELD_HOST_DIRECTIVE_OUTPUTS` name tuples, and subclassing — are documented in [Wrapping form primitives](../../../docs/wrapping-form-primitives.md).
|
package/dialog/README.md
CHANGED
|
@@ -2,11 +2,11 @@
|
|
|
2
2
|
|
|
3
3
|
A modal window overlaid on the page, with a focus trap, scroll lock and Escape / dismiss handling. Also openable imperatively through ForDialogManager.
|
|
4
4
|
|
|
5
|
-
> New to overlays in forty-cdk? [Your first overlay](
|
|
5
|
+
> New to overlays in forty-cdk? [Your first overlay](../../../docs/your-first-overlay.md) walks a Popover from empty markup to styled-and-animated and explains the `@if` / open-state model and the portal → global CSS rule.
|
|
6
6
|
|
|
7
7
|
## Two flows, one engine
|
|
8
8
|
|
|
9
|
-
The same focus trap, scroll lock, portal, and
|
|
9
|
+
The same focus trap, scroll lock, portal, and dismissible-layer behaviors run under both APIs. Pick the one that fits the call site.
|
|
10
10
|
|
|
11
11
|
### Declarative — `[forDialog]`
|
|
12
12
|
|
|
@@ -204,7 +204,7 @@ Set them once for a scope with `provideForDialogDefaults({ animateEnter, animate
|
|
|
204
204
|
| `initialFocus` | — | `'first'` (first focusable inside) or `'container'` (the dialog host).<br>**Default:** `'first'` |
|
|
205
205
|
| `ariaLabel` | — | Manual `aria-label` if no `[forDialogTitle]` is rendered.<br>**Default:** `null` |
|
|
206
206
|
| `dismiss` | `OutputEmitterRef<ForDialogCloseReason>` | Output. Dialog wants to be unmounted. Reasons: `'escape'`, `'backdrop'`, `'pointerDownOutside'`, `'focusOutside'`, `'closeButton'`, `'programmatic'`.<br>**Default:** — |
|
|
207
|
-
| `escapeKeyDown` | `OutputEmitterRef<VetoableNativeEvent<KeyboardEvent>>` | Output. Escape while this dialog is the topmost
|
|
207
|
+
| `escapeKeyDown` | `OutputEmitterRef<VetoableNativeEvent<KeyboardEvent>>` | Output. Escape while this dialog is the topmost dismissible layer.<br>**Default:** — |
|
|
208
208
|
| `pointerDownOutside` | `OutputEmitterRef<VetoableNativeEvent<PointerEvent>>` | Output. Pointer-down outside the dialog.<br>**Default:** — |
|
|
209
209
|
| `focusOutside` | `OutputEmitterRef<VetoableNativeEvent<FocusEvent>>` | Output. Focus moves outside the dialog.<br>**Default:** — |
|
|
210
210
|
| `interactOutside` | `OutputEmitterRef<VetoableNativeEvent<PointerEvent \| FocusEvent>>` | Output. Composite: fires alongside both of the above (and shares their veto state).<br>**Default:** — |
|
|
@@ -249,7 +249,7 @@ Keep `dismissible: true` (the default) so Escape still closes, and veto only the
|
|
|
249
249
|
|
|
250
250
|
### Inputs — focus callbacks
|
|
251
251
|
|
|
252
|
-
The auto-focus pair is bound as **function references** (input callbacks), not as event listeners. Each callback receives a `VetoableEvent` whose `preventDefault()` suppresses the directive's default focus action. This shape mirrors `ForDialogManager`'s `config.autoFocusOn*` callbacks and guarantees the `autoFocusOnClose` callback fires reliably on every close path — including a direct `open.set(false)` that bypasses the `(dismiss)` output. See [
|
|
252
|
+
The auto-focus pair is bound as **function references** (input callbacks), not as event listeners. Each callback receives a `VetoableEvent` whose `preventDefault()` suppresses the directive's default focus action. This shape mirrors `ForDialogManager`'s `config.autoFocusOn*` callbacks and guarantees the `autoFocusOnClose` callback fires reliably on every close path — including a direct `open.set(false)` that bypasses the `(dismiss)` output. See [Conventions › Auto-focus hook shape](../../../.claude/rules/conventions.md#auto-focus-hook-shape) for why the free-floating overlays (Dialog, Drawer) use callback-shape inputs while the trigger-anchored ones use output-shape.
|
|
253
253
|
|
|
254
254
|
| Property | Type | Description |
|
|
255
255
|
| ------------------ | -------------------------------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
|
|
@@ -351,7 +351,7 @@ Implements the [WAI-ARIA Modal Dialog pattern](https://www.w3.org/WAI/ARIA/apg/p
|
|
|
351
351
|
|
|
352
352
|
## Styling
|
|
353
353
|
|
|
354
|
-
forty-cdk ships no styles. Add your own class to each piece — the `for*` selectors are the behavior API, not a styling contract (see [Styling forty-cdk](
|
|
354
|
+
forty-cdk ships no styles. Add your own class to each piece — the `for*` selectors are the behavior API, not a styling contract (see [Styling forty-cdk](../../../docs/styling.md)). Key your CSS off the reflected `data-*` attributes listed per piece in the [API](#api) section.
|
|
355
355
|
|
|
356
356
|
> **This dialog portals to `document.body`.** CSS scoped to ancestors of `[forDialog]` (or `[forDialogBackdrop]`) will not apply once the surface is moved to the body. Style it with **global CSS** or a class. Declaratively you write the surface yourself, so add the class directly (`<div forDialog class="my-dialog">`); for programmatically opened instances pass `class` / `classList` on the `ForDialogManager.open()` config — they land on the same `[forDialog]` host that carries `data-state` / `role` / `aria-modal`, merged and never clobbering them.
|
|
357
357
|
|
|
@@ -401,4 +401,8 @@ Pass `[container]` to portal the dialog surface into a specific element instead
|
|
|
401
401
|
- **Inert siblings**. When `modal`, every direct child of `document.body` other than the dialog box (and its backdrop) gets `inert` and `aria-hidden="true"` while open, and is restored on close. This is what `aria-modal="true"` alone is missing — Safari + VoiceOver and several other AT pairings still announce siblings of an aria-modal node otherwise. Stacking is order-safe: when a second modal opens on top, the first becomes inert; closing the top dialog re-activates the underlying one.
|
|
402
402
|
- **Vetoable dismissals**. Each of `(escapeKeyDown)`, `(pointerDownOutside)`, `(focusOutside)`, `(interactOutside)` fires before the corresponding `(dismiss)`. Call `preventDefault()` on the event to keep the dialog open (e.g. to ask "are you sure?" first).
|
|
403
403
|
- **The close button** (`[forDialogClose]`) always requests close, regardless of `dismissible`. Reason emitted is `'closeButton'`.
|
|
404
|
-
- **Both flows share the same engine** — the focus trap, scroll lock,
|
|
404
|
+
- **Both flows share the same engine** — the focus trap, scroll lock, dismissible layer, and portal in `ForDialogManager.open()` use the same `_internal/` utilities as the directive. Behavior is identical.
|
|
405
|
+
|
|
406
|
+
## Wrapping in a design system
|
|
407
|
+
|
|
408
|
+
Subclassing the root is the supported pattern; the subclass must re-provide `FOR_DIALOG_CONTEXT` because Angular does not inherit a directive's `providers`, and every projected piece resolves its context through it. See [Wrapping non-form roots](../../../docs/wrapping-non-form-roots.md).
|